diff --git a/.circleci/config.yml b/.circleci/config.yml index 4ee1ddefd4f..4812d5a7f07 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1634,7 +1634,7 @@ jobs: - run: command: | MERGE_BASE="$(git merge-base upstream/main HEAD)" - DIFF_PATHS="webui/react/src/components/kit webui/react/src/pages/DesignKit.tsx webui/react/design" + DIFF_PATHS="webui/react/src/package-lock.json webui/react/src/package.json webui/react/src/pages/DesignKit.tsx webui/react/design" if git diff --quiet $MERGE_BASE -- $DIFF_PATHS; then echo "DesignKit not changed, halting job now." circleci-agent step halt diff --git a/webui/react/Makefile b/webui/react/Makefile index 89ec72c300b..36584004c43 100644 --- a/webui/react/Makefile +++ b/webui/react/Makefile @@ -112,12 +112,10 @@ test: test-ci: VITEST_MAX_THREADS=6 VITEST_MIN_THREADS=1 npm run test:coverage -- --reporter=junit --reporter=default --outputFile.junit=junit.xml -# INCLUDE_FLAKY runs all tests even if they use flakyIt. -# By default this would run ALL tests. -# To avoid duplication, I use a filename (LogViewer) here to specify which group of tests to run. +# INCLUDE_FLAKY=true runs all tests with @flaky in the test name .PHONY: test-ci-flaky test-ci-flaky: - INCLUDE_FLAKY=true VITEST_MAX_THREADS=6 VITEST_MIN_THREADS=1 npm run test -- LogViewer --reporter=default + INCLUDE_FLAKY=true VITEST_MAX_THREADS=6 VITEST_MIN_THREADS=1 npm run test -- --reporter=default .PHONY: visual-test-deps visual-test-deps: node_modules/playwright-core/.local-browsers diff --git a/webui/react/src/components/kit/__mocks__/Tooltip.tsx b/webui/react/__mocks__/determined-ui/Tooltip.tsx similarity index 66% rename from webui/react/src/components/kit/__mocks__/Tooltip.tsx rename to webui/react/__mocks__/determined-ui/Tooltip.tsx index 072bfd7668c..a8580072a52 100644 --- a/webui/react/src/components/kit/__mocks__/Tooltip.tsx +++ b/webui/react/__mocks__/determined-ui/Tooltip.tsx @@ -1,9 +1,8 @@ +import type { TooltipProps } from 'determined-ui/Tooltip'; import React from 'react'; -import type { TooltipProps } from 'components/kit/Tooltip'; - -const { default: OriginalTooltip } = await vi.importActual( - 'components/kit/Tooltip', +const { default: OriginalTooltip } = await vi.importActual( + 'determined-ui/Tooltip', ); const Tooltip: React.FC = (props: TooltipProps) => { diff --git a/webui/react/design/index.tsx b/webui/react/design/index.tsx index 9e9e3854989..f60dbf0075c 100644 --- a/webui/react/design/index.tsx +++ b/webui/react/design/index.tsx @@ -1,3 +1,6 @@ +import { UIProvider } from 'determined-ui/Theme'; +import { ConfirmationProvider } from 'determined-ui/useConfirm'; +import { Loaded } from 'determined-ui/utils/loadable'; import { Map } from 'immutable'; import { observable } from 'micro-observables'; import { createRoot } from 'react-dom/client'; @@ -6,9 +9,6 @@ import { createBrowserRouter, RouterProvider } from 'react-router-dom'; import 'uplot/dist/uPlot.min.css'; import css from 'App.module.scss'; -import { UIProvider } from 'components/kit/Theme'; -import { ConfirmationProvider } from 'components/kit/useConfirm'; -import { Loaded } from 'components/kit/utils/loadable'; import { Settings, UserSettings } from 'hooks/useSettingsProvider'; import DesignKit from 'pages/DesignKit'; diff --git a/webui/react/package-lock.json b/webui/react/package-lock.json index 0fc21d07ac1..38302d27131 100644 --- a/webui/react/package-lock.json +++ b/webui/react/package-lock.json @@ -18,6 +18,7 @@ "core-js": "3.32", "dayjs": "^1.11.7", "debug": "^4.3.4", + "determined-ui": "git+https://git@github.com/determined-ai/determined-ui.git#v0.5.1", "events": "^3.3.0", "fp-ts": "^2.13.1", "fuse.js": "^6.6.2", @@ -338,10 +339,11 @@ } }, "node_modules/@codemirror/lang-markdown": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/@codemirror/lang-markdown/-/lang-markdown-6.1.1.tgz", - "integrity": "sha512-n87Ms6Y5UYb1UkFu8sRzTLfq/yyF1y2AYiWvaVdbBQi5WDj1tFk5N+AKA+WC0Jcjc1VxvrCCM0iizjdYYi9sFQ==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@codemirror/lang-markdown/-/lang-markdown-6.2.2.tgz", + "integrity": "sha512-wmwM9Y5n/e4ndU51KcYDaQnb9goYdhXjU71dDW9goOc1VUTIPph6WKAPdJ6BzC0ZFy+UTsDwTXGWSP370RH69Q==", "dependencies": { + "@codemirror/autocomplete": "^6.7.1", "@codemirror/lang-html": "^6.0.0", "@codemirror/language": "^6.3.0", "@codemirror/state": "^6.0.0", @@ -351,32 +353,32 @@ } }, "node_modules/@codemirror/lang-python": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/@codemirror/lang-python/-/lang-python-6.1.2.tgz", - "integrity": "sha512-nbQfifLBZstpt6Oo4XxA2LOzlSp4b/7Bc5cmodG1R+Cs5PLLCTUvsMNWDnziiCfTOG/SW1rVzXq/GbIr6WXlcw==", + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/@codemirror/lang-python/-/lang-python-6.1.3.tgz", + "integrity": "sha512-S9w2Jl74hFlD5nqtUMIaXAq9t5WlM0acCkyuQWUUSvZclk1sV+UfnpFiZzuZSG+hfEaOmxKR5UxY/Uxswn7EhQ==", "dependencies": { "@codemirror/autocomplete": "^6.3.2", - "@codemirror/language": "^6.0.0", - "@lezer/python": "^1.0.0" + "@codemirror/language": "^6.8.0", + "@lezer/python": "^1.1.4" } }, "node_modules/@codemirror/language": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.7.0.tgz", - "integrity": "sha512-4SMwe6Fwn57klCUsVN0y4/h/iWT+XIXFEmop2lIHHuWO0ubjCrF3suqSZLyOQlznxkNnNbOOfKe5HQbQGCAmTg==", + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.9.1.tgz", + "integrity": "sha512-lWRP3Y9IUdOms6DXuBpoWwjkR7yRmnS0hKYCbSfPz9v6Em1A1UCRujAkDiCrdYfs1Z0Eu4dGtwovNPStIfkgNA==", "dependencies": { "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.0.0", - "@lezer/common": "^1.0.0", + "@lezer/common": "^1.1.0", "@lezer/highlight": "^1.0.0", "@lezer/lr": "^1.0.0", "style-mod": "^4.0.0" } }, "node_modules/@codemirror/legacy-modes": { - "version": "6.3.2", - "resolved": "https://registry.npmjs.org/@codemirror/legacy-modes/-/legacy-modes-6.3.2.tgz", - "integrity": "sha512-ki5sqNKWzKi5AKvpVE6Cna4Q+SgxYuYVLAZFSsMjGBWx5qSVa+D+xipix65GS3f2syTfAD9pXKMX4i4p49eneQ==", + "version": "6.3.3", + "resolved": "https://registry.npmjs.org/@codemirror/legacy-modes/-/legacy-modes-6.3.3.tgz", + "integrity": "sha512-X0Z48odJ0KIoh/HY8Ltz75/4tDYc9msQf1E/2trlxFaFFhgjpVHjZ/BCXe1Lk7s4Gd67LL/CeEEHNI+xHOiESg==", "dependencies": { "@codemirror/language": "^6.0.0" } @@ -890,23 +892,23 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.4.0.tgz", - "integrity": "sha512-A9983Q0LnDGdLPjxyXQ00sbV+K+O+ko2Dr+CZigbHWtX9pNfxlaBkMR8X1CztI73zuEyEBXTVjx7CE+/VSwDiQ==", + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.9.1.tgz", + "integrity": "sha512-Y27x+MBLjXa+0JWDhykM3+JE+il3kHKAEqabfEWq3SDhZjLYb6/BHL/JKFnH3fe207JaXkyDo685Oc2Glt6ifA==", "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/@eslint/eslintrc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz", - "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", + "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.5.2", + "espree": "^9.6.0", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -922,9 +924,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.41.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.41.0.tgz", - "integrity": "sha512-LxcyMGxwmTh2lY9FwHPGWOHmYFCZvbrFCBZL4FzSSsxsRPuhrYUg/49/0KDfW8tnIEaEHtfmn6+NPN+1DqaNmA==", + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.51.0.tgz", + "integrity": "sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -947,9 +949,9 @@ } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", - "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "version": "0.11.11", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz", + "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==", "dev": true, "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", @@ -1076,9 +1078,9 @@ "dev": true }, "node_modules/@lezer/common": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.0.2.tgz", - "integrity": "sha512-SVgiGtMnMnW3ActR8SXgsDhw7a0w0ChHSYAyAUxxrOiJ1OqYWEKk/xJd84tTSPo1mo6DXLObAJALNnd0Hrv7Ng==" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.1.0.tgz", + "integrity": "sha512-XPIN3cYDXsoJI/oDWoR2tD++juVrhgIago9xyKhZ7IhGlzdDM9QgC8D8saKNCz5pindGcznFr2HBSsEQSWnSjw==" }, "node_modules/@lezer/css": { "version": "1.1.2", @@ -2516,9 +2518,9 @@ } }, "node_modules/@uiw/codemirror-extensions-basic-setup": { - "version": "4.20.2", - "resolved": "https://registry.npmjs.org/@uiw/codemirror-extensions-basic-setup/-/codemirror-extensions-basic-setup-4.20.2.tgz", - "integrity": "sha512-8oF7ICSEoJVjn9MNKLsY5BaxGsFS/Qh8AMHa/0hZP1fExeI+LKhaaSfHbdRk8RpYE5Ffjtx+tBQfh22YBiv5dQ==", + "version": "4.21.19", + "resolved": "https://registry.npmjs.org/@uiw/codemirror-extensions-basic-setup/-/codemirror-extensions-basic-setup-4.21.19.tgz", + "integrity": "sha512-FwnzjNSc1mbzlcOlGmZgK2JMFcmPSHDeDUoql4ioyffF6ytiUD6LB9exOlQlAppzAZkKBYHqBwBjd0gdJYpH/w==", "dependencies": { "@codemirror/autocomplete": "^6.0.0", "@codemirror/commands": "^6.0.0", @@ -2539,15 +2541,15 @@ } }, "node_modules/@uiw/react-codemirror": { - "version": "4.20.2", - "resolved": "https://registry.npmjs.org/@uiw/react-codemirror/-/react-codemirror-4.20.2.tgz", - "integrity": "sha512-Rf6i9HgtNnYAVRBb1gfWlhiiOBrEPuIfHLn87cV9XPpjP+YtqZoP6VMMlMq4XFTbZ/E1GIxnSUgJMQToTth0iw==", + "version": "4.21.19", + "resolved": "https://registry.npmjs.org/@uiw/react-codemirror/-/react-codemirror-4.21.19.tgz", + "integrity": "sha512-KCm+izhkeRCz9uuPY4WtlMAwEE6HsGR/iHGFDABj2OFq9DfnpAIFyVx2Z87NxMHvHi7zttn6JerxwNLJdV12og==", "dependencies": { "@babel/runtime": "^7.18.6", "@codemirror/commands": "^6.1.0", "@codemirror/state": "^6.1.1", "@codemirror/theme-one-dark": "^6.0.0", - "@uiw/codemirror-extensions-basic-setup": "4.20.2", + "@uiw/codemirror-extensions-basic-setup": "4.21.19", "codemirror": "^6.0.0" }, "peerDependencies": { @@ -4005,9 +4007,9 @@ } }, "node_modules/dayjs": { - "version": "1.11.7", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.7.tgz", - "integrity": "sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ==" + "version": "1.11.10", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", + "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==" }, "node_modules/debug": { "version": "4.3.4", @@ -4182,6 +4184,43 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/determined-ui": { + "version": "0.5.1", + "resolved": "git+https://git@github.com/determined-ai/determined-ui.git#cc4c5372226e2cbd02f0c16e7cebdad9e5bb937e", + "dependencies": { + "@ant-design/icons": "^5.0.1", + "@codemirror/lang-markdown": "^6.2.1", + "@codemirror/lang-python": "^6.1.3", + "@codemirror/language": "^6.9.1", + "@codemirror/legacy-modes": "^6.3.3", + "@uiw/react-codemirror": "^4.21.18", + "ansi-to-html": "^0.7.2", + "antd": "^5.1.7", + "dayjs": "^1.11.10", + "debug": "^4.3.4", + "io-ts": "^2.2.20", + "lodash": "^4.17.21", + "markdown-to-jsx": "^7.3.2", + "micro-observables": "^1.7.2", + "notebook": "file:vendor/notebook", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-window": "^1.8.9", + "screenfull": "^6.0.2", + "sprintf-js": "^1.1.3", + "throttle-debounce": "^5.0.0", + "uplot": "^1.6.18" + } + }, + "node_modules/determined-ui/vendor/notebook": { + "version": "0.7.0", + "extraneous": true, + "dependencies": { + "ansi_up": "^5.1.0", + "dompurify": "^2.4.0", + "marked": "^4.1.1" + } + }, "node_modules/diff": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", @@ -4595,27 +4634,27 @@ } }, "node_modules/eslint": { - "version": "8.41.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.41.0.tgz", - "integrity": "sha512-WQDQpzGBOP5IrXPo4Hc0814r4/v2rrIsB0rhT7jtunIalgg6gYXWhRMOejVO8yH21T/FGaxjmFjBMNqcIlmH1Q==", + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.51.0.tgz", + "integrity": "sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.3", - "@eslint/js": "8.41.0", - "@humanwhocodes/config-array": "^0.11.8", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.2", + "@eslint/js": "8.51.0", + "@humanwhocodes/config-array": "^0.11.11", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", + "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.0", - "eslint-visitor-keys": "^3.4.1", - "espree": "^9.5.2", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -4625,7 +4664,6 @@ "globals": "^13.19.0", "graphemer": "^1.4.0", "ignore": "^5.2.0", - "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", @@ -4635,9 +4673,8 @@ "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", + "optionator": "^0.9.3", "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" }, "bin": { @@ -5950,9 +5987,9 @@ } }, "node_modules/globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "version": "13.23.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", + "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -7521,9 +7558,9 @@ } }, "node_modules/markdown-to-jsx": { - "version": "7.1.9", - "resolved": "https://registry.npmjs.org/markdown-to-jsx/-/markdown-to-jsx-7.1.9.tgz", - "integrity": "sha512-x4STVIKIJR0mGgZIZ5RyAeQD7FEZd5tS8m/htbcVGlex32J+hlSLj+ExrHCxP6nRKF1EKbcO7i6WhC1GtOpBlA==", + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/markdown-to-jsx/-/markdown-to-jsx-7.3.2.tgz", + "integrity": "sha512-B+28F5ucp83aQm+OxNrPkS8z0tMKaeHiy0lHJs3LqCyDQFtWuenaIrkaVTgAm1pf1AU85LXltva86hlaT17i8Q==", "engines": { "node": ">= 10" }, @@ -10062,9 +10099,9 @@ } }, "node_modules/react-window": { - "version": "1.8.8", - "resolved": "https://registry.npmjs.org/react-window/-/react-window-1.8.8.tgz", - "integrity": "sha512-D4IiBeRtGXziZ1n0XklnFGu7h9gU684zepqyKzgPNzrsrk7xOCxni+TCckjg2Nr/DiaEEGVVmnhYSlT2rB47dQ==", + "version": "1.8.9", + "resolved": "https://registry.npmjs.org/react-window/-/react-window-1.8.9.tgz", + "integrity": "sha512-+Eqx/fj1Aa5WnhRfj9dJg4VYATGwIUP2ItwItiJ6zboKWA6EX3lYDAXfGF2hyNqplEprhbtjbipiADEcwQ823Q==", "dependencies": { "@babel/runtime": "^7.0.0", "memoize-one": ">=3.1.1 <6" @@ -10850,8 +10887,9 @@ "license": "CC0-1.0" }, "node_modules/sprintf-js": { - "version": "1.1.2", - "license": "BSD-3-Clause" + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==" }, "node_modules/stack-utils": { "version": "2.0.3", diff --git a/webui/react/package.json b/webui/react/package.json index 764c5755b6e..94c7811bbab 100644 --- a/webui/react/package.json +++ b/webui/react/package.json @@ -42,6 +42,7 @@ "core-js": "3.32", "dayjs": "^1.11.7", "debug": "^4.3.4", + "determined-ui": "git+https://git@github.com/determined-ai/determined-ui.git#v0.5.1", "events": "^3.3.0", "fp-ts": "^2.13.1", "fuse.js": "^6.6.2", diff --git a/webui/react/src/App.tsx b/webui/react/src/App.tsx index eae6d776ebd..33b7d474213 100644 --- a/webui/react/src/App.tsx +++ b/webui/react/src/App.tsx @@ -1,4 +1,10 @@ import { App as AntdApp } from 'antd'; +import Button from 'determined-ui/Button'; +import Spinner from 'determined-ui/Spinner'; +import useUI, { UIProvider } from 'determined-ui/Theme'; +import { notification } from 'determined-ui/Toast'; +import { ConfirmationProvider } from 'determined-ui/useConfirm'; +import { Loadable } from 'determined-ui/utils/loadable'; import { useObservable } from 'micro-observables'; import React, { useEffect, useLayoutEffect, useState } from 'react'; import { DndProvider } from 'react-dnd'; @@ -7,12 +13,6 @@ import { HelmetProvider } from 'react-helmet-async'; import { useParams } from 'react-router-dom'; import JupyterLabGlobal from 'components/JupyterLabGlobal'; -import Button from 'components/kit/Button'; -import Spinner from 'components/kit/Spinner'; -import useUI, { UIProvider } from 'components/kit/Theme'; -import { notification } from 'components/kit/Toast'; -import { ConfirmationProvider } from 'components/kit/useConfirm'; -import { Loadable } from 'components/kit/utils/loadable'; import Link from 'components/Link'; import Navigation from 'components/Navigation'; import PageMessage from 'components/PageMessage'; diff --git a/webui/react/src/components/ActionDropdown/ActionDropdown.test.tsx b/webui/react/src/components/ActionDropdown/ActionDropdown.test.tsx index 0e2b49158a8..75b2d1e0c86 100644 --- a/webui/react/src/components/ActionDropdown/ActionDropdown.test.tsx +++ b/webui/react/src/components/ActionDropdown/ActionDropdown.test.tsx @@ -1,8 +1,8 @@ import { render, screen, waitFor } from '@testing-library/react'; import userEvent, { PointerEventsCheckLevel } from '@testing-library/user-event'; +import { ConfirmationProvider } from 'determined-ui/useConfirm'; import ActionDropdown from 'components/ActionDropdown/ActionDropdown'; -import { ConfirmationProvider } from 'components/kit/useConfirm'; import { ValueOf } from 'types'; const user = userEvent.setup({ pointerEventsCheck: PointerEventsCheckLevel.Never }); diff --git a/webui/react/src/components/ActionDropdown/ActionDropdown.tsx b/webui/react/src/components/ActionDropdown/ActionDropdown.tsx index 9823483e75c..58f586c6665 100644 --- a/webui/react/src/components/ActionDropdown/ActionDropdown.tsx +++ b/webui/react/src/components/ActionDropdown/ActionDropdown.tsx @@ -1,9 +1,9 @@ +import Button from 'determined-ui/Button'; +import Dropdown, { MenuItem } from 'determined-ui/Dropdown'; +import Icon from 'determined-ui/Icon'; +import useConfirm, { ConfirmModalProps } from 'determined-ui/useConfirm'; import React, { JSXElementConstructor, useCallback } from 'react'; -import Button from 'components/kit/Button'; -import Dropdown, { MenuItem } from 'components/kit/Dropdown'; -import Icon from 'components/kit/Icon'; -import useConfirm, { ConfirmModalProps } from 'components/kit/useConfirm'; import { Eventually } from 'types'; import handleError, { DetError, ErrorLevel, ErrorType, wrapPublicMessage } from 'utils/error'; import { capitalize } from 'utils/string'; diff --git a/webui/react/src/components/ActionSheet.tsx b/webui/react/src/components/ActionSheet.tsx index e103c026cc6..53c120cab9a 100644 --- a/webui/react/src/components/ActionSheet.tsx +++ b/webui/react/src/components/ActionSheet.tsx @@ -1,7 +1,7 @@ +import Icon, { IconName } from 'determined-ui/Icon'; import React, { useCallback, useRef } from 'react'; import { CSSTransition } from 'react-transition-group'; -import Icon, { IconName } from 'components/kit/Icon'; import Link, { Props as LinkProps } from 'components/Link'; import css from './ActionSheet.module.scss'; diff --git a/webui/react/src/components/AddUsersToGroupsModal.tsx b/webui/react/src/components/AddUsersToGroupsModal.tsx index e3c22d8a1f1..36ba165e4fb 100644 --- a/webui/react/src/components/AddUsersToGroupsModal.tsx +++ b/webui/react/src/components/AddUsersToGroupsModal.tsx @@ -1,7 +1,8 @@ -import Form from 'components/kit/Form'; -import { Modal } from 'components/kit/Modal'; -import Select, { Option } from 'components/kit/Select'; -import { makeToast } from 'components/kit/Toast'; +import Form from 'determined-ui/Form'; +import { Modal } from 'determined-ui/Modal'; +import Select, { Option } from 'determined-ui/Select'; +import { makeToast } from 'determined-ui/Toast'; + import { assignMultipleGroups } from 'services/api'; import { V1GroupSearchResult } from 'services/api-ts-sdk'; import handleError from 'utils/error'; diff --git a/webui/react/src/components/AuthToken.tsx b/webui/react/src/components/AuthToken.tsx index 207a6a23f43..8724da1adeb 100644 --- a/webui/react/src/components/AuthToken.tsx +++ b/webui/react/src/components/AuthToken.tsx @@ -1,9 +1,9 @@ +import Button from 'determined-ui/Button'; +import Icon from 'determined-ui/Icon'; +import Message from 'determined-ui/Message'; +import { makeToast } from 'determined-ui/Toast'; import React, { useCallback } from 'react'; -import Button from 'components/kit/Button'; -import Icon from 'components/kit/Icon'; -import Message from 'components/kit/Message'; -import { makeToast } from 'components/kit/Toast'; import { globalStorage } from 'globalStorage'; import { copyToClipboard } from 'utils/dom'; diff --git a/webui/react/src/components/Badge.test.tsx b/webui/react/src/components/Badge.test.tsx index b8044467ac6..fce49646230 100644 --- a/webui/react/src/components/Badge.test.tsx +++ b/webui/react/src/components/Badge.test.tsx @@ -1,8 +1,8 @@ import { render, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; +import { UIProvider } from 'determined-ui/Theme'; import React, { useState } from 'react'; -import { UIProvider } from 'components/kit/Theme'; import { stateToLabel } from 'constants/states'; import { ResourceState, SlotState } from 'types'; import { generateAlphaNumeric } from 'utils/string'; diff --git a/webui/react/src/components/Badge.tsx b/webui/react/src/components/Badge.tsx index f46bc436fca..80f3f026684 100644 --- a/webui/react/src/components/Badge.tsx +++ b/webui/react/src/components/Badge.tsx @@ -1,12 +1,12 @@ -import React, { CSSProperties, useMemo } from 'react'; - import useUI, { DarkLight, getCssVar, getStateColorCssVar, StateOfUnion, -} from 'components/kit/Theme'; -import Tooltip from 'components/kit/Tooltip'; +} from 'determined-ui/Theme'; +import Tooltip from 'determined-ui/Tooltip'; +import React, { CSSProperties, useMemo } from 'react'; + import { stateToLabel } from 'constants/states'; import { ResourceState, RunState, SlotState, ValueOf } from 'types'; import { hsl2str, str2hsl } from 'utils/color'; diff --git a/webui/react/src/components/BadgeTag.test.tsx b/webui/react/src/components/BadgeTag.test.tsx index 9414af7bd4a..02bf3e592dd 100644 --- a/webui/react/src/components/BadgeTag.test.tsx +++ b/webui/react/src/components/BadgeTag.test.tsx @@ -1,7 +1,7 @@ import { render } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; +import { UIProvider } from 'determined-ui/Theme'; -import { UIProvider } from 'components/kit/Theme'; import { generateAlphaNumeric } from 'utils/string'; import BadgeTag, { Props } from './BadgeTag'; @@ -10,7 +10,7 @@ const LABEL = generateAlphaNumeric(); const CONTENT = generateAlphaNumeric(); const CONTENT_TOOLTIP = generateAlphaNumeric(); -vi.mock('components/kit/Tooltip'); +vi.mock('determined-ui/Tooltip'); const setup = ({ children = CONTENT, tooltip = CONTENT_TOOLTIP, ...props }: Props = {}) => { const view = render( diff --git a/webui/react/src/components/BadgeTag.tsx b/webui/react/src/components/BadgeTag.tsx index 9b7e9912551..31ae63f6f82 100644 --- a/webui/react/src/components/BadgeTag.tsx +++ b/webui/react/src/components/BadgeTag.tsx @@ -1,7 +1,6 @@ +import Tooltip from 'determined-ui/Tooltip'; import React from 'react'; -import Tooltip from 'components/kit/Tooltip'; - import Badge, { BadgeProps } from './Badge'; import css from './BadgeTag.module.scss'; diff --git a/webui/react/src/components/Bar.tsx b/webui/react/src/components/Bar.tsx index f14505b6116..c89a1f885dc 100644 --- a/webui/react/src/components/Bar.tsx +++ b/webui/react/src/components/Bar.tsx @@ -1,7 +1,7 @@ +import { ShirtSize } from 'determined-ui/Theme'; +import Tooltip from 'determined-ui/Tooltip'; import React from 'react'; -import { ShirtSize } from 'components/kit/Theme'; -import Tooltip from 'components/kit/Tooltip'; import { floatToPercent } from 'utils/string'; import css from './Bar.module.scss'; diff --git a/webui/react/src/components/BatchActionConfirmModal.test.tsx b/webui/react/src/components/BatchActionConfirmModal.test.tsx index cff89904122..750148d6d84 100644 --- a/webui/react/src/components/BatchActionConfirmModal.test.tsx +++ b/webui/react/src/components/BatchActionConfirmModal.test.tsx @@ -1,9 +1,9 @@ import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; +import Button from 'determined-ui/Button'; +import { DEFAULT_CANCEL_LABEL, useModal } from 'determined-ui/Modal'; import React from 'react'; -import Button from 'components/kit/Button'; -import { DEFAULT_CANCEL_LABEL, useModal } from 'components/kit/Modal'; import { ExperimentAction as Action, ExperimentAction } from 'types'; import BatchActionConfirmModalComponent from './BatchActionConfirmModal'; diff --git a/webui/react/src/components/BatchActionConfirmModal.tsx b/webui/react/src/components/BatchActionConfirmModal.tsx index f3285e3b69d..5112b04b063 100644 --- a/webui/react/src/components/BatchActionConfirmModal.tsx +++ b/webui/react/src/components/BatchActionConfirmModal.tsx @@ -1,6 +1,6 @@ +import { Modal } from 'determined-ui/Modal'; import React from 'react'; -import { Modal } from 'components/kit/Modal'; import { UNMANAGED_EXPERIMENT_ANNOTATION_MESSAGE } from 'constant'; import { ExperimentAction } from 'types'; import handleError from 'utils/error'; diff --git a/webui/react/src/components/ChangeUserStatusModal.tsx b/webui/react/src/components/ChangeUserStatusModal.tsx index c04be301337..d54d5520817 100644 --- a/webui/react/src/components/ChangeUserStatusModal.tsx +++ b/webui/react/src/components/ChangeUserStatusModal.tsx @@ -1,8 +1,9 @@ -import Form from 'components/kit/Form'; -import { ValueOf } from 'components/kit/internal/types'; -import { Modal } from 'components/kit/Modal'; -import Select, { Option } from 'components/kit/Select'; -import { makeToast } from 'components/kit/Toast'; +import Form from 'determined-ui/Form'; +import { Modal } from 'determined-ui/Modal'; +import Select, { Option } from 'determined-ui/Select'; +import { makeToast } from 'determined-ui/Toast'; +import { ValueOf } from 'determined-ui/utils/types'; + import { patchUsers } from 'services/api'; import handleError from 'utils/error'; diff --git a/webui/react/src/components/CheckpointModal.tsx b/webui/react/src/components/CheckpointModal.tsx index f8c7ea7c4ea..271f3d691aa 100644 --- a/webui/react/src/components/CheckpointModal.tsx +++ b/webui/react/src/components/CheckpointModal.tsx @@ -1,6 +1,8 @@ +import Button from 'determined-ui/Button'; +import { Modal } from 'determined-ui/Modal'; +import useConfirm from 'determined-ui/useConfirm'; import React, { useCallback, useMemo } from 'react'; -import { Modal } from 'components/kit/Modal'; import { ModalCloseReason } from 'hooks/useModal/useModal'; import { paths } from 'routes/utils'; import { detApi } from 'services/apiConfig'; @@ -20,8 +22,6 @@ import { checkpointSize } from 'utils/workload'; import Badge, { BadgeType } from './Badge'; import css from './CheckpointModal.module.scss'; import HumanReadableNumber from './HumanReadableNumber'; -import Button from './kit/Button'; -import useConfirm from './kit/useConfirm'; import Link from './Link'; export interface Props { diff --git a/webui/react/src/components/CheckpointModalTrigger.test.tsx b/webui/react/src/components/CheckpointModalTrigger.test.tsx index 33172d2b16d..47397e1a9de 100644 --- a/webui/react/src/components/CheckpointModalTrigger.test.tsx +++ b/webui/react/src/components/CheckpointModalTrigger.test.tsx @@ -1,15 +1,14 @@ import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; +import { UIProvider } from 'determined-ui/Theme'; +import { ConfirmationProvider } from 'determined-ui/useConfirm'; import React, { useEffect } from 'react'; import { BrowserRouter } from 'react-router-dom'; import CheckpointModalTrigger from 'components/CheckpointModalTrigger'; -import { UIProvider } from 'components/kit/Theme'; import authStore from 'stores/auth'; import { generateTestExperimentData } from 'utils/tests/generateTestData'; -import { ConfirmationProvider } from './kit/useConfirm'; - const TEST_MODAL_TITLE = 'Checkpoint Modal Test'; const REGISTER_CHECKPOINT_TEXT = 'Register Checkpoint'; diff --git a/webui/react/src/components/CheckpointModalTrigger.tsx b/webui/react/src/components/CheckpointModalTrigger.tsx index 4eb8ec7c710..c22578400cb 100644 --- a/webui/react/src/components/CheckpointModalTrigger.tsx +++ b/webui/react/src/components/CheckpointModalTrigger.tsx @@ -1,8 +1,8 @@ +import Button from 'determined-ui/Button'; +import Icon from 'determined-ui/Icon'; +import { useModal } from 'determined-ui/Modal'; import React, { useCallback } from 'react'; -import Button from 'components/kit/Button'; -import Icon from 'components/kit/Icon'; -import { useModal } from 'components/kit/Modal'; import ModelCreateModal from 'components/ModelCreateModal'; import useModalCheckpointRegister from 'hooks/useModal/Checkpoint/useModalCheckpointRegister'; import { ModalCloseReason } from 'hooks/useModal/useModal'; diff --git a/webui/react/src/components/ColumnsCustomizeModal.test.tsx b/webui/react/src/components/ColumnsCustomizeModal.test.tsx index 9e4b958b880..5a5ead03fc7 100644 --- a/webui/react/src/components/ColumnsCustomizeModal.test.tsx +++ b/webui/react/src/components/ColumnsCustomizeModal.test.tsx @@ -1,10 +1,10 @@ import { render, waitFor, within } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; +import Button from 'determined-ui/Button'; +import { useModal } from 'determined-ui/Modal'; import React, { useMemo } from 'react'; import ColumnsCustomizeModalComponent from 'components/ColumnsCustomizeModal'; -import Button from 'components/kit/Button'; -import { useModal } from 'components/kit/Modal'; import { DEFAULT_COLUMNS } from 'pages/ExperimentList.settings'; import { generateAlphaNumeric, sentenceToCamelCase } from 'utils/string'; diff --git a/webui/react/src/components/ColumnsCustomizeModal.tsx b/webui/react/src/components/ColumnsCustomizeModal.tsx index 22805740a81..b5c73ad7477 100644 --- a/webui/react/src/components/ColumnsCustomizeModal.tsx +++ b/webui/react/src/components/ColumnsCustomizeModal.tsx @@ -1,6 +1,6 @@ +import { Modal } from 'determined-ui/Modal'; import React, { useRef, useState } from 'react'; -import { Modal } from 'components/kit/Modal'; import Transfer from 'components/Transfer'; import handleError from 'utils/error'; diff --git a/webui/react/src/components/ConfigureAgentModal.tsx b/webui/react/src/components/ConfigureAgentModal.tsx index 5490135eab2..e4bdbc1f3b2 100644 --- a/webui/react/src/components/ConfigureAgentModal.tsx +++ b/webui/react/src/components/ConfigureAgentModal.tsx @@ -1,11 +1,11 @@ +import Form from 'determined-ui/Form'; +import Input from 'determined-ui/Input'; +import InputNumber from 'determined-ui/InputNumber'; +import { Modal } from 'determined-ui/Modal'; +import Spinner from 'determined-ui/Spinner'; +import { makeToast } from 'determined-ui/Toast'; import React, { useEffect, useId, useState } from 'react'; -import Form from 'components/kit/Form'; -import Input from 'components/kit/Input'; -import InputNumber from 'components/kit/InputNumber'; -import { Modal } from 'components/kit/Modal'; -import Spinner from 'components/kit/Spinner'; -import { makeToast } from 'components/kit/Toast'; import { patchUser } from 'services/api'; import { V1AgentUserGroup } from 'services/api-ts-sdk'; import { DetailedUser } from 'types'; diff --git a/webui/react/src/components/CreateGroupModal.test.tsx b/webui/react/src/components/CreateGroupModal.test.tsx index 037aec1e7c5..989f17198d3 100644 --- a/webui/react/src/components/CreateGroupModal.test.tsx +++ b/webui/react/src/components/CreateGroupModal.test.tsx @@ -1,10 +1,10 @@ import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; +import Button from 'determined-ui/Button'; +import { useModal } from 'determined-ui/Modal'; +import { UIProvider } from 'determined-ui/Theme'; import React from 'react'; -import Button from 'components/kit/Button'; -import { useModal } from 'components/kit/Modal'; -import { UIProvider } from 'components/kit/Theme'; import { createGroup as mockCreateGroup } from 'services/api'; import { V1GroupSearchResult } from 'services/api-ts-sdk'; import { GetGroupParams } from 'services/types'; diff --git a/webui/react/src/components/CreateGroupModal.tsx b/webui/react/src/components/CreateGroupModal.tsx index b495ae31d67..a8e5e14b0f7 100644 --- a/webui/react/src/components/CreateGroupModal.tsx +++ b/webui/react/src/components/CreateGroupModal.tsx @@ -1,15 +1,15 @@ import { Select, Typography } from 'antd'; +import Form from 'determined-ui/Form'; +import Input from 'determined-ui/Input'; +import { Modal } from 'determined-ui/Modal'; +import Spinner from 'determined-ui/Spinner'; +import { makeToast } from 'determined-ui/Toast'; +import { Loadable } from 'determined-ui/utils/loadable'; import { filter } from 'fp-ts/lib/Set'; import _ from 'lodash'; import { useObservable } from 'micro-observables'; import React, { useCallback, useEffect, useId, useState } from 'react'; -import Form from 'components/kit/Form'; -import Input from 'components/kit/Input'; -import { Modal } from 'components/kit/Modal'; -import Spinner from 'components/kit/Spinner'; -import { makeToast } from 'components/kit/Toast'; -import { Loadable } from 'components/kit/utils/loadable'; import Link from 'components/Link'; import usePermissions from 'hooks/usePermissions'; import { paths } from 'routes/utils'; diff --git a/webui/react/src/components/CreateUserModal.test.tsx b/webui/react/src/components/CreateUserModal.test.tsx index fd9fc58f853..eb03ae95dc9 100644 --- a/webui/react/src/components/CreateUserModal.test.tsx +++ b/webui/react/src/components/CreateUserModal.test.tsx @@ -1,10 +1,10 @@ import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; +import Button from 'determined-ui/Button'; +import { useModal } from 'determined-ui/Modal'; import React from 'react'; import { BrowserRouter } from 'react-router-dom'; -import Button from 'components/kit/Button'; -import { useModal } from 'components/kit/Modal'; import { postUser as mockCreateUser } from 'services/api'; import CreateUserModalComponent, { diff --git a/webui/react/src/components/CreateUserModal.tsx b/webui/react/src/components/CreateUserModal.tsx index 597e499e0c7..f7ab56b6454 100644 --- a/webui/react/src/components/CreateUserModal.tsx +++ b/webui/react/src/components/CreateUserModal.tsx @@ -1,13 +1,13 @@ import { Select, Switch, Typography } from 'antd'; +import Form, { hasErrors } from 'determined-ui/Form'; +import Input from 'determined-ui/Input'; +import { Modal } from 'determined-ui/Modal'; +import Spinner from 'determined-ui/Spinner'; +import { makeToast } from 'determined-ui/Toast'; +import { Loadable } from 'determined-ui/utils/loadable'; import { filter } from 'fp-ts/lib/Set'; import React, { useCallback, useEffect, useId, useState } from 'react'; -import Form, { hasErrors } from 'components/kit/Form'; -import Input from 'components/kit/Input'; -import { Modal } from 'components/kit/Modal'; -import Spinner from 'components/kit/Spinner'; -import { makeToast } from 'components/kit/Toast'; -import { Loadable } from 'components/kit/utils/loadable'; import Link from 'components/Link'; import useAuthCheck from 'hooks/useAuthCheck'; import usePermissions from 'hooks/usePermissions'; diff --git a/webui/react/src/components/DeleteGroupModal.test.tsx b/webui/react/src/components/DeleteGroupModal.test.tsx index 35d0122e92d..1c7addf9949 100644 --- a/webui/react/src/components/DeleteGroupModal.test.tsx +++ b/webui/react/src/components/DeleteGroupModal.test.tsx @@ -1,10 +1,10 @@ import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; +import Button from 'determined-ui/Button'; +import { useModal } from 'determined-ui/Modal'; +import { UIProvider } from 'determined-ui/Theme'; import React from 'react'; -import Button from 'components/kit/Button'; -import { useModal } from 'components/kit/Modal'; -import { UIProvider } from 'components/kit/Theme'; import { deleteGroup as mockDeleteGroup } from 'services/api'; import { V1GroupSearchResult } from 'services/api-ts-sdk'; diff --git a/webui/react/src/components/DeleteGroupModal.tsx b/webui/react/src/components/DeleteGroupModal.tsx index 00a466a93ff..fbc4241c0be 100644 --- a/webui/react/src/components/DeleteGroupModal.tsx +++ b/webui/react/src/components/DeleteGroupModal.tsx @@ -1,7 +1,7 @@ +import { Modal } from 'determined-ui/Modal'; +import { makeToast } from 'determined-ui/Toast'; import React from 'react'; -import { Modal } from 'components/kit/Modal'; -import { makeToast } from 'components/kit/Toast'; import { deleteGroup } from 'services/api'; import { V1GroupSearchResult } from 'services/api-ts-sdk'; import handleError, { ErrorType } from 'utils/error'; diff --git a/webui/react/src/components/DeleteModelModal.tsx b/webui/react/src/components/DeleteModelModal.tsx index ace7bb6c89b..9f0e8302aca 100644 --- a/webui/react/src/components/DeleteModelModal.tsx +++ b/webui/react/src/components/DeleteModelModal.tsx @@ -1,4 +1,5 @@ -import { Modal } from 'components/kit/Modal'; +import { Modal } from 'determined-ui/Modal'; + import { paths } from 'routes/utils'; import { deleteModel } from 'services/api'; import { ModelItem } from 'types'; diff --git a/webui/react/src/components/DeterminedAuth.tsx b/webui/react/src/components/DeterminedAuth.tsx index 47665635a58..3867909130d 100644 --- a/webui/react/src/components/DeterminedAuth.tsx +++ b/webui/react/src/components/DeterminedAuth.tsx @@ -1,11 +1,11 @@ import { ConfigProvider } from 'antd'; +import Button from 'determined-ui/Button'; +import Form from 'determined-ui/Form'; +import Icon from 'determined-ui/Icon'; +import Input from 'determined-ui/Input'; +import useUI from 'determined-ui/Theme'; import React, { useCallback, useState } from 'react'; -import Button from 'components/kit/Button'; -import Form from 'components/kit/Form'; -import Icon from 'components/kit/Icon'; -import Input from 'components/kit/Input'; -import useUI from 'components/kit/Theme'; import Link from 'components/Link'; import { paths } from 'routes/utils'; import { login } from 'services/api'; diff --git a/webui/react/src/components/DynamicIcon.tsx b/webui/react/src/components/DynamicIcon.tsx index cd85fc6352f..5b098f310ef 100644 --- a/webui/react/src/components/DynamicIcon.tsx +++ b/webui/react/src/components/DynamicIcon.tsx @@ -1,6 +1,6 @@ +import useUI, { DarkLight } from 'determined-ui/Theme'; import React, { CSSProperties, useMemo } from 'react'; -import useUI, { DarkLight } from 'components/kit/Theme'; import { hex2hsl, hsl2str } from 'utils/color'; import md5 from 'utils/md5'; diff --git a/webui/react/src/components/DynamicTabs.tsx b/webui/react/src/components/DynamicTabs.tsx index 5194d70ddb3..ce7d70bff2c 100644 --- a/webui/react/src/components/DynamicTabs.tsx +++ b/webui/react/src/components/DynamicTabs.tsx @@ -1,10 +1,9 @@ import { TabsProps } from 'antd'; +import Pivot, { PivotTabType } from 'determined-ui/Pivot'; import _ from 'lodash'; import React, { createContext, useCallback, useContext, useEffect, useState } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; -import Pivot, { PivotTabType } from 'components/kit/Pivot'; - interface DynamicTabBarProps extends Omit { basePath: string; type?: PivotTabType; diff --git a/webui/react/src/components/ExperimentActionDropdown.tsx b/webui/react/src/components/ExperimentActionDropdown.tsx index b0d775ca4c2..c57c0a282ce 100644 --- a/webui/react/src/components/ExperimentActionDropdown.tsx +++ b/webui/react/src/components/ExperimentActionDropdown.tsx @@ -1,15 +1,16 @@ import { GridCell } from '@hpe.com/glide-data-grid'; +import Button from 'determined-ui/Button'; +import Dropdown, { DropdownEvent, MenuItem } from 'determined-ui/Dropdown'; +import Icon from 'determined-ui/Icon'; +import { useModal } from 'determined-ui/Modal'; +import { makeToast } from 'determined-ui/Toast'; +import useConfirm from 'determined-ui/useConfirm'; +import { copyToClipboard } from 'determined-ui/utils/functions'; import React, { MouseEvent, useCallback, useMemo } from 'react'; import css from 'components/ActionDropdown/ActionDropdown.module.scss'; import ExperimentEditModalComponent from 'components/ExperimentEditModal'; import ExperimentMoveModalComponent from 'components/ExperimentMoveModal'; -import Button from 'components/kit/Button'; -import Dropdown, { DropdownEvent, MenuItem } from 'components/kit/Dropdown'; -import Icon from 'components/kit/Icon'; -import { copyToClipboard } from 'components/kit/internal/functions'; -import { useModal } from 'components/kit/Modal'; -import { makeToast } from 'components/kit/Toast'; import useModalHyperparameterSearch from 'hooks/useModal/HyperparameterSearch/useModalHyperparameterSearch'; import usePermissions from 'hooks/usePermissions'; import { handlePath } from 'routes/utils'; @@ -29,8 +30,6 @@ import { getActionsForExperiment } from 'utils/experiment'; import { capitalize } from 'utils/string'; import { openCommandResponse } from 'utils/wait'; -import useConfirm from './kit/useConfirm'; - interface Props { children?: React.ReactNode; cell?: GridCell; diff --git a/webui/react/src/components/ExperimentCreateModal.test.tsx b/webui/react/src/components/ExperimentCreateModal.test.tsx index 94336a6b1e6..1f20c7b4375 100644 --- a/webui/react/src/components/ExperimentCreateModal.test.tsx +++ b/webui/react/src/components/ExperimentCreateModal.test.tsx @@ -1,5 +1,7 @@ import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; +import Button from 'determined-ui/Button'; +import { useModal } from 'determined-ui/Modal'; import React from 'react'; import ExperimentCreateModalComponent, { @@ -7,8 +9,6 @@ import ExperimentCreateModalComponent, { FULL_CONFIG_BUTTON_TEXT, SIMPLE_CONFIG_BUTTON_TEXT, } from 'components/ExperimentCreateModal'; -import Button from 'components/kit/Button'; -import { useModal } from 'components/kit/Modal'; import { createExperiment as mockCreateExperiment } from 'services/api'; import { generateTestExperimentData } from 'utils/tests/generateTestData'; diff --git a/webui/react/src/components/ExperimentCreateModal.tsx b/webui/react/src/components/ExperimentCreateModal.tsx index 715f8b92d5b..bbd43e39696 100644 --- a/webui/react/src/components/ExperimentCreateModal.tsx +++ b/webui/react/src/components/ExperimentCreateModal.tsx @@ -1,14 +1,14 @@ +import Button from 'determined-ui/Button'; +import Form, { hasErrors } from 'determined-ui/Form'; +import Input from 'determined-ui/Input'; +import Message from 'determined-ui/Message'; +import { Modal } from 'determined-ui/Modal'; +import Spinner from 'determined-ui/Spinner'; +import { Loaded } from 'determined-ui/utils/loadable'; import yaml from 'js-yaml'; import _ from 'lodash'; import React, { useCallback, useEffect, useId, useState } from 'react'; -import Button from 'components/kit/Button'; -import Form, { hasErrors } from 'components/kit/Form'; -import Input from 'components/kit/Input'; -import Message from 'components/kit/Message'; -import { Modal } from 'components/kit/Modal'; -import Spinner from 'components/kit/Spinner'; -import { Loaded } from 'components/kit/utils/loadable'; import { paths } from 'routes/utils'; import { createExperiment } from 'services/api'; import { V1LaunchWarning } from 'services/api-ts-sdk'; @@ -96,7 +96,7 @@ const trialContinueConfig = ( }; }; -const CodeEditor = React.lazy(() => import('components/kit/CodeEditor')); +const CodeEditor = React.lazy(() => import('determined-ui/CodeEditor')); const DEFAULT_MODAL_STATE = { config: {}, diff --git a/webui/react/src/components/ExperimentDeleteModal.test.tsx b/webui/react/src/components/ExperimentDeleteModal.test.tsx index 05f07f4c0c6..e8e3af73ec1 100644 --- a/webui/react/src/components/ExperimentDeleteModal.test.tsx +++ b/webui/react/src/components/ExperimentDeleteModal.test.tsx @@ -1,10 +1,10 @@ import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; +import Button from 'determined-ui/Button'; +import { useModal } from 'determined-ui/Modal'; import React from 'react'; import ExperimentDeleteModalComponent, { BUTTON_TEXT } from 'components/ExperimentDeleteModal'; -import Button from 'components/kit/Button'; -import { useModal } from 'components/kit/Modal'; import { deleteExperiment as mockDeleteExperiment } from 'services/api'; import { generateTestExperimentData } from 'utils/tests/generateTestData'; diff --git a/webui/react/src/components/ExperimentDeleteModal.tsx b/webui/react/src/components/ExperimentDeleteModal.tsx index e2094aea2e8..3509580e0c0 100644 --- a/webui/react/src/components/ExperimentDeleteModal.tsx +++ b/webui/react/src/components/ExperimentDeleteModal.tsx @@ -1,6 +1,6 @@ +import { Modal } from 'determined-ui/Modal'; import React from 'react'; -import { Modal } from 'components/kit/Modal'; import { paths } from 'routes/utils'; import { deleteExperiment } from 'services/api'; import { ExperimentBase } from 'types'; diff --git a/webui/react/src/components/ExperimentEditModal.test.tsx b/webui/react/src/components/ExperimentEditModal.test.tsx index c200d2e3abc..30ab69b2653 100644 --- a/webui/react/src/components/ExperimentEditModal.test.tsx +++ b/webui/react/src/components/ExperimentEditModal.test.tsx @@ -1,5 +1,7 @@ import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; +import Button from 'determined-ui/Button'; +import { useModal } from 'determined-ui/Modal'; import React from 'react'; import ExperimentEditModalComponent, { @@ -7,8 +9,6 @@ import ExperimentEditModalComponent, { DESCRIPTION_LABEL, NAME_LABEL, } from 'components/ExperimentEditModal'; -import Button from 'components/kit/Button'; -import { useModal } from 'components/kit/Modal'; import { patchExperiment as mockPatchExperiment } from 'services/api'; import { generateTestExperimentData } from 'utils/tests/generateTestData'; diff --git a/webui/react/src/components/ExperimentEditModal.tsx b/webui/react/src/components/ExperimentEditModal.tsx index 2703bce09e8..be299488252 100644 --- a/webui/react/src/components/ExperimentEditModal.tsx +++ b/webui/react/src/components/ExperimentEditModal.tsx @@ -1,8 +1,8 @@ +import Form, { hasErrors } from 'determined-ui/Form'; +import Input from 'determined-ui/Input'; +import { Modal } from 'determined-ui/Modal'; import React, { useId, useState } from 'react'; -import Form, { hasErrors } from 'components/kit/Form'; -import Input from 'components/kit/Input'; -import { Modal } from 'components/kit/Modal'; import { patchExperiment } from 'services/api'; import { ExperimentItem } from 'types'; import handleError from 'utils/error'; diff --git a/webui/react/src/components/ExperimentIcons.tsx b/webui/react/src/components/ExperimentIcons.tsx index 931ad1a645f..773fc92a22e 100644 --- a/webui/react/src/components/ExperimentIcons.tsx +++ b/webui/react/src/components/ExperimentIcons.tsx @@ -1,6 +1,6 @@ +import Icon, { Props as IconProps, IconSize } from 'determined-ui/Icon'; import React, { useMemo } from 'react'; -import Icon, { Props as IconProps, IconSize } from 'components/kit/Icon'; import { stateToLabel } from 'constants/states'; import { CompoundRunState, JobState, RunState } from 'types'; diff --git a/webui/react/src/components/ExperimentMoveModal.tsx b/webui/react/src/components/ExperimentMoveModal.tsx index 0635dcfceb1..c12a74033a0 100644 --- a/webui/react/src/components/ExperimentMoveModal.tsx +++ b/webui/react/src/components/ExperimentMoveModal.tsx @@ -1,14 +1,14 @@ import { Typography } from 'antd'; +import Form from 'determined-ui/Form'; +import Icon from 'determined-ui/Icon'; +import { Modal } from 'determined-ui/Modal'; +import Select, { Option } from 'determined-ui/Select'; +import Spinner from 'determined-ui/Spinner'; +import { makeToast } from 'determined-ui/Toast'; +import { Loadable } from 'determined-ui/utils/loadable'; import { useObservable } from 'micro-observables'; import React, { useEffect, useId, useState } from 'react'; -import Form from 'components/kit/Form'; -import Icon from 'components/kit/Icon'; -import { Modal } from 'components/kit/Modal'; -import Select, { Option } from 'components/kit/Select'; -import Spinner from 'components/kit/Spinner'; -import { makeToast } from 'components/kit/Toast'; -import { Loadable } from 'components/kit/utils/loadable'; import Link from 'components/Link'; import usePermissions from 'hooks/usePermissions'; import { paths } from 'routes/utils'; diff --git a/webui/react/src/components/ExperimentStopModal.test.tsx b/webui/react/src/components/ExperimentStopModal.test.tsx index 5365e8e4e92..067899201ed 100644 --- a/webui/react/src/components/ExperimentStopModal.test.tsx +++ b/webui/react/src/components/ExperimentStopModal.test.tsx @@ -1,13 +1,13 @@ import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; +import Button from 'determined-ui/Button'; +import { useModal } from 'determined-ui/Modal'; import React from 'react'; import ExperimentStopModalComponent, { BUTTON_TEXT, CHECKBOX_TEXT, } from 'components/ExperimentStopModal'; -import Button from 'components/kit/Button'; -import { useModal } from 'components/kit/Modal'; import { cancelExperiment as mockCancelExperiment, killExperiment as mockKillExperiment, diff --git a/webui/react/src/components/ExperimentStopModal.tsx b/webui/react/src/components/ExperimentStopModal.tsx index 479abe1ea2d..5179576a10c 100644 --- a/webui/react/src/components/ExperimentStopModal.tsx +++ b/webui/react/src/components/ExperimentStopModal.tsx @@ -1,9 +1,9 @@ import { CheckboxChangeEvent } from 'antd/lib/checkbox'; +import Checkbox from 'determined-ui/Checkbox'; +import Message from 'determined-ui/Message'; +import { Modal } from 'determined-ui/Modal'; import React, { useState } from 'react'; -import Checkbox from 'components/kit/Checkbox'; -import Message from 'components/kit/Message'; -import { Modal } from 'components/kit/Modal'; import { cancelExperiment, killExperiment } from 'services/api'; import { ExperimentAction, ValueOf } from 'types'; import handleError, { ErrorLevel, ErrorType } from 'utils/error'; diff --git a/webui/react/src/components/ExperimentTensorBoardModal.tsx b/webui/react/src/components/ExperimentTensorBoardModal.tsx index 54be0234a2e..47038e0090d 100644 --- a/webui/react/src/components/ExperimentTensorBoardModal.tsx +++ b/webui/react/src/components/ExperimentTensorBoardModal.tsx @@ -1,4 +1,5 @@ -import { Modal } from 'components/kit/Modal'; +import { Modal } from 'determined-ui/Modal'; + import { UNMANAGED_EXPERIMENT_ANNOTATION_MESSAGE } from 'constant'; import { openOrCreateTensorBoard } from 'services/api'; import { V1BulkExperimentFilters } from 'services/api-ts-sdk'; diff --git a/webui/react/src/components/FilterCounter.tsx b/webui/react/src/components/FilterCounter.tsx index abd26dd5e0c..3b94eaf1310 100644 --- a/webui/react/src/components/FilterCounter.tsx +++ b/webui/react/src/components/FilterCounter.tsx @@ -1,6 +1,6 @@ +import Button from 'determined-ui/Button'; import React from 'react'; -import Button from 'components/kit/Button'; interface Props { activeFilterCount: number; onReset: () => void; diff --git a/webui/react/src/components/FilterForm/TableFilter.tsx b/webui/react/src/components/FilterForm/TableFilter.tsx index bb3435956f2..27234851fd7 100644 --- a/webui/react/src/components/FilterForm/TableFilter.tsx +++ b/webui/react/src/components/FilterForm/TableFilter.tsx @@ -1,13 +1,13 @@ +import Button from 'determined-ui/Button'; +import Dropdown from 'determined-ui/Dropdown'; +import Icon from 'determined-ui/Icon'; +import { Loadable } from 'determined-ui/utils/loadable'; import { useObservable } from 'micro-observables'; import { useCallback } from 'react'; import FilterForm from 'components/FilterForm/components/FilterForm'; import { FilterFormStore } from 'components/FilterForm/components/FilterFormStore'; import { FormKind } from 'components/FilterForm/components/type'; -import Button from 'components/kit/Button'; -import Dropdown from 'components/kit/Dropdown'; -import Icon from 'components/kit/Icon'; -import { Loadable } from 'components/kit/utils/loadable'; import { V1ProjectColumn } from 'services/api-ts-sdk'; interface Props { diff --git a/webui/react/src/components/FilterForm/components/ConjunctionContainer.tsx b/webui/react/src/components/FilterForm/components/ConjunctionContainer.tsx index 4cc27ea2052..09864222304 100644 --- a/webui/react/src/components/FilterForm/components/ConjunctionContainer.tsx +++ b/webui/react/src/components/FilterForm/components/ConjunctionContainer.tsx @@ -1,5 +1,6 @@ +import Select, { Option, SelectValue } from 'determined-ui/Select'; + import { Conjunction } from 'components/FilterForm/components/type'; -import Select, { Option, SelectValue } from 'components/kit/Select'; import css from './ConjunctionContainer.module.scss'; diff --git a/webui/react/src/components/FilterForm/components/FilterField.tsx b/webui/react/src/components/FilterForm/components/FilterField.tsx index 80802f03f36..e7f449ceb68 100644 --- a/webui/react/src/components/FilterForm/components/FilterField.tsx +++ b/webui/react/src/components/FilterForm/components/FilterField.tsx @@ -1,6 +1,13 @@ import { type SelectProps as AntdSelectProps } from 'antd'; import type { DatePickerProps } from 'antd/es/date-picker'; import dayjs from 'dayjs'; +import Button from 'determined-ui/Button'; +import DatePicker from 'determined-ui/DatePicker'; +import Icon from 'determined-ui/Icon'; +import Input from 'determined-ui/Input'; +import InputNumber from 'determined-ui/InputNumber'; +import Select, { SelectValue } from 'determined-ui/Select'; +import { Loadable } from 'determined-ui/utils/loadable'; import { useObservable } from 'micro-observables'; import { useCallback, useState } from 'react'; import { useDrag, useDrop } from 'react-dnd'; @@ -21,13 +28,6 @@ import { SEARCHER_TYPE, SpecialColumnNames, } from 'components/FilterForm/components/type'; -import Button from 'components/kit/Button'; -import DatePicker from 'components/kit/DatePicker'; -import Icon from 'components/kit/Icon'; -import Input from 'components/kit/Input'; -import InputNumber from 'components/kit/InputNumber'; -import Select, { SelectValue } from 'components/kit/Select'; -import { Loadable } from 'components/kit/utils/loadable'; import { V1ColumnType, V1ProjectColumn } from 'services/api-ts-sdk'; import clusterStore from 'stores/cluster'; import userStore from 'stores/users'; diff --git a/webui/react/src/components/FilterForm/components/FilterForm.tsx b/webui/react/src/components/FilterForm/components/FilterForm.tsx index 3af34a575f5..3e2fbe08449 100644 --- a/webui/react/src/components/FilterForm/components/FilterForm.tsx +++ b/webui/react/src/components/FilterForm/components/FilterForm.tsx @@ -1,13 +1,13 @@ +import Button from 'determined-ui/Button'; +import Spinner from 'determined-ui/Spinner'; +import Toggle from 'determined-ui/Toggle'; +import { Loadable } from 'determined-ui/utils/loadable'; import { useObservable } from 'micro-observables'; import { useRef } from 'react'; import { FilterFormStore, ITEM_LIMIT } from 'components/FilterForm/components/FilterFormStore'; import FilterGroup from 'components/FilterForm/components/FilterGroup'; import { FormKind } from 'components/FilterForm/components/type'; -import Button from 'components/kit/Button'; -import Spinner from 'components/kit/Spinner'; -import Toggle from 'components/kit/Toggle'; -import { Loadable } from 'components/kit/utils/loadable'; import { V1ProjectColumn } from 'services/api-ts-sdk'; import css from './FilterForm.module.scss'; diff --git a/webui/react/src/components/FilterForm/components/FilterFormStore.test.ts b/webui/react/src/components/FilterForm/components/FilterFormStore.test.ts index f48e60f450f..e4a49308297 100644 --- a/webui/react/src/components/FilterForm/components/FilterFormStore.test.ts +++ b/webui/react/src/components/FilterForm/components/FilterFormStore.test.ts @@ -1,3 +1,5 @@ +import { Loadable, NotLoaded } from 'determined-ui/utils/loadable'; + import { FilterFormStore } from 'components/FilterForm/components/FilterFormStore'; import { Conjunction, @@ -7,7 +9,6 @@ import { FormKind, Operator, } from 'components/FilterForm/components/type'; -import { Loadable, NotLoaded } from 'components/kit/utils/loadable'; import { V1ColumnType, V1LocationType, V1ProjectColumn } from 'services/api-ts-sdk'; // Remove `id` property from object diff --git a/webui/react/src/components/FilterForm/components/FilterFormStore.ts b/webui/react/src/components/FilterForm/components/FilterFormStore.ts index d5ed971c352..a078bbc489b 100644 --- a/webui/react/src/components/FilterForm/components/FilterFormStore.ts +++ b/webui/react/src/components/FilterForm/components/FilterFormStore.ts @@ -1,3 +1,4 @@ +import { Loadable, Loaded, NotLoaded } from 'determined-ui/utils/loadable'; import { observable, Observable, WritableObservable } from 'micro-observables'; import { v4 as uuidv4 } from 'uuid'; @@ -12,7 +13,6 @@ import { FormKind, Operator, } from 'components/FilterForm/components/type'; -import { Loadable, Loaded, NotLoaded } from 'components/kit/utils/loadable'; import { V1ColumnType, V1LocationType, V1ProjectColumn } from 'services/api-ts-sdk'; export const ITEM_LIMIT = 50; diff --git a/webui/react/src/components/FilterForm/components/FilterGroup.tsx b/webui/react/src/components/FilterForm/components/FilterGroup.tsx index 6cd2e5f2f12..f18697670c9 100644 --- a/webui/react/src/components/FilterForm/components/FilterGroup.tsx +++ b/webui/react/src/components/FilterForm/components/FilterGroup.tsx @@ -1,4 +1,6 @@ import { Dropdown, DropDownProps, type MenuProps } from 'antd'; +import Button from 'determined-ui/Button'; +import Icon from 'determined-ui/Icon'; import { useMemo, useRef } from 'react'; import { useDrag, useDrop } from 'react-dnd'; @@ -6,8 +8,6 @@ import ConjunctionContainer from 'components/FilterForm/components/ConjunctionCo import FilterField from 'components/FilterForm/components/FilterField'; import { FilterFormStore, ITEM_LIMIT } from 'components/FilterForm/components/FilterFormStore'; import { Conjunction, FormField, FormGroup, FormKind } from 'components/FilterForm/components/type'; -import Button from 'components/kit/Button'; -import Icon from 'components/kit/Icon'; import { V1ProjectColumn } from 'services/api-ts-sdk'; import css from './FilterGroup.module.scss'; diff --git a/webui/react/src/components/GalleryModal.tsx b/webui/react/src/components/GalleryModal.tsx index c01701f0b48..0b798d28e4a 100644 --- a/webui/react/src/components/GalleryModal.tsx +++ b/webui/react/src/components/GalleryModal.tsx @@ -1,9 +1,9 @@ import { Modal } from 'antd'; import { ModalProps } from 'antd/es/modal/Modal'; +import Button from 'determined-ui/Button'; +import Icon from 'determined-ui/Icon'; import React, { useCallback, useEffect, useState } from 'react'; -import Button from 'components/kit/Button'; -import Icon from 'components/kit/Icon'; import { keyEmitter, KeyEvent } from 'hooks/useKeyTracker'; import useResize from 'hooks/useResize'; import { isNumber } from 'utils/data'; diff --git a/webui/react/src/components/Grid.tsx b/webui/react/src/components/Grid.tsx index 3ab7b619c9d..4ab03ea0051 100644 --- a/webui/react/src/components/Grid.tsx +++ b/webui/react/src/components/Grid.tsx @@ -1,6 +1,6 @@ +import { ShirtSize } from 'determined-ui/Theme'; import React from 'react'; -import { ShirtSize } from 'components/kit/Theme'; import { ValueOf } from 'types'; import { isNumber } from 'utils/data'; diff --git a/webui/react/src/components/HpSelect.tsx b/webui/react/src/components/HpSelect.tsx index 4b976bdd96f..e80bd280cae 100644 --- a/webui/react/src/components/HpSelect.tsx +++ b/webui/react/src/components/HpSelect.tsx @@ -1,7 +1,7 @@ import { DefaultOptionType, LabeledValue, SelectValue } from 'antd/es/select'; +import Select, { Option, SelectProps } from 'determined-ui/Select'; import React, { useCallback, useMemo } from 'react'; -import Select, { Option, SelectProps } from 'components/kit/Select'; import { ALL_VALUE } from 'types'; import { isObject } from 'utils/data'; diff --git a/webui/react/src/components/HumanReadableNumber.tsx b/webui/react/src/components/HumanReadableNumber.tsx index a32f13f6372..d5ea2395bff 100644 --- a/webui/react/src/components/HumanReadableNumber.tsx +++ b/webui/react/src/components/HumanReadableNumber.tsx @@ -1,6 +1,6 @@ +import Tooltip from 'determined-ui/Tooltip'; import React from 'react'; -import Tooltip from 'components/kit/Tooltip'; import { CommonProps } from 'types'; import { humanReadableNumber } from 'utils/number'; diff --git a/webui/react/src/components/Image/Image.test.tsx b/webui/react/src/components/Image/Image.test.tsx index 725d0cb062b..3a365ef0da0 100644 --- a/webui/react/src/components/Image/Image.test.tsx +++ b/webui/react/src/components/Image/Image.test.tsx @@ -1,6 +1,5 @@ import { render, screen } from '@testing-library/react'; - -import { DarkLight } from 'components/kit/Theme'; +import { DarkLight } from 'determined-ui/Theme'; import { ImageAlert, ImageEmpty, ImageWarning, type Props } from './Image'; diff --git a/webui/react/src/components/Image/Image.tsx b/webui/react/src/components/Image/Image.tsx index 60db5e3e070..f16cca12017 100644 --- a/webui/react/src/components/Image/Image.tsx +++ b/webui/react/src/components/Image/Image.tsx @@ -1,7 +1,6 @@ +import { DarkLight } from 'determined-ui/Theme'; import React from 'react'; -import { DarkLight } from 'components/kit/Theme'; - import css from './Image.module.scss'; export interface Props { diff --git a/webui/react/src/components/JupyterLabButton.tsx b/webui/react/src/components/JupyterLabButton.tsx index dcd7f9aef9a..df1840206ef 100644 --- a/webui/react/src/components/JupyterLabButton.tsx +++ b/webui/react/src/components/JupyterLabButton.tsx @@ -1,10 +1,10 @@ +import Button from 'determined-ui/Button'; +import { shortcutToString } from 'determined-ui/InputShortcut'; +import { useModal } from 'determined-ui/Modal'; +import Tooltip from 'determined-ui/Tooltip'; import React from 'react'; import JupyterLabModalComponent from 'components/JupyterLabModal'; -import Button from 'components/kit/Button'; -import { shortcutToString } from 'components/kit/InputShortcut'; -import { useModal } from 'components/kit/Modal'; -import Tooltip from 'components/kit/Tooltip'; import shortCutSettingsConfig, { Settings as ShortcutSettings, } from 'components/UserSettings.settings'; diff --git a/webui/react/src/components/JupyterLabGlobal.tsx b/webui/react/src/components/JupyterLabGlobal.tsx index 0a12b474d7d..0d24ed0de65 100644 --- a/webui/react/src/components/JupyterLabGlobal.tsx +++ b/webui/react/src/components/JupyterLabGlobal.tsx @@ -1,8 +1,8 @@ +import { matchesShortcut } from 'determined-ui/InputShortcut'; +import { useModal } from 'determined-ui/Modal'; import React, { useEffect } from 'react'; import JupyterLabModalComponent from 'components/JupyterLabModal'; -import { matchesShortcut } from 'components/kit/InputShortcut'; -import { useModal } from 'components/kit/Modal'; import shortCutSettingsConfig, { Settings as ShortcutSettings, } from 'components/UserSettings.settings'; diff --git a/webui/react/src/components/JupyterLabModal.test.tsx b/webui/react/src/components/JupyterLabModal.test.tsx index 3dc834699a4..e834ca871da 100644 --- a/webui/react/src/components/JupyterLabModal.test.tsx +++ b/webui/react/src/components/JupyterLabModal.test.tsx @@ -1,12 +1,12 @@ import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; +import Button from 'determined-ui/Button'; +import { useModal } from 'determined-ui/Modal'; +import { UIProvider } from 'determined-ui/Theme'; import React, { useEffect } from 'react'; import { BrowserRouter } from 'react-router-dom'; import JupyterLabModalComponent from 'components/JupyterLabModal'; -import Button from 'components/kit/Button'; -import { useModal } from 'components/kit/Modal'; -import { UIProvider } from 'components/kit/Theme'; import { SettingsProvider } from 'hooks/useSettingsProvider'; import authStore from 'stores/auth'; import { WorkspaceState } from 'types'; @@ -29,7 +29,7 @@ vi.mock('services/api', () => ({ })); vi.mock('stores/cluster', async (importOriginal) => { - const loadable = await import('components/kit/utils/loadable'); + const loadable = await import('determined-ui/utils/loadable'); const observable = await import('utils/observable'); const store = { resourcePools: observable.observable(loadable.Loaded([])) }; @@ -45,7 +45,7 @@ vi.mock('utils/wait', () => ({ waitPageUrl: () => '', })); -vi.mock('components/kit/CodeEditor', () => ({ +vi.mock('determined-ui/CodeEditor', () => ({ __esModule: true, default: () => <>, })); diff --git a/webui/react/src/components/JupyterLabModal.tsx b/webui/react/src/components/JupyterLabModal.tsx index ce67d758b3c..6e934e9118a 100644 --- a/webui/react/src/components/JupyterLabModal.tsx +++ b/webui/react/src/components/JupyterLabModal.tsx @@ -1,16 +1,16 @@ import { Select } from 'antd'; +import Button from 'determined-ui/Button'; +import Form, { FormInstance } from 'determined-ui/Form'; +import Input from 'determined-ui/Input'; +import InputNumber from 'determined-ui/InputNumber'; +import Message from 'determined-ui/Message'; +import { Modal } from 'determined-ui/Modal'; +import Spinner from 'determined-ui/Spinner'; +import { Loadable, Loaded, NotLoaded } from 'determined-ui/utils/loadable'; import { number, string, undefined as undefinedType, union } from 'io-ts'; import yaml from 'js-yaml'; import React, { useCallback, useEffect, useId, useMemo, useState } from 'react'; -import Button from 'components/kit/Button'; -import Form, { FormInstance } from 'components/kit/Form'; -import Input from 'components/kit/Input'; -import InputNumber from 'components/kit/InputNumber'; -import Message from 'components/kit/Message'; -import { Modal } from 'components/kit/Modal'; -import Spinner from 'components/kit/Spinner'; -import { Loadable, Loaded, NotLoaded } from 'components/kit/utils/loadable'; import Link from 'components/Link'; import usePermissions from 'hooks/usePermissions'; import { SettingsConfig, useSettings } from 'hooks/useSettings'; @@ -81,7 +81,7 @@ interface Props { workspace?: Workspace; } -const CodeEditor = React.lazy(() => import('components/kit/CodeEditor')); +const CodeEditor = React.lazy(() => import('determined-ui/CodeEditor')); const JupyterLabModalComponent: React.FC = ({ workspace }: Props) => { const idPrefix = useId(); diff --git a/webui/react/src/components/Link.tsx b/webui/react/src/components/Link.tsx index afc392cc7d6..f979e301d6c 100644 --- a/webui/react/src/components/Link.tsx +++ b/webui/react/src/components/Link.tsx @@ -1,6 +1,6 @@ +import Button from 'determined-ui/Button'; import React, { CSSProperties, MouseEvent, useCallback } from 'react'; -import Button from 'components/kit/Button'; import { handlePath, linkPath } from 'routes/utils'; import { AnyMouseEventHandler, windowOpenFeatures } from 'utils/routes'; diff --git a/webui/react/src/components/LoadingWrapper.tsx b/webui/react/src/components/LoadingWrapper.tsx index fa9eba8bcf2..6b9c8cd3ec7 100644 --- a/webui/react/src/components/LoadingWrapper.tsx +++ b/webui/react/src/components/LoadingWrapper.tsx @@ -1,7 +1,7 @@ import { Skeleton, SkeletonProps } from 'antd'; +import Message, { Props as MessageProps } from 'determined-ui/Message'; import React, { useMemo } from 'react'; -import Message, { Props as MessageProps } from 'components/kit/Message'; import { ValueOf } from 'types'; import { isObject, validateEnum } from 'utils/data'; diff --git a/webui/react/src/components/Logo.tsx b/webui/react/src/components/Logo.tsx index c8449fcbc14..fe62952cf61 100644 --- a/webui/react/src/components/Logo.tsx +++ b/webui/react/src/components/Logo.tsx @@ -1,3 +1,4 @@ +import useUI, { DarkLight } from 'determined-ui/Theme'; import React, { useMemo } from 'react'; import logoDeterminedOnDarkHorizontal from 'assets/images/logo-determined-on-dark-horizontal.svg?url'; @@ -6,7 +7,6 @@ import logoDeterminedOnLightHorizontal from 'assets/images/logo-determined-on-li import logoDeterminedOnLightVertical from 'assets/images/logo-determined-on-light-vertical.svg?url'; import logoHpeOnDarkHorizontal from 'assets/images/logo-hpe-on-dark-horizontal.svg?url'; import logoHpeOnLightHorizontal from 'assets/images/logo-hpe-on-light-horizontal.svg?url'; -import useUI, { DarkLight } from 'components/kit/Theme'; import { serverAddress } from 'routes/utils'; import { BrandingType } from 'stores/determinedInfo'; import { ValueOf } from 'types'; diff --git a/webui/react/src/components/ManageGroupsModal.tsx b/webui/react/src/components/ManageGroupsModal.tsx index 87cd4fb9b13..58bb206ee0a 100644 --- a/webui/react/src/components/ManageGroupsModal.tsx +++ b/webui/react/src/components/ManageGroupsModal.tsx @@ -1,10 +1,10 @@ import { Select } from 'antd'; +import Form from 'determined-ui/Form'; +import { Modal } from 'determined-ui/Modal'; +import Spinner from 'determined-ui/Spinner'; +import { makeToast } from 'determined-ui/Toast'; import React, { useEffect, useId } from 'react'; -import Form from 'components/kit/Form'; -import { Modal } from 'components/kit/Modal'; -import Spinner from 'components/kit/Spinner'; -import { makeToast } from 'components/kit/Toast'; import { updateGroup } from 'services/api'; import { V1GroupSearchResult } from 'services/api-ts-sdk'; import determinedStore from 'stores/determinedInfo'; diff --git a/webui/react/src/components/Markdown.tsx b/webui/react/src/components/Markdown.tsx index 1da4b528f65..41414535619 100644 --- a/webui/react/src/components/Markdown.tsx +++ b/webui/react/src/components/Markdown.tsx @@ -1,16 +1,16 @@ import type { TabsProps } from 'antd'; +import Pivot from 'determined-ui/Pivot'; +import Spinner from 'determined-ui/Spinner'; +import { Loaded } from 'determined-ui/utils/loadable'; import { default as MarkdownViewer } from 'markdown-to-jsx'; import React, { useMemo } from 'react'; -import Pivot from 'components/kit/Pivot'; -import Spinner from 'components/kit/Spinner'; -import { Loaded } from 'components/kit/utils/loadable'; import useResize from 'hooks/useResize'; import handleError from 'utils/error'; import css from './Markdown.module.scss'; -const CodeEditor = React.lazy(() => import('components/kit/CodeEditor')); +const CodeEditor = React.lazy(() => import('determined-ui/CodeEditor')); interface Props { disabled?: boolean; diff --git a/webui/react/src/components/Metadata/EditableMetadata.tsx b/webui/react/src/components/Metadata/EditableMetadata.tsx index e5a81ca38c5..ccfa32c8b9d 100644 --- a/webui/react/src/components/Metadata/EditableMetadata.tsx +++ b/webui/react/src/components/Metadata/EditableMetadata.tsx @@ -1,7 +1,7 @@ +import Form from 'determined-ui/Form'; import React, { useCallback, useEffect, useMemo } from 'react'; import InfoBox, { InfoRow } from 'components/InfoBox'; -import Form from 'components/kit/Form'; import Link from 'components/Link'; import { Metadata } from 'types'; diff --git a/webui/react/src/components/Metadata/EditableRow.tsx b/webui/react/src/components/Metadata/EditableRow.tsx index 2a15b005499..dc734ad60bb 100644 --- a/webui/react/src/components/Metadata/EditableRow.tsx +++ b/webui/react/src/components/Metadata/EditableRow.tsx @@ -1,11 +1,10 @@ +import Button from 'determined-ui/Button'; +import Dropdown from 'determined-ui/Dropdown'; +import Form, { FormListFieldData } from 'determined-ui/Form'; +import Icon from 'determined-ui/Icon'; +import Input from 'determined-ui/Input'; import React, { useCallback } from 'react'; -import Button from 'components/kit/Button'; -import Dropdown from 'components/kit/Dropdown'; -import Form, { FormListFieldData } from 'components/kit/Form'; -import Icon from 'components/kit/Icon'; -import Input from 'components/kit/Input'; - import css from './EditableRow.module.scss'; export const METADATA_KEY_PLACEHOLDER = 'Enter metadata label'; diff --git a/webui/react/src/components/Metadata/MetadataCard.tsx b/webui/react/src/components/Metadata/MetadataCard.tsx index 0c174429f37..a6a44b003e8 100644 --- a/webui/react/src/components/Metadata/MetadataCard.tsx +++ b/webui/react/src/components/Metadata/MetadataCard.tsx @@ -1,9 +1,9 @@ import { Card, Space } from 'antd'; +import Button from 'determined-ui/Button'; +import Icon from 'determined-ui/Icon'; +import Spinner from 'determined-ui/Spinner'; import React, { useCallback, useMemo, useState } from 'react'; -import Button from 'components/kit/Button'; -import Icon from 'components/kit/Icon'; -import Spinner from 'components/kit/Spinner'; import { Metadata } from 'types'; import handleError, { ErrorType } from 'utils/error'; diff --git a/webui/react/src/components/MetricBadgeTag.test.tsx b/webui/react/src/components/MetricBadgeTag.test.tsx index 40a565e1824..45a10a81edf 100644 --- a/webui/react/src/components/MetricBadgeTag.test.tsx +++ b/webui/react/src/components/MetricBadgeTag.test.tsx @@ -1,11 +1,11 @@ import { fireEvent, render, screen } from '@testing-library/react'; +import { UIProvider } from 'determined-ui/Theme'; -import { UIProvider } from 'components/kit/Theme'; import { Metric } from 'types'; import MetricBadgeTag from './MetricBadgeTag'; -vi.mock('components/kit/Tooltip'); +vi.mock('determined-ui/Tooltip'); const setup = (metric: Metric) => { const handleOnChange = vi.fn(); diff --git a/webui/react/src/components/MetricSelect.tsx b/webui/react/src/components/MetricSelect.tsx index 7ff0cc6482a..1f756d67855 100644 --- a/webui/react/src/components/MetricSelect.tsx +++ b/webui/react/src/components/MetricSelect.tsx @@ -1,7 +1,7 @@ import { RefSelectProps } from 'antd/es/select'; +import Select, { OptGroup, Option, SelectValue } from 'determined-ui/Select'; import React, { useCallback, useMemo, useRef, useState } from 'react'; -import Select, { OptGroup, Option, SelectValue } from 'components/kit/Select'; import { Metric } from 'types'; import { metricKeyToMetric, metricSorter, metricToKey } from 'utils/metric'; diff --git a/webui/react/src/components/ModelActionDropdown.tsx b/webui/react/src/components/ModelActionDropdown.tsx index 6dda4ede8ea..9c2125aeed4 100644 --- a/webui/react/src/components/ModelActionDropdown.tsx +++ b/webui/react/src/components/ModelActionDropdown.tsx @@ -1,8 +1,8 @@ +import Dropdown, { MenuItem } from 'determined-ui/Dropdown'; +import { useModal } from 'determined-ui/Modal'; import React, { useCallback } from 'react'; import DeleteModelModal from 'components/DeleteModelModal'; -import Dropdown, { MenuItem } from 'components/kit/Dropdown'; -import { useModal } from 'components/kit/Modal'; import ModelMoveModal from 'components/ModelMoveModal'; import usePermissions from 'hooks/usePermissions'; import { archiveModel, unarchiveModel } from 'services/api'; diff --git a/webui/react/src/components/ModelCreateModal.tsx b/webui/react/src/components/ModelCreateModal.tsx index 7b080ca0ab7..bf09ebc00df 100644 --- a/webui/react/src/components/ModelCreateModal.tsx +++ b/webui/react/src/components/ModelCreateModal.tsx @@ -1,14 +1,14 @@ +import Button from 'determined-ui/Button'; +import Form from 'determined-ui/Form'; +import Icon from 'determined-ui/Icon'; +import Input from 'determined-ui/Input'; +import { Modal } from 'determined-ui/Modal'; +import Select from 'determined-ui/Select'; +import { makeToast } from 'determined-ui/Toast'; +import { Loadable } from 'determined-ui/utils/loadable'; import { useObservable } from 'micro-observables'; import { useId, useState } from 'react'; -import Button from 'components/kit/Button'; -import Form from 'components/kit/Form'; -import Icon from 'components/kit/Icon'; -import Input from 'components/kit/Input'; -import { Modal } from 'components/kit/Modal'; -import Select from 'components/kit/Select'; -import { makeToast } from 'components/kit/Toast'; -import { Loadable } from 'components/kit/utils/loadable'; import Link from 'components/Link'; import { ModalCloseReason } from 'hooks/useModal/useModal'; import usePermissions from 'hooks/usePermissions'; diff --git a/webui/react/src/components/ModelDownloadModal.tsx b/webui/react/src/components/ModelDownloadModal.tsx index 0a33ed52ff7..62b743e8a6e 100644 --- a/webui/react/src/components/ModelDownloadModal.tsx +++ b/webui/react/src/components/ModelDownloadModal.tsx @@ -1,5 +1,6 @@ -import ClipboardButton from 'components/kit/ClipboardButton'; -import { Modal } from 'components/kit/Modal'; +import ClipboardButton from 'determined-ui/ClipboardButton'; +import { Modal } from 'determined-ui/Modal'; + import { ModelVersion } from 'types'; import css from './ModelDownloadModal.module.scss'; diff --git a/webui/react/src/components/ModelEditModal.tsx b/webui/react/src/components/ModelEditModal.tsx index 57f54599828..9243ea0425e 100644 --- a/webui/react/src/components/ModelEditModal.tsx +++ b/webui/react/src/components/ModelEditModal.tsx @@ -1,8 +1,8 @@ +import Form from 'determined-ui/Form'; +import Input from 'determined-ui/Input'; +import { Modal } from 'determined-ui/Modal'; import { useId } from 'react'; -import Form from 'components/kit/Form'; -import Input from 'components/kit/Input'; -import { Modal } from 'components/kit/Modal'; import { patchModel } from 'services/api'; import { ModelItem } from 'types'; import handleError from 'utils/error'; diff --git a/webui/react/src/components/ModelMoveModal.tsx b/webui/react/src/components/ModelMoveModal.tsx index 068157ea2a9..b5d7d53d772 100644 --- a/webui/react/src/components/ModelMoveModal.tsx +++ b/webui/react/src/components/ModelMoveModal.tsx @@ -1,11 +1,11 @@ +import Form from 'determined-ui/Form'; +import { Modal } from 'determined-ui/Modal'; +import Select from 'determined-ui/Select'; +import { makeToast } from 'determined-ui/Toast'; +import { Loadable } from 'determined-ui/utils/loadable'; import { useObservable } from 'micro-observables'; import { useId } from 'react'; -import Form from 'components/kit/Form'; -import { Modal } from 'components/kit/Modal'; -import Select from 'components/kit/Select'; -import { makeToast } from 'components/kit/Toast'; -import { Loadable } from 'components/kit/utils/loadable'; import Link from 'components/Link'; import usePermissions from 'hooks/usePermissions'; import { WorkspaceDetailsTab } from 'pages/WorkspaceDetails'; diff --git a/webui/react/src/components/ModelRegistry.tsx b/webui/react/src/components/ModelRegistry.tsx index c13826a487c..973df74c105 100644 --- a/webui/react/src/components/ModelRegistry.tsx +++ b/webui/react/src/components/ModelRegistry.tsx @@ -5,22 +5,22 @@ import { SorterResult, TablePaginationConfig, } from 'antd/lib/table/interface'; +import Button from 'determined-ui/Button'; +import Dropdown, { MenuItem } from 'determined-ui/Dropdown'; +import Icon from 'determined-ui/Icon'; +import Input from 'determined-ui/Input'; +import Message from 'determined-ui/Message'; +import { useModal } from 'determined-ui/Modal'; +import Tags, { tagsActionHelper } from 'determined-ui/Tags'; +import Toggle from 'determined-ui/Toggle'; +import Tooltip from 'determined-ui/Tooltip'; +import { Loadable } from 'determined-ui/utils/loadable'; import _ from 'lodash'; import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import DeleteModelModal from 'components/DeleteModelModal'; import DynamicIcon from 'components/DynamicIcon'; import FilterCounter from 'components/FilterCounter'; -import Button from 'components/kit/Button'; -import Dropdown, { MenuItem } from 'components/kit/Dropdown'; -import Icon from 'components/kit/Icon'; -import Input from 'components/kit/Input'; -import Message from 'components/kit/Message'; -import { useModal } from 'components/kit/Modal'; -import Tags, { tagsActionHelper } from 'components/kit/Tags'; -import Toggle from 'components/kit/Toggle'; -import Tooltip from 'components/kit/Tooltip'; -import { Loadable } from 'components/kit/utils/loadable'; import Link from 'components/Link'; import { ModelActionMenuKey as MenuKey, ModelActionDropdown } from 'components/ModelActionDropdown'; import ModelCreateModal from 'components/ModelCreateModal'; diff --git a/webui/react/src/components/ModelVersionDeleteModal.tsx b/webui/react/src/components/ModelVersionDeleteModal.tsx index 37a819aa9cc..37a79ffb478 100644 --- a/webui/react/src/components/ModelVersionDeleteModal.tsx +++ b/webui/react/src/components/ModelVersionDeleteModal.tsx @@ -1,4 +1,5 @@ -import { Modal } from 'components/kit/Modal'; +import { Modal } from 'determined-ui/Modal'; + import { paths } from 'routes/utils'; import { deleteModelVersion } from 'services/api'; import { ModelVersion } from 'types'; diff --git a/webui/react/src/components/ModelVersionEditModal.tsx b/webui/react/src/components/ModelVersionEditModal.tsx index f3160ccf8e1..413fba9430d 100644 --- a/webui/react/src/components/ModelVersionEditModal.tsx +++ b/webui/react/src/components/ModelVersionEditModal.tsx @@ -1,8 +1,8 @@ +import Form from 'determined-ui/Form'; +import Input from 'determined-ui/Input'; +import { Modal } from 'determined-ui/Modal'; import { useId } from 'react'; -import Form from 'components/kit/Form'; -import Input from 'components/kit/Input'; -import { Modal } from 'components/kit/Modal'; import { patchModelVersion } from 'services/api'; import { ModelVersion } from 'types'; import handleError from 'utils/error'; diff --git a/webui/react/src/components/Navigation.tsx b/webui/react/src/components/Navigation.tsx index d9612ea844e..e233bf3b4bf 100644 --- a/webui/react/src/components/Navigation.tsx +++ b/webui/react/src/components/Navigation.tsx @@ -1,9 +1,9 @@ +import Spinner from 'determined-ui/Spinner'; +import useUI from 'determined-ui/Theme'; +import { useInitApi } from 'determined-ui/Toast'; +import { Loadable } from 'determined-ui/utils/loadable'; import React, { useEffect } from 'react'; -import Spinner from 'components/kit/Spinner'; -import useUI from 'components/kit/Theme'; -import { useInitApi } from 'components/kit/Toast'; -import { Loadable } from 'components/kit/utils/loadable'; import clusterStore from 'stores/cluster'; import determinedStore, { BrandingType } from 'stores/determinedInfo'; import permissionStore from 'stores/permissions'; diff --git a/webui/react/src/components/NavigationSideBar.tsx b/webui/react/src/components/NavigationSideBar.tsx index 7c724f43fd2..06124c3e1ed 100644 --- a/webui/react/src/components/NavigationSideBar.tsx +++ b/webui/react/src/components/NavigationSideBar.tsx @@ -1,19 +1,19 @@ import { Typography } from 'antd'; +import Button from 'determined-ui/Button'; +import Dropdown, { MenuItem } from 'determined-ui/Dropdown'; +import Icon, { IconName, IconSize } from 'determined-ui/Icon'; +import { matchesShortcut, shortcutToString } from 'determined-ui/InputShortcut'; +import { useModal } from 'determined-ui/Modal'; +import Spinner from 'determined-ui/Spinner'; +import useUI from 'determined-ui/Theme'; +import Tooltip from 'determined-ui/Tooltip'; +import { Loadable } from 'determined-ui/utils/loadable'; import { boolean } from 'io-ts'; import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useLocation } from 'react-router-dom'; import { CSSTransition } from 'react-transition-group'; import DynamicIcon from 'components/DynamicIcon'; -import Button from 'components/kit/Button'; -import Dropdown, { MenuItem } from 'components/kit/Dropdown'; -import Icon, { IconName, IconSize } from 'components/kit/Icon'; -import { matchesShortcut, shortcutToString } from 'components/kit/InputShortcut'; -import { useModal } from 'components/kit/Modal'; -import Spinner from 'components/kit/Spinner'; -import useUI from 'components/kit/Theme'; -import Tooltip from 'components/kit/Tooltip'; -import { Loadable } from 'components/kit/utils/loadable'; import Link, { Props as LinkProps } from 'components/Link'; import UserSettings from 'components/UserSettings'; import shortCutSettingsConfig, { diff --git a/webui/react/src/components/NavigationTabbar.tsx b/webui/react/src/components/NavigationTabbar.tsx index c12be1ecaf0..0e68f7b8f5d 100644 --- a/webui/react/src/components/NavigationTabbar.tsx +++ b/webui/react/src/components/NavigationTabbar.tsx @@ -1,13 +1,13 @@ +import Icon, { IconName } from 'determined-ui/Icon'; +import { useModal } from 'determined-ui/Modal'; +import Spinner from 'determined-ui/Spinner'; +import useUI from 'determined-ui/Theme'; +import { Loadable } from 'determined-ui/utils/loadable'; import React, { useCallback, useEffect, useState } from 'react'; import { useLocation } from 'react-router-dom'; import ActionSheet, { ActionItem } from 'components/ActionSheet'; import DynamicIcon from 'components/DynamicIcon'; -import Icon, { IconName } from 'components/kit/Icon'; -import { useModal } from 'components/kit/Modal'; -import Spinner from 'components/kit/Spinner'; -import useUI from 'components/kit/Theme'; -import { Loadable } from 'components/kit/utils/loadable'; import Link, { Props as LinkProps } from 'components/Link'; import UserSettings from 'components/UserSettings'; import usePermissions from 'hooks/usePermissions'; diff --git a/webui/react/src/components/OverviewStats.tsx b/webui/react/src/components/OverviewStats.tsx index 3495ca591ed..88c883a93de 100644 --- a/webui/react/src/components/OverviewStats.tsx +++ b/webui/react/src/components/OverviewStats.tsx @@ -1,8 +1,7 @@ import { Typography } from 'antd'; +import Card from 'determined-ui/Card'; import React from 'react'; -import Card from 'components/kit/Card'; - import css from './OverviewStats.module.scss'; interface Props { diff --git a/webui/react/src/components/Page.tsx b/webui/react/src/components/Page.tsx index 955cfad81e7..1978342aa1e 100644 --- a/webui/react/src/components/Page.tsx +++ b/webui/react/src/components/Page.tsx @@ -1,9 +1,9 @@ +import { MenuItem } from 'determined-ui/Dropdown'; +import Spinner from 'determined-ui/Spinner'; import { useObservable } from 'micro-observables'; import React, { MutableRefObject } from 'react'; import { Helmet } from 'react-helmet-async'; -import { MenuItem } from 'components/kit/Dropdown'; -import Spinner from 'components/kit/Spinner'; import PageHeader from 'components/PageHeader'; import PageNotFound from 'components/PageNotFound'; import usePermissions from 'hooks/usePermissions'; diff --git a/webui/react/src/components/PageHeader/PageHeader.tsx b/webui/react/src/components/PageHeader/PageHeader.tsx index cdb9b6a2cf9..d66641f8920 100644 --- a/webui/react/src/components/PageHeader/PageHeader.tsx +++ b/webui/react/src/components/PageHeader/PageHeader.tsx @@ -1,8 +1,8 @@ +import Breadcrumb from 'determined-ui/Breadcrumb'; +import { MenuItem } from 'determined-ui/Dropdown'; +import Tooltip from 'determined-ui/Tooltip'; import React, { useMemo } from 'react'; -import Breadcrumb from 'components/kit/Breadcrumb'; -import { MenuItem } from 'components/kit/Dropdown'; -import Tooltip from 'components/kit/Tooltip'; import Link from 'components/Link'; import { BreadCrumbRoute } from 'components/Page'; import { CommonProps } from 'types'; diff --git a/webui/react/src/components/PageHeaderFoldable.tsx b/webui/react/src/components/PageHeaderFoldable.tsx index f8b7febf019..82191d6a4f9 100644 --- a/webui/react/src/components/PageHeaderFoldable.tsx +++ b/webui/react/src/components/PageHeaderFoldable.tsx @@ -1,9 +1,9 @@ +import Button from 'determined-ui/Button'; +import Dropdown, { DropdownEvent, MenuItem } from 'determined-ui/Dropdown'; +import Icon from 'determined-ui/Icon'; +import Tooltip from 'determined-ui/Tooltip'; import React, { useCallback, useState } from 'react'; -import Button from 'components/kit/Button'; -import Dropdown, { DropdownEvent, MenuItem } from 'components/kit/Dropdown'; -import Icon from 'components/kit/Icon'; -import Tooltip from 'components/kit/Tooltip'; import { isMouseEvent } from 'utils/routes'; import css from './PageHeaderFoldable.module.scss'; diff --git a/webui/react/src/components/PageMessage.tsx b/webui/react/src/components/PageMessage.tsx index 28453d28965..9c6fa7d9eb7 100644 --- a/webui/react/src/components/PageMessage.tsx +++ b/webui/react/src/components/PageMessage.tsx @@ -1,7 +1,7 @@ +import Message from 'determined-ui/Message'; import { useObservable } from 'micro-observables'; import React from 'react'; -import Message from 'components/kit/Message'; import Logo from 'components/Logo'; import Page from 'components/Page'; import determinedStore from 'stores/determinedInfo'; diff --git a/webui/react/src/components/PageNotFound.tsx b/webui/react/src/components/PageNotFound.tsx index b8eca08acab..117d3bb6207 100644 --- a/webui/react/src/components/PageNotFound.tsx +++ b/webui/react/src/components/PageNotFound.tsx @@ -1,7 +1,7 @@ +import Button from 'determined-ui/Button'; +import Message from 'determined-ui/Message'; import React from 'react'; -import Button from 'components/kit/Button'; -import Message from 'components/kit/Message'; import { paths } from 'routes/utils'; import Link from './Link'; diff --git a/webui/react/src/components/ParallelCoordinates.tsx b/webui/react/src/components/ParallelCoordinates.tsx index 1ba9577462e..c713904f578 100644 --- a/webui/react/src/components/ParallelCoordinates.tsx +++ b/webui/react/src/components/ParallelCoordinates.tsx @@ -1,8 +1,7 @@ +import useUI from 'determined-ui/Theme'; import Hermes from 'hermes-parallel-coordinates'; import React, { useEffect, useRef } from 'react'; -import useUI from 'components/kit/Theme'; - import css from './ParallelCoordinates.module.scss'; interface Props { diff --git a/webui/react/src/components/PasswordChangeModal.test.tsx b/webui/react/src/components/PasswordChangeModal.test.tsx index 90b177c52f7..f2be13d73d6 100644 --- a/webui/react/src/components/PasswordChangeModal.test.tsx +++ b/webui/react/src/components/PasswordChangeModal.test.tsx @@ -1,10 +1,10 @@ import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; +import Button from 'determined-ui/Button'; +import { useModal } from 'determined-ui/Modal'; +import { UIProvider } from 'determined-ui/Theme'; import React, { useCallback, useEffect } from 'react'; -import Button from 'components/kit/Button'; -import { useModal } from 'components/kit/Modal'; -import { UIProvider } from 'components/kit/Theme'; import { setUserPassword as mockSetUserPassword } from 'services/api'; import { V1LoginRequest } from 'services/api-ts-sdk'; import authStore from 'stores/auth'; diff --git a/webui/react/src/components/PasswordChangeModal.tsx b/webui/react/src/components/PasswordChangeModal.tsx index 303f21b97ef..323c1241cd2 100644 --- a/webui/react/src/components/PasswordChangeModal.tsx +++ b/webui/react/src/components/PasswordChangeModal.tsx @@ -1,10 +1,10 @@ +import Form from 'determined-ui/Form'; +import Input from 'determined-ui/Input'; +import { Modal } from 'determined-ui/Modal'; +import { makeToast } from 'determined-ui/Toast'; +import { Loadable } from 'determined-ui/utils/loadable'; import React, { useId, useState } from 'react'; -import Form from 'components/kit/Form'; -import Input from 'components/kit/Input'; -import { Modal } from 'components/kit/Modal'; -import { makeToast } from 'components/kit/Toast'; -import { Loadable } from 'components/kit/utils/loadable'; import { login, setUserPassword } from 'services/api'; import userStore from 'stores/users'; import handleError, { ErrorType } from 'utils/error'; diff --git a/webui/react/src/components/ProgressBar.tsx b/webui/react/src/components/ProgressBar.tsx index 91cb64c739d..63914e0e134 100644 --- a/webui/react/src/components/ProgressBar.tsx +++ b/webui/react/src/components/ProgressBar.tsx @@ -1,7 +1,7 @@ +import { getStateColorCssVar, StateOfUnion } from 'determined-ui/Theme'; import React from 'react'; import Bar from 'components/Bar'; -import { getStateColorCssVar, StateOfUnion } from 'components/kit/Theme'; import { floatToPercent } from 'utils/string'; export interface Props { diff --git a/webui/react/src/components/ProjectActionDropdown.tsx b/webui/react/src/components/ProjectActionDropdown.tsx index 8f24150172f..2959d2dd0ce 100644 --- a/webui/react/src/components/ProjectActionDropdown.tsx +++ b/webui/react/src/components/ProjectActionDropdown.tsx @@ -1,10 +1,10 @@ +import Button from 'determined-ui/Button'; +import Dropdown, { MenuItem } from 'determined-ui/Dropdown'; +import Icon from 'determined-ui/Icon'; +import { useModal } from 'determined-ui/Modal'; import React, { useCallback, useMemo } from 'react'; import css from 'components/ActionDropdown/ActionDropdown.module.scss'; -import Button from 'components/kit/Button'; -import Dropdown, { MenuItem } from 'components/kit/Dropdown'; -import Icon from 'components/kit/Icon'; -import { useModal } from 'components/kit/Modal'; import usePermissions from 'hooks/usePermissions'; import { archiveProject, unarchiveProject } from 'services/api'; import { Project } from 'types'; diff --git a/webui/react/src/components/ProjectCard.tsx b/webui/react/src/components/ProjectCard.tsx index 067bbb2ea2e..daa9f630985 100644 --- a/webui/react/src/components/ProjectCard.tsx +++ b/webui/react/src/components/ProjectCard.tsx @@ -1,9 +1,9 @@ import { Typography } from 'antd'; +import Card from 'determined-ui/Card'; +import Icon from 'determined-ui/Icon'; +import Tooltip from 'determined-ui/Tooltip'; import React from 'react'; -import Card from 'components/kit/Card'; -import Icon from 'components/kit/Icon'; -import Tooltip from 'components/kit/Tooltip'; import TimeAgo from 'components/TimeAgo'; import { handlePath, paths } from 'routes/utils'; import { Project } from 'types'; diff --git a/webui/react/src/components/ProjectCreateModal.tsx b/webui/react/src/components/ProjectCreateModal.tsx index 0c38132fa1f..7d1c19d8ff7 100644 --- a/webui/react/src/components/ProjectCreateModal.tsx +++ b/webui/react/src/components/ProjectCreateModal.tsx @@ -1,8 +1,8 @@ +import Form from 'determined-ui/Form'; +import Input from 'determined-ui/Input'; +import { Modal } from 'determined-ui/Modal'; import React, { useCallback, useId } from 'react'; -import Form from 'components/kit/Form'; -import Input from 'components/kit/Input'; -import { Modal } from 'components/kit/Modal'; import { paths } from 'routes/utils'; import { createProject } from 'services/api'; import handleError, { DetError, ErrorLevel, ErrorType } from 'utils/error'; diff --git a/webui/react/src/components/ProjectDeleteModal.tsx b/webui/react/src/components/ProjectDeleteModal.tsx index 1185cc95aac..4e98e781ee0 100644 --- a/webui/react/src/components/ProjectDeleteModal.tsx +++ b/webui/react/src/components/ProjectDeleteModal.tsx @@ -1,8 +1,8 @@ +import Form from 'determined-ui/Form'; +import Input from 'determined-ui/Input'; +import { Modal } from 'determined-ui/Modal'; import React, { useCallback, useId } from 'react'; -import Form from 'components/kit/Form'; -import Input from 'components/kit/Input'; -import { Modal } from 'components/kit/Modal'; import { deleteProject } from 'services/api'; import { Project } from 'types'; import handleError, { ErrorLevel, ErrorType } from 'utils/error'; diff --git a/webui/react/src/components/ProjectEditModal.tsx b/webui/react/src/components/ProjectEditModal.tsx index 5695a3a8fac..b39eeb5821d 100644 --- a/webui/react/src/components/ProjectEditModal.tsx +++ b/webui/react/src/components/ProjectEditModal.tsx @@ -1,8 +1,8 @@ +import Form from 'determined-ui/Form'; +import Input from 'determined-ui/Input'; +import { Modal } from 'determined-ui/Modal'; import React, { useCallback, useId } from 'react'; -import Form from 'components/kit/Form'; -import Input from 'components/kit/Input'; -import { Modal } from 'components/kit/Modal'; import { patchProject } from 'services/api'; import { Project } from 'types'; import handleError, { ErrorLevel, ErrorType } from 'utils/error'; diff --git a/webui/react/src/components/ProjectMoveModal.tsx b/webui/react/src/components/ProjectMoveModal.tsx index cc59a2046d8..183a53c7e49 100644 --- a/webui/react/src/components/ProjectMoveModal.tsx +++ b/webui/react/src/components/ProjectMoveModal.tsx @@ -1,11 +1,11 @@ import { Select, Typography } from 'antd'; import { SelectValue } from 'antd/lib/select'; +import Icon from 'determined-ui/Icon'; +import { Modal } from 'determined-ui/Modal'; +import { makeToast } from 'determined-ui/Toast'; +import { Loadable } from 'determined-ui/utils/loadable'; import React, { useCallback, useState } from 'react'; -import Icon from 'components/kit/Icon'; -import { Modal } from 'components/kit/Modal'; -import { makeToast } from 'components/kit/Toast'; -import { Loadable } from 'components/kit/utils/loadable'; import Link from 'components/Link'; import usePermissions from 'hooks/usePermissions'; import { paths } from 'routes/utils'; diff --git a/webui/react/src/components/ProjectNoteDeleteModal.tsx b/webui/react/src/components/ProjectNoteDeleteModal.tsx index 0fd734f6e18..8224886de84 100644 --- a/webui/react/src/components/ProjectNoteDeleteModal.tsx +++ b/webui/react/src/components/ProjectNoteDeleteModal.tsx @@ -1,6 +1,6 @@ +import { Modal } from 'determined-ui/Modal'; import React, { useCallback } from 'react'; -import { Modal } from 'components/kit/Modal'; import { setProjectNotes } from 'services/api'; import { Project } from 'types'; import handleError, { ErrorLevel, ErrorType } from 'utils/error'; diff --git a/webui/react/src/components/RadioGroup.tsx b/webui/react/src/components/RadioGroup.tsx index a8e1f6c41a3..b0bf5530841 100644 --- a/webui/react/src/components/RadioGroup.tsx +++ b/webui/react/src/components/RadioGroup.tsx @@ -1,11 +1,11 @@ import { Radio } from 'antd'; import { RadioChangeEvent } from 'antd/lib/radio'; +import Icon, { IconName, IconSize } from 'determined-ui/Icon'; +import Tooltip from 'determined-ui/Tooltip'; import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { throttle } from 'throttle-debounce'; import { ConditionalWrapper } from 'components/ConditionalWrapper'; -import Icon, { IconName, IconSize } from 'components/kit/Icon'; -import Tooltip from 'components/kit/Tooltip'; import useResize from 'hooks/useResize'; import css from './RadioGroup.module.scss'; diff --git a/webui/react/src/components/ResourcePoolBindingModal.tsx b/webui/react/src/components/ResourcePoolBindingModal.tsx index 30bce2d92ce..81d026b5e19 100644 --- a/webui/react/src/components/ResourcePoolBindingModal.tsx +++ b/webui/react/src/components/ResourcePoolBindingModal.tsx @@ -1,11 +1,10 @@ +import { Modal } from 'determined-ui/Modal'; +import Paragraph from 'determined-ui/Typography/Paragraph'; import React, { useRef, useState } from 'react'; -import { Modal } from 'components/kit/Modal'; import Transfer from 'components/Transfer'; import handleError from 'utils/error'; -import Paragraph from './kit/Typography/Paragraph'; - interface Props { pool: string; bindings: string[]; diff --git a/webui/react/src/components/ResourcePoolBindings.tsx b/webui/react/src/components/ResourcePoolBindings.tsx index 1dcec04e665..2cf24906c3e 100644 --- a/webui/react/src/components/ResourcePoolBindings.tsx +++ b/webui/react/src/components/ResourcePoolBindings.tsx @@ -1,10 +1,10 @@ +import Button from 'determined-ui/Button'; +import { useModal } from 'determined-ui/Modal'; +import { Loadable } from 'determined-ui/utils/loadable'; import { useObservable } from 'micro-observables'; import { useCallback, useEffect, useMemo } from 'react'; import DynamicIcon from 'components/DynamicIcon'; -import Button from 'components/kit/Button'; -import { useModal } from 'components/kit/Modal'; -import { Loadable } from 'components/kit/utils/loadable'; import Link from 'components/Link'; import ResourcePoolBindingModalComponent from 'components/ResourcePoolBindingModal'; import { ColumnDef } from 'components/Table/InteractiveTable'; diff --git a/webui/react/src/components/ResourcePoolCard.test.tsx b/webui/react/src/components/ResourcePoolCard.test.tsx index 6761b79552e..39818369fd4 100644 --- a/webui/react/src/components/ResourcePoolCard.test.tsx +++ b/webui/react/src/components/ResourcePoolCard.test.tsx @@ -1,7 +1,7 @@ import { render, screen, waitFor } from '@testing-library/react'; +import { UIProvider } from 'determined-ui/Theme'; import React, { Suspense } from 'react'; -import { UIProvider } from 'components/kit/Theme'; import resourcePools from 'fixtures/responses/cluster/resource-pools.json'; import { ResourcePool } from 'types'; diff --git a/webui/react/src/components/ResourcePoolCard.tsx b/webui/react/src/components/ResourcePoolCard.tsx index 0e9f268970b..c1a322e298b 100644 --- a/webui/react/src/components/ResourcePoolCard.tsx +++ b/webui/react/src/components/ResourcePoolCard.tsx @@ -1,3 +1,11 @@ +import Card from 'determined-ui/Card'; +import { MenuItem } from 'determined-ui/Dropdown'; +import Icon from 'determined-ui/Icon'; +import { useModal } from 'determined-ui/Modal'; +import Spinner from 'determined-ui/Spinner'; +import useUI, { DarkLight, ShirtSize } from 'determined-ui/Theme'; +import Tooltip from 'determined-ui/Tooltip'; +import { Loadable } from 'determined-ui/utils/loadable'; import React, { Suspense, useCallback, useEffect, useMemo } from 'react'; import awsLogoOnDark from 'assets/images/aws-logo-on-dark.svg?url'; @@ -5,14 +13,6 @@ import awsLogo from 'assets/images/aws-logo.svg?url'; import gcpLogo from 'assets/images/gcp-logo.svg?url'; import k8sLogo from 'assets/images/k8s-logo.svg?url'; import staticLogo from 'assets/images/on-prem-logo.svg?url'; -import Card from 'components/kit/Card'; -import { MenuItem } from 'components/kit/Dropdown'; -import Icon from 'components/kit/Icon'; -import { useModal } from 'components/kit/Modal'; -import Spinner from 'components/kit/Spinner'; -import useUI, { DarkLight, ShirtSize } from 'components/kit/Theme'; -import Tooltip from 'components/kit/Tooltip'; -import { Loadable } from 'components/kit/utils/loadable'; import SlotAllocationBar from 'components/SlotAllocationBar'; import { V1ResourcePoolTypeToLabel, V1SchedulerTypeToLabel } from 'constants/states'; import useFeature from 'hooks/useFeature'; diff --git a/webui/react/src/components/ResponsiveFilters.tsx b/webui/react/src/components/ResponsiveFilters.tsx index 4b397b5da00..b804ca4f810 100644 --- a/webui/react/src/components/ResponsiveFilters.tsx +++ b/webui/react/src/components/ResponsiveFilters.tsx @@ -1,8 +1,8 @@ +import Button from 'determined-ui/Button'; +import Dropdown from 'determined-ui/Dropdown'; +import Icon from 'determined-ui/Icon'; import React, { useEffect, useRef, useState } from 'react'; -import Button from 'components/kit/Button'; -import Dropdown from 'components/kit/Dropdown'; -import Icon from 'components/kit/Icon'; import useResize from 'hooks/useResize'; import css from './ResponsiveFilters.module.scss'; diff --git a/webui/react/src/components/RoutePagination.test.tsx b/webui/react/src/components/RoutePagination.test.tsx index e45ca0e167d..97c61b32153 100644 --- a/webui/react/src/components/RoutePagination.test.tsx +++ b/webui/react/src/components/RoutePagination.test.tsx @@ -4,7 +4,7 @@ import React from 'react'; import RoutePagination from './RoutePagination'; -vi.mock('components/kit/Tooltip'); +vi.mock('determined-ui/Tooltip'); const FIRST_ID = 6; const MIDDLE_ID = 66; diff --git a/webui/react/src/components/RoutePagination.tsx b/webui/react/src/components/RoutePagination.tsx index 0809cf97df6..5be2235ea47 100644 --- a/webui/react/src/components/RoutePagination.tsx +++ b/webui/react/src/components/RoutePagination.tsx @@ -1,7 +1,7 @@ +import Pagination from 'determined-ui/Pagination'; +import Tooltip from 'determined-ui/Tooltip'; import React, { useCallback, useEffect, useState } from 'react'; -import Pagination from 'components/kit/Pagination'; -import Tooltip from 'components/kit/Tooltip'; import { keyEmitter, KeyEvent } from 'hooks/useKeyTracker'; import css from './RoutePagination.module.scss'; diff --git a/webui/react/src/components/Router.tsx b/webui/react/src/components/Router.tsx index 3080bac7aee..4ec88acd3d1 100644 --- a/webui/react/src/components/Router.tsx +++ b/webui/react/src/components/Router.tsx @@ -1,9 +1,9 @@ +import Message from 'determined-ui/Message'; +import useUI from 'determined-ui/Theme'; import { useObservable } from 'micro-observables'; import React, { useEffect } from 'react'; import { Navigate, Route, Routes, useLocation } from 'react-router-dom'; -import Message from 'components/kit/Message'; -import useUI from 'components/kit/Theme'; import { paths } from 'routes/utils'; import authStore from 'stores/auth'; import { RouteConfig } from 'types'; diff --git a/webui/react/src/components/ScaleSelect.tsx b/webui/react/src/components/ScaleSelect.tsx index 5d5e783efef..68b3004b9d4 100644 --- a/webui/react/src/components/ScaleSelect.tsx +++ b/webui/react/src/components/ScaleSelect.tsx @@ -1,6 +1,6 @@ +import Select, { Option, SelectValue } from 'determined-ui/Select'; import React from 'react'; -import Select, { Option, SelectValue } from 'components/kit/Select'; import { Scale } from 'types'; import { capitalize } from 'utils/string'; diff --git a/webui/react/src/components/Section.tsx b/webui/react/src/components/Section.tsx index 9bfef481e44..118f67ce436 100644 --- a/webui/react/src/components/Section.tsx +++ b/webui/react/src/components/Section.tsx @@ -1,6 +1,6 @@ +import Spinner from 'determined-ui/Spinner'; import React from 'react'; -import Spinner from 'components/kit/Spinner'; import { isString } from 'utils/data'; import { generateAlphaNumeric, toHtmlId } from 'utils/string'; diff --git a/webui/react/src/components/SetUserRolesModal.tsx b/webui/react/src/components/SetUserRolesModal.tsx index 123fc4f9b82..1c179441013 100644 --- a/webui/react/src/components/SetUserRolesModal.tsx +++ b/webui/react/src/components/SetUserRolesModal.tsx @@ -1,10 +1,10 @@ +import Form from 'determined-ui/Form'; +import { Modal } from 'determined-ui/Modal'; +import Select, { Option } from 'determined-ui/Select'; +import { makeToast } from 'determined-ui/Toast'; +import { Loadable } from 'determined-ui/utils/loadable'; import { useObservable } from 'micro-observables'; -import Form from 'components/kit/Form'; -import { Modal } from 'components/kit/Modal'; -import Select, { Option } from 'components/kit/Select'; -import { makeToast } from 'components/kit/Toast'; -import { Loadable } from 'components/kit/utils/loadable'; import { assignRolesToUser } from 'services/api'; import roleStore from 'stores/roles'; import { UserRole } from 'types'; diff --git a/webui/react/src/components/SlotAllocationBar.tsx b/webui/react/src/components/SlotAllocationBar.tsx index a7e4fcfe0d7..56e7d291041 100644 --- a/webui/react/src/components/SlotAllocationBar.tsx +++ b/webui/react/src/components/SlotAllocationBar.tsx @@ -1,10 +1,10 @@ +import { getStateColorCssVar, ShirtSize } from 'determined-ui/Theme'; +import Tooltip from 'determined-ui/Tooltip'; import React, { useMemo } from 'react'; import Badge from 'components/Badge'; import Bar from 'components/Bar'; import { ConditionalWrapper } from 'components/ConditionalWrapper'; -import { getStateColorCssVar, ShirtSize } from 'components/kit/Theme'; -import Tooltip from 'components/kit/Tooltip'; import { resourceStateToLabel } from 'constants/states'; import { paths } from 'routes/utils'; import { V1ResourcePoolType } from 'services/api-ts-sdk'; diff --git a/webui/react/src/components/Table/InteractiveTable.tsx b/webui/react/src/components/Table/InteractiveTable.tsx index 27899aeff10..6c4e655b6ce 100644 --- a/webui/react/src/components/Table/InteractiveTable.tsx +++ b/webui/react/src/components/Table/InteractiveTable.tsx @@ -7,6 +7,7 @@ import { SorterResult, TablePaginationConfig, } from 'antd/es/table/interface'; +import Spinner from 'determined-ui/Spinner'; import _ from 'lodash'; import React, { createContext, @@ -27,7 +28,6 @@ import { DraggableEventHandler, } from 'react-draggable'; -import Spinner from 'components/kit/Spinner'; import SkeletonTable from 'components/Table/SkeletonTable'; import useResize from 'hooks/useResize'; import { UpdateSettings } from 'hooks/useSettings'; diff --git a/webui/react/src/components/Table/ResponsiveTable.tsx b/webui/react/src/components/Table/ResponsiveTable.tsx index 151ed8b84c3..06c4adc22cc 100644 --- a/webui/react/src/components/Table/ResponsiveTable.tsx +++ b/webui/react/src/components/Table/ResponsiveTable.tsx @@ -2,9 +2,9 @@ import { Table } from 'antd'; import { SpinProps } from 'antd/es/spin'; import { TableProps } from 'antd/es/table'; import { SorterResult } from 'antd/es/table/interface'; +import Spinner from 'determined-ui/Spinner'; import React, { useEffect, useRef, useState } from 'react'; -import Spinner from 'components/kit/Spinner'; import useResize from 'hooks/useResize'; import { TrialItem } from 'types'; import { hasObjectKeys } from 'utils/data'; diff --git a/webui/react/src/components/Table/Table.tsx b/webui/react/src/components/Table/Table.tsx index 472fa779ded..5357d37ce52 100644 --- a/webui/react/src/components/Table/Table.tsx +++ b/webui/react/src/components/Table/Table.tsx @@ -1,4 +1,8 @@ import { Space, Typography } from 'antd'; +import Icon from 'determined-ui/Icon'; +import Spinner from 'determined-ui/Spinner'; +import { StateOfUnion } from 'determined-ui/Theme'; +import Tooltip from 'determined-ui/Tooltip'; import React from 'react'; import Badge, { BadgeType } from 'components/Badge'; @@ -6,10 +10,6 @@ import { ConditionalWrapper } from 'components/ConditionalWrapper'; import DynamicIcon from 'components/DynamicIcon'; import ExperimentIcons from 'components/ExperimentIcons'; import HumanReadableNumber from 'components/HumanReadableNumber'; -import Icon from 'components/kit/Icon'; -import Spinner from 'components/kit/Spinner'; -import { StateOfUnion } from 'components/kit/Theme'; -import Tooltip from 'components/kit/Tooltip'; import Link from 'components/Link'; import ProgressBar from 'components/ProgressBar'; import TimeAgo from 'components/TimeAgo'; diff --git a/webui/react/src/components/Table/TableBatch.tsx b/webui/react/src/components/Table/TableBatch.tsx index fdf677fde88..63f64cd8f89 100644 --- a/webui/react/src/components/Table/TableBatch.tsx +++ b/webui/react/src/components/Table/TableBatch.tsx @@ -1,8 +1,7 @@ import { Select } from 'antd'; +import Button from 'determined-ui/Button'; import React, { useCallback, useState } from 'react'; -import Button from 'components/kit/Button'; - import css from './TableBatch.module.scss'; interface Action { diff --git a/webui/react/src/components/Table/TableBulkActions.tsx b/webui/react/src/components/Table/TableBulkActions.tsx index 9bca5ada10f..3a9c62ac57a 100644 --- a/webui/react/src/components/Table/TableBulkActions.tsx +++ b/webui/react/src/components/Table/TableBulkActions.tsx @@ -1,8 +1,7 @@ import { Select } from 'antd'; +import Button from 'determined-ui/Button'; import React, { useCallback, useMemo, useState } from 'react'; -import Button from 'components/kit/Button'; - import css from './TableBatch.module.scss'; export interface Action { diff --git a/webui/react/src/components/Table/TableFilterDropdown.tsx b/webui/react/src/components/Table/TableFilterDropdown.tsx index 6ddc2409e0d..62c664c2ead 100644 --- a/webui/react/src/components/Table/TableFilterDropdown.tsx +++ b/webui/react/src/components/Table/TableFilterDropdown.tsx @@ -1,10 +1,10 @@ import { FilterDropdownProps } from 'antd/es/table/interface'; +import Button from 'determined-ui/Button'; +import Icon from 'determined-ui/Icon'; +import Input, { InputRef } from 'determined-ui/Input'; import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { FixedSizeList, ListChildComponentProps } from 'react-window'; -import Button from 'components/kit/Button'; -import Icon from 'components/kit/Icon'; -import Input, { InputRef } from 'components/kit/Input'; import usePrevious from 'hooks/usePrevious'; import css from './TableFilterDropdown.module.scss'; diff --git a/webui/react/src/components/Table/TableFilterSearch.tsx b/webui/react/src/components/Table/TableFilterSearch.tsx index bc1771e0049..bd6cd3f21d5 100644 --- a/webui/react/src/components/Table/TableFilterSearch.tsx +++ b/webui/react/src/components/Table/TableFilterSearch.tsx @@ -1,10 +1,9 @@ import { FilterDropdownProps } from 'antd/es/table/interface'; +import Button from 'determined-ui/Button'; +import Icon from 'determined-ui/Icon'; +import Input, { InputRef } from 'determined-ui/Input'; import React, { useCallback, useEffect, useRef, useState } from 'react'; -import Button from 'components/kit/Button'; -import Icon from 'components/kit/Icon'; -import Input, { InputRef } from 'components/kit/Input'; - import css from './TableFilterSearch.module.scss'; interface Props extends FilterDropdownProps { diff --git a/webui/react/src/components/TaskActionDropdown.tsx b/webui/react/src/components/TaskActionDropdown.tsx index 93d4191536c..b51f38fb43e 100644 --- a/webui/react/src/components/TaskActionDropdown.tsx +++ b/webui/react/src/components/TaskActionDropdown.tsx @@ -1,9 +1,10 @@ +import Button from 'determined-ui/Button'; +import Dropdown, { MenuItem } from 'determined-ui/Dropdown'; +import Icon from 'determined-ui/Icon'; +import useConfirm from 'determined-ui/useConfirm'; import React from 'react'; import css from 'components/ActionDropdown/ActionDropdown.module.scss'; -import Button from 'components/kit/Button'; -import Dropdown, { MenuItem } from 'components/kit/Dropdown'; -import Icon from 'components/kit/Icon'; import usePermissions from 'hooks/usePermissions'; import { paths } from 'routes/utils'; import { killTask } from 'services/api'; @@ -12,7 +13,6 @@ import handleError, { ErrorLevel, ErrorType } from 'utils/error'; import { capitalize } from 'utils/string'; import { isTaskKillable } from 'utils/task'; -import useConfirm from './kit/useConfirm'; import Link from './Link'; interface Props { diff --git a/webui/react/src/components/TaskBar.tsx b/webui/react/src/components/TaskBar.tsx index 376de679df2..a3b67b2b1be 100644 --- a/webui/react/src/components/TaskBar.tsx +++ b/webui/react/src/components/TaskBar.tsx @@ -1,7 +1,8 @@ +import Dropdown, { MenuItem } from 'determined-ui/Dropdown'; +import Icon from 'determined-ui/Icon'; +import useConfirm from 'determined-ui/useConfirm'; import React, { useCallback, useMemo } from 'react'; -import Dropdown, { MenuItem } from 'components/kit/Dropdown'; -import Icon from 'components/kit/Icon'; import usePermissions from 'hooks/usePermissions'; import { paths } from 'routes/utils'; import { killTask } from 'services/api'; @@ -9,7 +10,6 @@ import { CommandTask, CommandType } from 'types'; import handleError from 'utils/error'; import { routeToReactUrl } from 'utils/routes'; -import useConfirm from './kit/useConfirm'; import css from './TaskBar.module.scss'; interface Props { diff --git a/webui/react/src/components/TaskList.tsx b/webui/react/src/components/TaskList.tsx index 69839cf5ed9..6f945ead18b 100644 --- a/webui/react/src/components/TaskList.tsx +++ b/webui/react/src/components/TaskList.tsx @@ -5,6 +5,11 @@ import { SorterResult, TablePaginationConfig, } from 'antd/es/table/interface'; +import Button from 'determined-ui/Button'; +import Icon from 'determined-ui/Icon'; +import { useModal } from 'determined-ui/Modal'; +import { ShirtSize } from 'determined-ui/Theme'; +import { Loadable } from 'determined-ui/utils/loadable'; import _ from 'lodash'; import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; @@ -12,10 +17,6 @@ import Badge, { BadgeType } from 'components/Badge'; import FilterCounter from 'components/FilterCounter'; import Grid from 'components/Grid'; import JupyterLabButton from 'components/JupyterLabButton'; -import Button from 'components/kit/Button'; -import Icon from 'components/kit/Icon'; -import { ShirtSize } from 'components/kit/Theme'; -import { Loadable } from 'components/kit/utils/loadable'; import Link from 'components/Link'; import InteractiveTable, { ColumnDef } from 'components/Table/InteractiveTable'; import { @@ -64,7 +65,6 @@ import { commandStateSorter, filterTasks, isTaskKillable, taskFromCommandTask } import { getDisplayName } from 'utils/user'; import BatchActionConfirmModalComponent from './BatchActionConfirmModal'; -import { useModal } from './kit/Modal'; import css from './TaskList.module.scss'; import WorkspaceFilter from './WorkspaceFilter'; diff --git a/webui/react/src/components/TextEditorModal.tsx b/webui/react/src/components/TextEditorModal.tsx index d35e3f5ae35..b084509a166 100644 --- a/webui/react/src/components/TextEditorModal.tsx +++ b/webui/react/src/components/TextEditorModal.tsx @@ -1,10 +1,9 @@ import { Modal } from 'antd'; +import Button from 'determined-ui/Button'; +import Form from 'determined-ui/Form'; +import Input from 'determined-ui/Input'; import React, { useCallback, useId, useMemo, useState } from 'react'; -import Button from 'components/kit/Button'; -import Form from 'components/kit/Form'; -import Input from 'components/kit/Input'; - import css from './TextEditorModal.module.scss'; const FORM_ID = 'edit-text-form'; diff --git a/webui/react/src/components/ThemeToggle.test.tsx b/webui/react/src/components/ThemeToggle.test.tsx index 0d9a74ed92d..ca16fda1791 100644 --- a/webui/react/src/components/ThemeToggle.test.tsx +++ b/webui/react/src/components/ThemeToggle.test.tsx @@ -1,10 +1,9 @@ import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; +import { Mode, UIProvider } from 'determined-ui/Theme'; import React from 'react'; import { BrowserRouter } from 'react-router-dom'; -import { Mode, UIProvider } from 'components/kit/Theme'; - import ThemeToggle, { ThemeOptions } from './ThemeToggle'; const ThemeToggleContainer: React.FC = () => ( diff --git a/webui/react/src/components/ThemeToggle.tsx b/webui/react/src/components/ThemeToggle.tsx index 41d1befabf1..ca5bc831339 100644 --- a/webui/react/src/components/ThemeToggle.tsx +++ b/webui/react/src/components/ThemeToggle.tsx @@ -1,7 +1,6 @@ +import useUI, { Mode } from 'determined-ui/Theme'; import React from 'react'; -import useUI, { Mode } from 'components/kit/Theme'; - import css from './ThemeToggle.module.scss'; interface Props { diff --git a/webui/react/src/components/TimeAgo.tsx b/webui/react/src/components/TimeAgo.tsx index 99af35bf550..4950cdbcd9f 100644 --- a/webui/react/src/components/TimeAgo.tsx +++ b/webui/react/src/components/TimeAgo.tsx @@ -1,7 +1,7 @@ import dayjs, { Dayjs } from 'dayjs'; +import Tooltip from 'determined-ui/Tooltip'; import React, { useEffect, useMemo, useState } from 'react'; -import Tooltip from 'components/kit/Tooltip'; import { ValueOf } from 'types'; import { isNumber, isString } from 'utils/data'; import { diff --git a/webui/react/src/components/Transfer.tsx b/webui/react/src/components/Transfer.tsx index 47a265c902a..7febc7d7a43 100644 --- a/webui/react/src/components/Transfer.tsx +++ b/webui/react/src/components/Transfer.tsx @@ -1,8 +1,8 @@ +import Input from 'determined-ui/Input'; import _ from 'lodash'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { FixedSizeList as List } from 'react-window'; -import Input from 'components/kit/Input'; import Link from 'components/Link'; import DraggableListItem from './DraggableListItem'; diff --git a/webui/react/src/components/TrialLogPreview.tsx b/webui/react/src/components/TrialLogPreview.tsx index f16d59e5806..f6938045f13 100644 --- a/webui/react/src/components/TrialLogPreview.tsx +++ b/webui/react/src/components/TrialLogPreview.tsx @@ -1,12 +1,12 @@ import dayjs from 'dayjs'; -import React, { useCallback, useEffect, useRef, useState } from 'react'; - import LogViewerEntry, { DATETIME_FORMAT, LogEntry, MAX_DATETIME_LENGTH, -} from 'components/kit/LogViewer/LogViewerEntry'; -import Tooltip from 'components/kit/Tooltip'; +} from 'determined-ui/LogViewer/LogViewerEntry'; +import Tooltip from 'determined-ui/Tooltip'; +import React, { useCallback, useEffect, useRef, useState } from 'react'; + import useGetCharMeasureInContainer from 'hooks/useGetCharMeasureInContainer'; import { detApi } from 'services/apiConfig'; import { mapV1LogsResponse } from 'services/decoder'; diff --git a/webui/react/src/components/UPlot/UPlotChart.tsx b/webui/react/src/components/UPlot/UPlotChart.tsx index fc426444fe2..fa4fc5652f5 100644 --- a/webui/react/src/components/UPlot/UPlotChart.tsx +++ b/webui/react/src/components/UPlot/UPlotChart.tsx @@ -1,11 +1,11 @@ +import Button from 'determined-ui/Button'; +import Icon from 'determined-ui/Icon'; +import Spinner from 'determined-ui/Spinner'; +import useUI, { DarkLight } from 'determined-ui/Theme'; import React, { RefObject, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { throttle } from 'throttle-debounce'; import uPlot, { AlignedData } from 'uplot'; -import Button from 'components/kit/Button'; -import Icon from 'components/kit/Icon'; -import Spinner from 'components/kit/Spinner'; -import useUI, { DarkLight } from 'components/kit/Theme'; import usePrevious from 'hooks/usePrevious'; import useResize from 'hooks/useResize'; import handleError, { ErrorLevel, ErrorType } from 'utils/error'; diff --git a/webui/react/src/components/UserAvatar.test.tsx b/webui/react/src/components/UserAvatar.test.tsx index cae39e4da55..5a99c91f613 100644 --- a/webui/react/src/components/UserAvatar.test.tsx +++ b/webui/react/src/components/UserAvatar.test.tsx @@ -1,8 +1,8 @@ import { waitFor } from '@testing-library/dom'; import { act, render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; +import { UIProvider } from 'determined-ui/Theme'; -import { UIProvider } from 'components/kit/Theme'; import { User } from 'types'; import UserAvatar, { Props } from './UserAvatar'; @@ -15,7 +15,7 @@ const testUsers: User[] = [ }, ]; -vi.mock('components/kit/Tooltip'); +vi.mock('determined-ui/Tooltip'); const Component = ({ user }: Partial = {}) => { return ; diff --git a/webui/react/src/components/UserAvatar.tsx b/webui/react/src/components/UserAvatar.tsx index e8e28c79a8d..e9695a35d8c 100644 --- a/webui/react/src/components/UserAvatar.tsx +++ b/webui/react/src/components/UserAvatar.tsx @@ -1,6 +1,6 @@ +import Avatar, { Props as AvatarProps } from 'determined-ui/Avatar'; import React from 'react'; -import Avatar, { Props as AvatarProps } from 'components/kit/Avatar'; import { User } from 'types'; import { getDisplayName } from 'utils/user'; diff --git a/webui/react/src/components/UserBadge.tsx b/webui/react/src/components/UserBadge.tsx index 0db65a0a989..0d4272b53a7 100644 --- a/webui/react/src/components/UserBadge.tsx +++ b/webui/react/src/components/UserBadge.tsx @@ -1,6 +1,6 @@ +import Nameplate from 'determined-ui/Nameplate'; import React from 'react'; -import Nameplate from 'components/kit/Nameplate'; import UserAvatar from 'components/UserAvatar'; import { User } from 'types'; diff --git a/webui/react/src/components/UserSettings.settings.ts b/webui/react/src/components/UserSettings.settings.ts index bc95b0fe39a..0bf052ec8a1 100644 --- a/webui/react/src/components/UserSettings.settings.ts +++ b/webui/react/src/components/UserSettings.settings.ts @@ -1,6 +1,6 @@ +import { KeyboardShortcut } from 'determined-ui/InputShortcut'; import { type } from 'io-ts'; -import { KeyboardShortcut } from 'components/kit/InputShortcut'; import { SettingsConfig } from 'hooks/useSettings'; export interface Settings { diff --git a/webui/react/src/components/UserSettings.test.tsx b/webui/react/src/components/UserSettings.test.tsx index 4e3950bf7cc..e6effbd7e59 100644 --- a/webui/react/src/components/UserSettings.test.tsx +++ b/webui/react/src/components/UserSettings.test.tsx @@ -1,9 +1,10 @@ import { waitFor } from '@testing-library/dom'; import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; +import { UIProvider } from 'determined-ui/Theme'; +import { ConfirmationProvider } from 'determined-ui/useConfirm'; import React, { useCallback, useEffect } from 'react'; -import { UIProvider } from 'components/kit/Theme'; import { patchUser as mockPatchUser } from 'services/api'; import { PatchUserParams } from 'services/types'; import authStore from 'stores/auth'; @@ -11,7 +12,6 @@ import userStore from 'stores/users'; import userSettings from 'stores/userSettings'; import { DetailedUser } from 'types'; -import { ConfirmationProvider } from './kit/useConfirm'; import UserSettings from './UserSettings'; vi.mock('services/api', () => ({ diff --git a/webui/react/src/components/UserSettings.tsx b/webui/react/src/components/UserSettings.tsx index 803c69c72eb..b8f4b35a221 100644 --- a/webui/react/src/components/UserSettings.tsx +++ b/webui/react/src/components/UserSettings.tsx @@ -1,17 +1,21 @@ import { Space } from 'antd'; +import Accordion from 'determined-ui/Accordion'; +import Button from 'determined-ui/Button'; +import Drawer from 'determined-ui/Drawer'; +import Icon from 'determined-ui/Icon'; +import InlineForm from 'determined-ui/InlineForm'; +import Input from 'determined-ui/Input'; +import InputShortcut, { KeyboardShortcut, shortcutToString } from 'determined-ui/InputShortcut'; +import { useModal } from 'determined-ui/Modal'; +import Select, { Option } from 'determined-ui/Select'; +import Spinner from 'determined-ui/Spinner'; +import useUI, { Mode } from 'determined-ui/Theme'; +import { makeToast } from 'determined-ui/Toast'; +import Paragraph from 'determined-ui/Typography/Paragraph'; +import useConfirm from 'determined-ui/useConfirm'; +import { Loadable } from 'determined-ui/utils/loadable'; import React, { useCallback, useState } from 'react'; -import Drawer from 'components/kit/Drawer'; -import Icon from 'components/kit/Icon'; -import InlineForm from 'components/kit/InlineForm'; -import Input from 'components/kit/Input'; -import InputShortcut, { KeyboardShortcut, shortcutToString } from 'components/kit/InputShortcut'; -import { useModal } from 'components/kit/Modal'; -import Select, { Option } from 'components/kit/Select'; -import Spinner from 'components/kit/Spinner'; -import useUI, { Mode } from 'components/kit/Theme'; -import { makeToast } from 'components/kit/Toast'; -import { Loadable } from 'components/kit/utils/loadable'; import PasswordChangeModalComponent from 'components/PasswordChangeModal'; import Section from 'components/Section'; import { ThemeOptions } from 'components/ThemeToggle'; @@ -39,10 +43,6 @@ import userSettings from 'stores/userSettings'; import handleError, { ErrorType } from 'utils/error'; import { useObservable } from 'utils/observable'; -import Accordion from './kit/Accordion'; -import Button from './kit/Button'; -import Paragraph from './kit/Typography/Paragraph'; -import useConfirm from './kit/useConfirm'; import css from './UserSettings.module.scss'; import UserSettingsModalComponent from './UserSettingsModal'; diff --git a/webui/react/src/components/UserSettingsModal.tsx b/webui/react/src/components/UserSettingsModal.tsx index 92632677163..7fd0b75cb9a 100644 --- a/webui/react/src/components/UserSettingsModal.tsx +++ b/webui/react/src/components/UserSettingsModal.tsx @@ -1,18 +1,17 @@ import { Alert } from 'antd'; +import CodeEditor from 'determined-ui/CodeEditor'; +import { Modal } from 'determined-ui/Modal'; +import useUI, { Mode } from 'determined-ui/Theme'; +import { Loadable, Loaded } from 'determined-ui/utils/loadable'; import { Map } from 'immutable'; import { useMemoizedObservable } from 'micro-observables'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; -import { Modal } from 'components/kit/Modal'; -import useUI, { Mode } from 'components/kit/Theme'; -import { Loadable, Loaded } from 'components/kit/utils/loadable'; import userSettings from 'stores/userSettings'; import { Json } from 'types'; import { isJsonObject, isObject } from 'utils/data'; import handleError from 'utils/error'; -import CodeEditor from './kit/CodeEditor'; - interface Props { onSave?: () => void; } diff --git a/webui/react/src/components/WebhookCreateModal.tsx b/webui/react/src/components/WebhookCreateModal.tsx index c9ba6080400..ab3a5ea88ee 100644 --- a/webui/react/src/components/WebhookCreateModal.tsx +++ b/webui/react/src/components/WebhookCreateModal.tsx @@ -1,9 +1,9 @@ import { Select } from 'antd'; +import Form from 'determined-ui/Form'; +import Input from 'determined-ui/Input'; +import { Modal } from 'determined-ui/Modal'; import React, { useCallback, useId, useState } from 'react'; -import Form from 'components/kit/Form'; -import Input from 'components/kit/Input'; -import { Modal } from 'components/kit/Modal'; import { paths } from 'routes/utils'; import { createWebhook } from 'services/api'; import { V1TriggerType, V1WebhookType } from 'services/api-ts-sdk/api'; diff --git a/webui/react/src/components/WebhookDeleteModal.tsx b/webui/react/src/components/WebhookDeleteModal.tsx index 464707dc0cf..819d2a2e4fb 100644 --- a/webui/react/src/components/WebhookDeleteModal.tsx +++ b/webui/react/src/components/WebhookDeleteModal.tsx @@ -1,6 +1,6 @@ +import { Modal } from 'determined-ui/Modal'; import React from 'react'; -import { Modal } from 'components/kit/Modal'; import { paths } from 'routes/utils'; import { deleteWebhook } from 'services/api'; import { Webhook } from 'types'; diff --git a/webui/react/src/components/WorkspaceCreateModal.tsx b/webui/react/src/components/WorkspaceCreateModal.tsx index a9072ef808a..1362c9cf98e 100644 --- a/webui/react/src/components/WorkspaceCreateModal.tsx +++ b/webui/react/src/components/WorkspaceCreateModal.tsx @@ -1,13 +1,13 @@ import { Divider, Switch } from 'antd'; +import Form from 'determined-ui/Form'; +import Input from 'determined-ui/Input'; +import InputNumber from 'determined-ui/InputNumber'; +import { Modal } from 'determined-ui/Modal'; +import Spinner from 'determined-ui/Spinner'; +import { Loadable, Loaded, NotLoaded } from 'determined-ui/utils/loadable'; import yaml from 'js-yaml'; import React, { useCallback, useEffect, useId, useMemo } from 'react'; -import Form from 'components/kit/Form'; -import Input from 'components/kit/Input'; -import InputNumber from 'components/kit/InputNumber'; -import { Modal } from 'components/kit/Modal'; -import Spinner from 'components/kit/Spinner'; -import { Loadable, Loaded, NotLoaded } from 'components/kit/utils/loadable'; import usePermissions from 'hooks/usePermissions'; import { paths } from 'routes/utils'; import { patchWorkspace } from 'services/api'; @@ -37,7 +37,7 @@ interface Props { workspaceId?: number; } -const CodeEditor = React.lazy(() => import('components/kit/CodeEditor')); +const CodeEditor = React.lazy(() => import('determined-ui/CodeEditor')); const WorkspaceCreateModalComponent: React.FC = ({ onClose, workspaceId }: Props = {}) => { const idPrefix = useId(); diff --git a/webui/react/src/components/WorkspaceDeleteModal.tsx b/webui/react/src/components/WorkspaceDeleteModal.tsx index c07fb1662a1..c73eaa68cbe 100644 --- a/webui/react/src/components/WorkspaceDeleteModal.tsx +++ b/webui/react/src/components/WorkspaceDeleteModal.tsx @@ -1,8 +1,8 @@ +import Form from 'determined-ui/Form'; +import Input from 'determined-ui/Input'; +import { Modal } from 'determined-ui/Modal'; import React, { useCallback, useId } from 'react'; -import Form from 'components/kit/Form'; -import Input from 'components/kit/Input'; -import { Modal } from 'components/kit/Modal'; import { paths } from 'routes/utils'; import workspaceStore from 'stores/workspaces'; import { Workspace } from 'types'; diff --git a/webui/react/src/components/WorkspaceMemberAddModal.tsx b/webui/react/src/components/WorkspaceMemberAddModal.tsx index 2c7adb2fa8e..26c5c3fc2a2 100644 --- a/webui/react/src/components/WorkspaceMemberAddModal.tsx +++ b/webui/react/src/components/WorkspaceMemberAddModal.tsx @@ -1,11 +1,11 @@ import { Select } from 'antd'; +import Form from 'determined-ui/Form'; +import Icon from 'determined-ui/Icon'; +import { Modal } from 'determined-ui/Modal'; +import Nameplate from 'determined-ui/Nameplate'; +import { makeToast } from 'determined-ui/Toast'; import React, { useCallback, useId, useState } from 'react'; -import Form from 'components/kit/Form'; -import Icon from 'components/kit/Icon'; -import { Modal } from 'components/kit/Modal'; -import Nameplate from 'components/kit/Nameplate'; -import { makeToast } from 'components/kit/Toast'; import UserBadge from 'components/UserBadge'; import { assignRolesToGroup, assignRolesToUser } from 'services/api'; import { V1Role } from 'services/api-ts-sdk'; diff --git a/webui/react/src/components/WorkspaceMemberRemoveModal.tsx b/webui/react/src/components/WorkspaceMemberRemoveModal.tsx index 1da41469f48..ef624a75568 100644 --- a/webui/react/src/components/WorkspaceMemberRemoveModal.tsx +++ b/webui/react/src/components/WorkspaceMemberRemoveModal.tsx @@ -1,7 +1,7 @@ +import { Modal } from 'determined-ui/Modal'; +import { makeToast } from 'determined-ui/Toast'; import React, { useCallback, useState } from 'react'; -import { Modal } from 'components/kit/Modal'; -import { makeToast } from 'components/kit/Toast'; import { removeRolesFromGroup, removeRolesFromUser } from 'services/api'; import { UserOrGroupWithRoleInfo } from 'types'; import handleError, { DetError, ErrorLevel, ErrorType } from 'utils/error'; diff --git a/webui/react/src/components/kit/Accordion.test.tsx b/webui/react/src/components/kit/Accordion.test.tsx deleted file mode 100644 index afa6cded866..00000000000 --- a/webui/react/src/components/kit/Accordion.test.tsx +++ /dev/null @@ -1,211 +0,0 @@ -import { StyleProvider } from '@ant-design/cssinjs'; -import { render, screen } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; - -import Accordion from './Accordion'; - -const user = userEvent.setup(); -type AccordionProps = Parameters[0]; -type AccordionGroupProps = Parameters[0]; - -const titleText = 'title'; -const childText = 'child'; -const singleSetup = (props: Omit = {}) => { - return render( - - - {childText} - - , - ); -}; - -const groupInfo = { - [1]: { - child: 'One -- Child', - title: 'One -- Title', - }, - [2]: { - child: 'Two -- Child', - title: 'Two -- Title', - }, - [3]: { - child: 'Three -- Child', - title: 'Three -- Title', - }, -} as const; - -const groupSetup = (props: Omit = {}) => { - return render( - - - {Object.entries(groupInfo).map(([key, texts]) => ( - // children are mounted immediately to make testing the group state easier - - {texts.child} - - ))} - - , - ); -}; - -describe('Accordion', () => { - describe('single', () => { - it('displays title and children when clicked', async () => { - singleSetup(); - const title = screen.getByText(titleText); - expect(title).toBeVisible(); - await user.click(title); - expect(screen.getByText(childText)).toBeVisible(); - }); - describe('mountChildren', () => { - it('when mountChildren is set to immediately, the child is mounted on mount', () => { - singleSetup({ mountChildren: 'immediately' }); - expect(screen.getByText(childText)).toBeInTheDocument(); - }); - it('when mountChildren is set to on-mount, the child is unmounted on close', async () => { - singleSetup({ mountChildren: 'on-open' }); - expect(screen.queryByText(childText)).toBeNull(); - const title = screen.getByText(titleText); - await user.click(title); - expect(screen.getByText(childText)).toBeInTheDocument(); - await user.click(title); - expect(screen.queryByText(childText)).toBeNull(); - }); - it('when mountchildren is set to on-mount-once, the child remains mounted on close', async () => { - singleSetup({ mountChildren: 'once-on-open' }); - expect(screen.queryByText(childText)).toBeNull(); - const title = screen.getByText(titleText); - await user.click(title); - expect(screen.getByText(childText)).toBeInTheDocument(); - await user.click(title); - expect(screen.getByText(childText)).toBeInTheDocument(); - }); - }); - describe('control', () => { - it('when defaultOpen is set to true, the child is open on mount and uncontrolled', async () => { - singleSetup({ defaultOpen: true }); - const child = screen.getByText(childText); - const title = screen.getByText(titleText); - expect(child).toBeVisible(); - await user.click(title); - expect(child).not.toBeVisible(); - }); - it('when defaultOpen is set to false, the child is closed on mount and uncontrolled', async () => { - singleSetup({ defaultOpen: false }); - expect(screen.queryByText(childText)).toBeNull(); - const title = screen.getByText(titleText); - await user.click(title); - expect(screen.queryByText(childText)).toBeVisible(); - }); - it('when open is true, the child is open on mount and controlled', async () => { - singleSetup({ open: true }); - const child = screen.getByText(childText); - const title = screen.getByText(titleText); - expect(child).toBeVisible(); - await user.click(title); - expect(child).toBeVisible(); - }); - it('when open is false, the child is closed on mount and controlled', async () => { - singleSetup({ open: false }); - expect(screen.queryByText(childText)).toBeNull(); - const title = screen.getByText(titleText); - await user.click(title); - expect(screen.queryByText(childText)).toBeNull(); - }); - }); - }); - describe('group', () => { - type AccordionState = 'open' | 'closed'; - interface GroupState { - [1]: AccordionState; - [2]: AccordionState; - [3]: AccordionState; - } - const expectGroupState = (groupState: GroupState) => { - Object.entries(groupState).forEach(([key, val]) => { - // cast here because key types are collapsed on iteration - const childText = groupInfo[key as unknown as 1 | 2 | 3].child; - if (val === 'open') { - expect(screen.getByText(childText)).toBeVisible(); - } else { - expect(screen.getByText(childText)).not.toBeVisible(); - } - }); - }; - it('renders the accordion group', async () => { - groupSetup(); - expectGroupState({ - [1]: 'closed', - [2]: 'closed', - [3]: 'closed', - }); - const oneTitle = groupInfo[1].title; - await user.click(screen.getByText(oneTitle)); - expectGroupState({ - [1]: 'open', - [2]: 'closed', - [3]: 'closed', - }); - }); - it('can be controlled via openKey', async () => { - groupSetup({ openKey: 1 }); - const expectedGroupState = { - [1]: 'open', - [2]: 'closed', - [3]: 'closed', - } as const; - expectGroupState(expectedGroupState); - const oneTitle = groupInfo[1].title; - await user.click(screen.getByText(oneTitle)); - expectGroupState(expectedGroupState); - }); - it('can have defaults set via defaultOpenKey', async () => { - groupSetup({ defaultOpenKey: 1 }); - expectGroupState({ - [1]: 'open', - [2]: 'closed', - [3]: 'closed', - }); - const oneTitle = groupInfo[1].title; - await user.click(screen.getByText(oneTitle)); - expectGroupState({ - [1]: 'closed', - [2]: 'closed', - [3]: 'closed', - }); - }); - it('can set multiple children to open via openKey', () => { - groupSetup({ openKey: [1, 3] }); - expectGroupState({ - [1]: 'open', - [2]: 'closed', - [3]: 'open', - }); - }); - it('can default multiple children to open via defaultOpenKey', () => { - groupSetup({ defaultOpenKey: [1, 3] }); - expectGroupState({ - [1]: 'open', - [2]: 'closed', - [3]: 'open', - }); - }); - it('can keep only one child open in exclusive mode', async () => { - groupSetup({ defaultOpenKey: 3, exclusive: true }); - expectGroupState({ - [1]: 'closed', - [2]: 'closed', - [3]: 'open', - }); - const oneTitle = groupInfo[1].title; - await user.click(screen.getByText(oneTitle)); - expectGroupState({ - [1]: 'open', - [2]: 'closed', - [3]: 'closed', - }); - }); - }); -}); diff --git a/webui/react/src/components/kit/Accordion.tsx b/webui/react/src/components/kit/Accordion.tsx deleted file mode 100644 index 8a27b209c41..00000000000 --- a/webui/react/src/components/kit/Accordion.tsx +++ /dev/null @@ -1,90 +0,0 @@ -import { Collapse } from 'antd'; -import React from 'react'; - -import { ConditionalWrapper } from 'components/kit/internal/ConditionalWrapper'; - -interface AccordionProps { - title: React.ReactNode; - children: React.ReactNode; - key?: string | number; - open?: boolean; - defaultOpen?: boolean; - mountChildren?: 'immediately' | 'on-open' | 'once-on-open'; -} - -interface AccordionGroupProps { - exclusive?: boolean; - openKey?: string | number | string[] | number[]; - defaultOpenKey?: string | number | string[] | number[]; - children: React.ReactNode; -} - -const AccordionGroup: React.FC = ({ - exclusive, - children, - openKey, - defaultOpenKey, -}) => { - // handle uncontrolled behavior - const activeProp = openKey !== undefined ? { activeKey: openKey } : {}; - // disable default collapse accordion behavior where the first child is open - const defaultActiveKey = defaultOpenKey ? defaultOpenKey : exclusive ? [] : undefined; - return ( - - {children} - - ); -}; - -const Accordion: React.FC & { Group: typeof AccordionGroup } = ({ - title, - children, - open, - defaultOpen, - mountChildren = 'once-on-open', - ...otherProps -}) => { - // Collapse passes housekeeping props through to the child -- assume - // that we're in a multi-accordion situation when we encounter this - const inGroup = 'panelKey' in otherProps; - // key used for single accordion cases - const key = -1; - - const wrapper = (c: React.ReactElement) => { - // handle isActive for single accordions - let collapseProps = {}; - if (defaultOpen !== undefined) { - collapseProps = { defaultActiveKey: defaultOpen ? key : '' }; - } - if (open !== undefined) { - collapseProps = { activeKey: open ? key : '' }; - } - return {c}; - }; - let panelProps = {}; - switch (mountChildren) { - case 'immediately': { - panelProps = { forceRender: true }; - break; - } - case 'on-open': { - panelProps = { destroyInactivePanel: true }; - break; - } - case 'once-on-open': - default: { - panelProps = {}; - } - } - - return ( - - - {children} - - - ); -}; - -export default Accordion; -Accordion.Group = AccordionGroup; diff --git a/webui/react/src/components/kit/Avatar.module.scss b/webui/react/src/components/kit/Avatar.module.scss deleted file mode 100644 index e6d39c28395..00000000000 --- a/webui/react/src/components/kit/Avatar.module.scss +++ /dev/null @@ -1,21 +0,0 @@ -.base { - align-items: center; - border-radius: 100%; - display: flex; - font-size: 10px; - font-weight: bold; - height: 24px; - justify-content: center; - line-height: 1; - width: 24px; -} -.base.large { - font-size: 24px; - height: 64px; - width: 64px; -} -.base.extra-large { - font-size: 96px; - height: 192px; - width: 192px; -} diff --git a/webui/react/src/components/kit/Avatar.test.tsx b/webui/react/src/components/kit/Avatar.test.tsx deleted file mode 100644 index 1990cb83d4b..00000000000 --- a/webui/react/src/components/kit/Avatar.test.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import { render, screen } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; -import React from 'react'; - -import { UIProvider } from 'components/kit/Theme'; - -import Avatar, { Props } from './Avatar'; - -vi.mock('components/kit/Tooltip'); -const user = userEvent.setup(); - -const setup = ({ displayName, hideTooltip = false, ...props }: Props) => { - render( - - - , - ); -}; - -describe('Avatar', () => { - const displayName = 'Bugs Bunny'; - const initials = 'BB'; - - it('should display initials of name', async () => { - setup({ displayName }); - - expect(await screen.findByText(initials)).toBeInTheDocument(); - }); - - it('should display name on hover', async () => { - setup({ displayName }); - - await user.hover(await screen.findByText(initials)); - - expect(await screen.findByText(displayName)).toBeInTheDocument(); - }); - - it('shouldnt display name on hover if hideTooltip is true', async () => { - setup({ displayName, hideTooltip: true }); - - await user.hover(await screen.findByText(initials)); - - expect(screen.queryByText(displayName)).not.toBeInTheDocument(); - }); -}); diff --git a/webui/react/src/components/kit/Avatar.tsx b/webui/react/src/components/kit/Avatar.tsx deleted file mode 100644 index ed0fc9eae3f..00000000000 --- a/webui/react/src/components/kit/Avatar.tsx +++ /dev/null @@ -1,80 +0,0 @@ -import React from 'react'; - -import { hex2hsl, hsl2str } from 'components/kit/internal/functions'; -import md5 from 'components/kit/internal/md5'; -import { DarkLight, ValueOf } from 'components/kit/internal/types'; -import useUI from 'components/kit/Theme'; -import Tooltip from 'components/kit/Tooltip'; - -import css from './Avatar.module.scss'; - -export const Size = { - ExtraLarge: 'extra-large', - Large: 'large', - Medium: 'medium', -} as const; - -export type Size = ValueOf; - -export interface Props { - displayName: string; - hideTooltip?: boolean; - /** do not color the bg based on displayName */ - noColor?: boolean; - size?: Size; - square?: boolean; -} - -export const getInitials = (name = ''): string => { - // Reduce the name to initials. - const initials = name - .split(/\s+/) - .map((n) => n.charAt(0).toUpperCase()) - .join(''); - - // If initials are long, just keep the first and the last. - return initials.length > 2 - ? `${initials.charAt(0)}${initials.substring(initials.length - 1)}` - : initials; -}; - -export const getColor = (name = '', darkLight: DarkLight): string => { - const hslColor = name ? hex2hsl(md5(name).substring(0, 6)) : hex2hsl('#808080'); - return hsl2str({ - ...hslColor, - l: darkLight === DarkLight.Dark ? 38 : 60, - }); -}; - -const Avatar: React.FC = ({ - displayName, - hideTooltip, - noColor, - size = Size.Medium, - square, -}) => { - const { ui } = useUI(); - - const style = { - backgroundColor: noColor ? 'var(--theme-stage-strong)' : getColor(displayName, ui.darkLight), - borderRadius: square ? '10%' : '100%', - color: noColor ? 'var(--theme-stage-on-strong)' : 'white', - }; - const classes = [css.base, css[size]]; - - const avatar = ( -
- {getInitials(displayName)} -
- ); - - return hideTooltip ? ( - avatar - ) : ( - - {avatar} - - ); -}; - -export default Avatar; diff --git a/webui/react/src/components/kit/Breadcrumb.module.css b/webui/react/src/components/kit/Breadcrumb.module.css deleted file mode 100644 index ed827bd8397..00000000000 --- a/webui/react/src/components/kit/Breadcrumb.module.css +++ /dev/null @@ -1,3 +0,0 @@ -.base { - align-self: flex-start; -} diff --git a/webui/react/src/components/kit/Breadcrumb.tsx b/webui/react/src/components/kit/Breadcrumb.tsx deleted file mode 100644 index e6da3996c7c..00000000000 --- a/webui/react/src/components/kit/Breadcrumb.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import { Breadcrumb as AntdBreadcrumb } from 'antd'; -import React, { ReactNode } from 'react'; - -import Button from 'components/kit/Button'; -import { Column, Columns } from 'components/kit/Columns'; -import Dropdown, { MenuItem } from 'components/kit/Dropdown'; -import Icon from 'components/kit/Icon'; - -import css from './Breadcrumb.module.css'; -interface BreadcrumbProps { - children?: ReactNode; - separator?: ReactNode; - menuItems?: MenuItem[]; - onClickMenu?: (key: string) => void; -} - -interface BreadcrumbItemProps { - children?: ReactNode; -} - -type BreadcrumbItem = React.FC; -type BreadcrumbSeparator = React.FC; -type Breadcrumb = React.FC & { - Item: BreadcrumbItem; - Separator: BreadcrumbSeparator; -}; - -const Breadcrumb: Breadcrumb = (props: BreadcrumbProps) => { - return ( -
- - - {props.children} - - {props.menuItems && ( - - -
- ); -}; - -Breadcrumb.Item = AntdBreadcrumb.Item; -Breadcrumb.Separator = AntdBreadcrumb.Separator; - -export default Breadcrumb; diff --git a/webui/react/src/components/kit/Button.module.scss b/webui/react/src/components/kit/Button.module.scss deleted file mode 100644 index a1dccfc6712..00000000000 --- a/webui/react/src/components/kit/Button.module.scss +++ /dev/null @@ -1,58 +0,0 @@ -.base:global(.ant-btn-dangerous) { - &:global(.ant-btn-default) { - border-color: var(--theme-status-critical); - color: var(--theme-status-critical); - } - &:global(.ant-btn-primary) { - background-color: var(--theme-status-critical); - } - &:global(.ant-btn-text) { - color: var(--theme-status-critical); - } - &:global(.ant-btn-dashed) { - border-color: var(--theme-status-critical); - color: var(--theme-status-critical); - } -} -.base:global(.ant-btn[disabled].ant-btn-text:disabled) { - background-color: transparent; - border: none; - - &:hover { - background-color: transparent; - border: none; - } -} -.selected { - &:global(.ant-btn-default) { - border-color: #177ddc; - color: #177ddc; - } - &:global(.ant-btn-dashed) { - border-color: #177ddc; - color: #177ddc; - } -} -.content { - align-items: center; - display: flex; - gap: 8px; - height: 100%; - justify-content: center; - - .icon, - .children { - align-items: center; - display: flex; - height: 100%; - } -} -.column { - &:global(.ant-btn) { - height: 100%; // override antd px values - } - > .content { - flex-direction: column; - margin: 8px 0; - } -} diff --git a/webui/react/src/components/kit/Button.tsx b/webui/react/src/components/kit/Button.tsx deleted file mode 100644 index abf1ca84230..00000000000 --- a/webui/react/src/components/kit/Button.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import { Button as AntdButton } from 'antd'; -import React, { forwardRef, MouseEvent, ReactNode } from 'react'; - -import { ConditionalWrapper } from 'components/kit/internal/ConditionalWrapper'; -import Tooltip from 'components/kit/Tooltip'; - -import css from './Button.module.scss'; - -interface ButtonProps { - block?: boolean; - children?: ReactNode; - danger?: boolean; - disabled?: boolean; - form?: string; - hideChildren?: boolean; - htmlType?: 'button' | 'submit' | 'reset'; - icon?: ReactNode; - column?: boolean; - loading?: boolean | { delay?: number }; - onClick?: (event: MouseEvent) => void; - ref?: React.Ref; - selected?: boolean; - size?: 'large' | 'middle' | 'small'; - type?: 'primary' | 'text' | 'default' | 'dashed'; - tooltip?: string; -} - -interface CloneElementProps { - // antd parent component (Dropdown) may set this component's className prop via cloneElement. - className?: string; -} - -const Button: React.FC = forwardRef( - ( - { - size = 'middle', - tooltip = '', - className, // do not include className in {...props} below. - hideChildren = false, - children, - icon, - ...props - }: ButtonProps & CloneElementProps, - ref, - ) => { - const classes = [css.base]; - if (className) classes.push(className); // preserve className value set via cloneElement. - if (props.selected) classes.push(css.selected); - if (props.column) classes.push(css.column); - - return ( - 0} - wrapper={(children) => {children}}> - - {props.loading ? ( - !hideChildren && children // use antd spinner and styling - ) : ( -
- {icon &&
{icon}
} - {!hideChildren && children &&
{children}
} -
- )} -
-
- ); - }, -); - -export default Button; diff --git a/webui/react/src/components/kit/Card.module.scss b/webui/react/src/components/kit/Card.module.scss deleted file mode 100644 index 5c5595df32d..00000000000 --- a/webui/react/src/components/kit/Card.module.scss +++ /dev/null @@ -1,68 +0,0 @@ -.cardBase { - --transition-duration: 0.25s; - --transition-delay: 0.05s; - --outside-padding: 16px; - background-color: var(--theme-surface); - border-radius: var(--theme-border-radius-weak); - box-shadow: 0 1.6px 3.6px 1.6px rgb(0 0 0 / 13%); - color: var(--theme-surface-on); - display: flex; - flex-direction: column; - max-width: fit-content; - padding: var(--outside-padding); - position: relative; - transition: background-color var(--transition-duration); - transition-delay: var(--transition-delay); - - .action { - background-color: inherit; - opacity: 0; - padding-bottom: 2px; - padding-left: 2px; - position: absolute; - right: var(--outside-padding); - top: var(--outside-padding); - transition: all var(--transition-duration); - transition-delay: var(--transition-delay); - } - .content { - display: flex; - flex-direction: column; - flex-grow: 1; - - & > * { - flex-grow: 1; - } - } - &.clickable { - cursor: pointer; - } - &:hover, - &:focus-within { - color: var(--theme-surface-on); - - &.clickable { - background-color: var(--theme-surface-weak); - } - .action { - opacity: 1; - } - } - &:focus-visible { - outline: var(--theme-stroke-width-strong) solid var(--theme-ix-border-active); - } - &.smallCard { - --outside-padding: 8px; - } - &.mediumCard { - --outside-padding: 16px; - } -} -.groupBase { - padding: 4px; - - & > .cardBase { - max-width: none; - min-width: 100%; - } -} diff --git a/webui/react/src/components/kit/Card.tsx b/webui/react/src/components/kit/Card.tsx deleted file mode 100644 index f5a9b11bc72..00000000000 --- a/webui/react/src/components/kit/Card.tsx +++ /dev/null @@ -1,108 +0,0 @@ -import React, { Children, CSSProperties } from 'react'; - -import Icon from 'components/kit/Icon'; -import { isNumber } from 'components/kit/internal/functions'; -import Grid, { GridMode } from 'components/kit/internal/Grid'; - -import Button from './Button'; -import css from './Card.module.scss'; -import Dropdown, { MenuItem } from './Dropdown'; -import { AnyMouseEventHandler } from './internal/types'; - -type CardProps = { - actionMenu?: MenuItem[]; - children?: React.ReactNode; - disabled?: boolean; - size?: keyof typeof CardSize; - onDropdown?: (key: string) => void; - onClick?: AnyMouseEventHandler; -}; - -const CardSize: Record = { - medium: { minHeight: '110px', minWidth: '302px' }, - small: { minHeight: '64px', minWidth: '143px' }, -} as const; - -type Card = React.FC & { - Group: React.FC; -}; - -const stopPropagation = (e: React.MouseEvent): void => e.stopPropagation(); - -const Card: Card = ({ - actionMenu, - children, - disabled = false, - onClick, - onDropdown, - size = 'small', -}: CardProps) => { - const classnames = [css.cardBase]; - if (onClick) classnames.push(css.clickable); - const sizeStyle = CardSize[size]; - switch (size) { - case 'small': - classnames.push(css.smallCard); - break; - case 'medium': - classnames.push(css.mediumCard); - break; - } - - const actionsAvailable = actionMenu?.length !== undefined && actionMenu.length > 0; - - return ( -
- {children &&
{children}
} - {actionsAvailable && ( -
- -
- )} -
- ); -}; - -interface CardGroupProps { - children?: React.ReactNode; - size?: keyof typeof CardSize; // This should match the size of cards in group. - wrap?: boolean; -} - -const CardGroup: React.FC = ({ - children, - wrap = true, - size = 'small', -}: CardGroupProps) => { - const cardSize = CardSize[size].minWidth; - const minCardWidth = cardSize ? (isNumber(cardSize) ? cardSize : parseInt(cardSize)) : undefined; - - return ( - - {children} - - ); -}; - -Card.Group = CardGroup; - -export default Card; diff --git a/webui/react/src/components/kit/Checkbox.tsx b/webui/react/src/components/kit/Checkbox.tsx deleted file mode 100644 index ae46d1470fa..00000000000 --- a/webui/react/src/components/kit/Checkbox.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { Checkbox as AntdCheckbox } from 'antd'; -import type { CheckboxChangeEvent } from 'antd/lib/checkbox'; -import React, { ReactNode } from 'react'; - -interface CheckboxProps { - checked?: boolean; - children?: ReactNode; - disabled?: boolean; - id?: string; - indeterminate?: boolean; - onChange?: (event: CheckboxChangeEvent) => void; -} - -interface GroupProps { - children?: ReactNode; -} - -const Checkbox: Checkbox = (props: CheckboxProps) => { - return ; -}; - -type Checkbox = React.FC & { - Group: React.FC; -}; - -Checkbox.Group = AntdCheckbox.Group; - -export default Checkbox; diff --git a/webui/react/src/components/kit/ClipboardButton.test.tsx b/webui/react/src/components/kit/ClipboardButton.test.tsx deleted file mode 100644 index 09aa713480e..00000000000 --- a/webui/react/src/components/kit/ClipboardButton.test.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { render, screen, waitFor } from '@testing-library/react'; -import userEvent, { PointerEventsCheckLevel } from '@testing-library/user-event'; - -import ClipboardButton, { TOOLTIP_LABEL_DEFAULT } from './ClipboardButton'; - -const user = userEvent.setup({ pointerEventsCheck: PointerEventsCheckLevel.Never }); - -const CLIPBOARD_CONTENT = 'Copy this into the clipboard.'; - -const setup = () => { - const handleCopy = vi.fn(); - const view = render( CLIPBOARD_CONTENT} onCopy={handleCopy} />); - return { handleCopy, view }; -}; - -describe('ClipboardButton', () => { - it('displays a clipboard button and copies content to clipboard', async () => { - const { handleCopy } = setup(); - const roleOptions = { name: TOOLTIP_LABEL_DEFAULT }; - - await waitFor(() => { - expect(screen.queryByRole('button', roleOptions)).toBeInTheDocument(); - }); - - await user.click(screen.getByRole('button', roleOptions)); - expect(handleCopy).toHaveBeenCalled(); - }); -}); diff --git a/webui/react/src/components/kit/ClipboardButton.tsx b/webui/react/src/components/kit/ClipboardButton.tsx deleted file mode 100644 index fac68da0574..00000000000 --- a/webui/react/src/components/kit/ClipboardButton.tsx +++ /dev/null @@ -1,88 +0,0 @@ -import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; - -import Icon from 'components/kit/Icon'; -import { copyToClipboard } from 'components/kit/internal/functions'; - -import Button from './Button'; -import { makeToast } from './Toast'; -import Tooltip, { Placement } from './Tooltip'; - -type IconName = 'clipboard' | 'checkmark'; - -interface Props { - copiedMessage?: string; - disabled?: boolean; - // A get content function is used to dynamically fetch content when it is needed. - getContent: () => string; - tooltipPlacement?: Placement; - onCopy?: () => void; -} - -export const TOOLTIP_LABEL_DEFAULT = 'Copy to clipboard'; -const TOOLTIP_LABEL_SUCCESS = 'Copied!'; - -const ClipboardButton: React.FC = ({ - copiedMessage = TOOLTIP_LABEL_SUCCESS, - disabled, - getContent, - tooltipPlacement = 'top', - onCopy, -}) => { - const [iconName, setIconName] = useState('clipboard'); - const [tooltipLabel, setTooltipLabel] = useState(TOOLTIP_LABEL_DEFAULT); - const [tooltipOpen, setTooltipOpen] = useState(false); - const buttonRef = useRef(null); - - const icon = useMemo(() => , [iconName]); - - const handleCopyToClipboard = useCallback(async () => { - try { - await copyToClipboard(getContent()); - setTooltipLabel(copiedMessage); - setIconName('checkmark'); - onCopy?.(); - } catch (e) { - setTooltipOpen(false); - makeToast({ - description: (e as Error)?.message, - severity: 'Error', - title: 'Unable to Copy to Clipboard', - }); - } - }, [copiedMessage, getContent, onCopy]); - - useEffect(() => { - const button = buttonRef.current; - const onMouseEnter = () => { - setTooltipLabel(TOOLTIP_LABEL_DEFAULT); - setIconName('clipboard'); - setTooltipOpen(true); - }; - const onMouseLeave = () => { - setTooltipOpen(false); - setIconName('clipboard'); - }; - - button?.addEventListener('mouseenter', onMouseEnter); - button?.addEventListener('mouseleave', onMouseLeave); - - return () => { - button?.removeEventListener('mouseenter', onMouseEnter); - button?.removeEventListener('mouseleave', onMouseLeave); - }; - }, []); - - return ( - - - */} - {readonly && file !== NotLoaded && ( - ; - -const user = userEvent.setup({ pointerEventsCheck: PointerEventsCheckLevel.Never }); - -const setup = (props: PropsWithChildren = { children: Trigger(), menu: MENU }) => { - const handleClick = vi.fn(); - const view = render(); - return { handleClick, view }; -}; - -describe('Dropdown', () => { - it('renders dropdown trigger', async () => { - setup(); - - await waitFor(() => { - expect(screen.queryByRole('button', { name: TRIGGER_LABEL })).toBeInTheDocument(); - }); - }); - - it('opens dropdown', async () => { - setup(); - - await user.click(screen.getByRole('button', { name: TRIGGER_LABEL })); - - await waitFor(() => { - expect(screen.queryByRole('menuitem', { name: MENU_LABEL_1 })).toBeInTheDocument(); - expect(screen.queryByRole('menuitem', { name: MENU_LABEL_2 })).toBeInTheDocument(); - expect(screen.queryByRole('menuitem', { name: MENU_LABEL_3 })).toBeInTheDocument(); - }); - }); - - it('select option and closes dropdown', async () => { - const { handleClick } = setup(); - - await user.click(screen.getByRole('button', { name: TRIGGER_LABEL })); - await waitFor(() => { - expect(screen.queryByRole('menuitem', { name: MENU_LABEL_1 })).toBeInTheDocument(); - }); - - await user.click(screen.getByRole('menuitem', { name: MENU_LABEL_1 })); - expect(handleClick).toHaveBeenCalled(); - - /** - * The dropdown is appended to the end of the body/document and dismissing the - * dropdown menu does not remove it, but simply applies a class to hide it. - */ - await waitFor(() => { - const menu = document.getElementsByClassName('ant-dropdown'); - expect(menu[0]).toHaveClass('ant-dropdown-hidden'); - }); - }); -}); diff --git a/webui/react/src/components/kit/Dropdown.tsx b/webui/react/src/components/kit/Dropdown.tsx deleted file mode 100644 index 29b58f87327..00000000000 --- a/webui/react/src/components/kit/Dropdown.tsx +++ /dev/null @@ -1,120 +0,0 @@ -import { Popover as AntdPopover, Dropdown as AntDropdown } from 'antd'; -import { MenuProps as AntdMenuProps } from 'antd/es/menu/menu'; -import { MenuClickEventHandler } from 'rc-menu/lib/interface'; -import { PropsWithChildren, useMemo } from 'react'; -import * as React from 'react'; - -import css from './Dropdown.module.scss'; - -export interface MenuDivider { - type: 'divider'; -} - -export interface MenuOption { - danger?: boolean; - disabled?: boolean; - key: number | string; - label?: React.ReactNode; - icon?: React.ReactNode; - onClick?: MenuClickEventHandler; -} - -export interface MenuOptionGroup { - children: MenuItem[]; - label: React.ReactNode; - type: 'group'; -} - -export type MenuItem = MenuDivider | MenuOption | MenuOptionGroup | null; - -export type Placement = 'bottomLeft' | 'bottomRight'; - -export type DropdownEvent = React.MouseEvent | React.KeyboardEvent; - -interface BaseProps { - content?: React.ReactNode; - disabled?: boolean; - isContextMenu?: boolean; - menu?: MenuItem[]; - open?: boolean; - onOpenChange?: (open: boolean) => void; - autoWidthOverlay?: boolean; - placement?: Placement; - onClick?: (key: string, e: DropdownEvent) => void | Promise; -} - -type ContentProps = { - content?: React.ReactNode; - menu?: never; - selectable?: never; - selectedKeys?: never; -}; - -type MenuProps = { - content?: never; - menu?: MenuItem[]; - selectable?: boolean; - selectedKeys?: string[]; -}; - -export type Props = (ContentProps | MenuProps) & BaseProps; - -const Dropdown: React.FC> = ({ - children, - content, - disabled, - isContextMenu, - menu = [], - open, - autoWidthOverlay, - placement = 'bottomLeft', - onClick, - onOpenChange, - selectable, - selectedKeys, -}) => { - const antdMenu: AntdMenuProps = useMemo(() => { - return { - items: menu, - onClick: (info) => { - info.domEvent.stopPropagation(); - onClick?.(info.key, info.domEvent); - }, - selectable, - selectedKeys, - }; - }, [menu, onClick, selectable, selectedKeys]); - const overlayStyle = autoWidthOverlay ? { minWidth: 'auto' } : undefined; - - /** - * Using `dropdownRender` for Dropdown causes some issues with triggering the dropdown. - * Instead, Popover is used when rendering content (as opposed to menu). - */ - return content ? ( - - {children} - - ) : ( - - {children} - - ); -}; - -export default Dropdown; diff --git a/webui/react/src/components/kit/Form.module.scss b/webui/react/src/components/kit/Form.module.scss deleted file mode 100644 index 8eba431fc98..00000000000 --- a/webui/react/src/components/kit/Form.module.scss +++ /dev/null @@ -1,10 +0,0 @@ -.formItem { - margin-bottom: 8px; - - :global(.ant-form-item-explain) { - align-items: flex-start; - display: flex; - flex-direction: column; - gap: 4px; - } -} diff --git a/webui/react/src/components/kit/Form.tsx b/webui/react/src/components/kit/Form.tsx deleted file mode 100644 index 57130a3d288..00000000000 --- a/webui/react/src/components/kit/Form.tsx +++ /dev/null @@ -1,118 +0,0 @@ -import { - Form as AntdForm, - FormInstance as AntdFormInstance, - FormItemProps as AntdFormItemProps, - FormProps as AntdFormProps, -} from 'antd'; -import { FormListFieldData as AntdFormListFieldData } from 'antd/lib/form/FormList'; -import { FieldData as AntdFieldData, NamePath as AntdNamePath } from 'rc-field-form/lib/interface'; -import React, { FC, ReactNode, Ref } from 'react'; - -import { Primitive } from 'components/kit/internal/types'; - -import css from './Form.module.scss'; - -type Rules = AntdFormItemProps['rules']; // https://github.com/ant-design/ant-design/issues/39466 -type GridCol = { - span: number; -}; -type TriggerEvent = 'onChange' | 'onSubmit'; - -interface FormItemProps { - children?: ReactNode; - className?: string; - dependencies?: AntdNamePath[]; - extra?: ReactNode; - field?: AntdFormListFieldData; - hidden?: boolean; - initialValue?: string | number | Primitive; - label?: ReactNode; - labelCol?: GridCol; // https://ant.design/components/grid#col - max?: number; - maxMessage?: string; - name?: string | number | (string | number)[]; - noStyle?: boolean; - required?: boolean; - requiredMessage?: string; - rules?: Rules; // https://ant.design/components/form#rule - validateMessage?: string; - validateStatus?: 'success' | 'warning' | 'error' | 'validating'; - validateTrigger?: TriggerEvent[]; - valuePropName?: string; -} - -const FormItem: React.FC = ({ - children, - label, - labelCol = { span: 24 }, - max, - maxMessage, - required, - requiredMessage, - rules = [], - validateMessage, - ...props -}: FormItemProps) => { - if (required) rules.push({ message: requiredMessage || `${label} required`, required: true }); - if (max) rules.push({ max, message: maxMessage || `${label} cannot exceed ${max} characters` }); - - return ( - - {children} - - ); -}; - -interface FormProps { - autoComplete?: string; - children?: ReactNode; - className?: string; - fields?: AntdFieldData[]; - form?: AntdFormProps['form']; - hidden?: boolean; - id?: string; - initialValues?: object; - labelCol?: GridCol; - layout?: 'horizontal' | 'vertical' | 'inline'; - name?: string; - noValidate?: boolean; - onFieldsChange?: AntdFormProps['onFieldsChange']; - onFinish?: AntdFormProps['onFinish']; - onValuesChange?: AntdFormProps['onValuesChange']; - ref?: Ref; - wrapperCol?: GridCol; -} - -type Form = JSX.Element & { - Item?: FC; - List?: typeof AntdForm.List; - useForm?: typeof AntdForm.useForm; -}; - -const Form = ({ noValidate = true, ...props }: FormProps): JSX.Element => { - return ; -}; - -Form.Item = FormItem; -Form.List = AntdForm.List; -Form.ErrorList = AntdForm.ErrorList; -Form.useForm = AntdForm.useForm; -Form.useWatch = AntdForm.useWatch; - -export const hasErrors = (form: FormInstance): boolean => { - return form.getFieldsError().some(({ errors }) => errors.length); -}; - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export type FormInstance = AntdFormInstance; - -export type FormListFieldData = AntdFormListFieldData; - -export default Form; diff --git a/webui/react/src/components/kit/Icon.tsx b/webui/react/src/components/kit/Icon.tsx deleted file mode 100644 index 6af7b3c0dce..00000000000 --- a/webui/react/src/components/kit/Icon.tsx +++ /dev/null @@ -1,357 +0,0 @@ -import { - ExclamationCircleOutlined, - HolderOutlined, - MinusCircleOutlined, - ProjectOutlined, -} from '@ant-design/icons'; -import React, { useMemo } from 'react'; - -import Tooltip from 'components/kit/Tooltip'; - -import ActiveIcon from './Icon/Active'; -import css from './Icon/Icon.module.scss'; -import QueuedIcon from './Icon/Queue'; -import { SpinBowtie, SpinHalf, SpinShadow } from './Icon/Spin'; -import AddIcon from './icons/add.svg'; -import ArchiveIcon from './icons/archive.svg'; -import ArrowDownIcon from './icons/arrow-down.svg'; -import ArrowLeftIcon from './icons/arrow-left.svg'; -import ArrowRightIcon from './icons/arrow-right.svg'; -import ArrowUpIcon from './icons/arrow-up.svg'; -import CancelledIcon from './icons/cancelled.svg'; -import CheckmarkIcon from './icons/checkmark.svg'; -import CheckpointIcon from './icons/checkpoint.svg'; -import ClipboardIcon from './icons/clipboard.svg'; -import CloseIcon from './icons/close.svg'; -import CloudIcon from './icons/cloud.svg'; -import ClusterIcon from './icons/cluster.svg'; -import CollapseIcon from './icons/collapse.svg'; -import ColumnsIcon from './icons/columns.svg'; -import CommandIcon from './icons/command.svg'; -import DaiLogoIcon from './icons/dai-logo.svg'; -import DashboardIcon from './icons/dashboard.svg'; -import DebugIcon from './icons/debug.svg'; -import DocsIcon from './icons/docs.svg'; -import DocumentIcon from './icons/document.svg'; -import DownloadIcon from './icons/download.svg'; -import ErrorIcon from './icons/error.svg'; -import ExpandIcon from './icons/expand.svg'; -import ExperimentIcon from './icons/experiment.svg'; -import EyeCloseIcon from './icons/eye-close.svg'; -import EyeOpenIcon from './icons/eye-open.svg'; -import FilterIcon from './icons/filter.svg'; -import ForkIcon from './icons/fork.svg'; -import FourSquaresIcon from './icons/four-squares.svg'; -import FullscreenIcon from './icons/fullscreen.svg'; -import GridIcon from './icons/grid.svg'; -import GroupIcon from './icons/group.svg'; -import HeatIcon from './icons/heat.svg'; -import HeatmapIcon from './icons/heatmap.svg'; -import HomeIcon from './icons/home.svg'; -import InfoIcon from './icons/info.svg'; -import JupyterLabIcon from './icons/jupyter-lab.svg'; -import LearningIcon from './icons/learning.svg'; -import ListIcon from './icons/list.svg'; -import LockIcon from './icons/lock.svg'; -import LogsIcon from './icons/logs.svg'; -import ModelIcon from './icons/model.svg'; -import NotebookIcon from './icons/notebook.svg'; -import OptionsIcon from './icons/options.svg'; -import OverflowHorizontalIcon from './icons/overflow-horizontal.svg'; -import OverflowVerticalIcon from './icons/overflow-vertical.svg'; -import PanelOnIcon from './icons/panel-on.svg'; -import PanelIcon from './icons/panel.svg'; -import ParcoordsIcon from './icons/parcoords.svg'; -import PauseIcon from './icons/pause.svg'; -import PencilIcon from './icons/pencil.svg'; -import PinIcon from './icons/pin.svg'; -import PlayIcon from './icons/play.svg'; -import PopoutIcon from './icons/popout.svg'; -import PowerIcon from './icons/power.svg'; -import QueueIcon from './icons/queue.svg'; -import ResetIcon from './icons/reset.svg'; -import RowExtraLargeIcon from './icons/row-extra-large.svg'; -import RowLargeIcon from './icons/row-large.svg'; -import RowMediumIcon from './icons/row-medium.svg'; -import RowSmallIcon from './icons/row-small.svg'; -import ScatterPlotIcon from './icons/scatter-plot.svg'; -import ScrollIcon from './icons/scroll.svg'; -import SearchIcon from './icons/search.svg'; -import SearcherAdaptiveIcon from './icons/searcher-adaptive.svg'; -import SearcherGridIcon from './icons/searcher-grid.svg'; -import SearcherRandomIcon from './icons/searcher-random.svg'; -import SettingsIcon from './icons/settings.svg'; -import ShellIcon from './icons/shell.svg'; -import SpinnerIcon from './icons/spinner.svg'; -import StarIcon from './icons/star.svg'; -import StopIcon from './icons/stop.svg'; -import TasksIcon from './icons/tasks.svg'; -import TensorBoardIcon from './icons/tensor-board.svg'; -import TensorboardIcon from './icons/tensorboard.svg'; -import UndoIcon from './icons/undo.svg'; -import UserIcon from './icons/user.svg'; -import WarningIcon from './icons/warning.svg'; -import WorkspacesIcon from './icons/workspaces.svg'; -import { XOR } from './internal/types'; - -export const IconSizeArray = [ - 'tiny', - 'small', - 'medium', - 'large', - 'big', - 'great', - 'huge', - 'enormous', - 'giant', - 'jumbo', - 'mega', -] as const; - -export type IconSize = (typeof IconSizeArray)[number]; - -export const svgIcons = [ - 'columns', - 'filter', - 'four-squares', - 'options', - 'panel', - 'panel-on', - 'row-large', - 'row-medium', - 'row-small', - 'row-xl', - 'heatmap', - 'scroll', - 'home', - 'dai-logo', - 'arrow-left', - 'arrow-right', - 'add', - 'search', - 'arrow-down', - 'arrow-up', - 'cancelled', - 'group', - 'workspaces', - 'archive', - 'queue', - 'model', - 'fork', - 'pause', - 'play', - 'stop', - 'reset', - 'undo', - 'learning', - 'heat', - 'scatter-plot', - 'parcoords', - 'pencil', - 'settings', - 'docs', - 'power', - 'close', - 'dashboard', - 'checkmark', - 'cloud', - 'document', - 'logs', - 'tasks', - 'checkpoint', - 'download', - 'debug', - 'error', - 'warning', - 'info', - 'clipboard', - 'fullscreen', - 'eye-close', - 'eye-open', - 'user', - 'jupyter-lab', - 'lock', - 'popout', - 'spinner', - 'collapse', - 'expand', - 'tensorboard', - 'cluster', - 'command', - 'experiment', - 'grid', - 'list', - 'notebook', - 'overflow-horizontal', - 'overflow-vertical', - 'shell', - 'star', - 'tensor-board', - 'searcher-random', - 'searcher-grid', - 'searcher-adaptive', - 'critical', - 'trace', - 'webhooks', - 'external', - 'pin', -] as const; - -const svgIconMap: Partial> = { - 'add': AddIcon, - 'archive': ArchiveIcon, - 'arrow-down': ArrowDownIcon, - 'arrow-left': ArrowLeftIcon, - 'arrow-right': ArrowRightIcon, - 'arrow-up': ArrowUpIcon, - 'cancelled': CancelledIcon, - 'checkmark': CheckmarkIcon, - 'checkpoint': CheckpointIcon, - 'clipboard': ClipboardIcon, - 'close': CloseIcon, - 'cloud': CloudIcon, - 'cluster': ClusterIcon, - 'collapse': CollapseIcon, - 'columns': ColumnsIcon, - 'command': CommandIcon, - 'critical': ErrorIcon, // duplicate of error - 'dai-logo': DaiLogoIcon, - 'dashboard': DashboardIcon, - 'debug': DebugIcon, - 'docs': DocsIcon, - 'document': DocumentIcon, - 'download': DownloadIcon, - 'error': ErrorIcon, - 'expand': ExpandIcon, - 'experiment': ExperimentIcon, - 'external': GroupIcon, // duplicate of group - 'eye-close': EyeCloseIcon, - 'eye-open': EyeOpenIcon, - 'filter': FilterIcon, - 'fork': ForkIcon, - 'four-squares': FourSquaresIcon, - 'fullscreen': FullscreenIcon, - 'grid': GridIcon, - 'group': GroupIcon, - 'heat': HeatIcon, - 'heatmap': HeatmapIcon, - 'home': HomeIcon, - 'info': InfoIcon, - 'jupyter-lab': JupyterLabIcon, - 'learning': LearningIcon, - 'list': ListIcon, - 'lock': LockIcon, - 'logs': LogsIcon, - 'model': ModelIcon, - 'notebook': NotebookIcon, - 'options': OptionsIcon, - 'overflow-horizontal': OverflowHorizontalIcon, - 'overflow-vertical': OverflowVerticalIcon, - 'panel': PanelIcon, - 'panel-on': PanelOnIcon, - 'parcoords': ParcoordsIcon, - 'pause': PauseIcon, - 'pencil': PencilIcon, - 'pin': PinIcon, - 'play': PlayIcon, - 'popout': PopoutIcon, - 'power': PowerIcon, - 'queue': QueueIcon, - 'reset': ResetIcon, - 'row-large': RowLargeIcon, - 'row-medium': RowMediumIcon, - 'row-small': RowSmallIcon, - 'row-xl': RowExtraLargeIcon, - 'scatter-plot': ScatterPlotIcon, - 'scroll': ScrollIcon, - 'search': SearchIcon, - 'searcher-adaptive': SearcherAdaptiveIcon, - 'searcher-grid': SearcherGridIcon, - 'searcher-random': SearcherRandomIcon, - 'settings': SettingsIcon, - 'shell': ShellIcon, - 'spinner': SpinnerIcon, - 'star': StarIcon, - 'stop': StopIcon, - 'tasks': TasksIcon, - 'tensor-board': TensorBoardIcon, - 'tensorboard': TensorboardIcon, - 'trace': DaiLogoIcon, // duplicate of dai-logo - 'undo': UndoIcon, - 'user': UserIcon, - 'warning': WarningIcon, - 'webhooks': SearcherRandomIcon, // duplicate of searcher-random - 'workspaces': WorkspacesIcon, -} as const; - -const antdIcons = ['exclamation-circle', 'holder', 'minus-circle', 'project'] as const; - -const antdIconMap: Partial> = { - 'exclamation-circle': ExclamationCircleOutlined, - 'holder': HolderOutlined, - 'minus-circle': MinusCircleOutlined, - 'project': ProjectOutlined, -}; - -const componentIcons = ['active', 'spin-bowtie', 'spin-half', 'spin-shadow', 'queued'] as const; - -const componentIconMap: Partial> = { - 'active': ActiveIcon, - 'queued': QueuedIcon, - 'spin-bowtie': SpinBowtie, - 'spin-half': SpinHalf, - 'spin-shadow': SpinShadow, -}; - -export const IconNameArray = [...svgIcons, ...antdIcons, ...componentIcons]; - -export type IconName = (typeof IconNameArray)[number]; - -type CommonProps = { - color?: 'cancel' | 'error' | 'success'; - size?: IconSize; - showTooltip?: boolean; - name: IconName; - backgroundColor?: React.CSSProperties['backgroundColor']; // currently only supported by Queued - opacity?: React.CSSProperties['opacity']; // currently only supported by Queued -}; -export type Props = CommonProps & - XOR< - { - title: string; - }, - { - decorative: true; - } - >; -const Icon: React.FC = ({ - name, - size = 'medium', - color, - decorative, - title, - showTooltip = false, - backgroundColor, - opacity, -}: Props) => { - const classes = [css.base]; - - const iconComponent = useMemo(() => { - if (name === 'queued') - return ; - const MappedIcon = svgIconMap[name] ?? antdIconMap[name] ?? componentIconMap[name]; - return MappedIcon && ; - }, [backgroundColor, name, opacity]); - - if (size) classes.push(css[size]); - if (color) classes.push(css[color]); - - const icon = ( - - {iconComponent} - - ); - return showTooltip && !decorative ? {icon} : icon; -}; - -export default Icon; diff --git a/webui/react/src/components/kit/Icon/Active.module.scss b/webui/react/src/components/kit/Icon/Active.module.scss deleted file mode 100644 index 165933f7c73..00000000000 --- a/webui/react/src/components/kit/Icon/Active.module.scss +++ /dev/null @@ -1,52 +0,0 @@ -@use 'sass:math'; - -.base { - align-items: center; - display: flex; - justify-content: center; - width: 100%; - - .dots { - $duration: 1s; - $size: 3px; - - &, - &::before, - &::after { - animation-delay: math.div(-$duration, 3); - animation-duration: $duration; - animation-iteration-count: infinite; - animation-name: pulse; - animation-timing-function: ease-in-out; - border-radius: 50%; - box-shadow: 0 -1rem var(--theme-strong); - content: ''; - display: block; - height: $size; - position: relative; - top: 1rem; - width: $size; - } - &::before, - &::after { - height: 100%; - position: absolute; - top: 0; - width: 100%; - } - &::before { - animation-delay: math.div(-(2 * $duration), 3); - left: -0.5rem; - } - &::after { - animation-delay: 0s; - left: 0.5rem; - } - } -} - -@keyframes pulse { - 50% { - opacity: 0.5; - } -} diff --git a/webui/react/src/components/kit/Icon/Active.tsx b/webui/react/src/components/kit/Icon/Active.tsx deleted file mode 100644 index decae3566a7..00000000000 --- a/webui/react/src/components/kit/Icon/Active.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import React from 'react'; - -import css from './Active.module.scss'; - -const Active: React.FC = () => { - return ( -
-
-
- ); -}; - -export default Active; diff --git a/webui/react/src/components/kit/Icon/Icon.module.scss b/webui/react/src/components/kit/Icon/Icon.module.scss deleted file mode 100644 index bf7613e793e..00000000000 --- a/webui/react/src/components/kit/Icon/Icon.module.scss +++ /dev/null @@ -1,58 +0,0 @@ -.base { - align-items: center; - aspect-ratio: 1 / 1; - display: inline-flex !important; - fill: currentColor; - flex-shrink: 0; - user-select: none; - - svg { - aspect-ratio: 1 / 1; - width: 100%; - } -} -.tiny { - width: var(--icon-tiny); -} -.small { - width: var(--icon-small); -} -.medium { - width: var(--icon-medium); -} -.large { - width: var(--icon-large); -} -.big { - width: var(--icon-big); -} -.great { - width: var(--icon-great); -} -.huge { - width: var(--icon-huge); -} -.enormous { - width: var(--icon-enormous); -} -.giant { - width: var(--icon-giant); -} -.jumbo { - width: var(--icon-jumbo); -} -.mega { - width: var(--icon-mega); -} -.cancel { - color: var(--theme-ix-cancel); -} -.error { - color: var(--theme-status-error); -} -.success { - color: var(--theme-status-success); -} -.filter { - margin-top: 1px; -} diff --git a/webui/react/src/components/kit/Icon/Icon.test.tsx b/webui/react/src/components/kit/Icon/Icon.test.tsx deleted file mode 100644 index 4f6e0fd52ad..00000000000 --- a/webui/react/src/components/kit/Icon/Icon.test.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { render } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; - -import Icon, { IconNameArray, IconSizeArray, type Props, svgIcons } from 'components/kit/Icon'; - -const setup = (props?: Props) => { - const user = userEvent.setup(); - const props_: Partial = props ?? {}; - const title = ('title' in props_ ? props_.title : undefined) ?? 'Icon'; - const view = render( - , - ); - return { user, view }; -}; - -describe('Icon', () => { - describe('Size of icon', () => { - it.each(IconSizeArray)('should display a %s-size icon', (size) => { - const { view } = setup({ name: 'star', size, title: size }); - const firstChild = view.container.firstChild; - expect(firstChild).toHaveClass(size); - }); - }); - - describe('Name of icon', () => { - // TODO: figure out how to test which icon is displayed - it.each(IconNameArray)('should display a %s icon', (name) => { - const { view } = setup({ name, title: name }); - const firstChild = view.container.firstChild; - if ((svgIcons as readonly string[]).includes(name)) { - expect(firstChild?.firstChild?.nodeName).toBe('svg'); - expect(view.getByLabelText(name)).toBeVisible(); - } - }); - }); - - // TODO: test `title`. cannot display title in test-library probably due to - // screen.debug() doesnt show tooltip element somehow - - // describe('Tooltip Title', () => {}); -}); diff --git a/webui/react/src/components/kit/Icon/Queue.module.scss b/webui/react/src/components/kit/Icon/Queue.module.scss deleted file mode 100644 index 8db790a768c..00000000000 --- a/webui/react/src/components/kit/Icon/Queue.module.scss +++ /dev/null @@ -1,43 +0,0 @@ -.base { - height: 100%; - margin: auto; - position: relative; - width: 100%; - - .spinner, - .innerSpinner { - animation: pulse 1.75s infinite ease-in-out; - background-color: rgba(143 143 143 / 20%); - border-radius: 50%; - height: 100%; - left: 0; - opacity: 0.85; - position: absolute; - top: 0; - width: 100%; - } - .innerSpinner { - animation: pulseSpinner 1.75s infinite ease-in-out; - background-color: rgba(143 143 143 / 40%); - } -} - -@keyframes pulse { - 0%, - 100% { - transform: scale(1); - } - 50% { - transform: scale(0.75); - } -} - -@keyframes pulseSpinner { - 0%, - 100% { - transform: scale(0); - } - 50% { - transform: scale(0.6); - } -} diff --git a/webui/react/src/components/kit/Icon/Queue.tsx b/webui/react/src/components/kit/Icon/Queue.tsx deleted file mode 100644 index ef88a05416a..00000000000 --- a/webui/react/src/components/kit/Icon/Queue.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import React, { CSSProperties, useMemo } from 'react'; - -import css from './Queue.module.scss'; - -interface Props { - backgroundColor?: CSSProperties['backgroundColor']; - opacity?: CSSProperties['opacity']; -} - -const Queue: React.FC = ({ backgroundColor, opacity }) => { - const spinnerStyle = useMemo(() => { - return { backgroundColor, opacity }; - }, [backgroundColor, opacity]); - - return ( -
-
-
-
- ); -}; - -export default Queue; diff --git a/webui/react/src/components/kit/Icon/Spin.module.scss b/webui/react/src/components/kit/Icon/Spin.module.scss deleted file mode 100644 index fbf442c890d..00000000000 --- a/webui/react/src/components/kit/Icon/Spin.module.scss +++ /dev/null @@ -1,61 +0,0 @@ -@use 'sass:math'; - -$axes: X Y Z; -$size: 100%; -$mask: conic-gradient(#0000 30%, #000), linear-gradient(#000 0 0) content-box; - -.base { - align-items: center; - border-color: currentColor; - display: flex; - height: $size; - justify-content: center; - width: $size; - - .spinner { - animation-duration: 0.75s; - animation-iteration-count: infinite; - animation-name: rotateZ; - animation-timing-function: linear; - border-color: var(--theme-ix-border); - border-radius: 50%; - border-style: solid; - border-width: 2px; - height: $size; - width: $size; - } - .spinner__bowtie { - animation: rotateHalf 1s infinite; - border-bottom-color: var(--theme-surface-on); - border-top-color: var(--theme-surface-on); - } - .spinner__half { - border-left-color: var(--theme-surface-on); - border-top-color: var(--theme-surface-on); - } - .spinner__shadow { - animation: rotateZ 0.75s infinite linear; - border-color: var(--theme-surface-on); - -webkit-mask: $mask; - mask: $mask; - -webkit-mask-composite: source-out; - mask-composite: subtract; - } -} - -@each $axis in $axes { - @keyframes rotate#{$axis} { - from { - transform: rotate#{$axis}#{'(0deg)'}; - } - to { - transform: rotate#{$axis}#{'(360deg)'}; - } - } -} - -@keyframes rotateHalf { - to { - transform: rotate(0.5turn); - } -} diff --git a/webui/react/src/components/kit/Icon/Spin.tsx b/webui/react/src/components/kit/Icon/Spin.tsx deleted file mode 100644 index 615f8af5042..00000000000 --- a/webui/react/src/components/kit/Icon/Spin.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import React from 'react'; - -import css from './Spin.module.scss'; - -interface Props { - type: 'bowtie' | 'half' | 'shadow'; -} - -const Spin: React.FC = ({ type }) => { - const classnames = [css.spinner, css[`spinner__${type}`]]; - return ( -
-
-
- ); -}; - -export const SpinBowtie: React.FC = () => ; -export const SpinHalf: React.FC = () => ; -export const SpinShadow: React.FC = () => ; - -export default Spin; diff --git a/webui/react/src/components/kit/InlineForm.module.scss b/webui/react/src/components/kit/InlineForm.module.scss deleted file mode 100644 index 15cf64d30ef..00000000000 --- a/webui/react/src/components/kit/InlineForm.module.scss +++ /dev/null @@ -1,28 +0,0 @@ -.formBase { - align-items: start; - display: inline-grid; - grid-template-columns: 168px auto 84px; - width: 100%; - - .buttonsContainer { - display: inline-flex; - justify-content: end; - - & > button { - transition: none; // there's a transition (RTL slide) when enabling edit mode... - - &:last-of-type { - margin-left: 10px; - } - } - } - label { - margin: 5px 0; - } - .formItemInput { - margin-inline-end: 0; - } - .readOnlyElement { - padding: 12px; - } -} diff --git a/webui/react/src/components/kit/InlineForm.tsx b/webui/react/src/components/kit/InlineForm.tsx deleted file mode 100644 index 8418b095655..00000000000 --- a/webui/react/src/components/kit/InlineForm.tsx +++ /dev/null @@ -1,175 +0,0 @@ -import { Form, FormProps } from 'antd'; -import { Rule } from 'antd/es/form'; -import React, { useCallback, useEffect, useMemo, useState } from 'react'; - -import Button from 'components/kit/Button'; -import Icon from 'components/kit/Icon'; - -import css from './InlineForm.module.scss'; - -type InlineForm = (props: Props) => JSX.Element; - -interface Props extends React.PropsWithChildren, Omit { - label?: React.ReactNode; - value?: T; // used to turn the Form.Item as controlled input - initialValue: T; - onSubmit?: (inputValue: T) => Promise | void; - required?: boolean; - isPassword?: boolean; - rules?: Rule[]; - testId?: string; - valueFormatter?: (value: T) => string; - open?: boolean; // used to set `isEditing` as a controlled value - onEdit?: () => void; - onCancel?: () => void; -} - -function InlineForm({ - label, - children, - valueFormatter, - initialValue, - value, - isPassword = false, - rules, - required, - testId = '', - onSubmit, - onEdit, - onCancel, - open, - ...formProps -}: Props): JSX.Element { - const [isEditing, setIsEditing] = useState(false); - const [hasFormError, setHasFormError] = useState(false); - const [previousValue, setPreviousValue] = useState(initialValue); // had to set a state due to uncontrolled form reseting to the initialValue instead of previous value - const [form] = Form.useForm(); - const shouldCollapseText = useMemo(() => String(initialValue).length >= 45, [initialValue]); // prevents layout breaking, specially if using Input.TextArea. - const inputCurrentValue = Form.useWatch('input', form); - const readOnlyText = useMemo(() => { - let textValue = valueFormatter - ? valueFormatter(value ?? initialValue) - : String(value ?? initialValue); - if (value === undefined) { - if (inputCurrentValue !== undefined && inputCurrentValue !== initialValue) - textValue = valueFormatter ? valueFormatter(inputCurrentValue) : inputCurrentValue; - } - - if (isPassword) return textValue.replace(/\S/g, '*'); - if (shouldCollapseText) return textValue.slice(0, 50).concat('...'); - return textValue; - }, [shouldCollapseText, value, initialValue, isPassword, inputCurrentValue, valueFormatter]); - - useEffect(() => { - if (value !== undefined) { - form.setFieldValue('input', value); - } else { - form.setFieldValue('input', initialValue); - } - }, [initialValue, value, form]); - - useEffect(() => { - if (open !== undefined) setIsEditing(open); - }, [open]); - - React.useEffect(() => { - // Reacts to the input validation to enable/disable the "submit button" - let mounted = true; - if (isEditing) { - (async () => { - try { - await form.validateFields(['input']); - if (mounted) setHasFormError(false); - } catch { - if (mounted) setHasFormError(true); - } - })(); - } - return () => { - mounted = false; - }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [inputCurrentValue, isEditing, form]); - - const handleEdit = useCallback(() => { - if (open === undefined) setIsEditing(true); - onEdit?.(); - }, [open, onEdit]); - - const handleCancel = useCallback(() => { - form.resetFields(); - form.setFieldValue('input', previousValue); - - if (open === undefined) setIsEditing(false); - onCancel?.(); - }, [open, onCancel, form, previousValue]); - - const handleConfirm = useCallback(async () => { - if (form.getFieldError('input').length) return; - form.submit(); - try { - const formValues = await form.validateFields(); - setPreviousValue(formValues.input); - - if (open === undefined) setIsEditing(false); - onSubmit?.(formValues.input); - } catch (error) { - form.setFieldValue('input', initialValue); - } - }, [form, initialValue, open, onSubmit]); - - return ( -
- - - {isEditing ? ( - children - ) : ( - - {readOnlyText} - - )} - -
- {isEditing ? ( - <> -
-
- ); -} - -export default InlineForm; diff --git a/webui/react/src/components/kit/Input.scss b/webui/react/src/components/kit/Input.scss deleted file mode 100644 index c0da66da7fa..00000000000 --- a/webui/react/src/components/kit/Input.scss +++ /dev/null @@ -1,7 +0,0 @@ -/* stylelint-disable selector-id-pattern */ - -#input_help { - align-items: flex-start; - display: flex; - flex-direction: column; -} diff --git a/webui/react/src/components/kit/Input.tsx b/webui/react/src/components/kit/Input.tsx deleted file mode 100644 index 5d9e8923f2a..00000000000 --- a/webui/react/src/components/kit/Input.tsx +++ /dev/null @@ -1,100 +0,0 @@ -import { Input as AntdInput, InputRef as AntdInputRef } from 'antd'; -import React, { - CSSProperties, - FC, - forwardRef, - ForwardRefExoticComponent, - ReactNode, - RefAttributes, - RefObject, -} from 'react'; - -import { useInputEscape } from 'components/kit/internal/useInputEscape'; - -import './Input.scss'; -interface InputProps { - addonAfter?: ReactNode; - allowClear?: boolean | { clearIcon: ReactNode }; - autoComplete?: string; - autoFocus?: boolean; - bordered?: boolean; - className?: string; - defaultValue?: string; - disabled?: boolean; - id?: string; - max?: number; - maxLength?: number; - min?: number; - onBlur?: ( - e: React.FocusEvent | React.KeyboardEvent, - previousValue?: string, - ) => void; - onChange?: (e: React.ChangeEvent) => void; - onPressEnter?: (e: React.KeyboardEvent) => void; - placeholder?: string; - prefix?: ReactNode; - size?: 'large' | 'middle' | 'small'; - style?: CSSProperties; - title?: string; - type?: string; - value?: string; -} - -interface TextAreaProps { - disabled?: boolean; - onChange?: (e: React.ChangeEvent) => void; - placeholder?: string; - rows?: number; - value?: string; -} - -interface PasswordProps { - autoFocus?: boolean; - disabled?: boolean; - placeholder?: string; - prefix?: ReactNode; -} - -interface GroupProps { - children?: ReactNode; - className?: string; - compact?: boolean; -} - -const Input: Input = forwardRef((props: InputProps, ref) => { - const { onFocus, onBlur, inputRef } = useInputEscape(ref, props.onBlur); - - return ( - } onBlur={onBlur} onFocus={onFocus} /> - ); -}) as Input; - -type Input = ForwardRefExoticComponent> & { - Group: FC; - Password: ForwardRefExoticComponent>; - TextArea: ForwardRefExoticComponent>; -}; - -Input.Group = AntdInput.Group; - -Input.Password = forwardRef((props: PasswordProps, ref) => { - const { onFocus, onBlur, inputRef } = useInputEscape(ref); - - return ( - } - onBlur={onBlur} - onFocus={onFocus} - /> - ); -}); - -Input.TextArea = forwardRef((props: TextAreaProps, ref) => { - const { onFocus, onBlur, inputRef } = useInputEscape(ref); - return ; -}); - -export type InputRef = AntdInputRef; - -export default Input; diff --git a/webui/react/src/components/kit/InputNumber.tsx b/webui/react/src/components/kit/InputNumber.tsx deleted file mode 100644 index 5821aeec8c6..00000000000 --- a/webui/react/src/components/kit/InputNumber.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { InputNumber as AntdInputNumber } from 'antd'; -import React, { forwardRef } from 'react'; - -import { useInputNumberEscape } from 'components/kit/internal/useInputEscape'; -interface InputNumberProps { - className?: string; - defaultValue?: number; - disabled?: boolean; - max?: number; - min?: number; - onChange?: (value: number | string | null) => void; - placeholder?: string; - precision?: number; - step?: number; - value?: number; - onPressEnter?: (e: React.KeyboardEvent) => void; -} - -const InputNumber: React.FC = forwardRef( - ({ ...props }: InputNumberProps, ref: React.ForwardedRef) => { - const { onFocus, onBlur, inputRef } = useInputNumberEscape(ref); - return ; - }, -); - -export default InputNumber; diff --git a/webui/react/src/components/kit/InputSearch.tsx b/webui/react/src/components/kit/InputSearch.tsx deleted file mode 100644 index 04fe0ce5411..00000000000 --- a/webui/react/src/components/kit/InputSearch.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { Input } from 'antd'; -import React from 'react'; - -interface InputSearchProps { - allowClear?: boolean; - disabled?: boolean; - enterButton?: boolean; - placeholder?: string; - value?: string; -} - -const InputSearch: React.FC = (props: InputSearchProps) => { - return ; -}; - -export default InputSearch; diff --git a/webui/react/src/components/kit/InputShortcut.tsx b/webui/react/src/components/kit/InputShortcut.tsx deleted file mode 100644 index 44f23a94f27..00000000000 --- a/webui/react/src/components/kit/InputShortcut.tsx +++ /dev/null @@ -1,106 +0,0 @@ -import { Input, InputRef } from 'antd'; -import * as t from 'io-ts'; -import React, { useCallback, useEffect, useRef, useState } from 'react'; - -export const KeyboardShortcut = t.type({ - alt: t.boolean, - ctrl: t.boolean, - key: t.string, - meta: t.boolean, - shift: t.boolean, -}); - -export type KeyboardShortcut = t.TypeOf; - -export const matchesShortcut = (e: KeyboardEvent, shortcut: KeyboardShortcut): boolean => - e.ctrlKey === shortcut.ctrl && - e.metaKey === shortcut.meta && - e.altKey === shortcut.alt && - e.shiftKey === shortcut.shift && - formatKey(e.code, e.key) === shortcut.key; - -export const shortcutToString = (shortcut: KeyboardShortcut): string => { - const os = window.navigator.userAgent; - const s: string[] = []; - shortcut.ctrl && s.push('Ctrl'); - shortcut.meta && s.push(os.includes('Mac') ? 'Cmd' : os.includes('Win') ? 'Win' : 'Super'); - shortcut.shift && s.push('Shift'); - shortcut.alt && s.push('Alt'); - shortcut.key && s.push(shortcut.key); - return s.join(' + '); -}; - -export const formatKey = (code: string, key: string): string => { - if (code.startsWith('Digit')) return code.replace('Digit', ''); - switch (code) { - case 'BracketLeft': - return '['; - case 'BracketRight': - return ']'; - case 'Backslash': - return '\\'; - case 'Semicolon': - return ';'; - case 'Quote': - return "'"; - case 'Comma': - return ','; - case 'Period': - return '.'; - case 'Slash': - return '/'; - case 'Space': - return 'Space'; - default: - if (['Control', 'Meta', 'Alt', 'Shift'].includes(key)) return ''; - return key.toUpperCase(); - } -}; - -interface InputShortcutProps { - disabled?: boolean; - onChange?: (k: KeyboardShortcut | undefined) => void; - placeholder?: string; - value?: KeyboardShortcut; -} - -const InputShortcut: React.FC = ({ - placeholder = 'Press any key', - value, - onChange, - ...props -}: InputShortcutProps) => { - const inputRef = useRef(null); - const [inputValue, setInputValue] = useState(); - - useEffect(() => { - value && setInputValue(shortcutToString(value)); - }, [value]); - - const onKeyDown = useCallback( - (e: React.KeyboardEvent) => { - e.preventDefault(); - const keys: KeyboardShortcut = { - alt: e.altKey, - ctrl: e.ctrlKey, - key: formatKey(e.code, e.key), - meta: e.metaKey, - shift: e.shiftKey, - }; - value ? onChange?.(keys) : setInputValue(shortcutToString(keys)); - }, - [onChange, value], - ); - - return ( - - ); -}; - -export default InputShortcut; diff --git a/webui/react/src/components/kit/LineChart.module.scss b/webui/react/src/components/kit/LineChart.module.scss deleted file mode 100644 index 032c91e1015..00000000000 --- a/webui/react/src/components/kit/LineChart.module.scss +++ /dev/null @@ -1,68 +0,0 @@ -.scrollContainer { - height: 100%; - overflow: auto; -} -.chartgridEmpty { - align-items: center; - display: flex; - justify-content: center; - min-height: 530px; -} -.chartgridContainer { - --grid-spacing: 6px; - background-color: var(--theme-background); - min-height: 530px; - overflow-y: hidden; -} -.chartgridCell { - background-color: var(--theme-background); - padding: 0; - padding: var(--grid-spacing); -} -.chartgridCellCard { - background-color: var(--theme-stage); - border: 1px solid var(--theme-stage-border); - border-radius: 4px; - height: 100%; - padding: 24px; -} -.chartTitle { - background-color: var(--theme-stage); - display: flex; - font-family: var(--theme-font-family); - font-size: 14px; - justify-content: center; - margin-bottom: -18px !important; - padding-bottom: 15px; - padding-top: 5px; - - @supports (font-variation-settings: normal) { - font-family: var(--theme-font-family-var); - } -} -.filterContainer { - column-gap: 16px; - display: flex; - justify-content: right; - margin-bottom: 12px; - padding-right: 6px; -} -.legendContainer { - margin-left: 35px; - - .legendItem { - display: inline-block; - font-family: var(--theme-font-family); - font-size: 12px; - margin-right: 16px; - - .colorButton { - font-weight: bold; - margin-right: 8px; - } - - @supports (font-variation-settings: normal) { - font-family: var(--theme-font-family-var); - } - } -} diff --git a/webui/react/src/components/kit/LineChart.tsx b/webui/react/src/components/kit/LineChart.tsx deleted file mode 100644 index 63af7b089bd..00000000000 --- a/webui/react/src/components/kit/LineChart.tsx +++ /dev/null @@ -1,391 +0,0 @@ -import React, { ReactNode, useMemo } from 'react'; -import { FixedSizeGrid, GridChildComponentProps } from 'react-window'; -import uPlot, { AlignedData, Plugin } from 'uplot'; - -import { - getCssVar, - getTimeTickValues, - glasbeyColor, - metricToStr, -} from 'components/kit/internal/functions'; -import ScaleSelect from 'components/kit/internal/ScaleSelect'; -import { ErrorHandler, Scale, Serie, XAxisDomain } from 'components/kit/internal/types'; -import { SyncProvider } from 'components/kit/internal/UPlot/SyncProvider'; -import { UPlotPoint } from 'components/kit/internal/UPlot/types'; -import UPlotChart, { Options } from 'components/kit/internal/UPlot/UPlotChart'; -import { closestPointPlugin } from 'components/kit/internal/UPlot/UPlotChart/closestPointPlugin'; -import { tooltipsPlugin } from 'components/kit/internal/UPlot/UPlotChart/tooltipsPlugin'; -import useResize from 'components/kit/internal/useResize'; -import XAxisFilter from 'components/kit/LineChart/XAxisFilter'; -import Message from 'components/kit/Message'; -import Spinner from 'components/kit/Spinner'; -import { Loadable } from 'components/kit/utils/loadable'; - -import css from './LineChart.module.scss'; - -export const TRAINING_SERIES_COLOR = '#009BDE'; -export const VALIDATION_SERIES_COLOR = '#F77B21'; - -/** - * @typedef ChartProps {object} - * Config for a single LineChart component. - * @param {number} [focusedSeries] - Highlight one Serie's line and fade the others, given an index in the given series. - * @param {number} [height=350] - Height in pixels. - * @param {Scale} [scale=Scale.Linear] - Linear or Log Scale for the y-axis. - * @param {Serie[]} series - Array of valid series to plot onto the chart. - * @param {boolean} [showLegend=false] - Display a custom legend below the chart with each metric's color, name, and type. - * @param {string} [title] - Title for the chart. - * @param {XAxisDomain} [xAxis=XAxisDomain.Batches] - Set the x-axis of the chart (example: batches, time). - * @param {string} [xLabel] - Directly set label below the x-axis. - * @param {string} [yLabel] - Directly set label left of the y-axis. - */ -interface ChartProps { - experimentId?: number; - focusedSeries?: number; - height?: number; - onPointClick?: (event: MouseEvent, point: UPlotPoint) => void; - onPointFocus?: (point: UPlotPoint | undefined) => void; - plugins?: Plugin[]; - scale?: Scale; - series: Serie[] | Loadable; - showLegend?: boolean; - title?: ReactNode; - xAxis?: XAxisDomain; - xLabel?: string; - yLabel?: string; - yTickValues?: uPlot.Axis.Values; -} - -interface LineChartProps extends Omit { - series: Serie[] | Loadable; - handleError: ErrorHandler; -} - -export const LineChart: React.FC = ({ - experimentId, - focusedSeries, - handleError, - height = 350, - onPointClick, - onPointFocus, - scale = Scale.Linear, - plugins: propPlugins, - series: propSeries, - showLegend = false, - title, - xAxis = XAxisDomain.Batches, - xLabel, - yLabel, - yTickValues, -}: LineChartProps) => { - const series = Loadable.ensureLoadable(propSeries).getOrElse([]); - const isLoading = Loadable.isLoadable(propSeries) && Loadable.isNotLoaded(propSeries); - - const hasPopulatedSeries: boolean = useMemo( - () => !!series.find((serie) => serie.data[xAxis]?.length), - [series, xAxis], - ); - - const seriesColors: string[] = useMemo( - () => series.map((s, i) => s.color ?? glasbeyColor(i)), - [series], - ); - - const seriesNames: string[] = useMemo(() => { - return series.map((s) => { - return metricToStr({ group: s.metricType ?? 'unknown', name: s.name ?? 'unknown' }); - }); - }, [series]); - - const chartData: AlignedData = useMemo(() => { - const xSet = new Set(); - const yValues: Record> = {}; - - series.forEach((serie, serieIndex) => { - yValues[serieIndex] = {}; - (serie.data[xAxis] || []).forEach((pt) => { - const xVal = pt[0]; - xSet.add(xVal); - yValues[serieIndex][xVal] = Number.isFinite(pt[1]) ? pt[1] : null; - }); - }); - - const xValues: number[] = Array.from(xSet); - xValues.sort((a, b) => a - b); - const yValuesArray: (number | null)[][] = Object.values(yValues).map((yValue) => { - return xValues.map((xValue) => (yValue[xValue] != null ? yValue[xValue] : null)); - }); - - return [xValues, ...yValuesArray]; - }, [series, xAxis]); - - const xTickValues: uPlot.Axis.Values | undefined = useMemo( - () => - xAxis === XAxisDomain.Time && - chartData.length > 0 && - chartData[0].length > 0 && - chartData[0][chartData[0].length - 1] - chartData[0][0] < 43200 // 12 hours - ? getTimeTickValues - : undefined, - [chartData, xAxis], - ); - - const chartOptions: Options = useMemo(() => { - const plugins: Plugin[] = propPlugins ?? [ - tooltipsPlugin({ - closeOnMouseExit: true, - isShownEmptyVal: false, - // use specified color on Serie, or glasbeyColor - seriesColors, - }), - closestPointPlugin({ - onPointClick, - onPointFocus, - yScale: 'y', - }), - ]; - - return { - axes: [ - { - font: `12px ${getCssVar('--theme-font-family')}`, - grid: { show: false }, - incrs: - xAxis === XAxisDomain.Time - ? undefined - : [ - /* eslint-disable array-element-newline */ - 1, 2, 3, 4, 5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000, 10_000, 25_000, - 50_000, 100_000, 250_000, 500_000, 1_000_000, 2_500_000, 5_000_000, - /* eslint-enable array-element-newline */ - ], - label: xLabel, - scale: 'x', - side: 2, - space: 120, - ticks: { show: false }, - values: xTickValues, - }, - { - font: `12px ${getCssVar('--theme-font-family')}`, - grid: { stroke: '#E3E3E3', width: 1 }, - label: yLabel, - labelGap: 8, - scale: 'y', - side: 3, - ticks: { show: false }, - values: yTickValues, - }, - ], - cursor: { - drag: { x: true, y: false }, - }, - height: height - (hasPopulatedSeries ? 0 : 20), - legend: { show: false }, - plugins, - scales: { - x: { - time: xAxis === XAxisDomain.Time, - }, - y: { - distr: scale === Scale.Log ? 3 : 1, - }, - }, - series: [ - { label: xLabel ?? xAxis ?? 'X' }, - ...series.map((serie, idx) => { - return { - alpha: focusedSeries === undefined || focusedSeries === idx ? 1 : 0.4, - label: seriesNames[idx], - points: { show: (serie.data[xAxis] || []).length <= 1 }, - scale: 'y', - spanGaps: true, - stroke: seriesColors[idx], - type: 'line', - width: 2, - }; - }), - ], - }; - }, [ - seriesColors, - onPointClick, - onPointFocus, - xLabel, - xTickValues, - yLabel, - yTickValues, - height, - xAxis, - scale, - series, - seriesNames, - hasPopulatedSeries, - propPlugins, - focusedSeries, - ]); - - return ( -
- {title &&
{title}
} - - {showLegend && ( -
- {hasPopulatedSeries ? ( - series.map((s, idx) => ( -
  • - - — - - {seriesNames[idx]} -
  • - )) - ) : ( -
  •  
  • - )} -
    - )} -
    - ); -}; - -export type ChartsProps = ChartProps[]; - -/** - * @typedef GroupProps {object} - * Config for a grid of LineCharts. - * @param {ChartsProps} chartsProps - Provide series to plot on each chart, and any chart-specific config. - * @param {XAxisDomain[]} [xAxisOptions] - A list of possible x-axes to select in a dropdown; examples: Batches, Time, Epoch. - * @param {Scale} scale - Scale of chart, can be linear or log - * @param {handleError} handleError - Error handler - */ -export interface GroupProps { - chartsProps: ChartsProps | Loadable; - onXAxisChange: (ax: XAxisDomain) => void; - scale: Scale; - setScale: React.Dispatch>; - xAxis: XAxisDomain; - handleError: ErrorHandler; -} - -/** - * VirtualChartRenderer is used by FixedSizeGrid to virtually render individual charts. - * `data` comes from the itemData prop that is passed to FixedSizeGrid. - */ -const VirtualChartRenderer: React.FC< - GridChildComponentProps<{ - chartsProps: ChartsProps; - columnCount: number; - scale: Scale; - xAxis: XAxisDomain; - handleError: ErrorHandler; - }> -> = ({ columnIndex, rowIndex, style, data }) => { - const { chartsProps, columnCount, scale, xAxis, handleError } = data; - - const cellIndex = rowIndex * columnCount + columnIndex; - - if (chartsProps === undefined || cellIndex >= chartsProps.length) return null; - const chartProps = chartsProps[cellIndex]; - - return ( -
    -
    - -
    -
    - ); -}; - -export const ChartGrid: React.FC = React.memo( - ({ - chartsProps: propChartsProps, - xAxis, - onXAxisChange, - scale, - setScale, - handleError, - }: GroupProps) => { - const { refCallback, size } = useResize(); - const height = size.height ?? 0; - const width = size.width ?? 0; - const columnCount = Math.max(1, Math.floor(width / 540)); - const chartsProps = Loadable.ensureLoadable(propChartsProps) - .getOrElse([]) - .filter( - (c) => - // filter out Loadable series which are Loaded yet have no serie with more than 0 points. - !Loadable.isLoadable(c.series) || - !Loadable.isLoaded(c.series) || - Loadable.getOrElse([], c.series).find((serie) => - Object.entries(serie.data).find(([, points]) => points.length > 0), - ), - ); - const isLoading = Loadable.isLoadable(propChartsProps) && Loadable.isNotLoaded(propChartsProps); - - // X-Axis control - const xAxisOptions = useMemo(() => { - const xOpts = new Set(); - chartsProps.forEach((chart) => { - const series = Loadable.ensureLoadable(chart.series).getOrElse([]); - series.forEach((serie) => { - Object.entries(serie.data).forEach(([xAxisOption, dataPoints]) => { - if (dataPoints.length > 0) { - xOpts.add(xAxisOption); - } - }); - }); - }); - return Array.from(xOpts).sort(); - }, [chartsProps]); - - if (chartsProps.length === 0 && !isLoading) - return ; - - return ( -
    -
    - - {chartsProps.length > 0 && ( - <> -
    - - {xAxisOptions && xAxisOptions.length > 1 && ( - - )} -
    - - - {VirtualChartRenderer} - - - - )} -
    -
    -
    - ); - }, -); diff --git a/webui/react/src/components/kit/LineChart/XAxisFilter.tsx b/webui/react/src/components/kit/LineChart/XAxisFilter.tsx deleted file mode 100644 index e43b7145b37..00000000000 --- a/webui/react/src/components/kit/LineChart/XAxisFilter.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import React from 'react'; - -import { XAxisDomain } from 'components/kit/internal/types'; -import Select, { Option, SelectValue } from 'components/kit/Select'; - -interface Props { - onChange: (value: XAxisDomain) => void; - options: string[]; - value: string; -} - -const XAxisFilter: React.FC = ({ options, onChange, value }: Props) => { - return ( - - ); -}; - -export default XAxisFilter; diff --git a/webui/react/src/components/kit/LineChart/useChartGrid.tsx b/webui/react/src/components/kit/LineChart/useChartGrid.tsx deleted file mode 100644 index 56fd8f6ebe2..00000000000 --- a/webui/react/src/components/kit/LineChart/useChartGrid.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import React, { useState } from 'react'; - -import { Scale } from 'components/kit/internal/types'; -import { ChartGrid, GroupProps } from 'components/kit/LineChart'; - -export const useChartGrid = (): (( - props: Omit, -) => JSX.Element) => { - const [scale, setScale] = useState(Scale.Linear); - return (props) => ; -}; diff --git a/webui/react/src/components/kit/LogViewer/LogViewer.module.scss b/webui/react/src/components/kit/LogViewer/LogViewer.module.scss deleted file mode 100644 index 330fdeef3ad..00000000000 --- a/webui/react/src/components/kit/LogViewer/LogViewer.module.scss +++ /dev/null @@ -1,62 +0,0 @@ -.base { - background-color: var(--theme-stage); - color: var(--theme-stage-on); - height: 100%; - position: relative; - width: 100%; - - .container { - height: 100%; - position: relative; - } - .container > .logs { - font-family: var(--theme-font-family-code); - font-size: 12px; - height: 100%; - } - .buttons { - bottom: 32px; - display: flex; - flex-direction: column; - position: absolute; - right: 32px; - } - .buttons > button { - background-color: var(--theme-float); - border-color: var(--theme-float-border); - box-shadow: var(--theme-elevation); - color: var(--theme-float-on); - transition: opacity 0.2s linear; - user-select: none; - } - .buttons > button + button { - margin-top: 16px; - } - .scrollToOldest { - opacity: 0.2; - opacity: 1; - user-select: auto; - } - .scrollToOldest:focus { - border-color: var(--theme-status-active); - color: var(--theme-status-active-on); - - &::after { - border-radius: var(--theme-border-radius); - box-shadow: var(--theme-outline); - content: ''; - height: 100%; - position: absolute; - width: 100%; - } - } -} -.options { - padding: 8px 8px 0 0; - - .transparentButton { - background-color: transparent !important; - border: none !important; - box-shadow: none !important; - } -} diff --git a/webui/react/src/components/kit/LogViewer/LogViewer.tsx b/webui/react/src/components/kit/LogViewer/LogViewer.tsx deleted file mode 100644 index d20d86dbc6e..00000000000 --- a/webui/react/src/components/kit/LogViewer/LogViewer.tsx +++ /dev/null @@ -1,614 +0,0 @@ -import { Space } from 'antd'; -import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react'; -import { flushSync } from 'react-dom'; -import { - ListChildComponentProps, - ListOnItemsRenderedProps, - ListOnScrollProps, - VariableSizeList, -} from 'react-window'; -import screenfull from 'screenfull'; -import { sprintf } from 'sprintf-js'; -import { throttle } from 'throttle-debounce'; - -import Button from 'components/kit/Button'; -import ClipboardButton from 'components/kit/ClipboardButton'; -import Icon from 'components/kit/Icon'; -import { - clone, - dateTimeStringSorter, - formatDatetime, - numericSorter, -} from 'components/kit/internal/functions'; -import Section from 'components/kit/internal/Section'; -import { readLogStream } from 'components/kit/internal/services'; -import { - ErrorHandler, - FetchArgs, - Log, - LogLevel, - RecordKey, - ValueOf, -} from 'components/kit/internal/types'; -import useGetCharMeasureInContainer from 'components/kit/internal/useGetCharMeasureInContainer'; -import useResize from 'components/kit/internal/useResize'; -import Spinner from 'components/kit/Spinner'; - -import css from './LogViewer.module.scss'; -import LogViewerEntry, { DATETIME_FORMAT, ICON_WIDTH, MAX_DATETIME_LENGTH } from './LogViewerEntry'; - -export interface Props { - decoder: (data: unknown) => Log; - handleCloseLogs?: () => void; - initialLogs?: unknown[]; - onDownload?: () => void; - onFetch?: (config: FetchConfig, type: FetchType) => FetchArgs; - onError: ErrorHandler; - serverAddress: (path: string) => string; - sortKey?: keyof Log; - title?: React.ReactNode; -} - -export interface ViewerLog extends Log { - formattedTime: string; -} - -type Hash = Record; - -export interface FetchConfig { - canceler: AbortController; - fetchDirection: FetchDirection; - limit: number; - offset?: number; - offsetLog?: Log; -} - -export const FetchType = { - Initial: 'Initial', - Newer: 'Newer', - Older: 'Older', - Stream: 'Stream', -} as const; - -export type FetchType = ValueOf; - -export const FetchDirection = { - Newer: 'Newer', - Older: 'Older', -} as const; - -export type FetchDirection = ValueOf; - -export const ARIA_LABEL_ENABLE_TAILING = 'Enable Tailing'; -export const ARIA_LABEL_SCROLL_TO_OLDEST = 'Scroll to Oldest'; - -const PAGE_LIMIT = 100; -const PADDING = 8; -const THROTTLE_TIME = 50; - -const defaultLocal = { - fetchOffset: -PAGE_LIMIT, - idMap: {} as Hash, - isAtOffsetEnd: false, - isFetching: false, - isOnBottom: false, - isOnTop: false, - isScrollReady: false, - previousHeight: 0, - previousWidth: 0, - scrollOffset: 0, -}; - -export const formatLogEntry = (log: Log): ViewerLog => { - const formattedTime = log.time ? formatDatetime(log.time, { format: DATETIME_FORMAT }) : ''; - return { ...log, formattedTime }; -}; - -const formatClipboardHeader = (log: Log): string => { - const logEntry = formatLogEntry(log); - const format = `%${MAX_DATETIME_LENGTH - 1}s `; - const level = `<${logEntry.level || ''}>`; - return sprintf(`%-9s ${format}`, level, logEntry.formattedTime); -}; - -const logSorter = - (key: keyof Log) => - (a: Log, b: Log): number => { - const aValue = a[key]; - const bValue = b[key]; - if (key === 'id') return numericSorter(aValue as number, bValue as number); - if (key === 'time') return dateTimeStringSorter(aValue as string, bValue as string); - return 0; - }; - -const LogViewer: React.FC = ({ - decoder, - initialLogs, - onDownload, - onFetch, - onError, - serverAddress, - sortKey = 'time', - handleCloseLogs, - ...props -}: Props) => { - const baseRef = useRef(null); - const listRef = useRef(null); - const [isFetching, setIsFetching] = useState(false); - const local = useRef(clone(defaultLocal)); - const [canceler] = useState(new AbortController()); - const [fetchDirection, setFetchDirection] = useState(FetchDirection.Older); - const [isTailing, setIsTailing] = useState(true); - const [showButtons, setShowButtons] = useState(false); - const [logs, setLogs] = useState([]); - const { refObject: logsRef, refCallback, size: containerSize } = useResize(); - const { size: pageSize } = useResize(); - const charMeasures = useGetCharMeasureInContainer(logsRef, containerSize); - - const { dateTimeWidth, maxCharPerLine } = useMemo(() => { - const dateTimeWidth = charMeasures.width * MAX_DATETIME_LENGTH; - const maxCharPerLine = - Math.floor( - (containerSize.width - ICON_WIDTH - dateTimeWidth - 2 * PADDING) / charMeasures.width, - ) - 2; - return { dateTimeWidth, maxCharPerLine }; - }, [charMeasures.width, containerSize.width]); - - const getItemHeight = useCallback( - (index: number): number => { - const log = logs[index]; - if (!log) return charMeasures.height; - - const lineCount = log.message - .split('\n') - .map((line) => (line.length > maxCharPerLine ? Math.ceil(line.length / maxCharPerLine) : 1)) - .reduce((acc, count) => acc + count, 0); - const itemHeight = lineCount * charMeasures.height; - - return index === 0 || index === logs.length - 1 ? itemHeight + PADDING : itemHeight; - }, - [charMeasures, maxCharPerLine, logs], - ); - - const resizeLogs = useCallback(() => listRef.current?.resetAfterIndex(0), []); - - const processLogs = useCallback( - (newLogs: Log[]) => { - const map = local.current.idMap; - return newLogs - .filter((log) => { - const isDuplicate = map[log.id]; - const isTqdm = log.message.includes('\r'); - map[log.id] = true; - return !isDuplicate && !isTqdm; - }) - .map((log) => formatLogEntry(log)) - .sort(logSorter(sortKey)); - }, - [sortKey], - ); - - const addLogs = useCallback( - (newLogs: ViewerLog[], prepend = false): void => { - if (newLogs.length === 0) return; - flushSync(() => { - setLogs((prevLogs) => (prepend ? [...newLogs, ...prevLogs] : [...prevLogs, ...newLogs])); - }); - resizeLogs(); - }, - [resizeLogs], - ); - - const fetchLogs = useCallback( - async (config: Partial, type: FetchType): Promise => { - if (!onFetch) return []; - - const buffer: Log[] = []; - - setIsFetching(true); - local.current.isFetching = true; - - await readLogStream( - serverAddress, - onFetch({ limit: PAGE_LIMIT, ...config } as FetchConfig, type), - onError, - (event) => { - const logEntry = decoder(event); - fetchDirection === FetchDirection.Older - ? buffer.unshift(logEntry) - : buffer.push(logEntry); - }, - ); - - setIsFetching(false); - local.current.isFetching = false; - - return processLogs(buffer); - }, - [decoder, fetchDirection, onFetch, onError, processLogs, serverAddress], - ); - - const handleItemsRendered = useCallback( - async ({ visibleStartIndex, visibleStopIndex }: ListOnItemsRenderedProps) => { - // Scroll may occur before the initial logs have rendered. - if (!local.current.isScrollReady) return; - - local.current.isOnTop = visibleStartIndex === 0; - local.current.isOnBottom = visibleStopIndex === logs.length - 1; - - // Still busy with a previous fetch, prevent another fetch. - if (local.current.isFetching || local.current.isAtOffsetEnd) return; - - // Detect when user scrolls to the "edge" and requires more logs to load. - const shouldFetchNewLogs = - local.current.isOnBottom && fetchDirection === FetchDirection.Newer; - const shouldFetchOldLogs = local.current.isOnTop && fetchDirection === FetchDirection.Older; - - if (shouldFetchNewLogs || shouldFetchOldLogs) { - const newLogs = await fetchLogs( - { - canceler, - fetchDirection, - offsetLog: shouldFetchNewLogs ? logs.last() : logs.first(), - }, - shouldFetchNewLogs ? FetchType.Newer : FetchType.Older, - ); - - addLogs(newLogs, shouldFetchOldLogs); - - // Restore previous scroll position upon adding older logs. - if (shouldFetchOldLogs) { - listRef.current?.scrollToItem(newLogs.length + 1, 'start'); - } - - // No more logs will load. - if (newLogs.length === 0) { - local.current.isAtOffsetEnd = true; - - /** - * The user has scrolled all the way to the newest entry, - * enable tailing behavior. - */ - if (shouldFetchNewLogs) { - setIsTailing(true); - setFetchDirection(FetchDirection.Older); - } - } - } - }, - [addLogs, canceler, fetchDirection, fetchLogs, logs], - ); - - /** - * scrollUpdateWasRequested: - * true: if the scroll was caused by scrollTo() or scrollToItem() - * false: if the scroll was caused by user interaction in the browser - */ - const handleScroll = useCallback( - ({ scrollDirection, scrollOffset, scrollUpdateWasRequested }: ListOnScrollProps) => { - /** - * `react-window` automatically adjusts floating point offsets to integers. - * Unfortunately, this triggers a second `onScroll` event with the `scrollUpdateWasRequested` - * set as `false` indicating user triggered scrolling, which is not the case. - * `isAutoWindowAdjustment` logic is used to filter out these auto adjustments made - * my `react-window`. - */ - const prevScrollOffset = local.current.scrollOffset; - const isUserScrollBackwards = scrollDirection === 'backward' && !scrollUpdateWasRequested; - const isAutoWindowAdjustment = - prevScrollOffset !== scrollOffset && Math.floor(prevScrollOffset) === scrollOffset; - if (isUserScrollBackwards && !isAutoWindowAdjustment) setIsTailing(false); - - // Re-engage tailing if the scroll position is at the bottom of the scrollable window. - if (logsRef.current) { - const listParent = logsRef.current.firstElementChild; - const list = listParent?.firstElementChild; - const scrollHeight = list?.scrollHeight ?? 0; - const parentHeight = listParent?.clientHeight ?? 0; - const scrollTop = scrollHeight - parentHeight; - if (scrollTop && scrollTop === scrollOffset) setIsTailing(true); - } - - // Store last scrollOffset. - local.current.scrollOffset = scrollOffset; - }, - [logsRef], - ); - - const handleScrollToOldest = useCallback(() => { - setIsTailing(false); - - if (fetchDirection === FetchDirection.Newer) { - listRef.current?.scrollToItem(0, 'start'); - } else { - local.current.fetchOffset = 0; - local.current.idMap = {}; - local.current.isScrollReady = false; - local.current.isAtOffsetEnd = false; - - setLogs([]); - setFetchDirection(FetchDirection.Newer); - } - }, [fetchDirection]); - - const handleEnableTailing = useCallback(() => { - setIsTailing(true); - - if (fetchDirection === FetchDirection.Older) { - listRef.current?.scrollToItem(logs.length, 'end'); - } else { - local.current.fetchOffset = -PAGE_LIMIT; - local.current.idMap = {}; - local.current.isScrollReady = false; - local.current.isAtOffsetEnd = false; - - setLogs([]); - setFetchDirection(FetchDirection.Older); - } - }, [fetchDirection, logs.length]); - - const clipboardCopiedMessage = useMemo(() => { - const linesLabel = logs.length === 1 ? 'entry' : 'entries'; - return `Copied ${logs.length} ${linesLabel}!`; - }, [logs]); - - const getClipboardContent = useCallback(() => { - return logs.map((log) => `${formatClipboardHeader(log)}${log.message || ''}`).join('\n'); - }, [logs]); - - const handleFullScreen = useCallback(() => { - if (baseRef.current && screenfull.isEnabled) screenfull.toggle(); - }, []); - - const handleDownload = useCallback(() => { - onDownload?.(); - }, [onDownload]); - - // Fetch initial logs on a mount or when the mode changes. - useEffect(() => { - fetchLogs({ canceler, fetchDirection }, FetchType.Initial).then((logs) => { - addLogs(logs, true); - - if (fetchDirection === FetchDirection.Older) { - // Slight delay on scrolling to the end for the log viewer to render and resolve everything. - setTimeout(() => { - listRef.current?.scrollToItem(Number.MAX_SAFE_INTEGER, 'end'); - local.current.isScrollReady = true; - }, 100); - } else { - listRef.current?.scrollToItem(0, 'start'); - local.current.isScrollReady = true; - } - }); - }, [addLogs, canceler, fetchDirection, fetchLogs]); - - // Enable streaming for loading latest entries. - useEffect(() => { - const canceler = new AbortController(); - let buffer: Log[] = []; - - const processBuffer = () => { - const logs = processLogs(buffer); - buffer = []; - - if (logs.length !== 0) { - /* - * We need to take a snapshot of `isOnBottom` BEFORE adding logs, - * to determine if the log viewer is tailing. - * The action of adding logs causes `isOnBottom` to be always false, - * because the newly append logs are past the visible window. - */ - const currentIsOnBottom = local.current.isOnBottom; - - addLogs(logs); - - if (currentIsOnBottom) { - listRef.current?.scrollToItem(Number.MAX_SAFE_INTEGER, 'end'); - } - } - }; - const throttledProcessBuffer = throttle(THROTTLE_TIME, processBuffer); - - if (fetchDirection === FetchDirection.Older && onFetch) { - readLogStream( - serverAddress, - onFetch({ canceler, fetchDirection, limit: PAGE_LIMIT }, FetchType.Stream), - onError, - (event) => { - buffer.push(decoder(event)); - throttledProcessBuffer(); - }, - ); - } - - return () => { - canceler.abort(); - throttledProcessBuffer.cancel(); - }; - }, [addLogs, decoder, fetchDirection, onError, serverAddress, onFetch, processLogs]); - - // Re-fetch logs when fetch callback changes. - useEffect(() => { - local.current = clone(defaultLocal); - - setLogs([]); - setIsTailing(true); - setFetchDirection(FetchDirection.Older); - }, [onFetch]); - - // Initialize logs if applicable. - useEffect(() => { - if (!initialLogs) return; - - addLogs(initialLogs.map((log) => formatLogEntry(decoder(log)))); - }, [addLogs, decoder, initialLogs]); - - // Abort all outstanding API calls if log viewer unmounts. - useEffect(() => { - return () => { - canceler.abort(); - }; - }, [canceler]); - - // Force recomputing messages height when container size changes. - useLayoutEffect(() => { - if (containerSize.width === 0 || containerSize.height === 0) return; - - const sizeChanged = - containerSize.height !== local.current.previousHeight || - containerSize.width !== local.current.previousWidth; - if (sizeChanged) resizeLogs(); - - local.current.previousWidth = containerSize.width; - local.current.previousHeight = containerSize.height; - }, [containerSize, resizeLogs]); - - // Show scrolling buttons based on whether or not logs spill outside of the list view. - useLayoutEffect(() => { - setShowButtons(() => { - if (!logsRef.current || logs.length === 0) return false; - const listParent = logsRef.current.firstElementChild; - const list = listParent?.firstElementChild; - const scrollHeight = list?.scrollHeight ?? 0; - const parentHeight = listParent?.clientHeight ?? 0; - return scrollHeight > parentHeight; - }); - }, [logs.length, logsRef]); - - /* - * This overwrites the copy to clipboard event handler for the purpose of modifying the user - * selected content. By default when copying content from a collection of HTML elements, each - * element content will have a newline appended in the clipboard content. This handler will - * detect which lines within the copied content to be the timestamp content and strip out the - * newline from that field. - */ - useLayoutEffect(() => { - if (!logsRef.current) return; - - const target = logsRef.current; - const handleCopy = (e: ClipboardEvent): void => { - const clipboardFormat = 'text/plain'; - const levelValues = Object.values(LogLevel).join('|'); - const levelRegex = new RegExp(`<\\[(${levelValues})\\]>\n`, 'gim'); - const selection = (window.getSelection()?.toString() || '').replace(levelRegex, '<$1> '); - const lines = selection?.split('\n'); - - if (lines?.length <= 1) { - e.clipboardData?.setData(clipboardFormat, selection); - } else { - const oddOrEven = lines - .map((line) => /^\[/.test(line) || /\]$/.test(line)) - .reduce( - (acc, isTimestamp, index) => { - if (isTimestamp) acc[index % 2 === 0 ? 'even' : 'odd']++; - return acc; - }, - { even: 0, odd: 0 }, - ); - const isEven = oddOrEven.even > oddOrEven.odd; - const content = lines.reduce((acc, line, index) => { - const skipNewline = (isEven && index % 2 === 0) || (!isEven && index % 2 === 1); - return acc + line + (skipNewline ? ' ' : '\n'); - }, ''); - e.clipboardData?.setData(clipboardFormat, content); - } - e.preventDefault(); - }; - - target.addEventListener('copy', handleCopy); - - return (): void => target?.removeEventListener('copy', handleCopy); - }, [logsRef]); - - const logViewerOptions = ( -
    - - -
    - ); - - const LogViewerRow: React.FC = useCallback( - ({ data, index, style }) => ( - - ), - [dateTimeWidth], - ); - - return ( -
    - -
    -
    -
    - - {LogViewerRow} - -
    -
    -
    -
    -
    -
    -
    - ); -}; - -export default LogViewer; diff --git a/webui/react/src/components/kit/LogViewer/LogViewerEntry.module.scss b/webui/react/src/components/kit/LogViewer/LogViewerEntry.module.scss deleted file mode 100644 index 6138ac9297a..00000000000 --- a/webui/react/src/components/kit/LogViewer/LogViewerEntry.module.scss +++ /dev/null @@ -1,73 +0,0 @@ -$no-wrap-height: 20px; - -.base { - display: flex; - position: absolute; - width: 100%; - - * { - white-space: nowrap; - } - .number { - color: var(--theme-stage-on); - flex-shrink: 0; - text-align: right; - user-select: none; - } - .number::after { - content: attr(data-label) '\00a0'; - } - .level { - color: var(--theme-stage-on); - flex-shrink: 0; - padding: 2px; - } - .level > .levelLabel { - font-size: 0; - } - .critical { - color: var(--theme-status-critical); - } - .debug { - color: var(--theme-status-active); - } - .error { - color: var(--theme-status-critical); - } - .trace { - color: var(--theme-status-active); - } - .warning { - color: var(--theme-status-warning); - } - .time { - color: var(--theme-stage-on-weak); - flex-shrink: 0; - } - .time::after { - content: '\00a0'; - } - .message { - flex-grow: 1; - line-break: anywhere; - white-space: pre-wrap; - word-break: break-all; - } -} -.base.noWrap { - height: $no-wrap-height; - - & > * { - height: $no-wrap-height; - } - .time { - line-height: $no-wrap-height; - } - .message { - line-break: normal; - line-height: $no-wrap-height; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } -} diff --git a/webui/react/src/components/kit/LogViewer/LogViewerEntry.test.tsx b/webui/react/src/components/kit/LogViewer/LogViewerEntry.test.tsx deleted file mode 100644 index d46771da803..00000000000 --- a/webui/react/src/components/kit/LogViewer/LogViewerEntry.test.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { render, screen } from '@testing-library/react'; -import { CSSProperties } from 'react'; - -import { LogLevel } from 'components/kit/internal/types'; - -import LogViewerEntry, { Props } from './LogViewerEntry'; - -const setup = (props: Props) => { - return render(); -}; - -describe('LogViewerEntry', () => { - const formattedTime = '[2022-02-22 21:24:37]'; - const level = LogLevel.Error; - const message = 'Uh-oh there is a boo-boo.'; - - it('should render log entry', async () => { - setup({ formattedTime, level, message }); - expect(await screen.getByText(formattedTime)).toBeInTheDocument(); - expect(await screen.getByText(message)).toBeInTheDocument(); - }); - - it('should render with all level types except None', () => { - Object.values(LogLevel).forEach((level) => { - if (level === LogLevel.None) return; - setup({ formattedTime, level: level, message }); - const icon = screen.getByLabelText(level); - expect(icon).not.toBeNull(); - expect(icon).toBeInTheDocument(); - }); - }); - - it('should render without wrapping', () => { - const { container } = setup({ formattedTime, level, message, noWrap: true }); - const noWrapLogEntry = container.querySelector('[class*="noWrap"]'); - expect(noWrapLogEntry).not.toBeNull(); - expect(noWrapLogEntry).toBeInTheDocument(); - }); - - it('should apply custom time style', () => { - const timeStyle: CSSProperties = { backgroundColor: 'HotPink' }; - const { container } = setup({ formattedTime, level, message, timeStyle }); - const hotPinkLogEntry = container.querySelector('[style*="HotPink"]'); - expect(hotPinkLogEntry).not.toBeNull(); - expect(hotPinkLogEntry).toBeInTheDocument(); - }); -}); diff --git a/webui/react/src/components/kit/LogViewer/LogViewerEntry.tsx b/webui/react/src/components/kit/LogViewer/LogViewerEntry.tsx deleted file mode 100644 index c380ebf7c7f..00000000000 --- a/webui/react/src/components/kit/LogViewer/LogViewerEntry.tsx +++ /dev/null @@ -1,65 +0,0 @@ -import React from 'react'; - -import Icon from 'components/kit/Icon'; -import { ansiToHtml, capitalize } from 'components/kit/internal/functions'; -import { LogLevel } from 'components/kit/internal/types'; -import Tooltip from 'components/kit/Tooltip'; - -import css from './LogViewerEntry.module.scss'; - -export interface LogEntry { - formattedTime: string; - level: LogLevel; - message: string; -} - -export interface Props extends LogEntry { - noWrap?: boolean; - style?: React.CSSProperties; - timeStyle?: React.CSSProperties; -} - -export const ICON_WIDTH = 26; - -// Format the datetime to... -const DATETIME_PREFIX = '['; -const DATETIME_SUFFIX = ']'; -export const DATETIME_FORMAT = `[${DATETIME_PREFIX}]YYYY-MM-DD HH:mm:ss${DATETIME_SUFFIX}`; - -// Max datetime size: DATETIME_FORMAT (plus 1 for a space suffix) -export const MAX_DATETIME_LENGTH = 22; - -const LogViewerEntry: React.FC = ({ - level = LogLevel.None, - message, - noWrap = false, - style, - formattedTime, - timeStyle, -}) => { - const classes = [css.base]; - const levelClasses = [css.level, css[level]]; - const messageClasses = [css.message, css[level]]; - - if (noWrap) classes.push(css.noWrap); - - return ( -
    - -
    -
    <[{level}]>
    - {level !== LogLevel.None && } -
    -
    -
    - {formattedTime} -
    -
    -
    - ); -}; - -export default LogViewerEntry; diff --git a/webui/react/src/components/kit/LogViewer/LogViewerSelect.settings.ts b/webui/react/src/components/kit/LogViewer/LogViewerSelect.settings.ts deleted file mode 100644 index 2ca93d7e349..00000000000 --- a/webui/react/src/components/kit/LogViewer/LogViewerSelect.settings.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { array, literal, number, string, undefined as undefinedType, union } from 'io-ts'; - -import { LogLevelFromApi, SettingsConfig } from 'components/kit/internal/types'; - -export interface Settings { - agentId?: string[]; - allocationId?: string[]; - containerId?: string[]; - level?: LogLevelFromApi[]; - rankId?: number[]; - searchText?: string; -} - -export const settingsConfigForTask = (taskId: string): SettingsConfig => - settingsConfigForLogs(taskId); - -export const settingsConfigForTrial = (id: number): SettingsConfig => - settingsConfigForLogs(id); - -const settingsConfigForLogs = (id: number | string): SettingsConfig => ({ - settings: { - agentId: { - defaultValue: undefined, - storageKey: 'agentId', - type: union([undefinedType, array(string)]), - }, - allocationId: { - defaultValue: undefined, - storageKey: 'allocationId', - type: union([undefinedType, array(string)]), - }, - containerId: { - defaultValue: undefined, - storageKey: 'containerId', - type: union([undefinedType, array(string)]), - }, - level: { - defaultValue: undefined, - storageKey: 'level', - type: union([ - undefinedType, - array( - union([ - literal(LogLevelFromApi.Critical), - literal(LogLevelFromApi.Debug), - literal(LogLevelFromApi.Error), - literal(LogLevelFromApi.Info), - literal(LogLevelFromApi.Trace), - literal(LogLevelFromApi.Unspecified), - literal(LogLevelFromApi.Warning), - ]), - ), - ]), - }, - rankId: { - defaultValue: undefined, - storageKey: 'rankId', - type: union([undefinedType, array(number)]), - }, - searchText: { - defaultValue: undefined, - storageKey: 'searchText', - type: union([undefinedType, string]), - }, - }, - storagePath: `log-viewer-filters-${id}`, -}); diff --git a/webui/react/src/components/kit/LogViewer/LogViewerSelect.test.tsx b/webui/react/src/components/kit/LogViewer/LogViewerSelect.test.tsx deleted file mode 100644 index eeab558ec35..00000000000 --- a/webui/react/src/components/kit/LogViewer/LogViewerSelect.test.tsx +++ /dev/null @@ -1,137 +0,0 @@ -/* eslint-disable @typescript-eslint/no-non-null-assertion */ -import { render, screen, waitFor } from '@testing-library/react'; -import userEvent, { PointerEventsCheckLevel } from '@testing-library/user-event'; - -import { generateAlphaNumeric, generateUUID } from 'components/kit/internal/functions'; -import { LogLevelFromApi } from 'components/kit/internal/types'; - -import LogViewerSelect, { ARIA_LABEL_RESET, Filters, LABELS } from './LogViewerSelect'; - -const DEFAULT_FILTER_OPTIONS: Filters = { - agentIds: new Array(3).fill('').map(() => `i-${generateAlphaNumeric(17)}`), - allocationIds: new Array(2).fill('').map((_, i) => `${generateUUID()}.${i}`), - containerIds: ['', ...new Array(2).fill('').map(() => generateUUID())], - rankIds: [0, 1, 2, -1], - // sources: ['agent', 'master'], - // stdtypes: ['stdout', 'stderr'], -}; - -const setup = (filterOptions: Filters, filterValues: Filters) => { - const handleOnChange = vi.fn(); - const handleOnReset = vi.fn(); - const view = render( - , - ); - const user = userEvent.setup({ pointerEventsCheck: PointerEventsCheckLevel.Never }); - return { handleOnChange, handleOnReset, user, view }; -}; - -describe('LogViewerFilter', () => { - it('should render all select filters with options', async () => { - setup(DEFAULT_FILTER_OPTIONS, {}); - - await waitFor(() => { - Object.values(LABELS).forEach((label) => { - if (!DEFAULT_FILTER_OPTIONS[label as keyof typeof DEFAULT_FILTER_OPTIONS]) return; - const regex = new RegExp(`All ${label}`, 'i'); - expect(screen.queryByText(regex)).toBeInTheDocument(); - }); - }); - }); - - it('should render select filters with selected options', async () => { - const values: Filters = { - agentIds: [DEFAULT_FILTER_OPTIONS.agentIds![1]], - allocationIds: [DEFAULT_FILTER_OPTIONS.allocationIds![1]], - containerIds: [DEFAULT_FILTER_OPTIONS.containerIds![1]], - levels: [LogLevelFromApi.Info], - rankIds: [DEFAULT_FILTER_OPTIONS.rankIds![1]], - }; - setup(DEFAULT_FILTER_OPTIONS, values); - - await waitFor(() => { - expect(screen.getAllByText('1 selected')).toHaveLength(5); - }); - }); - - it('should render filters with rank 0; No Rank added automatically', async () => { - const values: Filters = { - agentIds: [], - allocationIds: [], - containerIds: [], - levels: [], - rankIds: [0], - }; - const { user } = setup(values, { ...values, rankIds: [] }); - - const agentOption1 = screen.getByText('All Ranks'); - await user.click(agentOption1); - await waitFor(() => { - expect(screen.getAllByText('0')).toHaveLength(2); - }); - }); - - it('should render filters without rank', () => { - const values: Filters = { - agentIds: [], - allocationIds: [], - containerIds: [], - levels: [], - rankIds: undefined, - }; - setup(values, { ...values, rankIds: [] }); - - expect(screen.queryByText(new RegExp('rank', 'i'))).not.toBeInTheDocument(); - }); - - it('should call onChange when options are selected', async () => { - const { handleOnChange, user } = setup(DEFAULT_FILTER_OPTIONS, {}); - - const agentRegex = new RegExp(`All ${LABELS.agentIds}`, 'i'); - const agentOptionText1 = DEFAULT_FILTER_OPTIONS.agentIds![1]; - const agentOptionText2 = DEFAULT_FILTER_OPTIONS.agentIds![2]; - - const agent = screen.getByText(agentRegex); - await user.click(agent); - - const agentOption1 = await screen.findAllByText(agentOptionText1); - const agentOption2 = await screen.findByText(agentOptionText2); - await user.click(agentOption1[1]); - await user.click(agentOption2); - - await waitFor(() => { - expect(handleOnChange).toHaveBeenCalledWith({ - agentIds: [agentOptionText1, agentOptionText2], - }); - }); - }); - - it('should not show reset button when no filters are set', () => { - setup(DEFAULT_FILTER_OPTIONS, {}); - expect(screen.queryByText(ARIA_LABEL_RESET)).not.toBeInTheDocument(); - }); - - it('should show reset button when filters are set', () => { - const values = { - agentIds: [DEFAULT_FILTER_OPTIONS.agentIds![1]], - containerIds: [DEFAULT_FILTER_OPTIONS.containerIds![1]], - }; - setup(DEFAULT_FILTER_OPTIONS, values); - expect(screen.queryByText(ARIA_LABEL_RESET)).toBeInTheDocument(); - }); - - it('should call onReset when reset button is clicked', async () => { - const values = { agentIds: [DEFAULT_FILTER_OPTIONS.agentIds![1]] }; - const { handleOnReset, user } = setup(DEFAULT_FILTER_OPTIONS, values); - - await user.click(screen.getByText(ARIA_LABEL_RESET)); - - expect(handleOnReset).toHaveBeenCalled(); - }); -}); diff --git a/webui/react/src/components/kit/LogViewer/LogViewerSelect.tsx b/webui/react/src/components/kit/LogViewer/LogViewerSelect.tsx deleted file mode 100644 index adad73d1e4e..00000000000 --- a/webui/react/src/components/kit/LogViewer/LogViewerSelect.tsx +++ /dev/null @@ -1,224 +0,0 @@ -import { Space } from 'antd'; -import { SelectValue } from 'antd/es/select'; -import React, { useCallback, useEffect, useMemo, useState } from 'react'; -import { throttle } from 'throttle-debounce'; - -import Button from 'components/kit/Button'; -import Input from 'components/kit/Input'; -import { alphaNumericSorter } from 'components/kit/internal/functions'; -import { LogLevelFromApi } from 'components/kit/internal/types'; -import Select, { Option } from 'components/kit/Select'; - -interface Props { - onChange?: (filters: Filters) => void; - onReset?: () => void; - options: Filters; - showSearch: boolean; - values: Filters; -} - -export interface Filters { - agentIds?: string[]; - allocationIds?: string[]; - containerIds?: string[]; - levels?: LogLevelFromApi[]; - rankIds?: number[]; - searchText?: string; - // sources?: string[], - // stdtypes?: string[], -} - -export const ARIA_LABEL_RESET = 'Reset'; - -export const LABELS: Record = { - agentIds: 'Agents', - allocationIds: 'Allocations', - containerIds: 'Containers', - levels: 'Levels', - rankIds: 'Ranks', - searchText: 'Searches', -}; - -const LogViewerSelect: React.FC = ({ - onChange, - onReset, - options, - showSearch, - values, -}: Props) => { - const [filters, setFilters] = useState(values); - - const selectOptions = useMemo(() => { - const { agentIds, allocationIds, containerIds, rankIds } = options; - return { - ...options, - agentIds: agentIds?.sortAll(alphaNumericSorter), - allocationIds: allocationIds?.sortAll(alphaNumericSorter), - containerIds: containerIds?.sortAll(alphaNumericSorter), - levels: Object.entries(LogLevelFromApi) - .filter((entry) => entry[1] !== LogLevelFromApi.Unspecified) - .map(([key, value]) => ({ label: key, value })), - rankIds: rankIds ? [-1].concat(rankIds).sortAll(alphaNumericSorter) : [-1], - }; - }, [options]); - - const moreThanOne = useMemo(() => { - return Object.keys(selectOptions).reduce((acc, key) => { - const filterKey = key as keyof Filters; - const options = selectOptions[filterKey]; - - // !! casts `undefined` into the boolean value of `false`. - acc[filterKey] = !!(options && options.length > 1); - - return acc; - }, {} as Record); - }, [selectOptions]); - - const isResetShown = useMemo(() => { - if (values.searchText) return true; - - const keys = Object.keys(selectOptions); - for (let i = 0; i < keys.length; i++) { - const key = keys[i] as keyof Filters; - const value = values[key]; - if (value && value.length !== 0) return true; - } - - return false; - }, [selectOptions, values]); - - const throttledChangeFilter = useMemo( - () => - throttle( - 500, - (f: Filters) => { - onChange?.(f); - }, - { noLeading: true }, - ), - [onChange], - ); - - useEffect(() => { - return () => { - throttledChangeFilter.cancel(); - }; - }, [throttledChangeFilter]); - - const handleChange = useCallback( - (key: keyof Filters, caster: NumberConstructor | StringConstructor) => (value: SelectValue) => { - setFilters((prev) => { - const newF = { - ...prev, - [key]: (value as Array).map((item) => caster(item)), - }; - throttledChangeFilter(newF); - return newF; - }); - }, - [throttledChangeFilter], - ); - - const handleSearch = useCallback( - (e: React.ChangeEvent) => { - setFilters((prev) => { - const newF = { ...prev, searchText: e.target.value }; - throttledChangeFilter(newF); - return newF; - }); - }, - [throttledChangeFilter], - ); - - const handleReset = useCallback(() => { - setFilters({}); - onReset?.(); - throttledChangeFilter({}); - }, [onReset, throttledChangeFilter]); - - return ( - <> - - {showSearch && ( - - )} - {moreThanOne.allocationIds && ( - - )} - {!!selectOptions?.agentIds?.length && ( - - )} - {moreThanOne.containerIds && ( - - )} - {moreThanOne.rankIds && ( - - )} - - {isResetShown && } - - - ); -}; - -export default LogViewerSelect; diff --git a/webui/react/src/components/kit/Message.module.scss b/webui/react/src/components/kit/Message.module.scss deleted file mode 100644 index 2777d0f7e07..00000000000 --- a/webui/react/src/components/kit/Message.module.scss +++ /dev/null @@ -1,14 +0,0 @@ -.base { - align-items: center; - color: var(--theme-status-inactive-weak); - display: flex; - flex-direction: column; - gap: 8px; - height: 100%; - justify-content: center; - padding: 40px; - - .description { - text-align: center; - } -} diff --git a/webui/react/src/components/kit/Message.tsx b/webui/react/src/components/kit/Message.tsx deleted file mode 100644 index 8afb2a8658a..00000000000 --- a/webui/react/src/components/kit/Message.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import React, { ReactNode } from 'react'; - -import Icon, { IconName } from 'components/kit/Icon'; -import Header from 'components/kit/Typography/Header'; - -import css from './Message.module.scss'; - -interface base { - action?: React.ReactElement; - icon?: IconName | React.ReactElement; -} -interface descriptionRequired extends base { - description: ReactNode; - title?: string; -} -interface titleRequired extends base { - title: string; - description?: ReactNode; -} - -export type Props = descriptionRequired | titleRequired; - -const Message: React.FC = ({ action, description, title, icon }: Props) => { - const getIcon = (icon?: IconName | React.ReactElement) => { - if (typeof icon === 'string') { - return ; - } else { - return icon; - } - }; - - return ( -
    - {icon && getIcon(icon)} - {title &&
    {title}
    } - {description &&

    {description}

    } - {action} -
    - ); -}; - -export default Message; diff --git a/webui/react/src/components/kit/Modal.module.scss b/webui/react/src/components/kit/Modal.module.scss deleted file mode 100644 index 544ac6f6c96..00000000000 --- a/webui/react/src/components/kit/Modal.module.scss +++ /dev/null @@ -1,60 +0,0 @@ -.modalContent { - :global(.ant-modal-content) { - padding: 0; - } - :global(.ant-modal-close) { - inset-inline-end: 8px; - top: 8px; - } - :global(.ant-modal-header), - :global(.ant-modal-footer) { - margin: 0; - } -} -.modalBody { - display: flex; - flex-direction: column; - gap: 16px; - padding: 16px; -} -.header { - align-items: center; - display: flex; - height: 58px; - padding: 32px 16px 0; - - .headerTitle, - .headerLink { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - .dangerIcon { - color: var(--theme-status-critical); - } - > * { - margin-inline-end: 16px; - } -} -.footer { - align-items: center; - background-color: var(--theme-surface); - display: flex; - height: 70px; - justify-content: space-between; - padding: 16px; - width: 100%; - - .footerLink { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - .buttons { - white-space: nowrap; - - > * { - margin-inline-start: 8px; - } - } -} diff --git a/webui/react/src/components/kit/Modal.test.tsx b/webui/react/src/components/kit/Modal.test.tsx deleted file mode 100644 index 34c106d265d..00000000000 --- a/webui/react/src/components/kit/Modal.test.tsx +++ /dev/null @@ -1,65 +0,0 @@ -import { render, screen, waitFor } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; -import React, { useState } from 'react'; - -import Button from 'components/kit/Button'; -import { Modal, useModal } from 'components/kit/Modal'; - -const MODAL_TITLE = 'Modal Title'; -const MODAL_CONTENT = 'Modal string value'; - -const ModalComponent: React.FC<{ value: string }> = ({ value }) => { - return ( - -
    {value}
    -
    - ); -}; - -const ModalTrigger: React.FC = () => { - const Modal = useModal(ModalComponent); - const [modalValue, setModalValue] = useState(''); - return ( - <> - - - - ); -}; - -const setup = async () => { - const user = userEvent.setup(); - - render(); - - await user.click(await screen.findByRole('button')); - - return user; -}; - -describe('Modal', () => { - it('should open', async () => { - await setup(); - - expect(await screen.findByText(MODAL_TITLE)).toBeInTheDocument(); - expect(await screen.findByText(MODAL_CONTENT)).toBeInTheDocument(); - }); - - it('should close', async () => { - const user = await setup(); - - const closeButton = await screen.findByLabelText('Close'); - await user.click(closeButton); - - await waitFor(() => { - expect(screen.queryByText(MODAL_TITLE)).not.toBeInTheDocument(); - expect(screen.queryByText(MODAL_CONTENT)).not.toBeInTheDocument(); - }); - }); -}); diff --git a/webui/react/src/components/kit/Modal.tsx b/webui/react/src/components/kit/Modal.tsx deleted file mode 100644 index 5fa800343d2..00000000000 --- a/webui/react/src/components/kit/Modal.tsx +++ /dev/null @@ -1,181 +0,0 @@ -import { Modal as AntdModal } from 'antd'; -import React, { - createContext, - Dispatch, - ReactNode, - SetStateAction, - useCallback, - useContext, - useState, -} from 'react'; - -import Button from 'components/kit/Button'; -import Icon, { IconName } from 'components/kit/Icon'; -import { ErrorHandler, ErrorLevel, ErrorType } from 'components/kit/internal/types'; -import Spinner from 'components/kit/Spinner'; - -import css from './Modal.module.scss'; - -export type ModalSize = 'small' | 'medium' | 'large'; -const modalWidths: { [key in ModalSize]: number } = { - large: 1025, - medium: 692, - small: 358, -}; - -export type Opener = Dispatch>; - -export type ModalContext = { - isOpen: boolean; - setIsOpen: Opener; -}; - -export interface ModalSubmitParams { - disabled?: boolean; - text: string; - handler: () => Promise | void; - onComplete?: () => Promise | void; - handleError: ErrorHandler; - form?: string; -} - -interface ModalProps { - cancel?: boolean; - cancelText?: string; - danger?: boolean; - footerLink?: React.ReactNode; - headerLink?: React.ReactNode; - icon?: IconName; - key?: string; - onClose?: () => void; - size?: ModalSize; - submit?: ModalSubmitParams; - title: string; - children: ReactNode; -} - -export const DEFAULT_CANCEL_LABEL = 'Cancel'; - -const ModalContext = createContext(null); - -export const Modal: React.FC = ({ - cancel, - cancelText, - danger, - footerLink, - headerLink, - icon, - key, - onClose, - size = 'large', - submit, - title, - children: modalBody, -}: ModalProps) => { - const modalContext = useContext(ModalContext); - - if (modalContext === null) { - throw new Error('Modal used outside of ModalContext'); - } - const { isOpen, setIsOpen } = modalContext; - - const [isSubmitting, setIsSubmitting] = useState(false); - - const close = useCallback(() => { - setIsOpen(false); - onClose?.(); - }, [setIsOpen, onClose]); - - const handleSubmit = useCallback(async () => { - setIsSubmitting(true); - try { - await new Promise((resolve) => setTimeout(resolve)); // delays form validation until next event cycle to prevent validation conflicts - await submit?.handler(); - setIsSubmitting(false); - setIsOpen(false); - await submit?.onComplete?.(); - } catch (err) { - submit?.handleError(err, { - level: ErrorLevel.Error, - publicMessage: err instanceof Error ? err.message : '', - publicSubject: 'Could not submit form', - silent: false, - type: ErrorType.Server, - }); - setIsSubmitting(false); - } - }, [submit, setIsOpen]); - - return ( - } - footer={ -
    -
    {footerLink}
    -
    - {(cancel || cancelText) && ( - - )} - -
    -
    - } - key={key} - maskClosable={true} - open={isOpen} - title={ -
    - {danger ? ( -
    - -
    - ) : ( - icon && - )} -
    {title}
    -
    {headerLink}
    -
    - } - width={modalWidths[size]} - onCancel={close} - onOk={handleSubmit}> - -
    {modalBody}
    -
    -
    - ); -}; - -export const useModal = ( - Comp: React.FC, -): { Component: React.FC; open: () => void } => { - const [isOpen, setIsOpen] = useState(false); - const handleOpen = React.useCallback(() => setIsOpen(true), []); - - const Component = React.useCallback( - (props: ModalProps) => { - return ( - - - - ); - }, - [Comp, isOpen], - ); - return { Component, open: handleOpen }; -}; diff --git a/webui/react/src/components/kit/Nameplate.module.scss b/webui/react/src/components/kit/Nameplate.module.scss deleted file mode 100644 index e7f2b4687e5..00000000000 --- a/webui/react/src/components/kit/Nameplate.module.scss +++ /dev/null @@ -1,26 +0,0 @@ -.base { - align-items: center; - display: flex; - gap: 16px; - - .text { - overflow: hidden; - - .alias { - font-size: larger; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - .name { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - } -} -.compact { - font-size: smaller; - line-height: initial; - min-height: 38px; -} diff --git a/webui/react/src/components/kit/Nameplate.tsx b/webui/react/src/components/kit/Nameplate.tsx deleted file mode 100644 index 309b3644618..00000000000 --- a/webui/react/src/components/kit/Nameplate.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import React, { ReactNode } from 'react'; - -import css from './Nameplate.module.scss'; - -export interface Props { - alias?: string; - compact?: boolean; - icon: ReactNode; - name: string; -} - -const Nameplate: React.FC = ({ alias, compact, icon, name }) => { - const classnames = [css.base]; - if (compact) classnames.push(css.compact); - - return ( -
    - {icon} -
    - {alias &&
    {alias}
    } -
    {name}
    -
    -
    - ); -}; - -export default Nameplate; diff --git a/webui/react/src/components/kit/NoteCard.module.scss b/webui/react/src/components/kit/NoteCard.module.scss deleted file mode 100644 index 1395c9c4c30..00000000000 --- a/webui/react/src/components/kit/NoteCard.module.scss +++ /dev/null @@ -1,7 +0,0 @@ -.base { - min-height: 300px; - - :global(.ant-card-head-title) { - margin-right: 8px; - } -} diff --git a/webui/react/src/components/kit/NoteCard.tsx b/webui/react/src/components/kit/NoteCard.tsx deleted file mode 100644 index fe1c36aa3cf..00000000000 --- a/webui/react/src/components/kit/NoteCard.tsx +++ /dev/null @@ -1,194 +0,0 @@ -import { Card, Space } from 'antd'; -import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import { unstable_useBlocker as useBlocker } from 'react-router-dom'; - -import Button from 'components/kit/Button'; -import Icon from 'components/kit/Icon'; -import Input from 'components/kit/Input'; -import Markdown from 'components/kit/internal/Markdown'; -import { ErrorHandler, ErrorType, Note } from 'components/kit/internal/types'; -import Spinner from 'components/kit/Spinner'; - -import css from './NoteCard.module.scss'; - -interface Props { - disabled?: boolean; - disableTitle?: boolean; - extra?: React.ReactNode; - noteChangeSignal?: number; - note: Note; - onChange?: (editedNotes: string) => void; - onError: ErrorHandler; - onSaveNote: (notes: Note) => Promise; -} - -const NoteCard: React.FC = ({ - disabled = false, - disableTitle = false, - note, - extra, - onChange, - onError, - onSaveNote, - noteChangeSignal, -}: Props) => { - const [isEditing, setIsEditing] = useState(false); - const [isLoading, setIsLoading] = useState(false); - const [editedNotes, setEditedNotes] = useState(note?.contents || ''); - const [editedTitle, setEditedTitle] = useState(note?.name || ''); - const [notes, title] = useMemo(() => [note?.contents || '', note?.name || ''], [note]); - - const blocker = () => { - if (isEditing && notes !== editedNotes) { - const answer = window.confirm( - 'You have unsaved notes, are you sure you want to leave? Unsaved notes will be lost.', - ); - return !answer; - } - return false; - }; - useBlocker(() => blocker()); - - const existingNotes = useRef(notes); - const existingTitle = useRef(title); - - useEffect(() => { - existingNotes.current = notes; - }, [notes]); - useEffect(() => { - existingTitle.current = title; - }, [title]); - - useEffect(() => { - setIsEditing(false); - setIsLoading(false); - setEditedNotes(existingNotes.current); - setEditedTitle(existingTitle.current); - }, [noteChangeSignal]); - - const editNotes = useCallback(() => { - if (disabled) return; - setIsEditing(true); - }, [disabled]); - - const cancelEdit = useCallback(() => { - setIsEditing(false); - setEditedNotes(notes); - onChange?.(notes); - setEditedTitle(title); - }, [notes, title, onChange]); - - const onSave = useCallback( - async (editNotes: string) => { - await onSaveNote({ contents: editNotes, name: editedTitle }); - }, - [onSaveNote, editedTitle], - ); - - const onSaveTitle = useCallback( - async (editTitle: string) => { - await onSaveNote({ contents: editedNotes, name: editTitle }); - }, - [onSaveNote, editedNotes], - ); - - const saveNotes = useCallback(async () => { - try { - setIsLoading(true); - await onSave?.(editedNotes.trim()); - setIsEditing(false); - } catch (e) { - onError(e, { - publicSubject: 'Unable to update notes.', - silent: true, - type: ErrorType.Api, - }); - } - setIsLoading(false); - }, [editedNotes, onSave, onError]); - - const handleEditedNotes = useCallback( - (newNotes: string) => { - setEditedNotes(newNotes); - onChange?.(newNotes); - }, - [onChange], - ); - - const handleNotesClick = useCallback( - (e: React.MouseEvent) => { - if (e.detail > 1 || notes === '') editNotes(); - }, - [editNotes, notes], - ); - - useEffect(() => { - setEditedNotes(notes); - setIsEditing(false); - }, [notes]); - - return ( - - - - - ) : ( - disabled || ( - - } - - } - icon="document" - /> - ); - } - - return ( - <> -
    - {!disabled && ( - - )} -
    -
    - {notes.length > 0 && ( -
    -
      - {(notes as Note[]).map((note, idx) => ( - handleDropdown(idx)}> -
    • handleSwitchPage(idx)}> - {note.name} - {!disabled && ( - handleDropdown(idx)}> -
      e.stopPropagation()}> - -
      -
      - )} -
    • -
      - ))} -
    -
    - )} -
    - -
    -
    - handleDropdown(currentPage)}> -
    - {contextHolder} -
    - - ); -}; - -export default NoteCards; diff --git a/webui/react/src/components/kit/Notes.tsx b/webui/react/src/components/kit/Notes.tsx deleted file mode 100644 index ba70856adf0..00000000000 --- a/webui/react/src/components/kit/Notes.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import { ErrorHandler, Note } from 'components/kit/internal/types'; - -import NoteCard from './NoteCard'; -import NoteCards from './NoteCards'; -export type Props = - | { - multiple: true; - disabled?: boolean; - disableTitle?: boolean; - notes: Note[]; - onDelete?: (pageNumber: number) => void; - onNewPage: () => void; - onSave: (notes: Note[]) => Promise; - onError: ErrorHandler; - } - | { - multiple?: false; - disabled?: boolean; - disableTitle?: boolean; - notes: Note; - onSave: (notes: Note) => Promise; - onError: ErrorHandler; - }; - -const Notes: React.FC = ({ - multiple, - notes, - onError, - onSave, - disabled = false, - disableTitle, - ...props -}: Props) => { - return multiple ? ( - {}} - onSave={onSave} - /> - ) : ( - - ); -}; - -export default Notes; diff --git a/webui/react/src/components/kit/Pagination.tsx b/webui/react/src/components/kit/Pagination.tsx deleted file mode 100644 index b7c545a5498..00000000000 --- a/webui/react/src/components/kit/Pagination.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { Pagination as AntdPagination } from 'antd'; -import React, { ReactNode } from 'react'; - -interface PaginationProps { - current?: number; - itemRender?: ( - page: number, - type: 'page' | 'prev' | 'next' | 'jump-prev' | 'jump-next', - originalElement: ReactNode, - ) => ReactNode; - onChange?: (page: number, pageSize: number) => void; - pageSize?: number; - pageSizeOptions?: number[]; - showSizeChanger?: boolean; - total: number; -} - -const Pagination: React.FC = ({ - current = 1, - pageSize = 10, - total = 0, - ...props -}: PaginationProps) => { - return ; -}; - -export default Pagination; diff --git a/webui/react/src/components/kit/Pivot.module.scss b/webui/react/src/components/kit/Pivot.module.scss deleted file mode 100644 index 80669d0c944..00000000000 --- a/webui/react/src/components/kit/Pivot.module.scss +++ /dev/null @@ -1,57 +0,0 @@ -/* stylelint-disable no-descending-specificity */ - -/* Tabs */ - -.base { - &:global(.ant-tabs) { - height: 100%; - } - &:global(.ant-tabs > .ant-tabs-content-holder) { - height: 100%; - } - &:global(.ant-tabs .ant-tabs-tab-active > .ant-tabs-tab-btn) { - text-shadow: none; - } - &:global(.ant-tabs > .ant-tabs-content-holder > .ant-tabs-content) { - height: 100%; - } - &:global(.ant-tabs-top > .ant-tabs-nav::before), - &:global(.ant-tabs-bottom > .ant-tabs-nav::before), - &:global(.ant-tabs-top > div > .ant-tabs-nav::before), - &:global(.ant-tabs-bottom > div > .ant-tabs-nav::before) { - border-color: var(--theme-stage-border); - } - - /* Tabs Cards Style */ - - &:global(.ant-tabs-card > .ant-tabs-nav > .ant-tabs-nav-wrap .ant-tabs-tab) { - background-color: var(--theme-surface-strong); - border-color: var(--theme-surface-border); - } - &:global(.ant-tabs-card > .ant-tabs-nav > .ant-tabs-nav-wrap .ant-tabs-tab:hover) { - background-color: var(--theme-surface); - color: var(--theme-surface-on); - } - &:global(.ant-tabs-card > .ant-tabs-nav > .ant-tabs-nav-wrap .ant-tabs-tab-active) { - background-color: var(--theme-surface); - border-bottom-color: var(--theme-surface); - } - &:global(.ant-tabs-card > .ant-tabs-nav) { - margin: 0; - } - &:global(.ant-tabs-card > .ant-tabs-content-holder) { - background-color: var(--theme-surface); - border-color: var(--theme-surface-border); - border-style: solid; - border-width: 0 var(--theme-stroke-width) var(--theme-stroke-width) var(--theme-stroke-width); - } - &:global(.ant-tabs-card > .ant-tabs-content-holder > .ant-tabs-content) { - padding: 16px; - } - &:global(.ant-tabs-card.ant-tabs-top > .ant-tabs-nav::before), - &:global(.ant-tabs-card.ant-tabs-bottom > .ant-tabs-nav::before), - &:global(.ant-tabs-card.ant-tabs-top > div > .ant-tabs-nav::before), - &:global(.ant-tabs-card.ant-tabs-bottom > div > .ant-tabs-nav::before) { - border-color: var(--theme-surface-border); - } -} diff --git a/webui/react/src/components/kit/Pivot.tsx b/webui/react/src/components/kit/Pivot.tsx deleted file mode 100644 index 4d8d999b8d0..00000000000 --- a/webui/react/src/components/kit/Pivot.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { Tabs, TabsProps } from 'antd'; -import React, { KeyboardEvent, MouseEvent, ReactNode } from 'react'; - -import css from './Pivot.module.scss'; - -export type TabItem = { - children?: ReactNode; - forceRender?: boolean; - key: string; - label: ReactNode; -}; - -export type PivotTabType = 'primary' | 'secondary'; - -interface PivotProps { - activeKey?: string; - defaultActiveKey?: string; - destroyInactiveTabPane?: boolean; - items?: TabItem[]; - onChange?: (activeKey: string) => void; - onTabClick?: (key: string, event: MouseEvent | KeyboardEvent) => void; - tabBarExtraContent?: ReactNode; - type?: PivotTabType; -} - -const convertTabType = (type: PivotTabType): TabsProps['type'] => { - switch (type) { - case 'primary': - return 'line'; - case 'secondary': - return 'card'; - default: - return 'line'; - } -}; - -const Pivot: React.FC = ({ type = 'primary', ...props }: PivotProps) => { - const tabType = convertTabType(type); - - return ; -}; - -export default Pivot; diff --git a/webui/react/src/components/kit/Select.module.scss b/webui/react/src/components/kit/Select.module.scss deleted file mode 100644 index cba3412ac4f..00000000000 --- a/webui/react/src/components/kit/Select.module.scss +++ /dev/null @@ -1,27 +0,0 @@ -.base { - align-items: center; - display: flex; - gap: 8px; - max-width: 100%; - - :global(.ant-select-selection-overflow) { - overflow: hidden; - } - :global(.ant-select-selection-search-input), - :global(.ant-select-multiple .ant-select-selection-search-input) { - width: auto; - } -} -.disableTags { - :global(.ant-select-multiple .ant-select-selection-item) { - background-color: transparent; - border: 0; - } - :global(.ant-select-multiple.ant-select-open .ant-select-selection-item) { - display: none; - } - :global(.ant-select-multiple.ant-select-open .ant-select-selection-search) { - margin-left: 8px; - max-width: calc(100% - 32px); - } -} diff --git a/webui/react/src/components/kit/Select.test.tsx b/webui/react/src/components/kit/Select.test.tsx deleted file mode 100644 index 897fb8e55e8..00000000000 --- a/webui/react/src/components/kit/Select.test.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import { render, screen, waitFor } from '@testing-library/react'; -import userEvent, { PointerEventsCheckLevel } from '@testing-library/user-event'; - -import { generateAlphaNumeric } from 'components/kit/internal/functions'; - -import Select, { Option } from './Select'; - -const LABEL = generateAlphaNumeric(); -const PLACEHOLDER = generateAlphaNumeric(); -const NUM_OPTIONS = 5; -const OPTION_TITLE = 'option'; - -const user = userEvent.setup({ pointerEventsCheck: PointerEventsCheckLevel.Never }); - -const setup = () => { - const handleOpen = vi.fn(); - const view = render( - , - ); - return { handleOpen, user, view }; -}; - -describe('Select', () => { - it('displays label and placeholder', async () => { - setup(); - - await waitFor(() => { - expect(screen.queryByText(LABEL)).toBeInTheDocument(); - expect(screen.queryByText(PLACEHOLDER)).toBeInTheDocument(); - }); - }); - - it('opens select list', async () => { - const { handleOpen } = setup(); - - expect(handleOpen).not.toHaveBeenCalled(); - await user.click(screen.getByText(PLACEHOLDER)); - - await waitFor(() => { - expect(screen.queryAllByTitle(OPTION_TITLE)).toHaveLength(NUM_OPTIONS); - }); - }); - - it('selects option', async () => { - setup(); - - await user.click(screen.getByText(PLACEHOLDER)); - - const list = screen.getAllByTitle(OPTION_TITLE); - const firstOption = list[0].textContent ?? ''; - - await user.click(list[0]); - - await waitFor(() => { - expect(document.querySelector('.ant-select-selection-item')?.textContent).toBe(firstOption); - }); - }); - - it('searches', async () => { - setup(); - - await user.click(screen.getByText(PLACEHOLDER)); - - const firstOption = screen.getAllByTitle(OPTION_TITLE)[0].textContent ?? ''; - - await user.type(screen.getByRole('combobox'), firstOption); - - await waitFor(() => { - expect(screen.queryAllByTitle(OPTION_TITLE)).toHaveLength(1); - expect(screen.queryByTitle(OPTION_TITLE)?.textContent).toBe(firstOption); - }); - }); -}); diff --git a/webui/react/src/components/kit/Select.tsx b/webui/react/src/components/kit/Select.tsx deleted file mode 100644 index 1e7cabaf5ea..00000000000 --- a/webui/react/src/components/kit/Select.tsx +++ /dev/null @@ -1,153 +0,0 @@ -import { Select as AntdSelect, SelectProps as AntdSelectProps } from 'antd'; -import type { DefaultOptionType, RefSelectProps, SelectValue } from 'antd/es/select'; -import React, { forwardRef, useCallback, useMemo, useState } from 'react'; - -import Icon from 'components/kit/Icon'; -import Label, { LabelTypes } from 'components/kit/internal/Label'; -import { useSelectEscape } from 'components/kit/internal/useInputEscape'; - -import css from './Select.module.scss'; - -const { OptGroup, Option } = AntdSelect; - -export { Option, OptGroup, SelectValue }; - -type Options = DefaultOptionType | DefaultOptionType[]; -export interface SelectProps { - allowClear?: boolean; - attachDropdownToContainer?: boolean; - autoFocus?: boolean; - defaultValue?: T; - disableTags?: boolean; - disabled?: boolean; - filterOption?: AntdSelectProps['filterOption']; - filterSort?: AntdSelectProps['filterSort']; - id?: string; - label?: string; - loading?: boolean; - mode?: 'multiple' | 'tags'; - onBlur?: () => void; - onChange?: (value: T, option: Options) => void; - onDeselect?: (selected: SelectValue, option: Options) => void; - onSearch?: (searchInput: string) => void; - onSelect?: (selected: SelectValue, option: Options) => void; - options?: AntdSelectProps['options']; - placeholder?: string; - ref?: React.Ref; - dropdownMatchSelectWidth?: boolean | number; - searchable?: boolean; - value?: T; - width?: React.CSSProperties['width']; - onDropdownVisibleChange?: (open: boolean) => void; -} - -const countOptions = (children: React.ReactNode, options?: Options): number => { - let count = 0; - - if (options) return options.length; - if (!children) return count; - - if (Array.isArray(children)) { - count += children - .map((child) => countOptions(child, options)) - .reduce((acc, count) => acc + count, 0); - } - - const childType = (children as React.ReactElement).type; - const childProps = (children as React.ReactElement).props; - const childList = (childProps as React.ReactPortal)?.children; - if (childType === Option) count++; - if (childType === OptGroup && childList) count += countOptions(childList, options); - - return count; -}; - -const Select: React.FC> = forwardRef(function Select( - { - attachDropdownToContainer, - disabled, - disableTags = false, - searchable = true, - dropdownMatchSelectWidth = true, - filterOption, - label, - loading, - onSearch, - options, - width, - value, - children, - onDropdownVisibleChange, - ...passthrough - }: React.PropsWithChildren, - ref?: React.Ref, -) { - const [isOpen, setIsOpen] = useState(false); - const classes = [css.base]; - - const divRef = React.createRef(); - const { onBlur, onFocus, inputRef } = useSelectEscape(divRef, isOpen, ref); - - if (disableTags) classes.push(css.disableTags); - - const optionsCount = useMemo(() => countOptions(children, options), [children, options]); - const [maxTagCount, maxTagPlaceholder] = useMemo((): [0 | undefined, string] => { - if (!disableTags) return [undefined, '']; - const count = Array.isArray(value) ? value.length : value ? 1 : 0; - const itemLabel = 'selected'; - const placeholder = count === optionsCount ? 'All' : `${count} ${itemLabel}`; - return isOpen ? [0, ''] : [0, placeholder]; - }, [disableTags, isOpen, optionsCount, value]); - - const handleDropdownVisibleChange = useCallback((open: boolean) => { - setIsOpen(open); - }, []); - const handleFilter = useCallback((search: string, option?: DefaultOptionType): boolean => { - let label: string | null = null; - - if (!option?.children && !option?.label) return false; - - if (Array.isArray(option.children)) { - label = option.children.join(' '); - } else if (option.label) { - label = option.label.toString(); - } else if (typeof option.children === 'string') { - label = option.children; - } - return !!label && label.toLocaleLowerCase().includes(search.toLocaleLowerCase()); - }, []); - - const getPopupContainer = (triggerNode: Element) => { - // triggerNode.parentElement can be falsy, so instead of a ternary, we fall back - // to document.body - return (attachDropdownToContainer && triggerNode.parentElement) || document.body; - }; - - return ( -
    - {label && } - : undefined} - value={value} - onBlur={onBlur} - onDropdownVisibleChange={handleDropdownVisibleChange} - onFocus={onFocus} - onSearch={onSearch} - {...passthrough}> - {children} - -
    - ); -}); - -export default Select; diff --git a/webui/react/src/components/kit/Spinner.module.scss b/webui/react/src/components/kit/Spinner.module.scss deleted file mode 100644 index 330580a9fa9..00000000000 --- a/webui/react/src/components/kit/Spinner.module.scss +++ /dev/null @@ -1,26 +0,0 @@ -@keyframes rotate { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} - -.base { - height: 100%; - min-height: inherit; - position: relative; - width: 100%; - - .spin { - animation: rotate 1s linear infinite; - color: var(--theme-brand); - display: flex; - } - &.center { - align-items: center; - display: flex; - justify-content: center; - } -} diff --git a/webui/react/src/components/kit/Spinner.test.tsx b/webui/react/src/components/kit/Spinner.test.tsx deleted file mode 100644 index 19938451686..00000000000 --- a/webui/react/src/components/kit/Spinner.test.tsx +++ /dev/null @@ -1,107 +0,0 @@ -import { StyleProvider } from '@ant-design/cssinjs'; -import { render, screen, waitFor } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; -import React, { useEffect, useState } from 'react'; -import { Mock } from 'vitest'; - -import Spinner from './Spinner'; - -// vi.useRealTimers(); // This should solve the flakyness around timming out - -const spinnerTextContent = 'Spinner Text Content'; - -const user = userEvent.setup(); -interface Props { - handleButtonClick: Mock; - spinning: boolean; -} - -const SpinnerComponent = ({ spinning, handleButtonClick }: Props) => { - const [isSpin, setIsSpin] = useState(false); - - useEffect(() => { - setIsSpin(spinning); - }, [spinning]); - - const onToggle = () => setIsSpin((v) => !v); - - return ( - <> - - - - - - ); -}; - -const setup = async (spinning: boolean) => { - const handleButtonClick = vi.fn(); - const { container } = render( - // apply css-in-js styles without the :when selector - - , - , - ); - await new Promise((resolve) => setTimeout(resolve, 10)); - return { container, handleButtonClick }; -}; - -describe('Spinner', () => { - it('blocks inner content while spinning', async () => { - const { handleButtonClick } = await setup(true); - const button = await screen.findByTestId('inside-button'); - let error = null; - try { - await waitFor(() => user.click(button)); - } catch (e) { - error = e; - } - const spin = document.body.querySelector('.ant-spin'); - expect(spin).toHaveStyle({ position: 'absolute' }); - expect(error).not.toBeNull(); - expect(handleButtonClick).toHaveBeenCalledTimes(0); - }); - - it('doesnt block inner content when not spinning', async () => { - const { handleButtonClick } = await setup(false); - const button = screen.getByTestId('inside-button'); - await user.click(button); - expect(handleButtonClick).toHaveBeenCalledTimes(1); - }); - - it('displays tip text when spinning', async () => { - await setup(true); - expect(await screen.findByText(spinnerTextContent)).toBeInTheDocument(); - }); - - it('doesnt display tip text when not spinning', async () => { - await setup(false); - expect(screen.queryByText(spinnerTextContent)).not.toBeInTheDocument(); - }); - - it('goes away when spinning is updated to false', async () => { - const { container } = await setup(true); - - await waitFor(() => { - expect(container.getElementsByClassName('ant-spin-spinning')[0]).toBeInTheDocument(); - }); - await user.click(screen.getByTestId('toogle-button')); - await waitFor(() => { - expect(container.getElementsByClassName('ant-spin-spinning')?.[0] ?? false).toBeFalsy(); - }); - }); - - it('appears when spinning is updated to false', async () => { - const { container } = await setup(false); - expect(container.getElementsByClassName('ant-spin-spinning')?.[0]).toBeFalsy(); - await user.click(screen.getByTestId('toogle-button')); - await waitFor(() => { - expect(container.getElementsByClassName('ant-spin-spinning')[0]).toBeInTheDocument(); - }); - }); -}); diff --git a/webui/react/src/components/kit/Spinner.tsx b/webui/react/src/components/kit/Spinner.tsx deleted file mode 100644 index 13c95f02054..00000000000 --- a/webui/react/src/components/kit/Spinner.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { Spin } from 'antd'; -import React from 'react'; - -import Icon, { IconSize } from 'components/kit/Icon'; -import { XOR } from 'components/kit/internal/types'; -import { Loadable } from 'components/kit/utils/loadable'; - -import css from './Spinner.module.scss'; - -interface PropsBase { - center?: boolean; - size?: IconSize; - tip?: React.ReactNode; -} - -type Props = XOR< - { - children?: React.ReactNode; - conditionalRender?: boolean; - spinning?: boolean; - }, - { - children: (data: T) => JSX.Element; - data: Loadable; - } -> & - PropsBase; - -function Spinner({ - center, - children, - conditionalRender, - size = 'medium', - spinning = true, - tip, - data, -}: Props): JSX.Element { - const classes = [css.base]; - - if (center || tip) classes.push(css.center); - - const spinner = ( -
    - - -
    - } - spinning={spinning} - tip={tip}> - {data !== undefined || (conditionalRender && spinning) ? null : children} - -
    - ); - - if (!data) { - return spinner; - } else { - return Loadable.match(data, { - Failed: () => <>, - Loaded: children, - NotLoaded: () => spinner, // TODO circle back with design to find an appropriate error state here - }); - } -} - -export default Spinner; diff --git a/webui/react/src/components/kit/Tags.module.scss b/webui/react/src/components/kit/Tags.module.scss deleted file mode 100644 index ca7f08dbe99..00000000000 --- a/webui/react/src/components/kit/Tags.module.scss +++ /dev/null @@ -1,44 +0,0 @@ -.base { - display: inline; - - & > * { - cursor: pointer; - font-size: 12px; - height: 20px; - margin: 2px 8px 2px 0; - } - .showMore { - white-space: nowrap; - } - .tagPlus { - background: var(--theme-colors-monochrome-17); - border-style: dashed; - margin-right: 6px; - } - .tagPlus:hover, - .tagEdit:hover { - border-color: var(--theme-status-active); - } - &.ghost { - .tagEdit, - .tagPlus { - background: transparent; - border-color: var(--theme-colors-monochrome-17); - color: var(--theme-colors-monochrome-17); - opacity: 0.8; - - :global(.ant-tag-close-icon) { - color: var(--theme-colors-monochrome-17); - } - &:hover { - border-color: inherit; - color: inherit; - opacity: 1; - } - } - } - .tagInput { - margin: 0 8px 0 0; - top: -1px; - } -} diff --git a/webui/react/src/components/kit/Tags.test.tsx b/webui/react/src/components/kit/Tags.test.tsx deleted file mode 100644 index 482ec3895f1..00000000000 --- a/webui/react/src/components/kit/Tags.test.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import { render, within } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; -import React from 'react'; - -import TagList, { ARIA_LABEL_CONTAINER, ARIA_LABEL_TRIGGER, tagsActionHelper } from './Tags'; - -const initTags = ['hello', 'world', 'space gap'].sort(); - -const setup = (tags: string[] = []) => { - const handleOnChange = vi.fn(); - const view = render(); - const user = userEvent.setup(); - return { handleOnChange, user, view }; -}; - -describe('TagList', () => { - it('displays list of tags in order', () => { - const { view } = setup(initTags); - - const container = view.getByLabelText(ARIA_LABEL_CONTAINER); - initTags.forEach((tag, index) => { - expect(view.getByText(tag)).toBeInTheDocument(); - expect(container.children[index].textContent).toBe(tag); - }); - }); - - it('handles tag addition', async () => { - const addition = 'fox'; - const { handleOnChange, view, user } = setup(); - - const trigger = view.getByLabelText(ARIA_LABEL_TRIGGER); - await user.click(trigger); - - await user.keyboard(addition); - await user.click(view.getByLabelText(ARIA_LABEL_CONTAINER)); - expect(handleOnChange).toHaveBeenCalledWith([addition]); - }); - - it('handles tag removal', async () => { - const removalIndex = Math.floor(Math.random() * initTags.length); - const removalTag = initTags[removalIndex]; - const resultTags = [...initTags.slice(0, removalIndex), ...initTags.slice(removalIndex + 1)]; - const { handleOnChange, view, user } = setup(initTags); - - const tag = view.getByText(removalTag).closest('[id]') as HTMLElement; - expect(tag).not.toBeNull(); - - const tagClose = within(tag).getByLabelText('close'); - await user.click(tagClose); - - expect(handleOnChange).toHaveBeenCalledWith(resultTags); - }); - - it('handles tag renaming', async () => { - const rename = 'jump'; - const renameIndex = Math.floor(Math.random() * initTags.length); - const renameTag = initTags[renameIndex]; - const { handleOnChange, user, view } = setup(initTags); - - const tag = view.getByText(renameTag); - await user.click(tag); - - await user.keyboard(rename); - await user.click(view.getByLabelText(ARIA_LABEL_CONTAINER)); - - const updatedIndex = initTags.findIndex((tag: string) => tag === renameTag); - initTags[updatedIndex] = rename; - expect(handleOnChange).toHaveBeenCalledWith(initTags); - }); -}); diff --git a/webui/react/src/components/kit/Tags.tsx b/webui/react/src/components/kit/Tags.tsx deleted file mode 100644 index 33bc2086b65..00000000000 --- a/webui/react/src/components/kit/Tags.tsx +++ /dev/null @@ -1,193 +0,0 @@ -import { Tag } from 'antd'; -import React, { useCallback, useEffect, useRef, useState } from 'react'; - -import Icon from 'components/kit/Icon'; -import Input, { InputRef } from 'components/kit/Input'; -import { alphaNumericSorter, toHtmlId, truncate } from 'components/kit/internal/functions'; -import { ValueOf } from 'components/kit/internal/types'; -import Tooltip from 'components/kit/Tooltip'; - -import css from './Tags.module.scss'; -export const TagAction = { - Add: 'Add', - Remove: 'Remove', - Update: 'Update', -} as const; - -export type TagAction = ValueOf; - -export interface Props { - compact?: boolean; - disabled?: boolean; - ghost?: boolean; - // UpdatedId refers to index now, should change this to tag ID in the future. - onAction?: (action: TagAction, tag: string, updatedId?: number) => void; - tags: string[]; -} - -export const ARIA_LABEL_CONTAINER = 'new-tag-container'; -export const ARIA_LABEL_TRIGGER = 'new-tag-trigger'; -export const ARIA_LABEL_INPUT = 'new-tag-input'; - -const TAG_MAX_LENGTH = 50; -const COMPACT_MAX_THRESHOLD = 6; - -const Tags: React.FC = ({ compact, disabled = false, ghost, tags, onAction }: Props) => { - const initialState = { - editInputIndex: -1, - inputVisible: false, - inputWidth: 82, - }; - const [state, setState] = useState(initialState); - const [showMore, setShowMore] = useState(false); - const inputRef = useRef(null); - const editInputRef = useRef(null); - - const handleClose = useCallback( - (removedTag: string) => { - onAction?.(TagAction.Remove, removedTag); - }, - [onAction], - ); - - const handleTagPlus = useCallback(() => { - setState((state) => ({ ...state, inputVisible: true })); - }, []); - - useEffect(() => { - if (state.inputVisible) inputRef.current?.focus(); - }, [state.inputVisible]); - - useEffect(() => { - if (state.editInputIndex === -1) return; - editInputRef.current?.focus(); - editInputRef.current?.select(); - }, [state.editInputIndex]); - - const stopPropagation = useCallback((e: React.MouseEvent) => e.stopPropagation(), []); - - const handleInputConfirm = ( - e: React.FocusEvent | React.KeyboardEvent, - previousValue?: string, - tagID?: number, - ) => { - const newTag = (e.target as HTMLInputElement).value.trim(); - const oldTag = previousValue?.trim(); - if (newTag) { - if (oldTag && newTag !== oldTag) { - onAction?.(TagAction.Update, newTag, tagID); - } else { - onAction?.(TagAction.Add, newTag); - } - } - setState((state) => ({ ...state, editInputIndex: -1, inputVisible: false })); - }; - - const { editInputIndex, inputVisible, inputWidth } = state; - - const classes = [css.base]; - if (ghost) classes.push(css.ghost); - - const addTagControls = inputVisible ? ( - - ) : ( - !disabled && ( - - Add Tag - - ) - ); - - return ( -
    - {compact && addTagControls} - {tags - .sort((a, b) => alphaNumericSorter(a, b)) - .map((tag, index) => { - if (compact && !showMore && index >= COMPACT_MAX_THRESHOLD) { - if (index > COMPACT_MAX_THRESHOLD) return null; - return ( - setShowMore(true)}> - +{tags.length - COMPACT_MAX_THRESHOLD} more - - ); - } - if (editInputIndex === index) { - return ( - handleInputConfirm(e, tag, index)} - onPressEnter={(e) => handleInputConfirm(e, tag, index)} - /> - ); - } - - const htmlId = toHtmlId(tag); - const isLongTag: boolean = tag.length > TAG_MAX_LENGTH; - - const tagElement = ( - handleClose(tag)}> - { - e.preventDefault(); - if (disabled) return; - const element = document.getElementById(htmlId); - const rect = element?.getBoundingClientRect(); - setState((state) => ({ - ...state, - editInputIndex: index, - inputWidth: rect?.width ?? state.inputWidth, - })); - }}> - {isLongTag && !disabled ? truncate(tag, TAG_MAX_LENGTH) : tag} - - - ); - return isLongTag && !compact ? ( - - {tagElement} - - ) : ( - tagElement - ); - })} - {!compact && addTagControls} -
    - ); -}; - -export default Tags; - -// Eventually we will deprecate API calls that take the updated list of tags, and replace them with API calls that take only the updated tag. At that point, the tagsActionHelper could be removed or revised. -export const tagsActionHelper = ( - tags: string[], - callbackFn: (tags: string[]) => void, -): ((action: TagAction, tag: string, updatedId?: number) => void) => { - return (action: TagAction, tag: string, updatedId?: number) => { - let newTags = [...tags]; - if (action === TagAction.Add) { - newTags.push(tag); - } else if (action === TagAction.Remove) { - newTags = tags.filter((t) => t !== tag); - } else if (action === TagAction.Update && updatedId !== undefined) { - newTags[updatedId] = tag; - } - callbackFn(newTags); - }; -}; diff --git a/webui/react/src/components/kit/Theme/UI.tsx b/webui/react/src/components/kit/Theme/UI.tsx deleted file mode 100644 index f59ee40a1fa..00000000000 --- a/webui/react/src/components/kit/Theme/UI.tsx +++ /dev/null @@ -1,297 +0,0 @@ -import { ConfigProvider, theme } from 'antd'; -import { ThemeConfig } from 'antd/es/config-provider/context'; -import React, { - Dispatch, - useCallback, - useContext, - useEffect, - useLayoutEffect, - useMemo, - useReducer, - useState, -} from 'react'; - -import { BrandingType, RecordKey } from 'components/kit/internal/types'; - -import { themes } from './themes'; -import { DarkLight, globalCssVars, Mode, Theme } from './themeUtils'; - -interface StateUI { - chromeCollapsed: boolean; - darkLight: DarkLight; - isPageHidden: boolean; - mode: Mode; - showChrome: boolean; - showSpinner: boolean; - theme: Theme; -} - -const initUI: StateUI = { - chromeCollapsed: false, - darkLight: DarkLight.Light, - isPageHidden: false, - mode: Mode.System, - showChrome: true, - showSpinner: false, - theme: {} as Theme, -}; - -const StoreActionUI = { - HideUIChrome: 'HideUIChrome', - HideUISpinner: 'HideUISpinner', - SetMode: 'SetMode', - SetPageVisibility: 'SetPageVisibility', - SetTheme: 'SetTheme', - ShowUIChrome: 'ShowUIChrome', - ShowUISpinner: 'ShowUISpinner', -} as const; - -type ActionUI = - | { type: typeof StoreActionUI.HideUIChrome } - | { type: typeof StoreActionUI.HideUISpinner } - | { type: typeof StoreActionUI.SetMode; value: Mode } - | { type: typeof StoreActionUI.SetPageVisibility; value: boolean } - | { type: typeof StoreActionUI.SetTheme; value: { darkLight: DarkLight; theme: Theme } } - | { type: typeof StoreActionUI.ShowUIChrome } - | { type: typeof StoreActionUI.ShowUISpinner }; - -class UIActions { - constructor(private dispatch: Dispatch) {} - - public hideChrome = (): void => { - this.dispatch({ type: StoreActionUI.HideUIChrome }); - }; - - public hideSpinner = (): void => { - this.dispatch({ type: StoreActionUI.HideUISpinner }); - }; - - public setMode = (mode: Mode): void => { - this.dispatch({ type: StoreActionUI.SetMode, value: mode }); - }; - - public setPageVisibility = (isPageHidden: boolean): void => { - this.dispatch({ type: StoreActionUI.SetPageVisibility, value: isPageHidden }); - }; - - public setTheme = (darkLight: DarkLight, theme: Theme): void => { - this.dispatch({ type: StoreActionUI.SetTheme, value: { darkLight, theme } }); - }; - - public showChrome = (): void => { - this.dispatch({ type: StoreActionUI.ShowUIChrome }); - }; - - public showSpinner = (): void => { - this.dispatch({ type: StoreActionUI.ShowUISpinner }); - }; -} - -const MATCH_MEDIA_SCHEME_DARK = '(prefers-color-scheme: dark)'; -const MATCH_MEDIA_SCHEME_LIGHT = '(prefers-color-scheme: light)'; -const ANTD_THEMES: Record = { - [DarkLight.Dark]: { - algorithm: theme.darkAlgorithm, - components: { - Button: { - colorBgContainer: 'transparent', - }, - Checkbox: { - colorBgContainer: 'transparent', - }, - DatePicker: { - colorBgContainer: 'transparent', - }, - Input: { - colorBgContainer: 'transparent', - }, - InputNumber: { - colorBgContainer: 'transparent', - }, - Modal: { - colorBgElevated: 'var(--theme-stage)', - }, - Pagination: { - colorBgContainer: 'transparent', - }, - Progress: { - marginXS: 0, - }, - Radio: { - colorBgContainer: 'transparent', - }, - Select: { - colorBgContainer: 'transparent', - }, - Tree: { - colorBgContainer: 'transparent', - }, - }, - token: { - borderRadius: 2, - colorLink: '#57a3fa', - colorLinkHover: '#8dc0fb', - colorPrimary: '#1890ff', - fontFamily: 'var(--theme-font-family)', - }, - }, - [DarkLight.Light]: { - algorithm: theme.defaultAlgorithm, - components: { - Button: { - colorBgContainer: 'transparent', - }, - Progress: { - marginXS: 0, - }, - Tooltip: { - colorBgDefault: 'var(--theme-float)', - colorTextLightSolid: 'var(--theme-float-on)', - }, - }, - token: { - borderRadius: 2, - colorPrimary: '#1890ff', - fontFamily: 'var(--theme-font-family)', - }, - }, -}; - -const getDarkLight = (mode: Mode, systemMode: Mode): DarkLight => { - const resolvedMode = - mode === Mode.System ? (systemMode === Mode.System ? Mode.Light : systemMode) : mode; - return resolvedMode === Mode.Light ? DarkLight.Light : DarkLight.Dark; -}; - -const getSystemMode = (): Mode => { - const isDark = matchMedia?.(MATCH_MEDIA_SCHEME_DARK).matches; - if (isDark) return Mode.Dark; - - const isLight = matchMedia?.(MATCH_MEDIA_SCHEME_LIGHT).matches; - if (isLight) return Mode.Light; - - return Mode.System; -}; - -const camelCaseToKebab = (text: string): string => { - return text - .trim() - .split('') - .map((char, index) => { - return char === char.toUpperCase() ? `${index !== 0 ? '-' : ''}${char.toLowerCase()}` : char; - }) - .join(''); -}; - -/** - * return a part of the input state that should be updated. - * @param state ui state - * @param action - * @returns - */ -const reducerUI = (state: StateUI, action: ActionUI): Partial | void => { - switch (action.type) { - case StoreActionUI.HideUIChrome: - if (!state.showChrome) return; - return { showChrome: false }; - case StoreActionUI.HideUISpinner: - if (!state.showSpinner) return; - return { showSpinner: false }; - case StoreActionUI.SetMode: - return { mode: action.value }; - case StoreActionUI.SetPageVisibility: - return { isPageHidden: action.value }; - case StoreActionUI.SetTheme: - return { - darkLight: action.value.darkLight, - theme: action.value.theme, - }; - case StoreActionUI.ShowUIChrome: - if (state.showChrome) return; - return { showChrome: true }; - case StoreActionUI.ShowUISpinner: - if (state.showSpinner) return; - return { showSpinner: true }; - default: - return; - } -}; -const StateContext = React.createContext(undefined); -const DispatchContext = React.createContext | undefined>(undefined); - -const reducer = (state: StateUI, action: ActionUI): StateUI => { - const newState = reducerUI(state, action); - return { ...state, ...newState }; // TODO: check for deep equality here instead of on the full state -}; - -const useUI = (): { actions: UIActions; ui: StateUI } => { - const context = useContext(StateContext); - if (context === undefined) { - throw new Error('useStore(UI) must be used within a UIProvider'); - } - const dispatchContext = useContext(DispatchContext); - if (dispatchContext === undefined) { - throw new Error('useStoreDispatch must be used within a UIProvider'); - } - const uiActions = useMemo(() => new UIActions(dispatchContext), [dispatchContext]); - return { actions: uiActions, ui: context }; -}; - -export const UIProvider: React.FC<{ children?: React.ReactNode; branding?: BrandingType }> = ({ - children, - branding, -}) => { - const [state, dispatch] = useReducer(reducer, initUI); - const [systemMode, setSystemMode] = useState(() => getSystemMode()); - - const handleSchemeChange = useCallback((event: MediaQueryListEvent) => { - if (!event.matches) setSystemMode(getSystemMode()); - }, []); - - useLayoutEffect(() => { - // Set global CSS variables shared across themes. - Object.keys(globalCssVars).forEach((key) => { - const value = (globalCssVars as Record)[key]; - document.documentElement.style.setProperty(`--${camelCaseToKebab(key)}`, value); - }); - - // Set each theme property as top level CSS variable. - Object.keys(state.theme).forEach((key) => { - const value = (state.theme as Record)[key]; - document.documentElement.style.setProperty(`--theme-${camelCaseToKebab(key)}`, value); - }); - }, [state.theme]); - - // Detect browser/OS level dark/light mode changes. - useEffect(() => { - matchMedia?.(MATCH_MEDIA_SCHEME_DARK).addEventListener('change', handleSchemeChange); - matchMedia?.(MATCH_MEDIA_SCHEME_LIGHT).addEventListener('change', handleSchemeChange); - - return () => { - matchMedia?.(MATCH_MEDIA_SCHEME_DARK).removeEventListener('change', handleSchemeChange); - matchMedia?.(MATCH_MEDIA_SCHEME_LIGHT).removeEventListener('change', handleSchemeChange); - }; - }, [handleSchemeChange]); - - // Update darkLight and theme when branding, system mode, or mode changes. - useLayoutEffect(() => { - const darkLight = getDarkLight(state.mode, systemMode); - - dispatch({ - type: StoreActionUI.SetTheme, - value: { darkLight, theme: themes[branding || 'determined'][darkLight] }, - }); - }, [branding, systemMode, state.mode]); - - const antdTheme = ANTD_THEMES[state.darkLight]; - - return ( - - - {children} - - - ); -}; - -export default useUI; diff --git a/webui/react/src/components/kit/Theme/index.ts b/webui/react/src/components/kit/Theme/index.ts deleted file mode 100644 index 7bf74fc7919..00000000000 --- a/webui/react/src/components/kit/Theme/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -import useUI from 'components/kit/Theme/UI'; - -export * from 'components/kit/Theme/themeUtils'; -export * from 'components/kit/Theme/themes'; -export * from 'components/kit/Theme/UI'; - -export default useUI; diff --git a/webui/react/src/components/kit/Theme/themeUtils.ts b/webui/react/src/components/kit/Theme/themeUtils.ts deleted file mode 100644 index 77832305804..00000000000 --- a/webui/react/src/components/kit/Theme/themeUtils.ts +++ /dev/null @@ -1,303 +0,0 @@ -/* eslint-disable sort-keys-fix/sort-keys-fix */ -import { isColor, rgba2str, rgbaMix, str2rgba } from 'components/kit/internal/color'; -import { ValueOf } from 'components/kit/internal/types'; - -const STRONG_WEAK_DELTA = 45; - -const generateStrongWeak = (theme: Theme): Theme => { - const rgbaStrong = str2rgba(theme.strong); - const rgbaWeak = str2rgba(theme.weak); - - for (const [key, value] of Object.entries(theme)) { - const matches = key.match(/^(.+)(Strong|Weak)$/); - if (matches?.length === 3 && value === undefined) { - const isStrong = matches[2] === 'Strong'; - const baseKey = matches[1] as keyof Theme; - const baseValue = theme[baseKey]; - if (baseValue && isColor(baseValue)) { - const rgba = str2rgba(baseValue); - const mixer = isStrong ? rgbaStrong : rgbaWeak; - theme[key as keyof Theme] = rgba2str(rgbaMix(rgba, mixer, STRONG_WEAK_DELTA)); - } - } - } - - return theme as Theme; -}; - -const themeBase = { - // Color schemes - colorScheme: 'normal', - - // Font styles. - fontFamily: 'Inter, Arial, Helvetica, sans-serif', - fontFamilyVar: '"Inter var", Arial, Helvetica, sans-serif', - fontFamilyCode: '"Source Code Pro", monospace', - - // Palette colors for strong/weak calculations. - strong: undefined, - weak: undefined, - - // Brand colors. - brand: 'rgba(247, 123, 33, 1.0)', - brandStrong: undefined, - brandWeak: undefined, - - // Area and surface styles. - background: undefined, - backgroundStrong: undefined, - backgroundWeak: undefined, - backgroundOn: undefined, - backgroundOnStrong: undefined, - backgroundOnWeak: undefined, - backgroundBorder: undefined, - backgroundBorderStrong: undefined, - backgroundBorderWeak: undefined, - stage: undefined, - stageStrong: undefined, - stageWeak: undefined, - stageOn: undefined, - stageOnStrong: undefined, - stageOnWeak: undefined, - stageBorder: undefined, - stageBorderStrong: undefined, - stageBorderWeak: undefined, - surface: undefined, - surfaceStrong: undefined, - surfaceWeak: undefined, - surfaceOn: undefined, - surfaceOnStrong: undefined, - surfaceOnWeak: undefined, - surfaceBorder: undefined, - surfaceBorderStrong: undefined, - surfaceBorderWeak: undefined, - float: undefined, - floatStrong: undefined, - floatWeak: undefined, - floatOn: undefined, - floatOnStrong: undefined, - floatOnWeak: undefined, - floatBorder: undefined, - floatBorderStrong: undefined, - floatBorderWeak: undefined, - - // Interactive styles. - ix: undefined, - ixStrong: undefined, - ixWeak: undefined, - ixActive: undefined, - ixInactive: undefined, - ixOn: undefined, - ixOnStrong: undefined, - ixOnWeak: undefined, - ixOnActive: undefined, - ixOnInactive: undefined, - ixBorder: undefined, - ixBorderStrong: undefined, - ixBorderWeak: undefined, - ixBorderActive: undefined, - ixBorderInactive: undefined, - - // Specialized and unique styles. - density: '2', - targetFocus: '0px 0px 4px rgba(0, 155, 222, 0.12)', - borderRadius: '4px', - borderRadiusStrong: '8px', - borderRadiusWeak: '2px', - strokeWidth: '1px', - strokeWidthStrong: '3px', - strokeWidthWeak: '0.5px', - elevation: undefined, - elevationStrong: undefined, - elevationWeak: undefined, - overlay: undefined, - overlayStrong: undefined, - overlayWeak: undefined, - - // Status styles. - statusActive: 'rgba(0, 155, 222, 1.0)', - statusActiveStrong: undefined, - statusActiveWeak: undefined, - statusActiveOn: 'rgba(255, 255, 255, 1.0)', - statusActiveOnStrong: undefined, - statusActiveOnWeak: undefined, - statusCritical: 'rgba(204, 0, 0, 1.0)', - statusCriticalStrong: undefined, - statusCriticalWeak: undefined, - statusCriticalOn: 'rgba(255, 255, 255, 1.0)', - statusCriticalOnStrong: undefined, - statusCriticalOnWeak: undefined, - statusError: 'rgb(247, 140, 140)', - statusInactive: 'rgba(102, 102, 102, 1.0)', - statusInactiveStrong: undefined, - statusInactiveWeak: undefined, - statusInactiveOn: 'rgba(255, 255, 255, 1.0)', - statusInactiveOnStrong: undefined, - statusInactiveOnWeak: undefined, - statusPending: 'rgba(102, 102, 204, 1.0)', - statusPendingStrong: undefined, - statusPendingWeak: undefined, - statusPendingOn: 'rgba(255, 255, 255, 1.0)', - statusPendingOnStrong: undefined, - statusPendingOnWeak: undefined, - statusPotential: 'rgba(255, 255, 255, 0)', - statusSuccess: 'rgba(0, 153, 0, 1.0)', - statusSuccessStrong: undefined, - statusSuccessWeak: undefined, - statusSuccessOn: 'rgba(255, 255, 255, 1.0)', - statusSuccessOnStrong: undefined, - statusSuccessOnWeak: undefined, - statusWarning: 'rgba(204, 153, 0, 1.0)', - statusWarningStrong: undefined, - statusWarningWeak: undefined, - statusWarningOn: 'rgba(255, 255, 255, 1.0)', - statusWarningOnStrong: undefined, - statusWarningOnWeak: undefined, -}; - -const themeLight = { - // Color schemes - colorScheme: 'light', - - // Palette colors for strong/weak calculations. - strong: 'rgba(0, 0, 0, 1.0)', - weak: 'rgba(255, 255, 255, 1.0)', - - // Area and surface styles. - background: 'rgba(240, 240, 240, 1.0)', - backgroundOn: 'rgba(18, 18, 18, 1.0)', - backgroundBorder: undefined, - stage: 'rgba(246, 246, 246, 1.0)', - stageOn: 'rgba(69, 69, 69, 1.0)', - stageBorder: 'rgba(194, 194, 194, 1.0)', - surface: 'rgba(250, 250, 250, 1.0)', - surfaceOn: 'rgba(0, 8, 16, 1.0)', - surfaceBorder: 'rgba(212, 212, 212, 1.0)', - float: 'rgba(255, 255, 255, 1.0)', - floatOn: 'rgba(49, 49, 49, 1.0)', - floatBorder: 'rgba(225, 225, 225, 1.0)', - - // Interactive styles. - ix: 'rgba(255, 255, 255, 1.0)', - ixActive: 'rgba(231, 247, 255, 1.0)', - ixInactive: 'rgba(245, 245, 245, 1.0)', - ixOn: 'rgba(38, 38, 38, 1.0)', - ixOnActive: 'rgba(0, 155, 222, 1.0)', - ixOnInactive: 'rgba(217, 217, 217, 1.0)', - ixBorder: 'rgba(217, 217, 217, 1.0)', - ixBorderActive: 'rgba(0, 155, 222, 1.0)', - ixBorderInactive: 'rgba(217, 217, 217, 1.0)', - ixCancel: 'rgba(89,89,89,1)', - - // Specialized and unique styles. - overlay: 'rgba(255, 255, 255, 0.75)', - overlayStrong: 'rgba(255, 255, 255, 1.0)', - overlayWeak: 'rgba(255, 255, 255, 0.5)', - elevation: '0px 6px 12px rgba(0, 0, 0, 0.12)', - elevationStrong: '0px 12px 24px rgba(0, 0, 0, 0.12)', - elevationWeak: '0px 2px 4px rgba(0, 0, 0, 0.24)', -}; - -const themeDark = { - // Color schemes - colorScheme: 'dark', - - // Palette colors for strong/weak calculations. - strong: 'rgba(255, 255, 255, 1.0)', - weak: 'rgba(0, 0, 0, 1.0)', - - // Area and surface styles. - background: 'rgba(21, 21, 23, 1.0)', - backgroundOn: 'rgba(237, 237, 237, 1.0)', - backgroundBorder: undefined, - stage: 'rgba(35, 36, 38, 1.0)', - stageOn: 'rgba(186, 186, 186, 1.0)', - stageBorder: 'rgba(61, 61, 61, 1.0)', - surface: 'rgba(48, 49, 50, 1.0)', - surfaceOn: 'rgba(255, 247, 239, 1.0)', - surfaceBorder: 'rgba(85, 85, 85, 1.0)', - float: 'rgba(60, 61, 62, 1.0)', - floatOn: 'rgba(206, 206, 206, 1.0)', - floatBorder: 'rgba(90, 91, 92, 1.0)', - - // Interactive styles. - ix: 'rgba(21, 21, 23, 1.0)', - ixActive: 'rgba(17, 27, 38, 1.0)', - ixInactive: 'rgba(49, 49, 49, 1.0)', - ixOn: 'rgba(209, 209, 209, 1.0)', - ixOnActive: 'rgba(23, 125, 220, 1.0)', - ixOnInactive: 'rgba(80, 80, 80, 1.0)', - ixBorder: 'rgba(67, 67, 67, 1.0)', - ixBorderActive: 'rgba(23, 125, 220, 1.0)', - ixBorderInactive: 'rgba(80, 80, 80, 1.0)', - ixCancel: 'rgba(115,115,115,1)', - - // Specialized and unique styles. - overlay: 'rgba(0, 0, 0, 0.75)', - overlayStrong: 'rgba(0, 0, 0, 1.0)', - overlayWeak: 'rgba(0, 0, 0, 0.5)', - elevation: '0px 6px 12px rgba(255, 255, 255, 0.06)', - elevationStrong: '0px 12px 24px rgba(255, 255, 255, 0.06)', - elevationWeak: '0px 2px 4px rgba(255, 255, 255, 0.12)', -}; - -export const themeLightDetermined: Theme = generateStrongWeak( - Object.assign({}, themeBase, themeLight), -); -export const themeDarkDetermined: Theme = generateStrongWeak( - Object.assign({}, themeBase, themeDark), -); -const themeHpe = { brand: 'rgba(1, 169, 130, 1.0)' }; - -export const themeLightHpe: Theme = generateStrongWeak( - Object.assign({}, themeBase, themeLight, themeHpe), -); -export const themeDarkHpe: Theme = generateStrongWeak( - Object.assign({}, themeBase, themeDark, themeHpe), -); - -export type Theme = Record; - -export const globalCssVars = { - animationCurve: '0.2s cubic-bezier(0.785, 0.135, 0.15, 0.86)', - - iconBig: '28px', - iconEnormous: '40px', - iconGiant: '44px', - iconGreat: '32px', - iconHuge: '36px', - iconJumbo: '48px', - iconLarge: '24px', - iconMedium: '20px', - iconMega: '52px', - iconSmall: '16px', - iconTiny: '12px', - - navBottomBarHeight: '56px', - navSideBarWidthMax: '240px', - navSideBarWidthMin: '56px', -}; - -export const Mode = { - System: 'system', - Light: 'light', - Dark: 'dark', -} as const; - -export type Mode = ValueOf; - -/** - * DarkLight is a resolved form of `Mode` where we figure out - * what `Mode.System` should ultimate resolve to (`Dark` vs `Light). - */ -export const DarkLight = { - Dark: 'dark', - Light: 'light', -} as const; - -export type DarkLight = ValueOf; - -export const getCssVar = (name: string): string => { - const varName = name.replace(/^(var\()?(.*?)\)?$/i, '$2'); - return window.getComputedStyle(document.body)?.getPropertyValue(varName); -}; diff --git a/webui/react/src/components/kit/Theme/themes.ts b/webui/react/src/components/kit/Theme/themes.ts deleted file mode 100644 index d39267fbde2..00000000000 --- a/webui/react/src/components/kit/Theme/themes.ts +++ /dev/null @@ -1,108 +0,0 @@ -/* eslint-disable sort-keys-fix/sort-keys-fix */ -import { - BrandingType, - CheckpointState, - CommandState, - JobState, - ResourceState, - RunState, - SlotState, - ValueOf, - WorkspaceState, -} from 'components/kit/internal/types'; - -import { - DarkLight, - getCssVar, - themeDarkDetermined, - themeDarkHpe, - themeLightDetermined, - themeLightHpe, -} from './themeUtils'; - -/* - * Where did we get our sizes from? - * https://www.quora.com/What-is-the-difference-among-big-large-huge-enormous-and-giant - */ -export const ShirtSize = { - Small: 'small', - Medium: 'medium', - Large: 'large', -} as const; - -export type ShirtSize = ValueOf; - -const stateColorMapping = { - [RunState.Active]: 'active', - [RunState.Canceled]: 'inactive', - [RunState.Completed]: 'success', - [RunState.Deleted]: 'critical', - [RunState.Deleting]: 'critical', - [RunState.DeleteFailed]: 'critical', - [RunState.Error]: 'critical', - [RunState.Paused]: 'warning', - [RunState.StoppingCanceled]: 'inactive', - [RunState.StoppingCompleted]: 'success', - [RunState.StoppingError]: 'critical', - [RunState.StoppingKilled]: 'killed', - [CheckpointState.PartiallyDeleted]: 'warning', - [RunState.Unspecified]: 'inactive', - [RunState.Queued]: 'warning', - [RunState.Pulling]: 'pending', - [RunState.Starting]: 'pending', - [RunState.Running]: 'active', - [CommandState.Waiting]: 'inactive', - [CommandState.Pulling]: 'active', - [CommandState.Starting]: 'active', - [CommandState.Running]: 'active', - [CommandState.Terminating]: 'inactive', - [CommandState.Terminated]: 'inactive', - [ResourceState.Unspecified]: 'inactive', - [ResourceState.Running]: 'active', - [ResourceState.Assigned]: 'pending', - [ResourceState.Pulling]: 'pending', - [ResourceState.Starting]: 'pending', - [ResourceState.Warm]: 'free', - [SlotState.Free]: 'free', - [SlotState.Pending]: 'pending', - [SlotState.Running]: 'active', - [SlotState.Potential]: 'potential', - [JobState.SCHEDULED]: 'active', - [JobState.SCHEDULEDBACKFILLED]: 'active', - [JobState.QUEUED]: 'warning', - [JobState.UNSPECIFIED]: 'inactive', -}; - -export type StateOfUnion = - | RunState - | CommandState - | ResourceState - | CheckpointState - | SlotState - | JobState - | WorkspaceState; - -export const getStateColorCssVar = ( - state: StateOfUnion | undefined, - options: { isOn?: boolean; strongWeak?: 'strong' | 'weak' } = {}, -): string => { - const name = state ? stateColorMapping[state] : 'active'; - const on = options.isOn ? '-on' : ''; - const strongWeak = options.strongWeak ? `-${options.strongWeak}` : ''; - return `var(--theme-status-${name}${on}${strongWeak})`; -}; - -export const getStateColor = (state: StateOfUnion | undefined): string => { - return getCssVar(getStateColorCssVar(state)); -}; - -export const themes = { - [BrandingType.Determined]: { - [DarkLight.Dark]: themeDarkDetermined, - [DarkLight.Light]: themeLightDetermined, - }, - [BrandingType.HPE]: { - [DarkLight.Dark]: themeDarkHpe, - [DarkLight.Light]: themeLightHpe, - }, -}; diff --git a/webui/react/src/components/kit/Theme/themesUtils.test.ts b/webui/react/src/components/kit/Theme/themesUtils.test.ts deleted file mode 100644 index d10486a20d8..00000000000 --- a/webui/react/src/components/kit/Theme/themesUtils.test.ts +++ /dev/null @@ -1,110 +0,0 @@ -import { isColor, labDistance, rgb2lab, str2rgba } from 'components/kit/internal/color'; - -import * as themes from './themeUtils'; - -const supportedThemes = { - darkDet: themes.themeDarkDetermined, - darkHpe: themes.themeDarkHpe, - lightDet: themes.themeLightDetermined, - lightHpe: themes.themeLightHpe, -}; - -/** a pair of theme color variable names that are likely to show up next to each other */ -type ThemeVarPair = (keyof themes.Theme)[]; - -const genPairs = (name: string, incl_weak = false) => { - const base = [ - [`${name}`, `${name}On`], - [`${name}`, `${name}Border`], - ] as ThemeVarPair[]; - - // same intentsity pairs. - const strong = [...base.map(([a, b]) => [`${a}Strong`, `${b}Strong`])] as ThemeVarPair[]; - const weak = [...base.map(([a, b]) => [`${a}Weak`, `${b}Weak`])] as ThemeVarPair[]; - - // stronger color on top of weaker color. - const strongOnDefault = [...base.map(([a, b]) => [`${a}`, `${b}Strong`])] as ThemeVarPair[]; - const defaultOnWeak = [...base.map(([a, b]) => [`${a}Weak`, `${b}`])] as ThemeVarPair[]; - - // weak colors on top of strong colors. - const weakOnDefault = [...base.map(([a, b]) => [`${a}`, `${b}Weak`])] as ThemeVarPair[]; - const defaultOnStrong = [...base.map(([a, b]) => [`${a}Strong`, `${b}`])] as ThemeVarPair[]; - - const pairs = [...base, ...strong, ...weak, ...strongOnDefault, ...defaultOnWeak]; - - if (incl_weak) { - pairs.push(...weakOnDefault, ...defaultOnStrong); - } - - return pairs; -}; - -/** - * - * @param pairs - * @param tolerance defines the required minimum distance between at least one of the rgba values. - * @returns - */ -const findViolators = (pairs: ThemeVarPair[], tolerance: number): string[] => { - const violators: (string | number)[][] = []; - Object.entries(supportedThemes).forEach(([name, theme]) => { - pairs.forEach(([k1, k2]) => { - expect(theme[k1]).toBeDefined(); - expect(theme[k2]).toBeDefined(); - expect(isColor(theme[k1])).toBe(true); - expect(isColor(theme[k2])).toBe(true); - const c1 = str2rgba(theme[k1] as string); - const c2 = str2rgba(theme[k2] as string); - const c1CL = rgb2lab(c1); - const c2CL = rgb2lab(c2); - const distance = labDistance(c1CL, c2CL); - if (distance < tolerance) { - violators.push([`Theme: ${name} - ${k1} ${k2}`, distance]); - } - }); - }); - // sort violators by distance. - const reports = violators - .sort((a, b) => (a[1] as number) - (b[1] as number)) - .map(([name, distance]) => `${name} - ${distance}`); - return reports; -}; - -describe('themes', () => { - /** pars of theme colors used next to eachother */ - const customPairs: ThemeVarPair[] = [ - ['ixActive', 'ixOnActive'], - ['ixActive', 'ixBorderActive'], - ['ixInactive', 'ixOnInactive'], - ['ixInactive', 'ixBorderInactive'], - ['background', 'backgroundOn'], - ]; - - const basePairs = ['surface', 'stage', 'float']; - - it('should have sufficient distance between adjacent colors', () => { - /** defines the required minimum distance between at least one of the rgba values. */ - const TOLERANCE = 4.1; - const violators = findViolators( - [ - ...customPairs, - ...basePairs.map((name) => genPairs(name, false)).reduce((acc, cur) => acc.concat(cur), []), - ], - TOLERANCE, - ); - expect(violators).toEqual([]); - }); - - it('should have sufficient distance between adjacent colors - weak combinations', () => { - /** defines the required minimum distance between at least one of the rgba values. */ - const TOLERANCE = 1.9; - const violators = findViolators( - [ - ...customPairs, - ...basePairs.map((name) => genPairs(name, true)).reduce((acc, cur) => acc.concat(cur), []), - ], - TOLERANCE, - ); - expect(violators).toEqual([]); - }); -}); diff --git a/webui/react/src/components/kit/Toast.module.scss b/webui/react/src/components/kit/Toast.module.scss deleted file mode 100644 index 505f34edbc6..00000000000 --- a/webui/react/src/components/kit/Toast.module.scss +++ /dev/null @@ -1,25 +0,0 @@ -.message { - display: flex; - - span { - margin-right: 4px; - } - :global { - .icon-error { - color: var(--theme-status-critical); - font-weight: bold; - } - .icon-warning { - color: var(--theme-status-warning); - font-weight: bold; - } - .icon-info { - color: var(--theme-status-active); - font-weight: bold; - } - .icon-checkmark { - color: var(--theme-status-success); - font-weight: bold; - } - } -} diff --git a/webui/react/src/components/kit/Toast.tsx b/webui/react/src/components/kit/Toast.tsx deleted file mode 100644 index cf0d118d332..00000000000 --- a/webui/react/src/components/kit/Toast.tsx +++ /dev/null @@ -1,74 +0,0 @@ -import { notification as antdNotification, App } from 'antd'; -import { useAppProps } from 'antd/es/app/context'; -import React, { useEffect } from 'react'; - -import Icon, { IconName } from './Icon'; -import css from './Toast.module.scss'; - -/** - * Wrapper for static dialog functionality from antd. Regular static instances - * are not responsive to the theming context, and will appear with the default - * styling, so we use the app context from antd which hooks into the context. - * This requires our code to call the `App.useApp` hook somewhere, so we do that - * in the AppView. We fall back to the vanilla static methods so testing - * functionality isn't broken. - */ - -let notification: useAppProps['notification'] = antdNotification; - -export const useInitApi = (): void => { - const api = App.useApp(); - // minimize reassignments - useEffect(() => { - ({ notification } = api); - }, [api]); -}; - -export { notification }; - -export type Severity = 'Info' | 'Confirm' | 'Warning' | 'Error'; - -export type ToastArgs = { - title: string; - severity?: Severity; - description?: string; - link?: React.ReactNode; - closeable?: boolean; - duration?: number; -}; - -const getIconName = (s: Severity): IconName => { - if (s === 'Confirm') return 'checkmark'; - return s.toLowerCase() as IconName; -}; - -export const makeToast = ({ - title, - severity = 'Info', - closeable = true, - duration = 4.5, - description, - link, -}: ToastArgs): void => { - const args = { - closeIcon: closeable ? : null, - description: description ? ( - link ? ( -
    -

    {description}

    - {link} -
    - ) : ( - description - ) - ) : undefined, - duration, - message: ( -
    - - {title} -
    - ), - }; - notification.open(args); -}; diff --git a/webui/react/src/components/kit/Toggle.tsx b/webui/react/src/components/kit/Toggle.tsx deleted file mode 100644 index ef4f16b6326..00000000000 --- a/webui/react/src/components/kit/Toggle.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { Space, Switch } from 'antd'; -import React, { useCallback } from 'react'; - -import Label from 'components/kit/internal/Label'; - -interface Props { - checked?: boolean; - label?: string; - onChange?: (checked: boolean) => void; -} - -const Toggle: React.FC = ({ checked = false, label, onChange }: Props) => { - const handleClick = useCallback(() => { - if (onChange) onChange(!checked); - }, [checked, onChange]); - - return ( - - {label && } - - - ); -}; - -export default Toggle; diff --git a/webui/react/src/components/kit/Tooltip.tsx b/webui/react/src/components/kit/Tooltip.tsx deleted file mode 100644 index 9a50aab9d8a..00000000000 --- a/webui/react/src/components/kit/Tooltip.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { Tooltip as AntdTooltip } from 'antd'; -import React, { ReactNode } from 'react'; - -export type Placement = - | 'top' - | 'left' - | 'right' - | 'bottom' - | 'topLeft' - | 'topRight' - | 'bottomLeft' - | 'bottomRight' - | 'leftTop' - | 'leftBottom' - | 'rightTop' - | 'rightBottom'; - -export interface TooltipProps { - children?: ReactNode; - content?: ReactNode; - mouseEnterDelay?: number; - open?: boolean; - placement?: Placement; - trigger?: 'hover' | 'focus' | 'click' | 'contextMenu' | Array; - showArrow?: boolean; -} - -const Tooltip: React.FC = ({ - content, - mouseEnterDelay, - open, - placement = 'top', - ...props -}: TooltipProps) => { - return ( - - ); -}; - -export default Tooltip; diff --git a/webui/react/src/components/kit/Typography/Header.tsx b/webui/react/src/components/kit/Typography/Header.tsx deleted file mode 100644 index 14d54f2883f..00000000000 --- a/webui/react/src/components/kit/Typography/Header.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import React from 'react'; - -import { TypographySize } from 'components/kit/internal/fonts'; - -import css from './index.module.scss'; -interface Props { - size?: TypographySize; -} - -const Header: React.FC> = ({ children, size }) => { - const getThemeClass = () => { - if (!size) return ''; - - if (size === TypographySize.XL) return css.headerXL; - if (size === TypographySize.L) return css.headerL; - if (size === TypographySize.default) return css.headerDefault; - if (size === TypographySize.S) return css.headerS; - - return css.headerXS; - }; - - const classes = [css.header, getThemeClass()]; - - return

    {children}

    ; -}; - -export default Header; diff --git a/webui/react/src/components/kit/Typography/Paragraph.tsx b/webui/react/src/components/kit/Typography/Paragraph.tsx deleted file mode 100644 index 53d8e7fee11..00000000000 --- a/webui/react/src/components/kit/Typography/Paragraph.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import React from 'react'; - -import { ThemeFont, TypographySize } from 'components/kit/internal/fonts'; - -import css from './index.module.scss'; - -interface Props { - size?: TypographySize; - type?: 'single line' | 'multi line'; - font?: 'code' | 'ui'; -} - -const Paragraph: React.FC> = ({ - children, - font = 'ui', - size, - type = 'single line', -}) => { - const getThemeClass = () => { - if (!size) return ''; - - const lineType = type.replace(' line', ''); - - if (size === TypographySize.XL) return css[`${lineType}LineXL`]; - if (size === TypographySize.L) return css[`${lineType}LineL`]; - if (size === TypographySize.default) return css[`${lineType}LineDefault`]; - if (size === TypographySize.S) return css[`${lineType}LineS`]; - - return css[`${lineType}LineXS`]; - }; - - return ( -

    - {children} -

    - ); -}; - -export default Paragraph; diff --git a/webui/react/src/components/kit/Typography/index.module.scss b/webui/react/src/components/kit/Typography/index.module.scss deleted file mode 100644 index c322849aa00..00000000000 --- a/webui/react/src/components/kit/Typography/index.module.scss +++ /dev/null @@ -1,160 +0,0 @@ -/* stylelint-disable custom-property-pattern */ - -:root { - /* font-size */ - --header-size-xl: 28px; - - /* line-height */ - --header-ln-xl: 36px; - - /* font-size */ - --header-size-l: 24px; - - /* line-height */ - --header-ln-l: 32px; - - /* font-size */ - --header-size-default: 22px; - - /* line-height */ - --header-ln-default: 28px; - - /* font-size */ - --header-size-s: 18px; - - /* line-height */ - --header-ln-s: 23px; - - /* font-size */ - --header-size-xs: 16px; - - /* line-height */ - --header-ln-xs: 21px; - - /* font-size */ - --multi-line-size-xl: 16px; - - /* line-height */ - --multi-line-ln-xl: 26px; - - /* font-size */ - --multi-line-size-l: 14px; - - /* line-height */ - --multi-line-ln-l: 22px; - - /* font-size */ - --multi-line-size-default: 12px; - - /* line-height */ - --multi-line-ln-default: 20px; - - /* font-size */ - --multi-line-size-s: 11px; - - /* line-height */ - --multi-line-ln-s: 18px; - - /* font-size */ - --multi-line-size-xs: 10px; - - /* line-height */ - --multi-line-ln-xs: 16px; - - /* font-size */ - --single-line-size-xl: 16px; - - /* line-height */ - --single-line-ln-xl: 20px; - - /* font-size */ - --single-line-size-l: 14px; - - /* line-height */ - --single-line-ln-l: 18px; - - /* font-size */ - --single-line-size-default: 12px; - - /* line-height */ - --single-line-ln-default: 16px; - - /* font-size */ - --single-line-size-s: 11px; - - /* line-height */ - --single-line-ln-s: 14px; - - /* font-size */ - --single-line-size-xs: 10px; - - /* line-height */ - --single-line-ln-xs: 12px; -} -.header { - color: var(--theme-colors-monochrome-3); - font-size: 16px; - font-weight: 400; - font-weight: 500; - line-height: 32px; -} -.headerXL { - font-size: var(--header-size-xl); - line-height: var(--header-ln-xl); -} -.headerL { - font-size: var(--header-size-l); - line-height: var(--header-ln-l); -} -.headerDefault { - font-size: var(--header-size-default); - line-height: var(--header-ln-default); -} -.headerS { - font-size: var(--header-size-s); - line-height: var(--header-ln-s); -} -.headerXS { - font-size: var(--header-size-xs); - line-height: var(--header-ln-xs); -} -.multiLineXL { - font-size: var(--multi-line-size-xl); - line-height: var(--multi-line-ln-xl); -} -.multiLineL { - font-size: var(--multi-line-size-l); - line-height: var(--multi-line-ln-l); -} -.multiLineDefault { - font-size: var(--multi-line-size-default); - line-height: var(--multi-line-ln-default); -} -.multiLineS { - font-size: var(--single-line-size-s); - line-height: var(--single-line-ln-s); -} -.multiLineXS { - font-size: var(--single-line-size-xs); - line-height: var(--single-line-ln-xs); -} -.singleLineXL { - font-size: var(--single-line-size-xl); - line-height: var(--single-line-ln-xl); -} -.singleLineL { - font-size: var(--single-line-size-l); - line-height: var(--single-line-ln-l); -} -.singleLineDefault { - font-size: var(--single-line-size-default); - line-height: var(--single-line-ln-default); -} -.singleLineS { - font-size: var(--single-line-size-s); - line-height: var(--single-line-ln-s); -} -.singleLineXS { - font-size: var(--single-line-size-xs); - line-height: var(--single-line-ln-xs); -} diff --git a/webui/react/src/components/kit/icons/add.svg b/webui/react/src/components/kit/icons/add.svg deleted file mode 100644 index 5155bd8ce2b..00000000000 --- a/webui/react/src/components/kit/icons/add.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/archive.svg b/webui/react/src/components/kit/icons/archive.svg deleted file mode 100644 index abf42ce45ab..00000000000 --- a/webui/react/src/components/kit/icons/archive.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/arrow-down.svg b/webui/react/src/components/kit/icons/arrow-down.svg deleted file mode 100644 index 756b64afdbd..00000000000 --- a/webui/react/src/components/kit/icons/arrow-down.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/arrow-left.svg b/webui/react/src/components/kit/icons/arrow-left.svg deleted file mode 100644 index d629a41aebc..00000000000 --- a/webui/react/src/components/kit/icons/arrow-left.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/arrow-right.svg b/webui/react/src/components/kit/icons/arrow-right.svg deleted file mode 100644 index 7f3b706819a..00000000000 --- a/webui/react/src/components/kit/icons/arrow-right.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/arrow-up.svg b/webui/react/src/components/kit/icons/arrow-up.svg deleted file mode 100644 index b00f1f80903..00000000000 --- a/webui/react/src/components/kit/icons/arrow-up.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/cancelled.svg b/webui/react/src/components/kit/icons/cancelled.svg deleted file mode 100644 index d07b0464b73..00000000000 --- a/webui/react/src/components/kit/icons/cancelled.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/checkmark.svg b/webui/react/src/components/kit/icons/checkmark.svg deleted file mode 100644 index 8370910197e..00000000000 --- a/webui/react/src/components/kit/icons/checkmark.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/checkpoint.svg b/webui/react/src/components/kit/icons/checkpoint.svg deleted file mode 100644 index 5f4441d2602..00000000000 --- a/webui/react/src/components/kit/icons/checkpoint.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/clipboard.svg b/webui/react/src/components/kit/icons/clipboard.svg deleted file mode 100644 index 3041eb3bc29..00000000000 --- a/webui/react/src/components/kit/icons/clipboard.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/close.svg b/webui/react/src/components/kit/icons/close.svg deleted file mode 100644 index a1a0bf5dc59..00000000000 --- a/webui/react/src/components/kit/icons/close.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/cloud.svg b/webui/react/src/components/kit/icons/cloud.svg deleted file mode 100644 index 04144361306..00000000000 --- a/webui/react/src/components/kit/icons/cloud.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/cluster.svg b/webui/react/src/components/kit/icons/cluster.svg deleted file mode 100644 index 299fc810438..00000000000 --- a/webui/react/src/components/kit/icons/cluster.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/collapse.svg b/webui/react/src/components/kit/icons/collapse.svg deleted file mode 100644 index 566325aa066..00000000000 --- a/webui/react/src/components/kit/icons/collapse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/columns.svg b/webui/react/src/components/kit/icons/columns.svg deleted file mode 100644 index 49e6af4496f..00000000000 --- a/webui/react/src/components/kit/icons/columns.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - diff --git a/webui/react/src/components/kit/icons/command.svg b/webui/react/src/components/kit/icons/command.svg deleted file mode 100644 index f54b4b15842..00000000000 --- a/webui/react/src/components/kit/icons/command.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/dai-logo.svg b/webui/react/src/components/kit/icons/dai-logo.svg deleted file mode 100644 index 9ab94b663d5..00000000000 --- a/webui/react/src/components/kit/icons/dai-logo.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/dashboard.svg b/webui/react/src/components/kit/icons/dashboard.svg deleted file mode 100644 index e2c129e9fc9..00000000000 --- a/webui/react/src/components/kit/icons/dashboard.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/debug.svg b/webui/react/src/components/kit/icons/debug.svg deleted file mode 100644 index b5e7eec7f07..00000000000 --- a/webui/react/src/components/kit/icons/debug.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/docs.svg b/webui/react/src/components/kit/icons/docs.svg deleted file mode 100644 index c08c9931396..00000000000 --- a/webui/react/src/components/kit/icons/docs.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/document.svg b/webui/react/src/components/kit/icons/document.svg deleted file mode 100644 index 143d7a044e4..00000000000 --- a/webui/react/src/components/kit/icons/document.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/download.svg b/webui/react/src/components/kit/icons/download.svg deleted file mode 100644 index 91591519dd4..00000000000 --- a/webui/react/src/components/kit/icons/download.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/error.svg b/webui/react/src/components/kit/icons/error.svg deleted file mode 100644 index 5923a64d734..00000000000 --- a/webui/react/src/components/kit/icons/error.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/expand.svg b/webui/react/src/components/kit/icons/expand.svg deleted file mode 100644 index a8f52e0626d..00000000000 --- a/webui/react/src/components/kit/icons/expand.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/experiment.svg b/webui/react/src/components/kit/icons/experiment.svg deleted file mode 100644 index 0b388666cba..00000000000 --- a/webui/react/src/components/kit/icons/experiment.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/eye-close.svg b/webui/react/src/components/kit/icons/eye-close.svg deleted file mode 100644 index 87d32b3308e..00000000000 --- a/webui/react/src/components/kit/icons/eye-close.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/eye-open.svg b/webui/react/src/components/kit/icons/eye-open.svg deleted file mode 100644 index 29033ae7f45..00000000000 --- a/webui/react/src/components/kit/icons/eye-open.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/filter.svg b/webui/react/src/components/kit/icons/filter.svg deleted file mode 100644 index 95dcfe5f783..00000000000 --- a/webui/react/src/components/kit/icons/filter.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - diff --git a/webui/react/src/components/kit/icons/fork.svg b/webui/react/src/components/kit/icons/fork.svg deleted file mode 100644 index 6e691686848..00000000000 --- a/webui/react/src/components/kit/icons/fork.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/four-squares.svg b/webui/react/src/components/kit/icons/four-squares.svg deleted file mode 100644 index 0684bbaedbb..00000000000 --- a/webui/react/src/components/kit/icons/four-squares.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - diff --git a/webui/react/src/components/kit/icons/fullscreen.svg b/webui/react/src/components/kit/icons/fullscreen.svg deleted file mode 100644 index 155279405c9..00000000000 --- a/webui/react/src/components/kit/icons/fullscreen.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/grid.svg b/webui/react/src/components/kit/icons/grid.svg deleted file mode 100644 index 9b06bed5bac..00000000000 --- a/webui/react/src/components/kit/icons/grid.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/group.svg b/webui/react/src/components/kit/icons/group.svg deleted file mode 100644 index 91cc0496b66..00000000000 --- a/webui/react/src/components/kit/icons/group.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/heat.svg b/webui/react/src/components/kit/icons/heat.svg deleted file mode 100644 index 6ac0124fc84..00000000000 --- a/webui/react/src/components/kit/icons/heat.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/heatmap.svg b/webui/react/src/components/kit/icons/heatmap.svg deleted file mode 100644 index aae0d60e874..00000000000 --- a/webui/react/src/components/kit/icons/heatmap.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - diff --git a/webui/react/src/components/kit/icons/home.svg b/webui/react/src/components/kit/icons/home.svg deleted file mode 100644 index 7cb18b4f461..00000000000 --- a/webui/react/src/components/kit/icons/home.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/info.svg b/webui/react/src/components/kit/icons/info.svg deleted file mode 100644 index fa949d666a2..00000000000 --- a/webui/react/src/components/kit/icons/info.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/jupyter-lab.svg b/webui/react/src/components/kit/icons/jupyter-lab.svg deleted file mode 100644 index ae8e2a7c2df..00000000000 --- a/webui/react/src/components/kit/icons/jupyter-lab.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/learning.svg b/webui/react/src/components/kit/icons/learning.svg deleted file mode 100644 index 473bf367ec3..00000000000 --- a/webui/react/src/components/kit/icons/learning.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/list.svg b/webui/react/src/components/kit/icons/list.svg deleted file mode 100644 index 7f212ed8a1e..00000000000 --- a/webui/react/src/components/kit/icons/list.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/lock.svg b/webui/react/src/components/kit/icons/lock.svg deleted file mode 100644 index a1933504a39..00000000000 --- a/webui/react/src/components/kit/icons/lock.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/logs.svg b/webui/react/src/components/kit/icons/logs.svg deleted file mode 100644 index 3d75b96366f..00000000000 --- a/webui/react/src/components/kit/icons/logs.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/model.svg b/webui/react/src/components/kit/icons/model.svg deleted file mode 100644 index a921ac99572..00000000000 --- a/webui/react/src/components/kit/icons/model.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/notebook.svg b/webui/react/src/components/kit/icons/notebook.svg deleted file mode 100644 index 8e5f734344b..00000000000 --- a/webui/react/src/components/kit/icons/notebook.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/options.svg b/webui/react/src/components/kit/icons/options.svg deleted file mode 100644 index 71a27a6ef30..00000000000 --- a/webui/react/src/components/kit/icons/options.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - diff --git a/webui/react/src/components/kit/icons/overflow-horizontal.svg b/webui/react/src/components/kit/icons/overflow-horizontal.svg deleted file mode 100644 index 80ab67a35cd..00000000000 --- a/webui/react/src/components/kit/icons/overflow-horizontal.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/overflow-vertical.svg b/webui/react/src/components/kit/icons/overflow-vertical.svg deleted file mode 100644 index b9fc07bcc6a..00000000000 --- a/webui/react/src/components/kit/icons/overflow-vertical.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/panel-on.svg b/webui/react/src/components/kit/icons/panel-on.svg deleted file mode 100644 index 75d43b4dc28..00000000000 --- a/webui/react/src/components/kit/icons/panel-on.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - diff --git a/webui/react/src/components/kit/icons/panel.svg b/webui/react/src/components/kit/icons/panel.svg deleted file mode 100644 index 860d21b56ef..00000000000 --- a/webui/react/src/components/kit/icons/panel.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/webui/react/src/components/kit/icons/parcoords.svg b/webui/react/src/components/kit/icons/parcoords.svg deleted file mode 100644 index 572713068eb..00000000000 --- a/webui/react/src/components/kit/icons/parcoords.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/pause.svg b/webui/react/src/components/kit/icons/pause.svg deleted file mode 100644 index 400ad607795..00000000000 --- a/webui/react/src/components/kit/icons/pause.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/pencil.svg b/webui/react/src/components/kit/icons/pencil.svg deleted file mode 100644 index 3e2a23bfb65..00000000000 --- a/webui/react/src/components/kit/icons/pencil.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/pin.svg b/webui/react/src/components/kit/icons/pin.svg deleted file mode 100644 index ab578890000..00000000000 --- a/webui/react/src/components/kit/icons/pin.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/webui/react/src/components/kit/icons/play.svg b/webui/react/src/components/kit/icons/play.svg deleted file mode 100644 index 7ddd627256f..00000000000 --- a/webui/react/src/components/kit/icons/play.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/popout.svg b/webui/react/src/components/kit/icons/popout.svg deleted file mode 100644 index 0428f1f938f..00000000000 --- a/webui/react/src/components/kit/icons/popout.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/power.svg b/webui/react/src/components/kit/icons/power.svg deleted file mode 100644 index 8487bb67c9a..00000000000 --- a/webui/react/src/components/kit/icons/power.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/queue.svg b/webui/react/src/components/kit/icons/queue.svg deleted file mode 100644 index 3c8a52e3d25..00000000000 --- a/webui/react/src/components/kit/icons/queue.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/reset.svg b/webui/react/src/components/kit/icons/reset.svg deleted file mode 100644 index bc04886b532..00000000000 --- a/webui/react/src/components/kit/icons/reset.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/row-extra-large.svg b/webui/react/src/components/kit/icons/row-extra-large.svg deleted file mode 100644 index c102e62f6d5..00000000000 --- a/webui/react/src/components/kit/icons/row-extra-large.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/webui/react/src/components/kit/icons/row-large.svg b/webui/react/src/components/kit/icons/row-large.svg deleted file mode 100644 index a09756c1f21..00000000000 --- a/webui/react/src/components/kit/icons/row-large.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - diff --git a/webui/react/src/components/kit/icons/row-medium.svg b/webui/react/src/components/kit/icons/row-medium.svg deleted file mode 100644 index 2c301a197c3..00000000000 --- a/webui/react/src/components/kit/icons/row-medium.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - diff --git a/webui/react/src/components/kit/icons/row-small.svg b/webui/react/src/components/kit/icons/row-small.svg deleted file mode 100644 index 5b79f2df52a..00000000000 --- a/webui/react/src/components/kit/icons/row-small.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - diff --git a/webui/react/src/components/kit/icons/scatter-plot.svg b/webui/react/src/components/kit/icons/scatter-plot.svg deleted file mode 100644 index 2ff1ec529c0..00000000000 --- a/webui/react/src/components/kit/icons/scatter-plot.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/scroll.svg b/webui/react/src/components/kit/icons/scroll.svg deleted file mode 100644 index 793d6a92a7d..00000000000 --- a/webui/react/src/components/kit/icons/scroll.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/webui/react/src/components/kit/icons/search.svg b/webui/react/src/components/kit/icons/search.svg deleted file mode 100644 index 123636d31f6..00000000000 --- a/webui/react/src/components/kit/icons/search.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/searcher-adaptive.svg b/webui/react/src/components/kit/icons/searcher-adaptive.svg deleted file mode 100644 index 4e8a277bff2..00000000000 --- a/webui/react/src/components/kit/icons/searcher-adaptive.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/searcher-grid.svg b/webui/react/src/components/kit/icons/searcher-grid.svg deleted file mode 100644 index 6aebc8de054..00000000000 --- a/webui/react/src/components/kit/icons/searcher-grid.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/searcher-random.svg b/webui/react/src/components/kit/icons/searcher-random.svg deleted file mode 100644 index c18fe700a48..00000000000 --- a/webui/react/src/components/kit/icons/searcher-random.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/settings.svg b/webui/react/src/components/kit/icons/settings.svg deleted file mode 100644 index 1732e047da0..00000000000 --- a/webui/react/src/components/kit/icons/settings.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/shell.svg b/webui/react/src/components/kit/icons/shell.svg deleted file mode 100644 index 443c093441f..00000000000 --- a/webui/react/src/components/kit/icons/shell.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/spinner.svg b/webui/react/src/components/kit/icons/spinner.svg deleted file mode 100644 index 400aea7702b..00000000000 --- a/webui/react/src/components/kit/icons/spinner.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/star.svg b/webui/react/src/components/kit/icons/star.svg deleted file mode 100644 index 17b0c9f4f97..00000000000 --- a/webui/react/src/components/kit/icons/star.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/stop.svg b/webui/react/src/components/kit/icons/stop.svg deleted file mode 100644 index 396a2d7fcdb..00000000000 --- a/webui/react/src/components/kit/icons/stop.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/tasks.svg b/webui/react/src/components/kit/icons/tasks.svg deleted file mode 100644 index c3678d6cb9b..00000000000 --- a/webui/react/src/components/kit/icons/tasks.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/tensor-board.svg b/webui/react/src/components/kit/icons/tensor-board.svg deleted file mode 100644 index f26d01d44b1..00000000000 --- a/webui/react/src/components/kit/icons/tensor-board.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/tensorboard.svg b/webui/react/src/components/kit/icons/tensorboard.svg deleted file mode 100644 index 5aef3a72c15..00000000000 --- a/webui/react/src/components/kit/icons/tensorboard.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/undo.svg b/webui/react/src/components/kit/icons/undo.svg deleted file mode 100644 index 32fb3611058..00000000000 --- a/webui/react/src/components/kit/icons/undo.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/user.svg b/webui/react/src/components/kit/icons/user.svg deleted file mode 100644 index 397578821c2..00000000000 --- a/webui/react/src/components/kit/icons/user.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/warning.svg b/webui/react/src/components/kit/icons/warning.svg deleted file mode 100644 index 2bbb26d9c02..00000000000 --- a/webui/react/src/components/kit/icons/warning.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/icons/workspaces.svg b/webui/react/src/components/kit/icons/workspaces.svg deleted file mode 100644 index 78761e66130..00000000000 --- a/webui/react/src/components/kit/icons/workspaces.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/webui/react/src/components/kit/internal/CodeMirrorEditor.tsx b/webui/react/src/components/kit/internal/CodeMirrorEditor.tsx deleted file mode 100644 index 11ef6ddc2f0..00000000000 --- a/webui/react/src/components/kit/internal/CodeMirrorEditor.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { markdown, markdownLanguage } from '@codemirror/lang-markdown'; -import { python } from '@codemirror/lang-python'; -import { StreamLanguage } from '@codemirror/language'; -import { yaml } from '@codemirror/legacy-modes/mode/yaml'; -import ReactCodeMirror, { ReactCodeMirrorProps } from '@uiw/react-codemirror'; -import React from 'react'; - -import { DarkLight } from 'components/kit/internal/types'; -import useUI from 'components/kit/Theme'; - -interface Props extends ReactCodeMirrorProps { - syntax: 'python' | 'markdown' | 'yaml'; -} - -const langs = { - markdown: () => markdown({ base: markdownLanguage }), - python, - yaml: () => StreamLanguage.define(yaml), -}; - -const CodeMirrorEditor: React.FC = ({ syntax, ...props }) => { - const { ui } = useUI(); - - return ( - - ); -}; - -export default CodeMirrorEditor; diff --git a/webui/react/src/components/kit/internal/ConditionalWrapper.tsx b/webui/react/src/components/kit/internal/ConditionalWrapper.tsx deleted file mode 100644 index fd3839d0093..00000000000 --- a/webui/react/src/components/kit/internal/ConditionalWrapper.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import React, { ReactElement } from 'react'; - -interface Props { - children: ReactElement; - condition: boolean; - falseWrapper?: (children: ReactElement) => JSX.Element; - wrapper: (children: ReactElement) => JSX.Element; -} - -/* - * Note: If the condition changes and children is a component, - * the child component will go through an unmount and mount. - */ -export const ConditionalWrapper: React.FC = ({ condition, children, ...props }: Props) => { - if (condition) return props.wrapper(children); - if (!condition && props.falseWrapper) return props.falseWrapper(children); - return children; -}; diff --git a/webui/react/src/components/kit/internal/Grid.module.scss b/webui/react/src/components/kit/internal/Grid.module.scss deleted file mode 100644 index 7ac9e7c621d..00000000000 --- a/webui/react/src/components/kit/internal/Grid.module.scss +++ /dev/null @@ -1,18 +0,0 @@ -.base { - display: grid; -} -.border { - grid-gap: 1px; - - & > * { - outline: 1px solid var(--theme-colors-monochrome-12); - position: relative; - z-index: 0; - } -} -.row { - grid-auto-flow: column; - -webkit-overflow-scrolling: touch; - overflow-x: auto; - padding-bottom: 6px; -} diff --git a/webui/react/src/components/kit/internal/Grid.tsx b/webui/react/src/components/kit/internal/Grid.tsx deleted file mode 100644 index 6a9f0585817..00000000000 --- a/webui/react/src/components/kit/internal/Grid.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import React from 'react'; - -import { isNumber } from 'components/kit/internal/functions'; -import { ValueOf } from 'components/kit/internal/types'; -import { ShirtSize } from 'components/kit/Theme'; - -import css from './Grid.module.scss'; - -export const GridMode = { - AutoFill: 'auto-fill', // will squeeze as many items into a given space and minimum size - AutoFit: 'auto-fit', // auto-fill but also stretch to fit the entire available space. - ScrollableRow: 'scrollableRow', -} as const; - -export type GridMode = ValueOf; - -interface Props { - border?: boolean; - children: React.ReactNode; - className?: string; - count?: number; - gap?: ShirtSize | number; - minItemWidth?: number; - mode?: GridMode | number; -} - -const sizeMap = { - [ShirtSize.Small]: '4px', - [ShirtSize.Medium]: '8px', - [ShirtSize.Large]: '16px', -}; - -const Grid: React.FC = ({ - border, - gap = ShirtSize.Medium, - minItemWidth = 240, - mode = GridMode.AutoFit, - children, - className, - count, -}: Props) => { - const style = { - gridGap: isNumber(gap) ? `${gap}px` : `calc(${sizeMap[gap]} + var(--theme-density) * 1px)`, - gridTemplateColumns: '', - }; - const classes = [css.base]; - - if (className) classes.push(className); - if (border) classes.push(css.border); - if (mode === GridMode.AutoFill || GridMode.AutoFit) { - style.gridTemplateColumns = `repeat(${mode}, minmax(${minItemWidth}px, 1fr))`; - } - if (mode === GridMode.ScrollableRow) { - classes.push(css.row); - style.gridTemplateColumns = `repeat(${count}, minmax(${minItemWidth}px, ${minItemWidth}px))`; - } - return ( -
    - {children} -
    - ); -}; - -export default Grid; diff --git a/webui/react/src/components/kit/internal/Image/Image.module.scss b/webui/react/src/components/kit/internal/Image/Image.module.scss deleted file mode 100644 index b12a3ee924e..00000000000 --- a/webui/react/src/components/kit/internal/Image/Image.module.scss +++ /dev/null @@ -1,84 +0,0 @@ -.alert { - .shadow1 { - fill: #f6f6f6; - } - .shadow2 { - fill: #ececec; - } - .shadow3 { - fill: #ddd; - } - .sign { - fill: #fff; - stroke: #ddd; - } - .iDot { - fill: #ddd; - } - .iBar { - fill: #ddd; - } -} -.warning { - .shadow1 { - fill: #f6f6f6; - } - .shadow2 { - fill: #ececec; - } - .shadow3 { - fill: #ddd; - } - .sign { - fill: #fff; - stroke: #ddd; - } - .exclamationDot { - fill: #ddd; - } - .exclamationBar { - fill: #ddd; - } -} -.alert.dark { - .shadow1 { - fill: #222; - } - .shadow2 { - fill: #333; - } - .shadow3 { - fill: #444; - } - .sign { - fill: #333; - stroke: #666; - } - .iDot { - fill: #999; - } - .iBar { - fill: #999; - } -} -.warning.dark { - .shadow1 { - fill: #222; - } - .shadow2 { - fill: #333; - } - .shadow3 { - fill: #444; - } - .sign { - fill: #333; - stroke: #666; - } - .exclamationDot { - fill: #999; - } - .exclamationBar { - fill: #999; - } -} diff --git a/webui/react/src/components/kit/internal/Image/Image.test.tsx b/webui/react/src/components/kit/internal/Image/Image.test.tsx deleted file mode 100644 index e4c9a3edf6f..00000000000 --- a/webui/react/src/components/kit/internal/Image/Image.test.tsx +++ /dev/null @@ -1,123 +0,0 @@ -import { render, screen } from '@testing-library/react'; - -import { DarkLight } from 'components/kit/internal/types'; - -import { ImageAlert, ImageEmpty, ImageWarning, type Props } from './Image'; - -const setupImageAlert = (props?: Props) => { - const view = render(); - return { view }; -}; - -const setupImageEmpty = () => { - const view = render(); - return { view }; -}; - -const setupImageWarning = (props?: Props) => { - const view = render(); - return { view }; -}; - -describe('Image', () => { - describe('ImageAlert', () => { - it('should display ImageAlert with implicit props', () => { - const { view } = setupImageAlert(); - const svg = view.container.querySelector('svg'); - expect(screen.getByTitle('Alert')).toBeInTheDocument(); - expect(view.container.firstChild).toHaveClass('alert'); - expect(view.container.firstChild).not.toHaveClass('dark'); - expect(view.container.firstChild).toHaveAttribute('fill', 'none'); - expect(view.container.firstChild).toHaveAttribute('height', '100'); - expect(view.container.firstChild).toHaveAttribute('width', '100'); - expect(view.container.firstChild).toHaveAttribute('viewBox', '0 0 1024 1024'); - expect(view.container.firstChild).toHaveAttribute('xmlns', 'http://www.w3.org/2000/svg'); - expect(svg).not.toBeEmptyDOMElement(); - }); - - it('should display ImageAlert with explicit props, Light Mode', () => { - const { view } = setupImageAlert({ darkLight: DarkLight.Light }); - const svg = view.container.querySelector('svg'); - expect(screen.getByTitle('Alert')).toBeInTheDocument(); - expect(view.container.firstChild).toHaveClass('alert'); - expect(view.container.firstChild).not.toHaveClass('dark'); - expect(view.container.firstChild).toHaveAttribute('fill', 'none'); - expect(view.container.firstChild).toHaveAttribute('height', '100'); - expect(view.container.firstChild).toHaveAttribute('width', '100'); - expect(view.container.firstChild).toHaveAttribute('viewBox', '0 0 1024 1024'); - expect(view.container.firstChild).toHaveAttribute('xmlns', 'http://www.w3.org/2000/svg'); - expect(svg).not.toBeEmptyDOMElement(); - }); - - it('should display ImageAlert with explicit props, Dark Mode', () => { - const { view } = setupImageAlert({ darkLight: DarkLight.Dark }); - const svg = view.container.querySelector('svg'); - expect(screen.getByTitle('Alert')).toBeInTheDocument(); - expect(view.container.firstChild).toHaveClass(...['alert', 'dark']); - expect(view.container.firstChild).toHaveAttribute('fill', 'none'); - expect(view.container.firstChild).toHaveAttribute('height', '100'); - expect(view.container.firstChild).toHaveAttribute('width', '100'); - expect(view.container.firstChild).toHaveAttribute('viewBox', '0 0 1024 1024'); - expect(view.container.firstChild).toHaveAttribute('xmlns', 'http://www.w3.org/2000/svg'); - expect(svg).not.toBeEmptyDOMElement(); - }); - }); - - describe('ImageEmpty', () => { - it('should display ImageEmpty with implicit props', () => { - const { view } = setupImageEmpty(); - const svg = view.container.querySelector('svg'); - expect(screen.getByTitle('Empty')).toBeInTheDocument(); - expect(view.container.firstChild).toHaveClass(...['ant-empty-img-simple']); - expect(view.container.firstChild).not.toHaveAttribute('fill', 'none'); - expect(view.container.firstChild).toHaveAttribute('height', '100'); - expect(view.container.firstChild).toHaveAttribute('width', '100'); - expect(view.container.firstChild).toHaveAttribute('viewBox', '-8 -5 80 51'); - expect(view.container.firstChild).toHaveAttribute('xmlns', 'http://www.w3.org/2000/svg'); - expect(svg).not.toBeEmptyDOMElement(); - }); - }); - - describe('ImageWarning', () => { - it('should display ImageWarning with implicit props', () => { - const { view } = setupImageWarning(); - const svg = view.container.querySelector('svg'); - expect(screen.getByTitle('Warning')).toBeInTheDocument(); - expect(view.container.firstChild).toHaveClass('warning'); - expect(view.container.firstChild).not.toHaveClass('dark'); - expect(view.container.firstChild).toHaveAttribute('fill', 'none'); - expect(view.container.firstChild).toHaveAttribute('height', '100'); - expect(view.container.firstChild).toHaveAttribute('width', '100'); - expect(view.container.firstChild).toHaveAttribute('viewBox', '0 0 1024 1024'); - expect(view.container.firstChild).toHaveAttribute('xmlns', 'http://www.w3.org/2000/svg'); - expect(svg).not.toBeEmptyDOMElement(); - }); - - it('should display ImageWarning with explicit props, Light Mode', () => { - const { view } = setupImageWarning({ darkLight: DarkLight.Light }); - const svg = view.container.querySelector('svg'); - expect(screen.getByTitle('Warning')).toBeInTheDocument(); - expect(view.container.firstChild).toHaveClass('warning'); - expect(view.container.firstChild).not.toHaveClass('dark'); - expect(view.container.firstChild).toHaveAttribute('fill', 'none'); - expect(view.container.firstChild).toHaveAttribute('height', '100'); - expect(view.container.firstChild).toHaveAttribute('width', '100'); - expect(view.container.firstChild).toHaveAttribute('viewBox', '0 0 1024 1024'); - expect(view.container.firstChild).toHaveAttribute('xmlns', 'http://www.w3.org/2000/svg'); - expect(svg).not.toBeEmptyDOMElement(); - }); - - it('should display ImageWarning with explicit props, Dark Mode', () => { - const { view } = setupImageWarning({ darkLight: DarkLight.Dark }); - const svg = view.container.querySelector('svg'); - expect(screen.getByTitle('Warning')).toBeInTheDocument(); - expect(view.container.firstChild).toHaveClass(...['warning', 'dark']); - expect(view.container.firstChild).toHaveAttribute('fill', 'none'); - expect(view.container.firstChild).toHaveAttribute('height', '100'); - expect(view.container.firstChild).toHaveAttribute('width', '100'); - expect(view.container.firstChild).toHaveAttribute('viewBox', '0 0 1024 1024'); - expect(view.container.firstChild).toHaveAttribute('xmlns', 'http://www.w3.org/2000/svg'); - expect(svg).not.toBeEmptyDOMElement(); - }); - }); -}); diff --git a/webui/react/src/components/kit/internal/Image/Image.tsx b/webui/react/src/components/kit/internal/Image/Image.tsx deleted file mode 100644 index fb26b9ec510..00000000000 --- a/webui/react/src/components/kit/internal/Image/Image.tsx +++ /dev/null @@ -1,92 +0,0 @@ -import React from 'react'; - -import { DarkLight } from 'components/kit/internal/types'; - -import css from './Image.module.scss'; - -export interface Props { - darkLight?: DarkLight; -} - -export const ImageAlert: React.FC = ({ darkLight }) => { - const classes = [css.alert]; - if (darkLight === DarkLight.Dark) classes.push(css.dark); - return ( - - Alert - - - - - - - - ); -}; - -export const ImageEmpty: React.FC = () => ( - - Empty - - - - - - - - -); - -export const ImageWarning: React.FC = ({ darkLight }) => { - const classes = [css.warning]; - if (darkLight === DarkLight.Dark) classes.push(css.dark); - return ( - - Warning - - - - - - - - ); -}; diff --git a/webui/react/src/components/kit/internal/Image/index.ts b/webui/react/src/components/kit/internal/Image/index.ts deleted file mode 100644 index 4bbac90149c..00000000000 --- a/webui/react/src/components/kit/internal/Image/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './Image'; diff --git a/webui/react/src/components/kit/internal/Label.module.scss b/webui/react/src/components/kit/internal/Label.module.scss deleted file mode 100644 index c57f991709a..00000000000 --- a/webui/react/src/components/kit/internal/Label.module.scss +++ /dev/null @@ -1,11 +0,0 @@ -.base { - cursor: pointer; - font-size: 14px; - white-space: nowrap; -} -.alignRight { - text-align: right; -} -.textOnly { - cursor: auto; -} diff --git a/webui/react/src/components/kit/internal/Label.tsx b/webui/react/src/components/kit/internal/Label.tsx deleted file mode 100644 index c7f9e1ac450..00000000000 --- a/webui/react/src/components/kit/internal/Label.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import React from 'react'; - -import { ValueOf } from 'components/kit/internal/types'; - -import css from './Label.module.scss'; - -export const LabelTypes = { - TextOnly: 'textOnly', -} as const; - -export type LabelTypes = ValueOf; - -interface Props extends React.HTMLAttributes { - children: React.ReactNode; - type?: LabelTypes; -} - -const Label: React.FC = ({ className, children, type, ...props }: Props) => { - const classes = [css.base]; - - if (type) classes.push(css[type]); - if (className) classes.push(className); - - return React.createElement('div', { className: classes.join(' '), ...props }, children); -}; - -export default Label; diff --git a/webui/react/src/components/kit/internal/Logger.ts b/webui/react/src/components/kit/internal/Logger.ts deleted file mode 100644 index 2b434277542..00000000000 --- a/webui/react/src/components/kit/internal/Logger.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { debug } from 'debug'; - -import { ValueOf } from 'components/kit/internal/types'; - -const LIB_NAME = 'det'; -export const NAMEPACE_SEPARATOR = '/'; - -/** - * Log levels in order of serverity (low to high). - * Modeled after Syslog RFC 5424 - * https://tools.ietf.org/html/rfc5424 - */ -export const Level = { - Debug: 'debug', - Error: 'error', - Info: 'info', - Trace: 'trace', - Warn: 'warn', -} as const; - -export type Level = ValueOf; - -// enum LogBackend { -// Console, -// Debug, -// } - -const generateNamespace = (parts: string[], separator = NAMEPACE_SEPARATOR) => { - return parts.join(separator); -}; - -const loggers: Record = {}; - -/** returns the underlying Debug logger. */ -export const getLogger = (namespace: string, level: Level): ((...msg: unknown[]) => void) => { - const key = `${namespace}:${level}`; - if (!loggers[key]) { - loggers[key] = debug(key); - } - return loggers[key]; -}; - -export interface LoggerInterface { - debug(...msg: unknown[]): void; - error(...msg: unknown[]): void; - info(...msg: unknown[]): void; - trace(...msg: unknown[]): void; - warn(...msg: unknown[]): void; -} - -/** - * log filtering is controlled by localStorage.debug. - * read more on: https://github.com/debug-js/debug#usage - */ -class Logger implements LoggerInterface { - private namespace: string; - - constructor(namespace: string) { - this.namespace = namespace; - } - - extend(...namespace: string[]): Logger { - return new Logger(generateNamespace([this.namespace, ...namespace])); - } - - debug(...msg: unknown[]): void { - this.logWithLevel(Level.Debug, ...msg); - } - - trace(...msg: unknown[]): void { - this.logWithLevel(Level.Trace, ...msg); - } - - info(...msg: unknown[]): void { - this.logWithLevel(Level.Info, ...msg); - } - - error(...msg: unknown[]): void { - this.logWithLevel(Level.Error, ...msg); - } - - warn(...msg: unknown[]): void { - this.logWithLevel(Level.Warn, ...msg); - } - - private logWithLevel(level: Level, ...msg: unknown[]): void { - // TODO: set up and persist loggers. - getLogger(this.namespace, level)(...msg); - } -} - -const rootLogger = new Logger(LIB_NAME); - -export default rootLogger; diff --git a/webui/react/src/components/kit/internal/Markdown.module.scss b/webui/react/src/components/kit/internal/Markdown.module.scss deleted file mode 100644 index 355014f0748..00000000000 --- a/webui/react/src/components/kit/internal/Markdown.module.scss +++ /dev/null @@ -1,776 +0,0 @@ -// adapted from this repo: https://github.com/sindresorhus/github-markdown-css - -.base { - font-family: var(--theme-font-family), -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif, - 'Apple Color', Emoji; - font-size: 16px; - height: 100%; - line-height: 1.5; - overflow: auto; - padding: 16px; - -ms-text-size-adjust: 100%; - -webkit-text-size-adjust: 100%; - word-wrap: break-word; - - .noOverflow { - height: 100%; - overflow: hidden; - } - .anchor { - float: left; - line-height: 1; - margin-left: -20px; - padding-right: 4px; - - &:focus { - outline: none; - } - } - summary { - display: list-item; - } - details { - display: block; - margin-bottom: 16px; - margin-top: 0; - - summary { - cursor: pointer; - } - } - a { - background-color: initial; - color: #0366d6; - text-decoration: none; - - &:hover { - outline-width: 0; - text-decoration: underline; - } - &:not([href]) { - color: inherit; - text-decoration: none; - } - &:active { - outline-width: 0; - } - } - strong { - font-weight: inherit; - font-weight: bolder; - font-weight: 600; - } - h1 { - border-bottom: 1px solid #eaecef; - font-size: 32px; - font-weight: 600; - line-height: 1.25; - margin: 0.67em 0; - margin-bottom: 0; - margin-bottom: 16px; - margin-top: 0; - margin-top: 24px; - padding-bottom: 0.3em; - - &:hover { - .anchor { - text-decoration: none; - } - } - } - img { - background-color: #fff; - border-style: none; - box-sizing: initial; - max-width: 100%; - } - hr { - background: transparent; - background-color: #e1e4e8; - border: 0; - border-bottom: 1px solid #dfe2e5; - border-bottom-color: #eee; - box-sizing: initial; - height: 0.25em; - margin: 15px 0; - margin: 24px 0; - overflow: visible; - overflow: hidden; - padding: 0; - - &::after { - clear: both; - content: ''; - display: table; - } - &::before { - content: ''; - display: table; - } - } - input { - font: inherit; - font-family: inherit; - font-size: inherit; - line-height: inherit; - margin: 0; - overflow: visible; - - &::-webkit-inner-spin-button { - -webkit-appearance: none; - appearance: none; - margin: 0; - } - &::-webkit-outer-spin-button { - -webkit-appearance: none; - appearance: none; - margin: 0; - } - } - [type='checkbox'] { - box-sizing: border-box; - padding: 0; - } - * { - box-sizing: border-box; - } - td { - padding: 0; - } - th { - padding: 0; - } - table { - border-collapse: collapse; - border-spacing: 0; - display: block; - margin-bottom: 16px; - margin-top: 0; - overflow: auto; - width: 100%; - - th { - border: 1px solid #dfe2e5; - font-weight: 600; - padding: 6px 13px; - } - tr { - background-color: #fff; - border-top: 1px solid #c6cbd1; - - &:nth-child(2n) { - background-color: #f6f8fa; - } - } - td { - border: 1px solid #dfe2e5; - padding: 6px 13px; - } - } - kbd { - background-color: #fafbfc; - border: 1px solid #d1d5da; - border-radius: 3px; - box-shadow: inset 0 -1px 0 #d1d5da; - color: #444d56; - display: inline-block; - font: 11px SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; - font-family: monospace; - font-size: 1em; - line-height: 10px; - padding: 3px 5px; - vertical-align: middle; - } - h2 { - border-bottom: 1px solid #eaecef; - font-size: 24px; - font-weight: 600; - line-height: 1.25; - margin-bottom: 0; - margin-bottom: 16px; - margin-top: 0; - margin-top: 24px; - padding-bottom: 0.3em; - - &:hover { - .anchor { - text-decoration: none; - } - } - } - h3 { - font-size: 20px; - font-weight: 600; - line-height: 1.25; - margin-bottom: 16px; - margin-top: 24px; - - &:hover { - .anchor { - text-decoration: none; - } - } - } - h4 { - font-size: 16px; - font-weight: 600; - line-height: 1.25; - margin-bottom: 0; - margin-bottom: 16px; - margin-top: 0; - margin-top: 24px; - - &:hover { - .anchor { - text-decoration: none; - } - } - } - h5 { - font-size: 14px; - font-weight: 600; - line-height: 1.25; - margin-bottom: 0; - margin-bottom: 16px; - margin-top: 0; - margin-top: 24px; - - &:hover { - .anchor { - text-decoration: none; - } - } - } - h6 { - color: #6a737d; - font-size: 12px; - font-weight: 600; - line-height: 1.25; - margin-bottom: 16px; - margin-top: 24px; - - &:hover { - .anchor { - text-decoration: none; - } - } - } - p { - font-size: 16px; - margin-bottom: 16px; - margin-top: 0; - } - &:first-child { - margin-top: 0 !important; - } - &:last-child { - margin-bottom: 0 !important; - } - blockquote { - border-left: 0.25em solid #dfe2e5; - color: #6a737d; - margin: 0; - margin-bottom: 16px; - margin-top: 0; - padding: 0 1em; - - &:first-child { - margin-top: 0; - } - &:last-child { - margin-bottom: 0; - } - } - dd { - margin-left: 0; - } - code { - background-color: rgba(27 31 35 / 5%); - border-radius: 3px; - font-family: SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; - font-size: 12px; - margin: 0; - padding: 0.2em 0.4em; - } - pre { - background-color: #f6f8fa; - border-radius: 3px; - font-family: monospace; - font-family: SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; - font-size: 1em; - font-size: 12px; - font-size: 85%; - line-height: 1.45; - margin-bottom: 0; - margin-bottom: 16px; - margin-top: 0; - overflow: auto; - padding: 16px; - word-break: normal; - - > code { - background: transparent; - border: 0; - font-size: 100%; - margin: 0; - padding: 0; - white-space: pre; - word-break: normal; - } - code { - background-color: initial; - border: 0; - display: inline; - line-height: inherit; - margin: 0; - overflow: visible; - padding: 0; - word-wrap: normal; - } - } - &:checked { - + { - .radio-label { - border-color: #0366d6; - position: relative; - z-index: 1; - } - } - } - .border { - border: 1px solid #e1e4e8 !important; - } - .border-0 { - border: 0 !important; - } - .border-bottom { - border-bottom: 1px solid #e1e4e8 !important; - } - .rounded-1 { - border-radius: 3px !important; - } - .bg-white { - background-color: #fff !important; - } - .bg-gray-light { - background-color: #fafbfc !important; - } - .text-gray-light { - color: #6a737d !important; - } - .mb-0 { - margin-bottom: 0 !important; - } - .my-2 { - margin-bottom: 8px !important; - margin-top: 8px !important; - } - .pl-0 { - padding-left: 0 !important; - } - .py-0 { - padding-bottom: 0 !important; - padding-top: 0 !important; - } - .pl-1 { - padding-left: 4px !important; - } - .pl-2 { - padding-left: 8px !important; - } - .py-2 { - padding-bottom: 8px !important; - padding-top: 8px !important; - } - .px-3 { - padding-left: 16px !important; - padding-right: 16px !important; - } - .pl-4 { - padding-left: 24px !important; - } - .pl-5 { - padding-left: 32px !important; - } - .pl-6 { - padding-left: 40px !important; - } - .f6 { - font-size: 12px !important; - } - .lh-condensed { - line-height: 1.25 !important; - } - .text-bold { - font-weight: 600 !important; - } - .pl-c { - color: #6a737d; - } - .pl-ent { - color: #22863a; - } - .pl-k { - color: #d73a49; - } - .pl-bu { - color: #b31d28; - } - .pl-ii { - background-color: #b31d28; - color: #fafbfc; - } - .pl-c2 { - background-color: #d73a49; - color: #fafbfc; - - &::before { - content: '^M'; - } - } - .pl-sr { - color: #032f62; - - .pl-cce { - color: #22863a; - color: #032f62; - font-weight: 700; - } - .pl-sra { - color: #032f62; - } - .pl-sre { - color: #032f62; - } - } - .pl-ml { - color: #735c0f; - } - .pl-mi { - color: #24292e; - font-style: italic; - } - .pl-mb { - color: #24292e; - font-weight: 700; - } - .pl-md { - background-color: #ffeef0; - color: #b31d28; - } - .pl-mi1 { - background-color: #f0fff4; - color: #22863a; - } - .pl-mc { - background-color: #ffebda; - color: #e36209; - } - .pl-mi2 { - background-color: #005cc5; - color: #f6f8fa; - } - .pl-mdr { - color: #6f42c1; - font-weight: 700; - } - .pl-ba { - color: #586069; - } - .pl-sg { - color: #959da5; - } - .pl-corl { - color: #032f62; - text-decoration: underline; - } - .pl-3 { - padding-left: 16px !important; - } - .pl-7 { - padding-left: 48px !important; - } - .pl-8 { - padding-left: 64px !important; - } - .pl-9 { - padding-left: 80px !important; - } - .pl-10 { - padding-left: 96px !important; - } - .pl-11 { - padding-left: 112px !important; - } - .pl-12 { - padding-left: 128px !important; - } - &::after { - clear: both; - content: ''; - display: table; - } - li { - word-break: break-all; - - > p { - margin-top: 16px; - } - + { - li { - margin-top: 0.25em; - } - } - } - dl { - margin-bottom: 16px; - margin-top: 0; - padding: 0; - - dt { - font-size: 1em; - font-style: italic; - font-weight: 600; - margin-top: 16px; - padding: 0; - } - dd { - margin-bottom: 16px; - padding: 0 16px; - } - } - img[align='right'] { - padding-left: 20px; - } - img[align='left'] { - padding-right: 20px; - } - .highlight { - margin-bottom: 16px; - - pre { - background-color: #f6f8fa; - border-radius: 3px; - font-size: 85%; - line-height: 1.45; - margin-bottom: 0; - overflow: auto; - padding: 16px; - word-break: normal; - } - } - .commit-tease-sha { - color: #444d56; - display: inline-block; - font-family: SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; - font-size: 90%; - } - .full-commit { - .btn-outline { - &:not(:disabled) { - &:hover { - border-color: #005cc5; - color: #005cc5; - } - } - } - } - .blob-wrapper { - overflow-x: auto; - overflow-y: hidden; - } - .blob-wrapper-embedded { - max-height: 240px; - overflow-y: auto; - } - .blob-num { - color: rgba(27 31 35 / 30%); - cursor: pointer; - font-family: SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; - font-size: 12px; - line-height: 20px; - min-width: 50px; - padding-left: 10px; - padding-right: 10px; - text-align: right; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - vertical-align: top; - white-space: nowrap; - width: 1%; - - &:hover { - color: rgba(27 31 35 / 60%); - } - &::before { - content: attr(data-line-number); - } - } - .blob-code { - line-height: 20px; - padding-left: 10px; - padding-right: 10px; - position: relative; - vertical-align: top; - } - .blob-code-inner { - color: #24292e; - font-family: SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; - font-size: 12px; - overflow: visible; - white-space: pre; - word-wrap: normal; - } - .tab-size[data-tab-size='1'] { - -moz-tab-size: 1; - tab-size: 1; - } - .tab-size[data-tab-size='2'] { - -moz-tab-size: 2; - tab-size: 2; - } - .tab-size[data-tab-size='3'] { - -moz-tab-size: 3; - tab-size: 3; - } - .tab-size[data-tab-size='4'] { - -moz-tab-size: 4; - tab-size: 4; - } - .tab-size[data-tab-size='5'] { - -moz-tab-size: 5; - tab-size: 5; - } - .tab-size[data-tab-size='6'] { - -moz-tab-size: 6; - tab-size: 6; - } - .tab-size[data-tab-size='7'] { - -moz-tab-size: 7; - tab-size: 7; - } - .tab-size[data-tab-size='8'] { - -moz-tab-size: 8; - tab-size: 8; - } - .tab-size[data-tab-size='9'] { - -moz-tab-size: 9; - tab-size: 9; - } - .tab-size[data-tab-size='10'] { - -moz-tab-size: 10; - tab-size: 10; - } - .tab-size[data-tab-size='11'] { - -moz-tab-size: 11; - tab-size: 11; - } - .tab-size[data-tab-size='12'] { - -moz-tab-size: 12; - tab-size: 12; - } - .task-list-item { - list-style-type: none; - - + { - .task-list-item { - margin-top: 3px; - } - } - input { - margin: 0 0.2em 0.25em -1.6em; - vertical-align: middle; - } - } - ol { - margin-bottom: 16px; - margin-top: 0; - padding-left: 0; - padding-left: 2em; - } - ul { - margin-bottom: 0; - margin-bottom: 16px; - margin-top: 0; - padding-left: 0; - padding-left: 2em; - } - .pl-c1 { - color: #005cc5; - } - .pl-v { - color: #e36209; - } - .pl-s { - color: #032f62; - - .pl-v { - color: #005cc5; - } - .pl-s1 { - color: #24292e; - } - .pl-pse { - .pl-s1 { - color: #032f62; - } - } - } - .pl-e { - color: #6f42c1; - } - .pl-en { - color: #6f42c1; - } - .pl-smi { - color: #24292e; - } - .pl-pds { - color: #032f62; - } - .pl-smw { - color: #e36209; - } - .pl-mh { - color: #005cc5; - font-weight: 700; - - .pl-en { - color: #005cc5; - font-weight: 700; - } - } - .pl-ms { - color: #005cc5; - font-weight: 700; - } - &::before { - content: ''; - display: table; - } - .pl-token.active { - background: #ffea7f; - cursor: pointer; - } - .pl-token { - &:hover { - background: #ffea7f; - cursor: pointer; - } - } -} -.render { - color: var(--theme-stage-on); - font-size: 14px; - height: 100%; - padding: 16px; - - .placeholder { - color: var(--theme-stage-on-weak); - font-size: 14px; - font-style: italic; - height: 100%; - } -} diff --git a/webui/react/src/components/kit/internal/Markdown.tsx b/webui/react/src/components/kit/internal/Markdown.tsx deleted file mode 100644 index 99e9bcd9da4..00000000000 --- a/webui/react/src/components/kit/internal/Markdown.tsx +++ /dev/null @@ -1,105 +0,0 @@ -import type { TabsProps } from 'antd'; -import { default as MarkdownViewer } from 'markdown-to-jsx'; -import React, { useMemo } from 'react'; - -import useResize from 'components/kit/internal/useResize'; -import Pivot from 'components/kit/Pivot'; -import Spinner from 'components/kit/Spinner'; - -import css from './Markdown.module.scss'; - -const CodeMirrorEditor = React.lazy(() => import('components/kit/internal/CodeMirrorEditor')); - -interface Props { - disabled?: boolean; - editing?: boolean; - markdown: string; - onChange?: (editedMarkdown: string) => void; - onClick?: (e: React.MouseEvent) => void; -} - -interface RenderProps { - markdown: string; - onClick?: (e: React.MouseEvent) => void; - placeholder?: string; -} - -const TabType = { - Edit: 'edit', - Preview: 'preview', -} as const; - -const MarkdownRender: React.FC = ({ markdown, placeholder, onClick }) => { - const showPlaceholder = !markdown && placeholder; - return ( -
    - {showPlaceholder ? ( -
    {placeholder}
    - ) : ( - {markdown} - )} -
    - ); -}; - -const Markdown: React.FC = ({ - disabled = false, - editing = false, - markdown, - onChange, - onClick, -}: Props) => { - const { size } = useResize(); - const tabItems: TabsProps['items'] = useMemo(() => { - return [ - { - children: ( -
    - - -
    - }> - - -
    - ), - key: TabType.Edit, - label: 'Edit', - }, - { - children: , - key: TabType.Preview, - label: 'Preview', - }, - ]; - }, [markdown, onChange, onClick, size]); - - return ( -
    - {editing && !disabled ? ( - - ) : ( - - )} -
    - ); -}; - -export default Markdown; diff --git a/webui/react/src/components/kit/internal/ScaleSelect.tsx b/webui/react/src/components/kit/internal/ScaleSelect.tsx deleted file mode 100644 index 99a8a5c9ae0..00000000000 --- a/webui/react/src/components/kit/internal/ScaleSelect.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import React from 'react'; - -import { capitalize } from 'components/kit/internal/functions'; -import { Scale } from 'components/kit/internal/types'; -import Select, { Option, SelectValue } from 'components/kit/Select'; - -interface Props { - onChange: (value: Scale) => void; - value: Scale; -} - -const ScaleSelect: React.FC = ({ onChange, value }: Props) => { - return ( - - ); -}; - -export default ScaleSelect; diff --git a/webui/react/src/components/kit/internal/Section.module.scss b/webui/react/src/components/kit/internal/Section.module.scss deleted file mode 100644 index 1423062493e..00000000000 --- a/webui/react/src/components/kit/internal/Section.module.scss +++ /dev/null @@ -1,101 +0,0 @@ -/* stylelint-disable no-descending-specificity */ - -.base { - display: flex; - flex-direction: column; - - &:not(:last-child) { - padding-bottom: 16px; - } - .header { - align-items: center; - display: flex; - flex-shrink: 0; - justify-content: space-between; - margin-bottom: 8px; - } - .title { - align-items: center; - display: flex; - flex-grow: 1; - height: 32px; - line-height: 32px; - margin-bottom: 0; - white-space: nowrap; - } - .title.string { - font-size: 16px; - } - .options { - display: flex; - margin-left: auto; - } - .title + .options { - margin-left: 8px; - } - .body { - border-color: var(--theme-stage-border); - border-style: solid; - border-width: 0; - flex-grow: 1; - height: max-content; - min-height: 0; - position: relative; - } - .filterBar { - background-color: var(--theme-stage); - border: solid var(--theme-stroke-width) var(--theme-stage-border); - border-radius: var(--theme-border-radius); - display: inline-flex; - flex-wrap: wrap; - justify-content: center; - padding: 4px; - width: 100%; - - & > * { - margin: 4px; - } - } -} -.base.maxHeight { - height: 100%; -} -.base.divider .body { - border-top-width: var(--theme-stroke-width); - padding-top: 8px; -} -.base.bodyBorder { - .body { - background-color: var(--theme-stage); - border: solid var(--theme-stroke-width) var(--theme-stage-border); - border-radius: var(--theme-border-radius); - padding: 16px; - } - .filterBar { - border-radius: var(--theme-border-radius) var(--theme-border-radius) 0 0; - border-width: var(--theme-stroke-width) var(--theme-stroke-width) 0 var(--theme-stroke-width); - } - .filterBar + .body { - border-radius: 0 0 var(--theme-border-radius) var(--theme-border-radius); - } -} -.base.bodyDynamic { - .body > :global(.ant-spin-nested-loading) { - height: 100%; - position: absolute; - width: 100%; - } -} -.base.bodyNoPadding { - .body { - padding: 0; - } -} -.base.bodyScroll { - height: 100%; - - .body { - height: 100%; - overflow: auto; - } -} diff --git a/webui/react/src/components/kit/internal/Section.tsx b/webui/react/src/components/kit/internal/Section.tsx deleted file mode 100644 index 18fb796b8f7..00000000000 --- a/webui/react/src/components/kit/internal/Section.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import React from 'react'; - -import { generateAlphaNumeric, isString, toHtmlId } from 'components/kit/internal/functions'; -import Spinner from 'components/kit/Spinner'; - -import css from './Section.module.scss'; - -interface Props { - bodyBorder?: boolean; - bodyDynamic?: boolean; - bodyNoPadding?: boolean; - bodyScroll?: boolean; - children?: React.ReactNode; - className?: string; - divider?: boolean; - filters?: React.ReactNode; - hideTitle?: boolean; - id?: string; - loading?: boolean; - maxHeight?: boolean; - options?: React.ReactNode; - title?: string | React.ReactNode; -} - -const defaultProps = { divider: false }; - -const Section: React.FC = ({ className = '', ...props }: Props) => { - const defaultId = isString(props.title) ? toHtmlId(props.title) : generateAlphaNumeric(); - const id = props.id || defaultId; - const classes = [css.base, className]; - const titleClasses = [css.title]; - - if (props.bodyBorder) classes.push(css.bodyBorder); - if (props.bodyDynamic) classes.push(css.bodyDynamic); - if (props.bodyNoPadding) classes.push(css.bodyNoPadding); - if (props.bodyScroll) classes.push(css.bodyScroll); - if (props.divider) classes.push(css.divider); - if (props.filters) classes.push(css.filters); - if (props.maxHeight) classes.push(css.maxHeight); - if (typeof props.title === 'string') titleClasses.push(css.string); - - return ( -
    - {(props.title || props.options) && ( -
    - {props.title && !props.hideTitle && ( -
    {props.title}
    - )} - {props.options &&
    {props.options}
    } -
    - )} - {props.filters &&
    {props.filters}
    } -
    - {props.children} -
    -
    - ); -}; - -Section.defaultProps = defaultProps; - -export default Section; diff --git a/webui/react/src/components/kit/internal/UPlot/SyncProvider.tsx b/webui/react/src/components/kit/internal/UPlot/SyncProvider.tsx deleted file mode 100644 index 42f880283cf..00000000000 --- a/webui/react/src/components/kit/internal/UPlot/SyncProvider.tsx +++ /dev/null @@ -1,169 +0,0 @@ -import { observable } from 'micro-observables'; -import React, { createContext, useContext, useMemo } from 'react'; -import uPlot, { AlignedData } from 'uplot'; - -import { generateUUID } from 'components/kit/internal/functions'; -import { XAxisDomain } from 'components/kit/internal/types'; - -type Bounds = { - dataBounds: { - max: number; - min: number; - } | null; - unzoomedBounds: { - max: number; - min: number; - } | null; - zoomBounds: { - max: number; - min: number; - } | null; -}; - -class SyncService { - axis: XAxisDomain | undefined; - bounds = observable({ dataBounds: null, unzoomedBounds: null, zoomBounds: null }); - - pubSub: uPlot.SyncPubSub; - - activeBounds = this.bounds.select((b) => b?.zoomBounds ?? b?.unzoomedBounds); - key: string; - - constructor(syncKey?: string) { - this.key = syncKey ?? generateUUID(); - this.pubSub = uPlot.sync(this.key); - this.activeBounds.subscribe((activeBounds) => { - if (!activeBounds) return; - const { min, max } = activeBounds; - this.pubSub.plots.forEach((u) => { - u.setScale('x', { max, min }); - }); - }); - } - - syncChart(chart: uPlot) { - const activeBounds = this?.activeBounds.get(); - if (activeBounds) chart.setScale('x', activeBounds); - } - - resetZoom() { - this.bounds.update((b) => ({ ...b, zoomBounds: null })); - } - - setZoom(min: number, max: number) { - this.bounds.update((b) => ({ ...b, zoomBounds: { max, min } })); - } - - updateDataBounds(data: AlignedData, axis?: XAxisDomain) { - const xValues = data[0]; - const lastIdx = xValues.length - 1; - const chartMin = xValues[0]; - const chartMax = xValues[lastIdx]; - - if (chartMin === undefined || chartMax === undefined) return; - - this.bounds.update((b) => { - const resetAxis = axis !== this.axis && !!axis && !!this.axis; - if (axis) { - this.axis = axis; - } - - const previousMin = - b.dataBounds?.min !== undefined && isFinite(b.dataBounds?.min) && !resetAxis - ? b.dataBounds?.min - : chartMin; - - const previousMax = - b.dataBounds?.max !== undefined && isFinite(b.dataBounds?.max) && !resetAxis - ? b.dataBounds?.max - : chartMax; - - const dataMin = Math.min(previousMin, chartMin); - const dataMax = Math.max(previousMax, chartMax); - - const width = dataMax - dataMin; - const margin = 0.02 * width; - - const unzoomedMin = width > 0 ? dataMin - margin : Math.min(dataMin, 0); - let unzoomedMax = width > 0 ? dataMax + margin : 2 * dataMax; - if (unzoomedMin === unzoomedMax) { - // for single point at x=0 - unzoomedMax = 1; - } - - return { - ...b, - dataBounds: { max: dataMax, min: dataMin }, - unzoomedBounds: { max: unzoomedMax, min: unzoomedMin }, - zoomBounds: resetAxis ? null : b.zoomBounds, - }; - }); - } -} - -interface Props { - children: React.ReactNode; - // pass a new key when you want the zoom to be reset, - // e.g. when changing the x-axis. by default it will - // reset when the component remounts - syncKey?: string; -} - -const SyncContext = createContext(null); - -export const SyncProvider: React.FC = ({ syncKey, children }) => { - const syncService = useMemo(() => new SyncService(syncKey), [syncKey]); - - return {children}; -}; - -export const useChartSync = (): { - options: Partial; - syncService: SyncService; -} => { - const syncProviderService = useContext(SyncContext); - - const syncService = useMemo( - () => syncProviderService ?? new SyncService(), - [syncProviderService], - ); - - const options = useMemo(() => { - const syncKey = syncService?.pubSub.key; - const syncScales: [string, null] = ['x', null]; - return { - cursor: { - bind: { - dblclick: () => { - return () => { - syncService?.resetZoom(); - return null; - }; - }, - }, - drag: { dist: 5, setScale: false, uni: 10, x: true, y: false }, - sync: { - key: syncKey, - scales: syncScales, - setSeries: false, - }, - }, - - hooks: { - init: [syncService.syncChart], - ready: [syncService.syncChart], - setData: [(chart: uPlot) => syncService.updateDataBounds(chart.data)], - setSelect: [ - (chart: uPlot) => { - const min = chart.posToVal(chart.select.left, 'x'); - const max = chart.posToVal(chart.select.left + chart.select.width, 'x'); - syncService?.setZoom(min, max); - chart.setSelect({ height: 0, left: 0, top: 0, width: 0 }, false); - }, - ], - }, - }; - }, [syncService]); - - return { options, syncService }; -}; diff --git a/webui/react/src/components/kit/internal/UPlot/UPlotChart.module.scss b/webui/react/src/components/kit/internal/UPlot/UPlotChart.module.scss deleted file mode 100644 index 76362856990..00000000000 --- a/webui/react/src/components/kit/internal/UPlot/UPlotChart.module.scss +++ /dev/null @@ -1,28 +0,0 @@ -.base { - background-color: var(--theme-stage); - margin-bottom: 10px; - margin-top: 10px; - position: relative; -} -.base.dark { - :global(.u-select) { - background-color: rgba(255 255 255 / 10%); - } -} -.chartEmpty { - align-items: center; - display: flex; - height: 100%; - justify-content: center; -} -.download { - border: 0; - cursor: pointer; - position: absolute; - right: 0; - top: -10px; - z-index: 10; -} -.invisibleLink { - display: none; -} diff --git a/webui/react/src/components/kit/internal/UPlot/UPlotChart.tsx b/webui/react/src/components/kit/internal/UPlot/UPlotChart.tsx deleted file mode 100644 index cbdf227e4da..00000000000 --- a/webui/react/src/components/kit/internal/UPlot/UPlotChart.tsx +++ /dev/null @@ -1,317 +0,0 @@ -import React, { RefObject, useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import { throttle } from 'throttle-debounce'; -import uPlot, { AlignedData } from 'uplot'; - -import Button from 'components/kit/Button'; -import Icon from 'components/kit/Icon'; -import { - DarkLight, - ErrorHandler, - ErrorLevel, - ErrorType, - XAxisDomain, -} from 'components/kit/internal/types'; -import usePrevious from 'components/kit/internal/usePrevious'; -import useResize from 'components/kit/internal/useResize'; -import Spinner from 'components/kit/Spinner'; -import useUI from 'components/kit/Theme'; - -import { useChartSync } from './SyncProvider'; -import { FacetedData } from './types'; -import css from './UPlotChart.module.scss'; - -export interface Options extends Omit { - key?: number; - width?: number; -} - -interface Props { - allowDownload?: boolean; - data?: AlignedData | FacetedData; - experimentId?: number; - isLoading?: boolean; - options?: Partial; - style?: React.CSSProperties; - handleError?: ErrorHandler; - xAxis?: XAxisDomain; -} - -const SCROLL_THROTTLE_TIME = 500; - -const shouldRecreate = ( - prev: Partial | undefined, - next: Partial | undefined, -): boolean => { - if (!next) return false; - if (!prev) return true; - if (prev === next) return false; - if (prev.key !== next.key) return true; - if (Object.keys(prev).length !== Object.keys(next).length) return true; - - if (prev.axes?.length !== next.axes?.length) return true; - - if (prev?.series?.length !== next.series?.length) return true; - - const someScaleHasChanged = Object.entries(next.scales ?? {}).some(([scaleKey, nextScale]) => { - const prevScale = prev?.scales?.[scaleKey]; - return prevScale?.distr !== nextScale?.distr; - }); - - if (someScaleHasChanged) return true; - - const someAxisHasChanged = prev.axes?.some((prevAxis, seriesIdx) => { - const nextAxis = next.axes?.[seriesIdx]; - return ( - prevAxis.label !== nextAxis?.label || - prevAxis.stroke !== nextAxis?.stroke || - prevAxis.scale !== nextAxis?.scale - ); - }); - if (someAxisHasChanged) return true; - - const someSeriesHasChanged = prev.series?.some((prevSerie, seriesIdx) => { - const nextSerie = next.series?.[seriesIdx]; - - return ( - (nextSerie?.label != null && prevSerie?.label !== nextSerie?.label) || - (prevSerie?.stroke != null && prevSerie?.stroke !== nextSerie?.stroke) || - (nextSerie?.paths != null && prevSerie?.paths !== nextSerie?.paths) || - (nextSerie?.fill != null && prevSerie?.fill !== nextSerie?.fill) || - prevSerie?.points?.show !== nextSerie?.points?.show - ); - }); - if (someSeriesHasChanged) return true; - - return false; -}; -type ChartType = 'Line' | 'Scatter'; - -const UPlotChart: React.FC = ({ - allowDownload, - data, - isLoading, - options, - style, - handleError, - experimentId, - xAxis, -}: Props) => { - const chartRef = useRef(); - const [divHeight, setDivHeight] = useState((options?.height ?? 300) + 20); - const { refObject, refCallback, size } = useResize(); - const classes = [css.base]; - - const { ui } = useUI(); - const { options: syncOptions, syncService } = useChartSync(); - - // line charts have their zoom state handled by `SyncProvider`, scatter charts do not. - const chartType: ChartType = options?.mode === 2 ? 'Scatter' : 'Line'; - - const hasData = data && data.length > 1 && (chartType === 'Scatter' || data?.[0]?.length); - - if (ui.darkLight === DarkLight.Dark) classes.push(css.dark); - - useEffect(() => { - if (data !== undefined && chartType === 'Line') - syncService.updateDataBounds(data as AlignedData, xAxis); - }, [syncService, chartType, data, xAxis]); - - const extendedOptions = useMemo(() => { - const extended: Partial = uPlot.assign( - { - width: size.width, - }, - chartType === 'Line' ? syncOptions : {}, - options ?? {}, - ); - - if (chartType === 'Line') { - const activeBounds = syncService.activeBounds.get(); - if (activeBounds) { - const { min, max } = activeBounds; - const xScale = extended.scales?.x; - if (xScale) { - xScale.max = max; - xScale.min = min; - } - } - } - - // Override chart support colors to match theme. - if (ui.theme && extended.axes) { - const borderColor = ui.theme.surfaceBorderWeak; - const labelColor = ui.theme.surfaceOn; - extended.axes = extended.axes.map((axis) => { - return { - ...axis, - border: { stroke: borderColor }, - grid: { ...axis.grid, stroke: borderColor }, - stroke: labelColor, - ticks: { ...axis.ticks, stroke: borderColor }, - }; - }); - } - - return extended as uPlot.Options; - }, [options, ui.theme, chartType, size.width, syncOptions, syncService]); - - const previousOptions = usePrevious(extendedOptions, undefined); - - useEffect(() => { - return () => { - chartRef?.current?.destroy(); - chartRef.current = undefined; - }; - }, []); - - useEffect(() => { - if (!refObject.current) return; - if (!hasData) { - chartRef.current?.destroy(); - chartRef.current = undefined; - return; - } - if (!chartRef.current || shouldRecreate(previousOptions, extendedOptions)) { - chartRef.current?.destroy(); - chartRef.current = undefined; - try { - if (chartType === 'Scatter' || extendedOptions.series.length === data?.length) { - chartRef.current = new uPlot(extendedOptions, data as AlignedData, refObject.current); - } - } catch (e) { - chartRef.current?.destroy(); - chartRef.current = undefined; - handleError?.(e, { - level: ErrorLevel.Error, - publicMessage: 'Unable to Load data for chart', - publicSubject: 'Bad Data', - silent: false, - type: ErrorType.Ui, - }); - } - } else { - try { - chartRef.current?.setData(data as AlignedData, chartType === 'Scatter'); - } catch (e) { - chartRef.current?.destroy(); - chartRef.current = undefined; - handleError?.(e, { - level: ErrorLevel.Error, - publicMessage: 'Unable to Load data for chart', - publicSubject: 'Bad Data', - silent: false, - type: ErrorType.Ui, - }); - } - } - }, [data, hasData, extendedOptions, previousOptions, refObject, handleError, chartType]); - - useEffect(() => { - extendedOptions.series.forEach((ser, i) => { - const chartSer = chartRef.current?.series?.[i]; - if (chartSer && chartSer.show !== ser?.show) - chartRef.current?.setSeries(i, { show: ser.show }, false); - }); - }, [extendedOptions.series]); - - /** - * Resize the chart when resize events happen. - */ - useEffect(() => { - if (!chartRef.current) return; - const [width, height] = [size.width, options?.height || chartRef.current.height]; - if (chartRef.current.width === width && chartRef.current.height === height) return; - chartRef.current.setSize({ height, width }); - const container = refObject.current; - if (container && height) setDivHeight(height); - }, [options?.height, refObject, size]); - - /* - * Resync the chart when scroll events happen to correct the cursor position upon - * a parent container scrolling. - */ - useEffect(() => { - const throttleFunc = throttle(SCROLL_THROTTLE_TIME, () => { - if (chartRef.current) chartRef.current.syncRect(); - }); - const handleScroll = () => throttleFunc(); - - /* - * The true at the end is the important part, - * it tells the browser to capture the event on dispatch, - * even if that event does not normally bubble, like change, focus, and scroll. - */ - document.addEventListener('scroll', handleScroll, true); - - return () => { - document.removeEventListener('scroll', handleScroll); - throttleFunc.cancel(); - }; - }, []); - - return ( -
    - {allowDownload && } - {!hasData && !isLoading && ( -
    - No data to plot. -
    - )} - {isLoading && } -
    - ); -}; - -export default UPlotChart; - -const DownloadButton = ({ - containerRef, - experimentId, -}: { - containerRef: RefObject; - experimentId?: number; -}) => { - const downloadUrl = useRef(); - const downloadNode = useRef(null); - const fileName = useMemo( - () => (experimentId ? `chart-trial-${experimentId}.png` : 'chart.png'), - [experimentId], - ); - - useEffect(() => { - return () => { - if (downloadUrl.current) URL.revokeObjectURL(downloadUrl.current); - }; - }, []); - - const handleDownloadClick = useCallback(() => { - if (downloadUrl.current) URL.revokeObjectURL(downloadUrl.current); - const canvas = containerRef.current?.querySelector('canvas'); - const url = canvas?.toDataURL('image/png'); - if (url && downloadNode.current) { - downloadNode.current.href = url; - downloadNode.current.click(); - } - downloadUrl.current = url; - }, [containerRef]); - - return ( - <> -
    -
    - {/* this is an invisible link used to programatically download the image file */} - - - ); -}; diff --git a/webui/react/src/components/kit/internal/UPlot/UPlotChart/closestPointPlugin.module.scss b/webui/react/src/components/kit/internal/UPlot/UPlotChart/closestPointPlugin.module.scss deleted file mode 100644 index bc91a1a2a96..00000000000 --- a/webui/react/src/components/kit/internal/UPlot/UPlotChart/closestPointPlugin.module.scss +++ /dev/null @@ -1,34 +0,0 @@ -$tooltip-offset: 5px; - -.point { - border-radius: 100%; - display: none !important; - position: absolute; - transform: translate(-50%, -50%); -} -.tooltip { - display: none; - pointer-events: none; - position: absolute; - z-index: 99; - - .box { - background-color: var(--theme-float); - border: solid var(--theme-stroke-width) var(--theme-float-border); - border-radius: var(--theme-border-radius); - box-shadow: var(--theme-elevation-strong); - left: $tooltip-offset; - padding: 8px; - position: absolute; - top: $tooltip-offset; - white-space: nowrap; - } -} -.tooltip.top .box { - bottom: $tooltip-offset; - top: auto; -} -.tooltip.left .box { - left: auto; - right: $tooltip-offset; -} diff --git a/webui/react/src/components/kit/internal/UPlot/UPlotChart/closestPointPlugin.ts b/webui/react/src/components/kit/internal/UPlot/UPlotChart/closestPointPlugin.ts deleted file mode 100644 index 352ed8b8de4..00000000000 --- a/webui/react/src/components/kit/internal/UPlot/UPlotChart/closestPointPlugin.ts +++ /dev/null @@ -1,207 +0,0 @@ -import _ from 'lodash'; -import { throttle } from 'throttle-debounce'; -import uPlot, { Plugin } from 'uplot'; - -import { distance, findInsertionIndex } from 'components/kit/internal/functions'; -import { CheckpointsDict } from 'components/kit/internal/types'; - -import css from './closestPointPlugin.module.scss'; - -interface Point { - idx: number; - seriesIdx: number; -} - -interface Props { - checkpointsDict?: CheckpointsDict; - distInPx?: number; // max cursor distance from data point to focus it (in pixel) - getPointTooltipHTML?: (xVal: number, yVal: number, point: Point) => string; - onPointClick?: (e: MouseEvent, point: Point) => void; - onPointFocus?: (point: Point | undefined) => void; - pointSizeInPx?: number; - yScale: string; // y scale to use -} - -export const closestPointPlugin = ({ - distInPx = 30, - getPointTooltipHTML, - onPointClick, - onPointFocus, - pointSizeInPx = 7, - yScale, - checkpointsDict, -}: Props): Plugin => { - let distValX: number; // distInPx transformed to X value - let distValY: number; // distInPx transformed to Y value - let focusedPoint: Point | undefined; // focused data point - let pointEl: HTMLDivElement; - let tooltipEl: HTMLDivElement; - - const findClosestPoint = ( - uPlot: uPlot, - cursorLeft: number, - cursorTop: number, - ): Point | undefined => { - let closestDistance: number = Number.MAX_VALUE; - let closestPoint: Point | undefined; - - // filter out hidden y series - const shownData = uPlot.data.slice(1).filter((_, idx) => uPlot.series[idx + 1].show); - - // find idx range - // note: assuming X data to be sorted, uPlot behaves odd if that's false - const cursorValX = uPlot.posToVal(cursorLeft, 'x'); - const idxMax = findInsertionIndex(uPlot.data[0], cursorValX + distValX) - 1; - const idxMin = findInsertionIndex(uPlot.data[0], cursorValX - distValX); - - // find y value range - const cursorValY = uPlot.posToVal(cursorTop, yScale); - const yValMax = cursorValY + distValY; - const yValMin = cursorValY - distValY; - - // cycle on each data point in the idx range found - for (let idx = idxMin; idx <= idxMax; idx++) { - const posX = uPlot.valToPos(uPlot.data[0][idx], 'x'); - - for (let seriesIdx = 0; seriesIdx < shownData.length; seriesIdx++) { - const yVal = shownData[seriesIdx][idx]; - - // value is inside Y range - if (yVal && yVal >= yValMin && yVal <= yValMax) { - const posY = uPlot.valToPos(yVal, yScale); - - const yValDistance = distance(posX, posY, cursorLeft, cursorTop); - if (yValDistance < closestDistance) { - closestDistance = yValDistance; - closestPoint = { idx, seriesIdx }; - } - } - } - } - - return closestPoint; - }; - - const focusPoint = (uPlot: uPlot, point: Point | undefined) => { - focusedPoint = point; - - if (typeof onPointFocus === 'function') { - onPointFocus(focusedPoint); - } - - const series = point && uPlot.series[point.seriesIdx]; - const xVal = point && uPlot.data[0][point.idx]; - const yVal = point && uPlot.data[point.seriesIdx][point.idx]; - - const xPos = point && uPlot.valToPos(uPlot.data[0][point.idx], 'x'); - const yPos = yVal && uPlot.valToPos(yVal, yScale); - - if ( - !point || - !series || - xVal == null || - yVal == null || - xPos == null || - yPos == null || - !!checkpointsDict?.[xVal] - ) { - pointEl.style.display = 'none'; - tooltipEl.style.display = 'none'; - return; - } - - // point - if (pointSizeInPx > 0) { - pointEl.style.backgroundColor = - typeof series.stroke === 'function' - ? (series.stroke(uPlot, point.seriesIdx) as string) - : 'rgba(0, 155, 222, 1)'; - pointEl.style.display = 'block'; - pointEl.style.height = pointSizeInPx + 'px'; - pointEl.style.left = xPos + 'px'; - pointEl.style.top = yPos + 'px'; - pointEl.style.width = pointSizeInPx + 'px'; - } - - // tooltip - const tooltipHtml = - typeof getPointTooltipHTML === 'function' && getPointTooltipHTML(xVal, yVal, point); - if (tooltipHtml) { - const classes = [css.tooltip]; - if (xPos > uPlot.bbox.width / 2 / window.devicePixelRatio) classes.push(css.left); - if (yPos > uPlot.bbox.height / 2 / window.devicePixelRatio) classes.push(css.top); - - tooltipEl.className = classes.join(' '); - tooltipEl.innerHTML = `
    ${tooltipHtml}
    `; - tooltipEl.style.display = 'block'; - tooltipEl.style.left = xPos + 'px'; - tooltipEl.style.top = yPos + 'px'; - } else { - tooltipEl.style.display = 'none'; - } - }; - - const handleCursorMove = throttle(50, (uPlot: uPlot) => { - const { left, idx, top } = uPlot.cursor; - - if (!left || left < 0 || !top || top < 0 || idx == null) { - if (focusedPoint) focusPoint(uPlot, undefined); - return; - } - - const point = findClosestPoint(uPlot, left, top); - if (!point) { - if (focusedPoint) focusPoint(uPlot, undefined); - return; - } - - if (!_.isEqual(point, focusedPoint)) { - focusPoint(uPlot, point); - } - }); - - return { - hooks: { - ready: (uPlot: uPlot) => { - const over = uPlot.root.querySelector('.u-over'); - if (!over) return; - - // point div - pointEl = document.createElement('div'); - pointEl.className = css.point; - over.appendChild(pointEl); - - // point div - tooltipEl = document.createElement('div'); - over.appendChild(tooltipEl); - - // click handler - if (typeof onPointClick === 'function') { - let mousedownX: number; - let mousedownY: number; - over.addEventListener('mousedown', (e) => { - mousedownX = (e as MouseEvent).clientX; - mousedownY = (e as MouseEvent).clientY; - }); - over.addEventListener('mouseup', (e) => { - if ( - (e as MouseEvent).clientX !== mousedownX || - (e as MouseEvent).clientY !== mousedownY || - !focusedPoint - ) - return; - - onPointClick(e as MouseEvent, focusedPoint); - }); - } - }, - setCursor: (uPlot: uPlot) => handleCursorMove(uPlot), - setScale: (uPlot: uPlot) => { - const xMax = uPlot.scales.x.max ?? 100; - const xMin = uPlot.scales.x.min ?? 0; - distValX = (xMax - xMin) / 20; - distValY = uPlot.posToVal(0, yScale) - uPlot.posToVal(distInPx, yScale); - }, - }, - }; -}; diff --git a/webui/react/src/components/kit/internal/UPlot/UPlotChart/drawPointsPlugin.ts b/webui/react/src/components/kit/internal/UPlot/UPlotChart/drawPointsPlugin.ts deleted file mode 100644 index 1ba31f26bd1..00000000000 --- a/webui/react/src/components/kit/internal/UPlot/UPlotChart/drawPointsPlugin.ts +++ /dev/null @@ -1,86 +0,0 @@ -import uPlot, { Plugin } from 'uplot'; - -import { isNumber } from 'components/kit/internal/functions'; -import { CheckpointsDict } from 'components/kit/internal/types'; - -const NUM_POINTS = 4; -const OUTER_RADIUS = 5; -const INNER_RADIUS = 3; -const outerRadius = OUTER_RADIUS * devicePixelRatio; -const innerRadius = INNER_RADIUS * devicePixelRatio; - -export const drawPointsPlugin = (checkpointsDict: CheckpointsDict): Plugin => { - function drawCheckpoint(ctx: CanvasRenderingContext2D, cx: number, cy: number) { - let rot = (Math.PI / 2) * 3; - let x = cx; - let y = cy; - const step = Math.PI / NUM_POINTS; - - ctx.beginPath(); - ctx.moveTo(cx, cy - outerRadius); - - for (let i = 0; i < NUM_POINTS; i++) { - x = cx + Math.cos(rot) * outerRadius; - y = cy + Math.sin(rot) * outerRadius; - ctx.lineTo(x, y); - rot += step; - - x = cx + Math.cos(rot) * innerRadius; - y = cy + Math.sin(rot) * innerRadius; - ctx.lineTo(x, y); - rot += step; - } - - ctx.lineTo(cx, cy - outerRadius); - ctx.closePath(); - } - - // function drawPoints(u: uPlot, i, i0, i1) { - function drawPoints(u: uPlot, seriesIdx: number, idx0: number, idx1: number) { - const { ctx } = u; - const { scale } = u.series[seriesIdx]; - - ctx.save(); - - let j = idx0; - let foundCheckpoint = false; - - while (j <= idx1) { - const xVal = u.data[0][j]; - const yVal = u.data[seriesIdx][j]; - - if (scale && isNumber(yVal) && checkpointsDict[Math.floor(xVal)]) { - foundCheckpoint = true; - const cx = Math.round(u.valToPos(xVal, 'x', true)); - const cy = Math.round(u.valToPos(yVal, scale, true)); - drawCheckpoint(ctx, cx, cy); - const blankFill = getComputedStyle(ctx.canvas).getPropertyValue('--theme-stage'); - ctx.fillStyle = blankFill; - ctx.fill(); - ctx.stroke(); - } - - j++; - } - - ctx.restore(); - if (!foundCheckpoint && u.data[seriesIdx].length === 1) { - return true; - } - } - - return { - hooks: {}, - opts: (u, opts) => { - opts.series.forEach((s, i) => { - if (i > 0) { - uPlot.assign(s, { - points: { - show: drawPoints, - }, - }); - } - }); - }, - }; -}; diff --git a/webui/react/src/components/kit/internal/UPlot/UPlotChart/tooltipsPlugin.module.scss b/webui/react/src/components/kit/internal/UPlot/UPlotChart/tooltipsPlugin.module.scss deleted file mode 100644 index ebb94c9aedf..00000000000 --- a/webui/react/src/components/kit/internal/UPlot/UPlotChart/tooltipsPlugin.module.scss +++ /dev/null @@ -1,44 +0,0 @@ -.tooltip { - background: var(--theme-float); - border: solid var(--theme-stroke-width) var(--theme-float-border-strong); - box-shadow: var(--theme-elevation-strong); - color: var(--theme-float-on); - display: none; - font-size: 11px; - position: absolute; - z-index: 99; - - .checkpointHeader, - .valueX, - .valueY, - .valueYEmpty { - margin: 5px 6px 2px; - position: relative; - white-space: nowrap; - } - .valueY, - .valueYEmpty { - padding-left: 13px; - } - .valueYEmpty { - opacity: 0.5; - } - .color { - border-radius: 100%; - border-width: 0; - display: inline-block; - height: 9px; - left: 0; - position: absolute; - top: 3px; - vertical-align: top; - width: 9px; - } -} -.bar { - background: var(--theme-float-border-strong); - bottom: 0; - position: absolute; - top: 0; - width: var(--theme-stroke-width); -} diff --git a/webui/react/src/components/kit/internal/UPlot/UPlotChart/tooltipsPlugin.ts b/webui/react/src/components/kit/internal/UPlot/UPlotChart/tooltipsPlugin.ts deleted file mode 100644 index 2a30ba5e68c..00000000000 --- a/webui/react/src/components/kit/internal/UPlot/UPlotChart/tooltipsPlugin.ts +++ /dev/null @@ -1,214 +0,0 @@ -import uPlot, { Plugin } from 'uplot'; - -import { glasbeyColor, humanReadableNumber } from 'components/kit/internal/functions'; - -import css from './tooltipsPlugin.module.scss'; - -export type ChartTooltip = string | null; - -interface TooltipResult { - html?: string; - val: number | null | undefined; - yDist?: number; -} - -interface Props { - closeOnMouseExit?: boolean; - getXTooltipHeader?: (xIndex: number) => ChartTooltip; - getXTooltipYLabels?: (xIndex: number) => ChartTooltip[]; - isShownEmptyVal: boolean; - seriesColors: string[]; -} - -export const tooltipsPlugin = ( - { - closeOnMouseExit, - getXTooltipHeader, - getXTooltipYLabels, - isShownEmptyVal, - seriesColors, - }: Props = { - isShownEmptyVal: true, - seriesColors: [], - }, -): Plugin => { - let barEl: HTMLDivElement | null = null; - let displayedIdx: number | null = null; - let tooltipEl: HTMLDivElement | null = null; - - const _buildTooltipHtml = (uPlot: uPlot, idx: number): string => { - let html = ''; - - const header: ChartTooltip = - typeof getXTooltipHeader === 'function' ? getXTooltipHeader(idx) : ''; - - const yLabels: ChartTooltip[] = - typeof getXTooltipYLabels === 'function' ? getXTooltipYLabels(idx) : []; - - const xSerie = uPlot.series[0]; - const xValue = - typeof xSerie.value === 'function' - ? xSerie.value(uPlot, uPlot.data[0][idx], 0, idx) - : uPlot.data[0][idx]; - html += ` -
    - ${header} - ${xSerie.label} ${xValue} -
    `; - - let minYDist = 1000; - const seriesValues: Array = uPlot.series - .map((serie, i) => { - if (serie.scale === 'x' || !serie.show) return; - - const label = yLabels[i - 1] || null; - const valueRaw = uPlot.data[i][idx]; - - const cssClass = valueRaw !== null ? css.valueY : css.valueYEmpty; - if (isShownEmptyVal || valueRaw || valueRaw === 0) { - const log = Math.log10(Math.abs(valueRaw || 0)); - const precision = log > -5 ? 6 - Math.max(0, Math.ceil(log)) : undefined; - const yDist = Math.abs(uPlot.valToPos(valueRaw || 0, 'y') - (uPlot.cursor.top || 0)); - minYDist = Math.min(minYDist, yDist); - - return { - html: ` -
    - - ${label ? label + '
    ' : ''} - ${serie.label}: ${valueRaw != null ? humanReadableNumber(valueRaw, precision) : 'N/A'} -
    `, - val: valueRaw, - yDist, - }; - } - return { val: null }; - }) - .filter((val) => val?.val !== null && !!val?.html); - - html += seriesValues - .sort((a, b) => { - if (!a || !b) { - return 0; - } - if (a.val === null) { - if (b.val === null) { - return 0; - } - return 1; - } else if (b.val === null) { - return -1; - } - return (b.val || 0) - (a.val || 0); - }) - .map((seriesValue) => { - if (seriesValue?.yDist === minYDist) { - return `${seriesValue?.html || ''}`; - } - return seriesValue?.html || ''; - }) - .join(''); - - return html; - }; - - const _getTooltipLeftPx = (uPlot: uPlot, idx: number): number => { - const margin = 32; - const idxLeft = uPlot.valToPos(uPlot.data[0][idx], 'x'); - if (!tooltipEl) return idxLeft; - - const chartWidth = uPlot.root.querySelector('.u-over')?.getBoundingClientRect().width; - const tooltipWidth = tooltipEl.getBoundingClientRect().width; - - // right - if (chartWidth && idxLeft + tooltipWidth >= chartWidth * 0.9) { - return Math.max(0, idxLeft - tooltipWidth - margin); - } - - // left - return idxLeft + margin; - }; - - const _updateTooltipVerticalPosition = (uPlot: uPlot, cursorTop: number) => { - if (!tooltipEl) return; - - const chartHeight = uPlot.root.querySelector('.u-over')?.getBoundingClientRect().height; - - const vPos = chartHeight && cursorTop > chartHeight / 2 ? 'top' : 'bottom'; - - tooltipEl.style.bottom = vPos === 'bottom' ? '0px' : 'auto'; - tooltipEl.style.top = vPos === 'top' ? '0px' : 'auto'; - }; - - const showIdx = (uPlot: uPlot, idx: number) => { - if (!tooltipEl || !barEl) return; - displayedIdx = idx; - - const idxLeft = uPlot.valToPos(uPlot.data[0][idx], 'x'); - - barEl.style.display = 'block'; - barEl.style.left = idxLeft + 'px'; - - tooltipEl.innerHTML = _buildTooltipHtml(uPlot, idx); - tooltipEl.style.display = 'block'; - tooltipEl.style.left = _getTooltipLeftPx(uPlot, idx) + 'px'; - }; - - const hide = () => { - if (!tooltipEl || !barEl) return; - displayedIdx = null; - - barEl.style.display = 'none'; - tooltipEl.style.display = 'none'; - }; - - return { - hooks: { - init: (uPlot: uPlot) => { - uPlot.over.onmouseenter = (e) => { - const originElement = e.relatedTarget as Element; - if (!originElement?.className?.includes('tooltip')) { - hide(); - } - }; - if (closeOnMouseExit) { - uPlot.over.onmouseout = () => { - hide(); - }; - } - }, - ready: (uPlot: uPlot) => { - tooltipEl = document.createElement('div'); - tooltipEl.className = css.tooltip; - uPlot.root.querySelector('.u-over')?.appendChild(tooltipEl); - - barEl = document.createElement('div'); - barEl.className = css.bar; - uPlot.root.querySelector('.u-over')?.appendChild(barEl); - }, - setCursor: (uPlot: uPlot) => { - const { left, idx, top } = uPlot.cursor; - - if (!left || left < 0 || !top || top < 0 || idx == null) { - hide(); - return; - } - - const seriesWithXValue = uPlot.series.find( - (serie, serieId) => serie.scale !== 'x' && serie.show && uPlot.data[serieId][idx] != null, - ); - if (seriesWithXValue) { - showIdx(uPlot, idx); - } else { - hide(); - } - - if (displayedIdx) { - _updateTooltipVerticalPosition(uPlot, top); - } - }, - }, - }; -}; diff --git a/webui/react/src/components/kit/internal/UPlot/UPlotChart/trackAxis.module.scss b/webui/react/src/components/kit/internal/UPlot/UPlotChart/trackAxis.module.scss deleted file mode 100644 index 498e9f260e7..00000000000 --- a/webui/react/src/components/kit/internal/UPlot/UPlotChart/trackAxis.module.scss +++ /dev/null @@ -1,3 +0,0 @@ -.trackAxis { - box-shadow: -1px 1px var(--theme-surface-border-strong); -} diff --git a/webui/react/src/components/kit/internal/UPlot/UPlotChart/trackAxis.ts b/webui/react/src/components/kit/internal/UPlot/UPlotChart/trackAxis.ts deleted file mode 100644 index 508541a236a..00000000000 --- a/webui/react/src/components/kit/internal/UPlot/UPlotChart/trackAxis.ts +++ /dev/null @@ -1,13 +0,0 @@ -import uPlot, { Plugin } from 'uplot'; - -import css from './trackAxis.module.scss'; - -export const trackAxis = (): Plugin => { - return { - hooks: { - ready: (uPlot: uPlot) => { - uPlot.root.querySelector('.u-over')?.classList.add(css.trackAxis); - }, - }, - }; -}; diff --git a/webui/react/src/components/kit/internal/UPlot/types.ts b/webui/react/src/components/kit/internal/UPlot/types.ts deleted file mode 100644 index 9ec410afea5..00000000000 --- a/webui/react/src/components/kit/internal/UPlot/types.ts +++ /dev/null @@ -1,32 +0,0 @@ -import uPlot from 'uplot'; - -export type UPlotData = number | null | undefined; -export type FacetedData = [ - null: null, - series: [ - xValues: UPlotData[], - yValues: UPlotData[], - sizes: UPlotData[] | null, - fills: UPlotData[] | null, - strokes: UPlotData[] | null, - labels: (number | string)[] | null, - ], -]; - -export type UPlotAxisSplits = ( - u: uPlot, - axisIndex: number, - min: UPlotData, - max: UPlotData, -) => number[]; - -export interface UPlotScatterProps { - data: FacetedData; - options: Partial; - tooltipLabels: (string | null)[]; -} - -export interface UPlotPoint { - idx: number; - seriesIdx: number; -} diff --git a/webui/react/src/components/kit/internal/color.ts b/webui/react/src/components/kit/internal/color.ts deleted file mode 100644 index bb91c7f1351..00000000000 --- a/webui/react/src/components/kit/internal/color.ts +++ /dev/null @@ -1,121 +0,0 @@ -/* - * r - red between 0 and 255 - * g - green between 0 and 255 - * b - blue between 0 and 255 - * a - alpha between 0.0 and 1.0 - */ -interface RgbaColor { - a?: number; - b: number; - g: number; - r: number; -} - -/** CIELAB color space */ -interface CIELAB { - a: number; - b: number; - /** perceptual lightness */ - l: number; -} - -const hexRegex = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i; -const hslRegex = /^hsl\(\d+,\s*\d+%,\s*\d+%\)$/i; -const rgbaRegex = /^rgba?\(\s*?(\d+)\s*?,\s*?(\d+)\s*?,\s*?(\d+)\s*?(,\s*?([\d.]+)\s*?)?\)$/i; - -export const isColor = (color: string): boolean => { - return hexRegex.test(color) || hslRegex.test(color) || rgbaRegex.test(color); -}; - -export const hex2rgb = (hex: string): RgbaColor => { - const rgb = { b: 0, g: 0, r: 0 }; - const result = hexRegex.exec(hex); - - if (result && result.length > 3) { - rgb.r = parseInt(result[1], 16); - rgb.g = parseInt(result[2], 16); - rgb.b = parseInt(result[3], 16); - } - - return rgb; -}; - -export const rgba2str = (rgba: RgbaColor): string => { - if (rgba.a != null) { - return `rgba(${rgba.r}, ${rgba.g}, ${rgba.b}, ${rgba.a})`; - } - return `rgb(${rgba.r}, ${rgba.g}, ${rgba.b})`; -}; - -export const rgbaMix = ( - rgba0: RgbaColor, - rgba1: RgbaColor, - amount: number, - rounded = true, -): RgbaColor => { - const dr = rgba1.r - rgba0.r; - const dg = rgba1.g - rgba0.g; - const db = rgba1.b - rgba0.b; - const da = (rgba1.a ?? 1.0) - (rgba0.a ?? 1.0); - const [adr, adg, adb, ada] = [dr, dg, db, da].map((x) => Math.abs(x)); - const delta = adr + adg + adb + 255 * ada; - if (delta === 0) return rgba0; - - const [pr, pg, pb, pa] = [dr, dg, db, da].map((x) => (x * amount) / delta); - const r = Math.min(255, Math.max(0, rgba0.r + pr)); - const g = Math.min(255, Math.max(0, rgba0.g + pg)); - const b = Math.min(255, Math.max(0, rgba0.b + pb)); - const a = Math.min(1.0, Math.max(0.0, (rgba0.a ?? 1.0) + pa)); - return { - a, - b: rounded ? Math.round(b) : b, - g: rounded ? Math.round(g) : g, - r: rounded ? Math.round(r) : r, - }; -}; - -export const str2rgba = (str: string): RgbaColor => { - if (hexRegex.test(str)) return hex2rgb(str); - - const regex = rgbaRegex; - const result = regex.exec(str); - if (result && result.length > 3) { - const rgba = { a: 1.0, b: 0, g: 0, r: 0 }; - rgba.r = parseInt(result[1]); - rgba.g = parseInt(result[2]); - rgba.b = parseInt(result[3]); - if (result.length > 5 && result[5] != null) rgba.a = parseFloat(result[5]); - return rgba; - } - - return { a: 0.0, b: 0, g: 0, r: 0 }; -}; - -/** convert rgb to CIELAB color. ignores alpha values */ -export const rgb2lab = (rgb: RgbaColor): CIELAB => { - const [r, g, b] = [rgb.r / 255, rgb.g / 255, rgb.b / 255]; - const [x, y, z] = [ - r * 0.4124 + g * 0.3576 + b * 0.1805, - r * 0.2126 + g * 0.7152 + b * 0.0722, - r * 0.0193 + g * 0.1192 + b * 0.9505, - ]; - const [l, a, bb] = [116 * y ** 2 - 16, 500 * (x - y), 200 * (y - z)]; - return { a, b: bb, l }; -}; - -/** calculate euclidean distance between two n dimentional points */ -const pointDistance = (p0: number[], p1: number[]): number => { - let sum = 0; - if (p0.length !== p1.length) { - throw new Error('points must be of same dimension'); - } - for (let i = 0; i < p0.length; i++) { - sum += (p1[i] - p0[i]) ** 2; - } - return Math.sqrt(sum); -}; - -/** calculate euclidean distance between two CIELAB colors */ -export const labDistance = (lab0: CIELAB, lab1: CIELAB): number => { - return pointDistance([lab0.l, lab0.a, lab0.b], [lab1.l, lab1.a, lab1.b]); -}; diff --git a/webui/react/src/components/kit/internal/fonts.ts b/webui/react/src/components/kit/internal/fonts.ts deleted file mode 100644 index 92e06903534..00000000000 --- a/webui/react/src/components/kit/internal/fonts.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { ValueOf } from 'components/kit/internal/types'; - -export const ThemeFont = { - Code: 'var(--theme-font-family-code)', - UI: 'var(--theme-font-family)', -} as const; - -export const TypographySize = { - default: 'default', - L: 'L', - S: 'S', - XL: 'XL', - XS: 'XS', -} as const; - -export type TypographySize = ValueOf; diff --git a/webui/react/src/components/kit/internal/functions.ts b/webui/react/src/components/kit/internal/functions.ts deleted file mode 100644 index db4075991da..00000000000 --- a/webui/react/src/components/kit/internal/functions.ts +++ /dev/null @@ -1,569 +0,0 @@ -import ansiConverter from 'ansi-to-html'; -import dayjs from 'dayjs'; -import utc from 'dayjs/plugin/utc'; -dayjs.extend(utc); - -import { Metric, NullOrUndefined } from 'components/kit/internal/types'; - -const GLASBEY = [ - [0, 155, 222], - [87, 43, 255], - [158, 73, 209], - [184, 125, 112], - [0, 128, 90], - [253, 229, 0], - [149, 75, 119], - [140, 213, 104], - [114, 58, 62], - [63, 65, 172], - [102, 162, 214], - [206, 105, 193], - [94, 89, 106], - [237, 172, 136], - [106, 166, 160], - [230, 170, 210], - [99, 0, 136], - [219, 253, 0], - [25, 40, 104], - [255, 66, 180], - [197, 89, 14], - [67, 135, 23], - [0, 211, 145], - [255, 90, 249], - [102, 116, 91], - [179, 174, 142], - [140, 125, 156], - [198, 0, 70], - [46, 78, 108], - [70, 109, 166], - [115, 137, 158], - [202, 175, 168], - [167, 141, 206], - [100, 254, 0], - [0, 121, 146], - [161, 99, 255], - [216, 255, 245], - [241, 140, 1], - [160, 172, 20], - [90, 46, 91], - [158, 134, 137], - [187, 204, 208], - [197, 175, 212], - [109, 221, 219], - [244, 255, 208], - [134, 101, 0], - [99, 105, 0], - [104, 65, 168], - [197, 151, 45], - [255, 116, 169], - [94, 187, 39], - [0, 183, 88], - [167, 255, 203], - [171, 122, 164], - [148, 189, 255], - [193, 226, 137], - [255, 201, 15], - [197, 0, 213], - [138, 109, 99], - [143, 133, 105], - [83, 78, 75], - [104, 96, 171], - [213, 182, 122], - [23, 90, 44], - [37, 0, 154], - [243, 209, 190], - [104, 111, 138], - [107, 165, 106], - [104, 84, 134], - [186, 205, 174], - [127, 153, 136], - [0, 220, 203], - [145, 4, 155], - [27, 188, 235], - [210, 156, 235], - [111, 0, 112], - [50, 161, 177], - [147, 108, 202], - [164, 70, 65], - [138, 140, 229], - [0, 69, 213], - [203, 139, 199], - [151, 150, 183], - [118, 32, 212], - [204, 75, 114], - [0, 78, 104], - [56, 34, 104], - [79, 86, 56], - [171, 187, 111], - [49, 58, 134], - [152, 211, 165], - [143, 175, 185], - [223, 228, 216], - [224, 0, 171], - [219, 193, 203], - [140, 223, 255], - [77, 83, 227], - [111, 105, 102], - [28, 0, 255], - [115, 45, 83], - [108, 145, 78], - [17, 109, 168], - [38, 159, 255], - [176, 163, 95], - [87, 133, 200], - [152, 89, 146], - [255, 161, 163], - [186, 186, 254], - [136, 42, 37], - [168, 230, 219], - [167, 242, 151], - [214, 148, 103], - [64, 91, 186], - [146, 93, 58], - [47, 79, 54], - [150, 124, 39], - [155, 149, 138], - [87, 180, 208], - [100, 71, 0], - [47, 93, 95], - [65, 142, 142], - [19, 63, 173], - [60, 150, 106], - [133, 61, 161], - [186, 183, 191], - [103, 198, 172], - [207, 105, 101], - [0, 176, 146], - [218, 227, 44], - [54, 111, 1], - [83, 121, 255], - [127, 129, 66], - [0, 233, 79], - [40, 84, 153], - [0, 10, 93], - [88, 0, 163], - [0, 136, 12], - [167, 131, 90], - [251, 236, 255], - [1, 105, 75], - [212, 118, 136], - [255, 199, 230], - [218, 255, 165], - [120, 111, 216], - [75, 2, 223], - [92, 104, 106], - [162, 107, 120], - [103, 128, 126], - [134, 71, 90], - [202, 0, 0], - [43, 0, 124], - [114, 255, 151], - [225, 227, 182], - [201, 83, 220], - [52, 120, 119], - [142, 190, 88], -]; - -const isBigInt = (data: unknown): data is bigint => typeof data === 'bigint'; -const isBoolean = (data: unknown): data is boolean => typeof data === 'boolean'; -const isMap = (data: unknown): data is Map => data instanceof Map; -const isNullOrUndefined = (data: unknown): data is null | undefined => data == null; -export const isNumber = (data: unknown): data is number => typeof data === 'number'; -export const isObject = (data: unknown): boolean => { - return typeof data === 'object' && !Array.isArray(data) && !isSet(data) && data !== null; -}; -const isPrimitive = (data: unknown): boolean => - isBigInt(data) || - isBoolean(data) || - isNullOrUndefined(data) || - isNumber(data) || - isString(data) || - isSymbol(data); -const isSet = (data: unknown): data is Set => data instanceof Set; -export const isString = (data: unknown): data is string => typeof data === 'string'; -const isSymbol = (data: unknown): data is symbol => typeof data === 'symbol'; - -/* - * Sort numbers and strings with the following properties. - * - case insensitive - * - numbers come before string - * - place `null` and `undefined` at the end of numbers and strings - */ -export const alphaNumericSorter = ( - a: NullOrUndefined, - b: NullOrUndefined, -): number => { - // Handle undefined and null cases. - if (a == null || b == null) return nullSorter(a, b); - - // Sort with English locale. - return a.toString().localeCompare(b.toString(), 'en', { numeric: true }); -}; - -/* - * This also handles `undefined` and treats it equally as `null`. - * NOTE: `undefined == null` is true (double equal sign not triple) - */ -const nullSorter = (a: unknown, b: unknown): number => { - if (a != null && b == null) return -1; - if (a == null && b != null) return 1; - return 0; -}; - -export const toHtmlId = (str: string): string => { - return str - .replace(/[\s_]/gi, '-') - .replace(/[^a-z0-9-]/gi, '') - .toLowerCase(); -}; - -export const truncate = (str: string, maxLength = 20, suffix = '...'): string => { - if (maxLength < suffix.length + 1) { - maxLength = suffix.length + 1; - } - if (str.length <= maxLength) { - return str; - } - return str.slice(0, maxLength - suffix.length) + suffix; -}; - -export const copyToClipboard = async (content: string): Promise => { - try { - // This method is only available on https and localhost - await navigator.clipboard.writeText(content); - } catch (e) { - throw new Error('Clipboard access on https and localhost only!'); - } -}; - -const LETTERS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; -const CHARACTERS = `0123456789${LETTERS}`; -const DEFAULT_ALPHA_NUMERIC_LENGTH = 8; - -export const generateAlphaNumeric = ( - length = DEFAULT_ALPHA_NUMERIC_LENGTH, - chars = CHARACTERS, -): string => { - let result = ''; - for (let i = length; i > 0; --i) { - result += chars[Math.floor(Math.random() * chars.length)]; - } - return result; -}; - -export const generateUUID = (): string => { - return [ - generateAlphaNumeric(8), - generateAlphaNumeric(4), - generateAlphaNumeric(4), - generateAlphaNumeric(4), - generateAlphaNumeric(12), - ].join('-'); -}; - -// eslint-disable-next-line -export const clone = (data: any, deep = true): any => { - if (isPrimitive(data)) return data; - if (isMap(data)) return new Map(data); - if (isSet(data)) return new Set(data); - return deep ? JSON.parse(JSON.stringify(data)) : { ...data }; -}; - -const DEFAULT_DATETIME_FORMAT = 'YYYY-MM-DD, HH:mm:ss'; - -export const formatDatetime = ( - datetime: string, - options: { format?: string; inputUTC?: boolean; outputUTC?: boolean } = {}, -): string => { - const config = { - format: DEFAULT_DATETIME_FORMAT, - inputUTC: false, - outputUTC: true, - ...options, - }; - // Strip out the timezone info if we want to force UTC input. - const dateString = config.inputUTC ? stripTimezone(datetime) : datetime; - - // `dayjs.utc` respects timezone in the datetime string if available. - let dayjsDate = dayjs.utc(dateString); - - // Prep the date as UTC or local time based on output UTC option. - if (!config.outputUTC) dayjsDate = dayjsDate.local(); - - // Return the formatted date based on provided format. - return dayjsDate.format(config.format); -}; - -const stripTimezone = (datetime: string): string => { - const timezoneRegex = /(Z|(-|\+)\d{2}:\d{2})$/; - return datetime.replace(timezoneRegex, ''); -}; - -/* - * Sorts ISO 8601 datetime strings. - * https://tc39.es/ecma262/#sec-date-time-string-format - */ -export const dateTimeStringSorter = ( - a: NullOrUndefined, - b: NullOrUndefined, -): number => { - // Handle undefined and null cases. - if (a == null || b == null) return nullSorter(a, b); - - // Compare as date objects. - const [aTime, bTime] = [new Date(a).getTime(), new Date(b).getTime()]; - if (aTime === bTime) return 0; - return aTime < bTime ? -1 : 1; -}; - -export const numericSorter = (a: NullOrUndefined, b: NullOrUndefined): number => { - // Handle undefined and null cases. - if (a == null || b == null) return nullSorter(a, b); - - // Sort by numeric type. - if (a === b) return 0; - return a < b ? -1 : 1; -}; - -const converter = new ansiConverter({ newline: true }); - -export const ansiToHtml = (ansi: string): string => { - const ansiWithHtml = ansi - .replace(/(&|\u0026)/g, '&') - .replace(/(>|\u003e)/g, '>') - .replace(/(<|\u003c)/g, '<') - .replace(/('|\u0027)/g, ''') - .replace(/("|\u0022)/g, '"'); - return converter.toHtml(ansiWithHtml); -}; - -/** titlecase a sentence */ -export const capitalize = (str: string): string => { - return str - .split(/\s+/) - .map((part) => capitalizeWord(part)) - .join(' '); -}; - -const capitalizeWord = (str: string): string => { - return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase(); -}; - -export const getCssVar = (name: string): string => { - const varName = name.replace(/^(var\()?(.*?)\)?$/i, '$2'); - return window.getComputedStyle(document.body)?.getPropertyValue(varName); -}; - -export const glasbeyColor = (sequence: number): string => { - const index = sequence % GLASBEY.length; - const rgb = GLASBEY[index]; - return `rgb(${rgb[0]}, ${rgb[1]}, ${rgb[2]})`; -}; - -export const getTimeTickValues: uPlot.Axis.Values = (_self, rawValue) => { - return rawValue.map((val) => dayjs.unix(val).format('hh:mm:ss.SSS').slice(0, -2)); -}; - -const DEFAULT_PRECISION = 6; -export const humanReadableNumber = (num: number, precision = DEFAULT_PRECISION): string => { - const stringNum = num.toString(); - let content: string = stringNum; - - if (isNaN(num)) { - content = 'NaN'; - } else if (!Number.isFinite(num)) { - content = `${num < 0 ? '-' : ''}Infinity`; - } else if (!Number.isInteger(num)) { - content = num.toFixed(Math.max(precision, 0)); - - const absoluteNum = Math.abs(num); - if (absoluteNum < 0.01 || absoluteNum > 999) { - content = num.toExponential(Math.max(precision, 0)); - } - } - - return content; -}; - -// credits: https://gist.github.com/Izhaki/834a9d37d1ad34c6179b6a16e670b526 -export const findInsertionIndex = ( - sortedArray: number[], - value: number, - compareFn: (a: number, b: number) => number = (a, b) => a - b, -): number => { - // empty array - if (sortedArray.length === 0) return 0; - - // value beyond current sortedArray range - if (compareFn(value, sortedArray[sortedArray.length - 1]) >= 0) return sortedArray.length; - - const getMidPoint = (start: number, end: number): number => Math.floor((end - start) / 2) + start; - - let iEnd = sortedArray.length - 1; - let iStart = 0; - - let iMiddle = getMidPoint(iStart, iEnd); - - // binary search - while (iStart < iEnd) { - const comparison = compareFn(value, sortedArray[iMiddle]); - - // found match - if (comparison === 0) return iMiddle; - - if (comparison < 0) { - // target is lower in array, move the index halfway down - iEnd = iMiddle; - } else { - // target is higher in array, move the index halfway up - iStart = iMiddle + 1; - } - iMiddle = getMidPoint(iStart, iEnd); - } - - return iMiddle; -}; - -export function distance(x0: number, y0: number, x1: number, y1: number): number { - return Math.sqrt((x1 - x0) ** 2 + (y1 - y0) ** 2); -} - -/* - * h - hue between 0 and 360 - * s - saturation between 0.0 and 1.0 - * l - lightness between 0.0 and 1.0 - */ -interface HslColor { - h: number; - l: number; - s: number; -} - -/* - * r - red between 0 and 255 - * g - green between 0 and 255 - * b - blue between 0 and 255 - * a - alpha between 0.0 and 1.0 - */ -interface RgbaColor { - a?: number; - b: number; - g: number; - r: number; -} -const hexRegex = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i; -const rgbaRegex = /^rgba?\(\s*?(\d+)\s*?,\s*?(\d+)\s*?,\s*?(\d+)\s*?(,\s*?([\d.]+)\s*?)?\)$/i; - -export const rgba2str = (rgba: RgbaColor): string => { - if (rgba.a != null) { - return `rgba(${rgba.r}, ${rgba.g}, ${rgba.b}, ${rgba.a})`; - } - return `rgb(${rgba.r}, ${rgba.g}, ${rgba.b})`; -}; - -export const rgbaFromGradient = ( - rgba0: RgbaColor, - rgba1: RgbaColor, - percent: number, -): RgbaColor => { - const r = Math.round((rgba1.r - rgba0.r) * percent + rgba0.r); - const g = Math.round((rgba1.g - rgba0.g) * percent + rgba0.g); - const b = Math.round((rgba1.b - rgba0.b) * percent + rgba0.b); - - if (rgba0.a != null && rgba1.a != null) { - const a = (rgba1.a - rgba0.a) * percent + rgba0.a; - return { a, b, g, r }; - } - - return { b, g, r }; -}; - -export const hex2rgb = (hex: string): RgbaColor => { - const rgb = { b: 0, g: 0, r: 0 }; - const result = hexRegex.exec(hex); - - if (result && result.length > 3) { - rgb.r = parseInt(result[1], 16); - rgb.g = parseInt(result[2], 16); - rgb.b = parseInt(result[3], 16); - } - - return rgb; -}; - -export const str2rgba = (str: string): RgbaColor => { - if (hexRegex.test(str)) return hex2rgb(str); - - const regex = rgbaRegex; - const result = regex.exec(str); - if (result && result.length > 3) { - const rgba = { a: 1.0, b: 0, g: 0, r: 0 }; - rgba.r = parseInt(result[1]); - rgba.g = parseInt(result[2]); - rgba.b = parseInt(result[3]); - if (result.length > 5 && result[5] != null) rgba.a = parseFloat(result[5]); - return rgba; - } - - return { a: 0.0, b: 0, g: 0, r: 0 }; -}; - -export const hex2hsl = (hex: string): HslColor => { - return rgba2hsl(hex2rgb(hex)); -}; - -export const rgba2hsl = (rgba: RgbaColor): HslColor => { - const r = rgba.r / 255; - const g = rgba.g / 255; - const b = rgba.b / 255; - const max = Math.max(r, g, b); - const min = Math.min(r, g, b); - const avg = (max + min) / 2; - const hsl: HslColor = { h: Math.round(Math.random() * 6), l: 0.5, s: 0.5 }; - - hsl.h = hsl.s = hsl.l = avg; - - if (max === min) { - hsl.h = hsl.s = 0; // achromatic - } else { - const d = max - min; - hsl.s = hsl.l > 0.5 ? d / (2 - max - min) : d / (max + min); - switch (max) { - case r: - hsl.h = (g - b) / d + (g < b ? 6 : 0); - break; - case g: - hsl.h = (b - r) / d + 2; - break; - case b: - hsl.h = (r - g) / d + 4; - break; - } - } - - hsl.h = Math.round((360 * hsl.h) / 6); - hsl.s = Math.round(hsl.s * 100); - hsl.l = Math.round(hsl.l * 100); - - return hsl; -}; - -export const hsl2str = (hsl: HslColor): string => { - return `hsl(${hsl.h}, ${hsl.s}%, ${hsl.l}%)`; -}; - -const METRIC_KEY_DELIMITER = '.'; - -export const metricToStr = (metric: Metric, truncateLimit = 30): string => { - /** - * TODO - also see `src/components/MetricBadgeTag.tsx' - * Metric group may sometimes end up being `undefined` when an old metric setting - * is restored and the UI attempts to use it. Adding a safeguard for now. - * Better approach of hunting down all the places it can be stored as a setting - * and validating it upon loading and discarding it if invalid. - */ - const label = !metric.group - ? metric.name - : [metric.group, metric.name].join(METRIC_KEY_DELIMITER); - return label.length > truncateLimit ? label.substring(0, truncateLimit) + '...' : label; -}; diff --git a/webui/react/src/components/kit/internal/md5.ts b/webui/react/src/components/kit/internal/md5.ts deleted file mode 100644 index e2475308c55..00000000000 --- a/webui/react/src/components/kit/internal/md5.ts +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Updated to Typescript from the original source: - * http://www.myersdaily.org/joseph/javascript/md5-text.html - */ -/* eslint-disable */ -const md5cycle = (x: number[], k: number[]): void => { - let a = x[0], - b = x[1], - c = x[2], - d = x[3]; - - a = ff(a, b, c, d, k[0], 7, -680876936); - d = ff(d, a, b, c, k[1], 12, -389564586); - c = ff(c, d, a, b, k[2], 17, 606105819); - b = ff(b, c, d, a, k[3], 22, -1044525330); - a = ff(a, b, c, d, k[4], 7, -176418897); - d = ff(d, a, b, c, k[5], 12, 1200080426); - c = ff(c, d, a, b, k[6], 17, -1473231341); - b = ff(b, c, d, a, k[7], 22, -45705983); - a = ff(a, b, c, d, k[8], 7, 1770035416); - d = ff(d, a, b, c, k[9], 12, -1958414417); - c = ff(c, d, a, b, k[10], 17, -42063); - b = ff(b, c, d, a, k[11], 22, -1990404162); - a = ff(a, b, c, d, k[12], 7, 1804603682); - d = ff(d, a, b, c, k[13], 12, -40341101); - c = ff(c, d, a, b, k[14], 17, -1502002290); - b = ff(b, c, d, a, k[15], 22, 1236535329); - - a = gg(a, b, c, d, k[1], 5, -165796510); - d = gg(d, a, b, c, k[6], 9, -1069501632); - c = gg(c, d, a, b, k[11], 14, 643717713); - b = gg(b, c, d, a, k[0], 20, -373897302); - a = gg(a, b, c, d, k[5], 5, -701558691); - d = gg(d, a, b, c, k[10], 9, 38016083); - c = gg(c, d, a, b, k[15], 14, -660478335); - b = gg(b, c, d, a, k[4], 20, -405537848); - a = gg(a, b, c, d, k[9], 5, 568446438); - d = gg(d, a, b, c, k[14], 9, -1019803690); - c = gg(c, d, a, b, k[3], 14, -187363961); - b = gg(b, c, d, a, k[8], 20, 1163531501); - a = gg(a, b, c, d, k[13], 5, -1444681467); - d = gg(d, a, b, c, k[2], 9, -51403784); - c = gg(c, d, a, b, k[7], 14, 1735328473); - b = gg(b, c, d, a, k[12], 20, -1926607734); - - a = hh(a, b, c, d, k[5], 4, -378558); - d = hh(d, a, b, c, k[8], 11, -2022574463); - c = hh(c, d, a, b, k[11], 16, 1839030562); - b = hh(b, c, d, a, k[14], 23, -35309556); - a = hh(a, b, c, d, k[1], 4, -1530992060); - d = hh(d, a, b, c, k[4], 11, 1272893353); - c = hh(c, d, a, b, k[7], 16, -155497632); - b = hh(b, c, d, a, k[10], 23, -1094730640); - a = hh(a, b, c, d, k[13], 4, 681279174); - d = hh(d, a, b, c, k[0], 11, -358537222); - c = hh(c, d, a, b, k[3], 16, -722521979); - b = hh(b, c, d, a, k[6], 23, 76029189); - a = hh(a, b, c, d, k[9], 4, -640364487); - d = hh(d, a, b, c, k[12], 11, -421815835); - c = hh(c, d, a, b, k[15], 16, 530742520); - b = hh(b, c, d, a, k[2], 23, -995338651); - - a = ii(a, b, c, d, k[0], 6, -198630844); - d = ii(d, a, b, c, k[7], 10, 1126891415); - c = ii(c, d, a, b, k[14], 15, -1416354905); - b = ii(b, c, d, a, k[5], 21, -57434055); - a = ii(a, b, c, d, k[12], 6, 1700485571); - d = ii(d, a, b, c, k[3], 10, -1894986606); - c = ii(c, d, a, b, k[10], 15, -1051523); - b = ii(b, c, d, a, k[1], 21, -2054922799); - a = ii(a, b, c, d, k[8], 6, 1873313359); - d = ii(d, a, b, c, k[15], 10, -30611744); - c = ii(c, d, a, b, k[6], 15, -1560198380); - b = ii(b, c, d, a, k[13], 21, 1309151649); - a = ii(a, b, c, d, k[4], 6, -145523070); - d = ii(d, a, b, c, k[11], 10, -1120210379); - c = ii(c, d, a, b, k[2], 15, 718787259); - b = ii(b, c, d, a, k[9], 21, -343485551); - - x[0] = add32(a, x[0]); - x[1] = add32(b, x[1]); - x[2] = add32(c, x[2]); - x[3] = add32(d, x[3]); -}; - -const cmn = (q: number, a: number, b: number, x: number, s: number, t: number): number => { - a = add32(add32(a, q), add32(x, t)); - return add32((a << s) | (a >>> (32 - s)), b); -}; - -const ff = ( - a: number, - b: number, - c: number, - d: number, - x: number, - s: number, - t: number, -): number => { - return cmn((b & c) | (~b & d), a, b, x, s, t); -}; - -const gg = ( - a: number, - b: number, - c: number, - d: number, - x: number, - s: number, - t: number, -): number => { - return cmn((b & d) | (c & ~d), a, b, x, s, t); -}; - -const hh = ( - a: number, - b: number, - c: number, - d: number, - x: number, - s: number, - t: number, -): number => { - return cmn(b ^ c ^ d, a, b, x, s, t); -}; - -const ii = ( - a: number, - b: number, - c: number, - d: number, - x: number, - s: number, - t: number, -): number => { - return cmn(c ^ (b | ~d), a, b, x, s, t); -}; - -const add32 = (a: number, b: number): number => { - return (a + b) & 0xffffffff; -}; - -const md51 = (s: string): number[] => { - let txt = ''; - let n = s.length, - state = [1732584193, -271733879, -1732584194, 271733878], - i; - for (i = 64; i <= s.length; i += 64) { - md5cycle(state, md5blk(s.substring(i - 64, i))); - } - s = s.substring(i - 64); - let tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - for (i = 0; i < s.length; i++) tail[i >> 2] |= s.charCodeAt(i) << (i % 4 << 3); - tail[i >> 2] |= 0x80 << (i % 4 << 3); - if (i > 55) { - md5cycle(state, tail); - for (i = 0; i < 16; i++) tail[i] = 0; - } - tail[14] = n * 8; - md5cycle(state, tail); - return state; -}; - -/* there needs to be support for Unicode here, - * unless we pretend that we can redefine the MD-5 - * algorithm for multi-byte characters (perhaps - * by adding every four 16-bit characters and - * shortening the sum to 32 bits). Otherwise - * I suggest performing MD-5 as if every character - * was two bytes--e.g., 0040 0025 = @%--but then - * how will an ordinary MD-5 sum be matched? - * There is no way to standardize text to something - * like UTF-8 before transformation; speed cost is - * utterly prohibitive. The JavaScript standard - * itself needs to look at this: it should start - * providing access to strings as preformed UTF-8 - * 8-bit unsigned value arrays. - */ -const md5blk = (s: string): number[] => { - /* I figured global was faster. */ - let md5blks: number[] = [], - i; /* Andy King said do it this way. */ - for (i = 0; i < 64; i += 4) { - md5blks[i >> 2] = - s.charCodeAt(i) + - (s.charCodeAt(i + 1) << 8) + - (s.charCodeAt(i + 2) << 16) + - (s.charCodeAt(i + 3) << 24); - } - return md5blks; -}; - -const hex_chr = '0123456789abcdef'.split(''); - -const rhex = (n: number): string => { - let s = '', - j = 0; - for (; j < 4; j++) s += hex_chr[(n >> (j * 8 + 4)) & 0x0f] + hex_chr[(n >> (j * 8)) & 0x0f]; - return s; -}; - -const hex = (x: number[]): string => { - return x.map((r) => rhex(r)).join(''); -}; - -const md5 = (s: string): string => { - return hex(md51(s)); -}; - -export default md5; diff --git a/webui/react/src/components/kit/internal/monokai.css b/webui/react/src/components/kit/internal/monokai.css deleted file mode 100644 index 5da3a6a0f4a..00000000000 --- a/webui/react/src/components/kit/internal/monokai.css +++ /dev/null @@ -1,3308 +0,0 @@ -/* stylelint-disable */ -.ipynb-renderer-root { - background-color: var(--theme-surface); - padding: 8px; -} -.ipynb-renderer-root div#notebook { - font-family: sans-serif; - font-size: 13pt; - line-height: 170%; - color: #f8f8f0; - -webkit-font-smoothing: antialiased !important; - padding-top: 25px !important; -} -.ipynb-renderer-root body, -.ipynb-renderer-root div.body { - font-family: sans-serif; - font-size: 13pt; - color: #f8f8f0; - background-color: #1e1e1e; - background: #1e1e1e; - -webkit-font-smoothing: antialiased !important; -} -.ipynb-renderer-root body.notebook_app { - padding: 0; - background-color: #1e1e1e; - background: #1e1e1e; - padding-right: 0px !important; - overflow-y: hidden; -} -.ipynb-renderer-root a { - font-family: sans-serif; - color: #f8f8f0; - -webkit-font-smoothing: antialiased !important; -} -.ipynb-renderer-root a:hover, -.ipynb-renderer-root a:focus { - color: #f8f8f0; - -webkit-font-smoothing: antialiased !important; -} -.ipynb-renderer-root div#maintoolbar { - position: relative; - width: 90%; - margin-left: -10%; - padding-right: 8%; - float: left; - background: #1e1e1e !important; - background-color: #1e1e1e !important; -} -.ipynb-renderer-root #maintoolbar { - margin-bottom: -3px; - margin-top: 2px !important; - border: 0px; - min-height: 27px; - padding-top: 2px; - padding-bottom: 0px; -} -.ipynb-renderer-root #maintoolbar .container { - width: 75%; - margin-right: auto; - margin-left: auto; -} -.ipynb-renderer-root .list_header, -.ipynb-renderer-root div#notebook_list_header.row.list_header { - font-size: 14pt; - color: #f8f8f0; - background-color: transparent; - height: 35px; -} -.ipynb-renderer-root i.fa.fa-folder { - display: inline-block; - font: normal normal normal 14px 'FontAwesome'; - font-family: 'FontAwesome' !important; - text-rendering: auto; - -webkit-font-smoothing: antialiased; - font-size: 18px; - -moz-osx-font-smoothing: grayscale; -} -.ipynb-renderer-root #running .panel-group .panel .panel-heading { - font-size: 14pt; - color: #f8f8f0; - padding: 8px 8px; - background: #2f2f2f; - background-color: #2f2f2f; -} -.ipynb-renderer-root #running .panel-group .panel .panel-heading a { - font-size: 14pt; - color: #f8f8f0; -} -.ipynb-renderer-root #running .panel-group .panel .panel-heading a:focus, -.ipynb-renderer-root #running .panel-group .panel .panel-heading a:hover { - font-size: 14pt; - color: #f8f8f0; -} -.ipynb-renderer-root #running .panel-group .panel .panel-body .list_container .list_item { - background: #232323; - background-color: #232323; - padding: 2px; - border-bottom: 2px solid rgba(93, 92, 82, 0.25); -} -.ipynb-renderer-root #running .panel-group .panel .panel-body .list_container .list_item:hover { - background: #232323; - background-color: #232323; -} -.ipynb-renderer-root #running .panel-group .panel .panel-body { - padding: 2px; -} -.ipynb-renderer-root button#refresh_running_list { - border: none !important; -} -.ipynb-renderer-root button#refresh_cluster_list { - border: none !important; -} -.ipynb-renderer-root div.running_list_info.toolbar_info { - font-size: 15px; - padding: 4px 0 4px 0; - margin-top: 5px; - margin-bottom: 8px; - height: 24px; - line-height: 24px; - text-shadow: none; -} -.ipynb-renderer-root .list_placeholder { - font-weight: normal; -} -.ipynb-renderer-root #tree-selector { - padding: 0px; - border-color: transparent; -} -.ipynb-renderer-root #project_name > ul > li > a > i.fa.fa-home { - color: #a6e22e; - font-size: 17pt; - display: inline-block; - position: static; - padding: 0px 0px; - font-weight: normal; - text-align: center; - vertical-align: text-top; -} -.ipynb-renderer-root .fa-folder:before { - color: #ae81ff; -} -.ipynb-renderer-root .fa-arrow-up:before { - font-size: 14px; -} -.ipynb-renderer-root .fa-arrow-down:before { - font-size: 14px; -} -.ipynb-renderer-root span#last-modified.btn.btn-xs.btn-default.sort-action:hover .fa, -.ipynb-renderer-root span#sort-name.btn.btn-xs.btn-default.sort-action:hover .fa { - color: #a6e22e; -} -.ipynb-renderer-root .folder_icon:before { - display: inline-block; - font: normal normal normal 14px/1 FontAwesome; - font-size: inherit; - text-rendering: auto; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - content: '\f07b'; - color: #ae81ff; -} -.ipynb-renderer-root .notebook_icon:before { - display: inline-block; - font: normal normal normal 14px/1 FontAwesome; - font-size: inherit; - text-rendering: auto; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - content: '\f02d'; - position: relative; - color: #a6e22e !important; - top: 0px; -} -.ipynb-renderer-root .file_icon:before { - display: inline-block; - font: normal normal normal 14px/1 FontAwesome; - font-size: inherit; - text-rendering: auto; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - content: '\f15b'; - position: relative; - top: 0px; - color: #888888 !important; -} -.ipynb-renderer-root #project_name a { - display: inline-flex; - padding-left: 7px; - margin-left: -2px; - text-align: -webkit-auto; - vertical-align: baseline; - font-size: 18px; -} -.ipynb-renderer-root div#notebook_toolbar div.dynamic-instructions { - font-family: sans-serif; - font-size: 17px; - color: #75715e; -} -.ipynb-renderer-root span#login_widget > .button, -.ipynb-renderer-root #logout { - font-family: 'Proxima Nova', sans-serif; - color: #f8f8f0; - background: transparent; - background-color: transparent; - border: 2px solid #2f2f2f; - font-weight: normal; - box-shadow: none; - text-shadow: none; - border-radius: 3px; - margin-right: 10px; - padding: 2px 7px; -} -.ipynb-renderer-root span#login_widget > .button:hover, -.ipynb-renderer-root #logout:hover { - color: #a6e22e; - background-color: transparent; - background: transparent; - border: 2px solid #a6e22e; - background-image: none; - box-shadow: none !important; - border-radius: 3px; -} -.ipynb-renderer-root span#login_widget > .button:focus, -.ipynb-renderer-root #logout:focus, -.ipynb-renderer-root span#login_widget > .button.focus, -.ipynb-renderer-root #logout.focus, -.ipynb-renderer-root span#login_widget > .button:active, -.ipynb-renderer-root #logout:active, -.ipynb-renderer-root span#login_widget > .button.active, -.ipynb-renderer-root #logout.active, -.ipynb-renderer-root .open > .dropdown-togglespan#login_widget > .button, -.ipynb-renderer-root .open > .dropdown-toggle#logout { - color: #f8f8f2; - background-color: #f8f8f0; - background: #f8f8f0; - border-color: #f8f8f0; - background-image: none; - box-shadow: none !important; - border-radius: 2px; -} -.ipynb-renderer-root body > #header #header-container { - padding-bottom: 0px; - padding-top: 4px; - box-sizing: border-box; - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; -} -.ipynb-renderer-root body > #header { - background: #1e1e1e; - background-color: #1e1e1e; - position: relative; - z-index: 100; -} -.ipynb-renderer-root .list_container { - font-size: 13pt; - color: #f8f8f0; - border: none; - text-shadow: none !important; -} -.ipynb-renderer-root .list_container > div { - border-bottom: 1px solid rgba(93, 92, 82, 0.25); - font-size: 13pt; -} -.ipynb-renderer-root .list_header > div, -.ipynb-renderer-root .list_item > div { - padding-top: 6px; - padding-bottom: 2px; - padding-left: 0px; -} -.ipynb-renderer-root .list_header > div .item_link, -.ipynb-renderer-root .list_item > div .item_link { - margin-left: -1px; - vertical-align: middle; - line-height: 22px; - font-size: 13pt; -} -.ipynb-renderer-root .item_icon { - color: #ae81ff; - font-size: 13pt; - vertical-align: middle; -} -.ipynb-renderer-root .list_item input:not([type='checkbox']) { - padding-right: 0px; - height: 1.75em; - width: 25%; - margin: 0px 0 0; - margin-top: 0px; -} -.ipynb-renderer-root .list_header > div .item_link, -.ipynb-renderer-root .list_item > div .item_link { - margin-left: -1px; - vertical-align: middle; - line-height: 1.5em; - font-size: 12pt; - display: inline-table; - position: static; -} -.ipynb-renderer-root #button-select-all { - height: 34px; - min-width: 55px; - z-index: 0; - border: none !important; - padding-top: 0px; - padding-bottom: 0px; - margin-bottom: 0px; - margin-top: 0px; - left: -3px; - border-radius: 0px !important; -} -.ipynb-renderer-root #button-select-all:focus, -.ipynb-renderer-root #button-select-all:active:focus, -.ipynb-renderer-root #button-select-all.active:focus, -.ipynb-renderer-root #button-select-all.focus, -.ipynb-renderer-root #button-select-all:active.focus, -.ipynb-renderer-root #button-select-all.active.focus { - background-color: #2f2f2f !important; - background: #2f2f2f !important; -} -.ipynb-renderer-root button#tree-selector-btn { - height: 34px; - font-size: 12pt; - border: none; - left: 0px; - border-radius: 0px !important; -} -.ipynb-renderer-root input#select-all.pull-left.tree-selector { - margin-left: 7px; - margin-right: 2px; - margin-top: 2px; - top: 4px; -} -.ipynb-renderer-root input[type='radio'], -.ipynb-renderer-root input[type='checkbox'] { - margin-top: 1px; - line-height: normal; -} -.ipynb-renderer-root .delete-button { - border: none !important; -} -.ipynb-renderer-root i.fa.fa-trash { - font-size: 13.5pt; -} -.ipynb-renderer-root .list_container a { - font-size: 16px; - color: #f8f8f0; - border: none; - text-shadow: none !important; - font-weight: normal; - font-style: normal; -} -.ipynb-renderer-root div.list_container a:hover { - color: #f8f8f0; -} -.ipynb-renderer-root .list_header > div input, -.ipynb-renderer-root .list_item > div input { - margin-right: 7px; - margin-left: 12px; - vertical-align: baseline; - line-height: 22px; - position: relative; - top: -1px; -} -.ipynb-renderer-root div.list_item:hover { - background-color: rgba(93, 92, 82, 0.1); -} -.ipynb-renderer-root .breadcrumb > li { - font-size: 12pt; - color: #f8f8f0; - border: none; - text-shadow: none !important; -} -.ipynb-renderer-root .breadcrumb > li + li:before { - content: '/\00a0'; - padding: 0px; - color: #f8f8f0; - font-size: 18px; -} -.ipynb-renderer-root #project_name > .breadcrumb { - padding: 0px; - margin-bottom: 0px; - background-color: transparent; - font-weight: normal; - margin-top: -2px; -} -.ipynb-renderer-root ul#tabs a { - font-family: sans-serif; - font-size: 13.5pt; - font-weight: normal; - font-style: normal; - text-shadow: none !important; -} -.ipynb-renderer-root .nav-tabs { - font-family: sans-serif; - font-size: 13.5pt; - font-weight: normal; - font-style: normal; - background-color: transparent; - border-color: transparent; - text-shadow: none !important; - border: 2px solid transparent; -} -.ipynb-renderer-root .nav-tabs > li > a:active, -.ipynb-renderer-root .nav-tabs > li > a:focus, -.ipynb-renderer-root .nav-tabs > li > a:hover, -.ipynb-renderer-root .nav-tabs > li.active > a, -.ipynb-renderer-root .nav-tabs > li.active > a:focus, -.ipynb-renderer-root .nav-tabs > li.active > a:hover, -.ipynb-renderer-root .nav-tabs > li.active > a, -.ipynb-renderer-root .nav-tabs > li.active > a:hover, -.ipynb-renderer-root .nav-tabs > li.active > a:focus { - color: #a6e22e; - background-color: transparent; - border-color: transparent; - border-bottom: 2px solid transparent; -} -.ipynb-renderer-root .nav > li.disabled > a, -.ipynb-renderer-root .nav > li.disabled > a:hover { - color: #75715e; -} -.ipynb-renderer-root .nav-tabs > li > a:before { - content: ''; - position: absolute; - width: 100%; - height: 2px; - bottom: -2px; - left: 0; - background-color: #a6e22e; - visibility: hidden; - -webkit-transform: perspective(0) scaleX(0); - transform: perspective(0) scaleX(0); - -webkit-transition: ease 220ms; - transition: ease 220ms; - -webkit-font-smoothing: antialiased !important; -} -.ipynb-renderer-root .nav-tabs > li > a:hover:before { - visibility: visible; - -webkit-transform: perspective(1) scaleX(1); - transform: perspective(1) scaleX(1); -} -.ipynb-renderer-root .nav-tabs > li.active > a:before { - content: ''; - position: absolute; - width: 100%; - height: 2px; - bottom: -2px; - left: 0; - background-color: #a6e22e; - visibility: visible; - -webkit-transform: perspective(1) scaleX(1); - transform: perspective(1) scaleX(1); - -webkit-font-smoothing: subpixel-antialiased !important; -} -.ipynb-renderer-root div#notebook { - font-family: sans-serif; - font-size: 13pt; - padding-top: 4px; -} -.ipynb-renderer-root .notebook_app { - background-color: #1e1e1e; -} -.ipynb-renderer-root #notebook-container { - padding: 13px 2px; - background-color: #1e1e1e; - min-height: 0px; - box-shadow: none; - width: 980px; - margin-right: auto; - margin-left: auto; -} -.ipynb-renderer-root div#ipython-main-app.container { - width: 980px; - margin-right: auto; - margin-left: auto; -} -.ipynb-renderer-root .container { - width: 980px; - margin-right: auto; - margin-left: auto; -} -.ipynb-renderer-root div#menubar-container { - width: 100%; - width: 980px; -} -.ipynb-renderer-root div#header-container { - width: 980px; -} -.ipynb-renderer-root .notebook_app #header, -.ipynb-renderer-root .edit_app #header { - box-shadow: none !important; - background-color: #1e1e1e; - border-bottom: 2px solid rgba(93, 92, 82, 0.25); -} -.ipynb-renderer-root #header, -.ipynb-renderer-root .edit_app #header { - font-family: sans-serif; - font-size: 13pt; - box-shadow: none; - background-color: #1e1e1e; -} -.ipynb-renderer-root #header .header-bar, -.ipynb-renderer-root .edit_app #header .header-bar { - background: #1e1e1e; - background-color: #1e1e1e; -} -.ipynb-renderer-root body > #header .header-bar { - width: 100%; - background: #1e1e1e; -} -.ipynb-renderer-root span.checkpoint_status, -.ipynb-renderer-root span.autosave_status { - font-size: small; - display: none; -} -.ipynb-renderer-root #menubar, -.ipynb-renderer-root div#menubar { - background-color: #1e1e1e; - padding-top: 0px !important; -} -.ipynb-renderer-root #menubar .navbar, -.ipynb-renderer-root .navbar-default { - background-color: #1e1e1e; - margin-bottom: 0px; - margin-top: 0px; -} -.ipynb-renderer-root .navbar { - border: none; -} -.ipynb-renderer-root div.navbar-text, -.ipynb-renderer-root .navbar-text, -.ipynb-renderer-root .navbar-text.indicator_area, -.ipynb-renderer-root p.navbar-text.indicator_area { - margin-top: 8px !important; - margin-bottom: 0px; - color: #a6e22e; -} -.ipynb-renderer-root .navbar-default { - font-family: sans-serif; - font-size: 13pt; - background-color: #1e1e1e; - border-color: rgba(93, 92, 82, 0.25); - line-height: 1.5em; - padding-bottom: 0px; -} -.ipynb-renderer-root .navbar-default .navbar-nav > li > a { - font-family: sans-serif; - font-size: 13pt; - color: #f8f8f0; - display: block; - line-height: 1.5em; - padding-top: 14px; - padding-bottom: 11px; -} -.ipynb-renderer-root .navbar-default .navbar-nav > li > a:hover, -.ipynb-renderer-root .navbar-default .navbar-nav > li > a:focus { - color: #f8f8f0 !important; - background-color: rgba(93, 92, 82, 0.25) !important; - border-color: rgba(93, 92, 82, 0.25) !important; - line-height: 1.5em; - transition: 80ms ease; -} -.ipynb-renderer-root .navbar-default .navbar-nav > .open > a, -.ipynb-renderer-root .navbar-default .navbar-nav > .open > a:hover, -.ipynb-renderer-root .navbar-default .navbar-nav > .open > a:focus { - color: #f8f8f2; - background-color: #383838; - border-color: #383838; - line-height: 1.5em; -} -.ipynb-renderer-root .navbar-nav > li > .dropdown-menu { - margin-top: 0px; -} -.ipynb-renderer-root .navbar-nav { - margin: 0; -} -.ipynb-renderer-root div.notification_widget.info, -.ipynb-renderer-root .notification_widget.info, -.ipynb-renderer-root .notification_widget:active:hover, -.ipynb-renderer-root .notification_widget.active:hover, -.ipynb-renderer-root .open > .dropdown-toggle.notification_widget:hover, -.ipynb-renderer-root .notification_widget:active:focus, -.ipynb-renderer-root .notification_widget.active:focus, -.ipynb-renderer-root .open > .dropdown-toggle.notification_widget:focus, -.ipynb-renderer-root .notification_widget:active.focus, -.ipynb-renderer-root .notification_widget.active.focus, -.ipynb-renderer-root .open > .dropdown-toggle.notification_widget.focus, -.ipynb-renderer-root div#notification_notebook.notification_widget.btn.btn-xs.navbar-btn, -.ipynb-renderer-root div#notification_notebook.notification_widget.btn.btn-xs.navbar-btn:hover, -.ipynb-renderer-root div#notification_notebook.notification_widget.btn.btn-xs.navbar-btn:focus { - color: #f8f8f0 !important; - background-color: transparent !important; - border-color: transparent !important; - padding-bottom: 0px !important; - margin-bottom: 0px !important; - font-size: 9pt !important; - z-index: 0; -} -.ipynb-renderer-root div#notification_notebook.notification_widget.btn.btn-xs.navbar-btn { - font-size: 9pt !important; - z-index: 0; -} -.ipynb-renderer-root .notification_widget { - color: #ae81ff; - z-index: -500; - font-size: 9pt; - background: transparent; - background-color: transparent; - margin-right: 3px; - border: none; -} -.ipynb-renderer-root .notification_widget, -.ipynb-renderer-root div.notification_widget { - margin-right: 0px; - margin-left: 0px; - padding-right: 0px; - vertical-align: text-top !important; - margin-top: 6px !important; - background: transparent !important; - background-color: transparent !important; - font-size: 9pt !important; - border: none; -} -.ipynb-renderer-root .navbar-btn.btn-xs:hover { - border: none !important; - background: transparent !important; - background-color: transparent !important; - color: #f8f8f0 !important; -} -.ipynb-renderer-root div.notification_widget.info, -.ipynb-renderer-root .notification_widget.info { - display: none !important; -} -.ipynb-renderer-root .edit_mode .modal_indicator:before { - display: none; -} -.ipynb-renderer-root .command_mode .modal_indicator:before { - display: none; -} -.ipynb-renderer-root .item_icon { - color: #ae81ff; -} -.ipynb-renderer-root .item_buttons .kernel-name { - font-size: 13pt; - color: #ae81ff; -} -.ipynb-renderer-root .running_notebook_icon:before { - color: #a6e22e !important; - font: normal normal normal 15px/1 FontAwesome; - font-size: 15px; - text-rendering: auto; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - content: '\f10c'; - vertical-align: middle; - position: static; - display: inherit; -} -.ipynb-renderer-root .item_buttons .running-indicator { - padding-top: 4px; - color: #a6e22e; - font-family: sans-serif; - text-rendering: auto; - -webkit-font-smoothing: antialiased; -} -.ipynb-renderer-root #notification_trusted { - font-family: sans-serif; - border: none; - background: transparent; - background-color: transparent; - margin-bottom: 0px !important; - vertical-align: bottom !important; - color: #75715e !important; - cursor: default !important; -} -.ipynb-renderer-root #notification_area, -.ipynb-renderer-root div.notification_area { - float: right !important; - position: static; - cursor: pointer; - padding-top: 6px; - padding-right: 4px; -} -.ipynb-renderer-root div#notification_notebook.notification_widget.btn.btn-xs.navbar-btn { - font-size: 9pt !important; - z-index: 0; - margin-top: -5px !important; -} -.ipynb-renderer-root #modal_indicator { - float: right !important; - color: #4c8be2; - background: #1e1e1e; - background-color: #1e1e1e; - margin-top: 8px !important; - margin-left: 0px; -} -.ipynb-renderer-root #kernel_indicator { - float: right !important; - color: #a6e22e; - background: #1e1e1e; - background-color: #1e1e1e; - border-left: 2px solid #a6e22e; - padding-top: 0px; - padding-bottom: 4px; - margin-top: 10px !important; - margin-left: -2px; - padding-left: 5px !important; -} -.ipynb-renderer-root #kernel_indicator .kernel_indicator_name { - font-size: 17px; - color: #a6e22e; - background: #1e1e1e; - background-color: #1e1e1e; - padding-left: 5px; - padding-right: 5px; - margin-top: 4px; - vertical-align: text-top; - padding-bottom: 0px; -} -.ipynb-renderer-root .kernel_idle_icon:before { - display: inline-block; - font: normal normal normal 22px/1 FontAwesome; - font-size: 22px; - text-rendering: auto; - -webkit-font-smoothing: antialiased; - cursor: pointer; - margin-left: 0px !important; - opacity: 0.7; - vertical-align: bottom; - margin-top: 1px; - content: '\f1db'; -} -.ipynb-renderer-root .kernel_busy_icon:before { - display: inline-block; - font: normal normal normal 22px/1 FontAwesome; - font-size: 22px; - -webkit-animation: pulsate 2s infinite ease-out; - animation: pulsate 2s infinite ease-out; - text-rendering: auto; - -webkit-font-smoothing: antialiased; - cursor: pointer; - margin-left: 0px !important; - vertical-align: bottom; - margin-top: 1px; - content: '\f111'; -} -@-webkit-keyframes pulsate { - 0% { - -webkit-transform: scale(1, 1); - opacity: 0.8; - } - 8% { - -webkit-transform: scale(1, 1); - opacity: 0.8; - } - 50% { - -webkit-transform: scale(0.75, 0.75); - opacity: 0.3; - } - 92% { - -webkit-transform: scale(1, 1); - opacity: 0.8; - } - 100% { - -webkit-transform: scale(1, 1); - opacity: 0.8; - } -} -.ipynb-renderer-root div.notification_widget.info, -.ipynb-renderer-root .notification_widget.info, -.ipynb-renderer-root .notification_widget:active:hover, -.ipynb-renderer-root .notification_widget.active:hover, -.ipynb-renderer-root .open > .dropdown-toggle.notification_widget:hover, -.ipynb-renderer-root .notification_widget:active:focus, -.ipynb-renderer-root .notification_widget.active:focus, -.ipynb-renderer-root .open > .dropdown-toggle.notification_widget:focus, -.ipynb-renderer-root .notification_widget:active.focus, -.ipynb-renderer-root .notification_widget.active.focus, -.ipynb-renderer-root .open > .dropdown-toggle.notification_widget.focus, -.ipynb-renderer-root div#notification_notebook.notification_widget.btn.btn-xs.navbar-btn, -.ipynb-renderer-root div#notification_notebook.notification_widget.btn.btn-xs.navbar-btn:hover, -.ipynb-renderer-root div#notification_notebook.notification_widget.btn.btn-xs.navbar-btn:focus { - color: #f8f8f0; - background-color: #1e1e1e; - border-color: #1e1e1e; -} -.ipynb-renderer-root #notification_area, -.ipynb-renderer-root div.notification_area { - float: right !important; - position: static; -} -.ipynb-renderer-root .notification_widget, -.ipynb-renderer-root div.notification_widget { - margin-right: 0px; - margin-left: 0px; - padding-right: 0px; - vertical-align: text-top !important; - margin-top: 6px !important; - z-index: 1000; -} -.ipynb-renderer-root #kernel_logo_widget, -.ipynb-renderer-root #kernel_logo_widget .current_kernel_logo { - display: block; -} -.ipynb-renderer-root div#ipython_notebook { - display: none; -} -.ipynb-renderer-root i.fa.fa-icon { - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - text-rendering: auto; -} -.ipynb-renderer-root .fa { - display: inline-block; - font: normal normal normal 10pt/1 'FontAwesome', sans-serif; - text-rendering: auto; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} -.ipynb-renderer-root .dropdown-menu { - font-family: sans-serif; - font-size: 13pt; - box-shadow: none; - padding: 0px; - text-align: left; - border: none; - background-color: #383838; - background: #383838; - line-height: 1; -} -.ipynb-renderer-root .dropdown-menu:hover { - font-family: sans-serif; - font-size: 13pt; - padding: 0px; - text-align: left; - border: none; - background-color: #383838; - box-shadow: none; - line-height: 1; -} -.ipynb-renderer-root .dropdown-menu > li > a { - font-family: sans-serif; - font-size: 12pt; - display: block; - padding: 10px 20px 9px 10px; - color: #f8f8f0; - background-color: #383838; - background: #383838; -} -.ipynb-renderer-root .dropdown-menu > li > a:hover, -.ipynb-renderer-root .dropdown-menu > li > a:focus { - color: #f8f8f0; - background-color: rgba(93, 92, 82, 0.25); - background: rgba(93, 92, 82, 0.25); - border-color: rgba(93, 92, 82, 0.25); - transition: 200ms ease; -} -.ipynb-renderer-root .dropdown-menu .divider { - height: 1px; - margin: 0px 0px; - overflow: hidden; - background-color: rgba(93, 92, 82, 0.5); -} -.ipynb-renderer-root .dropdown-submenu > .dropdown-menu { - display: none; - top: 2px !important; - left: 100%; - margin-top: -2px; - margin-left: 0px; - padding-top: 0px; - transition: 200ms ease; -} -.ipynb-renderer-root .dropdown-menu > .disabled > a, -.ipynb-renderer-root .dropdown-menu > .disabled > a:hover, -.ipynb-renderer-root .dropdown-menu > .disabled > a:focus { - font-family: sans-serif; - font-size: 12pt; - font-weight: normal; - color: #75715e; - padding: none; - display: block; - clear: both; - white-space: nowrap; -} -.ipynb-renderer-root .dropdown-submenu > a:after { - color: #f8f8f0; - margin-right: -16px; - margin-top: 0px; - display: inline-block; -} -.ipynb-renderer-root .dropdown-submenu:hover > a:after, -.ipynb-renderer-root .dropdown-submenu:active > a:after, -.ipynb-renderer-root .dropdown-submenu:focus > a:after, -.ipynb-renderer-root .dropdown-submenu:visited > a:after { - color: #a6e22e; - margin-right: -16px; - display: inline-block !important; -} -.ipynb-renderer-root div.kse-dropdown > .dropdown-menu, -.ipynb-renderer-root .kse-dropdown > .dropdown-menu { - min-width: 0; - top: 94%; -} -.ipynb-renderer-root .btn, -.ipynb-renderer-root .btn-default { - font-family: sans-serif; - color: #f8f8f0; - background: #2f2f2f; - background-color: #2f2f2f; - border: 2px solid #2f2f2f; - font-weight: normal; - box-shadow: none; - text-shadow: none; - border-radius: 3px; - font-size: 13pt !important; -} -.ipynb-renderer-root .btn:hover, -.ipynb-renderer-root .btn:active:hover, -.ipynb-renderer-root .btn.active:hover, -.ipynb-renderer-root .btn-default:hover, -.ipynb-renderer-root .open > .dropdown-toggle.btn-default:hover, -.ipynb-renderer-root .open > .dropdown-toggle.btn:hover { - color: #a6e22e; - border: 2px solid #2a2a2a; - background-color: #2a2a2a; - background: #2a2a2a; - background-image: none; - box-shadow: none !important; - border-radius: 3px; -} -.ipynb-renderer-root .btn:active, -.ipynb-renderer-root .btn.active, -.ipynb-renderer-root .btn:active:focus, -.ipynb-renderer-root .btn.active:focus, -.ipynb-renderer-root .btn:active.focus, -.ipynb-renderer-root .btn.active.focus, -.ipynb-renderer-root .btn-default:focus, -.ipynb-renderer-root .btn-default.focus, -.ipynb-renderer-root .btn-default:active, -.ipynb-renderer-root .btn-default.active, -.ipynb-renderer-root .btn-default:active:hover, -.ipynb-renderer-root .btn-default.active:hover, -.ipynb-renderer-root .btn-default:active:focus, -.ipynb-renderer-root .btn-default.active:focus, -.ipynb-renderer-root .btn-default:active.focus, -.ipynb-renderer-root .btn-default.active.focus, -.ipynb-renderer-root .open > .dropdown-toggle.btn:focus, -.ipynb-renderer-root .open > .dropdown-toggle.btn.focus, -.ipynb-renderer-root .open > .dropdown-toggle.btn-default:hover, -.ipynb-renderer-root .open > .dropdown-toggle.btn-default:focus, -.ipynb-renderer-root .open > .dropdown-toggle.btn-default.hover, -.ipynb-renderer-root .open > .dropdown-toggle.btn-default.focus { - color: #a6e22e; - border: 2px solid #2a2a2a; - background-color: #2a2a2a !important; - background: #2a2a2a !important; - background-image: none; - box-shadow: none !important; - border-radius: 3px; -} -.ipynb-renderer-root .btn-default:active:hover, -.ipynb-renderer-root .btn-default.active:hover, -.ipynb-renderer-root .btn-default:active:focus, -.ipynb-renderer-root .btn-default.active:focus, -.ipynb-renderer-root .btn-default:active.focus, -.ipynb-renderer-root .btn-default.active.focus { - color: #a6e22e !important; - background-color: #2f2f2f; - border-color: #546745 !important; - transition: 2000ms ease; -} -.ipynb-renderer-root .btn:focus, -.ipynb-renderer-root .btn.focus, -.ipynb-renderer-root .btn:active:focus, -.ipynb-renderer-root .btn.active:focus, -.ipynb-renderer-root .btn:active, -.ipynb-renderer-root .btn.active, -.ipynb-renderer-root .btn:active.focus, -.ipynb-renderer-root .btn.active.focus { - color: #a6e22e !important; - outline: none !important; - outline-width: 0px !important; - background: #546745 !important; - background-color: #546745 !important; - border-color: #546745 !important; - transition: 200ms ease !important; -} -.ipynb-renderer-root .item_buttons > .btn, -.ipynb-renderer-root .item_buttons > .btn-group, -.ipynb-renderer-root .item_buttons > .input-group { - font-size: 13pt; - background: transparent; - background-color: transparent; - border: 0px solid #2f2f2f; - border-bottom: 2px solid transparent; - margin-left: 5px; - padding-top: 4px !important; -} -.ipynb-renderer-root .item_buttons > .btn:hover, -.ipynb-renderer-root .item_buttons > .btn-group:hover, -.ipynb-renderer-root .item_buttons > .input-group:hover, -.ipynb-renderer-root .item_buttons > .btn.active, -.ipynb-renderer-root .item_buttons > .btn-group.active, -.ipynb-renderer-root .item_buttons > .input-group.active, -.ipynb-renderer-root .item_buttons > .btn.focus { - margin-left: 5px; - background: #2a2a2a; - padding-top: 4px !important; - background-color: transparent; - border: 0px solid transparent; - border-bottom: 2px solid #a6e22e; - border-radius: 0px; - transition: none; -} -.ipynb-renderer-root .item_buttons { - line-height: 1.5em !important; -} -.ipynb-renderer-root .item_buttons .btn { - min-width: 11ex; -} -.ipynb-renderer-root .btn-group > .btn:first-child { - margin-left: 0px; -} -.ipynb-renderer-root .btn-group > .btn-mini, -.ipynb-renderer-root .btn-sm, -.ipynb-renderer-root .btn-group-sm > .btn, -.ipynb-renderer-root .btn-xs, -.ipynb-renderer-root .btn-group-xs > .btn, -.ipynb-renderer-root .alternate_upload .btn-upload, -.ipynb-renderer-root .btn-group, -.ipynb-renderer-root .btn-group-vertical { - font-size: inherit; - font-weight: normal; - height: inherit; - line-height: inherit; -} -.ipynb-renderer-root .btn-xs, -.ipynb-renderer-root .btn-group-xs > .btn { - font-size: initial !important; - background-image: none; - font-weight: normal; - text-shadow: none; - display: inline-table; - padding: 2px 5px; - line-height: 1.45; -} -.ipynb-renderer-root div#new-buttons > button, -.ipynb-renderer-root #new-buttons > button, -.ipynb-renderer-root div#refresh_notebook_list, -.ipynb-renderer-root #refresh_notebook_list { - background: transparent; - background-color: transparent; - border: none; -} -.ipynb-renderer-root div#new-buttons > button:hover, -.ipynb-renderer-root #new-buttons > button:hover, -.ipynb-renderer-root div#refresh_notebook_list, -.ipynb-renderer-root #refresh_notebook_list, -.ipynb-renderer-root div.alternate_upload .btn-upload, -.ipynb-renderer-root .alternate_upload .btn-upload, -.ipynb-renderer-root div.dynamic-buttons > button, -.ipynb-renderer-root .dynamic-buttons > button, -.ipynb-renderer-root .dynamic-buttons > button:focus, -.ipynb-renderer-root .dynamic-buttons > button:active:focus, -.ipynb-renderer-root .dynamic-buttons > button.active:focus, -.ipynb-renderer-root .dynamic-buttons > button.focus, -.ipynb-renderer-root .dynamic-buttons > button:active.focus, -.ipynb-renderer-root .dynamic-buttons > button.active.focus, -.ipynb-renderer-root #new-buttons > button:focus, -.ipynb-renderer-root #new-buttons > button:active:focus, -.ipynb-renderer-root #new-buttons > button.active:focus, -.ipynb-renderer-root #new-buttons > button.focus, -.ipynb-renderer-root #new-buttons > button:active.focus, -.ipynb-renderer-root #new-buttons > button.active.focus, -.ipynb-renderer-root .alternate_upload .btn-upload:focus, -.ipynb-renderer-root .alternate_upload .btn-upload:active:focus, -.ipynb-renderer-root .alternate_upload .btn-upload.active:focus, -.ipynb-renderer-root .alternate_upload .btn-upload.focus, -.ipynb-renderer-root .alternate_upload .btn-upload:active.focus, -.ipynb-renderer-root .alternate_upload .btn-upload.active.focus { - background: transparent !important; - background-color: transparent !important; - border: none !important; -} -.ipynb-renderer-root .alternate_upload input.fileinput { - text-align: center; - vertical-align: bottom; - margin-left: -0.5ex; - display: inline-table; - border: solid 0px #2f2f2f; - margin-bottom: -1ex; -} -.ipynb-renderer-root .alternate_upload .btn-upload { - display: inline-table; - background: transparent; - border: none; -} -.ipynb-renderer-root .btn-group .btn + .btn, -.ipynb-renderer-root .btn-group .btn + .btn-group, -.ipynb-renderer-root .btn-group .btn-group + .btn, -.ipynb-renderer-root .btn-group .btn-group + .btn-group { - margin-left: -2px; -} -.ipynb-renderer-root .btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) { - border-bottom-right-radius: 0; - border-top-right-radius: 0; - z-index: 2; -} -.ipynb-renderer-root .dropdown-header { - font-family: sans-serif !important; - font-size: 13pt !important; - color: #a6e22e !important; - border-bottom: none !important; - padding: 0px !important; - margin: 6px 6px 0px !important; -} -.ipynb-renderer-root span#last-modified.btn.btn-xs.btn-default.sort-action, -.ipynb-renderer-root span#sort-name.btn.btn-xs.btn-default.sort-action, -.ipynb-renderer-root span#file-size.btn.btn-xs.btn-default.sort-action { - font-family: sans-serif; - font-size: 16px; - background-color: transparent; - background: transparent; - border: none; - color: #f8f8f0; - padding-bottom: 0px; - margin-bottom: 0px; - vertical-align: sub; -} -.ipynb-renderer-root span#last-modified.btn.btn-xs.btn-default.sort-action { - margin-left: 19px; -} -.ipynb-renderer-root button.close { - border: 0px none; - font-family: sans-serif; - font-size: 20pt; - font-weight: normal; -} -.ipynb-renderer-root .dynamic-buttons { - padding-top: 0px; - display: inline-block; - width: 100%; -} -.ipynb-renderer-root .close { - color: #f92672; - opacity: 0.5; - text-shadow: none; - font-weight: normal; -} -.ipynb-renderer-root .close:hover { - color: #f92672; - opacity: 1; - font-weight: normal; -} -.ipynb-renderer-root div.nbext-enable-btns .btn[disabled], -.ipynb-renderer-root div.nbext-enable-btns .btn[disabled]:hover, -.ipynb-renderer-root .btn-default.disabled, -.ipynb-renderer-root .btn-default[disabled], -.ipynb-renderer-root .btn-default.disabled:hover, -.ipynb-renderer-root .btn-default[disabled]:hover, -.ipynb-renderer-root fieldset[disabled] .btn-default:hover, -.ipynb-renderer-root .btn-default.disabled:focus, -.ipynb-renderer-root .btn-default[disabled]:focus, -.ipynb-renderer-root fieldset[disabled] .btn-default:focus, -.ipynb-renderer-root .btn-default.disabled.focus, -.ipynb-renderer-root .btn-default[disabled].focus, -.ipynb-renderer-root fieldset[disabled] .btn-default.focus { - color: #888; - background: #2c2c2c; - background-color: #2c2c2c; - border-color: #2c2c2c; - transition: 200ms ease; -} -.ipynb-renderer-root .input-group-addon { - padding: 2px 5px; - font-size: 13pt; - font-weight: normal; - height: auto; - color: #f8f8f0; - text-align: center; - background-color: transparent; - border: 2px solid transparent !important; - text-transform: capitalize; -} -.ipynb-renderer-root a.btn.btn-default.input-group-addon:hover { - background: transparent !important; - background-color: transparent !important; -} -.ipynb-renderer-root .btn-group > .btn + .dropdown-toggle { - padding-left: 8px; - padding-right: 8px; - height: 100%; -} -.ipynb-renderer-root .btn-group > .btn + .dropdown-toggle:hover { - background: #2a2a2a !important; -} -.ipynb-renderer-root .input-group-btn { - position: relative; - font-size: inherit; - white-space: nowrap; - background: #2f2f2f; - background-color: #2f2f2f; - border: none; -} -.ipynb-renderer-root .input-group-btn:hover { - background: #2a2a2a; - background-color: #2a2a2a; - border: none; -} -.ipynb-renderer-root .input-group-btn:first-child > .btn, -.ipynb-renderer-root .input-group-btn:first-child > .btn-group { - background: #2f2f2f; - background-color: #2f2f2f; - border: none; - margin-left: 2px; - margin-right: -1px; - font-size: inherit; -} -.ipynb-renderer-root .input-group-btn:first-child > .btn:hover, -.ipynb-renderer-root .input-group-btn:first-child > .btn-group:hover { - background: #2a2a2a; - background-color: #2a2a2a; - border: none; - font-size: inherit; - transition: 200ms ease; -} -.ipynb-renderer-root div.modal .btn-group > .btn:first-child { - background: #2f2f2f; - background-color: #2f2f2f; - border: 1px solid #2c2c2c; - margin-top: 0px !important; - margin-left: 0px; - margin-bottom: 2px; -} -.ipynb-renderer-root div.modal .btn-group > .btn:first-child:hover { - background: #2a2a2a; - background-color: #2a2a2a; - border: 1px solid #2a2a2a; - transition: 200ms ease; -} -.ipynb-renderer-root div.modal > button, -.ipynb-renderer-root div.modal-footer > button { - background: #2f2f2f; - background-color: #2f2f2f; - border-color: #2f2f2f; -} -.ipynb-renderer-root div.modal > button:hover, -.ipynb-renderer-root div.modal-footer > button:hover { - background: #2a2a2a; - background-color: #2a2a2a; - border-color: #2a2a2a; - transition: 200ms ease; -} -.ipynb-renderer-root .modal-content { - font-family: sans-serif; - font-size: 12pt; - position: relative; - background: #2f2f2f; - background-color: #2f2f2f; - border: none; - border-radius: 1px; - background-clip: padding-box; - outline: none; -} -.ipynb-renderer-root .modal-header { - font-family: sans-serif; - font-size: 13pt; - color: #f8f8f0; - background: #2f2f2f; - background-color: #2f2f2f; - border-color: rgba(93, 92, 82, 0.25); - padding: 12px; - min-height: 16.4286px; -} -.ipynb-renderer-root .modal-content h4 { - font-family: sans-serif; - font-size: 16pt; - color: #f8f8f0; - padding: 5px; -} -.ipynb-renderer-root .modal-body { - background-color: #232323; - position: relative; - padding: 15px; -} -.ipynb-renderer-root .modal-footer { - padding: 8px; - text-align: right; - background-color: #232323; - border-top: none; -} -.ipynb-renderer-root .alert-info { - background-color: #2f2f2f; - border-color: rgba(93, 92, 82, 0.25); - color: #f8f8f0; -} -.ipynb-renderer-root .modal-header .close { - margin-top: -5px; - font-size: 25pt; -} -.ipynb-renderer-root .modal-backdrop, -.ipynb-renderer-root .modal-backdrop.in { - opacity: 0.85; - background-color: notebook-bg; -} -.ipynb-renderer-root div.panel, -.ipynb-renderer-root div.panel-default, -.ipynb-renderer-root .panel, -.ipynb-renderer-root .panel-default { - font-family: sans-serif; - font-size: 13pt; - background-color: #232323; - color: #f8f8f0; - margin-bottom: 14px; - border: 0; - box-shadow: none; -} -.ipynb-renderer-root div.panel > .panel-heading, -.ipynb-renderer-root div.panel-default > .panel-heading { - font-size: 14pt; - color: #f8f8f0; - background: #2f2f2f; - background-color: #2f2f2f; - border: 0; -} -.ipynb-renderer-root .modal .modal-dialog { - min-width: 950px; - margin: 50px auto; -} -.ipynb-renderer-root div.container-fluid { - margin-right: auto; - margin-left: auto; - padding-left: 0px; - padding-right: 5px; -} -.ipynb-renderer-root div.form-control, -.ipynb-renderer-root .form-control { - font-family: sans-serif; - font-size: initial; - color: #f8f8f0; - background-color: #282828; - border: 1px solid #282828 !important; - margin-left: 2px; - box-shadow: none; - transition: border-color 0.15s ease-in-out 0s, box-shadow 0.15s ease-in-out 0s; -} -.ipynb-renderer-root .form-control-static { - min-height: inherit; - height: inherit; -} -.ipynb-renderer-root .form-group.list-group-item { - color: #f8f8f0; - background-color: #232323; - border-color: rgba(93, 92, 82, 0.25); - margin-bottom: 0px; -} -.ipynb-renderer-root .form-group .input-group { - float: left; -} -.ipynb-renderer-root input, -.ipynb-renderer-root button, -.ipynb-renderer-root select, -.ipynb-renderer-root textarea { - background-color: #282828; - font-weight: normal; - border: 1px solid rgba(93, 92, 82, 0.25); -} -.ipynb-renderer-root select.form-control.select-xs { - height: 30px; - font-size: 13pt; -} -.ipynb-renderer-root .toolbar select, -.ipynb-renderer-root .toolbar label { - width: auto; - vertical-align: top; - margin-right: 0px; - margin-bottom: 0px; - display: inline; - font-size: 92%; - margin-left: 10px; - padding: 0px; - background: #2f2f2f !important; - background-color: #2f2f2f !important; - border: 2px solid #2f2f2f !important; -} -.ipynb-renderer-root .toolbar .btn { - padding: 3px 8px; -} -.ipynb-renderer-root .form-control:focus { - border-color: #a6e22e; - outline: 2px solid #49483e; - -webkit-box-shadow: none; -} -.ipynb-renderer-root ::-webkit-input-placeholder { - color: #75715e; -} -.ipynb-renderer-root ::-moz-placeholder { - color: #75715e; -} -.ipynb-renderer-root :-ms-input-placeholder { - color: #75715e; -} -.ipynb-renderer-root :-moz-placeholder { - color: #75715e; -} -.ipynb-renderer-root [dir='ltr'] #find-and-replace .input-group-btn + .form-control { - border: 2px solid rgba(93, 92, 82, 0.25) !important; -} -.ipynb-renderer-root [dir='ltr'] #find-and-replace .input-group-btn + .form-control:focus { - border-color: #a6e22e; - outline: 2px solid #49483e; - -webkit-box-shadow: none; - box-shadow: none; -} -.ipynb-renderer-root div.output.output_scroll { - box-shadow: none; -} -.ipynb-renderer-root ::-webkit-scrollbar { - width: 11px; - max-height: 9px; - background-color: #2d2d2d; - border-radius: 3px; - border: none; -} -.ipynb-renderer-root ::-webkit-scrollbar-track { - background: #2d2d2d; - border: none; - width: 11px; - max-height: 9px; -} -.ipynb-renderer-root ::-webkit-scrollbar-thumb { - border-radius: 2px; - border: none; - background: #49483e; - background-clip: content-box; - width: 11px; -} -.ipynb-renderer-root HTML, -.ipynb-renderer-root body, -.ipynb-renderer-root div, -.ipynb-renderer-root dl, -.ipynb-renderer-root dt, -.ipynb-renderer-root dd, -.ipynb-renderer-root ul, -.ipynb-renderer-root ol, -.ipynb-renderer-root li, -.ipynb-renderer-root h1, -.ipynb-renderer-root h2, -.ipynb-renderer-root h3, -.ipynb-renderer-root h4, -.ipynb-renderer-root h5, -.ipynb-renderer-root h6, -.ipynb-renderer-root pre, -.ipynb-renderer-root code, -.ipynb-renderer-root form, -.ipynb-renderer-root fieldset, -.ipynb-renderer-root legend, -.ipynb-renderer-root input, -.ipynb-renderer-root button, -.ipynb-renderer-root textarea, -.ipynb-renderer-root p, -.ipynb-renderer-root blockquote, -.ipynb-renderer-root th, -.ipynb-renderer-root td, -.ipynb-renderer-root span, -.ipynb-renderer-root a { - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - font-weight: 400; -} -.ipynb-renderer-root .rendered_html tr, -.ipynb-renderer-root .rendered_html th, -.ipynb-renderer-root .rendered_html td { - text-align: left; - vertical-align: middle; - padding: 0.42em 0.47em; - line-height: normal; - white-space: normal; - max-width: none; - border: none; -} -.ipynb-renderer-root .rendered_html td { - font-family: sans-serif !important; - font-size: 9.3pt; -} -.ipynb-renderer-root .rendered_html table { - font-family: sans-serif !important; - margin-left: 8px; - margin-right: auto; - border: none; - border-collapse: collapse; - border-spacing: 0; - color: #cccccc; - table-layout: fixed; -} -.ipynb-renderer-root .rendered_html thead { - font-family: sans-serif !important; - font-size: 9.4pt !important; - background: #1e1e1e; - color: #cccccc; - border-bottom: 1px solid #1e1e1e; - vertical-align: bottom; -} -.ipynb-renderer-root .rendered_html tbody tr:nth-child(odd) { - background: #282828; -} -.ipynb-renderer-root .rendered_html tbody tr { - background: #202020; -} -.ipynb-renderer-root .rendered_html tbody tr:hover:nth-child(odd) { - background: #252525; -} -.ipynb-renderer-root .rendered_html tbody tr:hover { - background: #1e1e1e; -} -.ipynb-renderer-root .rendered_html * + table { - margin-top: 0.05em; -} -.ipynb-renderer-root div.widget-area { - background-color: #1e1e1e; - background: #1e1e1e; - color: #cccccc; -} -.ipynb-renderer-root div.widget-area a { - font-family: sans-serif; - font-size: 12pt; - font-weight: normal; - font-style: normal; - color: #f8f8f0; - text-shadow: none !important; -} -.ipynb-renderer-root div.widget-area a:hover, -.ipynb-renderer-root div.widget-area a:focus { - font-family: sans-serif; - font-size: 12pt; - font-weight: normal; - font-style: normal; - color: #f8f8f0; - background: rgba(93, 92, 82, 0.25); - background-color: rgba(93, 92, 82, 0.25); - border-color: transparent; - background-image: none; - text-shadow: none !important; -} -.ipynb-renderer-root div.widget_item.btn-group > button.btn.btn-default.widget-combo-btn, -.ipynb-renderer-root div.widget_item.btn-group > button.btn.btn-default.widget-combo-btn:hover { - background: #2c2c2c; - background-color: #2c2c2c; - border: 2px solid #2c2c2c !important; - font-size: inherit; - z-index: 0; -} -.ipynb-renderer-root div.jupyter-widgets.widget-hprogress.widget-hbox { - display: inline-table !important; - width: 38% !important; - margin-left: 10px; -} -.ipynb-renderer-root div.jupyter-widgets.widget-hprogress.widget-hbox .widget-label, -.ipynb-renderer-root div.widget-hbox .widget-label, -.ipynb-renderer-root .widget-hbox .widget-label, -.ipynb-renderer-root .widget-inline-hbox .widget-label, -.ipynb-renderer-root div.widget-label { - text-align: -webkit-auto !important; - margin-left: 15px !important; - max-width: 240px !important; - min-width: 100px !important; - vertical-align: text-top !important; - color: #cccccc !important; - font-size: 14px !important; -} -.ipynb-renderer-root .widget-hprogress .progress { - flex-grow: 1; - height: 20px; - margin-top: auto; - margin-left: 12px; - margin-bottom: auto; - width: 300px; -} -.ipynb-renderer-root .progress { - overflow: hidden; - height: 22px; - margin-bottom: 10px; - padding-left: 10px; - background-color: #49483e !important; - border-radius: 2px; - -webkit-box-shadow: none; - box-shadow: none; - z-index: 10; -} -.ipynb-renderer-root .progress-bar-danger { - background-color: #e74c3c !important; -} -.ipynb-renderer-root .progress-bar-info { - background-color: #3498db !important; -} -.ipynb-renderer-root .progress-bar-warning { - background-color: #ff914d !important; -} -.ipynb-renderer-root .progress-bar-success { - background-color: #83a83b !important; -} -.ipynb-renderer-root .widget-select select { - margin-left: 12px; -} -.ipynb-renderer-root :link { - font-family: sans-serif; - font-size: 100%; - color: darkgreen; - text-decoration: underline; -} -.ipynb-renderer-root .rendered_html :visited, -.ipynb-renderer-root .rendered_html :visited:active, -.ipynb-renderer-root .rendered_html :visited:focus { - color: #acdf45; -} -.ipynb-renderer-root .rendered_html :visited:hover, -.ipynb-renderer-root :link:hover { - font-family: sans-serif; - font-size: 100%; - color: #97dc0b; -} -.ipynb-renderer-root div.cell.text_cell a.anchor-link:link { - font-size: inherit; - text-decoration: none; - padding: 0px 20px; - visibility: none; - color: rgba(0, 0, 0, 0.32); -} -.ipynb-renderer-root div.cell.text_cell a.anchor-link:link:hover { - font-size: inherit; - color: #a6e22e; -} -.ipynb-renderer-root .navbar-text { - margin-top: 4px; - margin-bottom: 0px; -} -.ipynb-renderer-root #clusters > a { - color: #a6e22e; - text-decoration: underline; - cursor: auto; -} -.ipynb-renderer-root #clusters > a:hover { - color: #ae81ff; - text-decoration: underline; - cursor: auto; -} -.ipynb-renderer-root - #nbextensions-configurator-container - > div.row.container-fluid.nbext-selector - > h3 { - font-size: 17px; - margin-top: 5px; - margin-bottom: 8px; - height: 24px; - padding: 4px 0 4px 0; -} -.ipynb-renderer-root div#nbextensions-configurator-container.container, -.ipynb-renderer-root #nbextensions-configurator-container.container { - width: 100%; - margin-right: auto; - margin-left: auto; -} -.ipynb-renderer-root div.nbext-selector > nav > .nav > li > a { - font-family: sans-serif; - font-size: 10.5pt; - padding: 2px 5px; -} -.ipynb-renderer-root div.nbext-selector > nav > .nav > li > a:hover { - background: transparent; -} -.ipynb-renderer-root div.nbext-selector > nav > .nav > li:hover { - background-color: rgba(93, 92, 82, 0.25) !important; - background: rgba(93, 92, 82, 0.25) !important; -} -.ipynb-renderer-root div.nbext-selector > nav > .nav > li.active:hover { - background: transparent !important; - background-color: transparent !important; -} -.ipynb-renderer-root .nav-pills > li.active > a, -.ipynb-renderer-root .nav-pills > li.active > a:active, -.ipynb-renderer-root .nav-pills > li.active > a:hover, -.ipynb-renderer-root .nav-pills > li.active > a:focus { - color: #f8f8f2; - background-color: rgba(93, 92, 82, 0.25) !important; - background: rgba(93, 92, 82, 0.25) !important; - -webkit-backface-visibility: hidden; - -webkit-font-smoothing: subpixel-antialiased !important; -} -.ipynb-renderer-root div.nbext-readme > .nbext-readme-contents > .rendered_html { - font-family: sans-serif; - font-size: 11.5pt; - line-height: 145%; - padding: 1em 1em; - color: #f8f8f0; - background-color: #282828; - -webkit-box-shadow: none; - -moz-box-shadow: none; - box-shadow: none; -} -.ipynb-renderer-root .nbext-icon, -.ipynb-renderer-root .nbext-desc, -.ipynb-renderer-root .nbext-compat-div, -.ipynb-renderer-root .nbext-enable-btns, -.ipynb-renderer-root .nbext-params { - margin-bottom: 8px; - font-size: 11.5pt; -} -.ipynb-renderer-root div.nbext-readme > .nbext-readme-contents { - padding: 0; - overflow-y: hidden; -} -.ipynb-renderer-root div.nbext-readme > .nbext-readme-contents:not(:empty) { - margin-top: 0.5em; - margin-bottom: 2em; - border: none; - border-top-color: rgba(148, 204, 114, 0.2); -} -.ipynb-renderer-root .nbext-showhide-incompat { - padding-bottom: 0.5em; - color: #888; - font-size: 10.5pt; -} -.ipynb-renderer-root .nbext-filter-menu.dropdown-menu > li > a:hover, -.ipynb-renderer-root .nbext-filter-menu.dropdown-menu > li > a:focus, -.ipynb-renderer-root .nbext-filter-menu.dropdown-menu > li > a.ui-state-focus { - color: #f8f8f0 !important; - background-color: rgba(93, 92, 82, 0.25) !important; - background: rgba(93, 92, 82, 0.25) !important; - border-color: rgba(93, 92, 82, 0.25) !important; -} -.ipynb-renderer-root .nbext-filter-input-wrap > .nbext-filter-input-subwrap, -.ipynb-renderer-root .nbext-filter-input-wrap > .nbext-filter-input-subwrap > input { - border: none; - outline: none; - background-color: transparent; - padding: 0; - vertical-align: middle; - margin-top: -2px; -} -.ipynb-renderer-root span.rendered_html code { - background-color: transparent; - color: #f8f8f0; -} -.ipynb-renderer-root #nbextensions-configurator-container > div.row.container-fluid.nbext-selector { - padding-left: 0px; - padding-right: 0px; -} -.ipynb-renderer-root .nbext-filter-menu { - max-height: 55vh !important; - overflow-y: auto; - outline: none; - border: none; -} -.ipynb-renderer-root .nbext-filter-menu:hover { - border: none; -} -.ipynb-renderer-root .alert-warning { - background-color: #232323; - border-color: #232323; - color: #f8f8f0; -} -.ipynb-renderer-root .notification_widget.danger { - color: #fff; - background-color: #e74c3c; - border-color: #e74c3c; - padding-right: 5px; -} -.ipynb-renderer-root - #nbextensions-configurator-container - > div.nbext-buttons.tree-buttons.no-padding.pull-right - > span - > button { - border: none !important; -} -.ipynb-renderer-root button#refresh_running_list { - border: none !important; -} -.ipynb-renderer-root mark, -.ipynb-renderer-root .mark { - background-color: #282828; - color: #f8f8f0; - padding: 0.15em; -} -.ipynb-renderer-root a.text-warning, -.ipynb-renderer-root a.text-warning:hover { - color: #75715e; -} -.ipynb-renderer-root a.text-warning.bg-warning { - background-color: #1e1e1e; -} -.ipynb-renderer-root span.bg-success.text-success { - background-color: transparent; - color: #a6e22e; -} -.ipynb-renderer-root span.bg-danger.text-danger { - background-color: #1e1e1e; - color: #f92672; -} -.ipynb-renderer-root .has-success .input-group-addon { - color: #a6e22e; - border-color: transparent; - background: inherit; - background-color: rgba(83, 180, 115, 0.1); -} -.ipynb-renderer-root .has-success .form-control { - border-color: #a6e22e; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.025); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.025); -} -.ipynb-renderer-root .has-error .input-group-addon { - color: #f92672; - border-color: transparent; - background: inherit; - background-color: rgba(192, 57, 67, 0.1); -} -.ipynb-renderer-root .has-error .form-control { - border-color: #f92672; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.025); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.025); -} -.ipynb-renderer-root .kse-input-group-pretty > kbd { - font-family: monospace, monospace; - color: #f8f8f0; - font-weight: normal; - background: transparent; -} -.ipynb-renderer-root .kse-input-group-pretty > kbd { - font-family: monospace, monospace; - color: #f8f8f0; - font-weight: normal; - background: transparent; -} -.ipynb-renderer-root div.nbext-enable-btns .btn[disabled], -.ipynb-renderer-root div.nbext-enable-btns .btn[disabled]:hover, -.ipynb-renderer-root .btn-default.disabled, -.ipynb-renderer-root .btn-default[disabled] { - background: #2c2c2c; - background-color: #2c2c2c; - color: #f3f3e6; -} -.ipynb-renderer-root label#Keyword-Filter { - display: none; -} -.ipynb-renderer-root .input-group .nbext-list-btn-add, -.ipynb-renderer-root .input-group-btn:last-child > .btn-group > .btn { - background: #2f2f2f; - background-color: #2f2f2f; - border-color: #2f2f2f; - border: 2px solid #2f2f2f; -} -.ipynb-renderer-root .input-group .nbext-list-btn-add:hover, -.ipynb-renderer-root .input-group-btn:last-child > .btn-group > .btn:hover { - background: #2a2a2a; - background-color: #2a2a2a; - border-color: #2a2a2a; - border: 2px solid #2a2a2a; -} -.ipynb-renderer-root - #notebook-container - > div.cell.code_cell.rendered.selected - > div.widget-area - > div.widget-subarea - > div - > div.widget_item.btn-group - > button.btn.btn-default.dropdown-toggle.widget-combo-carrot-btn { - background: #2f2f2f; - background-color: #2f2f2f; - border-color: #2f2f2f; -} -.ipynb-renderer-root - #notebook-container - > div.cell.code_cell.rendered.selected - > div.widget-area - > div.widget-subarea - > div - > div.widget_item.btn-group - > button.btn.btn-default.dropdown-toggle.widget-combo-carrot-btn:hover { - background: #2a2a2a; - background-color: #2a2a2a; - border-color: #2a2a2a; -} -.ipynb-renderer-root .ui-widget-content { - background: #2f2f2f; - background-color: #2f2f2f; - border: 2px solid #2f2f2f; - color: #f8f8f0; -} -.ipynb-renderer-root div.collapsible_headings_toggle { - color: rgba(93, 92, 82, 0.5) !important; -} -.ipynb-renderer-root div.collapsible_headings_toggle:hover { - color: #a6e22e !important; -} -.ipynb-renderer-root .collapsible_headings_toggle .h1, -.ipynb-renderer-root .collapsible_headings_toggle .h2, -.ipynb-renderer-root .collapsible_headings_toggle .h3, -.ipynb-renderer-root .collapsible_headings_toggle .h4, -.ipynb-renderer-root .collapsible_headings_toggle .h5, -.ipynb-renderer-root .collapsible_headings_toggle .h6 { - margin: 0.3em 0.4em 0em 0em !important; - line-height: 1.2 !important; -} -.ipynb-renderer-root div.collapsible_headings_toggle .fa-caret-down:before, -.ipynb-renderer-root div.collapsible_headings_toggle .fa-caret-right:before { - font-size: xx-large; - transition: transform 1000ms; - transform: none !important; -} -.ipynb-renderer-root - .collapsible_headings_collapsed.collapsible_headings_ellipsis - .rendered_html - h1:after, -.ipynb-renderer-root - .collapsible_headings_collapsed.collapsible_headings_ellipsis - .rendered_html - h2:after, -.ipynb-renderer-root - .collapsible_headings_collapsed.collapsible_headings_ellipsis - .rendered_html - h3:after, -.ipynb-renderer-root - .collapsible_headings_collapsed.collapsible_headings_ellipsis - .rendered_html - h4:after, -.ipynb-renderer-root - .collapsible_headings_collapsed.collapsible_headings_ellipsis - .rendered_html - h5:after, -.ipynb-renderer-root - .collapsible_headings_collapsed.collapsible_headings_ellipsis - .rendered_html - h6:after { - position: absolute; - right: 0; - bottom: 20% !important; - content: '[\002026]'; - color: rgba(93, 92, 82, 0.5) !important; - padding: 0.5em 0em 0em 0em !important; -} -.ipynb-renderer-root .collapsible_headings_ellipsis .rendered_html h1, -.ipynb-renderer-root .collapsible_headings_ellipsis .rendered_html h2, -.ipynb-renderer-root .collapsible_headings_ellipsis .rendered_html h3, -.ipynb-renderer-root .collapsible_headings_ellipsis .rendered_html h4, -.ipynb-renderer-root .collapsible_headings_ellipsis .rendered_html h5, -.ipynb-renderer-root .collapsible_headings_ellipsis .rendered_html h6, -.ipynb-renderer-root .collapsible_headings_toggle .fa { - transition: transform 1000ms !important; - -webkit-transform: inherit !important; - -moz-transform: inherit !important; - -ms-transform: inherit !important; - -o-transform: inherit !important; - transform: inherit !important; - padding-right: 0px !important; -} -.ipynb-renderer-root #toc-wrapper { - z-index: 90; - position: fixed !important; - display: flex; - flex-direction: column; - overflow: hidden; - padding: 10px; - border-style: solid; - border-width: thin; - border-right-width: medium !important; - background-color: #1e1e1e !important; -} -.ipynb-renderer-root #toc-wrapper.ui-draggable.ui-resizable.sidebar-wrapper { - border-color: rgba(93, 92, 82, 0.25) !important; -} -.ipynb-renderer-root #toc a, -.ipynb-renderer-root #navigate_menu a, -.ipynb-renderer-root .toc { - color: #f8f8f0 !important; - font-size: 11 !important; -} -.ipynb-renderer-root #toc li > span:hover { - background-color: rgba(93, 92, 82, 0.25) !important; -} -.ipynb-renderer-root #toc a:hover, -.ipynb-renderer-root #navigate_menu a:hover, -.ipynb-renderer-root .toc { - color: #f8f8f2 !important; - font-size: 11 !important; -} -.ipynb-renderer-root #toc-wrapper .toc-item-num { - color: #a6e22e !important; - font-size: 11 !important; -} -.ipynb-renderer-root input.raw_input { - font-family: monospace, monospace; - font-size: 11 !important; - color: #f8f8f0; - background-color: #282828; - border-color: #252525; - background: #252525; - width: auto; - vertical-align: baseline; - padding: 0em 0.25em; - margin: 0em 0.25em; - -webkit-box-shadow: none; - box-shadow: none; -} -.ipynb-renderer-root audio, -.ipynb-renderer-root video { - display: inline; - vertical-align: middle; - align-content: center; - margin-left: 20%; -} -.ipynb-renderer-root .cmd-palette .modal-body { - padding: 0px; - margin: 0px; -} -.ipynb-renderer-root .cmd-palette form { - background: #293547; - background-color: #293547; -} -.ipynb-renderer-root .typeahead-field input:last-child, -.ipynb-renderer-root .typeahead-hint { - background: #293547; - background-color: #293547; - z-index: 1; -} -.ipynb-renderer-root .typeahead-field input { - font-family: sans-serif; - color: #f8f8f0; - border: none; - font-size: 28pt; - display: inline-block; - line-height: inherit; - padding: 3px 10px; - height: 70px; -} -.ipynb-renderer-root .typeahead-select { - background-color: #293547; -} -.ipynb-renderer-root body > div.modal.cmd-palette.typeahead-field { - display: table; - border-collapse: separate; - background-color: #2b3850; -} -.ipynb-renderer-root .typeahead-container button { - font-family: sans-serif; - font-size: 28pt; - background-color: #2f2f2f; - border: none; - display: inline-block; - line-height: inherit; - padding: 3px 10px; - height: 70px; -} -.ipynb-renderer-root .typeahead-search-icon { - min-width: 40px; - min-height: 55px; - display: block; - vertical-align: middle; - text-align: center; -} -.ipynb-renderer-root .typeahead-container button:focus, -.ipynb-renderer-root .typeahead-container button:hover { - color: #f8f8f0; - background-color: #2a2a2a; - border-color: #2a2a2a; -} -.ipynb-renderer-root .typeahead-list > li.typeahead-group.active > a, -.ipynb-renderer-root .typeahead-list > li.typeahead-group > a, -.ipynb-renderer-root .typeahead-list > li.typeahead-group > a:focus, -.ipynb-renderer-root .typeahead-list > li.typeahead-group > a:hover { - display: none; -} -.ipynb-renderer-root .typeahead-dropdown > li > a, -.ipynb-renderer-root .typeahead-list > li > a { - color: #f8f8f0; - text-decoration: none; -} -.ipynb-renderer-root .typeahead-dropdown, -.ipynb-renderer-root .typeahead-list { - font-family: sans-serif; - font-size: 13pt; - color: #f8f8f0; - background-color: #202937; - border: none; - background-clip: padding-box; - margin-top: 0px; - padding: 3px 2px 3px 0px; - line-height: 1.7; -} -.ipynb-renderer-root .typeahead-dropdown > li.active > a, -.ipynb-renderer-root .typeahead-dropdown > li > a:focus, -.ipynb-renderer-root .typeahead-dropdown > li > a:hover, -.ipynb-renderer-root .typeahead-list > li.active > a, -.ipynb-renderer-root .typeahead-list > li > a:focus, -.ipynb-renderer-root .typeahead-list > li > a:hover { - color: #f8f8f0; - background-color: #2b3850; - border-color: #2b3850; -} -.ipynb-renderer-root .command-shortcut:before { - content: '(command)'; - padding-right: 3px; - color: #75715e; -} -.ipynb-renderer-root .edit-shortcut:before { - content: '(edit)'; - padding-right: 3px; - color: #75715e; -} -.ipynb-renderer-root ul.typeahead-list i { - margin-left: 1px; - width: 18px; - margin-right: 10px; -} -.ipynb-renderer-root ul.typeahead-list { - max-height: 50vh; - overflow: auto; -} -.ipynb-renderer-root .typeahead-list > li { - position: relative; - border: none; -} -.ipynb-renderer-root div.input.typeahead-hint, -.ipynb-renderer-root input.typeahead-hint, -.ipynb-renderer-root - body - > div.modal.cmd-palette.in - > div - > div - > div - > form - > div - > div.typeahead-field - > span.typeahead-query - > input.typeahead-hint { - color: #75715e !important; - background-color: transparent; - padding: 3px 10px; -} -.ipynb-renderer-root .typeahead-dropdown > li > a, -.ipynb-renderer-root .typeahead-list > li > a { - display: block; - padding: 5px; - clear: both; - font-weight: 400; - line-height: 1.7; - border: 1px solid #202937; - border-bottom-color: rgba(93, 92, 82, 0.5); -} -.ipynb-renderer-root body > div.modal.cmd-palette.in > div { - min-width: 750px; - margin: 150px auto; -} -.ipynb-renderer-root .typeahead-container strong { - font-weight: bolder; - color: #a6e22e; -} -.ipynb-renderer-root #find-and-replace #replace-preview .match, -.ipynb-renderer-root #find-and-replace #replace-preview .insert { - color: #fff; - background-color: #57564b; - border-color: #57564b; - border-style: solid; - border-width: 1px; - border-radius: 0px; -} -.ipynb-renderer-root #find-and-replace #replace-preview .replace .match { - background-color: #f92672; - border-color: #f92672; - border-radius: 0px; -} -.ipynb-renderer-root #find-and-replace #replace-preview .replace .insert { - background-color: #a6e22e; - border-color: #a6e22e; - border-radius: 0px; -} -.ipynb-renderer-root .jupyter-dashboard-menu-item.selected::before { - font-family: 'FontAwesome' !important; - content: '\f00c' !important; - position: absolute !important; - color: #a6e22e !important; - left: 0px !important; - top: 13px !important; - font-size: 12px !important; -} -.ipynb-renderer-root .shortcut_key, -.ipynb-renderer-root span.shortcut_key { - display: inline-block; - width: 16ex; - text-align: right; - font-family: monospace; -} -.ipynb-renderer-root .jupyter-keybindings { - padding: 1px; - line-height: 24px; - border-bottom: 1px solid rgba(93, 92, 82, 0.25); -} -.ipynb-renderer-root .jupyter-keybindings i { - background: #282828; - font-size: small; - padding: 5px; - margin-left: 7px; -} -.ipynb-renderer-root div#short-key-bindings-intro.well, -.ipynb-renderer-root .well { - background-color: #2f2f2f; - border: 1px solid #2f2f2f; - color: #f8f8f0; - border-radius: 2px; - -webkit-box-shadow: none; - box-shadow: none; -} -.ipynb-renderer-root #texteditor-backdrop { - background: #1e1e1e; - background-color: #1e1e1e; -} -.ipynb-renderer-root #texteditor-backdrop #texteditor-container .CodeMirror-gutter, -.ipynb-renderer-root #texteditor-backdrop #texteditor-container .CodeMirror-gutters { - background: #49483e; - background-color: #49483e; - color: #75715e; -} -.ipynb-renderer-root .edit_app #menubar .navbar { - margin-bottom: 0px; -} -.ipynb-renderer-root #texteditor-backdrop #texteditor-container { - padding: 0px; - background-color: #282828; - box-shadow: none; -} -.ipynb-renderer-root .terminal-app { - background: #1e1e1e; -} -.ipynb-renderer-root .terminal-app > #header { - background: #1e1e1e; -} -.ipynb-renderer-root .terminal-app .terminal { - font-family: monospace, monospace; - font-size: 11; - line-height: 170%; - color: #f8f8f0; - background: #282828; - padding: 0.4em; - border-radius: 2px; - -webkit-box-shadow: none; - box-shadow: none; -} -.ipynb-renderer-root .terminal .xterm-viewport { - background-color: #282828; - color: #f8f8f0; - overflow-y: auto; -} -.ipynb-renderer-root .terminal .xterm-color-0 { - color: #a6e22e; -} -.ipynb-renderer-root .terminal .xterm-color-1 { - color: #a6e22e; -} -.ipynb-renderer-root .terminal .xterm-color-2 { - color: #f92672; -} -.ipynb-renderer-root .terminal .xterm-color-3 { - color: #a6e22e; -} -.ipynb-renderer-root .terminal .xterm-color-4 { - color: #ae81ff; -} -.ipynb-renderer-root .terminal .xterm-color-5 { - color: #e6db74; -} -.ipynb-renderer-root .terminal .xterm-color-6 { - color: #a6e22e; -} -.ipynb-renderer-root .terminal .xterm-color-7 { - color: #a6e22e; -} -.ipynb-renderer-root .terminal .xterm-color-8 { - color: #a6e22e; -} -.ipynb-renderer-root .terminal .xterm-color-9 { - color: #e6db74; -} -.ipynb-renderer-root .terminal .xterm-color-10 { - color: #a6e22e; -} -.ipynb-renderer-root .terminal .xterm-color-14 { - color: #a6e22e; -} -.ipynb-renderer-root .terminal .xterm-bg-color-15 { - background-color: #282828; -} -.ipynb-renderer-root - .terminal:not(.xterm-cursor-style-underline):not(.xterm-cursor-style-bar) - .terminal-cursor { - background-color: #a6e22e; - color: #282828; -} -.ipynb-renderer-root .terminal:not(.focus) .terminal-cursor { - outline: 1px solid #a6e22e; - outline-offset: -1px; -} -.ipynb-renderer-root .celltoolbar { - font-size: 100%; - padding-top: 3px; - border-color: transparent; - border-bottom: thin solid rgba(148, 204, 114, 0.2); - background: transparent; -} -.ipynb-renderer-root .cell-tag, -.ipynb-renderer-root .tags-input input, -.ipynb-renderer-root .tags-input button { - color: #f8f8f0; - background-color: #1e1e1e; - background-image: none; - border: 1px solid #f8f8f0; - border-radius: 1px; - box-shadow: none; - width: inherit; - font-size: inherit; - height: 22px; - line-height: 22px; -} -.ipynb-renderer-root - #notebook-container - > div.cell.code_cell.rendered.selected - > div.input - > div.inner_cell - > div.ctb_hideshow.ctb_show - > div - > div - > button, -.ipynb-renderer-root - #notebook-container - > div.input - > div.inner_cell - > div.ctb_hideshow.ctb_show - > div - > div - > button { - font-size: 10pt; - color: #f8f8f0; - background-color: #1e1e1e; - background-image: none; - border: 1px solid #f8f8f0; - border-radius: 1px; - box-shadow: none; - width: inherit; - font-size: inherit; - height: 22px; - line-height: 22px; -} -.ipynb-renderer-root div#pager #pager-contents { - background: #1e1e1e !important; - background-color: #1e1e1e !important; -} -.ipynb-renderer-root div#pager pre { - color: #f8f8f0 !important; - background: #282828 !important; - background-color: #282828 !important; - padding: 0.4em; -} -.ipynb-renderer-root div#pager .ui-resizable-handle { - top: 0px; - height: 8px; - background: #a6e22e !important; - border-top: 1px solid #a6e22e; - border-bottom: 1px solid #a6e22e; -} -.ipynb-renderer-root div.input_area { - background-color: #282828; - background: #282828; - padding-right: 1.2em; - border: 0px; - border-radius: 0px; - border-top-right-radius: 4px; - border-bottom-right-radius: 4px; -} -.ipynb-renderer-root div.cell { - padding: 0px; - background: #282828; - background-color: #282828; - border: medium solid #1e1e1e; - border-radius: 4px; - top: 0; -} -.ipynb-renderer-root div.cell.selected { - background: #282828; - background-color: #282828; - border: medium solid #1e1e1e; - padding: 0px; - border-radius: 5px; -} -.ipynb-renderer-root .edit_mode div.cell.selected { - padding: 0px; - background: #282828; - background-color: #282828; - border: medium solid #1e1e1e; - border-radius: 5px; -} -.ipynb-renderer-root div.cell.edit_mode { - padding: 0px; - background: #282828; - background-color: #282828; -} -.ipynb-renderer-root div.CodeMirror-sizer { - margin-left: 0px; - margin-bottom: -21px; - border-right-width: 16px; - min-height: 37px; - padding-right: 0px; - padding-bottom: 0px; - margin-top: 0px; -} -.ipynb-renderer-root div.cell.selected:before, -.ipynb-renderer-root .edit_mode div.cell.selected:before, -.ipynb-renderer-root div.cell.selected:before, -.ipynb-renderer-root div.cell.selected.jupyter-soft-selected:before { - background: #282828 !important; - border: none; - border-radius: 3px; - position: absolute; - display: block; - top: 0px; - left: 0px; - width: 0px; - height: 100%; -} -.ipynb-renderer-root div.cell.text_cell.selected::before, -.ipynb-renderer-root .edit_mode div.cell.text_cell.selected:before, -.ipynb-renderer-root div.cell.text_cell.selected:before, -.ipynb-renderer-root div.cell.text_cell.selected.jupyter-soft-selected:before { - background: #282828 !important; - background-color: #282828 !important; - border-color: #57564b !important; -} -.ipynb-renderer-root div.cell.code_cell .input { - border-left: 5px solid #282828 !important; - border-radius: 3px; - border-bottom-left-radius: 3px; - border-top-left-radius: 3px; -} -.ipynb-renderer-root div.cell.code_cell.selected .input { - border-left: 5px solid #57564b !important; - border-radius: 3px; -} -.ipynb-renderer-root .edit_mode div.cell.code_cell.selected .input { - border-left: 5px solid #33322b !important; - border-radius: 3px; -} -.ipynb-renderer-root .edit_mode div.cell.selected:before { - height: 100%; - border-left: 5px solid #33322b !important; - border-radius: 3px; -} -.ipynb-renderer-root div.cell.jupyter-soft-selected, -.ipynb-renderer-root div.cell.selected.jupyter-soft-selected { - border-left-color: #33322b !important; - border-left-width: 0px !important; - padding-left: 7px !important; - border-right-color: #33322b !important; - border-right-width: 0px !important; - background: #33322b !important; - border-radius: 6px !important; -} -.ipynb-renderer-root div.cell.selected.jupyter-soft-selected .input { - border-left: 5px solid #282828 !important; -} -.ipynb-renderer-root div.cell.selected.jupyter-soft-selected { - border-left-color: #57564b; - border-color: #1e1e1e; - padding-left: 7px; - border-radius: 6px; -} -.ipynb-renderer-root div.cell.code_cell.selected .input { - border-left: none; - border-radius: 3px; -} -.ipynb-renderer-root div.cell.selected.jupyter-soft-selected .prompt, -.ipynb-renderer-root div.cell.text_cell.selected.jupyter-soft-selected .prompt { - top: 0; - border-left: #282828 !important; - border-radius: 2px; -} -.ipynb-renderer-root div.cell.text_cell.selected.jupyter-soft-selected .input_prompt { - border-left: none !important; -} -.ipynb-renderer-root div.cell.text_cell.jupyter-soft-selected, -.ipynb-renderer-root div.cell.text_cell.selected.jupyter-soft-selected { - border-left-color: #33322b !important; - border-left-width: 0px !important; - padding-left: 26px !important; - border-right-color: #33322b !important; - border-right-width: 0px !important; - background: #33322b !important; - border-radius: 5px !important; -} -.ipynb-renderer-root div.cell.jupyter-soft-selected .input, -.ipynb-renderer-root div.cell.selected.jupyter-soft-selected .input { - border-left-color: #33322b !important; -} -.ipynb-renderer-root div.prompt, -.ipynb-renderer-root .prompt { - font-family: monospace, monospace; - font-size: 9pt !important; - font-weight: normal; - color: #75715e; - line-height: 170%; - padding: 0px; - padding-top: 4px; - padding-left: 0px; - padding-right: 1px; - text-align: right !important; - min-width: 11.5ex !important; - width: 11.5ex !important; -} -.ipynb-renderer-root div.prompt.input_prompt { - font-size: 9pt !important; - background-color: #282828; - border-top: 0px; - border-top-right-radius: 0px; - border-bottom-left-radius: 0px; - border-bottom-right-radius: 0px; - padding-right: 3px; - min-width: 11.5ex; - width: 11.5ex !important; -} -.ipynb-renderer-root div.prompt_container { - display: flex; - flex-direction: row; - justify-content: space-between; - align-items: stretch !important; - text-align: right; -} -.ipynb-renderer-root div.cell.code_cell .input_prompt { - border-right: 2px solid #49483e; -} -.ipynb-renderer-root div.cell.selected .prompt { - top: 0; -} -.ipynb-renderer-root .edit_mode div.cell.selected .prompt { - top: 0; -} -.ipynb-renderer-root .edit_mode div.cell.selected .prompt { - top: 0; -} -.ipynb-renderer-root .run_this_cell { - visibility: hidden; - color: transparent; - padding-top: 0px; - padding-bottom: 0px; - padding-left: 3px; - padding-right: 12px; - width: 1.5ex; - width: 0ex; - background: transparent; - background-color: transparent; -} -.ipynb-renderer-root div.code_cell:hover div.input .run_this_cell { - visibility: visible; -} -.ipynb-renderer-root div.cell.code_cell.rendered.selected .run_this_cell:hover { - background-color: #1e1e1e; - background: #1e1e1e; - color: #57564b !important; -} -.ipynb-renderer-root div.cell.code_cell.rendered.unselected .run_this_cell:hover { - background-color: #1e1e1e; - background: #1e1e1e; - color: #57564b !important; -} -.ipynb-renderer-root i.fa-step-forward.fa { - display: inline-block; - font: normal normal normal 9px 'FontAwesome'; -} -.ipynb-renderer-root .fa-step-forward:before { - content: '\f04b'; -} -.ipynb-renderer-root div.cell.selected.jupyter-soft-selected .run_this_cell, -.ipynb-renderer-root div.cell.selected.jupyter-soft-selected .run_this_cell:hover, -.ipynb-renderer-root div.cell.unselected.jupyter-soft-selected .run_this_cell:hover, -.ipynb-renderer-root - div.cell.code_cell.rendered.selected.jupyter-soft-selected - .run_this_cell:hover, -.ipynb-renderer-root - div.cell.code_cell.rendered.unselected.jupyter-soft-selected - .run_this_cell:hover { - background-color: #33322b !important; - background: #33322b !important; - color: #33322b !important; -} -.ipynb-renderer-root div.output_wrapper { - background-color: #1e1e1e; - border: 0px; - left: 0px; - margin-bottom: 0em; - margin-top: 0em; - border-top-right-radius: 0px; - border-top-left-radius: 0px; -} -.ipynb-renderer-root div.output_subarea.output_text.output_stream.output_stdout, -.ipynb-renderer-root div.output_subarea.output_text { - font-family: monospace, monospace; - font-size: 8.5pt !important; - line-height: 150% !important; - background-color: #1e1e1e; - color: #cccccc; - border-top-right-radius: 0px; - border-top-left-radius: 0px; - margin-left: 11.5px; -} -.ipynb-renderer-root div.output_area pre { - font-family: monospace, monospace; - font-size: 8.5pt !important; - line-height: 151% !important; - color: #cccccc; - border-top-right-radius: 0px; - border-top-left-radius: 0px; -} -.ipynb-renderer-root div.output_area { - display: -webkit-box; -} -.ipynb-renderer-root div.output_html { - font-family: monospace, monospace; - font-size: 8.5pt; - color: #cccccc; - background-color: #1e1e1e; - background: #1e1e1e; -} -.ipynb-renderer-root div.output_subarea { - overflow-x: auto; - padding: 1.2em !important; - -webkit-box-flex: 1; - -moz-box-flex: 1; - box-flex: 1; - flex: 1; -} -.ipynb-renderer-root div.btn.btn-default.output_collapsed { - background: #222222; - background-color: #222222; - border-color: #222222; -} -.ipynb-renderer-root div.btn.btn-default.output_collapsed:hover { - background: #1d1d1d; - background-color: #1d1d1d; - border-color: #1d1d1d; -} -.ipynb-renderer-root div.prompt.output_prompt { - font-family: monospace, monospace; - font-weight: bold !important; - background-color: #1e1e1e; - color: transparent; - border-bottom-left-radius: 4px; - border-top-right-radius: 0px; - border-top-left-radius: 0px; - border-bottom-right-radius: 0px; - min-width: 12ex !important; - width: 12ex !important; - border-right: 2px solid transparent; -} -.ipynb-renderer-root div.out_prompt_overlay.prompt { - font-family: monospace, monospace; - font-weight: bold !important; - background-color: #1e1e1e; - border-bottom-left-radius: 2px; - border-top-right-radius: 0px; - border-top-left-radius: 0px; - border-bottom-right-radius: 0px; - min-width: 12ex !important; - width: 12ex !important; - border-right: 2px solid transparent; - color: transparent; -} -.ipynb-renderer-root div.out_prompt_overlay.prompt:hover { - background-color: #49483e; - box-shadow: none !important; - border: none; - border-bottom-left-radius: 2px; - -webkit-border-: 2px; - -moz-border-radius: 2px; - border-top-right-radius: 0px; - border-top-left-radius: 0px; - min-width: 12ex !important; - width: 12ex !important; - border-right: 2px solid #49483e !important; -} -.ipynb-renderer-root div.cell.code_cell .output_prompt { - border-right: 2px solid transparent; - color: transparent; -} -.ipynb-renderer-root div.cell.selected .output_prompt, -.ipynb-renderer-root div.cell.selected .out_prompt_overlay.prompt { - border-left: 5px solid #33322b; - border-right: 2px solid #1e1e1e; - border-radius: 0px !important; -} -.ipynb-renderer-root .edit_mode div.cell.selected .output_prompt, -.ipynb-renderer-root .edit_mode div.cell.selected .out_prompt_overlay.prompt { - border-left: 5px solid #33322b; - border-right: 2px solid #1e1e1e; - border-radius: 0px !important; -} -.ipynb-renderer-root div.text_cell, -.ipynb-renderer-root div.text_cell_render pre, -.ipynb-renderer-root div.text_cell_render { - font-family: sans-serif; - font-size: 13pt; - line-height: 130% !important; - color: #f8f8f0; - background: #282828; - background-color: #282828; - border-radius: 0px; -} -.ipynb-renderer-root div .text_cell_render { - padding: 0.4em 0.4em 0.4em 0.4em; -} -.ipynb-renderer-root div.cell.text_cell .CodeMirror-lines { - padding-top: 0.7em !important; - padding-bottom: 0.4em !important; - padding-left: 0.5em !important; - padding-right: 0.5em !important; - margin-top: 0.4em; - margin-bottom: 0.3em; -} -.ipynb-renderer-root div.cell.text_cell.unrendered div.input_area, -.ipynb-renderer-root div.cell.text_cell.rendered div.input_area { - background-color: #282828; - background: #282828; - border: 0px; - border-radius: 2px; -} -.ipynb-renderer-root div.cell.text_cell .CodeMirror, -.ipynb-renderer-root div.cell.text_cell .CodeMirror pre { - line-height: 170% !important; -} -.ipynb-renderer-root div.cell.text_cell.rendered.selected { - font-family: sans-serif; - line-height: 170% !important; - background: #282828; - background-color: #282828; - border-radius: 0px; -} -.ipynb-renderer-root div.cell.text_cell.unrendered.selected { - font-family: sans-serif; - line-height: 170% !important; - background: #282828; - background-color: #282828; - border-radius: 0px; -} -.ipynb-renderer-root div.cell.text_cell.selected { - font-family: sans-serif; - line-height: 170% !important; - background: #282828; - background-color: #282828; - border-radius: 0px; -} -.ipynb-renderer-root .edit_mode div.cell.text_cell.selected { - font-family: sans-serif; - line-height: 170% !important; - background: #282828; - background-color: #282828; - border-radius: 0px; -} -.ipynb-renderer-root div.text_cell.unrendered, -.ipynb-renderer-root div.text_cell.unrendered.selected, -.ipynb-renderer-root div.edit_mode div.text_cell.unrendered { - font-family: sans-serif; - line-height: 170% !important; - background: #282828; - background-color: #282828; - border-radius: 0px; -} -.ipynb-renderer-root div.cell.text_cell .prompt { - border-right: 0; - min-width: 11.5ex !important; - width: 11.5ex !important; -} -.ipynb-renderer-root div.cell.text_cell.rendered .prompt { - font-family: monospace, monospace; - font-size: 9.5pt !important; - font-weight: normal; - color: #75715e !important; - text-align: right !important; - min-width: 12ex !important; - width: 12ex !important; - background-color: #282828; - border-right: 2px solid #49483e; - border-left: 4px solid #282828; -} -.ipynb-renderer-root div.cell.text_cell.unrendered .prompt { - font-family: monospace, monospace; - font-size: 9.5pt !important; - font-weight: normal; - color: #75715e !important; - text-align: right !important; - min-width: 12ex !important; - width: 12ex !important; - border-right: 2px solid #49483e; - border-left: 4px solid #282828; - background-color: #282828; -} -.ipynb-renderer-root div.cell.text_cell.rendered .prompt { - border-right: 2px solid #49483e; -} -.ipynb-renderer-root div.cell.text_cell.rendered.selected .prompt { - top: 0; - border-left: 4px solid #57564b; - border-right: 2px solid #49483e; -} -.ipynb-renderer-root div.text_cell.unrendered.selected .prompt, -.ipynb-renderer-root div.text_cell.rendered.selected .prompt { - top: 0; - background: #282828; - border-left: 4px solid #33322b; - border-right: 2px solid #49483e; -} -.ipynb-renderer-root div.rendered_html code { - font-family: monospace, monospace; - font-size: 11; - padding-top: 3px; - padding-left: 2px; - color: #f8f8f0; - background: #282828; - background-color: #282828; -} -.ipynb-renderer-root pre, -.ipynb-renderer-root code, -.ipynb-renderer-root kbd, -.ipynb-renderer-root samp { - white-space: pre-wrap; -} -.ipynb-renderer-root .well code, -.ipynb-renderer-root code { - font-family: monospace, monospace; - font-size: 11 !important; - line-height: 170% !important; - color: #f8f8f0; - background: #282828; - background-color: #282828; - border-color: #282828; -} -.ipynb-renderer-root kbd { - padding: 1px; - font-size: 11; - font-weight: 800; - color: #f8f8f0; - background-color: transparent !important; - border: 0; - box-shadow: none; -} -.ipynb-renderer-root pre { - display: block; - padding: 8.5px; - margin: 0 0 9px; - font-size: 12pt; - line-height: 1.42857143; - color: #f8f8f0; - background-color: #282828; - border: 1px solid #282828; - border-radius: 2px; -} -.ipynb-renderer-root div.rendered_html { - color: #f8f8f0; -} -.ipynb-renderer-root .rendered_html * + ul { - margin-top: 0.4em; - margin-bottom: 0.3em; -} -.ipynb-renderer-root .rendered_html * + p { - margin-top: 0.5em; - margin-bottom: 0.5em; -} -.ipynb-renderer-root div.rendered_html pre { - font-family: monospace, monospace; - font-size: 11 !important; - line-height: 170% !important; - color: #f8f8f0 !important; - background: #282828; - background-color: #282828; - border-left: 3px solid #282828; - max-width: 80%; - border-radius: 0px; - padding-left: 5px; - margin-left: 6px; -} -.ipynb-renderer-root div.text_cell_render pre, -.ipynb-renderer-root div.text_cell_render code { - font-family: monospace, monospace; - font-size: 11 !important; - line-height: 170% !important; - color: #f8f8f0; - background: #1e1e1e; - background-color: #1e1e1e; - max-width: 80%; - border-radius: 0px; - border-left: none; -} -.ipynb-renderer-root div.text_cell_render pre { - border-left: 3px solid #49483e !important; - max-width: 80%; - border-radius: 0px; - padding-left: 5px; - margin-left: 6px; -} -.ipynb-renderer-root div.text_cell_render h1, -.ipynb-renderer-root div.rendered_html h1, -.ipynb-renderer-root div.text_cell_render h2, -.ipynb-renderer-root div.rendered_html h2, -.ipynb-renderer-root div.text_cell_render h3, -.ipynb-renderer-root div.rendered_html h3, -.ipynb-renderer-root div.text_cell_render h4, -.ipynb-renderer-root div.rendered_html h4, -.ipynb-renderer-root div.text_cell_render h5, -.ipynb-renderer-root div.rendered_html h5 { - font-family: sans-serif; - margin: 0.4em 0.2em 0.3em 0.2em !important; -} -.ipynb-renderer-root .rendered_html h1:first-child, -.ipynb-renderer-root .rendered_html h2:first-child, -.ipynb-renderer-root .rendered_html h3:first-child, -.ipynb-renderer-root .rendered_html h4:first-child, -.ipynb-renderer-root .rendered_html h5:first-child, -.ipynb-renderer-root .rendered_html h6:first-child { - margin-top: 0.2em !important; - margin-bottom: 0.2em !important; -} -.ipynb-renderer-root .rendered_html h1, -.ipynb-renderer-root .text_cell_render h1 { - color: #a6e22e !important; - font-size: 200%; - text-align: left; - font-style: normal; - font-weight: normal; -} -.ipynb-renderer-root .rendered_html h2, -.ipynb-renderer-root .text_cell_render h2 { - color: #a6e22e !important; - font-size: 170%; - font-style: normal; - font-weight: normal; -} -.ipynb-renderer-root .rendered_html h3, -.ipynb-renderer-root .text_cell_render h3 { - color: #a6e22e !important; - font-size: 140%; - font-style: normal; - font-weight: normal; -} -.ipynb-renderer-root .rendered_html h4, -.ipynb-renderer-root .text_cell_render h4 { - color: #a6e22e !important; - font-size: 110%; - font-style: normal; - font-weight: normal; -} -.ipynb-renderer-root .rendered_html h5, -.ipynb-renderer-root .text_cell_render h5 { - color: #a6e22e !important; - font-size: 100%; - font-style: normal; - font-weight: normal; -} -.ipynb-renderer-root hr { - margin-top: 8px; - margin-bottom: 10px; - border: 0; - border-top: 1px solid #a6e22e; -} -.ipynb-renderer-root .rendered_html hr { - color: #a6e22e; - background-color: #a6e22e; - margin-right: 2em; -} -.ipynb-renderer-root #complete > select > option:hover { - background: rgba(93, 92, 82, 0.25); - background-color: rgba(93, 92, 82, 0.25); -} -.ipynb-renderer-root div#_vivaldi-spatnav-focus-indicator._vivaldi-spatnav-focus-indicator { - position: absolute; - z-index: 9999999999; - top: 0px; - left: 0px; - box-shadow: none; - pointer-events: none; - border-radius: 2px; -} -.ipynb-renderer-root div.CodeMirror, -.ipynb-renderer-root div.CodeMirror pre { - font-family: monospace, monospace; - font-size: 11; - line-height: 170%; - color: #f8f8f0; -} -.ipynb-renderer-root div.CodeMirror-lines { - padding-bottom: 0.9em; - padding-left: 0.5em; - padding-right: 1.5em; - padding-top: 0.7em; -} -.ipynb-renderer-root span.ansiblack, -.ipynb-renderer-root .ansi-black-fg { - color: #282828; -} -.ipynb-renderer-root span.ansiblue, -.ipynb-renderer-root .ansi-blue-fg, -.ipynb-renderer-root .ansi-blue-intense-fg { - color: #66d9ef; -} -.ipynb-renderer-root span.ansigray, -.ipynb-renderer-root .ansi-gray-fg, -.ipynb-renderer-root .ansi-gray-intense-fg { - color: #888; -} -.ipynb-renderer-root span.ansigreen, -.ipynb-renderer-root .ansi-green-fg { - color: #a6e22e; -} -.ipynb-renderer-root .ansi-green-intense-fg { - color: #888; -} -.ipynb-renderer-root span.ansipurple, -.ipynb-renderer-root .ansi-purple-fg, -.ipynb-renderer-root .ansi-purple-intense-fg { - color: #ae81ff; -} -.ipynb-renderer-root span.ansicyan, -.ipynb-renderer-root .ansi-cyan-fg, -.ipynb-renderer-root .ansi-cyan-intense-fg { - color: #ae81ff; -} -.ipynb-renderer-root span.ansiyellow, -.ipynb-renderer-root .ansi-yellow-fg, -.ipynb-renderer-root .ansi-yellow-intense-fg { - color: #e6db74; -} -.ipynb-renderer-root span.ansired, -.ipynb-renderer-root .ansi-red-fg, -.ipynb-renderer-root .ansi-red-intense-fg { - color: #f92672; -} -.ipynb-renderer-root div.output-stderr { - background-color: #f92672; -} -.ipynb-renderer-root div.output-stderr pre { - color: #f8f8f2; -} -.ipynb-renderer-root div.js-error { - color: #f92672; -} -.ipynb-renderer-root .ipython_tooltip { - font-family: monospace, monospace; - font-size: 11; - line-height: 170%; - border: 2px solid #141414; - background: #282828; - background-color: #282828; - border-radius: 2px; - overflow-x: visible; - overflow-y: visible; - box-shadow: none; - position: absolute; - z-index: 1000; -} -.ipynb-renderer-root .ipython_tooltip .tooltiptext pre { - font-family: monospace, monospace; - font-size: 11; - line-height: 170%; - background: #282828; - background-color: #282828; - color: #f8f8f0; - overflow-x: visible; - overflow-y: visible; - max-width: 900px; -} -.ipynb-renderer-root div#tooltip.ipython_tooltip { - overflow-x: wrap; - overflow-y: visible; - max-width: 800px; -} -.ipynb-renderer-root div.tooltiptext.bigtooltip { - overflow-x: visible; - overflow-y: scroll; - height: 400px; - max-width: 800px; -} -.ipynb-renderer-root .cm-s-ipython.CodeMirror { - font-family: monospace, monospace; - font-size: 11; - background: #282828; - color: #f8f8f0; - border-radius: 2px; - font-style: normal; - font-weight: normal; - padding-right: 1.2em; -} -.ipynb-renderer-root .cm-s-ipython div.CodeMirror-selected { - background: #49483e; -} -.ipynb-renderer-root .CodeMirror-gutters { - border: none; - border-right: 1px solid #49483e !important; - background-color: #49483e !important; - background: #49483e !important; - border-radius: 0px; - white-space: nowrap; -} -.ipynb-renderer-root .cm-s-ipython .CodeMirror-gutters { - background: #49483e; - border: none; - border-radius: 0px; - width: 36px; -} -.ipynb-renderer-root .cm-s-ipython .CodeMirror-linenumber { - color: #75715e; -} -.ipynb-renderer-root .CodeMirror-sizer { - margin-left: 40px; -} -.ipynb-renderer-root .CodeMirror-linenumber, -.ipynb-renderer-root div.CodeMirror-linenumber, -.ipynb-renderer-root - .CodeMirror-gutter.CodeMirror-linenumber - div.CodeMirror-gutter.CodeMirror-linenumber { - padding-right: 1px; - margin-left: 0px; - margin: 0px; - width: 26px !important; - padding: 0px; - text-align: right; -} -.ipynb-renderer-root .CodeMirror-linenumber { - color: #75715e; -} -.ipynb-renderer-root .cm-s-ipython .CodeMirror-cursor { - border-left: 2px solid default !important; -} -.ipynb-renderer-root .cm-s-ipython span.cm-comment { - color: #75715e; - font-style: italic; -} -.ipynb-renderer-root .cm-s-ipython span.cm-atom { - color: #ae81ff; -} -.ipynb-renderer-root .cm-s-ipython span.cm-number { - color: #ae81ff; -} -.ipynb-renderer-root .cm-s-ipython span.cm-property { - color: #f8f8f0; -} -.ipynb-renderer-root .cm-s-ipython span.cm-attribute { - color: #f8f8f0; -} -.ipynb-renderer-root .cm-s-ipython span.cm-keyword { - color: #f92672; - font-weight: normal; -} -.ipynb-renderer-root .cm-s-ipython span.cm-string { - color: #e6db74; -} -.ipynb-renderer-root .cm-s-ipython span.cm-meta { - color: #fd971f; -} -.ipynb-renderer-root .cm-s-ipython span.cm-operator { - color: #a6e22e; -} -.ipynb-renderer-root .cm-s-ipython span.cm-builtin { - color: #a6e22e; -} -.ipynb-renderer-root .cm-s-ipython span.cm-variable { - color: #f8f8f0; -} -.ipynb-renderer-root .cm-s-ipython span.cm-variable-2 { - color: #a6e22e; -} -.ipynb-renderer-root .cm-s-ipython span.cm-variable-3 { - color: #fd971f; -} -.ipynb-renderer-root .cm-s-ipython span.cm-def { - color: #a6e22e; - font-weight: normal; -} -.ipynb-renderer-root .cm-s-ipython span.cm-error { - background: rgba(249, 38, 114, 0.4); -} -.ipynb-renderer-root .cm-s-ipython span.cm-tag { - color: #ae81ff; -} -.ipynb-renderer-root .cm-s-ipython span.cm-link { - color: #a6e22e; -} -.ipynb-renderer-root .cm-s-ipython span.cm-storage { - color: #ae81ff; -} -.ipynb-renderer-root .cm-s-ipython span.cm-entity { - color: #a6e22e; -} -.ipynb-renderer-root .cm-s-ipython span.cm-quote { - color: #e6db74; -} -.ipynb-renderer-root div.CodeMirror span.CodeMirror-matchingbracket { - color: #ffffff; - font-weight: bold; - background-color: #49483e; -} -.ipynb-renderer-root div.CodeMirror span.CodeMirror-nonmatchingbracket { - color: #ffffff; - font-weight: bold; - background: rgba(249, 38, 114, 0.4) !important; -} -.ipynb-renderer-root .cm-header-1 { - font-size: 215%; -} -.ipynb-renderer-root .cm-header-2 { - font-size: 180%; -} -.ipynb-renderer-root .cm-header-3 { - font-size: 150%; -} -.ipynb-renderer-root .cm-header-4 { - font-size: 120%; -} -.ipynb-renderer-root .cm-header-5 { - font-size: 100%; -} -.ipynb-renderer-root .cm-s-default .cm-hr { - color: #a6e22e; -} -.ipynb-renderer-root div.cell.text_cell .cm-s-default .cm-header { - font-family: sans-serif; - font-weight: normal; - color: #a6e22e !important; - margin-top: 0.3em !important; - margin-bottom: 0.3em !important; -} -.ipynb-renderer-root div.cell.text_cell .cm-s-default span.cm-variable-2 { - color: #f8f8f0 !important; -} -.ipynb-renderer-root div.cell.text_cell .cm-s-default span.cm-variable-3 { - color: #fd971f !important; -} -.ipynb-renderer-root .cm-s-default span.cm-comment { - color: #75715e !important; -} -.ipynb-renderer-root .cm-s-default .cm-tag { - color: #529b2f; -} -.ipynb-renderer-root .cm-s-default .cm-builtin { - color: #a6e22e; -} -.ipynb-renderer-root .cm-s-default .cm-string { - color: #e6db74; -} -.ipynb-renderer-root .cm-s-default .cm-keyword { - color: #f92672; -} -.ipynb-renderer-root .cm-s-default .cm-number { - color: #ae81ff; -} -.ipynb-renderer-root .cm-s-default .cm-error { - color: #ae81ff; -} -.ipynb-renderer-root .cm-s-default .cm-link { - color: #a6e22e; -} -.ipynb-renderer-root .cm-s-default .cm-atom { - color: #ae81ff; -} -.ipynb-renderer-root .cm-s-default .cm-def { - color: #a6e22e; -} -.ipynb-renderer-root .CodeMirror-cursor { - border-left: 2px solid default !important; - border-right: none; - width: 0; -} -.ipynb-renderer-root .cm-s-default div.CodeMirror-selected { - background: #49483e; -} -.ipynb-renderer-root .cm-s-default .cm-selected { - background: #49483e; -} -.ipynb-renderer-root .MathJax_Display, -.ipynb-renderer-root .MathJax { - border: 0 !important; - font-size: 100% !important; - text-align: center !important; - margin: 0em !important; - line-height: 2.25 !important; -} -.ipynb-renderer-root .MathJax:focus, -.ipynb-renderer-root body :focus .MathJax { - display: inline-block !important; -} -.ipynb-renderer-root .MathJax:focus, -.ipynb-renderer-root body :focus .MathJax { - display: inline-block !important; -} -.ipynb-renderer-root .cell { - margin: 5px 0; -} -.ipynb-renderer-root .input { - display: flex; - flex-direction: row; -} -.ipynb-renderer-root .input > .inner_cell { - overflow: auto; -} -.ipynb-renderer-root div.output_area { - display: flex; -} -.ipynb-renderer-root div.output_latex { - color: #888888; -} diff --git a/webui/react/src/components/kit/internal/services.ts b/webui/react/src/components/kit/internal/services.ts deleted file mode 100644 index 8bec8158987..00000000000 --- a/webui/react/src/components/kit/internal/services.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { isObject } from 'components/kit/internal/functions'; -import { ErrorHandler, FetchArgs } from 'components/kit/internal/types'; - -export const readLogStream = async ( - serverAddress: (path: string) => string, - fetchArgs: FetchArgs, - onError: ErrorHandler, - onEvent?: (event: T) => void, -): Promise => { - try { - const options = isObject(fetchArgs.options) ? fetchArgs.options : {}; - - /* - * Default fetch credentials is set to `same-origin`, but we need to change it - * to `include` for local dev because the ports do not match up (3000 vs 8080). - */ - if (process.env.IS_DEV) options.credentials = 'include'; - - const response = await fetch(serverAddress(fetchArgs.url), options); - - if (!response.ok) { - const body = await response.json(); - const e = new Error(body?.error?.message); - onError(e); - return; - } - - if (!response.body) return onError(`Unable to fetch stream from ${fetchArgs.url}.`); - - const decoder = new TextDecoder(); - const reader = response.body.getReader(); - let buffer = ''; - let isCancelled = false; - - // Cancel reader if an abort signal is received. - if (options?.signal) { - const signal: AbortSignal = options.signal; - const abortHandler = () => { - signal.removeEventListener('abort', abortHandler); - isCancelled = true; - }; - signal.addEventListener('abort', abortHandler); - } - - const handleStreamError = (e: Error) => onError(e); - const handleStreamLine = (line: string) => { - if (isCancelled) return; - try { - const ndjson = JSON.parse(line); - if (ndjson.error) { - onError(ndjson.error); - } else { - onEvent?.(ndjson.result); - } - } catch { - // JSON parsing error occurred, no-op. - } - }; - const handleStreamRead = (result: ReadableStreamReadResult): unknown => { - if (isCancelled) return; - if (result.done) { - // Process any data buffer remainder. - buffer = buffer.trim(); - if (buffer.length !== 0) handleStreamLine(buffer); - return; - } - - // Append incoming streaming data to buffer. - buffer += decoder.decode(result.value, { stream: true }); - - // Process only newline delimited data buffer. - const lines = buffer.split('\n'); - for (let i = 0; i < lines.length - 1; ++i) { - const line = lines[i].trim(); - if (line.length === 0) continue; - handleStreamLine(line); - } - - // Keep the unprocessed buffer data. - buffer = lines[lines.length - 1]; - - // Keep reading. - return reader.read().then(handleStreamRead).catch(handleStreamError); - }; - - return reader.read().then(handleStreamRead).catch(handleStreamError); - } catch (e) { - onError(e); - } -}; diff --git a/webui/react/src/components/kit/internal/types.ts b/webui/react/src/components/kit/internal/types.ts deleted file mode 100644 index fc5c146a362..00000000000 --- a/webui/react/src/components/kit/internal/types.ts +++ /dev/null @@ -1,382 +0,0 @@ -import { DataNode } from 'antd/lib/tree'; -import * as t from 'io-ts'; - -import { isObject, isString } from 'components/kit/internal/functions'; -import rootLogger, { LoggerInterface } from 'components/kit/internal/Logger'; - -export type Primitive = boolean | number | string; -export type RecordKey = string | number | symbol; -export type NullOrUndefined = T | null | undefined; -export type Range = [T, T]; - -export type ValueOf = T[keyof T]; - -type Without = { [P in Exclude]?: never }; -// XOR is taken from: https://stackoverflow.com/a/53229857 -export type XOR = T | U extends object ? (Without & U) | (Without & T) : T | U; - -export const Scale = { - Linear: 'linear', - Log: 'log', -} as const; - -export type Scale = ValueOf; - -interface EndTimes { - endTime?: string; -} - -export const CheckpointState = { - Active: 'ACTIVE', - Completed: 'COMPLETED', - Deleted: 'DELETED', - Error: 'ERROR', - PartiallyDeleted: 'PARTIALLY_DELETED', - Unspecified: 'UNSPECIFIED', -} as const; - -export type CheckpointState = ValueOf; - -interface BaseWorkload extends EndTimes { - totalBatches: number; -} -interface CheckpointWorkload extends BaseWorkload { - resources?: Record; - state: CheckpointState; - uuid?: string; -} -interface CheckpointWorkloadExtended extends CheckpointWorkload { - experimentId: number; - trialId: number; -} - -export type XAxisVal = number; -export type CheckpointsDict = Record; - -export interface SettingsConfigProp
    { - defaultValue: A; - skipUrlEncoding?: boolean; - storageKey: string; - type: t.Type; -} -export interface SettingsConfig { - settings: { [K in keyof T]: SettingsConfigProp }; - storagePath: string; -} - -export interface FetchArgs { - url: string; - // eslint-disable-next-line - options: any; -} - -/** - * DarkLight is a resolved form of `Mode` where we figure out - * what `Mode.System` should ultimate resolve to (`Dark` vs `Light). - */ -export const DarkLight = { - Dark: 'dark', - Light: 'light', -} as const; - -export type DarkLight = ValueOf; -export interface ClassNameProp { - /** classname to be applied to the base element */ - className?: string; -} - -export const ErrorLevel = { - Error: 'error', - Fatal: 'fatal', - Warn: 'warning', -} as const; - -export type ErrorLevel = ValueOf; - -export const ErrorType = { - // unexpected response structure. - Api: 'api', - - // the issue is caused by unexpected/invalid user input. - ApiBadResponse: 'apiBadResponse', - - // third-party api - Assert: 'assert', - - // internal apis and server errors. - Auth: 'auth', - Input: 'input', - Server: 'server', - Ui: 'ui', - Unknown: 'unknown', // assertion failure. -} as const; - -export type ErrorType = ValueOf; - -export type AnyMouseEvent = MouseEvent | React.MouseEvent; -export type AnyMouseEventHandler = (event: AnyMouseEvent) => void; - -export const ERROR_NAMESPACE = 'EH'; - -export const isError = (error: unknown): error is Error => { - return error instanceof Error; -}; -const DEFAULT_LOGGER = rootLogger.extend(ERROR_NAMESPACE); - -export const DEFAULT_ERROR_MESSAGE = 'Unknown error encountered.'; -const defaultErrOptions: DetErrorOptions = { - isUserTriggered: false, - level: ErrorLevel.Error, - logger: DEFAULT_LOGGER, - silent: false, - type: ErrorType.Unknown, -}; - -export interface DetErrorOptions { - id?: string; // slug unique to each place in the codebase that we will use this. - isUserTriggered?: boolean; // whether the error was triggered by an active interaction. - level?: ErrorLevel; - logger?: LoggerInterface; - payload?: unknown; - publicMessage?: string; - publicSubject?: string; - silent?: boolean; - type?: ErrorType; -} - -export class DetError extends Error implements DetErrorOptions { - id?: string; - isUserTriggered: boolean; - level: ErrorLevel; - logger: LoggerInterface; // CHECK: do we want this attached to DetError? - payload?: unknown; - publicMessage?: string; - publicSubject?: string; - silent: boolean; - type: ErrorType; - isHandled: boolean; - /** the wrapped error if one was provided. */ - sourceErr: unknown; - - /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ - constructor(e?: any, options: DetErrorOptions = {}) { - const defaultMessage = isError(e) ? e.message : isString(e) ? e : DEFAULT_ERROR_MESSAGE; - const message = options.publicSubject || options.publicMessage || defaultMessage; - super(message); - - const eOpts: Partial = {}; - if (isObject(e)) { - if ('id' in e && e.id != null) eOpts.id = e.id; - if ('isUserTriggered' in e && e.isUserTriggered != null) - eOpts.isUserTriggered = e.isUserTriggered; - if ('level' in e && e.level != null) eOpts.level = e.level; - if ('logger' in e && e.logger != null) eOpts.logger = e.logger; - if ('payload' in e && e.payload != null) eOpts.payload = e.payload; - if ('publicMessage' in e && e.publicMessage != null) eOpts.publicMessage = e.publicMessage; - if ('silent' in e && e.silent != null) eOpts.silent = e.silent; - if ('type' in e && e.type != null) eOpts.type = e.type; - } - - this.loadOptions({ ...defaultErrOptions, ...eOpts, ...options }); - this.isHandled = false; - this.sourceErr = e; - } - - loadOptions(options: DetErrorOptions): void { - Object.assign(this, options); - } -} - -export type ErrorHandler = ( - error: DetError | unknown, - options?: DetErrorOptions, -) => DetError | void; - -export interface TreeNode extends DataNode { - /** - * DataNode is the interface antd works with. DateNode properties we are interested in: - * - * key: we use V1FileNode.path - * title: name of node - * icon: custom Icon component - */ - children?: TreeNode[]; - download?: string; - get?: (path: string) => Promise; - isLeaf?: boolean; - subtitle?: string; -} - -export const MetricType = { - Training: 'training', - Validation: 'validation', -} as const; - -export type MetricType = ValueOf; - -export interface Note { - contents: string; - name: string; -} - -export interface User { - displayName?: string; - id: number; - modifiedAt?: number; - username: string; -} - -export const LogLevel = { - Critical: 'critical', - Debug: 'debug', - Error: 'error', - Info: 'info', - None: 'none', - Trace: 'trace', - Warning: 'warning', -} as const; - -export type LogLevel = ValueOf; - -// Disable `sort-keys` to sort LogLevel by higher severity levels -export const LogLevelFromApi = { - Critical: 'LOG_LEVEL_CRITICAL', - Error: 'LOG_LEVEL_ERROR', - Warning: 'LOG_LEVEL_WARNING', - // eslint-disable-next-line sort-keys-fix/sort-keys-fix - Info: 'LOG_LEVEL_INFO', - // eslint-disable-next-line sort-keys-fix/sort-keys-fix - Debug: 'LOG_LEVEL_DEBUG', - Trace: 'LOG_LEVEL_TRACE', - Unspecified: 'LOG_LEVEL_UNSPECIFIED', -} as const; - -export type LogLevelFromApi = ValueOf; - -export interface Log { - id: number | string; - level?: LogLevel; - message: string; - meta?: string; - time: string; -} - -export interface SsoProvider { - name: string; - ssoUrl: string; -} - -export const BrandingType = { - Determined: 'determined', - HPE: 'hpe', -} as const; - -export type BrandingType = ValueOf; - -export const RunState = { - Active: 'ACTIVE', - Canceled: 'CANCELED', - Completed: 'COMPLETED', - Deleted: 'DELETED', - DeleteFailed: 'DELETE_FAILED', - Deleting: 'DELETING', - Error: 'ERROR', - Paused: 'PAUSED', - Pulling: 'PULLING', - Queued: 'QUEUED', - Running: 'RUNNING', - Starting: 'STARTING', - StoppingCanceled: 'STOPPING_CANCELED', - StoppingCompleted: 'STOPPING_COMPLETED', - StoppingError: 'STOPPING_ERROR', - StoppingKilled: 'STOPPING_KILLED', - Unspecified: 'UNSPECIFIED', -} as const; - -export type RunState = ValueOf; - -/* Command */ -export const CommandState = { - Pulling: 'PULLING', - Queued: 'QUEUED', - Running: 'RUNNING', - Starting: 'STARTING', - Terminated: 'TERMINATED', - Terminating: 'TERMINATING', - Waiting: 'WAITING', -} as const; - -export type CommandState = ValueOf; - -// TODO: we might have to keep updaing it as the Api.Jobv1State changes... -export const JobState = { - QUEUED: 'STATE_QUEUED', - SCHEDULED: 'STATE_SCHEDULED', - SCHEDULEDBACKFILLED: 'STATE_SCHEDULED_BACKFILLED', - UNSPECIFIED: 'STATE_UNSPECIFIED', -} as const; - -export type JobState = ValueOf; - -export const ResourceState = { - // This is almost CommandState - Assigned: 'ASSIGNED', - Potential: 'POTENTIAL', - Pulling: 'PULLING', - Running: 'RUNNING', - Starting: 'STARTING', - Terminated: 'TERMINATED', - Unspecified: 'UNSPECIFIED', - Warm: 'WARM', -} as const; - -export type ResourceState = ValueOf; - -// High level Slot state -export const SlotState = { - Free: 'FREE', - Pending: 'PENDING', - Potential: 'POTENTIAL', - Running: 'RUNNING', -} as const; - -export type SlotState = ValueOf; - -export const WorkspaceState = { - Deleted: 'DELETED', - DeleteFailed: 'DELETE_FAILED', - Deleting: 'DELETING', - Unspecified: 'UNSPECIFIED', -} as const; - -export type WorkspaceState = ValueOf; - -/** - * @typedef Serie - * Represents a single Series to display on the chart. - * @param {string} [color] - A CSS-compatible color to directly set the line and tooltip color for the Serie. Defaults to glasbeyColor. - * @param {Partial>} data - An array of ordered [x, y] points for each axis. - * @param {MetricType} [metricType] - Indicator of a Serie representing a Training or Validation metric. - * @param {string} [name] - Name to display in legend and toolip instead of Series number. - */ - -export interface Serie { - color?: string; - data: Partial>; - key?: number; - metricType?: string; - name?: string; -} - -export const XAxisDomain = { - Batches: 'Batches', - Epochs: 'Epoch', - Time: 'Time', -} as const; - -export type XAxisDomain = ValueOf; - -export interface Metric { - group: string; - name: string; -} diff --git a/webui/react/src/components/kit/internal/useGetCharMeasureInContainer.ts b/webui/react/src/components/kit/internal/useGetCharMeasureInContainer.ts deleted file mode 100644 index 94e8c9b1bcf..00000000000 --- a/webui/react/src/components/kit/internal/useGetCharMeasureInContainer.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { RefObject, useMemo } from 'react'; - -import { SizeInfo } from 'components/kit/internal/useResize'; - -export interface CharMeasure { - height: number; - width: number; -} - -const useGetCharMeasureInContainer = ( - container: RefObject, - containerSize?: SizeInfo, -): CharMeasure => { - return useMemo(() => { - if (!container.current) { - return { - height: 0, - width: 0, - }; - } - - const elem = document.createElement('div'); - elem.style.display = 'inline'; - elem.style.opacity = '0'; - elem.style.position = 'fixed'; - elem.style.top = '0'; - elem.style.width = 'auto'; - elem.style.visibility = 'hidden'; - elem.textContent = 'W'; - container.current?.appendChild?.(elem); - - const charRect = elem.getBoundingClientRect(); - elem.remove(); - - return { - height: charRect.height, - width: charRect.width, - }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [container, containerSize]); -}; - -export default useGetCharMeasureInContainer; diff --git a/webui/react/src/components/kit/internal/useInputEscape.ts b/webui/react/src/components/kit/internal/useInputEscape.ts deleted file mode 100644 index d8915813a54..00000000000 --- a/webui/react/src/components/kit/internal/useInputEscape.ts +++ /dev/null @@ -1,340 +0,0 @@ -import { InputRef as AntdInputRef, InputRef, RefSelectProps } from 'antd'; -import React, { Ref, RefObject, useEffect, useImperativeHandle, useRef, useState } from 'react'; - -const DRAWER_BODY_CLASSNAME = 'ant-drawer-open'; -const DRAWER_MASK_CLASSNAME = 'ant-drawer-mask'; -const MODAL_WRAP_CLASSNAME = 'ant-modal-wrap'; - -const getOverlayAndMenuBodyElement = () => { - // In order for the Escape button to be able to - // close a menu after an input is unfocused - // we need to be able to re-focus the window - // to the body of the current menu. - - const overlays = [ - ...document.getElementsByClassName(MODAL_WRAP_CLASSNAME), - ...document.getElementsByClassName(DRAWER_MASK_CLASSNAME), - ]; - - // Only one overlay will exist when a menu is open - // the overlay that we want will be the first item - // in the list. - const overlay = overlays?.[0] as HTMLElement; - - const menuBody = - overlay?.className === MODAL_WRAP_CLASSNAME - ? overlay - : (document.getElementsByClassName(DRAWER_BODY_CLASSNAME)?.[0] as HTMLElement); - - return { - focusMenu: () => menuBody?.focus(), - overlayClassname: overlay?.className, - // If an overlay does not exist then the input is not - // inside of a menu or modal and we do not want to - // alter any event behavior - overlayExists: !!overlay, - }; -}; - -interface InputEscape { - onBlur?: ( - e: React.FocusEvent | React.KeyboardEvent, - previousValue?: string, - tagID?: number, - ) => void; -} - -interface InputTextEscape extends InputEscape { - inputRef?: React.RefObject; - onFocus: ( - e: React.FocusEvent, - ) => void; -} - -interface InputNumberEscape extends InputEscape { - onFocus: (e: React.FocusEvent) => void; - inputRef?: Ref; -} - -interface SelectEscape { - inputRef?: React.RefObject; - onFocus: (e: React.FocusEvent) => void; - onBlur?: ( - e: React.FocusEvent | React.KeyboardEvent, - previousValue?: string, - tagID?: number, - ) => void; -} - -const onEsc = ( - focused: boolean, - inputRef: React.RefObject, - event: KeyboardEvent, - handleFocused: (focused: boolean) => void, -) => { - const { overlayExists } = getOverlayAndMenuBodyElement(); - if (!overlayExists) return; - if (focused && event.key === 'Escape') { - event.stopPropagation(); - inputRef.current?.blur(); - getOverlayAndMenuBodyElement()?.focusMenu(); - handleFocused(false); - } -}; - -const onInputNumberClick = ( - blurred: boolean, - focused: boolean, - inputRef: React.RefObject, - event: MouseEvent, - handleFocused: (focused: boolean) => void, -) => { - const { overlayClassname, overlayExists } = getOverlayAndMenuBodyElement(); - if (!overlayExists) return; - const overlayClicked = (event.target as HTMLElement).className === overlayClassname; - - if (focused && (overlayClicked || event.target !== inputRef.current)) { - if (overlayClicked) { - event.stopPropagation(); - } - handleFocused(false); - // If the input is not already blurred then perform the blur - if (!blurred) inputRef.current?.blur(); - } -}; - -const onInputClick = ( - blurred: boolean, - focused: boolean, - inputRef: React.RefObject, - event: MouseEvent, - handleFocused: (focused: boolean) => void, -) => { - const { overlayClassname, overlayExists } = getOverlayAndMenuBodyElement(); - if (!overlayExists) return; - const overlayClicked = (event.target as HTMLElement).className === overlayClassname; - - if ( - focused && - (overlayClicked || (!!inputRef.current?.input && event.target !== inputRef.current?.input)) - ) { - if (overlayClicked) { - event.stopPropagation(); - } - handleFocused(false); - // If the input is not already blurred then perform the blur - if (!blurred) inputRef.current?.blur(); - } -}; - -const onClickSelect = ( - blurred: boolean, - event: MouseEvent, - isOpen: boolean, - hasOpened: boolean, - setHasOpened: (hasOpened: boolean) => void, -) => { - const targetClassname = (event.target as HTMLElement).className; - const { overlayClassname, overlayExists } = getOverlayAndMenuBodyElement(); - if (!overlayExists) return; - if (isOpen && targetClassname === overlayClassname) { - event.stopPropagation(); - } - - if (hasOpened && !isOpen && targetClassname === overlayClassname) { - event.stopPropagation(); - // If hasOpened is true in this instance - // then the event above will close the - // currently open Modal or Menu so we must stop the - // event. - setHasOpened(false); - } - - // If any element besides the overlay has been clicked - // set hasOpened as false to signify that the - // dropdown is now closed - if (blurred && hasOpened && targetClassname !== overlayClassname) setHasOpened(false); -}; - -const onEscSelect = ( - focused: boolean, - inputRef: React.RefObject, - event: KeyboardEvent, - handleFocused: (focused: boolean) => void, - setHasOpened: (hasOpened: boolean) => void, -) => { - const { overlayExists, focusMenu } = getOverlayAndMenuBodyElement(); - if (!overlayExists) return; - if (focused && event.key === 'Escape') { - event.stopPropagation(); - inputRef.current?.blur(); - focusMenu(); - handleFocused(false); - setHasOpened(false); - } -}; - -export const useInputNumberEscape = ( - ref: React.ForwardedRef, - onBlur?: ( - e: React.FocusEvent | React.KeyboardEvent, - previousValue?: string, - tagID?: string, - ) => void, -): InputNumberEscape => { - const inputRef = useRef(null); - useImperativeHandle(ref, () => inputRef?.current as HTMLInputElement); - - const [focused, setFocused] = useState(false); - const [blurred, setBlurred] = useState(false); - - useEffect(() => { - const handleEsc = (event: KeyboardEvent) => { - onEsc(focused, inputRef, event, setFocused); - }; - - const handleClick = (event: MouseEvent) => { - onInputNumberClick(blurred, focused, inputRef, event, setFocused); - }; - - window.addEventListener('keydown', handleEsc, true); - window.addEventListener('click', handleClick, true); - return () => { - window.removeEventListener('keydown', handleEsc, true); - window.removeEventListener('click', handleClick, true); - }; - }, [blurred, focused]); - - const handleBlur = ( - e: React.FocusEvent | React.KeyboardEvent, - previousValue?: string, - ) => { - setBlurred(true); - onBlur?.(e, previousValue); - }; - - const onFocus = () => { - setFocused(true); - setBlurred(false); - }; - return { inputRef, onBlur: handleBlur, onFocus }; -}; - -export const useInputEscape = ( - ref?: React.ForwardedRef, - onBlur?: ( - e: React.FocusEvent | React.KeyboardEvent, - previousValue?: string, - tagID?: string, - ) => void, -): InputTextEscape => { - const inputRef = useRef(null); - const [focused, setFocused] = useState(false); - const [blurred, setBlurred] = useState(false); - - useImperativeHandle(ref, () => inputRef?.current as T); - - useEffect(() => { - const handleEsc = (event: KeyboardEvent) => { - onEsc(focused, inputRef, event, setFocused); - }; - const handleClick = (event: MouseEvent) => { - onInputClick(blurred, focused, inputRef, event, setFocused); - }; - document.addEventListener('keydown', handleEsc, true); - document.addEventListener('click', handleClick, true); - return () => { - document.removeEventListener('keydown', handleEsc, true); - document.removeEventListener('click', handleClick, true); - }; - }, [focused, blurred]); - - const handleBlur = ( - e: React.FocusEvent | React.KeyboardEvent, - previousValue?: string, - ) => { - setBlurred(true); - onBlur?.(e, previousValue); - }; - - const onFocus = () => { - setFocused(true); - setBlurred(false); - }; - return { inputRef, onBlur: handleBlur, onFocus }; -}; - -export const useSelectEscape = ( - containerRef: RefObject, - isOpen: boolean, - ref?: React.ForwardedRef, - onBlur?: ( - e: React.FocusEvent | React.KeyboardEvent, - previousValue?: string, - tagID?: string, - ) => void, -): SelectEscape => { - const inputRef = useRef(null); - const [focused, setFocused] = useState(false); - const [blurred, setBlurred] = useState(false); - const [hasOpened, setHasOpened] = useState(false); - - useImperativeHandle(ref, () => inputRef.current as RefSelectProps); - - useEffect(() => { - /** - By the time a click event is captured in an - event handler the Select will have otherwise already - become unfocused and isOpen will be false. - hasOpened is used in place of "isOpen" to check - if the select is still open at the time of the click - event. - */ - if (isOpen) setHasOpened(true); - }, [isOpen]); - - useEffect(() => { - const handleClick = (event: MouseEvent) => { - onClickSelect(blurred, event, isOpen, hasOpened, setHasOpened); - }; - - const handleEsc = (event: KeyboardEvent) => { - onEscSelect(focused, inputRef, event, setFocused, setHasOpened); - }; - - /** - * The Select component is a special case where - * a seperate container is needed in order to - * properly handle blurring the component. - * In this implementation the event handler is attached to the - * containerRef, when the Select is unfocused - * the containerRef is unmounted which allows - * the "Escape" events to propogate - * normally. - */ - - containerRef.current?.addEventListener('keydown', handleEsc); - window.addEventListener('click', handleClick, true); - return () => { - // eslint-disable-next-line react-hooks/exhaustive-deps - containerRef.current?.removeEventListener('keydown', handleEsc); - - window.removeEventListener('click', handleClick, true); - }; - }, [blurred, containerRef, focused, setFocused, isOpen, hasOpened]); - - const handleBlur = ( - e: React.FocusEvent | React.KeyboardEvent, - previousValue?: string, - ) => { - setBlurred(true); - setFocused(false); - onBlur?.(e, previousValue); - }; - - const onFocus = () => { - setFocused(true); - }; - - return { inputRef, onBlur: handleBlur, onFocus }; -}; diff --git a/webui/react/src/components/kit/internal/usePrevious.ts b/webui/react/src/components/kit/internal/usePrevious.ts deleted file mode 100644 index 603d43abef4..00000000000 --- a/webui/react/src/components/kit/internal/usePrevious.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { useEffect, useRef } from 'react'; - -/* - * This hook takes advantage of useRef hook of retaining an - * older state to preserve and return the previous state - * of a useState hook. - */ -const usePrevious = (value: T, defaultValue: T): T => { - const ref = useRef(defaultValue); - - useEffect(() => { - ref.current = value; - }); - - return ref.current; -}; - -export default usePrevious; diff --git a/webui/react/src/components/kit/internal/useResize.ts b/webui/react/src/components/kit/internal/useResize.ts deleted file mode 100644 index b36f53cabd2..00000000000 --- a/webui/react/src/components/kit/internal/useResize.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { RefCallback, RefObject, useCallback, useEffect, useRef, useState } from 'react'; - -export interface SizeInfo { - height: number; - width: number; - x: number; - y: number; -} - -interface ResizeHook { - refObject: RefObject; - refCallback: RefCallback; - size: SizeInfo; -} - -const DEFAULT_SIZE = { - height: 0, - width: 0, - x: 0, - y: 0, -}; - -const useResize = (): ResizeHook => { - const elementRef = useRef(document.body); - const isMeasured = useRef(false); - const observer = useRef(); - const [resizeInfo, setResizeInfo] = useState({ ...DEFAULT_SIZE }); - - const measureRef = useCallback((node: HTMLElement) => { - isMeasured.current = true; - - // Tear down previous resize observer. - observer.current?.unobserve(elementRef.current); - - if (node) elementRef.current = node; - - // Set up resize observer. - const handleResize: ResizeObserverCallback = (entries: ResizeObserverEntry[]) => { - // Check to make sure the ref container is being observed for resize. - const elements = entries.map((entry: ResizeObserverEntry) => entry.target); - if (!elementRef.current || elements.indexOf(elementRef.current) === -1) return; - - const rect = elementRef.current.getBoundingClientRect(); - setResizeInfo(rect); - }; - observer.current = new ResizeObserver(handleResize); - observer.current?.observe(elementRef.current); - - const rect = elementRef.current.getBoundingClientRect(); - setResizeInfo(rect); - }, []); - - // If the `refCallback` is not applied, run measure against `document.body` - useEffect(() => { - if (!isMeasured.current) measureRef(document.body); - }, [measureRef]); - - // When hook unmounts clean up observer if applicable. - useEffect(() => { - return () => { - observer.current?.unobserve(elementRef.current); - observer.current = undefined; - }; - }, []); - - return { refCallback: measureRef, refObject: elementRef, size: resizeInfo }; -}; - -export default useResize; diff --git a/webui/react/src/components/kit/useConfirm.test.tsx b/webui/react/src/components/kit/useConfirm.test.tsx deleted file mode 100644 index 3e882eac654..00000000000 --- a/webui/react/src/components/kit/useConfirm.test.tsx +++ /dev/null @@ -1,80 +0,0 @@ -import { render, screen, waitFor } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; -import React from 'react'; - -import Button from 'components/kit/Button'; - -import useConfirm, { ConfirmationProvider, voidFn } from './useConfirm'; - -const CONFIRM_TITLE = 'Really?!'; -const CONFIRM_CONTENT = 'Do you really want to do this?!'; - -const handleConfirm = vi.fn(); -const handleClose = vi.fn(); - -const Container: React.FC = () => { - const confirm = useConfirm(); - - return ( - - ); -}; - -const user = userEvent.setup(); - -const setup = async () => { - render( - - - , - ); - await user.click(await screen.findByRole('button')); -}; - -describe('Modal', () => { - it('should open confirmation', async () => { - await setup(); - - expect(await screen.findByText(CONFIRM_TITLE)).toBeInTheDocument(); - expect(await screen.findByText(CONFIRM_CONTENT)).toBeInTheDocument(); - }); - - it('should confirm confirmation', async () => { - await setup(); - - const confirmButton = await screen.findByRole('button', { name: 'Confirm' }); - await user.click(confirmButton); - - await waitFor(() => { - expect(screen.queryByText(CONFIRM_TITLE)).not.toBeInTheDocument(); - expect(screen.queryByText(CONFIRM_CONTENT)).not.toBeInTheDocument(); - }); - - expect(handleConfirm).toHaveBeenCalled(); - }); - - it('should close confirmation', async () => { - await setup(); - - const cancelButton = await screen.findByRole('button', { name: 'Cancel' }); - await user.click(cancelButton); - - await waitFor(() => { - expect(screen.queryByText(CONFIRM_TITLE)).not.toBeInTheDocument(); - expect(screen.queryByText(CONFIRM_CONTENT)).not.toBeInTheDocument(); - }); - - expect(handleClose).toHaveBeenCalled(); - }); -}); diff --git a/webui/react/src/components/kit/useConfirm.tsx b/webui/react/src/components/kit/useConfirm.tsx deleted file mode 100644 index c2f08480a84..00000000000 --- a/webui/react/src/components/kit/useConfirm.tsx +++ /dev/null @@ -1,117 +0,0 @@ -import React, { PropsWithChildren, ReactNode, useState } from 'react'; - -import { ErrorHandler } from 'components/kit/internal/types'; - -import { Modal, ModalSize, useModal } from './Modal'; - -export interface ConfirmModalProps { - cancelText?: string; - content?: ReactNode; - danger?: boolean; - size?: ModalSize; - title?: string; - okText?: string; - onClose?: () => void; - onConfirm: () => Promise | void; - onError: ErrorHandler; -} - -export const DEFAULT_CONFIRM_TITLE = 'Confirm Action'; -export const DEFAULT_CONFIRM_LABEL = 'Confirm'; -export const DEFAULT_CONTENT = 'Are you sure?'; - -const ConfirmModal = ({ - cancelText, - content, - danger = false, - size = 'small', - title, - okText, - onClose, - onConfirm, - onError, -}: ConfirmModalProps) => { - return ( - -
    {content}
    -
    - ); -}; - -type ConfirmModalModifier = (args: ConfirmModalProps) => void; - -/* eslint-disable @typescript-eslint/no-empty-function */ -export const voidFn = (): void => {}; -export const voidPromiseFn = async (): Promise => {}; -const ConfirmationContext = React.createContext(null); - -export const ConfirmationProvider: React.FC = ({ children }) => { - const [modalProps, setModalProps] = useState(); - const Modal = useModal(ConfirmModal); - - const contextValue = ({ - cancelText, - content = DEFAULT_CONTENT, - danger = false, - okText, - size = 'small', - title, - onClose = voidFn, - onConfirm = voidPromiseFn, - onError = voidFn, - }: ConfirmModalProps) => { - setModalProps({ - cancelText, - content, - danger, - okText, - onClose, - onConfirm, - onError, - size, - title, - }); - Modal.open(); - }; - - return ( - <> - {React.useMemo( - () => ( - - {children} - - ), - /* eslint-disable-next-line react-hooks/exhaustive-deps */ - [children], - )} - - - ); -}; - -const useConfirm = (): ConfirmModalModifier => { - const context = React.useContext(ConfirmationContext); - if (context === null) { - throw new Error('Attempted to use confirmation modal outside of ConfirmationContext'); - } - return context; -}; - -export default useConfirm; diff --git a/webui/react/src/components/kit/useTags.tsx b/webui/react/src/components/kit/useTags.tsx deleted file mode 100644 index f6654f48669..00000000000 --- a/webui/react/src/components/kit/useTags.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import React, { useState } from 'react'; - -import Tags, { Props, tagsActionHelper } from 'components/kit/Tags'; - -export const useTags = (tags: string[]): ((props?: Omit) => JSX.Element) => { - const [ctags, setCtags] = useState(tags); - const onAction = tagsActionHelper(ctags, (ts) => setCtags(ts)); - return (props) => ; -}; diff --git a/webui/react/src/components/kit/utils/loadable.test.ts b/webui/react/src/components/kit/utils/loadable.test.ts deleted file mode 100644 index 1cf2af89b8e..00000000000 --- a/webui/react/src/components/kit/utils/loadable.test.ts +++ /dev/null @@ -1,213 +0,0 @@ -import fc from 'fast-check'; -import { describe, test } from 'vitest'; - -import { Failed, Loadable, Loaded, NotLoaded } from './loadable'; - -describe('loadable', () => { - // map - test.concurrent('map should retain any Loaded values', () => { - fc.assert( - fc.property(fc.anything(), (data) => { - expect(Loaded(data).map((d) => d)).toEqual(Loaded(data)); - }), - ); - }); - test.concurrent('map should modify any Loaded values', () => { - expect(Loaded(1).map((d) => d + 1)).toEqual(Loaded(2)); - }); - test.concurrent('map should leave NotLoaded unchanged', () => { - fc.assert( - fc.property(fc.func(fc.anything()), (data) => { - expect(NotLoaded.map(data)).toEqual(NotLoaded); - }), - ); - }); - test.concurrent('map should leave Failed unchanged', () => { - fc.assert( - fc.property(fc.func(fc.anything()), (data) => { - expect(Failed(new Error('test')).map(data)).toEqual(Failed(new Error('test'))); - }), - ); - }); - - // flatMap - test.concurrent('flatMap should retain any Loaded values', () => { - fc.assert( - fc.property(fc.anything(), (data) => { - expect(Loaded(data).flatMap((d) => Loaded(d))).toEqual(Loaded(data)); - }), - ); - }); - test.concurrent('flatMap should convert Loaded to NotLoaded', () => { - fc.assert( - fc.property(fc.anything(), (data) => { - expect(Loaded(data).flatMap(() => NotLoaded)).toEqual(NotLoaded); - }), - ); - }); - test.concurrent('flatMap should convert Loaded to Failed', () => { - fc.assert( - fc.property(fc.anything(), (data) => { - expect(Loaded(data).flatMap(() => Failed(new Error('test')))).toEqual( - Failed(new Error('test')), - ); - }), - ); - }); - test.concurrent('flatMap should modify any Loaded values', () => { - expect(Loaded(1).flatMap((d) => Loaded(d + 1))).toEqual(Loaded(2)); - }); - test.concurrent('flatMap should leave NotLoaded unchanged', () => { - fc.assert( - fc.property(fc.anything(), (data) => { - expect(NotLoaded.flatMap(() => Loaded(data))).toEqual(NotLoaded); - }), - ); - }); - test.concurrent('flatMap should leave Failed unchanged', () => { - fc.assert( - fc.property(fc.func(fc.anything()), (data) => { - expect(Failed(new Error('test')).flatMap(() => Loaded(data))).toEqual( - Failed(new Error('test')), - ); - }), - ); - }); - - // foreach - test.concurrent('forEach should observe Loaded values', () => { - fc.assert( - fc.property(fc.anything(), (data) => { - let i = null; - Loaded(data).forEach((d) => { - i = d; - }); - expect(i).toEqual(data); - }), - ); - }); - test.concurrent('forEach should not observe NotLoaded values', () => { - let i = null; - NotLoaded.forEach(() => { - i = 5; - }); - expect(i).toEqual(null); - }); - test.concurrent('forEach should not observe Failed values', () => { - let i = null; - Failed(new Error('test')).forEach(() => { - i = 5; - }); - expect(i).toEqual(null); - }); - - // getOrElse - test.concurrent('getOrElse should return Loaded values', () => { - fc.assert( - fc.property(fc.anything(), (data) => { - expect(Loaded(data).getOrElse(null)).toBe(data); - }), - ); - }); - test.concurrent('getOrElse should return default for NotLoaded', () => { - fc.assert( - fc.property(fc.anything(), (data) => { - expect((NotLoaded as Loadable).getOrElse(data)).toEqual(data); - }), - ); - }); - test.concurrent('getOrElse should return default for Failed', () => { - fc.assert( - fc.property(fc.anything(), (data) => { - expect(Failed(new Error('test')).getOrElse(data)).toEqual(data); - }), - ); - }); - - // match - test.concurrent('match should call Loaded case for Loaded', () => { - fc.assert( - fc.property(fc.anything(), (data) => { - expect( - Loaded(data).match({ - _: () => 1, - Loaded: (data) => data, - }), - ).toBe(data); - }), - ); - }); - test.concurrent('match should call NotLoaded case for NotLoaded', () => { - fc.assert( - fc.property(fc.anything(), (data) => { - expect( - NotLoaded.match({ - _: () => 1, - NotLoaded: () => data, - }), - ).toBe(data); - }), - ); - }); - test.concurrent('match should call Failed case for Failed', () => { - fc.assert( - fc.property(fc.anything(), (data) => { - expect( - Failed(new Error('test')).match({ - Failed: () => data, - Loaded: () => 1, - NotLoaded: () => 2, - }), - ).toBe(data); - }), - ); - }); - - // all - test.concurrent('all should handle all Loadeds', () => { - fc.assert( - fc.property(fc.array(fc.anything()), (data) => { - const loadeds = data.map((d) => Loaded(d)); - Loadable.all(loadeds).forEach((d) => { - expect(d).toEqual(data); - }); - }), - ); - }); - test.concurrent('all should convert any NotLoaded into NotLoaded', () => { - fc.assert( - fc.property(fc.array(fc.anything()), (data) => { - const loadeds = data.map((d) => Loaded(d)); - loadeds.push(NotLoaded); - expect(Loadable.all(loadeds)).toBe(NotLoaded); - - const loadeds2 = [NotLoaded, ...data.map((d) => Loaded(d))]; - expect(Loadable.all(loadeds2)).toBe(NotLoaded); - }), - ); - }); - test.concurrent('all should convert any Failed into Failed', () => { - fc.assert( - fc.property(fc.array(fc.anything()), (data) => { - const loadeds = data.map((d) => Loaded(d)); - loadeds.push(Failed(new Error('test'))); - expect(Loadable.all(loadeds)).toStrictEqual(Failed(new Error('test'))); - }), - ); - }); - test.concurrent('all should prioritize Failed over NotLoaded', () => { - fc.assert( - fc.property(fc.array(fc.anything()), (data) => { - const loadeds = data.map((d) => Loaded(d)); - loadeds.push(NotLoaded); - loadeds.push(Failed(new Error('test'))); - expect(Loadable.all(loadeds)).toStrictEqual(Failed(new Error('test'))); - - const loadeds2 = data.map((d) => Loaded(d)); - loadeds2.push(Failed(new Error('test'))); - loadeds2.push(NotLoaded); - expect(Loadable.all(loadeds)).toStrictEqual(Failed(new Error('test'))); - }), - ); - }); -}); diff --git a/webui/react/src/components/kit/utils/loadable.ts b/webui/react/src/components/kit/utils/loadable.ts deleted file mode 100644 index c6f7927c13b..00000000000 --- a/webui/react/src/components/kit/utils/loadable.ts +++ /dev/null @@ -1,312 +0,0 @@ -/* eslint-disable @typescript-eslint/no-non-null-assertion */ -const exhaustive = (v: never): never => v; - -type MatchArgs = - | { - Loaded: (data: T) => U; - NotLoaded: () => U; - Failed: (e: Error) => U; - } - | { - Loaded: (data: T) => U; - NotLoaded: () => U; - _: () => U; - } - | { - Loaded: (data: T) => U; - Failed: (e: Error) => U; - _: () => U; - } - | { - NotLoaded: () => U; - Failed: (e: Error) => U; - _: () => U; - } - | { - Loaded: (data: T) => U; - _: () => U; - } - | { - NotLoaded: () => U; - _: () => U; - } - | { - Failed: (e: Error) => U; - _: () => U; - }; - -class Loadable_ { - _tag: 'Loaded' | 'NotLoaded' | 'Failed'; - data: T | undefined; - error: Error | undefined; - - constructor( - tag: 'Loaded' | 'NotLoaded' | 'Failed', - data: T | undefined, - error: Error | undefined = undefined, - ) { - this._tag = tag; - this.data = data; - this.error = error; - } - - /** - * The map() function creates a new Loadable with the result of calling - * the provided function on the contained value in the passed Loadable. - * - * If the passed Loadable is NotLoaded then the return value is NotLoaded - */ - map(fn: (t: T) => U): Loadable { - switch (this._tag) { - case 'Loaded': - return new Loadable_('Loaded', fn(this.data!)) as Loadable; - case 'NotLoaded': - return NotLoaded as Loadable; - case 'Failed': - return new Loadable_('Failed', undefined, this.error) as Loadable; - default: - return exhaustive(this._tag); - } - } - static map(l: Loadable, fn: (_: T) => U): Loadable { - return l.map(fn); - } - - /** - * The flatMap() function creates a new Loadable with the result of calling - * the provided function on the contained value in the passed Loadable and then - * flattening the result. - * - * If any of the passed or returned Loadables is NotLoaded, the result is NotLoaded. - */ - flatMap(fn: (_: T) => Loadable): Loadable { - switch (this._tag) { - case 'Loaded': - return fn(this.data!) as Loadable; - case 'NotLoaded': - return NotLoaded as Loadable; - case 'Failed': - return new Loadable_('Failed', undefined, this.error) as Loadable; - default: - return exhaustive(this._tag); - } - } - static flatMap(l: Loadable, fn: (_: T) => Loadable): Loadable { - return l.flatMap(fn); - } - - /** - * Performs a side-effecting function if the passed Loadable is Loaded. - */ - forEach(fn: (_: T) => U): void { - switch (this._tag) { - case 'Loaded': { - fn(this.data!); - return; - } - case 'NotLoaded': - return; - case 'Failed': - return; - default: - exhaustive(this._tag); - } - } - static forEach(l: Loadable, fn: (_: T) => U): void { - return l.forEach(fn); - } - - /** - * If the passed Loadable is Loaded this returns the data, otherwise - * it returns the default value. - */ - getOrElse(def: T): T { - switch (this._tag) { - case 'Loaded': - return this.data!; - case 'NotLoaded': - return def; - case 'Failed': - return def; - default: - return exhaustive(this._tag); - } - } - static getOrElse(def: T, l: Loadable): T { - return l.getOrElse(def); - } - - /** - * Allows you to match out the cases in the Loadable with named - * arguments. - */ - match(cases: MatchArgs): U { - switch (this._tag) { - case 'Loaded': - return 'Loaded' in cases ? cases.Loaded(this.data!) : cases._(); - case 'NotLoaded': - return 'NotLoaded' in cases ? cases.NotLoaded() : cases._(); - case 'Failed': - return 'Failed' in cases ? cases.Failed(this.error!) : cases._(); - default: - return exhaustive(this._tag); - } - } - static match(l: Loadable, cases: MatchArgs): U { - return l.match(cases); - } - - /** Like `match` but without argument names */ - quickMatch(nl: U, fd: U, f: (data: T) => U): U { - switch (this._tag) { - case 'Loaded': - return f(this.data!); - case 'NotLoaded': - return nl; - case 'Failed': - return fd; - default: - return exhaustive(this._tag); - } - } - static quickMatch(l: Loadable, nl: U, fd: U, f: (data: T) => U): U { - return l.quickMatch(nl, fd, f); - } - - /** - * Groups up all passed Loadables. Failed takes priority over - * NotLoaded so all([NotLoaded, Failed, Loaded(4)]) returns Failed - */ - static all
    (ls: [Loadable]): Loadable<[A]>; - static all(ls: [Loadable, Loadable]): Loadable<[A, B]>; - static all(ls: [Loadable, Loadable, Loadable]): Loadable<[A, B, C]>; - static all( - ls: [Loadable, Loadable, Loadable, Loadable], - ): Loadable<[A, B, C, D]>; - static all( - ls: [Loadable, Loadable, Loadable, Loadable, Loadable], - ): Loadable<[A, B, C, D, E]>; - static all(ls: Array>): Loadable>; - static all(ls: Array>): Loadable> { - const res: unknown[] = []; - let isLoading = false; - for (const l of ls) { - if (l._tag === 'NotLoaded') { - isLoading = true; - } else if (l._tag === 'Failed') { - return new Loadable_('Failed', undefined, l.error) as Loadable; - } else { - res.push(l.data); - } - } - if (isLoading) { - return NotLoaded as Loadable; - } - return new Loadable_('Loaded', res) as Loadable; - } - - /** - * Filters an array of Loadables to remove NotLoaded values and returns array of data. - * Can also optionally accept a conditional function. - */ - static filterNotLoaded( - a: Array>, - conditionFn: (d: T, i?: number) => boolean = () => true, - ): Array { - return a.flatMap((l) => (l.isLoaded ? (conditionFn(l.data) ? [l.data] : []) : [])); - } - - /** Allows you to use Loadables with React's Suspense component */ - waitFor(): T { - switch (this._tag) { - case 'Loaded': - return this.data!; - case 'NotLoaded': - throw Promise.resolve(undefined); - case 'Failed': - throw this.error; - default: - return exhaustive(this._tag); - } - } - static waitFor(l: Loadable): T { - return l.waitFor(); - } - get isLoaded(): boolean { - return this._tag === 'Loaded'; - } - static isLoaded( - l: Loadable, - ): l is { _tag: 'Loaded'; data: T; isLoaded: true; isNotLoaded: false; isFailed: false } & Omit< - Loadable_, - 'isLoaded' | 'data' - > { - return l.isLoaded; - } - get isNotLoaded(): boolean { - return this._tag === 'NotLoaded'; - } - static isNotLoaded( - l: Loadable, - ): l is { _tag: 'NotLoaded'; isLoaded: false; isNotLoaded: true; isFailed: false } & Omit< - Loadable_, - 'isNotLoaded' | 'data' - > { - return l.isNotLoaded; - } - get isFailed(): boolean { - return this._tag === 'Failed'; - } - static isFailed( - l: Loadable, - ): l is { _tag: 'Failed'; isLoaded: false; isNotLoaded: false; isFailed: true } & Omit< - Loadable_, - 'isFailed' | 'data' - > { - return l.isFailed; - } - - /** Returns true if the passed object is a Loadable */ - static isLoadable(l: Loadable | Z): l is Loadable { - return ['Loaded', 'NotLoaded', 'Failed'].includes((l as Loadable)?._tag); - } - - /** If passed a Loadable, returns unchanged. Otherwise, wraps argument in Loaded */ - static ensureLoadable(l: Loadable | T): Loadable { - return this.isLoadable(l) ? l : Loaded(l); - } -} - -export type Loadable = - | ({ - _tag: 'Loaded'; - data: T; - isLoaded: true; - isNotLoaded: false; - isFailed: false; - } & Omit, '_tag' | 'isLoaded' | 'isNotLoaded' | 'isFailed' | 'data'>) - | ({ - _tag: 'NotLoaded'; - isLoaded: false; - isNotLoaded: true; - isFailed: false; - } & Omit, '_tag' | 'isLoaded' | 'isNotLoaded' | 'isFailed' | 'data'>) - | ({ - _tag: 'Failed'; - isLoaded: false; - isNotLoaded: false; - isFailed: true; - } & Omit, '_tag' | 'isLoaded' | 'isNotLoaded' | 'isFailed' | 'data'>); - -// There's no real way to add methods to a union type in typescript except for with Proxies -// but Proxies don't handle generics correctly. We have to "lie" to typescript here to convince -// it that our class is a union type. It's also impossible to write custom guard types -// as methods on a class so we have to lie to it about the return type of all of our guard methods. -const Loaded = (data: T): Loadable => new Loadable_('Loaded', data) as Loadable; -const NotLoaded: Loadable = new Loadable_('NotLoaded', undefined) as Loadable; -const Failed = (error: Error): Loadable => - new Loadable_('Failed', undefined, error) as Loadable; - -export const Loadable = Loadable_; - -export { Loaded, NotLoaded, Failed }; diff --git a/webui/react/src/constants/states.ts b/webui/react/src/constants/states.ts index 39d673fb544..18352c26b6a 100644 --- a/webui/react/src/constants/states.ts +++ b/webui/react/src/constants/states.ts @@ -1,4 +1,5 @@ -import { StateOfUnion } from 'components/kit/Theme'; +import { StateOfUnion } from 'determined-ui/Theme'; + import { V1ResourcePoolType, V1SchedulerType } from 'services/api-ts-sdk'; import { CheckpointState, diff --git a/webui/react/src/hooks/useExperimentTags.ts b/webui/react/src/hooks/useExperimentTags.ts index e6cb773ab79..fcb1826eb3e 100644 --- a/webui/react/src/hooks/useExperimentTags.ts +++ b/webui/react/src/hooks/useExperimentTags.ts @@ -1,6 +1,6 @@ +import { TagAction, tagsActionHelper } from 'determined-ui/Tags'; import { useCallback } from 'react'; -import { TagAction, tagsActionHelper } from 'components/kit/Tags'; import { patchExperiment } from 'services/api'; export interface UseExperimentTagsInterface { diff --git a/webui/react/src/hooks/useFeature.ts b/webui/react/src/hooks/useFeature.ts index ad488e40679..4675bed717e 100644 --- a/webui/react/src/hooks/useFeature.ts +++ b/webui/react/src/hooks/useFeature.ts @@ -1,8 +1,8 @@ +import { Loadable } from 'determined-ui/utils/loadable'; import { map } from 'fp-ts/lib/Record'; import { boolean, null as ioNull, partial, TypeOf, union } from 'io-ts'; import { useObservable } from 'micro-observables'; -import { Loadable } from 'components/kit/utils/loadable'; import determinedStore, { DeterminedInfo } from 'stores/determinedInfo'; import userSettings from 'stores/userSettings'; diff --git a/webui/react/src/hooks/useMetricNames.ts b/webui/react/src/hooks/useMetricNames.ts index 9474bbf7ffa..e4f2c8a04c9 100644 --- a/webui/react/src/hooks/useMetricNames.ts +++ b/webui/react/src/hooks/useMetricNames.ts @@ -1,7 +1,7 @@ +import { Loadable, Loaded, NotLoaded } from 'determined-ui/utils/loadable'; import _ from 'lodash'; import { useEffect, useState } from 'react'; -import { Loadable, Loaded, NotLoaded } from 'components/kit/utils/loadable'; import { V1ExpMetricNamesResponse } from 'services/api-ts-sdk'; import { detApi } from 'services/apiConfig'; import { readStream } from 'services/utils'; diff --git a/webui/react/src/hooks/useModal/Checkpoint/useCheckpointFlow.tsx b/webui/react/src/hooks/useModal/Checkpoint/useCheckpointFlow.tsx index 91a6a5f41b4..61f3468b1f4 100644 --- a/webui/react/src/hooks/useModal/Checkpoint/useCheckpointFlow.tsx +++ b/webui/react/src/hooks/useModal/Checkpoint/useCheckpointFlow.tsx @@ -1,7 +1,7 @@ +import { useModal } from 'determined-ui/Modal'; import { ReactElement, useCallback, useMemo } from 'react'; import CheckpointModalComponent from 'components/CheckpointModal'; -import { useModal } from 'components/kit/Modal'; import ModelCreateModal from 'components/ModelCreateModal'; import { ModalCloseReason } from 'hooks/useModal/useModal'; import { CheckpointWorkloadExtended, CoreApiGenericCheckpoint, ExperimentConfig } from 'types'; diff --git a/webui/react/src/hooks/useModal/Checkpoint/useModalCheckpointRegister.tsx b/webui/react/src/hooks/useModal/Checkpoint/useModalCheckpointRegister.tsx index 040743d4049..a843e130171 100644 --- a/webui/react/src/hooks/useModal/Checkpoint/useModalCheckpointRegister.tsx +++ b/webui/react/src/hooks/useModal/Checkpoint/useModalCheckpointRegister.tsx @@ -1,10 +1,10 @@ import { ModalFuncProps, Select } from 'antd'; +import Input from 'determined-ui/Input'; +import Tags, { tagsActionHelper } from 'determined-ui/Tags'; +import { makeToast } from 'determined-ui/Toast'; import _ from 'lodash'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; -import Input from 'components/kit/Input'; -import Tags, { tagsActionHelper } from 'components/kit/Tags'; -import { makeToast } from 'components/kit/Toast'; import Link from 'components/Link'; import EditableMetadata from 'components/Metadata/EditableMetadata'; import useModal, { ModalHooks as Hooks, ModalCloseReason } from 'hooks/useModal/useModal'; diff --git a/webui/react/src/hooks/useModal/HyperparameterSearch/useModalHyperparameterSearch.test.tsx b/webui/react/src/hooks/useModal/HyperparameterSearch/useModalHyperparameterSearch.test.tsx index 03f66d0373d..9e2650a3a5b 100644 --- a/webui/react/src/hooks/useModal/HyperparameterSearch/useModalHyperparameterSearch.test.tsx +++ b/webui/react/src/hooks/useModal/HyperparameterSearch/useModalHyperparameterSearch.test.tsx @@ -1,8 +1,8 @@ import { render, screen, waitFor, within } from '@testing-library/react'; import userEvent, { PointerEventsCheckLevel } from '@testing-library/user-event'; +import Button from 'determined-ui/Button'; import React from 'react'; -import Button from 'components/kit/Button'; import { createExperiment as mockCreateExperiment } from 'services/api'; import { generateTestExperimentData } from 'utils/tests/generateTestData'; @@ -13,7 +13,7 @@ const MODAL_TITLE = 'Hyperparameter Search'; vi.mock('stores/cluster', async (importOriginal) => { const types = await import('types'); const sdkTypes = await import('services/api-ts-sdk'); - const loadable = await import('components/kit/utils/loadable'); + const loadable = await import('determined-ui/utils/loadable'); const observable = await import('utils/observable'); const store = { diff --git a/webui/react/src/hooks/useModal/HyperparameterSearch/useModalHyperparameterSearch.tsx b/webui/react/src/hooks/useModal/HyperparameterSearch/useModalHyperparameterSearch.tsx index c11fbfaca4b..93989b7a0a0 100644 --- a/webui/react/src/hooks/useModal/HyperparameterSearch/useModalHyperparameterSearch.tsx +++ b/webui/react/src/hooks/useModal/HyperparameterSearch/useModalHyperparameterSearch.tsx @@ -1,17 +1,17 @@ import { Select as AntdSelect, ModalFuncProps, Radio, Space, Typography } from 'antd'; import { RefSelectProps } from 'antd/lib/select'; +import Button from 'determined-ui/Button'; +import Checkbox from 'determined-ui/Checkbox'; +import Form from 'determined-ui/Form'; +import Icon from 'determined-ui/Icon'; +import Input from 'determined-ui/Input'; +import InputNumber from 'determined-ui/InputNumber'; +import Message from 'determined-ui/Message'; +import Select, { Option, SelectValue } from 'determined-ui/Select'; +import { Loadable } from 'determined-ui/utils/loadable'; import yaml from 'js-yaml'; import React, { useCallback, useEffect, useId, useMemo, useRef, useState } from 'react'; -import Button from 'components/kit/Button'; -import Checkbox from 'components/kit/Checkbox'; -import Form from 'components/kit/Form'; -import Icon from 'components/kit/Icon'; -import Input from 'components/kit/Input'; -import InputNumber from 'components/kit/InputNumber'; -import Message from 'components/kit/Message'; -import Select, { Option, SelectValue } from 'components/kit/Select'; -import { Loadable } from 'components/kit/utils/loadable'; import Link from 'components/Link'; import useModal, { ModalHooks as Hooks, ModalCloseReason } from 'hooks/useModal/useModal'; import { paths } from 'routes/utils'; diff --git a/webui/react/src/hooks/usePageVisibility.ts b/webui/react/src/hooks/usePageVisibility.ts index c0cca2461c1..0fc3eff31bf 100644 --- a/webui/react/src/hooks/usePageVisibility.ts +++ b/webui/react/src/hooks/usePageVisibility.ts @@ -1,7 +1,6 @@ +import useUI from 'determined-ui/Theme'; import { useCallback, useEffect, useMemo } from 'react'; -import useUI from 'components/kit/Theme'; - interface DocumentHidden { hidden?: unknown; msHidden?: unknown; diff --git a/webui/react/src/hooks/usePermissions.common.tsx b/webui/react/src/hooks/usePermissions.common.tsx index f9275dc9579..fe5389da546 100644 --- a/webui/react/src/hooks/usePermissions.common.tsx +++ b/webui/react/src/hooks/usePermissions.common.tsx @@ -1,7 +1,7 @@ import { render, RenderResult } from '@testing-library/react'; +import { UIProvider } from 'determined-ui/Theme'; import React from 'react'; -import { UIProvider } from 'components/kit/Theme'; import usePermissions from 'hooks/usePermissions'; import { ActionWorkspaceParams } from 'services/types'; @@ -20,7 +20,7 @@ vi.mock('services/api', () => ({ })); vi.mock('stores/users', async (importOriginal) => { - const loadable = await import('components/kit/utils/loadable'); + const loadable = await import('determined-ui/utils/loadable'); const observable = await import('utils/observable'); const store = { currentUser: observable.observable( diff --git a/webui/react/src/hooks/usePermissions.rbacAdmin.test.tsx b/webui/react/src/hooks/usePermissions.rbacAdmin.test.tsx index 81dada7e30b..42952950b1e 100644 --- a/webui/react/src/hooks/usePermissions.rbacAdmin.test.tsx +++ b/webui/react/src/hooks/usePermissions.rbacAdmin.test.tsx @@ -18,7 +18,7 @@ vi.mock('stores/determinedInfo', async (importOriginal) => { }); vi.mock('stores/permissions', async (importOriginal) => { - const loadable = await import('components/kit/utils/loadable'); + const loadable = await import('determined-ui/utils/loadable'); const observable = await import('utils/observable'); const assigned = observable.observable( loadable.Loaded([ diff --git a/webui/react/src/hooks/usePermissions.rbacReadOnly.test.tsx b/webui/react/src/hooks/usePermissions.rbacReadOnly.test.tsx index 0fea2eb2ca6..fbcee61f910 100644 --- a/webui/react/src/hooks/usePermissions.rbacReadOnly.test.tsx +++ b/webui/react/src/hooks/usePermissions.rbacReadOnly.test.tsx @@ -18,7 +18,7 @@ vi.mock('stores/determinedInfo', async (importOriginal) => { }); vi.mock('stores/permissions', async (importOriginal) => { - const loadable = await import('components/kit/utils/loadable'); + const loadable = await import('determined-ui/utils/loadable'); const observable = await import('utils/observable'); const assigned = observable.observable( loadable.Loaded([ diff --git a/webui/react/src/hooks/usePermissions.ts b/webui/react/src/hooks/usePermissions.ts index 7d50319f000..b70c61b69fb 100644 --- a/webui/react/src/hooks/usePermissions.ts +++ b/webui/react/src/hooks/usePermissions.ts @@ -1,7 +1,7 @@ +import { Loadable } from 'determined-ui/utils/loadable'; import { useObservable } from 'micro-observables'; import { useMemo } from 'react'; -import { Loadable } from 'components/kit/utils/loadable'; import { V1PermissionType } from 'services/api-ts-sdk/api'; import determinedStore from 'stores/determinedInfo'; import permissionStore from 'stores/permissions'; diff --git a/webui/react/src/hooks/usePolling.ts b/webui/react/src/hooks/usePolling.ts index b46dafbe94b..835d645b3bd 100644 --- a/webui/react/src/hooks/usePolling.ts +++ b/webui/react/src/hooks/usePolling.ts @@ -1,7 +1,6 @@ +import useUI from 'determined-ui/Theme'; import { useCallback, useEffect, useRef } from 'react'; -import useUI from 'components/kit/Theme'; - type PollingFn = (() => Promise) | (() => void); interface PollingHooks { diff --git a/webui/react/src/hooks/useSettings.test.tsx b/webui/react/src/hooks/useSettings.test.tsx index 6d0ea6f15a8..b0629bc698b 100644 --- a/webui/react/src/hooks/useSettings.test.tsx +++ b/webui/react/src/hooks/useSettings.test.tsx @@ -1,10 +1,10 @@ import { waitFor } from '@testing-library/react'; import { act, renderHook, RenderResult } from '@testing-library/react-hooks'; +import { UIProvider } from 'determined-ui/Theme'; import { array, boolean, number, string, undefined as undefinedType, union } from 'io-ts'; import React, { useEffect } from 'react'; import { BrowserRouter } from 'react-router-dom'; -import { UIProvider } from 'components/kit/Theme'; import authStore from 'stores/auth'; import userStore from 'stores/users'; import userSettings from 'stores/userSettings'; diff --git a/webui/react/src/hooks/useSettings.ts b/webui/react/src/hooks/useSettings.ts index 4ddbf7fdbaf..98c8af88ae6 100644 --- a/webui/react/src/hooks/useSettings.ts +++ b/webui/react/src/hooks/useSettings.ts @@ -1,3 +1,4 @@ +import { Loadable } from 'determined-ui/utils/loadable'; import { Map } from 'immutable'; import * as t from 'io-ts'; import _ from 'lodash'; @@ -5,7 +6,6 @@ import { useObservable } from 'micro-observables'; import { useCallback, useContext, useEffect, useMemo } from 'react'; import { useNavigate } from 'react-router-dom'; -import { Loadable } from 'components/kit/utils/loadable'; import userStore from 'stores/users'; import userSettings from 'stores/userSettings'; import { Primitive } from 'types'; diff --git a/webui/react/src/hooks/useSettingsProvider.tsx b/webui/react/src/hooks/useSettingsProvider.tsx index 63322ac6f1e..49364eff93c 100644 --- a/webui/react/src/hooks/useSettingsProvider.tsx +++ b/webui/react/src/hooks/useSettingsProvider.tsx @@ -1,8 +1,8 @@ +import Spinner from 'determined-ui/Spinner'; +import { Loadable, NotLoaded } from 'determined-ui/utils/loadable'; import { Map } from 'immutable'; import React, { createContext, useEffect, useRef } from 'react'; -import Spinner from 'components/kit/Spinner'; -import { Loadable, NotLoaded } from 'components/kit/utils/loadable'; import authStore from 'stores/auth'; import userStore from 'stores/users'; import userSettings from 'stores/userSettings'; diff --git a/webui/react/src/hooks/useStorage.ts b/webui/react/src/hooks/useStorage.ts index 6541d190d17..f935af6cb9f 100644 --- a/webui/react/src/hooks/useStorage.ts +++ b/webui/react/src/hooks/useStorage.ts @@ -1,6 +1,6 @@ +import { Loadable } from 'determined-ui/utils/loadable'; import { useState } from 'react'; -import { Loadable } from 'components/kit/utils/loadable'; import { resetUserSetting } from 'services/api'; import userStore from 'stores/users'; import { useObservable } from 'utils/observable'; diff --git a/webui/react/src/hooks/useTheme.settings.ts b/webui/react/src/hooks/useTheme.settings.ts index dfea3440848..9e4abcfde14 100644 --- a/webui/react/src/hooks/useTheme.settings.ts +++ b/webui/react/src/hooks/useTheme.settings.ts @@ -1,6 +1,6 @@ +import { Mode } from 'determined-ui/Theme'; import { literal, union } from 'io-ts'; -import { Mode } from 'components/kit/Theme'; import { SettingsConfig } from 'hooks/useSettings'; export interface Settings { diff --git a/webui/react/src/omnibar/Omnibar.tsx b/webui/react/src/omnibar/Omnibar.tsx index 5538a2b4289..aefcb37977f 100644 --- a/webui/react/src/omnibar/Omnibar.tsx +++ b/webui/react/src/omnibar/Omnibar.tsx @@ -1,7 +1,7 @@ +import { matchesShortcut } from 'determined-ui/InputShortcut'; import OmnibarNpm from 'omnibar'; import React, { useCallback, useEffect, useState } from 'react'; -import { matchesShortcut } from 'components/kit/InputShortcut'; import shortCutSettingsConfig, { Settings as ShortcutSettings, } from 'components/UserSettings.settings'; diff --git a/webui/react/src/omnibar/tree-extension/index.ts b/webui/react/src/omnibar/tree-extension/index.ts index 100cc6c189e..3eab659deb4 100644 --- a/webui/react/src/omnibar/tree-extension/index.ts +++ b/webui/react/src/omnibar/tree-extension/index.ts @@ -1,6 +1,6 @@ +import { makeToast } from 'determined-ui/Toast'; import Fuse from 'fuse.js'; -import { makeToast } from 'components/kit/Toast'; import root from 'omnibar/tree-extension/trees/index'; import { Children, LeafNode, NonLeafNode, TreeNode, TreePath } from 'omnibar/tree-extension/types'; import { getNodeChildren, isLeafNode, isNLNode, traverseTree } from 'omnibar/tree-extension/utils'; diff --git a/webui/react/src/omnibar/tree-extension/trees/actions.tsx b/webui/react/src/omnibar/tree-extension/trees/actions.tsx index d554e17d88b..2ce4a4fa1d6 100644 --- a/webui/react/src/omnibar/tree-extension/trees/actions.tsx +++ b/webui/react/src/omnibar/tree-extension/trees/actions.tsx @@ -1,6 +1,6 @@ import { Modal as AntdModal } from 'antd'; +import { makeToast } from 'determined-ui/Toast'; -import { makeToast } from 'components/kit/Toast'; import root from 'omnibar/tree-extension/trees'; import { FinalAction } from 'omnibar/tree-extension/types'; import { dfsStaticRoutes } from 'omnibar/tree-extension/utils'; diff --git a/webui/react/src/pages/Admin/GroupManagement.tsx b/webui/react/src/pages/Admin/GroupManagement.tsx index c68a1bcca27..7dff27c4fed 100644 --- a/webui/react/src/pages/Admin/GroupManagement.tsx +++ b/webui/react/src/pages/Admin/GroupManagement.tsx @@ -1,16 +1,16 @@ import { Space, Table } from 'antd'; +import Button from 'determined-ui/Button'; +import Dropdown from 'determined-ui/Dropdown'; +import Icon from 'determined-ui/Icon'; +import { useModal } from 'determined-ui/Modal'; +import Nameplate from 'determined-ui/Nameplate'; +import { makeToast } from 'determined-ui/Toast'; import _ from 'lodash'; import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import dropdownCss from 'components/ActionDropdown/ActionDropdown.module.scss'; import CreateGroupModalComponent from 'components/CreateGroupModal'; import DeleteGroupModalComponent from 'components/DeleteGroupModal'; -import Button from 'components/kit/Button'; -import Dropdown from 'components/kit/Dropdown'; -import Icon from 'components/kit/Icon'; -import { useModal } from 'components/kit/Modal'; -import Nameplate from 'components/kit/Nameplate'; -import { makeToast } from 'components/kit/Toast'; import Section from 'components/Section'; import InteractiveTable, { onRightClickableCell } from 'components/Table/InteractiveTable'; import SkeletonTable from 'components/Table/SkeletonTable'; diff --git a/webui/react/src/pages/Admin/UserManagement.test.tsx b/webui/react/src/pages/Admin/UserManagement.test.tsx index aff6c192ae0..0ab44d65053 100644 --- a/webui/react/src/pages/Admin/UserManagement.test.tsx +++ b/webui/react/src/pages/Admin/UserManagement.test.tsx @@ -1,11 +1,11 @@ import { render, screen } from '@testing-library/react'; +import { UIProvider } from 'determined-ui/Theme'; import React, { useCallback, useEffect } from 'react'; import { DndProvider } from 'react-dnd'; import { HTML5Backend } from 'react-dnd-html5-backend'; import { HelmetProvider } from 'react-helmet-async'; import { BrowserRouter } from 'react-router-dom'; -import { UIProvider } from 'components/kit/Theme'; import { SettingsProvider } from 'hooks/useSettingsProvider'; import authStore from 'stores/auth'; import userStore from 'stores/users'; diff --git a/webui/react/src/pages/Admin/UserManagement.tsx b/webui/react/src/pages/Admin/UserManagement.tsx index 7fc2a4946ae..315dbb77abe 100644 --- a/webui/react/src/pages/Admin/UserManagement.tsx +++ b/webui/react/src/pages/Admin/UserManagement.tsx @@ -1,6 +1,12 @@ import { Space } from 'antd'; import { SortOrder } from 'antd/es/table/interface'; import { FilterDropdownProps } from 'antd/lib/table/interface'; +import Button from 'determined-ui/Button'; +import Dropdown, { MenuItem } from 'determined-ui/Dropdown'; +import Icon from 'determined-ui/Icon'; +import { useModal } from 'determined-ui/Modal'; +import { makeToast } from 'determined-ui/Toast'; +import { Loadable } from 'determined-ui/utils/loadable'; import _ from 'lodash'; import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; @@ -9,12 +15,6 @@ import AddUsersToGroupsModalComponent from 'components/AddUsersToGroupsModal'; import ChangeUserStatusModalComponent from 'components/ChangeUserStatusModal'; import ConfigureAgentModalComponent from 'components/ConfigureAgentModal'; import CreateUserModalComponent from 'components/CreateUserModal'; -import Button from 'components/kit/Button'; -import Dropdown, { MenuItem } from 'components/kit/Dropdown'; -import Icon from 'components/kit/Icon'; -import { useModal } from 'components/kit/Modal'; -import { makeToast } from 'components/kit/Toast'; -import { Loadable } from 'components/kit/utils/loadable'; import ManageGroupsModalComponent from 'components/ManageGroupsModal'; import Section from 'components/Section'; import SetUserRolesModalComponent from 'components/SetUserRolesModal'; diff --git a/webui/react/src/pages/Admin/index.tsx b/webui/react/src/pages/Admin/index.tsx index 82e9331a964..4fbbb415823 100644 --- a/webui/react/src/pages/Admin/index.tsx +++ b/webui/react/src/pages/Admin/index.tsx @@ -1,8 +1,8 @@ import type { TabsProps } from 'antd'; +import Pivot from 'determined-ui/Pivot'; import React, { useCallback, useMemo, useState } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; -import Pivot from 'components/kit/Pivot'; import Page from 'components/Page'; import usePermissions from 'hooks/usePermissions'; import GroupManagement from 'pages/Admin/GroupManagement'; diff --git a/webui/react/src/pages/Cluster/ClusterHistoricalUsage.tsx b/webui/react/src/pages/Cluster/ClusterHistoricalUsage.tsx index 31817f3562b..da59c15d771 100644 --- a/webui/react/src/pages/Cluster/ClusterHistoricalUsage.tsx +++ b/webui/react/src/pages/Cluster/ClusterHistoricalUsage.tsx @@ -1,9 +1,9 @@ import { Space } from 'antd'; import dayjs from 'dayjs'; +import Button from 'determined-ui/Button'; +import { Loadable, Loaded, NotLoaded } from 'determined-ui/utils/loadable'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; -import Button from 'components/kit/Button'; -import { Loadable, Loaded, NotLoaded } from 'components/kit/utils/loadable'; import Section from 'components/Section'; import { SyncProvider } from 'components/UPlot/SyncProvider'; import { useSettings } from 'hooks/useSettings'; diff --git a/webui/react/src/pages/Cluster/ClusterHistoricalUsageChart.tsx b/webui/react/src/pages/Cluster/ClusterHistoricalUsageChart.tsx index cb4b05421d0..8f67a860980 100644 --- a/webui/react/src/pages/Cluster/ClusterHistoricalUsageChart.tsx +++ b/webui/react/src/pages/Cluster/ClusterHistoricalUsageChart.tsx @@ -1,8 +1,8 @@ import dayjs from 'dayjs'; +import Message from 'determined-ui/Message'; import React, { useMemo } from 'react'; import uPlot, { AlignedData, Series } from 'uplot'; -import Message from 'components/kit/Message'; import UPlotChart, { Options } from 'components/UPlot/UPlotChart'; import { glasbeyColor } from 'utils/color'; diff --git a/webui/react/src/pages/Cluster/ClusterHistoricalUsageCsvModal.tsx b/webui/react/src/pages/Cluster/ClusterHistoricalUsageCsvModal.tsx index b47c83162f5..109918518ba 100644 --- a/webui/react/src/pages/Cluster/ClusterHistoricalUsageCsvModal.tsx +++ b/webui/react/src/pages/Cluster/ClusterHistoricalUsageCsvModal.tsx @@ -1,9 +1,9 @@ import { Form, Modal, Select } from 'antd'; import dayjs, { Dayjs } from 'dayjs'; +import DatePicker from 'determined-ui/DatePicker'; +import Icon from 'determined-ui/Icon'; import React from 'react'; -import DatePicker from 'components/kit/DatePicker'; -import Icon from 'components/kit/Icon'; import { handlePath, serverAddress } from 'routes/utils'; import { ValueOf } from 'types'; diff --git a/webui/react/src/pages/Cluster/ClusterHistoricalUsageFilters.tsx b/webui/react/src/pages/Cluster/ClusterHistoricalUsageFilters.tsx index 2fd84a60900..76c68624f94 100644 --- a/webui/react/src/pages/Cluster/ClusterHistoricalUsageFilters.tsx +++ b/webui/react/src/pages/Cluster/ClusterHistoricalUsageFilters.tsx @@ -1,8 +1,8 @@ import dayjs, { Dayjs } from 'dayjs'; +import DatePicker from 'determined-ui/DatePicker'; +import Select, { Option, SelectValue } from 'determined-ui/Select'; import React from 'react'; -import DatePicker from 'components/kit/DatePicker'; -import Select, { Option, SelectValue } from 'components/kit/Select'; import ResponsiveFilters from 'components/ResponsiveFilters'; import { DEFAULT_RANGE_DAY, diff --git a/webui/react/src/pages/Cluster/ClusterOverallBar.tsx b/webui/react/src/pages/Cluster/ClusterOverallBar.tsx index 1ae00e070d8..f6aaeed73fb 100644 --- a/webui/react/src/pages/Cluster/ClusterOverallBar.tsx +++ b/webui/react/src/pages/Cluster/ClusterOverallBar.tsx @@ -1,9 +1,9 @@ +import Message from 'determined-ui/Message'; +import Spinner from 'determined-ui/Spinner'; +import { ShirtSize } from 'determined-ui/Theme'; +import { Loadable } from 'determined-ui/utils/loadable'; import React, { useMemo } from 'react'; -import Message from 'components/kit/Message'; -import Spinner from 'components/kit/Spinner'; -import { ShirtSize } from 'components/kit/Theme'; -import { Loadable } from 'components/kit/utils/loadable'; import Section from 'components/Section'; import SlotAllocationBar from 'components/SlotAllocationBar'; import clusterStore from 'stores/cluster'; diff --git a/webui/react/src/pages/Cluster/ClusterOverallStats.test.tsx b/webui/react/src/pages/Cluster/ClusterOverallStats.test.tsx index 5e0a350ed55..c8591d783e0 100644 --- a/webui/react/src/pages/Cluster/ClusterOverallStats.test.tsx +++ b/webui/react/src/pages/Cluster/ClusterOverallStats.test.tsx @@ -1,6 +1,5 @@ import { render } from '@testing-library/react'; - -import { UIProvider } from 'components/kit/Theme'; +import { UIProvider } from 'determined-ui/Theme'; import { ClusterOverallStats } from './ClusterOverallStats'; diff --git a/webui/react/src/pages/Cluster/ClusterOverallStats.tsx b/webui/react/src/pages/Cluster/ClusterOverallStats.tsx index 578119c0967..b9fcd28b99b 100644 --- a/webui/react/src/pages/Cluster/ClusterOverallStats.tsx +++ b/webui/react/src/pages/Cluster/ClusterOverallStats.tsx @@ -1,8 +1,8 @@ +import Card from 'determined-ui/Card'; +import Spinner from 'determined-ui/Spinner'; +import { Loadable } from 'determined-ui/utils/loadable'; import React, { ReactNode, useEffect, useMemo } from 'react'; -import Card from 'components/kit/Card'; -import Spinner from 'components/kit/Spinner'; -import { Loadable } from 'components/kit/utils/loadable'; import OverviewStats from 'components/OverviewStats'; import Section from 'components/Section'; import { activeRunStates } from 'constants/states'; diff --git a/webui/react/src/pages/ClusterLogs.tsx b/webui/react/src/pages/ClusterLogs.tsx index 82c4927576f..fae414a4cb8 100644 --- a/webui/react/src/pages/ClusterLogs.tsx +++ b/webui/react/src/pages/ClusterLogs.tsx @@ -1,10 +1,10 @@ -import React, { useCallback } from 'react'; - import LogViewer, { FetchConfig, FetchDirection, FetchType, -} from 'components/kit/LogViewer/LogViewer'; +} from 'determined-ui/LogViewer/LogViewer'; +import React, { useCallback } from 'react'; + import { serverAddress } from 'routes/utils'; import { detApi } from 'services/apiConfig'; import { jsonToClusterLog } from 'services/decoder'; diff --git a/webui/react/src/pages/Clusters.tsx b/webui/react/src/pages/Clusters.tsx index 4d1d54cb6e2..1f7b1cf2a23 100644 --- a/webui/react/src/pages/Clusters.tsx +++ b/webui/react/src/pages/Clusters.tsx @@ -1,8 +1,8 @@ import type { TabsProps } from 'antd'; +import Pivot from 'determined-ui/Pivot'; import React, { useCallback, useMemo, useState } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; -import Pivot from 'components/kit/Pivot'; import Page from 'components/Page'; import usePermissions from 'hooks/usePermissions'; import { paths } from 'routes/utils'; diff --git a/webui/react/src/pages/Clusters/ClustersOverview.tsx b/webui/react/src/pages/Clusters/ClustersOverview.tsx index 7f2eb8537a5..5c01c95c6b5 100644 --- a/webui/react/src/pages/Clusters/ClustersOverview.tsx +++ b/webui/react/src/pages/Clusters/ClustersOverview.tsx @@ -1,8 +1,8 @@ +import Card from 'determined-ui/Card'; +import Icon from 'determined-ui/Icon'; +import { Loadable } from 'determined-ui/utils/loadable'; import React, { useCallback, useState } from 'react'; -import Card from 'components/kit/Card'; -import Icon from 'components/kit/Icon'; -import { Loadable } from 'components/kit/utils/loadable'; import ResourcePoolCard from 'components/ResourcePoolCard'; import ResourcePoolDetails from 'components/ResourcePoolDetails'; import Section from 'components/Section'; diff --git a/webui/react/src/pages/Dashboard.tsx b/webui/react/src/pages/Dashboard.tsx index 4273ec90ca2..baddd128ae3 100644 --- a/webui/react/src/pages/Dashboard.tsx +++ b/webui/react/src/pages/Dashboard.tsx @@ -1,13 +1,13 @@ +import Breadcrumb from 'determined-ui/Breadcrumb'; +import Card from 'determined-ui/Card'; +import Icon from 'determined-ui/Icon'; +import Message from 'determined-ui/Message'; +import Spinner from 'determined-ui/Spinner'; +import { Loadable } from 'determined-ui/utils/loadable'; import React, { useCallback, useEffect, useState } from 'react'; import ExperimentIcons from 'components/ExperimentIcons'; import JupyterLabButton from 'components/JupyterLabButton'; -import Breadcrumb from 'components/kit/Breadcrumb'; -import Card from 'components/kit/Card'; -import Icon from 'components/kit/Icon'; -import Message from 'components/kit/Message'; -import Spinner from 'components/kit/Spinner'; -import { Loadable } from 'components/kit/utils/loadable'; import Link from 'components/Link'; import Page, { BreadCrumbRoute } from 'components/Page'; import ProjectCard from 'components/ProjectCard'; diff --git a/webui/react/src/pages/Deprecated.tsx b/webui/react/src/pages/Deprecated.tsx index b4d3bdc43e8..06ca7eeb193 100644 --- a/webui/react/src/pages/Deprecated.tsx +++ b/webui/react/src/pages/Deprecated.tsx @@ -1,7 +1,6 @@ +import Spinner from 'determined-ui/Spinner'; import React from 'react'; -import Spinner from 'components/kit/Spinner'; - /** placeholder page for depracated pages. displayed while the user is redirected */ const Redirect: React.FC = () => ; diff --git a/webui/react/src/pages/DesignKit.module.scss b/webui/react/src/pages/DesignKit.module.scss index 972499dc52c..2fd1e396184 100644 --- a/webui/react/src/pages/DesignKit.module.scss +++ b/webui/react/src/pages/DesignKit.module.scss @@ -1,7 +1,5 @@ /* stylelint-disable no-descending-specificity */ -@import '../components/kit/Typography/index.module'; - .base { display: flex; gap: 8px; diff --git a/webui/react/src/pages/DesignKit.tsx b/webui/react/src/pages/DesignKit.tsx index 8788809e6c3..593e198e578 100644 --- a/webui/react/src/pages/DesignKit.tsx +++ b/webui/react/src/pages/DesignKit.tsx @@ -1,50 +1,51 @@ import { Card as AntDCard, Space } from 'antd'; import { SelectValue } from 'antd/es/select'; +import Accordion from 'determined-ui/Accordion'; +import Avatar from 'determined-ui/Avatar'; +import Breadcrumb from 'determined-ui/Breadcrumb'; +import Button from 'determined-ui/Button'; +import Card from 'determined-ui/Card'; +import Checkbox from 'determined-ui/Checkbox'; +import ClipboardButton from 'determined-ui/ClipboardButton'; +import CodeEditor from 'determined-ui/CodeEditor'; +import { Column, Columns } from 'determined-ui/Columns'; +import DatePicker from 'determined-ui/DatePicker'; +import Drawer from 'determined-ui/Drawer'; +import Dropdown, { MenuItem } from 'determined-ui/Dropdown'; +import Form from 'determined-ui/Form'; +import Icon, { IconNameArray, IconSizeArray } from 'determined-ui/Icon'; +import InlineForm from 'determined-ui/InlineForm'; +import Input from 'determined-ui/Input'; +import InputNumber from 'determined-ui/InputNumber'; +import InputSearch from 'determined-ui/InputSearch'; +import InputShortcut, { KeyboardShortcut } from 'determined-ui/InputShortcut'; +import { TypographySize } from 'determined-ui/internal/fonts'; +import { MetricType, Note, Serie, XAxisDomain } from 'determined-ui/internal/types'; +import { LineChart } from 'determined-ui/LineChart'; +import { useChartGrid } from 'determined-ui/LineChart/useChartGrid'; +import LogViewer from 'determined-ui/LogViewer/LogViewer'; +import Message from 'determined-ui/Message'; +import { Modal, useModal } from 'determined-ui/Modal'; +import Nameplate from 'determined-ui/Nameplate'; +import Notes, { Props as NotesProps } from 'determined-ui/Notes'; +import Pagination from 'determined-ui/Pagination'; +import Pivot from 'determined-ui/Pivot'; +import Select, { Option } from 'determined-ui/Select'; +import Spinner from 'determined-ui/Spinner'; +import useUI from 'determined-ui/Theme'; +import { makeToast } from 'determined-ui/Toast'; +import Toggle from 'determined-ui/Toggle'; +import Tooltip from 'determined-ui/Tooltip'; +import Header from 'determined-ui/Typography/Header'; +import Paragraph from 'determined-ui/Typography/Paragraph'; +import useConfirm, { voidPromiseFn } from 'determined-ui/useConfirm'; +import { useTags } from 'determined-ui/useTags'; +import { Loadable, Loaded, NotLoaded } from 'determined-ui/utils/loadable'; +import { ValueOf } from 'determined-ui/utils/types'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { Link, useLocation } from 'react-router-dom'; import Grid from 'components/Grid'; -import Accordion from 'components/kit/Accordion'; -import Avatar from 'components/kit/Avatar'; -import Breadcrumb from 'components/kit/Breadcrumb'; -import Button from 'components/kit/Button'; -import Card from 'components/kit/Card'; -import Checkbox from 'components/kit/Checkbox'; -import ClipboardButton from 'components/kit/ClipboardButton'; -import CodeEditor from 'components/kit/CodeEditor'; -import { Column, Columns } from 'components/kit/Columns'; -import DatePicker from 'components/kit/DatePicker'; -import Drawer from 'components/kit/Drawer'; -import Dropdown, { MenuItem } from 'components/kit/Dropdown'; -import Form from 'components/kit/Form'; -import Icon, { IconNameArray, IconSizeArray } from 'components/kit/Icon'; -import InlineForm from 'components/kit/InlineForm'; -import Input from 'components/kit/Input'; -import InputNumber from 'components/kit/InputNumber'; -import InputSearch from 'components/kit/InputSearch'; -import InputShortcut, { KeyboardShortcut } from 'components/kit/InputShortcut'; -import { TypographySize } from 'components/kit/internal/fonts'; -import { MetricType, Note, Serie, ValueOf, XAxisDomain } from 'components/kit/internal/types'; -import { LineChart } from 'components/kit/LineChart'; -import { useChartGrid } from 'components/kit/LineChart/useChartGrid'; -import LogViewer from 'components/kit/LogViewer/LogViewer'; -import Message from 'components/kit/Message'; -import { Modal, useModal } from 'components/kit/Modal'; -import Nameplate from 'components/kit/Nameplate'; -import Notes, { Props as NotesProps } from 'components/kit/Notes'; -import Pagination from 'components/kit/Pagination'; -import Pivot from 'components/kit/Pivot'; -import Select, { Option } from 'components/kit/Select'; -import Spinner from 'components/kit/Spinner'; -import useUI from 'components/kit/Theme'; -import { makeToast } from 'components/kit/Toast'; -import Toggle from 'components/kit/Toggle'; -import Tooltip from 'components/kit/Tooltip'; -import Header from 'components/kit/Typography/Header'; -import Paragraph from 'components/kit/Typography/Paragraph'; -import useConfirm, { voidPromiseFn } from 'components/kit/useConfirm'; -import { useTags } from 'components/kit/useTags'; -import { Loadable, Loaded, NotLoaded } from 'components/kit/utils/loadable'; import Label from 'components/Label'; import KitLink from 'components/Link'; import Logo from 'components/Logo'; diff --git a/webui/react/src/pages/ExperimentDetails/ExperimentCheckpoints.tsx b/webui/react/src/pages/ExperimentDetails/ExperimentCheckpoints.tsx index 0864778f650..e7448b61c93 100644 --- a/webui/react/src/pages/ExperimentDetails/ExperimentCheckpoints.tsx +++ b/webui/react/src/pages/ExperimentDetails/ExperimentCheckpoints.tsx @@ -1,11 +1,11 @@ import { FilterDropdownProps } from 'antd/es/table/interface'; +import { useModal } from 'determined-ui/Modal'; +import useConfirm from 'determined-ui/useConfirm'; import React, { Key, useCallback, useEffect, useMemo, useState } from 'react'; import ActionDropdown from 'components/ActionDropdown'; import Badge, { BadgeType } from 'components/Badge'; import CheckpointModalTrigger from 'components/CheckpointModalTrigger'; -import { useModal } from 'components/kit/Modal'; -import useConfirm from 'components/kit/useConfirm'; import ModelCreateModal from 'components/ModelCreateModal'; import Section from 'components/Section'; import InteractiveTable, { ContextMenuProps } from 'components/Table/InteractiveTable'; diff --git a/webui/react/src/pages/ExperimentDetails/ExperimentCodeViewer.test.tsx b/webui/react/src/pages/ExperimentDetails/ExperimentCodeViewer.test.tsx index 2d8749b3e00..4a21f47a038 100644 --- a/webui/react/src/pages/ExperimentDetails/ExperimentCodeViewer.test.tsx +++ b/webui/react/src/pages/ExperimentDetails/ExperimentCodeViewer.test.tsx @@ -1,10 +1,10 @@ import { findAllByText, screen } from '@testing-library/dom'; import { render } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; +import { UIProvider } from 'determined-ui/Theme'; import React, { useEffect, useState } from 'react'; import { BrowserRouter } from 'react-router-dom'; -import { UIProvider } from 'components/kit/Theme'; import { SettingsProvider } from 'hooks/useSettingsProvider'; import { paths } from 'routes/utils'; import authStore from 'stores/auth'; diff --git a/webui/react/src/pages/ExperimentDetails/ExperimentCodeViewer.tsx b/webui/react/src/pages/ExperimentDetails/ExperimentCodeViewer.tsx index 5d9f4736ca0..ec84ad545ab 100644 --- a/webui/react/src/pages/ExperimentDetails/ExperimentCodeViewer.tsx +++ b/webui/react/src/pages/ExperimentDetails/ExperimentCodeViewer.tsx @@ -1,10 +1,10 @@ +import Icon from 'determined-ui/Icon'; +import Spinner from 'determined-ui/Spinner'; +import { Failed, Loadable, Loaded, NotLoaded } from 'determined-ui/utils/loadable'; +import { TreeNode } from 'determined-ui/utils/types'; import yaml from 'js-yaml'; import React, { useEffect, useMemo, useState } from 'react'; -import Icon from 'components/kit/Icon'; -import { TreeNode } from 'components/kit/internal/types'; -import Spinner from 'components/kit/Spinner'; -import { Failed, Loadable, Loaded, NotLoaded } from 'components/kit/utils/loadable'; import { paths } from 'routes/utils'; import { getExperimentFileFromTree, getExperimentFileTree } from 'services/api'; import { V1FileNode } from 'services/api-ts-sdk'; @@ -14,7 +14,7 @@ import { isSingleTrialExperiment } from 'utils/experiment'; import css from './ExperimentCodeViewer.module.scss'; -const CodeEditor = React.lazy(() => import('components/kit/CodeEditor')); +const CodeEditor = React.lazy(() => import('determined-ui/CodeEditor')); const configIcon = ; diff --git a/webui/react/src/pages/ExperimentDetails/ExperimentDetails.test.tsx b/webui/react/src/pages/ExperimentDetails/ExperimentDetails.test.tsx index 4f56efa6be5..1d3d6471ab9 100644 --- a/webui/react/src/pages/ExperimentDetails/ExperimentDetails.test.tsx +++ b/webui/react/src/pages/ExperimentDetails/ExperimentDetails.test.tsx @@ -1,7 +1,7 @@ import { render, screen, waitFor } from '@testing-library/react'; +import { UIProvider } from 'determined-ui/Theme'; import { HelmetProvider } from 'react-helmet-async'; -import { UIProvider } from 'components/kit/Theme'; import { getExperimentDetails, getExpTrials, diff --git a/webui/react/src/pages/ExperimentDetails/ExperimentDetails.tsx b/webui/react/src/pages/ExperimentDetails/ExperimentDetails.tsx index dcfd831135a..f1ae8be6404 100644 --- a/webui/react/src/pages/ExperimentDetails/ExperimentDetails.tsx +++ b/webui/react/src/pages/ExperimentDetails/ExperimentDetails.tsx @@ -1,10 +1,10 @@ +import Message from 'determined-ui/Message'; +import Spinner from 'determined-ui/Spinner'; +import { Loadable } from 'determined-ui/utils/loadable'; import _ from 'lodash'; import React, { useCallback, useEffect, useRef, useState } from 'react'; import { useParams } from 'react-router-dom'; -import Message from 'components/kit/Message'; -import Spinner from 'components/kit/Spinner'; -import { Loadable } from 'components/kit/utils/loadable'; import Page, { BreadCrumbRoute } from 'components/Page'; import { terminalRunStates } from 'constants/states'; import usePolling from 'hooks/usePolling'; diff --git a/webui/react/src/pages/ExperimentDetails/ExperimentDetailsHeader.tsx b/webui/react/src/pages/ExperimentDetails/ExperimentDetailsHeader.tsx index 433948be51e..6eb174e9fa6 100644 --- a/webui/react/src/pages/ExperimentDetails/ExperimentDetailsHeader.tsx +++ b/webui/react/src/pages/ExperimentDetails/ExperimentDetailsHeader.tsx @@ -1,4 +1,10 @@ import { Button, Space, Typography } from 'antd'; +import Icon from 'determined-ui/Icon'; +import { useModal } from 'determined-ui/Modal'; +import Spinner from 'determined-ui/Spinner'; +import Tags from 'determined-ui/Tags'; +import { getStateColorCssVar } from 'determined-ui/Theme'; +import Tooltip from 'determined-ui/Tooltip'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; import Badge from 'components/Badge'; @@ -11,12 +17,6 @@ import ExperimentIcons from 'components/ExperimentIcons'; import ExperimentMoveModalComponent from 'components/ExperimentMoveModal'; import ExperimentStopModalComponent from 'components/ExperimentStopModal'; import InfoBox, { InfoRow } from 'components/InfoBox'; -import Icon from 'components/kit/Icon'; -import { useModal } from 'components/kit/Modal'; -import Spinner from 'components/kit/Spinner'; -import Tags from 'components/kit/Tags'; -import { getStateColorCssVar } from 'components/kit/Theme'; -import Tooltip from 'components/kit/Tooltip'; import Link from 'components/Link'; import PageHeaderFoldable, { Option } from 'components/PageHeaderFoldable'; import TimeAgo from 'components/TimeAgo'; diff --git a/webui/react/src/pages/ExperimentDetails/ExperimentMultiTrialTabs.tsx b/webui/react/src/pages/ExperimentDetails/ExperimentMultiTrialTabs.tsx index 612d89e259f..649adad8187 100644 --- a/webui/react/src/pages/ExperimentDetails/ExperimentMultiTrialTabs.tsx +++ b/webui/react/src/pages/ExperimentDetails/ExperimentMultiTrialTabs.tsx @@ -1,11 +1,11 @@ import type { TabsProps } from 'antd'; +import Notes from 'determined-ui/Notes'; +import Pivot from 'determined-ui/Pivot'; +import Spinner from 'determined-ui/Spinner'; import { string } from 'io-ts'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; -import { useLocation, useNavigate, useParams } from 'react-router-dom'; +import { unstable_useBlocker, useLocation, useNavigate, useParams } from 'react-router-dom'; -import Notes from 'components/kit/Notes'; -import Pivot from 'components/kit/Pivot'; -import Spinner from 'components/kit/Spinner'; import usePermissions from 'hooks/usePermissions'; import { SettingsConfig, useSettings } from 'hooks/useSettings'; import ExperimentCodeViewer from 'pages/ExperimentDetails/ExperimentCodeViewer'; @@ -165,6 +165,7 @@ const ExperimentMultiTrialTabs: React.FC = ({ disableTitle notes={{ contents: experiment.notes ?? '', name: 'Notes' }} onError={handleError} + onPageUnloadHook={unstable_useBlocker} onSave={handleNotesUpdate} /> ), diff --git a/webui/react/src/pages/ExperimentDetails/ExperimentSingleTrialTabs.tsx b/webui/react/src/pages/ExperimentDetails/ExperimentSingleTrialTabs.tsx index 380d595c145..ab6ced7e17a 100644 --- a/webui/react/src/pages/ExperimentDetails/ExperimentSingleTrialTabs.tsx +++ b/webui/react/src/pages/ExperimentDetails/ExperimentSingleTrialTabs.tsx @@ -1,14 +1,14 @@ import type { TabsProps } from 'antd'; +import Button from 'determined-ui/Button'; +import Message from 'determined-ui/Message'; +import Notes from 'determined-ui/Notes'; +import Pivot from 'determined-ui/Pivot'; +import Spinner from 'determined-ui/Spinner'; +import Tooltip from 'determined-ui/Tooltip'; import { string } from 'io-ts'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; -import { useLocation, useNavigate, useParams } from 'react-router-dom'; - -import Button from 'components/kit/Button'; -import Message from 'components/kit/Message'; -import Notes from 'components/kit/Notes'; -import Pivot from 'components/kit/Pivot'; -import Spinner from 'components/kit/Spinner'; -import Tooltip from 'components/kit/Tooltip'; +import { unstable_useBlocker, useLocation, useNavigate, useParams } from 'react-router-dom'; + import TrialLogPreview from 'components/TrialLogPreview'; import { UNMANAGED_MESSAGE } from 'constant'; import { terminalRunStates } from 'constants/states'; @@ -298,6 +298,7 @@ const ExperimentSingleTrialTabs: React.FC = ({ disableTitle notes={{ contents: experiment.notes ?? '', name: 'Notes' }} onError={handleError} + onPageUnloadHook={unstable_useBlocker} onSave={handleNotesUpdate} /> ), diff --git a/webui/react/src/pages/ExperimentDetails/ExperimentTrials.tsx b/webui/react/src/pages/ExperimentDetails/ExperimentTrials.tsx index 14e3a200a5e..b32b1c9ce44 100644 --- a/webui/react/src/pages/ExperimentDetails/ExperimentTrials.tsx +++ b/webui/react/src/pages/ExperimentDetails/ExperimentTrials.tsx @@ -1,12 +1,12 @@ import { TablePaginationConfig } from 'antd'; import { FilterDropdownProps, FilterValue, SorterResult } from 'antd/es/table/interface'; +import Dropdown from 'determined-ui/Dropdown'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; import ActionDropdown from 'components/ActionDropdown'; import Badge, { BadgeType } from 'components/Badge'; import CheckpointModalTrigger from 'components/CheckpointModalTrigger'; import HumanReadableNumber from 'components/HumanReadableNumber'; -import Dropdown from 'components/kit/Dropdown'; import Link from 'components/Link'; import Section from 'components/Section'; import InteractiveTable, { onRightClickableCell } from 'components/Table/InteractiveTable'; diff --git a/webui/react/src/pages/ExperimentDetails/ExperimentVisualization.tsx b/webui/react/src/pages/ExperimentDetails/ExperimentVisualization.tsx index 85029ce06ff..ff075ff4106 100644 --- a/webui/react/src/pages/ExperimentDetails/ExperimentVisualization.tsx +++ b/webui/react/src/pages/ExperimentDetails/ExperimentVisualization.tsx @@ -1,13 +1,13 @@ import { type TabsProps } from 'antd'; +import Message from 'determined-ui/Message'; +import Pivot from 'determined-ui/Pivot'; +import Spinner from 'determined-ui/Spinner'; +import useUI from 'determined-ui/Theme'; +import { Loadable } from 'determined-ui/utils/loadable'; import { useObservable } from 'micro-observables'; import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useLocation, useNavigate, useParams } from 'react-router-dom'; -import Message from 'components/kit/Message'; -import Pivot from 'components/kit/Pivot'; -import Spinner from 'components/kit/Spinner'; -import useUI from 'components/kit/Theme'; -import { Loadable } from 'components/kit/utils/loadable'; import Link from 'components/Link'; import { terminalRunStates } from 'constants/states'; import useMetricNames from 'hooks/useMetricNames'; diff --git a/webui/react/src/pages/ExperimentDetails/ExperimentVisualization/ExperimentVisualizationFilters.tsx b/webui/react/src/pages/ExperimentDetails/ExperimentVisualization/ExperimentVisualizationFilters.tsx index b66d18c24ad..255694a4223 100644 --- a/webui/react/src/pages/ExperimentDetails/ExperimentVisualization/ExperimentVisualizationFilters.tsx +++ b/webui/react/src/pages/ExperimentDetails/ExperimentVisualization/ExperimentVisualizationFilters.tsx @@ -1,11 +1,11 @@ +import Button from 'determined-ui/Button'; +import Icon from 'determined-ui/Icon'; +import Select, { Option, SelectValue } from 'determined-ui/Select'; import * as t from 'io-ts'; import _ from 'lodash'; import React, { useCallback, useEffect, useMemo } from 'react'; import HpSelect from 'components/HpSelect'; -import Button from 'components/kit/Button'; -import Icon from 'components/kit/Icon'; -import Select, { Option, SelectValue } from 'components/kit/Select'; import MetricSelect from 'components/MetricSelect'; import RadioGroup from 'components/RadioGroup'; import ScaleSelect from 'components/ScaleSelect'; diff --git a/webui/react/src/pages/ExperimentDetails/ExperimentVisualization/HpHeatMaps.tsx b/webui/react/src/pages/ExperimentDetails/ExperimentVisualization/HpHeatMaps.tsx index a0275c09515..e9efbe9b6a4 100644 --- a/webui/react/src/pages/ExperimentDetails/ExperimentVisualization/HpHeatMaps.tsx +++ b/webui/react/src/pages/ExperimentDetails/ExperimentVisualization/HpHeatMaps.tsx @@ -1,11 +1,11 @@ +import Message from 'determined-ui/Message'; +import Spinner from 'determined-ui/Spinner'; +import useUI from 'determined-ui/Theme'; import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import ColorLegend from 'components/ColorLegend'; import GalleryModal from 'components/GalleryModal'; import Grid, { GridMode } from 'components/Grid'; -import Message from 'components/kit/Message'; -import Spinner from 'components/kit/Spinner'; -import useUI from 'components/kit/Theme'; import MetricBadgeTag from 'components/MetricBadgeTag'; import Section from 'components/Section'; import { FacetedData, UPlotScatterProps } from 'components/UPlot/types'; diff --git a/webui/react/src/pages/ExperimentDetails/ExperimentVisualization/HpParallelCoordinates.tsx b/webui/react/src/pages/ExperimentDetails/ExperimentVisualization/HpParallelCoordinates.tsx index d10f16eaa9d..969010dad5b 100644 --- a/webui/react/src/pages/ExperimentDetails/ExperimentVisualization/HpParallelCoordinates.tsx +++ b/webui/react/src/pages/ExperimentDetails/ExperimentVisualization/HpParallelCoordinates.tsx @@ -1,9 +1,9 @@ +import Message from 'determined-ui/Message'; +import Spinner from 'determined-ui/Spinner'; +import useUI from 'determined-ui/Theme'; import Hermes, { DimensionType } from 'hermes-parallel-coordinates'; import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import Message from 'components/kit/Message'; -import Spinner from 'components/kit/Spinner'; -import useUI from 'components/kit/Theme'; import ParallelCoordinates from 'components/ParallelCoordinates'; import Section from 'components/Section'; import TableBatch from 'components/Table/TableBatch'; diff --git a/webui/react/src/pages/ExperimentDetails/ExperimentVisualization/HpScatterPlots.tsx b/webui/react/src/pages/ExperimentDetails/ExperimentVisualization/HpScatterPlots.tsx index 0a4fed26d47..c7f65b40211 100644 --- a/webui/react/src/pages/ExperimentDetails/ExperimentVisualization/HpScatterPlots.tsx +++ b/webui/react/src/pages/ExperimentDetails/ExperimentVisualization/HpScatterPlots.tsx @@ -1,10 +1,10 @@ +import Message from 'determined-ui/Message'; +import Spinner from 'determined-ui/Spinner'; +import useUI from 'determined-ui/Theme'; import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import GalleryModal from 'components/GalleryModal'; import Grid, { GridMode } from 'components/Grid'; -import Message from 'components/kit/Message'; -import Spinner from 'components/kit/Spinner'; -import useUI from 'components/kit/Theme'; import Section from 'components/Section'; import { FacetedData, UPlotScatterProps } from 'components/UPlot/types'; import UPlotScatter from 'components/UPlot/UPlotScatter'; diff --git a/webui/react/src/pages/ExperimentDetails/ExperimentVisualization/LearningCurve.tsx b/webui/react/src/pages/ExperimentDetails/ExperimentVisualization/LearningCurve.tsx index 0e22c9f0d4e..fbf9d6647fe 100644 --- a/webui/react/src/pages/ExperimentDetails/ExperimentVisualization/LearningCurve.tsx +++ b/webui/react/src/pages/ExperimentDetails/ExperimentVisualization/LearningCurve.tsx @@ -1,11 +1,11 @@ +import { LineChart } from 'determined-ui/LineChart'; +import Message from 'determined-ui/Message'; +import Spinner from 'determined-ui/Spinner'; +import useUI from 'determined-ui/Theme'; +import { Loadable, Loaded, NotLoaded } from 'determined-ui/utils/loadable'; import _ from 'lodash'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; -import { LineChart } from 'components/kit/LineChart'; -import Message from 'components/kit/Message'; -import Spinner from 'components/kit/Spinner'; -import useUI from 'components/kit/Theme'; -import { Loadable, Loaded, NotLoaded } from 'components/kit/utils/loadable'; import Section from 'components/Section'; import TableBatch from 'components/Table/TableBatch'; import { UPlotPoint } from 'components/UPlot/types'; diff --git a/webui/react/src/pages/ExperimentDetails/Header/ExperimentHeaderProgress.tsx b/webui/react/src/pages/ExperimentDetails/Header/ExperimentHeaderProgress.tsx index 7b7e6261e8d..d88e2560880 100644 --- a/webui/react/src/pages/ExperimentDetails/Header/ExperimentHeaderProgress.tsx +++ b/webui/react/src/pages/ExperimentDetails/Header/ExperimentHeaderProgress.tsx @@ -1,8 +1,8 @@ import { Progress } from 'antd'; +import { getStateColorCssVar } from 'determined-ui/Theme'; +import Tooltip from 'determined-ui/Tooltip'; import React from 'react'; -import { getStateColorCssVar } from 'components/kit/Theme'; -import Tooltip from 'components/kit/Tooltip'; import { ExperimentBase, JobState, RunState } from 'types'; import css from './ExperimentHeaderProgress.module.scss'; diff --git a/webui/react/src/pages/ExperimentDetails/TrialsComparisonModal.tsx b/webui/react/src/pages/ExperimentDetails/TrialsComparisonModal.tsx index 602f6b89e0b..8a188e911d0 100644 --- a/webui/react/src/pages/ExperimentDetails/TrialsComparisonModal.tsx +++ b/webui/react/src/pages/ExperimentDetails/TrialsComparisonModal.tsx @@ -1,14 +1,14 @@ import { Modal, Tag, Typography } from 'antd'; +import Message from 'determined-ui/Message'; +import Select, { Option, SelectValue } from 'determined-ui/Select'; +import Spinner from 'determined-ui/Spinner'; +import { Loadable } from 'determined-ui/utils/loadable'; +import usePrevious from 'determined-ui/utils/usePrevious'; import _ from 'lodash'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; import Badge, { BadgeType } from 'components/Badge'; import HumanReadableNumber from 'components/HumanReadableNumber'; -import usePrevious from 'components/kit/internal/usePrevious'; -import Message from 'components/kit/Message'; -import Select, { Option, SelectValue } from 'components/kit/Select'; -import Spinner from 'components/kit/Spinner'; -import { Loadable } from 'components/kit/utils/loadable'; import Link from 'components/Link'; import MetricBadgeTag from 'components/MetricBadgeTag'; import MetricSelect from 'components/MetricSelect'; diff --git a/webui/react/src/pages/ExperimentList.tsx b/webui/react/src/pages/ExperimentList.tsx index 6506cd347a3..9099611d682 100644 --- a/webui/react/src/pages/ExperimentList.tsx +++ b/webui/react/src/pages/ExperimentList.tsx @@ -1,5 +1,13 @@ import { Space, Typography } from 'antd'; import { FilterDropdownProps } from 'antd/lib/table/interface'; +import Button from 'determined-ui/Button'; +import Dropdown, { MenuItem } from 'determined-ui/Dropdown'; +import Icon from 'determined-ui/Icon'; +import Input from 'determined-ui/Input'; +import { useModal } from 'determined-ui/Modal'; +import Tags from 'determined-ui/Tags'; +import Toggle from 'determined-ui/Toggle'; +import { Loadable } from 'determined-ui/utils/loadable'; import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react'; import Badge, { BadgeType } from 'components/Badge'; @@ -10,14 +18,6 @@ import ExperimentActionDropdown from 'components/ExperimentActionDropdown'; import ExperimentMoveModalComponent from 'components/ExperimentMoveModal'; import FilterCounter from 'components/FilterCounter'; import HumanReadableNumber from 'components/HumanReadableNumber'; -import Button from 'components/kit/Button'; -import Dropdown, { MenuItem } from 'components/kit/Dropdown'; -import Icon from 'components/kit/Icon'; -import Input from 'components/kit/Input'; -import { useModal } from 'components/kit/Modal'; -import Tags from 'components/kit/Tags'; -import Toggle from 'components/kit/Toggle'; -import { Loadable } from 'components/kit/utils/loadable'; import Link from 'components/Link'; import InteractiveTable, { ColumnDef, diff --git a/webui/react/src/pages/F_ExpList/CompareMetrics.tsx b/webui/react/src/pages/F_ExpList/CompareMetrics.tsx index 1418983413c..91f05a4548b 100644 --- a/webui/react/src/pages/F_ExpList/CompareMetrics.tsx +++ b/webui/react/src/pages/F_ExpList/CompareMetrics.tsx @@ -1,8 +1,8 @@ +import { ChartGrid, ChartsProps } from 'determined-ui/LineChart'; +import { Loadable, Loaded, NotLoaded } from 'determined-ui/utils/loadable'; import _ from 'lodash'; import React, { useMemo, useState } from 'react'; -import { ChartGrid, ChartsProps } from 'components/kit/LineChart'; -import { Loadable, Loaded, NotLoaded } from 'components/kit/utils/loadable'; import MetricBadgeTag from 'components/MetricBadgeTag'; import { MapOfIdsToColors, useGlasbey } from 'hooks/useGlasbey'; import { TrialMetricData } from 'pages/TrialDetails/useTrialMetrics'; diff --git a/webui/react/src/pages/F_ExpList/CompareParallelCoordinates.tsx b/webui/react/src/pages/F_ExpList/CompareParallelCoordinates.tsx index 9d1808022c6..7311ea5960c 100644 --- a/webui/react/src/pages/F_ExpList/CompareParallelCoordinates.tsx +++ b/webui/react/src/pages/F_ExpList/CompareParallelCoordinates.tsx @@ -1,8 +1,8 @@ +import Message from 'determined-ui/Message'; +import Spinner from 'determined-ui/Spinner'; import Hermes, { DimensionType } from 'hermes-parallel-coordinates'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; -import Message from 'components/kit/Message'; -import Spinner from 'components/kit/Spinner'; import ParallelCoordinates from 'components/ParallelCoordinates'; import Section from 'components/Section'; import { useGlasbey } from 'hooks/useGlasbey'; diff --git a/webui/react/src/pages/F_ExpList/ComparisonView.tsx b/webui/react/src/pages/F_ExpList/ComparisonView.tsx index efad6526617..96ed31f916a 100644 --- a/webui/react/src/pages/F_ExpList/ComparisonView.tsx +++ b/webui/react/src/pages/F_ExpList/ComparisonView.tsx @@ -1,7 +1,7 @@ +import Message from 'determined-ui/Message'; +import Pivot, { TabItem } from 'determined-ui/Pivot'; import React, { useMemo } from 'react'; -import Message from 'components/kit/Message'; -import Pivot, { TabItem } from 'components/kit/Pivot'; import SplitPane from 'components/SplitPane'; import useScrollbarWidth from 'hooks/useScrollbarWidth'; import { TrialsComparisonTable } from 'pages/ExperimentDetails/TrialsComparisonModal'; diff --git a/webui/react/src/pages/F_ExpList/F_ExperimentList.tsx b/webui/react/src/pages/F_ExpList/F_ExperimentList.tsx index ca03436bdbe..3868ab21a3f 100644 --- a/webui/react/src/pages/F_ExpList/F_ExperimentList.tsx +++ b/webui/react/src/pages/F_ExpList/F_ExperimentList.tsx @@ -1,5 +1,11 @@ import { CompactSelection, GridSelection, Rectangle } from '@hpe.com/glide-data-grid'; import { Space } from 'antd'; +import { Column, Columns } from 'determined-ui/Columns'; +import Message from 'determined-ui/Message'; +import Pagination from 'determined-ui/Pagination'; +import { getCssVar } from 'determined-ui/Theme'; +import { notification } from 'determined-ui/Toast'; +import { Loadable, Loaded, NotLoaded } from 'determined-ui/utils/loadable'; import { isLeft } from 'fp-ts/lib/Either'; import { observable, useObservable } from 'micro-observables'; import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; @@ -12,12 +18,6 @@ import { FormGroup, IOFilterFormSet, } from 'components/FilterForm/components/type'; -import { Column, Columns } from 'components/kit/Columns'; -import Message from 'components/kit/Message'; -import Pagination from 'components/kit/Pagination'; -import { getCssVar } from 'components/kit/Theme'; -import { notification } from 'components/kit/Toast'; -import { Loadable, Loaded, NotLoaded } from 'components/kit/utils/loadable'; import { useGlasbey } from 'hooks/useGlasbey'; import useMobile from 'hooks/useMobile'; import usePolling from 'hooks/usePolling'; diff --git a/webui/react/src/pages/F_ExpList/glide-table/ColumnPickerMenu.tsx b/webui/react/src/pages/F_ExpList/glide-table/ColumnPickerMenu.tsx index 732aa19c652..06402acdea2 100644 --- a/webui/react/src/pages/F_ExpList/glide-table/ColumnPickerMenu.tsx +++ b/webui/react/src/pages/F_ExpList/glide-table/ColumnPickerMenu.tsx @@ -1,16 +1,16 @@ import { Space } from 'antd'; import { CheckboxChangeEvent } from 'antd/es/checkbox'; +import Button from 'determined-ui/Button'; +import Checkbox from 'determined-ui/Checkbox'; +import Dropdown from 'determined-ui/Dropdown'; +import Icon from 'determined-ui/Icon'; +import Input from 'determined-ui/Input'; +import Message from 'determined-ui/Message'; +import Pivot from 'determined-ui/Pivot'; +import Spinner from 'determined-ui/Spinner'; +import { Loadable } from 'determined-ui/utils/loadable'; import React, { ChangeEvent, useCallback, useMemo, useState } from 'react'; -import Button from 'components/kit/Button'; -import Checkbox from 'components/kit/Checkbox'; -import Dropdown from 'components/kit/Dropdown'; -import Icon from 'components/kit/Icon'; -import Input from 'components/kit/Input'; -import Message from 'components/kit/Message'; -import Pivot from 'components/kit/Pivot'; -import Spinner from 'components/kit/Spinner'; -import { Loadable } from 'components/kit/utils/loadable'; import { useSettings } from 'hooks/useSettings'; import { F_ExperimentListSettings, diff --git a/webui/react/src/pages/F_ExpList/glide-table/GlideTable.tsx b/webui/react/src/pages/F_ExpList/glide-table/GlideTable.tsx index 96aa8028c1c..d181b1ec514 100644 --- a/webui/react/src/pages/F_ExpList/glide-table/GlideTable.tsx +++ b/webui/react/src/pages/F_ExpList/glide-table/GlideTable.tsx @@ -14,6 +14,10 @@ import DataEditor, { Theme, } from '@hpe.com/glide-data-grid'; import { DrawHeaderCallback } from '@hpe.com/glide-data-grid/dist/ts/data-grid/data-grid-types'; +import { DropdownEvent, MenuItem } from 'determined-ui/Dropdown'; +import Icon from 'determined-ui/Icon'; +import useUI, { getCssVar } from 'determined-ui/Theme'; +import { Loadable } from 'determined-ui/utils/loadable'; import { literal, union } from 'io-ts'; import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { v4 as uuidv4 } from 'uuid'; @@ -25,10 +29,6 @@ import { Operator, SpecialColumnNames, } from 'components/FilterForm/components/type'; -import { DropdownEvent, MenuItem } from 'components/kit/Dropdown'; -import Icon from 'components/kit/Icon'; -import useUI, { getCssVar } from 'components/kit/Theme'; -import { Loadable } from 'components/kit/utils/loadable'; import { MapOfIdsToColors } from 'hooks/useGlasbey'; import useMobile from 'hooks/useMobile'; import { type HandleSelectionChangeType, PAGE_SIZE } from 'pages/F_ExpList/F_ExperimentList'; diff --git a/webui/react/src/pages/F_ExpList/glide-table/MultiSortMenu.tsx b/webui/react/src/pages/F_ExpList/glide-table/MultiSortMenu.tsx index 7685f89e35d..57862372b20 100644 --- a/webui/react/src/pages/F_ExpList/glide-table/MultiSortMenu.tsx +++ b/webui/react/src/pages/F_ExpList/glide-table/MultiSortMenu.tsx @@ -1,10 +1,10 @@ +import Button from 'determined-ui/Button'; +import Dropdown, { MenuItem } from 'determined-ui/Dropdown'; +import Icon from 'determined-ui/Icon'; +import Select from 'determined-ui/Select'; +import { Loadable } from 'determined-ui/utils/loadable'; import * as io from 'io-ts'; -import Button from 'components/kit/Button'; -import Dropdown, { MenuItem } from 'components/kit/Dropdown'; -import Icon from 'components/kit/Icon'; -import Select from 'components/kit/Select'; -import { Loadable } from 'components/kit/utils/loadable'; import { V1ColumnType } from 'services/api-ts-sdk'; import { ProjectColumn } from 'types'; diff --git a/webui/react/src/pages/F_ExpList/glide-table/OptionsMenu.tsx b/webui/react/src/pages/F_ExpList/glide-table/OptionsMenu.tsx index 7db66350ca5..5c5971442ab 100644 --- a/webui/react/src/pages/F_ExpList/glide-table/OptionsMenu.tsx +++ b/webui/react/src/pages/F_ExpList/glide-table/OptionsMenu.tsx @@ -1,10 +1,10 @@ +import Button from 'determined-ui/Button'; +import Dropdown, { MenuItem } from 'determined-ui/Dropdown'; +import Icon from 'determined-ui/Icon'; +import Toggle from 'determined-ui/Toggle'; import { TypeOf } from 'io-ts'; import { useMemo } from 'react'; -import Button from 'components/kit/Button'; -import Dropdown, { MenuItem } from 'components/kit/Dropdown'; -import Icon from 'components/kit/Icon'; -import Toggle from 'components/kit/Toggle'; import { valueof } from 'ioTypes'; import { TableViewMode } from './GlideTable'; diff --git a/webui/react/src/pages/F_ExpList/glide-table/TableActionBar.tsx b/webui/react/src/pages/F_ExpList/glide-table/TableActionBar.tsx index 14964c204b2..664aee3af8e 100644 --- a/webui/react/src/pages/F_ExpList/glide-table/TableActionBar.tsx +++ b/webui/react/src/pages/F_ExpList/glide-table/TableActionBar.tsx @@ -1,4 +1,12 @@ import { Space } from 'antd'; +import Button from 'determined-ui/Button'; +import { Column, Columns } from 'determined-ui/Columns'; +import Dropdown, { MenuItem } from 'determined-ui/Dropdown'; +import Icon, { IconName } from 'determined-ui/Icon'; +import { useModal } from 'determined-ui/Modal'; +import { makeToast } from 'determined-ui/Toast'; +import Tooltip from 'determined-ui/Tooltip'; +import { Loadable } from 'determined-ui/utils/loadable'; import React, { useCallback, useMemo, useState } from 'react'; import BatchActionConfirmModalComponent from 'components/BatchActionConfirmModal'; @@ -6,14 +14,6 @@ import ExperimentMoveModalComponent from 'components/ExperimentMoveModal'; import ExperimentTensorBoardModal from 'components/ExperimentTensorBoardModal'; import { FilterFormStore } from 'components/FilterForm/components/FilterFormStore'; import TableFilter from 'components/FilterForm/TableFilter'; -import Button from 'components/kit/Button'; -import { Column, Columns } from 'components/kit/Columns'; -import Dropdown, { MenuItem } from 'components/kit/Dropdown'; -import Icon, { IconName } from 'components/kit/Icon'; -import { useModal } from 'components/kit/Modal'; -import { makeToast } from 'components/kit/Toast'; -import Tooltip from 'components/kit/Tooltip'; -import { Loadable } from 'components/kit/utils/loadable'; import useMobile from 'hooks/useMobile'; import usePermissions from 'hooks/usePermissions'; import { diff --git a/webui/react/src/pages/F_ExpList/glide-table/columns.ts b/webui/react/src/pages/F_ExpList/glide-table/columns.ts index 97406b34662..666ddc022de 100644 --- a/webui/react/src/pages/F_ExpList/glide-table/columns.ts +++ b/webui/react/src/pages/F_ExpList/glide-table/columns.ts @@ -6,10 +6,10 @@ import { Theme as GTheme, SizedGridColumn, } from '@hpe.com/glide-data-grid'; +import { getColor, getInitials } from 'determined-ui/Avatar'; +import { DarkLight, Theme } from 'determined-ui/Theme'; +import { Loadable } from 'determined-ui/utils/loadable'; -import { getColor, getInitials } from 'components/kit/Avatar'; -import { DarkLight, Theme } from 'components/kit/Theme'; -import { Loadable } from 'components/kit/utils/loadable'; import { paths } from 'routes/utils'; import { DetailedUser, ExperimentWithTrial, ProjectColumn } from 'types'; import { getPath, isString } from 'utils/data'; diff --git a/webui/react/src/pages/F_ExpList/glide-table/contextMenu.tsx b/webui/react/src/pages/F_ExpList/glide-table/contextMenu.tsx index b1a7daa3a97..03bbaab8e97 100644 --- a/webui/react/src/pages/F_ExpList/glide-table/contextMenu.tsx +++ b/webui/react/src/pages/F_ExpList/glide-table/contextMenu.tsx @@ -1,9 +1,9 @@ import { GridCell } from '@hpe.com/glide-data-grid'; import { MenuProps } from 'antd'; +import { DropdownEvent } from 'determined-ui/Dropdown'; import React, { MutableRefObject, useCallback, useEffect, useRef } from 'react'; import ExperimentActionDropdown from 'components/ExperimentActionDropdown'; -import { DropdownEvent } from 'components/kit/Dropdown'; import { ExperimentAction, ExperimentItem, ProjectExperiment } from 'types'; // eslint-disable-next-line diff --git a/webui/react/src/pages/F_ExpList/glide-table/custom-renderers/cells/experimentStateCell.tsx b/webui/react/src/pages/F_ExpList/glide-table/custom-renderers/cells/experimentStateCell.tsx index 127daf508f9..029741f9671 100644 --- a/webui/react/src/pages/F_ExpList/glide-table/custom-renderers/cells/experimentStateCell.tsx +++ b/webui/react/src/pages/F_ExpList/glide-table/custom-renderers/cells/experimentStateCell.tsx @@ -1,6 +1,6 @@ import { CustomCell, CustomRenderer, GridCellKind } from '@hpe.com/glide-data-grid'; +import { Theme } from 'determined-ui/Theme'; -import { Theme } from 'components/kit/Theme'; import { roundedRect } from 'pages/F_ExpList/glide-table/custom-renderers/utils'; import { CompoundRunState, JobState, RunState } from 'types'; diff --git a/webui/react/src/pages/F_ExpList/glide-table/custom-renderers/cells/loadingCell.tsx b/webui/react/src/pages/F_ExpList/glide-table/custom-renderers/cells/loadingCell.tsx index 0ce540f8fd4..b02e227565e 100644 --- a/webui/react/src/pages/F_ExpList/glide-table/custom-renderers/cells/loadingCell.tsx +++ b/webui/react/src/pages/F_ExpList/glide-table/custom-renderers/cells/loadingCell.tsx @@ -1,6 +1,6 @@ import { CustomCell, CustomRenderer, GridCellKind } from '@hpe.com/glide-data-grid'; +import { Theme } from 'determined-ui/Theme'; -import { Theme } from 'components/kit/Theme'; import { roundedRect } from 'pages/F_ExpList/glide-table/custom-renderers/utils'; import { rgba2str, rgbaFromGradient, str2rgba } from 'utils/color'; diff --git a/webui/react/src/pages/F_ExpList/glide-table/exceptions.tsx b/webui/react/src/pages/F_ExpList/glide-table/exceptions.tsx index 4b1674e4acf..009ad57addc 100644 --- a/webui/react/src/pages/F_ExpList/glide-table/exceptions.tsx +++ b/webui/react/src/pages/F_ExpList/glide-table/exceptions.tsx @@ -1,7 +1,7 @@ +import Button from 'determined-ui/Button'; +import Message from 'determined-ui/Message'; import React from 'react'; -import Button from 'components/kit/Button'; -import Message from 'components/kit/Message'; import Link from 'components/Link'; import { paths } from 'routes/utils'; diff --git a/webui/react/src/pages/F_ExpList/glide-table/menu.tsx b/webui/react/src/pages/F_ExpList/glide-table/menu.tsx index f71b25b4285..2ce3f3a1abe 100644 --- a/webui/react/src/pages/F_ExpList/glide-table/menu.tsx +++ b/webui/react/src/pages/F_ExpList/glide-table/menu.tsx @@ -1,8 +1,7 @@ import { Rectangle } from '@hpe.com/glide-data-grid'; +import Dropdown, { MenuItem } from 'determined-ui/Dropdown'; import React, { MutableRefObject, useEffect, useRef } from 'react'; -import Dropdown, { MenuItem } from 'components/kit/Dropdown'; - // eslint-disable-next-line function useOutsideClickHandler(ref: MutableRefObject, handler: () => void) { useEffect(() => { diff --git a/webui/react/src/pages/F_ExpList/glide-table/tooltip.tsx b/webui/react/src/pages/F_ExpList/glide-table/tooltip.tsx index afb6d0e4b80..533c6a0daab 100644 --- a/webui/react/src/pages/F_ExpList/glide-table/tooltip.tsx +++ b/webui/react/src/pages/F_ExpList/glide-table/tooltip.tsx @@ -1,9 +1,8 @@ import { DataEditorProps, GridMouseEventArgs } from '@hpe.com/glide-data-grid'; import { Tooltip } from 'antd'; +import { Loadable } from 'determined-ui/utils/loadable'; import React, { ReactNode, useCallback, useEffect, useMemo } from 'react'; -import { Loadable } from 'components/kit/utils/loadable'; - import { ColumnDefs } from './columns'; import { GlideTableProps } from './GlideTable'; diff --git a/webui/react/src/pages/F_ExpList/glide-table/utils.ts b/webui/react/src/pages/F_ExpList/glide-table/utils.ts index fb9ad086c5e..35a701abec2 100644 --- a/webui/react/src/pages/F_ExpList/glide-table/utils.ts +++ b/webui/react/src/pages/F_ExpList/glide-table/utils.ts @@ -1,7 +1,7 @@ import { DataEditorProps } from '@hpe.com/glide-data-grid'; import dayjs from 'dayjs'; +import { Theme } from 'determined-ui/Theme'; -import { Theme } from 'components/kit/Theme'; import { ExperimentItem } from 'types'; import { DURATION_MINUTE, diff --git a/webui/react/src/pages/InteractiveTask.test.tsx b/webui/react/src/pages/InteractiveTask.test.tsx index 9ae3a621d2c..18eac092e83 100644 --- a/webui/react/src/pages/InteractiveTask.test.tsx +++ b/webui/react/src/pages/InteractiveTask.test.tsx @@ -1,11 +1,11 @@ import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; +import { UIProvider } from 'determined-ui/Theme'; +import { ConfirmationProvider } from 'determined-ui/useConfirm'; import React, { useEffect } from 'react'; import { HelmetProvider } from 'react-helmet-async'; import { BrowserRouter } from 'react-router-dom'; -import { UIProvider } from 'components/kit/Theme'; -import { ConfirmationProvider } from 'components/kit/useConfirm'; import authStore from 'stores/auth'; import InteractiveTask from './InteractiveTask'; diff --git a/webui/react/src/pages/InteractiveTask.tsx b/webui/react/src/pages/InteractiveTask.tsx index c4a892ca4b8..308468ead22 100644 --- a/webui/react/src/pages/InteractiveTask.tsx +++ b/webui/react/src/pages/InteractiveTask.tsx @@ -1,8 +1,8 @@ +import useUI from 'determined-ui/Theme'; import React, { useEffect, useState } from 'react'; import { Helmet } from 'react-helmet-async'; import { useParams, useSearchParams } from 'react-router-dom'; -import useUI from 'components/kit/Theme'; import TaskBar from 'components/TaskBar'; import { getTask } from 'services/api'; import { CommandState, CommandType, ValueOf } from 'types'; diff --git a/webui/react/src/pages/JobQueue/JobQueue.table.tsx b/webui/react/src/pages/JobQueue/JobQueue.table.tsx index 12c53bc1cb7..9583d357dd4 100644 --- a/webui/react/src/pages/JobQueue/JobQueue.table.tsx +++ b/webui/react/src/pages/JobQueue/JobQueue.table.tsx @@ -1,8 +1,8 @@ +import Icon from 'determined-ui/Icon'; +import Tooltip from 'determined-ui/Tooltip'; import React, { ReactNode } from 'react'; import Badge, { BadgeType } from 'components/Badge'; -import Icon from 'components/kit/Icon'; -import Tooltip from 'components/kit/Tooltip'; import Link from 'components/Link'; import { ColumnDef } from 'components/Table/InteractiveTable'; import { createOmitableRenderer, relativeTimeRenderer } from 'components/Table/Table'; diff --git a/webui/react/src/pages/JobQueue/JobQueue.tsx b/webui/react/src/pages/JobQueue/JobQueue.tsx index 5643626da0b..973a39c9471 100644 --- a/webui/react/src/pages/JobQueue/JobQueue.tsx +++ b/webui/react/src/pages/JobQueue/JobQueue.tsx @@ -1,10 +1,10 @@ +import Icon from 'determined-ui/Icon'; +import { DetError } from 'determined-ui/utils/error'; +import { Loadable } from 'determined-ui/utils/loadable'; import _ from 'lodash'; import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import ActionDropdown, { Triggers } from 'components/ActionDropdown'; -import Icon from 'components/kit/Icon'; -import { DetError } from 'components/kit/internal/types'; -import { Loadable } from 'components/kit/utils/loadable'; import Section from 'components/Section'; import InteractiveTable, { ColumnDef } from 'components/Table/InteractiveTable'; import SkeletonTable from 'components/Table/SkeletonTable'; diff --git a/webui/react/src/pages/JobQueue/ManageJob.tsx b/webui/react/src/pages/JobQueue/ManageJob.tsx index d40437731d5..ddd72787fdc 100644 --- a/webui/react/src/pages/JobQueue/ManageJob.tsx +++ b/webui/react/src/pages/JobQueue/ManageJob.tsx @@ -1,10 +1,10 @@ import { List, Modal, Select, Typography } from 'antd'; +import Form from 'determined-ui/Form'; +import Input from 'determined-ui/Input'; +import { Loadable } from 'determined-ui/utils/loadable'; import React, { ReactNode, useCallback, useMemo, useState } from 'react'; import Badge, { BadgeType } from 'components/Badge'; -import Form from 'components/kit/Form'; -import Input from 'components/kit/Input'; -import { Loadable } from 'components/kit/utils/loadable'; import { columns } from 'pages/JobQueue/JobQueue.table'; import { getJobQ, updateJobQueue } from 'services/api'; import * as api from 'services/api-ts-sdk'; diff --git a/webui/react/src/pages/ModelDetails.tsx b/webui/react/src/pages/ModelDetails.tsx index 03dd816aa23..a54640520fe 100644 --- a/webui/react/src/pages/ModelDetails.tsx +++ b/webui/react/src/pages/ModelDetails.tsx @@ -1,15 +1,15 @@ import { Typography } from 'antd'; import { FilterValue, SorterResult, TablePaginationConfig } from 'antd/lib/table/interface'; +import Input from 'determined-ui/Input'; +import Message from 'determined-ui/Message'; +import Notes from 'determined-ui/Notes'; +import Spinner from 'determined-ui/Spinner'; +import Tags, { tagsActionHelper } from 'determined-ui/Tags'; +import { Loadable, Loaded, NotLoaded } from 'determined-ui/utils/loadable'; import _ from 'lodash'; import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import { useParams } from 'react-router-dom'; +import { unstable_useBlocker, useParams } from 'react-router-dom'; -import Input from 'components/kit/Input'; -import Message from 'components/kit/Message'; -import Notes from 'components/kit/Notes'; -import Spinner from 'components/kit/Spinner'; -import Tags, { tagsActionHelper } from 'components/kit/Tags'; -import { Loadable, Loaded, NotLoaded } from 'components/kit/utils/loadable'; import MetadataCard from 'components/Metadata/MetadataCard'; import Page, { BreadCrumbRoute } from 'components/Page'; import PageNotFound from 'components/PageNotFound'; @@ -462,6 +462,7 @@ const ModelDetails: React.FC = () => { disableTitle notes={{ contents: model.notes ?? '', name: 'Notes' }} onError={handleError} + onPageUnloadHook={unstable_useBlocker} onSave={saveNotes} /> { disableTitle notes={{ contents: modelVersion.notes ?? '', name: 'Notes' }} onError={handleError} + onPageUnloadHook={unstable_useBlocker} onSave={saveNotes} />
    diff --git a/webui/react/src/pages/ModelVersionDetails/ModelVersionHeader.tsx b/webui/react/src/pages/ModelVersionDetails/ModelVersionHeader.tsx index 7603500bd02..ea672fd62d4 100644 --- a/webui/react/src/pages/ModelVersionDetails/ModelVersionHeader.tsx +++ b/webui/react/src/pages/ModelVersionDetails/ModelVersionHeader.tsx @@ -1,15 +1,15 @@ import { Modal, Space, Typography } from 'antd'; +import Button from 'determined-ui/Button'; +import ClipboardButton from 'determined-ui/ClipboardButton'; +import Dropdown, { MenuOption } from 'determined-ui/Dropdown'; +import Icon from 'determined-ui/Icon'; +import { useModal } from 'determined-ui/Modal'; +import Spinner from 'determined-ui/Spinner'; +import Tags, { tagsActionHelper } from 'determined-ui/Tags'; +import { Loadable } from 'determined-ui/utils/loadable'; import React, { useCallback, useMemo, useState } from 'react'; import InfoBox, { InfoRow } from 'components/InfoBox'; -import Button from 'components/kit/Button'; -import ClipboardButton from 'components/kit/ClipboardButton'; -import Dropdown, { MenuOption } from 'components/kit/Dropdown'; -import Icon from 'components/kit/Icon'; -import { useModal } from 'components/kit/Modal'; -import Spinner from 'components/kit/Spinner'; -import Tags, { tagsActionHelper } from 'components/kit/Tags'; -import { Loadable } from 'components/kit/utils/loadable'; import ModelDownloadModal from 'components/ModelDownloadModal'; import ModelVersionDeleteModal from 'components/ModelVersionDeleteModal'; import ModelVersionEditModal from 'components/ModelVersionEditModal'; diff --git a/webui/react/src/pages/ProjectDetails.tsx b/webui/react/src/pages/ProjectDetails.tsx index d9cac73e7de..2eda16f3e5b 100644 --- a/webui/react/src/pages/ProjectDetails.tsx +++ b/webui/react/src/pages/ProjectDetails.tsx @@ -1,12 +1,12 @@ import type { TabsProps } from 'antd'; +import Message from 'determined-ui/Message'; +import Spinner from 'determined-ui/Spinner'; +import { Loadable, Loaded, NotLoaded } from 'determined-ui/utils/loadable'; import _ from 'lodash'; import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useParams } from 'react-router-dom'; import DynamicTabs from 'components/DynamicTabs'; -import Message from 'components/kit/Message'; -import Spinner from 'components/kit/Spinner'; -import { Loadable, Loaded, NotLoaded } from 'components/kit/utils/loadable'; import Page, { BreadCrumbRoute } from 'components/Page'; import PageNotFound from 'components/PageNotFound'; import { useProjectActionMenu } from 'components/ProjectActionDropdown'; diff --git a/webui/react/src/pages/ProjectNotes.tsx b/webui/react/src/pages/ProjectNotes.tsx index 7de8a7d2232..d8635d8585a 100644 --- a/webui/react/src/pages/ProjectNotes.tsx +++ b/webui/react/src/pages/ProjectNotes.tsx @@ -1,8 +1,9 @@ +import { useModal } from 'determined-ui/Modal'; +import Notes from 'determined-ui/Notes'; import React, { useCallback, useState } from 'react'; +import { unstable_useBlocker } from 'react-router-dom'; import { useSetDynamicTabBar } from 'components/DynamicTabs'; -import { useModal } from 'components/kit/Modal'; -import Notes from 'components/kit/Notes'; import ProjectNoteDeleteModalComponent from 'components/ProjectNoteDeleteModal'; import usePermissions from 'hooks/usePermissions'; import { addProjectNote, setProjectNotes } from 'services/api'; @@ -68,6 +69,7 @@ const ProjectNotes: React.FC = ({ project, fetchProject }) => { onDelete={handleDeleteNote} onError={handleError} onNewPage={handleNewNotesPage} + onPageUnloadHook={unstable_useBlocker} onSave={handleSaveNotes} /> { return logs.findIndex((log) => log.message.includes(timestamp)); }; -vi.mock('components/kit/internal/useResize', () => { +vi.mock('determined-ui/internal/useResize', () => { const refObject = { current: null }; return { __esModule: true, @@ -149,12 +148,12 @@ vi.mock('components/kit/internal/useResize', () => { }; }); -vi.mock('components/kit/internal/useGetCharMeasureInContainer', () => ({ +vi.mock('determined-ui/internal/useGetCharMeasureInContainer', () => ({ __esModule: true, default: () => ({ height: 18, width: 7 }), })); -vi.mock('components/kit/internal/services', () => ({ +vi.mock('determined-ui/internal/services', () => ({ __esModule: true, readLogStream: ( serverAddress: (path: string) => string, @@ -294,22 +293,18 @@ describe('LogViewer', () => { }); }); - flakyIt( - 'should render logs with streaming', - async () => { - setup({ decoder, onError: handleError, onFetch, serverAddress }); - - await waitFor( - () => { - const lastLog = logsReference[logsReference.length - 1]; - expect(lastLog.message).not.toBeNull(); - expect(screen.queryByText(lastLog.message)).toBeInTheDocument(); - }, - { timeout: 6000 }, - ); - }, - 6500, - ); + it('should render logs with streaming @flaky', async () => { + setup({ decoder, onError: handleError, onFetch, serverAddress }); + + await waitFor( + () => { + const lastLog = logsReference[logsReference.length - 1]; + expect(lastLog.message).not.toBeNull(); + expect(screen.queryByText(lastLog.message)).toBeInTheDocument(); + }, + { timeout: 6000 }, + ); + }, 6500); it('should show oldest logs', async () => { setup({ decoder, onError: handleError, onFetch, serverAddress }); diff --git a/webui/react/src/pages/TaskLogs.tsx b/webui/react/src/pages/TaskLogs.tsx index 7a2530add0f..ac524ab05cf 100644 --- a/webui/react/src/pages/TaskLogs.tsx +++ b/webui/react/src/pages/TaskLogs.tsx @@ -1,13 +1,13 @@ -import React, { useCallback, useEffect, useMemo, useState } from 'react'; -import { useParams, useSearchParams } from 'react-router-dom'; - import LogViewer, { FetchConfig, FetchDirection, FetchType, -} from 'components/kit/LogViewer/LogViewer'; -import LogViewerSelect, { Filters } from 'components/kit/LogViewer/LogViewerSelect'; -import { Settings, settingsConfigForTask } from 'components/kit/LogViewer/LogViewerSelect.settings'; +} from 'determined-ui/LogViewer/LogViewer'; +import LogViewerSelect, { Filters } from 'determined-ui/LogViewer/LogViewerSelect'; +import { Settings, settingsConfigForTask } from 'determined-ui/LogViewer/LogViewerSelect.settings'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import { useParams, useSearchParams } from 'react-router-dom'; + import Page from 'components/Page'; import { commandTypeToLabel } from 'constants/states'; import { useSettings } from 'hooks/useSettings'; diff --git a/webui/react/src/pages/TrialDetails.tsx b/webui/react/src/pages/TrialDetails.tsx index 92999c436b1..6fd0b067adc 100644 --- a/webui/react/src/pages/TrialDetails.tsx +++ b/webui/react/src/pages/TrialDetails.tsx @@ -1,11 +1,11 @@ import type { TabsProps } from 'antd'; +import Message from 'determined-ui/Message'; +import Pivot from 'determined-ui/Pivot'; +import Spinner from 'determined-ui/Spinner'; +import { Loadable } from 'determined-ui/utils/loadable'; import React, { ReactNode, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; -import Message from 'components/kit/Message'; -import Pivot from 'components/kit/Pivot'; -import Spinner from 'components/kit/Spinner'; -import { Loadable } from 'components/kit/utils/loadable'; import Page from 'components/Page'; import RoutePagination from 'components/RoutePagination'; import TrialLogPreview from 'components/TrialLogPreview'; diff --git a/webui/react/src/pages/TrialDetails/Header/TrialHeaderLeft.tsx b/webui/react/src/pages/TrialDetails/Header/TrialHeaderLeft.tsx index 350ce015140..9dbfed2083b 100644 --- a/webui/react/src/pages/TrialDetails/Header/TrialHeaderLeft.tsx +++ b/webui/react/src/pages/TrialDetails/Header/TrialHeaderLeft.tsx @@ -1,8 +1,8 @@ +import Icon from 'determined-ui/Icon'; import React from 'react'; import { Link } from 'react-router-dom'; import ExperimentIcons from 'components/ExperimentIcons'; -import Icon from 'components/kit/Icon'; import { paths } from 'routes/utils'; import { ExperimentBase, TrialDetails } from 'types'; diff --git a/webui/react/src/pages/TrialDetails/MultiTrialDetailsHyperparameters.tsx b/webui/react/src/pages/TrialDetails/MultiTrialDetailsHyperparameters.tsx index b4f5636d785..265c89fcb68 100644 --- a/webui/react/src/pages/TrialDetails/MultiTrialDetailsHyperparameters.tsx +++ b/webui/react/src/pages/TrialDetails/MultiTrialDetailsHyperparameters.tsx @@ -1,7 +1,7 @@ import { Space } from 'antd'; +import { Loadable } from 'determined-ui/utils/loadable'; import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import { Loadable } from 'components/kit/utils/loadable'; import useMetricNames from 'hooks/useMetricNames'; import { useSettings } from 'hooks/useSettings'; import { ExperimentVisualizationType } from 'pages/ExperimentDetails/ExperimentVisualization'; diff --git a/webui/react/src/pages/TrialDetails/Profiles/Charts/SystemMetricChart.tsx b/webui/react/src/pages/TrialDetails/Profiles/Charts/SystemMetricChart.tsx index dd3846a16cc..29a1ffdb2d2 100644 --- a/webui/react/src/pages/TrialDetails/Profiles/Charts/SystemMetricChart.tsx +++ b/webui/react/src/pages/TrialDetails/Profiles/Charts/SystemMetricChart.tsx @@ -1,7 +1,7 @@ +import { LineChart } from 'determined-ui/LineChart'; import { string, undefined as undefinedType, union } from 'io-ts'; import React, { useEffect, useMemo } from 'react'; -import { LineChart } from 'components/kit/LineChart'; import Section from 'components/Section'; import { SettingsConfig, useSettings } from 'hooks/useSettings'; import { ChartProps, MetricType } from 'pages/TrialDetails/Profiles/types'; diff --git a/webui/react/src/pages/TrialDetails/Profiles/Charts/SystemMetricChartFilters.tsx b/webui/react/src/pages/TrialDetails/Profiles/Charts/SystemMetricChartFilters.tsx index 15091b2de61..7c3185f2922 100644 --- a/webui/react/src/pages/TrialDetails/Profiles/Charts/SystemMetricChartFilters.tsx +++ b/webui/react/src/pages/TrialDetails/Profiles/Charts/SystemMetricChartFilters.tsx @@ -1,6 +1,6 @@ +import Select, { Option, SelectValue } from 'determined-ui/Select'; import React, { useCallback, useMemo } from 'react'; -import Select, { Option, SelectValue } from 'components/kit/Select'; import { UpdateSettings } from 'hooks/useSettings'; import { AvailableSeriesType } from 'pages/TrialDetails/Profiles/types'; diff --git a/webui/react/src/pages/TrialDetails/Profiles/Charts/ThroughputMetricChart.tsx b/webui/react/src/pages/TrialDetails/Profiles/Charts/ThroughputMetricChart.tsx index 61ff5d962dd..b987f975462 100644 --- a/webui/react/src/pages/TrialDetails/Profiles/Charts/ThroughputMetricChart.tsx +++ b/webui/react/src/pages/TrialDetails/Profiles/Charts/ThroughputMetricChart.tsx @@ -1,6 +1,6 @@ +import { LineChart } from 'determined-ui/LineChart'; import React from 'react'; -import { LineChart } from 'components/kit/LineChart'; import Section from 'components/Section'; import { ChartProps, MetricType } from 'pages/TrialDetails/Profiles/types'; import { useFetchProfilerMetrics } from 'pages/TrialDetails/Profiles/useFetchProfilerMetrics'; diff --git a/webui/react/src/pages/TrialDetails/Profiles/Charts/TimingMetricChart.tsx b/webui/react/src/pages/TrialDetails/Profiles/Charts/TimingMetricChart.tsx index 8057a988695..c70075bb02e 100644 --- a/webui/react/src/pages/TrialDetails/Profiles/Charts/TimingMetricChart.tsx +++ b/webui/react/src/pages/TrialDetails/Profiles/Charts/TimingMetricChart.tsx @@ -1,6 +1,6 @@ +import { LineChart } from 'determined-ui/LineChart'; import React from 'react'; -import { LineChart } from 'components/kit/LineChart'; import Section from 'components/Section'; import { ChartProps, MetricType } from 'pages/TrialDetails/Profiles/types'; import { useFetchProfilerMetrics } from 'pages/TrialDetails/Profiles/useFetchProfilerMetrics'; diff --git a/webui/react/src/pages/TrialDetails/Profiles/useFetchProfilerMetrics.tsx b/webui/react/src/pages/TrialDetails/Profiles/useFetchProfilerMetrics.tsx index 4967b433f68..720246a3512 100644 --- a/webui/react/src/pages/TrialDetails/Profiles/useFetchProfilerMetrics.tsx +++ b/webui/react/src/pages/TrialDetails/Profiles/useFetchProfilerMetrics.tsx @@ -1,6 +1,6 @@ +import useUI from 'determined-ui/Theme'; import { useEffect, useState } from 'react'; -import useUI from 'components/kit/Theme'; import { terminalRunStates } from 'constants/states'; import { detApi } from 'services/apiConfig'; import { readStream } from 'services/utils'; diff --git a/webui/react/src/pages/TrialDetails/Profiles/useFetchProfilerSeries.ts b/webui/react/src/pages/TrialDetails/Profiles/useFetchProfilerSeries.ts index 5a0e666617a..3ca7a64bdd4 100644 --- a/webui/react/src/pages/TrialDetails/Profiles/useFetchProfilerSeries.ts +++ b/webui/react/src/pages/TrialDetails/Profiles/useFetchProfilerSeries.ts @@ -1,6 +1,6 @@ +import useUI from 'determined-ui/Theme'; import { useEffect, useState } from 'react'; -import useUI from 'components/kit/Theme'; import { V1GetTrialProfilerAvailableSeriesResponse } from 'services/api-ts-sdk'; import { detApi } from 'services/apiConfig'; import { readStream } from 'services/utils'; diff --git a/webui/react/src/pages/TrialDetails/TrialChart.tsx b/webui/react/src/pages/TrialDetails/TrialChart.tsx index af5a3e56df6..3a072c75624 100644 --- a/webui/react/src/pages/TrialDetails/TrialChart.tsx +++ b/webui/react/src/pages/TrialDetails/TrialChart.tsx @@ -1,7 +1,7 @@ +import { Loadable, Loaded, NotLoaded } from 'determined-ui/utils/loadable'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { AlignedData } from 'uplot'; -import { Loadable, Loaded, NotLoaded } from 'components/kit/utils/loadable'; import MetricSelect from 'components/MetricSelect'; import ResponsiveFilters from 'components/ResponsiveFilters'; import ScaleSelect from 'components/ScaleSelect'; diff --git a/webui/react/src/pages/TrialDetails/TrialDetailsHeader.tsx b/webui/react/src/pages/TrialDetails/TrialDetailsHeader.tsx index 46afc795626..c1262f9856a 100644 --- a/webui/react/src/pages/TrialDetails/TrialDetailsHeader.tsx +++ b/webui/react/src/pages/TrialDetails/TrialDetailsHeader.tsx @@ -1,10 +1,10 @@ +import Icon from 'determined-ui/Icon'; +import { useModal } from 'determined-ui/Modal'; import React, { useCallback, useMemo, useState } from 'react'; import ExperimentCreateModalComponent, { CreateExperimentType, } from 'components/ExperimentCreateModal'; -import Icon from 'components/kit/Icon'; -import { useModal } from 'components/kit/Modal'; import PageHeaderFoldable, { Option } from 'components/PageHeaderFoldable'; import { UNMANAGED_MESSAGE } from 'constant'; import { terminalRunStates } from 'constants/states'; diff --git a/webui/react/src/pages/TrialDetails/TrialDetailsHyperparameters.tsx b/webui/react/src/pages/TrialDetails/TrialDetailsHyperparameters.tsx index 9759a13a20d..699c3ae5013 100644 --- a/webui/react/src/pages/TrialDetails/TrialDetailsHyperparameters.tsx +++ b/webui/react/src/pages/TrialDetails/TrialDetailsHyperparameters.tsx @@ -1,6 +1,6 @@ +import Spinner from 'determined-ui/Spinner'; import React, { useMemo } from 'react'; -import Spinner from 'components/kit/Spinner'; import InteractiveTable, { ColumnDef } from 'components/Table/InteractiveTable'; import SkeletonTable from 'components/Table/SkeletonTable'; import { defaultRowClassName } from 'components/Table/Table'; diff --git a/webui/react/src/pages/TrialDetails/TrialDetailsLogs.tsx b/webui/react/src/pages/TrialDetails/TrialDetailsLogs.tsx index 269d3e62f90..f54799e526f 100644 --- a/webui/react/src/pages/TrialDetails/TrialDetailsLogs.tsx +++ b/webui/react/src/pages/TrialDetails/TrialDetailsLogs.tsx @@ -1,19 +1,16 @@ -import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; - -import ClipboardButton from 'components/kit/ClipboardButton'; +import ClipboardButton from 'determined-ui/ClipboardButton'; import LogViewer, { FetchConfig, FetchDirection, FetchType, -} from 'components/kit/LogViewer/LogViewer'; -import LogViewerSelect, { Filters } from 'components/kit/LogViewer/LogViewerSelect'; -import { - Settings, - settingsConfigForTrial, -} from 'components/kit/LogViewer/LogViewerSelect.settings'; -import Spinner from 'components/kit/Spinner'; -import useUI from 'components/kit/Theme'; -import useConfirm from 'components/kit/useConfirm'; +} from 'determined-ui/LogViewer/LogViewer'; +import LogViewerSelect, { Filters } from 'determined-ui/LogViewer/LogViewerSelect'; +import { Settings, settingsConfigForTrial } from 'determined-ui/LogViewer/LogViewerSelect.settings'; +import Spinner from 'determined-ui/Spinner'; +import useUI from 'determined-ui/Theme'; +import useConfirm from 'determined-ui/useConfirm'; +import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; + import { useSettings } from 'hooks/useSettings'; import { serverAddress } from 'routes/utils'; import { detApi } from 'services/apiConfig'; diff --git a/webui/react/src/pages/TrialDetails/TrialDetailsMetrics.tsx b/webui/react/src/pages/TrialDetails/TrialDetailsMetrics.tsx index ae2d6019bf0..d38535d3d8b 100644 --- a/webui/react/src/pages/TrialDetails/TrialDetailsMetrics.tsx +++ b/webui/react/src/pages/TrialDetails/TrialDetailsMetrics.tsx @@ -1,8 +1,8 @@ +import { ChartGrid, ChartsProps } from 'determined-ui/LineChart'; +import Spinner from 'determined-ui/Spinner'; +import { Loaded, NotLoaded } from 'determined-ui/utils/loadable'; import React, { useMemo, useState } from 'react'; -import { ChartGrid, ChartsProps } from 'components/kit/LineChart'; -import Spinner from 'components/kit/Spinner'; -import { Loaded, NotLoaded } from 'components/kit/utils/loadable'; import { UPlotPoint } from 'components/UPlot/types'; import { closestPointPlugin } from 'components/UPlot/UPlotChart/closestPointPlugin'; import { drawPointsPlugin } from 'components/UPlot/UPlotChart/drawPointsPlugin'; diff --git a/webui/react/src/pages/TrialDetails/TrialDetailsOverview.tsx b/webui/react/src/pages/TrialDetails/TrialDetailsOverview.tsx index c59ed3d43a1..e80887e9c45 100644 --- a/webui/react/src/pages/TrialDetails/TrialDetailsOverview.tsx +++ b/webui/react/src/pages/TrialDetails/TrialDetailsOverview.tsx @@ -1,7 +1,7 @@ +import Spinner from 'determined-ui/Spinner'; +import { Loadable } from 'determined-ui/utils/loadable'; import React, { useCallback, useMemo } from 'react'; -import Spinner from 'components/kit/Spinner'; -import { Loadable } from 'components/kit/utils/loadable'; import { terminalRunStates } from 'constants/states'; import useMetricNames from 'hooks/useMetricNames'; import usePermissions from 'hooks/usePermissions'; diff --git a/webui/react/src/pages/TrialDetails/TrialDetailsProfiles.tsx b/webui/react/src/pages/TrialDetails/TrialDetailsProfiles.tsx index f1bebad0b5f..b085239128e 100644 --- a/webui/react/src/pages/TrialDetails/TrialDetailsProfiles.tsx +++ b/webui/react/src/pages/TrialDetails/TrialDetailsProfiles.tsx @@ -1,6 +1,6 @@ +import Message from 'determined-ui/Message'; import React from 'react'; -import Message from 'components/kit/Message'; import Link from 'components/Link'; import Profiler from 'pages/TrialDetails/Profiles/Profiler'; import { paths } from 'routes/utils'; diff --git a/webui/react/src/pages/TrialDetails/TrialDetailsWorkloads.tsx b/webui/react/src/pages/TrialDetails/TrialDetailsWorkloads.tsx index bc3ba7ab6dd..dd8a5949c43 100644 --- a/webui/react/src/pages/TrialDetails/TrialDetailsWorkloads.tsx +++ b/webui/react/src/pages/TrialDetails/TrialDetailsWorkloads.tsx @@ -1,11 +1,11 @@ import { FilterValue, SorterResult, TablePaginationConfig } from 'antd/es/table/interface'; +import Select, { Option, SelectValue } from 'determined-ui/Select'; +import { Loadable, Loaded, NotLoaded } from 'determined-ui/utils/loadable'; import _ from 'lodash'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; import CheckpointModalTrigger from 'components/CheckpointModalTrigger'; import HumanReadableNumber from 'components/HumanReadableNumber'; -import Select, { Option, SelectValue } from 'components/kit/Select'; -import { Loadable, Loaded, NotLoaded } from 'components/kit/utils/loadable'; import MetricBadgeTag from 'components/MetricBadgeTag'; import ResponsiveFilters from 'components/ResponsiveFilters'; import Section from 'components/Section'; diff --git a/webui/react/src/pages/TrialDetails/TrialInfoBox.tsx b/webui/react/src/pages/TrialDetails/TrialInfoBox.tsx index 56b10c08e1c..f2ab24197c8 100644 --- a/webui/react/src/pages/TrialDetails/TrialInfoBox.tsx +++ b/webui/react/src/pages/TrialDetails/TrialInfoBox.tsx @@ -1,8 +1,8 @@ +import Card from 'determined-ui/Card'; +import { useModal } from 'determined-ui/Modal'; import React, { useCallback, useMemo } from 'react'; import CheckpointModalComponent from 'components/CheckpointModal'; -import Card from 'components/kit/Card'; -import { useModal } from 'components/kit/Modal'; import ModelCreateModal from 'components/ModelCreateModal'; import OverviewStats from 'components/OverviewStats'; import Section from 'components/Section'; diff --git a/webui/react/src/pages/TrialDetails/useTrialMetrics.ts b/webui/react/src/pages/TrialDetails/useTrialMetrics.ts index 6355310a6bb..2318bcb8a16 100644 --- a/webui/react/src/pages/TrialDetails/useTrialMetrics.ts +++ b/webui/react/src/pages/TrialDetails/useTrialMetrics.ts @@ -1,9 +1,9 @@ +import { TRAINING_SERIES_COLOR, VALIDATION_SERIES_COLOR } from 'determined-ui/LineChart'; +import { makeToast } from 'determined-ui/Toast'; +import { Loadable, Loaded, NotLoaded } from 'determined-ui/utils/loadable'; import _ from 'lodash'; import { useCallback, useEffect, useMemo, useState } from 'react'; -import { TRAINING_SERIES_COLOR, VALIDATION_SERIES_COLOR } from 'components/kit/LineChart'; -import { makeToast } from 'components/kit/Toast'; -import { Loadable, Loaded, NotLoaded } from 'components/kit/utils/loadable'; import { terminalRunStates } from 'constants/states'; import useMetricNames from 'hooks/useMetricNames'; import usePolling from 'hooks/usePolling'; diff --git a/webui/react/src/pages/Wait.tsx b/webui/react/src/pages/Wait.tsx index 28e8b758197..2f2689282d5 100644 --- a/webui/react/src/pages/Wait.tsx +++ b/webui/react/src/pages/Wait.tsx @@ -1,9 +1,9 @@ +import Spinner from 'determined-ui/Spinner'; +import useUI from 'determined-ui/Theme'; import React, { useEffect, useState } from 'react'; import { useParams, useSearchParams } from 'react-router-dom'; import Badge, { BadgeType } from 'components/Badge'; -import Spinner from 'components/kit/Spinner'; -import useUI from 'components/kit/Theme'; import PageMessage from 'components/PageMessage'; import { terminalCommandStates } from 'constants/states'; import { serverAddress } from 'routes/utils'; diff --git a/webui/react/src/pages/WebhookList.tsx b/webui/react/src/pages/WebhookList.tsx index b574ee5baca..c3a6e0ba507 100644 --- a/webui/react/src/pages/WebhookList.tsx +++ b/webui/react/src/pages/WebhookList.tsx @@ -1,14 +1,14 @@ import { Space } from 'antd'; import { FilterValue, SorterResult, TablePaginationConfig } from 'antd/lib/table/interface'; +import Button from 'determined-ui/Button'; +import Dropdown from 'determined-ui/Dropdown'; +import Icon from 'determined-ui/Icon'; +import Message from 'determined-ui/Message'; +import { useModal } from 'determined-ui/Modal'; import _ from 'lodash'; import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import Badge, { BadgeType } from 'components/Badge'; -import Button from 'components/kit/Button'; -import Dropdown from 'components/kit/Dropdown'; -import Icon from 'components/kit/Icon'; -import Message from 'components/kit/Message'; -import { useModal } from 'components/kit/Modal'; import Page from 'components/Page'; import InteractiveTable, { ColumnDef } from 'components/Table/InteractiveTable'; import SkeletonTable from 'components/Table/SkeletonTable'; diff --git a/webui/react/src/pages/WorkspaceDetails.tsx b/webui/react/src/pages/WorkspaceDetails.tsx index 909ac4b522d..2cc884b9d39 100644 --- a/webui/react/src/pages/WorkspaceDetails.tsx +++ b/webui/react/src/pages/WorkspaceDetails.tsx @@ -1,12 +1,12 @@ import type { TabsProps } from 'antd'; +import Message from 'determined-ui/Message'; +import Pivot from 'determined-ui/Pivot'; +import Spinner from 'determined-ui/Spinner'; +import { Loadable } from 'determined-ui/utils/loadable'; import _ from 'lodash'; import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; -import Message from 'components/kit/Message'; -import Pivot from 'components/kit/Pivot'; -import Spinner from 'components/kit/Spinner'; -import { Loadable } from 'components/kit/utils/loadable'; import ModelRegistry from 'components/ModelRegistry'; import Page from 'components/Page'; import PageNotFound from 'components/PageNotFound'; diff --git a/webui/react/src/pages/WorkspaceDetails/ResourcePoolsBound.tsx b/webui/react/src/pages/WorkspaceDetails/ResourcePoolsBound.tsx index 677aed43bad..315e4fadeea 100644 --- a/webui/react/src/pages/WorkspaceDetails/ResourcePoolsBound.tsx +++ b/webui/react/src/pages/WorkspaceDetails/ResourcePoolsBound.tsx @@ -1,9 +1,9 @@ +import Card from 'determined-ui/Card'; +import Icon from 'determined-ui/Icon'; +import { Loadable } from 'determined-ui/utils/loadable'; import { useObservable } from 'micro-observables'; import React, { useCallback, useEffect, useMemo } from 'react'; -import Card from 'components/kit/Card'; -import Icon from 'components/kit/Icon'; -import { Loadable } from 'components/kit/utils/loadable'; import ResourcePoolCard from 'components/ResourcePoolCard'; import Section from 'components/Section'; import usePermissions from 'hooks/usePermissions'; diff --git a/webui/react/src/pages/WorkspaceDetails/WorkspaceMembers.tsx b/webui/react/src/pages/WorkspaceDetails/WorkspaceMembers.tsx index afb7bb72e4a..52a2d5abfc4 100644 --- a/webui/react/src/pages/WorkspaceDetails/WorkspaceMembers.tsx +++ b/webui/react/src/pages/WorkspaceDetails/WorkspaceMembers.tsx @@ -1,12 +1,12 @@ import { Space } from 'antd'; import { FilterDropdownProps } from 'antd/lib/table/interface'; +import Button from 'determined-ui/Button'; +import Dropdown from 'determined-ui/Dropdown'; +import Icon from 'determined-ui/Icon'; +import { useModal } from 'determined-ui/Modal'; +import Nameplate from 'determined-ui/Nameplate'; import React, { useCallback, useEffect, useMemo } from 'react'; -import Button from 'components/kit/Button'; -import Dropdown from 'components/kit/Dropdown'; -import Icon from 'components/kit/Icon'; -import { useModal } from 'components/kit/Modal'; -import Nameplate from 'components/kit/Nameplate'; import InteractiveTable, { ColumnDef } from 'components/Table/InteractiveTable'; import SkeletonTable from 'components/Table/SkeletonTable'; import { getFullPaginationConfig } from 'components/Table/Table'; diff --git a/webui/react/src/pages/WorkspaceDetails/WorkspaceProjects.tsx b/webui/react/src/pages/WorkspaceDetails/WorkspaceProjects.tsx index 860bce44343..7b3e7c538f1 100644 --- a/webui/react/src/pages/WorkspaceDetails/WorkspaceProjects.tsx +++ b/webui/react/src/pages/WorkspaceDetails/WorkspaceProjects.tsx @@ -1,18 +1,18 @@ import { Space } from 'antd'; +import Button from 'determined-ui/Button'; +import Card from 'determined-ui/Card'; +import { Column, Columns } from 'determined-ui/Columns'; +import Input from 'determined-ui/Input'; +import Message from 'determined-ui/Message'; +import { useModal } from 'determined-ui/Modal'; +import Select, { Option } from 'determined-ui/Select'; +import Spinner from 'determined-ui/Spinner'; +import Toggle from 'determined-ui/Toggle'; +import { Loadable } from 'determined-ui/utils/loadable'; import _ from 'lodash'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; import GridListRadioGroup, { GridListView } from 'components/GridListRadioGroup'; -import Button from 'components/kit/Button'; -import Card from 'components/kit/Card'; -import { Column, Columns } from 'components/kit/Columns'; -import Input from 'components/kit/Input'; -import Message from 'components/kit/Message'; -import { useModal } from 'components/kit/Modal'; -import Select, { Option } from 'components/kit/Select'; -import Spinner from 'components/kit/Spinner'; -import Toggle from 'components/kit/Toggle'; -import { Loadable } from 'components/kit/utils/loadable'; import Link from 'components/Link'; import ProjectActionDropdown from 'components/ProjectActionDropdown'; import ProjectCard from 'components/ProjectCard'; diff --git a/webui/react/src/pages/WorkspaceDetails/WorkspaceQuickSearch.tsx b/webui/react/src/pages/WorkspaceDetails/WorkspaceQuickSearch.tsx index 435eadd9662..5f50957e419 100644 --- a/webui/react/src/pages/WorkspaceDetails/WorkspaceQuickSearch.tsx +++ b/webui/react/src/pages/WorkspaceDetails/WorkspaceQuickSearch.tsx @@ -1,12 +1,12 @@ import { Modal, Tree } from 'antd'; +import Icon from 'determined-ui/Icon'; +import Input from 'determined-ui/Input'; +import Message from 'determined-ui/Message'; +import Spinner from 'determined-ui/Spinner'; +import { Loadable } from 'determined-ui/utils/loadable'; import type { DefaultOptionType } from 'rc-tree-select/lib/TreeSelect'; import React, { useCallback, useMemo, useState } from 'react'; -import Icon from 'components/kit/Icon'; -import Input from 'components/kit/Input'; -import Message from 'components/kit/Message'; -import Spinner from 'components/kit/Spinner'; -import { Loadable } from 'components/kit/utils/loadable'; import Link from 'components/Link'; import { paths } from 'routes/utils'; import { getWorkspaceProjects } from 'services/api'; diff --git a/webui/react/src/pages/WorkspaceList.tsx b/webui/react/src/pages/WorkspaceList.tsx index 9e28c742191..150d2367061 100644 --- a/webui/react/src/pages/WorkspaceList.tsx +++ b/webui/react/src/pages/WorkspaceList.tsx @@ -1,17 +1,17 @@ import { Space } from 'antd'; +import Button from 'determined-ui/Button'; +import Card from 'determined-ui/Card'; +import { Column, Columns } from 'determined-ui/Columns'; +import Message from 'determined-ui/Message'; +import { useModal } from 'determined-ui/Modal'; +import Select, { Option } from 'determined-ui/Select'; +import Spinner from 'determined-ui/Spinner'; +import Toggle from 'determined-ui/Toggle'; +import { Loadable } from 'determined-ui/utils/loadable'; import _ from 'lodash'; import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import GridListRadioGroup, { GridListView } from 'components/GridListRadioGroup'; -import Button from 'components/kit/Button'; -import Card from 'components/kit/Card'; -import { Column, Columns } from 'components/kit/Columns'; -import Message from 'components/kit/Message'; -import { useModal } from 'components/kit/Modal'; -import Select, { Option } from 'components/kit/Select'; -import Spinner from 'components/kit/Spinner'; -import Toggle from 'components/kit/Toggle'; -import { Loadable } from 'components/kit/utils/loadable'; import Link from 'components/Link'; import Page from 'components/Page'; import InteractiveTable, { diff --git a/webui/react/src/pages/WorkspaceList/WorkspaceActionDropdown.tsx b/webui/react/src/pages/WorkspaceList/WorkspaceActionDropdown.tsx index 363bfad0547..73a35b01a5a 100644 --- a/webui/react/src/pages/WorkspaceList/WorkspaceActionDropdown.tsx +++ b/webui/react/src/pages/WorkspaceList/WorkspaceActionDropdown.tsx @@ -1,10 +1,10 @@ +import Button from 'determined-ui/Button'; +import Dropdown, { MenuItem } from 'determined-ui/Dropdown'; +import Icon from 'determined-ui/Icon'; +import { useModal } from 'determined-ui/Modal'; import React, { useCallback, useMemo } from 'react'; import css from 'components/ActionDropdown/ActionDropdown.module.scss'; -import Button from 'components/kit/Button'; -import Dropdown, { MenuItem } from 'components/kit/Dropdown'; -import Icon from 'components/kit/Icon'; -import { useModal } from 'components/kit/Modal'; import WorkspaceCreateModalComponent from 'components/WorkspaceCreateModal'; import WorkspaceDeleteModalComponent from 'components/WorkspaceDeleteModal'; import usePermissions from 'hooks/usePermissions'; diff --git a/webui/react/src/pages/WorkspaceList/WorkspaceCard.tsx b/webui/react/src/pages/WorkspaceList/WorkspaceCard.tsx index 43b23a64086..7ac91922dc9 100644 --- a/webui/react/src/pages/WorkspaceList/WorkspaceCard.tsx +++ b/webui/react/src/pages/WorkspaceList/WorkspaceCard.tsx @@ -1,12 +1,12 @@ import { Typography } from 'antd'; +import Card from 'determined-ui/Card'; +import { Columns } from 'determined-ui/Columns'; +import Icon from 'determined-ui/Icon'; +import Spinner from 'determined-ui/Spinner'; +import { Loadable } from 'determined-ui/utils/loadable'; import React from 'react'; import DynamicIcon from 'components/DynamicIcon'; -import Card from 'components/kit/Card'; -import { Columns } from 'components/kit/Columns'; -import Icon from 'components/kit/Icon'; -import Spinner from 'components/kit/Spinner'; -import { Loadable } from 'components/kit/utils/loadable'; import Avatar from 'components/UserAvatar'; import { handlePath, paths } from 'routes/utils'; import userStore from 'stores/users'; diff --git a/webui/react/src/quarantineTests.ts b/webui/react/src/quarantineTests.ts deleted file mode 100644 index 842631d0b17..00000000000 --- a/webui/react/src/quarantineTests.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const flakyIt = (name: string, fn?: jest.ProvidesCallback, timeout?: number): void => { - return (process.env.INCLUDE_FLAKY ? it : it.skip)(name, fn, timeout); -}; diff --git a/webui/react/src/stores/auth.ts b/webui/react/src/stores/auth.ts index db959c98539..41dedf707b9 100644 --- a/webui/react/src/stores/auth.ts +++ b/webui/react/src/stores/auth.ts @@ -1,6 +1,6 @@ +import { Loadable, Loaded, NotLoaded } from 'determined-ui/utils/loadable'; import { observable, WritableObservable } from 'micro-observables'; -import { Loadable, Loaded, NotLoaded } from 'components/kit/utils/loadable'; import { globalStorage } from 'globalStorage'; import { Auth } from 'types'; import { getCookie, setCookie } from 'utils/browser'; diff --git a/webui/react/src/stores/cluster.tsx b/webui/react/src/stores/cluster.tsx index 45c76732c83..b459719b886 100644 --- a/webui/react/src/stores/cluster.tsx +++ b/webui/react/src/stores/cluster.tsx @@ -1,7 +1,7 @@ +import { Loadable, Loaded, NotLoaded } from 'determined-ui/utils/loadable'; import { Map } from 'immutable'; import _ from 'lodash'; -import { Loadable, Loaded, NotLoaded } from 'components/kit/utils/loadable'; import { addResourcePoolBindings, deleteResourcePoolBindings, diff --git a/webui/react/src/stores/determinedInfo.tsx b/webui/react/src/stores/determinedInfo.tsx index 4a3f068b4de..177840204a2 100644 --- a/webui/react/src/stores/determinedInfo.tsx +++ b/webui/react/src/stores/determinedInfo.tsx @@ -1,4 +1,5 @@ -import { Loadable, Loaded, NotLoaded } from 'components/kit/utils/loadable'; +import { Loadable, Loaded, NotLoaded } from 'determined-ui/utils/loadable'; + import { getInfo } from 'services/api'; import { ValueOf } from 'types'; import { observable, WritableObservable } from 'utils/observable'; diff --git a/webui/react/src/stores/experiments.tsx b/webui/react/src/stores/experiments.tsx index df168c0239e..936ca6329f0 100644 --- a/webui/react/src/stores/experiments.tsx +++ b/webui/react/src/stores/experiments.tsx @@ -1,6 +1,6 @@ +import { Loadable, Loaded, NotLoaded } from 'determined-ui/utils/loadable'; import { Map } from 'immutable'; -import { Loadable, Loaded, NotLoaded } from 'components/kit/utils/loadable'; import { getExperiments } from 'services/api'; import { V1Pagination } from 'services/api-ts-sdk'; import { GetExperimentsParams } from 'services/types'; diff --git a/webui/react/src/stores/index.tsx b/webui/react/src/stores/index.tsx index 2342f371b94..ac247dfa960 100644 --- a/webui/react/src/stores/index.tsx +++ b/webui/react/src/stores/index.tsx @@ -1,7 +1,6 @@ +import { UIProvider } from 'determined-ui/Theme'; import React, { ReactElement, ReactNode } from 'react'; -import { UIProvider } from 'components/kit/Theme'; - export const StoreProvider = ({ children }: { children: ReactNode }): ReactElement => ( {children} ); diff --git a/webui/react/src/stores/permissions.tsx b/webui/react/src/stores/permissions.tsx index 353921f9d71..472e371c178 100644 --- a/webui/react/src/stores/permissions.tsx +++ b/webui/react/src/stores/permissions.tsx @@ -1,6 +1,6 @@ +import { Loadable, Loaded, NotLoaded } from 'determined-ui/utils/loadable'; import { Observable, observable, WritableObservable } from 'micro-observables'; -import { Loadable, Loaded, NotLoaded } from 'components/kit/utils/loadable'; import { getPermissionsSummary } from 'services/api'; import { UserAssignment, UserRole } from 'types'; import handleError from 'utils/error'; diff --git a/webui/react/src/stores/projects.tsx b/webui/react/src/stores/projects.tsx index d4165859840..67814e50439 100644 --- a/webui/react/src/stores/projects.tsx +++ b/webui/react/src/stores/projects.tsx @@ -1,6 +1,6 @@ +import { Loadable, Loaded, NotLoaded } from 'determined-ui/utils/loadable'; import { Map } from 'immutable'; -import { Loadable, Loaded, NotLoaded } from 'components/kit/utils/loadable'; import { getWorkspaceProjects } from 'services/api'; import { Project } from 'types'; import handleError from 'utils/error'; diff --git a/webui/react/src/stores/roles.tsx b/webui/react/src/stores/roles.tsx index 591952e62d5..441d679d55f 100644 --- a/webui/react/src/stores/roles.tsx +++ b/webui/react/src/stores/roles.tsx @@ -1,4 +1,5 @@ -import { Loadable, Loaded, NotLoaded } from 'components/kit/utils/loadable'; +import { Loadable, Loaded, NotLoaded } from 'determined-ui/utils/loadable'; + import { listRoles } from 'services/api'; import { ListRolesParams } from 'services/types'; import { UserRole } from 'types'; diff --git a/webui/react/src/stores/tasks.tsx b/webui/react/src/stores/tasks.tsx index bbfad4e45d0..8dc1262f7b0 100644 --- a/webui/react/src/stores/tasks.tsx +++ b/webui/react/src/stores/tasks.tsx @@ -1,6 +1,6 @@ +import { Loadable, Loaded, NotLoaded } from 'determined-ui/utils/loadable'; import { observable, WritableObservable } from 'micro-observables'; -import { Loadable, Loaded, NotLoaded } from 'components/kit/utils/loadable'; import { getActiveTasks } from 'services/api'; import { TaskCounts } from 'types'; diff --git a/webui/react/src/stores/userSettings.test.tsx b/webui/react/src/stores/userSettings.test.tsx index 3f58dc211c5..9bc7c30ebb2 100644 --- a/webui/react/src/stores/userSettings.test.tsx +++ b/webui/react/src/stores/userSettings.test.tsx @@ -1,7 +1,7 @@ +import { Loadable, Loaded } from 'determined-ui/utils/loadable'; import { Map } from 'immutable'; import * as t from 'io-ts'; -import { Loadable, Loaded } from 'components/kit/utils/loadable'; import authStore from 'stores/auth'; import userStore from 'stores/users'; diff --git a/webui/react/src/stores/userSettings.tsx b/webui/react/src/stores/userSettings.tsx index 6ee67af281c..bcdb249bcb4 100644 --- a/webui/react/src/stores/userSettings.tsx +++ b/webui/react/src/stores/userSettings.tsx @@ -1,9 +1,9 @@ +import { Loadable, Loaded, NotLoaded } from 'determined-ui/utils/loadable'; import { isRight, match } from 'fp-ts/Either'; import { pipe } from 'fp-ts/function'; import { Map } from 'immutable'; import * as t from 'io-ts'; -import { Loadable, Loaded, NotLoaded } from 'components/kit/utils/loadable'; import { getUserSetting, resetUserSetting, updateUserSetting } from 'services/api'; import { V1GetUserSettingResponse, V1UserWebSetting } from 'services/api-ts-sdk'; import { Json, JsonObject } from 'types'; diff --git a/webui/react/src/stores/users.tsx b/webui/react/src/stores/users.tsx index 2b715f3bd89..251578ccfa5 100644 --- a/webui/react/src/stores/users.tsx +++ b/webui/react/src/stores/users.tsx @@ -1,7 +1,7 @@ +import { Loadable, Loaded, NotLoaded } from 'determined-ui/utils/loadable'; import { Map } from 'immutable'; import _ from 'lodash'; -import { Loadable, Loaded, NotLoaded } from 'components/kit/utils/loadable'; import { getCurrentUser, getUsers, patchUser } from 'services/api'; import type { GetUsersParams, PatchUserParams } from 'services/types'; import { DetailedUser, DetailedUserList } from 'types'; diff --git a/webui/react/src/stores/workspaces.tsx b/webui/react/src/stores/workspaces.tsx index 4e8b5500894..7844948718b 100644 --- a/webui/react/src/stores/workspaces.tsx +++ b/webui/react/src/stores/workspaces.tsx @@ -1,8 +1,8 @@ +import { Loadable, Loaded, NotLoaded } from 'determined-ui/utils/loadable'; import { Map } from 'immutable'; import _ from 'lodash'; import { Observable, observable, WritableObservable } from 'micro-observables'; -import { Loadable, Loaded, NotLoaded } from 'components/kit/utils/loadable'; import { archiveWorkspace, createWorkspace, diff --git a/webui/react/src/utils/chart.ts b/webui/react/src/utils/chart.ts index 5014669b797..d7b24ce282e 100644 --- a/webui/react/src/utils/chart.ts +++ b/webui/react/src/utils/chart.ts @@ -1,7 +1,7 @@ import dayjs from 'dayjs'; +import { Theme } from 'determined-ui/Theme'; import uPlot from 'uplot'; -import { Theme } from 'components/kit/Theme'; import { Primitive, Range } from 'types'; import { ColorScale } from 'utils/color'; import { primitiveSorter } from 'utils/sort'; diff --git a/webui/react/src/utils/error.ts b/webui/react/src/utils/error.ts index 25e80d99301..426aff92eae 100644 --- a/webui/react/src/utils/error.ts +++ b/webui/react/src/utils/error.ts @@ -1,4 +1,5 @@ -import { makeToast, Severity } from 'components/kit/Toast'; +import { makeToast, Severity } from 'determined-ui/Toast'; + import { telemetryInstance } from 'hooks/useTelemetry'; import { paths } from 'routes/utils'; import { ValueOf } from 'types'; diff --git a/webui/react/src/utils/job.ts b/webui/react/src/utils/job.ts index e39e3b85187..1a831887699 100644 --- a/webui/react/src/utils/job.ts +++ b/webui/react/src/utils/job.ts @@ -1,4 +1,5 @@ -import { IconName } from 'components/kit/Icon'; +import { IconName } from 'determined-ui/Icon'; + import { updateJobQueue } from 'services/api'; import * as Api from 'services/api-ts-sdk'; import { CommandType, Job, JobType, ResourcePool } from 'types'; diff --git a/webui/react/tsconfig.json b/webui/react/tsconfig.json index 1f81274807a..4579fcf6822 100644 --- a/webui/react/tsconfig.json +++ b/webui/react/tsconfig.json @@ -18,5 +18,5 @@ "jsx": "react-jsx", "noFallthroughCasesInSwitch": true }, - "include": ["src/**/*", "typings/**/*.ts", "design/**/*", "*.ts"] + "include": ["src/**/*", "typings/**/*.ts", "design/**/*", "*.ts", "__mocks__/**/*"] } diff --git a/webui/react/vite.config.mts b/webui/react/vite.config.mts index c9218f7249c..199789e6de8 100644 --- a/webui/react/vite.config.mts +++ b/webui/react/vite.config.mts @@ -185,10 +185,13 @@ export default defineConfig(({ mode }) => ({ deps: { // necessary to fix react-dnd jsx runtime issue registerNodeLoader: true, + // resolve css imports + inline: [/determined-ui/], }, environment: 'jsdom', exclude: [...configDefaults.exclude, './src/e2e/*'], globals: true, setupFiles: ['./src/setupTests.ts'], + testNamePattern: process.env.INCLUDE_FLAKY === 'true' ? /@flaky/ : /^(?!.*@flaky)/ }, }));