From e8f2df9e6933f1e8d275faf4cc1ec6b3e93e0e05 Mon Sep 17 00:00:00 2001 From: Alexander Zinn Date: Thu, 4 Sep 2025 20:25:15 -0400 Subject: [PATCH] maintenance --- bun.lock | 871 ------------------ package.json | 9 +- src/App.tsx | 16 +- src/components/ProtectedRoute.tsx | 4 +- .../buttons/copy-icon-button/index.tsx | 12 +- .../buttons/copy-icon-button/styles.ts | 2 +- .../buttons/export-file-button/index.tsx | 12 +- .../buttons/icon-button/icon-button.tsx | 11 +- src/components/buttons/icon-button/index.tsx | 2 +- src/components/buttons/icon-button/styles.ts | 2 +- .../buttons/icon-buttons/add-button.tsx | 5 +- src/components/buttons/icon-buttons/index.ts | 2 +- .../buttons/icon-buttons/refresh-button.tsx | 5 +- src/components/buttons/icon-buttons/style.ts | 8 +- src/components/buttons/index.tsx | 4 +- src/components/buttons/radio-button/index.tsx | 55 +- src/components/buttons/radio-button/style.ts | 43 +- .../buttons/scroll-buttons/index.tsx | 14 +- .../delete-channel/delete-channel-form.tsx | 67 ++ .../delete-channel/delete-channel-modal.tsx | 111 +++ .../delete-channel/index.tsx | 4 + .../fork-channel/fork-channel-form.tsx | 107 +++ .../fork-channel/fork-channel-modal.tsx | 113 +++ .../channel-icon-menu/fork-channel/index.tsx | 4 + src/components/channel-icon-menu/index.tsx | 65 ++ .../channel-icon-menu/kill-channel/index.tsx | 4 + .../kill-channel/kill-channel-form.tsx | 129 +++ .../kill-channel/kill-channel-modal.tsx | 106 +++ .../create-token-components/capabilities.tsx | 62 ++ .../create-token-components/index.ts | 8 + .../create-token-components/index.tsx | 44 + .../label-icon-tooltip.tsx | 26 + .../create-token-components/styles.ts | 60 ++ .../create-token-components/validity-time.tsx | 60 ++ .../date-render-component/index.tsx | 51 + src/components/drop-down/index.tsx | 212 +++++ src/components/drop-down/style.ts | 59 ++ src/components/error-renderer/index.tsx | 12 + src/components/error-renderer/style.ts | 23 + src/components/forms/Checkbox.tsx | 83 ++ src/components/forms/Checkbox/index.tsx | 88 ++ src/components/forms/Input.tsx | 115 +-- src/components/forms/SearchInput.tsx | 77 ++ src/components/forms/label/index.ts | 1 + .../forms/label/{index.tsx => label.tsx} | 14 +- src/components/forms/label/style.ts | 4 +- src/components/icon-menu/icon-menu.tsx | 198 ++++ src/components/icon-menu/index.tsx | 4 + src/components/icon-menu/style.ts | 79 ++ src/components/icon-menu/types.ts | 19 + src/components/index.ts | 14 +- .../indicator-component/indicators/index.ts | 4 + .../indicators/indicators.tsx | 11 + .../indicator-component/indicators/style.ts | 43 + .../publishing-state-indicator.tsx | 41 + src/components/label/index.ts | 1 + src/components/layout/index.tsx | 57 ++ src/components/loaders/LoadingWheel.tsx | 26 +- src/components/loaders/index.ts | 2 +- src/components/modal/index.ts | 5 + .../modal-form-response/form-response.tsx | 40 + .../modal/modal-form-response/index.tsx | 4 + .../modal/modal-form-response/style.ts | 175 ++++ src/components/modal/modal.tsx | 87 ++ .../modal/multi-step-modal/index.ts | 5 + .../multi-step-modal/multi-step-modal.tsx | 66 ++ src/components/modal/style.ts | 80 ++ src/components/new-tab-link/index.tsx | 26 + src/components/pagination/index.ts | 5 + src/components/pagination/pagination.tsx | 87 ++ src/components/pagination/style.tsx | 45 + src/components/pre-formatted-code/index.tsx | 5 + .../pre-formatted-code/pre-formatted-code.tsx | 58 ++ src/components/pre-formatted-code/styles.ts | 34 + src/components/restricted-text/index.ts | 6 + .../restricted-text-with-label.tsx | 34 + .../restricted-text/restricted-text.tsx | 115 +++ src/components/restricted-text/style.ts | 96 ++ src/components/shared/theme.ts | 2 + src/components/shared/utils.ts | 17 +- src/components/table-screen-header/index.ts | 4 + src/components/table-screen-header/style.tsx | 37 + .../table-screen-header.tsx | 48 + src/components/table-with-pagination/index.ts | 6 + .../table-with-pagination.tsx | 205 +++++ src/components/table/index.ts | 8 + src/components/table/props.ts | 74 ++ src/components/table/style.tsx | 75 ++ src/components/table/table-body.tsx | 18 + src/components/table/table-cells/index.ts | 4 + .../table/table-cells/table-cell-dropdown.tsx | 29 + src/components/table/table-header-cell.tsx | 66 ++ src/components/table/table-header.tsx | 30 + src/components/table/table-row.tsx | 91 ++ src/components/table/table.tsx | 107 +++ src/components/tags/index.tsx | 30 + src/components/tags/style.ts | 37 + src/components/tooltip/index.tsx | 43 + src/components/tooltip/style.ts | 89 ++ src/components/tooltip/types.ts | 10 + src/components/typography/index.tsx | 5 +- .../ui/advanced-select/advanced-select.tsx | 202 ++++ src/components/ui/advanced-select/index.ts | 4 + src/components/ui/advanced-select/style.ts | 62 ++ src/components/ui/date-picker/date-picker.tsx | 54 ++ src/components/ui/date-picker/index.ts | 5 + src/components/ui/date-picker/style.ts | 44 + src/components/ui/index.ts | 12 + src/components/ui/input-with-tags/index.ts | 5 + .../ui/input-with-tags/input-with-tags.tsx | 102 ++ src/components/ui/input-with-tags/style.ts | 48 + src/components/ui/input.tsx | 128 +++ src/components/ui/link/index.tsx | 4 + src/components/ui/link/link.tsx | 18 + src/components/ui/link/styles.ts | 33 + src/components/ui/multi-select/index.ts | 5 + .../ui/multi-select/multi-select.tsx | 175 ++++ src/components/ui/multi-select/style.ts | 117 +++ src/components/ui/radio-button/index.ts | 4 + .../ui/radio-button/radio-button.tsx | 105 +++ src/components/ui/radio-button/style.ts | 81 ++ src/components/ui/select/index.ts | 5 + src/components/ui/select/select.tsx | 68 ++ src/components/ui/select/style.ts | 39 + src/components/ui/styles.ts | 19 + src/components/ui/textarea/index.ts | 5 + src/components/ui/textarea/style.ts | 43 + src/components/ui/textarea/textarea.tsx | 47 + src/constant-data/capabilities.ts | 1 + src/constant-data/error-messages.ts | 1 + src/constant-data/links.ts | 1 + src/constants/capabilities.ts | 2 +- src/declaredTypes.d.ts | 2 +- src/drop-down/index.tsx | 209 +++++ src/drop-down/style.ts | 59 ++ src/index.css | 13 +- src/indicator-component/indicators/index.ts | 4 + .../indicators/indicators.tsx | 27 + src/indicator-component/indicators/style.ts | 42 + .../publishing-state-indicator.tsx | 39 + src/interfaces/analyticsProps.tsx | 75 ++ src/interfaces/channelProps.tsx | 44 + src/interfaces/chartProps.tsx | 7 + src/interfaces/common.ts | 37 + src/interfaces/index.ts | 13 + src/interfaces/messagesProps.tsx | 34 + src/interfaces/permalinksProps.ts | 7 + src/interfaces/qosProps.ts | 29 + src/interfaces/roomProps.tsx | 8 + src/interfaces/storeProps.ts | 39 + src/interfaces/tableProps.ts | 57 ++ src/interfaces/videoProps.tsx | 6 + src/services/Authentication.service.ts | 12 +- src/services/Channel.service.ts | 249 +++++ src/services/PCastApi.service.ts | 1 + src/services/PlatformDetection.service.ts | 308 ++++--- src/services/UserDataStore/IndexedDB.ts | 6 +- src/services/UserDataStore/LocalStorage.ts | 6 +- src/services/UserDataStore/ObjectStore.ts | 6 +- src/services/platform-detection.service.ts | 191 ---- src/services/user-store/IUserDataStore.ts | 4 + src/services/user-store/index.ts | 27 + src/services/user-store/indexed-db.ts | 90 ++ src/services/user-store/local-storage.ts | 31 + src/services/user-store/object-store.ts | 25 + src/store/action/channels-publishing.ts | 164 ++++ src/store/action/channels.ts | 126 +++ src/store/action/screens.ts | 125 +++ .../middlewares/authenticationMiddleware.ts | 11 +- src/store/middlewares/loggerMiddleware.ts | 2 +- src/store/middlewares/promiseMiddleware.ts | 6 +- src/store/reducers/screens.ts | 7 + src/store/slices/Authentication.slice.ts | 8 + src/store/slices/Channels.slice.ts | 130 ++- src/store/store.ts | 6 +- src/theme/README.md | 24 +- src/theme/ThemeFactory.ts | 22 +- src/theme/defaultTheme/BackgroundSystem.ts | 4 +- src/theme/defaultTheme/ColorSystem.ts | 4 +- src/theme/defaultTheme/ScreenSystem.ts | 6 +- src/theme/defaultTheme/SpacingSystem.ts | 4 +- src/theme/defaultTheme/TypographySystem.ts | 6 +- src/theme/index.ts | 47 +- src/theme/interfaces/ITheme.ts | 10 +- src/theme/utils/ColorUtils.ts | 7 +- src/theme/utils/ViewportUtils.ts | 2 +- src/utility/contexts.ts | 6 + src/utility/conversions.ts | 20 + src/utility/custom-hooks.ts | 105 +++ src/utility/date.ts | 129 +++ src/utility/error-handler.ts | 76 ++ src/utility/filters.ts | 40 + src/utility/index.ts | 9 + src/utility/numbers.ts | 93 ++ src/utility/polyfills.ts | 39 + src/utility/sort.ts | 20 + src/utility/stream.ts | 40 + src/utility/validators.ts | 81 ++ src/views/ChannelList/ChannelList.tsx | 162 +++- .../channel-publishing-state-indicator.tsx | 9 + src/views/ChannelList/columns-config.tsx | 5 + .../columns-data.tsx} | 8 +- .../create-channel/create-channel-modal.tsx | 17 +- .../create-channel/index.tsx | 0 src/views/ChannelList/index.ts | 1 - src/views/{channels => ChannelList}/index.tsx | 2 +- src/views/LoginForm/LoginForm.tsx | 97 +- src/views/LoginForm/links.ts | 6 - src/views/LoginForm/style.ts | 5 +- src/views/LoginForm/text.ts | 2 +- src/views/LoginForm/view.tsx | 59 +- src/views/channels/channels.tsx | 149 --- tsconfig.app.tsbuildinfo | 1 + vite.config.ts | 2 +- 214 files changed, 8507 insertions(+), 1836 deletions(-) delete mode 100644 bun.lock create mode 100644 src/components/channel-icon-menu/delete-channel/delete-channel-form.tsx create mode 100644 src/components/channel-icon-menu/delete-channel/delete-channel-modal.tsx create mode 100644 src/components/channel-icon-menu/delete-channel/index.tsx create mode 100644 src/components/channel-icon-menu/fork-channel/fork-channel-form.tsx create mode 100644 src/components/channel-icon-menu/fork-channel/fork-channel-modal.tsx create mode 100644 src/components/channel-icon-menu/fork-channel/index.tsx create mode 100644 src/components/channel-icon-menu/index.tsx create mode 100644 src/components/channel-icon-menu/kill-channel/index.tsx create mode 100644 src/components/channel-icon-menu/kill-channel/kill-channel-form.tsx create mode 100644 src/components/channel-icon-menu/kill-channel/kill-channel-modal.tsx create mode 100644 src/components/create-token-components/capabilities.tsx create mode 100644 src/components/create-token-components/index.ts create mode 100644 src/components/create-token-components/index.tsx create mode 100644 src/components/create-token-components/label-icon-tooltip.tsx create mode 100644 src/components/create-token-components/styles.ts create mode 100644 src/components/create-token-components/validity-time.tsx create mode 100644 src/components/date-render-component/index.tsx create mode 100644 src/components/drop-down/index.tsx create mode 100644 src/components/drop-down/style.ts create mode 100644 src/components/error-renderer/index.tsx create mode 100644 src/components/error-renderer/style.ts create mode 100644 src/components/forms/Checkbox.tsx create mode 100644 src/components/forms/Checkbox/index.tsx create mode 100644 src/components/forms/SearchInput.tsx create mode 100644 src/components/forms/label/index.ts rename src/components/forms/label/{index.tsx => label.tsx} (68%) create mode 100644 src/components/icon-menu/icon-menu.tsx create mode 100644 src/components/icon-menu/index.tsx create mode 100644 src/components/icon-menu/style.ts create mode 100644 src/components/icon-menu/types.ts create mode 100644 src/components/indicator-component/indicators/index.ts create mode 100644 src/components/indicator-component/indicators/indicators.tsx create mode 100644 src/components/indicator-component/indicators/style.ts create mode 100644 src/components/indicator-component/publishing-state-indicator.tsx create mode 100644 src/components/label/index.ts create mode 100644 src/components/layout/index.tsx create mode 100644 src/components/modal/index.ts create mode 100644 src/components/modal/modal-form-response/form-response.tsx create mode 100644 src/components/modal/modal-form-response/index.tsx create mode 100644 src/components/modal/modal-form-response/style.ts create mode 100644 src/components/modal/modal.tsx create mode 100644 src/components/modal/multi-step-modal/index.ts create mode 100644 src/components/modal/multi-step-modal/multi-step-modal.tsx create mode 100644 src/components/modal/style.ts create mode 100644 src/components/new-tab-link/index.tsx create mode 100644 src/components/pagination/index.ts create mode 100644 src/components/pagination/pagination.tsx create mode 100644 src/components/pagination/style.tsx create mode 100644 src/components/pre-formatted-code/index.tsx create mode 100644 src/components/pre-formatted-code/pre-formatted-code.tsx create mode 100644 src/components/pre-formatted-code/styles.ts create mode 100644 src/components/restricted-text/index.ts create mode 100644 src/components/restricted-text/restricted-text-with-label.tsx create mode 100644 src/components/restricted-text/restricted-text.tsx create mode 100644 src/components/restricted-text/style.ts create mode 100644 src/components/shared/theme.ts create mode 100644 src/components/table-screen-header/index.ts create mode 100644 src/components/table-screen-header/style.tsx create mode 100644 src/components/table-screen-header/table-screen-header.tsx create mode 100644 src/components/table-with-pagination/index.ts create mode 100644 src/components/table-with-pagination/table-with-pagination.tsx create mode 100644 src/components/table/index.ts create mode 100644 src/components/table/props.ts create mode 100644 src/components/table/style.tsx create mode 100644 src/components/table/table-body.tsx create mode 100644 src/components/table/table-cells/index.ts create mode 100644 src/components/table/table-cells/table-cell-dropdown.tsx create mode 100644 src/components/table/table-header-cell.tsx create mode 100644 src/components/table/table-header.tsx create mode 100644 src/components/table/table-row.tsx create mode 100644 src/components/table/table.tsx create mode 100644 src/components/tags/index.tsx create mode 100644 src/components/tags/style.ts create mode 100644 src/components/tooltip/index.tsx create mode 100644 src/components/tooltip/style.ts create mode 100644 src/components/tooltip/types.ts create mode 100644 src/components/ui/advanced-select/advanced-select.tsx create mode 100644 src/components/ui/advanced-select/index.ts create mode 100644 src/components/ui/advanced-select/style.ts create mode 100644 src/components/ui/date-picker/date-picker.tsx create mode 100644 src/components/ui/date-picker/index.ts create mode 100644 src/components/ui/date-picker/style.ts create mode 100644 src/components/ui/index.ts create mode 100644 src/components/ui/input-with-tags/index.ts create mode 100644 src/components/ui/input-with-tags/input-with-tags.tsx create mode 100644 src/components/ui/input-with-tags/style.ts create mode 100644 src/components/ui/input.tsx create mode 100644 src/components/ui/link/index.tsx create mode 100644 src/components/ui/link/link.tsx create mode 100644 src/components/ui/link/styles.ts create mode 100644 src/components/ui/multi-select/index.ts create mode 100644 src/components/ui/multi-select/multi-select.tsx create mode 100644 src/components/ui/multi-select/style.ts create mode 100644 src/components/ui/radio-button/index.ts create mode 100644 src/components/ui/radio-button/radio-button.tsx create mode 100644 src/components/ui/radio-button/style.ts create mode 100644 src/components/ui/select/index.ts create mode 100644 src/components/ui/select/select.tsx create mode 100644 src/components/ui/select/style.ts create mode 100644 src/components/ui/styles.ts create mode 100644 src/components/ui/textarea/index.ts create mode 100644 src/components/ui/textarea/style.ts create mode 100644 src/components/ui/textarea/textarea.tsx create mode 100644 src/constant-data/capabilities.ts create mode 100644 src/constant-data/error-messages.ts create mode 100644 src/constant-data/links.ts create mode 100644 src/drop-down/index.tsx create mode 100644 src/drop-down/style.ts create mode 100644 src/indicator-component/indicators/index.ts create mode 100644 src/indicator-component/indicators/indicators.tsx create mode 100644 src/indicator-component/indicators/style.ts create mode 100644 src/indicator-component/publishing-state-indicator.tsx create mode 100644 src/interfaces/analyticsProps.tsx create mode 100644 src/interfaces/channelProps.tsx create mode 100644 src/interfaces/chartProps.tsx create mode 100644 src/interfaces/common.ts create mode 100644 src/interfaces/index.ts create mode 100644 src/interfaces/messagesProps.tsx create mode 100644 src/interfaces/permalinksProps.ts create mode 100644 src/interfaces/qosProps.ts create mode 100644 src/interfaces/roomProps.tsx create mode 100644 src/interfaces/storeProps.ts create mode 100644 src/interfaces/tableProps.ts create mode 100644 src/interfaces/videoProps.tsx create mode 100644 src/services/Channel.service.ts delete mode 100644 src/services/platform-detection.service.ts create mode 100644 src/services/user-store/IUserDataStore.ts create mode 100644 src/services/user-store/index.ts create mode 100644 src/services/user-store/indexed-db.ts create mode 100644 src/services/user-store/local-storage.ts create mode 100644 src/services/user-store/object-store.ts create mode 100644 src/store/action/channels-publishing.ts create mode 100644 src/store/action/channels.ts create mode 100644 src/store/action/screens.ts create mode 100644 src/store/reducers/screens.ts create mode 100644 src/utility/contexts.ts create mode 100644 src/utility/conversions.ts create mode 100644 src/utility/custom-hooks.ts create mode 100644 src/utility/date.ts create mode 100644 src/utility/error-handler.ts create mode 100644 src/utility/filters.ts create mode 100644 src/utility/index.ts create mode 100644 src/utility/numbers.ts create mode 100644 src/utility/polyfills.ts create mode 100644 src/utility/sort.ts create mode 100644 src/utility/stream.ts create mode 100644 src/utility/validators.ts create mode 100644 src/views/ChannelList/channel-publishing-state-indicator.tsx create mode 100644 src/views/ChannelList/columns-config.tsx rename src/views/{channels/columns-config.tsx => ChannelList/columns-data.tsx} (78%) rename src/views/{channels => ChannelList}/create-channel/create-channel-modal.tsx (88%) rename src/views/{channels => ChannelList}/create-channel/index.tsx (100%) delete mode 100644 src/views/ChannelList/index.ts rename src/views/{channels => ChannelList}/index.tsx (75%) delete mode 100644 src/views/LoginForm/links.ts delete mode 100644 src/views/channels/channels.tsx create mode 100644 tsconfig.app.tsbuildinfo diff --git a/bun.lock b/bun.lock deleted file mode 100644 index fcaea01..0000000 --- a/bun.lock +++ /dev/null @@ -1,871 +0,0 @@ -{ - "lockfileVersion": 1, - "workspaces": { - "": { - "name": "webcontrolcenter-zinn-2", - "dependencies": { - "@phenixrts/sdk": "2025.2.2", - "@reduxjs/toolkit": "2.9.0", - "@techniker-me/pcast-api": "2025.1.5", - "@techniker-me/tools": "2025.0.16", - "moment": "2.30.1", - "phenix-web-proto": "2020.0.3", - "react": "19.1.1", - "react-dom": "19.1.1", - "react-redux": "9.2.0", - "react-router-dom": "7.8.2", - "styled-components": "6.1.19", - }, - "devDependencies": { - "@eslint/js": "9.34.0", - "@types/node": "24.3.0", - "@types/react": "19.1.12", - "@types/react-dom": "19.1.9", - "@vitejs/plugin-react-swc": "4.0.1", - "babel-plugin-styled-components": "2.1.4", - "babel-plugin-transform-amd-to-commonjs": "1.6.0", - "eslint": "9.34.0", - "eslint-plugin-react": "7.37.5", - "eslint-plugin-react-hooks": "5.2.0", - "eslint-plugin-react-refresh": "0.4.20", - "globals": "16.3.0", - "prettier": "3.6.2", - "typescript": "5.9.2", - "typescript-eslint": "8.42.0", - "typescript-plugin-styled-components": "3.0.0", - "vite": "7.1.4", - "vite-plugin-babel": "1.3.2", - "vite-plugin-commonjs": "0.10.4", - }, - }, - }, - "packages": { - "@ampproject/remapping": ["@ampproject/remapping@2.3.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="], - - "@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="], - - "@babel/compat-data": ["@babel/compat-data@7.28.0", "", {}, "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw=="], - - "@babel/core": ["@babel/core@7.28.3", "", { "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.28.3", "@babel/helpers": "^7.28.3", "@babel/parser": "^7.28.3", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.3", "@babel/types": "^7.28.2", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ=="], - - "@babel/generator": ["@babel/generator@7.28.3", "", { "dependencies": { "@babel/parser": "^7.28.3", "@babel/types": "^7.28.2", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw=="], - - "@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="], - - "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.27.2", "", { "dependencies": { "@babel/compat-data": "^7.27.2", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ=="], - - "@babel/helper-globals": ["@babel/helper-globals@7.28.0", "", {}, "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw=="], - - "@babel/helper-module-imports": ["@babel/helper-module-imports@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w=="], - - "@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.28.3", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1", "@babel/traverse": "^7.28.3" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw=="], - - "@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.27.1", "", {}, "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw=="], - - "@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="], - - "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.27.1", "", {}, "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow=="], - - "@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="], - - "@babel/helpers": ["@babel/helpers@7.28.3", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/types": "^7.28.2" } }, "sha512-PTNtvUQihsAsDHMOP5pfobP8C6CM4JWXmP8DrEIt46c3r2bf87Ua1zoqevsMo9g+tWDwgWrFP5EIxuBx5RudAw=="], - - "@babel/parser": ["@babel/parser@7.28.3", "", { "dependencies": { "@babel/types": "^7.28.2" }, "bin": "./bin/babel-parser.js" }, "sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA=="], - - "@babel/plugin-syntax-jsx": ["@babel/plugin-syntax-jsx@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w=="], - - "@babel/template": ["@babel/template@7.27.2", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/parser": "^7.27.2", "@babel/types": "^7.27.1" } }, "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw=="], - - "@babel/traverse": ["@babel/traverse@7.28.3", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.3", "@babel/template": "^7.27.2", "@babel/types": "^7.28.2", "debug": "^4.3.1" } }, "sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ=="], - - "@babel/types": ["@babel/types@7.28.2", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ=="], - - "@emotion/is-prop-valid": ["@emotion/is-prop-valid@1.2.2", "", { "dependencies": { "@emotion/memoize": "^0.8.1" } }, "sha512-uNsoYd37AFmaCdXlg6EYD1KaPOaRWRByMCYzbKUX4+hhMfrxdVSelShywL4JVaAeM/eHUOSprYBQls+/neX3pw=="], - - "@emotion/memoize": ["@emotion/memoize@0.8.1", "", {}, "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA=="], - - "@emotion/unitless": ["@emotion/unitless@0.8.1", "", {}, "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ=="], - - "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.9", "", { "os": "aix", "cpu": "ppc64" }, "sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA=="], - - "@esbuild/android-arm": ["@esbuild/android-arm@0.25.9", "", { "os": "android", "cpu": "arm" }, "sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ=="], - - "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.9", "", { "os": "android", "cpu": "arm64" }, "sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg=="], - - "@esbuild/android-x64": ["@esbuild/android-x64@0.25.9", "", { "os": "android", "cpu": "x64" }, "sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw=="], - - "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.9", "", { "os": "darwin", "cpu": "arm64" }, "sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg=="], - - "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.9", "", { "os": "darwin", "cpu": "x64" }, "sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ=="], - - "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.9", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q=="], - - "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.9", "", { "os": "freebsd", "cpu": "x64" }, "sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg=="], - - "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.9", "", { "os": "linux", "cpu": "arm" }, "sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw=="], - - "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.9", "", { "os": "linux", "cpu": "arm64" }, "sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw=="], - - "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.9", "", { "os": "linux", "cpu": "ia32" }, "sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A=="], - - "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.9", "", { "os": "linux", "cpu": "none" }, "sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ=="], - - "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.9", "", { "os": "linux", "cpu": "none" }, "sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA=="], - - "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.9", "", { "os": "linux", "cpu": "ppc64" }, "sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w=="], - - "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.9", "", { "os": "linux", "cpu": "none" }, "sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg=="], - - "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.9", "", { "os": "linux", "cpu": "s390x" }, "sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA=="], - - "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.9", "", { "os": "linux", "cpu": "x64" }, "sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg=="], - - "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.9", "", { "os": "none", "cpu": "arm64" }, "sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q=="], - - "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.9", "", { "os": "none", "cpu": "x64" }, "sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g=="], - - "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.9", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ=="], - - "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.9", "", { "os": "openbsd", "cpu": "x64" }, "sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA=="], - - "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.9", "", { "os": "none", "cpu": "arm64" }, "sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg=="], - - "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.9", "", { "os": "sunos", "cpu": "x64" }, "sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw=="], - - "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.9", "", { "os": "win32", "cpu": "arm64" }, "sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ=="], - - "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.9", "", { "os": "win32", "cpu": "ia32" }, "sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww=="], - - "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.9", "", { "os": "win32", "cpu": "x64" }, "sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ=="], - - "@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.7.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw=="], - - "@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.1", "", {}, "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ=="], - - "@eslint/config-array": ["@eslint/config-array@0.21.0", "", { "dependencies": { "@eslint/object-schema": "^2.1.6", "debug": "^4.3.1", "minimatch": "^3.1.2" } }, "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ=="], - - "@eslint/config-helpers": ["@eslint/config-helpers@0.3.1", "", {}, "sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA=="], - - "@eslint/core": ["@eslint/core@0.15.2", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg=="], - - "@eslint/eslintrc": ["@eslint/eslintrc@3.3.1", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ=="], - - "@eslint/js": ["@eslint/js@9.34.0", "", {}, "sha512-EoyvqQnBNsV1CWaEJ559rxXL4c8V92gxirbawSmVUOWXlsRxxQXl6LmCpdUblgxgSkDIqKnhzba2SjRTI/A5Rw=="], - - "@eslint/object-schema": ["@eslint/object-schema@2.1.6", "", {}, "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA=="], - - "@eslint/plugin-kit": ["@eslint/plugin-kit@0.3.5", "", { "dependencies": { "@eslint/core": "^0.15.2", "levn": "^0.4.1" } }, "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w=="], - - "@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="], - - "@humanfs/node": ["@humanfs/node@0.16.6", "", { "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.3.0" } }, "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw=="], - - "@humanwhocodes/module-importer": ["@humanwhocodes/module-importer@1.0.1", "", {}, "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="], - - "@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="], - - "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], - - "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], - - "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], - - "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.30", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q=="], - - "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], - - "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="], - - "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], - - "@phenixrts/sdk": ["@phenixrts/sdk@2025.2.2", "", {}, "sha512-thxg7IE3a8qE/hk1KM6zMZcZXww54/Hy8UdR4C4J43itp4r+JfD3jKLMqrHajPazbz7IaqX8ihiMDgrmRBGI7w=="], - - "@reduxjs/toolkit": ["@reduxjs/toolkit@2.9.0", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "@standard-schema/utils": "^0.3.0", "immer": "^10.0.3", "redux": "^5.0.1", "redux-thunk": "^3.1.0", "reselect": "^5.1.0" }, "peerDependencies": { "react": "^16.9.0 || ^17.0.0 || ^18 || ^19", "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" }, "optionalPeers": ["react", "react-redux"] }, "sha512-fSfQlSRu9Z5yBkvsNhYF2rPS8cGXn/TZVrlwN1948QyZ8xMZ0JvP50S2acZNaf+o63u6aEeMjipFyksjIcWrog=="], - - "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.32", "", {}, "sha512-QReCdvxiUZAPkvp1xpAg62IeNzykOFA6syH2CnClif4YmALN1XKpB39XneL80008UbtMShthSVDKmrx05N1q/g=="], - - "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.50.0", "", { "os": "android", "cpu": "arm" }, "sha512-lVgpeQyy4fWN5QYebtW4buT/4kn4p4IJ+kDNB4uYNT5b8c8DLJDg6titg20NIg7E8RWwdWZORW6vUFfrLyG3KQ=="], - - "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.50.0", "", { "os": "android", "cpu": "arm64" }, "sha512-2O73dR4Dc9bp+wSYhviP6sDziurB5/HCym7xILKifWdE9UsOe2FtNcM+I4xZjKrfLJnq5UR8k9riB87gauiQtw=="], - - "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.50.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-vwSXQN8T4sKf1RHr1F0s98Pf8UPz7pS6P3LG9NSmuw0TVh7EmaE+5Ny7hJOZ0M2yuTctEsHHRTMi2wuHkdS6Hg=="], - - "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.50.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-cQp/WG8HE7BCGyFVuzUg0FNmupxC+EPZEwWu2FCGGw5WDT1o2/YlENbm5e9SMvfDFR6FRhVCBePLqj0o8MN7Vw=="], - - "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.50.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-UR1uTJFU/p801DvvBbtDD7z9mQL8J80xB0bR7DqW7UGQHRm/OaKzp4is7sQSdbt2pjjSS72eAtRh43hNduTnnQ=="], - - "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.50.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-G/DKyS6PK0dD0+VEzH/6n/hWDNPDZSMBmqsElWnCRGrYOb2jC0VSupp7UAHHQ4+QILwkxSMaYIbQ72dktp8pKA=="], - - "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.50.0", "", { "os": "linux", "cpu": "arm" }, "sha512-u72Mzc6jyJwKjJbZZcIYmd9bumJu7KNmHYdue43vT1rXPm2rITwmPWF0mmPzLm9/vJWxIRbao/jrQmxTO0Sm9w=="], - - "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.50.0", "", { "os": "linux", "cpu": "arm" }, "sha512-S4UefYdV0tnynDJV1mdkNawp0E5Qm2MtSs330IyHgaccOFrwqsvgigUD29uT+B/70PDY1eQ3t40+xf6wIvXJyg=="], - - "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.50.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-1EhkSvUQXJsIhk4msxP5nNAUWoB4MFDHhtc4gAYvnqoHlaL9V3F37pNHabndawsfy/Tp7BPiy/aSa6XBYbaD1g=="], - - "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.50.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-EtBDIZuDtVg75xIPIK1l5vCXNNCIRM0OBPUG+tbApDuJAy9mKago6QxX+tfMzbCI6tXEhMuZuN1+CU8iDW+0UQ=="], - - "@rollup/rollup-linux-loongarch64-gnu": ["@rollup/rollup-linux-loongarch64-gnu@4.50.0", "", { "os": "linux", "cpu": "none" }, "sha512-BGYSwJdMP0hT5CCmljuSNx7+k+0upweM2M4YGfFBjnFSZMHOLYR0gEEj/dxyYJ6Zc6AiSeaBY8dWOa11GF/ppQ=="], - - "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.50.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-I1gSMzkVe1KzAxKAroCJL30hA4DqSi+wGc5gviD0y3IL/VkvcnAqwBf4RHXHyvH66YVHxpKO8ojrgc4SrWAnLg=="], - - "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.50.0", "", { "os": "linux", "cpu": "none" }, "sha512-bSbWlY3jZo7molh4tc5dKfeSxkqnf48UsLqYbUhnkdnfgZjgufLS/NTA8PcP/dnvct5CCdNkABJ56CbclMRYCA=="], - - "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.50.0", "", { "os": "linux", "cpu": "none" }, "sha512-LSXSGumSURzEQLT2e4sFqFOv3LWZsEF8FK7AAv9zHZNDdMnUPYH3t8ZlaeYYZyTXnsob3htwTKeWtBIkPV27iQ=="], - - "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.50.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-CxRKyakfDrsLXiCyucVfVWVoaPA4oFSpPpDwlMcDFQvrv3XY6KEzMtMZrA+e/goC8xxp2WSOxHQubP8fPmmjOQ=="], - - "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.50.0", "", { "os": "linux", "cpu": "x64" }, "sha512-8PrJJA7/VU8ToHVEPu14FzuSAqVKyo5gg/J8xUerMbyNkWkO9j2ExBho/68RnJsMGNJq4zH114iAttgm7BZVkA=="], - - "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.50.0", "", { "os": "linux", "cpu": "x64" }, "sha512-SkE6YQp+CzpyOrbw7Oc4MgXFvTw2UIBElvAvLCo230pyxOLmYwRPwZ/L5lBe/VW/qT1ZgND9wJfOsdy0XptRvw=="], - - "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.50.0", "", { "os": "none", "cpu": "arm64" }, "sha512-PZkNLPfvXeIOgJWA804zjSFH7fARBBCpCXxgkGDRjjAhRLOR8o0IGS01ykh5GYfod4c2yiiREuDM8iZ+pVsT+Q=="], - - "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.50.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-q7cIIdFvWQoaCbLDUyUc8YfR3Jh2xx3unO8Dn6/TTogKjfwrax9SyfmGGK6cQhKtjePI7jRfd7iRYcxYs93esg=="], - - "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.50.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-XzNOVg/YnDOmFdDKcxxK410PrcbcqZkBmz+0FicpW5jtjKQxcW1BZJEQOF0NJa6JO7CZhett8GEtRN/wYLYJuw=="], - - "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.50.0", "", { "os": "win32", "cpu": "x64" }, "sha512-xMmiWRR8sp72Zqwjgtf3QbZfF1wdh8X2ABu3EaozvZcyHJeU0r+XAnXdKgs4cCAp6ORoYoCygipYP1mjmbjrsg=="], - - "@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="], - - "@standard-schema/utils": ["@standard-schema/utils@0.3.0", "", {}, "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g=="], - - "@swc/core": ["@swc/core@1.13.5", "", { "dependencies": { "@swc/counter": "^0.1.3", "@swc/types": "^0.1.24" }, "optionalDependencies": { "@swc/core-darwin-arm64": "1.13.5", "@swc/core-darwin-x64": "1.13.5", "@swc/core-linux-arm-gnueabihf": "1.13.5", "@swc/core-linux-arm64-gnu": "1.13.5", "@swc/core-linux-arm64-musl": "1.13.5", "@swc/core-linux-x64-gnu": "1.13.5", "@swc/core-linux-x64-musl": "1.13.5", "@swc/core-win32-arm64-msvc": "1.13.5", "@swc/core-win32-ia32-msvc": "1.13.5", "@swc/core-win32-x64-msvc": "1.13.5" }, "peerDependencies": { "@swc/helpers": ">=0.5.17" }, "optionalPeers": ["@swc/helpers"] }, "sha512-WezcBo8a0Dg2rnR82zhwoR6aRNxeTGfK5QCD6TQ+kg3xx/zNT02s/0o+81h/3zhvFSB24NtqEr8FTw88O5W/JQ=="], - - "@swc/core-darwin-arm64": ["@swc/core-darwin-arm64@1.13.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-lKNv7SujeXvKn16gvQqUQI5DdyY8v7xcoO3k06/FJbHJS90zEwZdQiMNRiqpYw/orU543tPaWgz7cIYWhbopiQ=="], - - "@swc/core-darwin-x64": ["@swc/core-darwin-x64@1.13.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-ILd38Fg/w23vHb0yVjlWvQBoE37ZJTdlLHa8LRCFDdX4WKfnVBiblsCU9ar4QTMNdeTBEX9iUF4IrbNWhaF1Ng=="], - - "@swc/core-linux-arm-gnueabihf": ["@swc/core-linux-arm-gnueabihf@1.13.5", "", { "os": "linux", "cpu": "arm" }, "sha512-Q6eS3Pt8GLkXxqz9TAw+AUk9HpVJt8Uzm54MvPsqp2yuGmY0/sNaPPNVqctCX9fu/Nu8eaWUen0si6iEiCsazQ=="], - - "@swc/core-linux-arm64-gnu": ["@swc/core-linux-arm64-gnu@1.13.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-aNDfeN+9af+y+M2MYfxCzCy/VDq7Z5YIbMqRI739o8Ganz6ST+27kjQFd8Y/57JN/hcnUEa9xqdS3XY7WaVtSw=="], - - "@swc/core-linux-arm64-musl": ["@swc/core-linux-arm64-musl@1.13.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-9+ZxFN5GJag4CnYnq6apKTnnezpfJhCumyz0504/JbHLo+Ue+ZtJnf3RhyA9W9TINtLE0bC4hKpWi8ZKoETyOQ=="], - - "@swc/core-linux-x64-gnu": ["@swc/core-linux-x64-gnu@1.13.5", "", { "os": "linux", "cpu": "x64" }, "sha512-WD530qvHrki8Ywt/PloKUjaRKgstQqNGvmZl54g06kA+hqtSE2FTG9gngXr3UJxYu/cNAjJYiBifm7+w4nbHbA=="], - - "@swc/core-linux-x64-musl": ["@swc/core-linux-x64-musl@1.13.5", "", { "os": "linux", "cpu": "x64" }, "sha512-Luj8y4OFYx4DHNQTWjdIuKTq2f5k6uSXICqx+FSabnXptaOBAbJHNbHT/06JZh6NRUouaf0mYXN0mcsqvkhd7Q=="], - - "@swc/core-win32-arm64-msvc": ["@swc/core-win32-arm64-msvc@1.13.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-cZ6UpumhF9SDJvv4DA2fo9WIzlNFuKSkZpZmPG1c+4PFSEMy5DFOjBSllCvnqihCabzXzpn6ykCwBmHpy31vQw=="], - - "@swc/core-win32-ia32-msvc": ["@swc/core-win32-ia32-msvc@1.13.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-C5Yi/xIikrFUzZcyGj9L3RpKljFvKiDMtyDzPKzlsDrKIw2EYY+bF88gB6oGY5RGmv4DAX8dbnpRAqgFD0FMEw=="], - - "@swc/core-win32-x64-msvc": ["@swc/core-win32-x64-msvc@1.13.5", "", { "os": "win32", "cpu": "x64" }, "sha512-YrKdMVxbYmlfybCSbRtrilc6UA8GF5aPmGKBdPvjrarvsmf4i7ZHGCEnLtfOMd3Lwbs2WUZq3WdMbozYeLU93Q=="], - - "@swc/counter": ["@swc/counter@0.1.3", "", {}, "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ=="], - - "@swc/types": ["@swc/types@0.1.24", "", { "dependencies": { "@swc/counter": "^0.1.3" } }, "sha512-tjTMh3V4vAORHtdTprLlfoMptu1WfTZG9Rsca6yOKyNYsRr+MUXutKmliB17orgSZk5DpnDxs8GUdd/qwYxOng=="], - - "@techniker-me/pcast-api": ["@techniker-me/pcast-api@2025.1.5", "https://registry-node.techniker.me/@techniker-me/pcast-api/-/pcast-api-2025.1.5.tgz", { "dependencies": { "phenix-edge-auth": "1.2.7" } }, "sha512-2e/ufy6rUx4fm9g8RMmzYXLUd+Tq8fQvpTCUQbgf7612u/tAZtmWujs3OUK4QzdIPF1W2GuPPWI3NzObb0paog=="], - - "@techniker-me/tools": ["@techniker-me/tools@2025.0.16", "https://registry-node.techniker.me/@techniker-me/tools/-/tools-2025.0.16.tgz", {}, "sha512-Ul2yj1vd4lCO8g7IW2pHkAsdeRVEUMqGpiIvSedCc1joVXEWPbh4GESW83kMHtisjFjjlZIzb3EVlCE0BCiBWQ=="], - - "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], - - "@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="], - - "@types/node": ["@types/node@24.3.0", "", { "dependencies": { "undici-types": "~7.10.0" } }, "sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow=="], - - "@types/react": ["@types/react@19.1.12", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-cMoR+FoAf/Jyq6+Df2/Z41jISvGZZ2eTlnsaJRptmZ76Caldwy1odD4xTr/gNV9VLj0AWgg/nmkevIyUfIIq5w=="], - - "@types/react-dom": ["@types/react-dom@19.1.9", "", { "peerDependencies": { "@types/react": "^19.0.0" } }, "sha512-qXRuZaOsAdXKFyOhRBg6Lqqc0yay13vN7KrIg4L7N4aaHN68ma9OK3NE1BoDFgFOTfM7zg+3/8+2n8rLUH3OKQ=="], - - "@types/stylis": ["@types/stylis@4.2.5", "", {}, "sha512-1Xve+NMN7FWjY14vLoY5tL3BVEQ/n42YLwaqJIPYhotZ9uBHt87VceMwWQpzmdEt2TNXIorIFG+YeCUUW7RInw=="], - - "@types/use-sync-external-store": ["@types/use-sync-external-store@0.0.6", "", {}, "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg=="], - - "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.42.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.42.0", "@typescript-eslint/type-utils": "8.42.0", "@typescript-eslint/utils": "8.42.0", "@typescript-eslint/visitor-keys": "8.42.0", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.42.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-Aq2dPqsQkxHOLfb2OPv43RnIvfj05nw8v/6n3B2NABIPpHnjQnaLo9QGMTvml+tv4korl/Cjfrb/BYhoL8UUTQ=="], - - "@typescript-eslint/parser": ["@typescript-eslint/parser@8.42.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.42.0", "@typescript-eslint/types": "8.42.0", "@typescript-eslint/typescript-estree": "8.42.0", "@typescript-eslint/visitor-keys": "8.42.0", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-r1XG74QgShUgXph1BYseJ+KZd17bKQib/yF3SR+demvytiRXrwd12Blnz5eYGm8tXaeRdd4x88MlfwldHoudGg=="], - - "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.42.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.42.0", "@typescript-eslint/types": "^8.42.0", "debug": "^4.3.4" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-vfVpLHAhbPjilrabtOSNcUDmBboQNrJUiNAGoImkZKnMjs2TIcWG33s4Ds0wY3/50aZmTMqJa6PiwkwezaAklg=="], - - "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.42.0", "", { "dependencies": { "@typescript-eslint/types": "8.42.0", "@typescript-eslint/visitor-keys": "8.42.0" } }, "sha512-51+x9o78NBAVgQzOPd17DkNTnIzJ8T/O2dmMBLoK9qbY0Gm52XJcdJcCl18ExBMiHo6jPMErUQWUv5RLE51zJw=="], - - "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.42.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-kHeFUOdwAJfUmYKjR3CLgZSglGHjbNTi1H8sTYRYV2xX6eNz4RyJ2LIgsDLKf8Yi0/GL1WZAC/DgZBeBft8QAQ=="], - - "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.42.0", "", { "dependencies": { "@typescript-eslint/types": "8.42.0", "@typescript-eslint/typescript-estree": "8.42.0", "@typescript-eslint/utils": "8.42.0", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-9KChw92sbPTYVFw3JLRH1ockhyR3zqqn9lQXol3/YbI6jVxzWoGcT3AsAW0mu1MY0gYtsXnUGV/AKpkAj5tVlQ=="], - - "@typescript-eslint/types": ["@typescript-eslint/types@8.42.0", "", {}, "sha512-LdtAWMiFmbRLNP7JNeY0SqEtJvGMYSzfiWBSmx+VSZ1CH+1zyl8Mmw1TT39OrtsRvIYShjJWzTDMPWZJCpwBlw=="], - - "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.42.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.42.0", "@typescript-eslint/tsconfig-utils": "8.42.0", "@typescript-eslint/types": "8.42.0", "@typescript-eslint/visitor-keys": "8.42.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-ku/uYtT4QXY8sl9EDJETD27o3Ewdi72hcXg1ah/kkUgBvAYHLwj2ofswFFNXS+FL5G+AGkxBtvGt8pFBHKlHsQ=="], - - "@typescript-eslint/utils": ["@typescript-eslint/utils@8.42.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.42.0", "@typescript-eslint/types": "8.42.0", "@typescript-eslint/typescript-estree": "8.42.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-JnIzu7H3RH5BrKC4NoZqRfmjqCIS1u3hGZltDYJgkVdqAezl4L9d1ZLw+36huCujtSBSAirGINF/S4UxOcR+/g=="], - - "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.42.0", "", { "dependencies": { "@typescript-eslint/types": "8.42.0", "eslint-visitor-keys": "^4.2.1" } }, "sha512-3WbiuzoEowaEn8RSnhJBrxSwX8ULYE9CXaPepS2C2W3NSA5NNIvBaslpBSBElPq0UGr0xVJlXFWOAKIkyylydQ=="], - - "@vitejs/plugin-react-swc": ["@vitejs/plugin-react-swc@4.0.1", "", { "dependencies": { "@rolldown/pluginutils": "1.0.0-beta.32", "@swc/core": "^1.13.2" }, "peerDependencies": { "vite": "^4 || ^5 || ^6 || ^7" } }, "sha512-NQhPjysi5duItyrMd5JWZFf2vNOuSMyw+EoZyTBDzk+DkfYD8WNrsUs09sELV2cr1P15nufsN25hsUBt4CKF9Q=="], - - "acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="], - - "acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="], - - "ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="], - - "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], - - "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], - - "array-buffer-byte-length": ["array-buffer-byte-length@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "is-array-buffer": "^3.0.5" } }, "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw=="], - - "array-includes": ["array-includes@3.1.9", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.4", "define-properties": "^1.2.1", "es-abstract": "^1.24.0", "es-object-atoms": "^1.1.1", "get-intrinsic": "^1.3.0", "is-string": "^1.1.1", "math-intrinsics": "^1.1.0" } }, "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ=="], - - "array.prototype.findlast": ["array.prototype.findlast@1.2.5", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.2", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "es-shim-unscopables": "^1.0.2" } }, "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ=="], - - "array.prototype.flat": ["array.prototype.flat@1.3.3", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-shim-unscopables": "^1.0.2" } }, "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg=="], - - "array.prototype.flatmap": ["array.prototype.flatmap@1.3.3", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-shim-unscopables": "^1.0.2" } }, "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg=="], - - "array.prototype.tosorted": ["array.prototype.tosorted@1.1.4", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.3", "es-errors": "^1.3.0", "es-shim-unscopables": "^1.0.2" } }, "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA=="], - - "arraybuffer.prototype.slice": ["arraybuffer.prototype.slice@1.0.4", "", { "dependencies": { "array-buffer-byte-length": "^1.0.1", "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "is-array-buffer": "^3.0.4" } }, "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ=="], - - "async-function": ["async-function@1.0.0", "", {}, "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA=="], - - "available-typed-arrays": ["available-typed-arrays@1.0.7", "", { "dependencies": { "possible-typed-array-names": "^1.0.0" } }, "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ=="], - - "babel-plugin-styled-components": ["babel-plugin-styled-components@2.1.4", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", "@babel/helper-module-imports": "^7.22.5", "@babel/plugin-syntax-jsx": "^7.22.5", "lodash": "^4.17.21", "picomatch": "^2.3.1" }, "peerDependencies": { "styled-components": ">= 2" } }, "sha512-Xgp9g+A/cG47sUyRwwYxGM4bR/jDRg5N6it/8+HxCnbT5XNKSKDT9xm4oag/osgqjC2It/vH0yXsomOG6k558g=="], - - "babel-plugin-transform-amd-to-commonjs": ["babel-plugin-transform-amd-to-commonjs@1.6.0", "", { "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-Dwvn+0BM6hdLMA5sfD9QzMICo8NnqqyqCyiNeKPruAuEZDdDVWbPkPh26ckJqfL/hYIkzAvK3Zj2H/7pBzIpig=="], - - "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], - - "brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], - - "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], - - "browserslist": ["browserslist@4.25.4", "", { "dependencies": { "caniuse-lite": "^1.0.30001737", "electron-to-chromium": "^1.5.211", "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-4jYpcjabC606xJ3kw2QwGEZKX0Aw7sgQdZCvIK9dhVSPh76BKo+C+btT1RRofH7B+8iNpEbgGNVWiLki5q93yg=="], - - "call-bind": ["call-bind@1.0.8", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.0", "es-define-property": "^1.0.0", "get-intrinsic": "^1.2.4", "set-function-length": "^1.2.2" } }, "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww=="], - - "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], - - "call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="], - - "callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="], - - "camelize": ["camelize@1.0.1", "", {}, "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ=="], - - "caniuse-lite": ["caniuse-lite@1.0.30001739", "", {}, "sha512-y+j60d6ulelrNSwpPyrHdl+9mJnQzHBr08xm48Qno0nSk4h3Qojh+ziv2qE6rXf4k3tadF4o1J/1tAbVm1NtnA=="], - - "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], - - "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], - - "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], - - "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], - - "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], - - "cookie": ["cookie@1.0.2", "", {}, "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA=="], - - "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], - - "css-color-keywords": ["css-color-keywords@1.0.0", "", {}, "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg=="], - - "css-to-react-native": ["css-to-react-native@3.2.0", "", { "dependencies": { "camelize": "^1.0.0", "css-color-keywords": "^1.0.0", "postcss-value-parser": "^4.0.2" } }, "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ=="], - - "csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="], - - "data-view-buffer": ["data-view-buffer@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-data-view": "^1.0.2" } }, "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ=="], - - "data-view-byte-length": ["data-view-byte-length@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-data-view": "^1.0.2" } }, "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ=="], - - "data-view-byte-offset": ["data-view-byte-offset@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "is-data-view": "^1.0.1" } }, "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ=="], - - "debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="], - - "deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="], - - "define-data-property": ["define-data-property@1.1.4", "", { "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", "gopd": "^1.0.1" } }, "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A=="], - - "define-properties": ["define-properties@1.2.1", "", { "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" } }, "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg=="], - - "doctrine": ["doctrine@2.1.0", "", { "dependencies": { "esutils": "^2.0.2" } }, "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw=="], - - "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], - - "electron-to-chromium": ["electron-to-chromium@1.5.212", "", {}, "sha512-gE7ErIzSW+d8jALWMcOIgf+IB6lpfsg6NwOhPVwKzDtN2qcBix47vlin4yzSregYDxTCXOUqAZjVY/Z3naS7ww=="], - - "es-abstract": ["es-abstract@1.24.0", "", { "dependencies": { "array-buffer-byte-length": "^1.0.2", "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.4", "data-view-buffer": "^1.0.2", "data-view-byte-length": "^1.0.2", "data-view-byte-offset": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", "get-intrinsic": "^1.3.0", "get-proto": "^1.0.1", "get-symbol-description": "^1.1.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "internal-slot": "^1.1.0", "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", "is-data-view": "^1.0.2", "is-negative-zero": "^2.0.3", "is-regex": "^1.2.1", "is-set": "^2.0.3", "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", "is-weakref": "^1.1.1", "math-intrinsics": "^1.1.0", "object-inspect": "^1.13.4", "object-keys": "^1.1.1", "object.assign": "^4.1.7", "own-keys": "^1.0.1", "regexp.prototype.flags": "^1.5.4", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", "set-proto": "^1.0.0", "stop-iteration-iterator": "^1.1.0", "string.prototype.trim": "^1.2.10", "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", "typed-array-buffer": "^1.0.3", "typed-array-byte-length": "^1.0.3", "typed-array-byte-offset": "^1.0.4", "typed-array-length": "^1.0.7", "unbox-primitive": "^1.1.0", "which-typed-array": "^1.1.19" } }, "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg=="], - - "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], - - "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], - - "es-iterator-helpers": ["es-iterator-helpers@1.2.1", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-abstract": "^1.23.6", "es-errors": "^1.3.0", "es-set-tostringtag": "^2.0.3", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.6", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "internal-slot": "^1.1.0", "iterator.prototype": "^1.1.4", "safe-array-concat": "^1.1.3" } }, "sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w=="], - - "es-module-lexer": ["es-module-lexer@1.7.0", "", {}, "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA=="], - - "es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="], - - "es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="], - - "es-shim-unscopables": ["es-shim-unscopables@1.1.0", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw=="], - - "es-to-primitive": ["es-to-primitive@1.3.0", "", { "dependencies": { "is-callable": "^1.2.7", "is-date-object": "^1.0.5", "is-symbol": "^1.0.4" } }, "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g=="], - - "esbuild": ["esbuild@0.25.9", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.9", "@esbuild/android-arm": "0.25.9", "@esbuild/android-arm64": "0.25.9", "@esbuild/android-x64": "0.25.9", "@esbuild/darwin-arm64": "0.25.9", "@esbuild/darwin-x64": "0.25.9", "@esbuild/freebsd-arm64": "0.25.9", "@esbuild/freebsd-x64": "0.25.9", "@esbuild/linux-arm": "0.25.9", "@esbuild/linux-arm64": "0.25.9", "@esbuild/linux-ia32": "0.25.9", "@esbuild/linux-loong64": "0.25.9", "@esbuild/linux-mips64el": "0.25.9", "@esbuild/linux-ppc64": "0.25.9", "@esbuild/linux-riscv64": "0.25.9", "@esbuild/linux-s390x": "0.25.9", "@esbuild/linux-x64": "0.25.9", "@esbuild/netbsd-arm64": "0.25.9", "@esbuild/netbsd-x64": "0.25.9", "@esbuild/openbsd-arm64": "0.25.9", "@esbuild/openbsd-x64": "0.25.9", "@esbuild/openharmony-arm64": "0.25.9", "@esbuild/sunos-x64": "0.25.9", "@esbuild/win32-arm64": "0.25.9", "@esbuild/win32-ia32": "0.25.9", "@esbuild/win32-x64": "0.25.9" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g=="], - - "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], - - "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], - - "eslint": ["eslint@9.34.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.0", "@eslint/config-helpers": "^0.3.1", "@eslint/core": "^0.15.2", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "9.34.0", "@eslint/plugin-kit": "^0.3.5", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-RNCHRX5EwdrESy3Jc9o8ie8Bog+PeYvvSR8sDGoZxNFTvZ4dlxUB3WzQ3bQMztFrSRODGrLLj8g6OFuGY/aiQg=="], - - "eslint-plugin-react": ["eslint-plugin-react@7.37.5", "", { "dependencies": { "array-includes": "^3.1.8", "array.prototype.findlast": "^1.2.5", "array.prototype.flatmap": "^1.3.3", "array.prototype.tosorted": "^1.1.4", "doctrine": "^2.1.0", "es-iterator-helpers": "^1.2.1", "estraverse": "^5.3.0", "hasown": "^2.0.2", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.1.2", "object.entries": "^1.1.9", "object.fromentries": "^2.0.8", "object.values": "^1.2.1", "prop-types": "^15.8.1", "resolve": "^2.0.0-next.5", "semver": "^6.3.1", "string.prototype.matchall": "^4.0.12", "string.prototype.repeat": "^1.0.0" }, "peerDependencies": { "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" } }, "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA=="], - - "eslint-plugin-react-hooks": ["eslint-plugin-react-hooks@5.2.0", "", { "peerDependencies": { "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" } }, "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg=="], - - "eslint-plugin-react-refresh": ["eslint-plugin-react-refresh@0.4.20", "", { "peerDependencies": { "eslint": ">=8.40" } }, "sha512-XpbHQ2q5gUF8BGOX4dHe+71qoirYMhApEPZ7sfhF/dNnOF1UXnCMGZf79SFTBO7Bz5YEIT4TMieSlJBWhP9WBA=="], - - "eslint-scope": ["eslint-scope@8.4.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg=="], - - "eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="], - - "espree": ["espree@10.4.0", "", { "dependencies": { "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.1" } }, "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ=="], - - "esquery": ["esquery@1.6.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg=="], - - "esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="], - - "estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="], - - "esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="], - - "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], - - "fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="], - - "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="], - - "fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="], - - "fastq": ["fastq@1.19.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ=="], - - "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], - - "file-entry-cache": ["file-entry-cache@8.0.0", "", { "dependencies": { "flat-cache": "^4.0.0" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="], - - "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], - - "find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="], - - "flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="], - - "flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="], - - "for-each": ["for-each@0.3.5", "", { "dependencies": { "is-callable": "^1.2.7" } }, "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg=="], - - "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], - - "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], - - "function.prototype.name": ["function.prototype.name@1.1.8", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "functions-have-names": "^1.2.3", "hasown": "^2.0.2", "is-callable": "^1.2.7" } }, "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q=="], - - "functions-have-names": ["functions-have-names@1.2.3", "", {}, "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ=="], - - "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="], - - "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], - - "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], - - "get-symbol-description": ["get-symbol-description@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6" } }, "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg=="], - - "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], - - "globals": ["globals@16.3.0", "", {}, "sha512-bqWEnJ1Nt3neqx2q5SFfGS8r/ahumIakg3HcwtNlrVlwXIeNumWn/c7Pn/wKzGhf6SaW6H6uWXLqC30STCMchQ=="], - - "globalthis": ["globalthis@1.0.4", "", { "dependencies": { "define-properties": "^1.2.1", "gopd": "^1.0.1" } }, "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ=="], - - "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], - - "graphemer": ["graphemer@1.4.0", "", {}, "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag=="], - - "has-bigints": ["has-bigints@1.1.0", "", {}, "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg=="], - - "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], - - "has-property-descriptors": ["has-property-descriptors@1.0.2", "", { "dependencies": { "es-define-property": "^1.0.0" } }, "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg=="], - - "has-proto": ["has-proto@1.2.0", "", { "dependencies": { "dunder-proto": "^1.0.0" } }, "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ=="], - - "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], - - "has-tostringtag": ["has-tostringtag@1.0.2", "", { "dependencies": { "has-symbols": "^1.0.3" } }, "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw=="], - - "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], - - "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], - - "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], - - "immer": ["immer@10.1.3", "", {}, "sha512-tmjF/k8QDKydUlm3mZU+tjM6zeq9/fFpPqH9SzWmBnVVKsPBg/V66qsMwb3/Bo90cgUN+ghdVBess+hPsxUyRw=="], - - "import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="], - - "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="], - - "internal-slot": ["internal-slot@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "hasown": "^2.0.2", "side-channel": "^1.1.0" } }, "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw=="], - - "is-array-buffer": ["is-array-buffer@3.0.5", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "get-intrinsic": "^1.2.6" } }, "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A=="], - - "is-async-function": ["is-async-function@2.1.1", "", { "dependencies": { "async-function": "^1.0.0", "call-bound": "^1.0.3", "get-proto": "^1.0.1", "has-tostringtag": "^1.0.2", "safe-regex-test": "^1.1.0" } }, "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ=="], - - "is-bigint": ["is-bigint@1.1.0", "", { "dependencies": { "has-bigints": "^1.0.2" } }, "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ=="], - - "is-boolean-object": ["is-boolean-object@1.2.2", "", { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A=="], - - "is-callable": ["is-callable@1.2.7", "", {}, "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA=="], - - "is-core-module": ["is-core-module@2.16.1", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w=="], - - "is-data-view": ["is-data-view@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "get-intrinsic": "^1.2.6", "is-typed-array": "^1.1.13" } }, "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw=="], - - "is-date-object": ["is-date-object@1.1.0", "", { "dependencies": { "call-bound": "^1.0.2", "has-tostringtag": "^1.0.2" } }, "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg=="], - - "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], - - "is-finalizationregistry": ["is-finalizationregistry@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg=="], - - "is-generator-function": ["is-generator-function@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "get-proto": "^1.0.0", "has-tostringtag": "^1.0.2", "safe-regex-test": "^1.1.0" } }, "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ=="], - - "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], - - "is-map": ["is-map@2.0.3", "", {}, "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw=="], - - "is-negative-zero": ["is-negative-zero@2.0.3", "", {}, "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw=="], - - "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], - - "is-number-object": ["is-number-object@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw=="], - - "is-regex": ["is-regex@1.2.1", "", { "dependencies": { "call-bound": "^1.0.2", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g=="], - - "is-set": ["is-set@2.0.3", "", {}, "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg=="], - - "is-shared-array-buffer": ["is-shared-array-buffer@1.0.4", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A=="], - - "is-string": ["is-string@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA=="], - - "is-symbol": ["is-symbol@1.1.1", "", { "dependencies": { "call-bound": "^1.0.2", "has-symbols": "^1.1.0", "safe-regex-test": "^1.1.0" } }, "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w=="], - - "is-typed-array": ["is-typed-array@1.1.15", "", { "dependencies": { "which-typed-array": "^1.1.16" } }, "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ=="], - - "is-weakmap": ["is-weakmap@2.0.2", "", {}, "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w=="], - - "is-weakref": ["is-weakref@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew=="], - - "is-weakset": ["is-weakset@2.0.4", "", { "dependencies": { "call-bound": "^1.0.3", "get-intrinsic": "^1.2.6" } }, "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ=="], - - "isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], - - "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], - - "iterator.prototype": ["iterator.prototype@1.1.5", "", { "dependencies": { "define-data-property": "^1.1.4", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.6", "get-proto": "^1.0.0", "has-symbols": "^1.1.0", "set-function-name": "^2.0.2" } }, "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g=="], - - "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], - - "js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="], - - "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], - - "json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="], - - "json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], - - "json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="], - - "json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], - - "jsx-ast-utils": ["jsx-ast-utils@3.3.5", "", { "dependencies": { "array-includes": "^3.1.6", "array.prototype.flat": "^1.3.1", "object.assign": "^4.1.4", "object.values": "^1.1.6" } }, "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ=="], - - "keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="], - - "levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="], - - "locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="], - - "lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="], - - "lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="], - - "loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="], - - "lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], - - "lxiv": ["lxiv@0.2.0", "", {}, "sha512-kZfRAqtw3M5iI0oe7sc3Xuo7BMVia5eDX7iodQqUM8cTUBuE0cAQsPXVOmxyD9a3ujAmgak3Dxw0f74aGGg2/w=="], - - "magic-string": ["magic-string@0.30.18", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-yi8swmWbO17qHhwIBNeeZxTceJMeBvWJaId6dyvTSOwTipqeHhMhOrz6513r1sOKnpvQ7zkhlG8tPrpilwTxHQ=="], - - "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], - - "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], - - "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], - - "minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], - - "moment": ["moment@2.30.1", "", {}, "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how=="], - - "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], - - "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], - - "natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="], - - "node-releases": ["node-releases@2.0.19", "", {}, "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw=="], - - "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], - - "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="], - - "object-keys": ["object-keys@1.1.1", "", {}, "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="], - - "object.assign": ["object.assign@4.1.7", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0", "has-symbols": "^1.1.0", "object-keys": "^1.1.1" } }, "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw=="], - - "object.entries": ["object.entries@1.1.9", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.4", "define-properties": "^1.2.1", "es-object-atoms": "^1.1.1" } }, "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw=="], - - "object.fromentries": ["object.fromentries@2.0.8", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.2", "es-object-atoms": "^1.0.0" } }, "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ=="], - - "object.values": ["object.values@1.2.1", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA=="], - - "optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="], - - "own-keys": ["own-keys@1.0.1", "", { "dependencies": { "get-intrinsic": "^1.2.6", "object-keys": "^1.1.1", "safe-push-apply": "^1.0.0" } }, "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg=="], - - "p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], - - "p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="], - - "parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="], - - "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], - - "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], - - "path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="], - - "pbf": ["pbf@3.1.0", "", { "dependencies": { "ieee754": "^1.1.6", "resolve-protobuf-schema": "^2.0.0" }, "bin": { "pbf": "bin/pbf" } }, "sha512-/hYJmIsTmh7fMkHAWWXJ5b8IKLWdjdlAFb3IHkRBn1XUhIYBChVGfVwmHEAV3UfXTxsP/AKfYTXTS/dCPxJd5w=="], - - "phenix-edge-auth": ["phenix-edge-auth@1.2.7", "", {}, "sha512-hmIA4iKrR6Pf+EoIu/k7kxKYXkiD7I8PQL7iZb+9NkC676hCeGPZK+OsRc9uNW+fDZgZlN1qoQjBxDiT5JRe+A=="], - - "phenix-web-assert": ["phenix-web-assert@2020.0.2", "", { "dependencies": { "phenix-web-lodash-light": "^2020.0.2" } }, "sha512-WRgWqXsL1Du/ty/dq/vkooOd3e2BhLCw24vVLWmWZjM/o5TjeOhxQSMSklrDuVRamVGiEkvuQpjL8lIeP/W4TQ=="], - - "phenix-web-batch-http": ["phenix-web-batch-http@2020.0.2", "", { "dependencies": { "phenix-web-assert": "^2020.0.2", "phenix-web-disposable": "^2020.0.2", "phenix-web-event": "^2020.0.2", "phenix-web-global": "^2020.0.2", "phenix-web-http": "^2020.0.2", "phenix-web-lodash-light": "^2020.0.2", "phenix-web-network-connection-monitor": "^2020.0.2", "phenix-web-observable": "^2020.0.2" } }, "sha512-SG9/9RerkYcXIEH9Vk6DRosWF2229DXyeUa0hiU7jawj8xrOnAE7CMVdKcbaK4GGbZWMrT4HetIAMkqxSaHGFA=="], - - "phenix-web-disposable": ["phenix-web-disposable@2020.0.2", "", { "dependencies": { "phenix-web-assert": "^2020.0.2", "phenix-web-lodash-light": "^2020.0.2" } }, "sha512-kW+x6ttFlEgjDB+d5sbqr+f72hTo95SgKLHZaW2LiLYiVNhGSiJT+AscyNWdK2uq4aNjwFVn7Wj3URuwzpudYQ=="], - - "phenix-web-event": ["phenix-web-event@2020.0.2", "", { "dependencies": { "phenix-web-assert": "^2020.0.2", "phenix-web-disposable": "^2020.0.2", "phenix-web-lodash-light": "^2020.0.2" } }, "sha512-6DnrzoZ6Dfwdh5sLaAmeApxf2FgUG/7iQWJL1+IGhAcb2GJqW+JQEMQ8aWIP9lnhQTaoDP8xsAp7aieAALRmrw=="], - - "phenix-web-global": ["phenix-web-global@2020.0.2", "", {}, "sha512-dBn6Ox6Nq79jx3zr/bI5K76yyCmMne/Br2XhRZ5XVXPKSYh5EMWdUBmtmaUub8Gi2Gc9gcJnq5NeiP7z8S1/6A=="], - - "phenix-web-http": ["phenix-web-http@2020.0.2", "", { "dependencies": { "phenix-web-assert": "^2020.0.2", "phenix-web-disposable": "^2020.0.2", "phenix-web-lodash-light": "^2020.0.2" } }, "sha512-5/vev4Zeabmcfl6s4c5sGScGGF6qecGRyVvooex5kExDWkRpm3az04migm87+Nyb/94vYTEoRYqpwFhrrHs5pw=="], - - "phenix-web-lodash-light": ["phenix-web-lodash-light@2020.0.4", "", {}, "sha512-E6xO/laCZXpmMKM/oLZrbB+uYteW4foTrybAoM82pRaLxYvevNUiZKD1xq4sIShMiWjqVv4GNOHlOp109GA/Pw=="], - - "phenix-web-network-connection-monitor": ["phenix-web-network-connection-monitor@2020.0.2", "", { "dependencies": { "phenix-web-disposable": "^2020.0.2", "phenix-web-event": "^2020.0.2", "phenix-web-global": "^2020.0.2", "phenix-web-lodash-light": "^2020.0.2", "phenix-web-observable": "^2020.0.2" } }, "sha512-GizAKpSqsM48lYTAL7s/y5AKX8v3nbx2V75vTVCee2XTYV7b8SR0LnUYkkaefZXE9D+uV+WH+vXUXT9niQBJ/Q=="], - - "phenix-web-observable": ["phenix-web-observable@2020.0.2", "", { "dependencies": { "phenix-web-assert": "^2020.0.2", "phenix-web-disposable": "^2020.0.2", "phenix-web-lodash-light": "^2020.0.2" } }, "sha512-HwdBUV9LFsCa5aov/I+zyD5uFsNcsxxUmjN+3F/0gbfLNRWJlNSRGzBFQrM3UWUE/YOFnEvsEiNg90ZlXpyoKA=="], - - "phenix-web-proto": ["phenix-web-proto@2020.0.3", "", { "dependencies": { "lxiv": "0.2.0", "pbf": "3.1.0", "phenix-web-assert": "^2020.0.2", "phenix-web-batch-http": "^2020.0.2", "phenix-web-disposable": "^2020.0.2", "phenix-web-event": "^2020.0.2", "phenix-web-global": "^2020.0.2", "phenix-web-lodash-light": "^2020.0.2", "phenix-web-reconnecting-websocket": "^2020.0.2" } }, "sha512-79D05OVnKOCTE8mX8his0gEtSaxWgUOsCYzwfZfSEzBk0o80n37ups2T3EfAaoVG9R0rRzWKwg1SmKpmsymxlA=="], - - "phenix-web-reconnecting-websocket": ["phenix-web-reconnecting-websocket@2020.0.2", "", { "dependencies": { "phenix-web-assert": "^2020.0.2", "phenix-web-lodash-light": "^2020.0.2", "phenix-web-network-connection-monitor": "^2020.0.2" } }, "sha512-5l8AvR+8BnQZNhiyz63tuH/xFh5i01YofU6woKHxPGV+HfhJUloHU4nVoUt7vRCfPKRuDTa7bh3hJEtBnOLYag=="], - - "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], - - "picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - - "possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="], - - "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="], - - "postcss-value-parser": ["postcss-value-parser@4.2.0", "", {}, "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="], - - "prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="], - - "prettier": ["prettier@3.6.2", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ=="], - - "prop-types": ["prop-types@15.8.1", "", { "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", "react-is": "^16.13.1" } }, "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg=="], - - "protocol-buffers-schema": ["protocol-buffers-schema@3.6.0", "", {}, "sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw=="], - - "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], - - "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], - - "react": ["react@19.1.1", "", {}, "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ=="], - - "react-dom": ["react-dom@19.1.1", "", { "dependencies": { "scheduler": "^0.26.0" }, "peerDependencies": { "react": "^19.1.1" } }, "sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw=="], - - "react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], - - "react-redux": ["react-redux@9.2.0", "", { "dependencies": { "@types/use-sync-external-store": "^0.0.6", "use-sync-external-store": "^1.4.0" }, "peerDependencies": { "@types/react": "^18.2.25 || ^19", "react": "^18.0 || ^19", "redux": "^5.0.0" }, "optionalPeers": ["@types/react", "redux"] }, "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g=="], - - "react-router": ["react-router@7.8.2", "", { "dependencies": { "cookie": "^1.0.1", "set-cookie-parser": "^2.6.0" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" }, "optionalPeers": ["react-dom"] }, "sha512-7M2fR1JbIZ/jFWqelpvSZx+7vd7UlBTfdZqf6OSdF9g6+sfdqJDAWcak6ervbHph200ePlu+7G8LdoiC3ReyAQ=="], - - "react-router-dom": ["react-router-dom@7.8.2", "", { "dependencies": { "react-router": "7.8.2" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" } }, "sha512-Z4VM5mKDipal2jQ385H6UBhiiEDlnJPx6jyWsTYoZQdl5TrjxEV2a9yl3Fi60NBJxYzOTGTTHXPi0pdizvTwow=="], - - "redux": ["redux@5.0.1", "", {}, "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w=="], - - "redux-thunk": ["redux-thunk@3.1.0", "", { "peerDependencies": { "redux": "^5.0.0" } }, "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw=="], - - "reflect.getprototypeof": ["reflect.getprototypeof@1.0.10", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.9", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.1", "which-builtin-type": "^1.2.1" } }, "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw=="], - - "regexp.prototype.flags": ["regexp.prototype.flags@1.5.4", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-errors": "^1.3.0", "get-proto": "^1.0.1", "gopd": "^1.2.0", "set-function-name": "^2.0.2" } }, "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA=="], - - "reselect": ["reselect@5.1.1", "", {}, "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w=="], - - "resolve": ["resolve@2.0.0-next.5", "", { "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA=="], - - "resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], - - "resolve-protobuf-schema": ["resolve-protobuf-schema@2.1.0", "", { "dependencies": { "protocol-buffers-schema": "^3.3.1" } }, "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ=="], - - "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], - - "rollup": ["rollup@4.50.0", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.50.0", "@rollup/rollup-android-arm64": "4.50.0", "@rollup/rollup-darwin-arm64": "4.50.0", "@rollup/rollup-darwin-x64": "4.50.0", "@rollup/rollup-freebsd-arm64": "4.50.0", "@rollup/rollup-freebsd-x64": "4.50.0", "@rollup/rollup-linux-arm-gnueabihf": "4.50.0", "@rollup/rollup-linux-arm-musleabihf": "4.50.0", "@rollup/rollup-linux-arm64-gnu": "4.50.0", "@rollup/rollup-linux-arm64-musl": "4.50.0", "@rollup/rollup-linux-loongarch64-gnu": "4.50.0", "@rollup/rollup-linux-ppc64-gnu": "4.50.0", "@rollup/rollup-linux-riscv64-gnu": "4.50.0", "@rollup/rollup-linux-riscv64-musl": "4.50.0", "@rollup/rollup-linux-s390x-gnu": "4.50.0", "@rollup/rollup-linux-x64-gnu": "4.50.0", "@rollup/rollup-linux-x64-musl": "4.50.0", "@rollup/rollup-openharmony-arm64": "4.50.0", "@rollup/rollup-win32-arm64-msvc": "4.50.0", "@rollup/rollup-win32-ia32-msvc": "4.50.0", "@rollup/rollup-win32-x64-msvc": "4.50.0", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-/Zl4D8zPifNmyGzJS+3kVoyXeDeT/GrsJM94sACNg9RtUE0hrHa1bNPtRSrfHTMH5HjRzce6K7rlTh3Khiw+pw=="], - - "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], - - "safe-array-concat": ["safe-array-concat@1.1.3", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", "get-intrinsic": "^1.2.6", "has-symbols": "^1.1.0", "isarray": "^2.0.5" } }, "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q=="], - - "safe-push-apply": ["safe-push-apply@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "isarray": "^2.0.5" } }, "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA=="], - - "safe-regex-test": ["safe-regex-test@1.1.0", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "is-regex": "^1.2.1" } }, "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw=="], - - "scheduler": ["scheduler@0.26.0", "", {}, "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA=="], - - "semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - - "set-cookie-parser": ["set-cookie-parser@2.7.1", "", {}, "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ=="], - - "set-function-length": ["set-function-length@1.2.2", "", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2" } }, "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg=="], - - "set-function-name": ["set-function-name@2.0.2", "", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "functions-have-names": "^1.2.3", "has-property-descriptors": "^1.0.2" } }, "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ=="], - - "set-proto": ["set-proto@1.0.0", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0" } }, "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw=="], - - "shallowequal": ["shallowequal@1.1.0", "", {}, "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ=="], - - "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], - - "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], - - "side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="], - - "side-channel-list": ["side-channel-list@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" } }, "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA=="], - - "side-channel-map": ["side-channel-map@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" } }, "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA=="], - - "side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="], - - "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], - - "stop-iteration-iterator": ["stop-iteration-iterator@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "internal-slot": "^1.1.0" } }, "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ=="], - - "string.prototype.matchall": ["string.prototype.matchall@4.0.12", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-abstract": "^1.23.6", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.6", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "internal-slot": "^1.1.0", "regexp.prototype.flags": "^1.5.3", "set-function-name": "^2.0.2", "side-channel": "^1.1.0" } }, "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA=="], - - "string.prototype.repeat": ["string.prototype.repeat@1.0.0", "", { "dependencies": { "define-properties": "^1.1.3", "es-abstract": "^1.17.5" } }, "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w=="], - - "string.prototype.trim": ["string.prototype.trim@1.2.10", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", "define-data-property": "^1.1.4", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-object-atoms": "^1.0.0", "has-property-descriptors": "^1.0.2" } }, "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA=="], - - "string.prototype.trimend": ["string.prototype.trimend@1.0.9", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ=="], - - "string.prototype.trimstart": ["string.prototype.trimstart@1.0.8", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg=="], - - "strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="], - - "styled-components": ["styled-components@6.1.19", "", { "dependencies": { "@emotion/is-prop-valid": "1.2.2", "@emotion/unitless": "0.8.1", "@types/stylis": "4.2.5", "css-to-react-native": "3.2.0", "csstype": "3.1.3", "postcss": "8.4.49", "shallowequal": "1.1.0", "stylis": "4.3.2", "tslib": "2.6.2" }, "peerDependencies": { "react": ">= 16.8.0", "react-dom": ">= 16.8.0" } }, "sha512-1v/e3Dl1BknC37cXMhwGomhO8AkYmN41CqyX9xhUDxry1ns3BFQy2lLDRQXJRdVVWB9OHemv/53xaStimvWyuA=="], - - "stylis": ["stylis@4.3.2", "", {}, "sha512-bhtUjWd/z6ltJiQwg0dUfxEJ+W+jdqQd8TbWLWyeIJHlnsqmGLRFFd8e5mA0AZi/zx90smXRlN66YMTcaSFifg=="], - - "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], - - "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="], - - "tinyglobby": ["tinyglobby@0.2.14", "", { "dependencies": { "fdir": "^6.4.4", "picomatch": "^4.0.2" } }, "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ=="], - - "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], - - "ts-api-utils": ["ts-api-utils@2.1.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ=="], - - "tslib": ["tslib@2.6.2", "", {}, "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="], - - "type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="], - - "typed-array-buffer": ["typed-array-buffer@1.0.3", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-typed-array": "^1.1.14" } }, "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw=="], - - "typed-array-byte-length": ["typed-array-byte-length@1.0.3", "", { "dependencies": { "call-bind": "^1.0.8", "for-each": "^0.3.3", "gopd": "^1.2.0", "has-proto": "^1.2.0", "is-typed-array": "^1.1.14" } }, "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg=="], - - "typed-array-byte-offset": ["typed-array-byte-offset@1.0.4", "", { "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "for-each": "^0.3.3", "gopd": "^1.2.0", "has-proto": "^1.2.0", "is-typed-array": "^1.1.15", "reflect.getprototypeof": "^1.0.9" } }, "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ=="], - - "typed-array-length": ["typed-array-length@1.0.7", "", { "dependencies": { "call-bind": "^1.0.7", "for-each": "^0.3.3", "gopd": "^1.0.1", "is-typed-array": "^1.1.13", "possible-typed-array-names": "^1.0.0", "reflect.getprototypeof": "^1.0.6" } }, "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg=="], - - "typescript": ["typescript@5.9.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A=="], - - "typescript-eslint": ["typescript-eslint@8.42.0", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.42.0", "@typescript-eslint/parser": "8.42.0", "@typescript-eslint/typescript-estree": "8.42.0", "@typescript-eslint/utils": "8.42.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-ozR/rQn+aQXQxh1YgbCzQWDFrsi9mcg+1PM3l/z5o1+20P7suOIaNg515bpr/OYt6FObz/NHcBstydDLHWeEKg=="], - - "typescript-plugin-styled-components": ["typescript-plugin-styled-components@3.0.0", "", { "peerDependencies": { "typescript": "~4.8 || 5" } }, "sha512-QWlhTl6NqsFxtJyxn7pJjm3RhgzXSByUftZ3AoQClrMMpa4yAaHuJKTN1gFpH3Ti+Rwm56fNUfG9pXSBU+WW3A=="], - - "unbox-primitive": ["unbox-primitive@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "has-bigints": "^1.0.2", "has-symbols": "^1.1.0", "which-boxed-primitive": "^1.1.1" } }, "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw=="], - - "undici-types": ["undici-types@7.10.0", "", {}, "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag=="], - - "update-browserslist-db": ["update-browserslist-db@1.1.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw=="], - - "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], - - "use-sync-external-store": ["use-sync-external-store@1.5.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A=="], - - "vite": ["vite@7.1.4", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.14" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-X5QFK4SGynAeeIt+A7ZWnApdUyHYm+pzv/8/A57LqSGcI88U6R6ipOs3uCesdc6yl7nl+zNO0t8LmqAdXcQihw=="], - - "vite-plugin-babel": ["vite-plugin-babel@1.3.2", "", { "peerDependencies": { "@babel/core": "^7.0.0", "vite": "^2.7.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-mEld4OVyuNs5+ISN+U5XyTnNcDwln/s2oER2m0PQ32YYPqPR25E3mfnhAA/RkZJxPuwFkprKWV405aZArE6kzA=="], - - "vite-plugin-commonjs": ["vite-plugin-commonjs@0.10.4", "", { "dependencies": { "acorn": "^8.12.1", "magic-string": "^0.30.11", "vite-plugin-dynamic-import": "^1.6.0" } }, "sha512-eWQuvQKCcx0QYB5e5xfxBNjQKyrjEWZIR9UOkOV6JAgxVhtbZvCOF+FNC2ZijBJ3U3Px04ZMMyyMyFBVWIJ5+g=="], - - "vite-plugin-dynamic-import": ["vite-plugin-dynamic-import@1.6.0", "", { "dependencies": { "acorn": "^8.12.1", "es-module-lexer": "^1.5.4", "fast-glob": "^3.3.2", "magic-string": "^0.30.11" } }, "sha512-TM0sz70wfzTIo9YCxVFwS8OA9lNREsh+0vMHGSkWDTZ7bgd1Yjs5RV8EgB634l/91IsXJReg0xtmuQqP0mf+rg=="], - - "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], - - "which-boxed-primitive": ["which-boxed-primitive@1.1.1", "", { "dependencies": { "is-bigint": "^1.1.0", "is-boolean-object": "^1.2.1", "is-number-object": "^1.1.1", "is-string": "^1.1.1", "is-symbol": "^1.1.1" } }, "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA=="], - - "which-builtin-type": ["which-builtin-type@1.2.1", "", { "dependencies": { "call-bound": "^1.0.2", "function.prototype.name": "^1.1.6", "has-tostringtag": "^1.0.2", "is-async-function": "^2.0.0", "is-date-object": "^1.1.0", "is-finalizationregistry": "^1.1.0", "is-generator-function": "^1.0.10", "is-regex": "^1.2.1", "is-weakref": "^1.0.2", "isarray": "^2.0.5", "which-boxed-primitive": "^1.1.0", "which-collection": "^1.0.2", "which-typed-array": "^1.1.16" } }, "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q=="], - - "which-collection": ["which-collection@1.0.2", "", { "dependencies": { "is-map": "^2.0.3", "is-set": "^2.0.3", "is-weakmap": "^2.0.2", "is-weakset": "^2.0.3" } }, "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw=="], - - "which-typed-array": ["which-typed-array@1.1.19", "", { "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.4", "for-each": "^0.3.5", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2" } }, "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw=="], - - "word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="], - - "yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], - - "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], - - "@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], - - "@eslint/eslintrc/globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="], - - "@humanfs/node/@humanwhocodes/retry": ["@humanwhocodes/retry@0.3.1", "", {}, "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA=="], - - "@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], - - "@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], - - "@typescript-eslint/typescript-estree/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], - - "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], - - "fdir/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], - - "styled-components/postcss": ["postcss@8.4.49", "", { "dependencies": { "nanoid": "^3.3.7", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA=="], - - "tinyglobby/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], - - "vite/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], - - "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], - } -} diff --git a/package.json b/package.json index f2b6cd6..d19db9c 100644 --- a/package.json +++ b/package.json @@ -23,10 +23,15 @@ "react-dom": "19.1.1", "react-redux": "9.2.0", "react-router-dom": "7.8.2", - "styled-components": "6.1.19" + "styled-components": "6.1.19", + "uuid": "11.1.0" }, "devDependencies": { "@eslint/js": "9.34.0", + "@fortawesome/fontawesome-svg-core": "7.0.1", + "@fortawesome/free-regular-svg-icons": "7.0.1", + "@fortawesome/free-solid-svg-icons": "7.0.1", + "@fortawesome/react-fontawesome": "3.0.2", "@types/node": "24.3.0", "@types/react": "19.1.12", "@types/react-dom": "19.1.9", @@ -39,6 +44,8 @@ "eslint-plugin-react-refresh": "0.4.20", "globals": "16.3.0", "prettier": "3.6.2", + "react-datepicker": "8.7.0", + "react-toastify": "11.0.5", "typescript": "5.9.2", "typescript-eslint": "8.42.0", "typescript-plugin-styled-components": "3.0.0", diff --git a/src/App.tsx b/src/App.tsx index be7bb75..128abd0 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,11 +1,19 @@ -import {JSX} from 'react'; +import React from 'react'; +import styled from 'styled-components'; import Router from './routers'; +import Theme from './theme'; -const App = (): JSX.Element => { +const AppContainer = styled.div` + min-height: 100vh; + background: ${Theme.backgrounds.defaultBackground}; + background-attachment: fixed; +`; + +const App = (): React.JSX.Element => { return ( - <> + - + ); }; diff --git a/src/components/ProtectedRoute.tsx b/src/components/ProtectedRoute.tsx index 7a8bf53..c358c0c 100644 --- a/src/components/ProtectedRoute.tsx +++ b/src/components/ProtectedRoute.tsx @@ -1,9 +1,9 @@ -import {JSX} from 'react'; +import React from 'react'; import {Navigate, useLocation} from 'react-router-dom'; import {useAppSelector} from 'store'; import {selectIsAuthenticated} from 'store/slices/Authentication.slice'; -export function ProtectedRoute({component}: {component: JSX.Element}): JSX.Element { +export function ProtectedRoute({component}: {component: React.JSX.Element}): React.JSX.Element { const isAuthenticated = useAppSelector(selectIsAuthenticated); const location = useLocation(); diff --git a/src/components/buttons/copy-icon-button/index.tsx b/src/components/buttons/copy-icon-button/index.tsx index 0344ff1..e36f983 100644 --- a/src/components/buttons/copy-icon-button/index.tsx +++ b/src/components/buttons/copy-icon-button/index.tsx @@ -1,7 +1,7 @@ /** * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. */ -import {useState} from 'react'; +import React, {useState} from 'react'; import {faCopy, faCheck} from '@fortawesome/free-solid-svg-icons'; import IconButton from 'components/buttons/icon-button'; @@ -9,7 +9,7 @@ import {CopyButtonContainer} from './styles'; const iconChangeTimeout = 2000; -export const CopyIconButton = (props: {text: string; quoted?: boolean; displayText?: boolean; className?: string}): JSX.Element => { +export const CopyIconButton = (props: {text: string; quoted?: boolean; displayText?: boolean; className?: string}): React.JSX.Element => { const {text, quoted = false, displayText = true, className} = props; const [copied, setCopied] = useState(false); const copyToClipboard = (): void => { @@ -22,11 +22,7 @@ export const CopyIconButton = (props: {text: string; quoted?: boolean; displayTe return ( {displayText && (quoted ? `"${text}"` : text)} - + ); -}; \ No newline at end of file +}; diff --git a/src/components/buttons/copy-icon-button/styles.ts b/src/components/buttons/copy-icon-button/styles.ts index 54e30cc..1f9cf58 100644 --- a/src/components/buttons/copy-icon-button/styles.ts +++ b/src/components/buttons/copy-icon-button/styles.ts @@ -6,4 +6,4 @@ import * as styled from 'styled-components'; export const CopyButtonContainer = styled.default.div` display: flex; align-items: center; -`; \ No newline at end of file +`; diff --git a/src/components/buttons/export-file-button/index.tsx b/src/components/buttons/export-file-button/index.tsx index 0ba7baa..3e8958e 100644 --- a/src/components/buttons/export-file-button/index.tsx +++ b/src/components/buttons/export-file-button/index.tsx @@ -1,6 +1,7 @@ /** * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. */ +import React from 'react'; import {theme} from 'components/shared/theme'; import {Button} from 'components/buttons'; @@ -12,7 +13,7 @@ interface IExportFileButton { fileName?: string; } -export const ExportFileButton = ({label = 'Export File', file, fileName = 'file'}: IExportFileButton): JSX.Element => { +export const ExportFileButton = ({label = 'Export File', file, fileName = 'file'}: IExportFileButton): React.JSX.Element => { const handleExport = () => { const downloadUrl = URL.createObjectURL(new Blob([file])); const linkTag = document.createElement('a'); @@ -24,13 +25,8 @@ export const ExportFileButton = ({label = 'Export File', file, fileName = 'file' }; return ( - ); -}; \ No newline at end of file +}; diff --git a/src/components/buttons/icon-button/icon-button.tsx b/src/components/buttons/icon-button/icon-button.tsx index 24e9721..c2d571f 100644 --- a/src/components/buttons/icon-button/icon-button.tsx +++ b/src/components/buttons/icon-button/icon-button.tsx @@ -16,17 +16,12 @@ interface IIconButton { className?: string; } -const IconButton = ({ - onClick, - tooltipText, - icon, - className -}: IIconButton) => ( +const IconButton = ({onClick, tooltipText, icon, className}: IIconButton) => ( - + ); -export default IconButton; \ No newline at end of file +export default IconButton; diff --git a/src/components/buttons/icon-button/index.tsx b/src/components/buttons/icon-button/index.tsx index 35c6141..f2a52ec 100644 --- a/src/components/buttons/icon-button/index.tsx +++ b/src/components/buttons/icon-button/index.tsx @@ -2,4 +2,4 @@ * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. */ -export {default} from './icon-button'; \ No newline at end of file +export {default} from './icon-button'; diff --git a/src/components/buttons/icon-button/styles.ts b/src/components/buttons/icon-button/styles.ts index 43fb911..2b555ac 100644 --- a/src/components/buttons/icon-button/styles.ts +++ b/src/components/buttons/icon-button/styles.ts @@ -27,4 +27,4 @@ export const IconButtonContainer = styled.default.div` &:hover { background-color: rgba(255, 255, 255, 0.1); } -`; \ No newline at end of file +`; diff --git a/src/components/buttons/icon-buttons/add-button.tsx b/src/components/buttons/icon-buttons/add-button.tsx index f0c0c07..833e95a 100644 --- a/src/components/buttons/icon-buttons/add-button.tsx +++ b/src/components/buttons/icon-buttons/add-button.tsx @@ -1,6 +1,7 @@ /** * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. */ +import React from 'react'; import {IconButton} from './style'; import addIcon from 'assets/images/icon/hash-plus.svg'; @@ -9,8 +10,8 @@ interface IAddButton { className: string; } -export const AddButton = ({onClick, className}: IAddButton): JSX.Element => ( +export const AddButton = ({onClick, className}: IAddButton): React.JSX.Element => ( {'Add'} -); \ No newline at end of file +); diff --git a/src/components/buttons/icon-buttons/index.ts b/src/components/buttons/icon-buttons/index.ts index 10f145b..e5dccfd 100644 --- a/src/components/buttons/icon-buttons/index.ts +++ b/src/components/buttons/icon-buttons/index.ts @@ -2,4 +2,4 @@ * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. */ export * from './refresh-button'; -export * from './add-button'; \ No newline at end of file +export * from './add-button'; diff --git a/src/components/buttons/icon-buttons/refresh-button.tsx b/src/components/buttons/icon-buttons/refresh-button.tsx index d682c83..b2700db 100644 --- a/src/components/buttons/icon-buttons/refresh-button.tsx +++ b/src/components/buttons/icon-buttons/refresh-button.tsx @@ -1,6 +1,7 @@ /** * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. */ +import React from 'react'; import {IconButton} from './style'; import refreshIcon from 'assets/images/icon/refresh.svg'; @@ -10,8 +11,8 @@ interface IRefreshButton { disabled?: boolean; } -export const RefreshButton = ({onClick, disabled = false}: IRefreshButton): JSX.Element => ( +export const RefreshButton = ({onClick, disabled = false}: IRefreshButton): React.JSX.Element => ( {'Refresh'} -); \ No newline at end of file +); diff --git a/src/components/buttons/icon-buttons/style.ts b/src/components/buttons/icon-buttons/style.ts index a36945d..cc04f6d 100644 --- a/src/components/buttons/icon-buttons/style.ts +++ b/src/components/buttons/icon-buttons/style.ts @@ -4,14 +4,14 @@ import * as styled from 'styled-components'; import {theme} from 'components/shared/theme'; -const {fontSizeL, colors} = theme; +const {typography: {fontSizeL}, colors} = theme; export const IconButton = styled.default.button` border: none; background-color: transparent; font-size: ${fontSizeL}; color: ${colors.white}; - opacity: ${({disabled}) => disabled ? 0.3 : 1}; - cursor: ${({disabled}) => disabled ? 'not-allowed' : 'pointer'}; + opacity: ${({disabled}) => (disabled ? 0.3 : 1)}; + cursor: ${({disabled}) => (disabled ? 'not-allowed' : 'pointer')}; display: flex; -`; \ No newline at end of file +`; diff --git a/src/components/buttons/index.tsx b/src/components/buttons/index.tsx index bc980a6..f39fa68 100644 --- a/src/components/buttons/index.tsx +++ b/src/components/buttons/index.tsx @@ -2,7 +2,7 @@ * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. */ import * as styled from 'styled-components'; -import Theme from 'theme'; +import Theme from 'theme'; export const Button = styled.default.button<{ backgroundColor?: string; @@ -54,4 +54,4 @@ export const CustomButton = styled.default(Button)` margin: 0.75rem; padding: ${Theme.spacing.small} ${Theme.spacing.xlarge}; overflow: visible; -`; \ No newline at end of file +`; diff --git a/src/components/buttons/radio-button/index.tsx b/src/components/buttons/radio-button/index.tsx index c7f0a60..8a7b04b 100644 --- a/src/components/buttons/radio-button/index.tsx +++ b/src/components/buttons/radio-button/index.tsx @@ -1,15 +1,10 @@ /** * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. */ -import {Fragment} from 'react'; +import React, {Fragment} from 'react'; import {Tooltip, Position} from 'components/tooltip'; import {Label} from 'components/label'; -import { - RadioGroup, - RadioWrapper, - RadioButtonContainer, - VisibleCheckBox -} from './style'; +import {RadioGroup, RadioWrapper, RadioButtonContainer, VisibleCheckBox} from './style'; interface IRadioItems { label: string; @@ -17,13 +12,13 @@ interface IRadioItems { tooltipMessage?: string; tooltipPosition?: Position; className?: string; - children?: JSX.Element; + children?: React.JSX.Element; disabled?: boolean; } interface IRadioButtonGroup { items: IRadioItems[]; - handleOnChange: (value) => void; + handleOnChange: (value: string) => void; currentValue: string; } @@ -32,30 +27,22 @@ const RadioButton = (props: {currentValue: string; value: string}) => { return ( - -
+ + +
+ ); }; -const RadioButtonGroup = (props: IRadioButtonGroup): JSX.Element => { +const RadioButtonGroup = (props: IRadioButtonGroup): React.JSX.Element => { const {items, handleOnChange, currentValue} = props; return ( - {items.map(( - { - label, - value, - disabled, - tooltipPosition, - tooltipMessage, - children, - className - }: IRadioItems, - index: number - ) => ( - ( + null} disabled={disabled} className="button-container" @@ -65,18 +52,12 @@ const RadioButtonGroup = (props: IRadioButtonGroup): JSX.Element => { {tooltipMessage ? ( - - @@ -85,4 +66,4 @@ const RadioButtonGroup = (props: IRadioButtonGroup): JSX.Element => { ); }; -export default RadioButtonGroup; \ No newline at end of file +export default RadioButtonGroup; diff --git a/src/components/buttons/radio-button/style.ts b/src/components/buttons/radio-button/style.ts index 5d93437..c05a463 100644 --- a/src/components/buttons/radio-button/style.ts +++ b/src/components/buttons/radio-button/style.ts @@ -2,13 +2,10 @@ * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. */ import * as styled from 'styled-components'; -import {theme, paddings} from 'components/shared/theme'; +import {theme, Theme} from 'components/shared/theme'; -const { - spacing, - primaryFontSize, - colors -} = theme; +const {spacing, typography: {primaryFontSize}, colors} = theme; +const paddings = Theme.paddings; export const RadioGroup = styled.default.div` display: flex; @@ -18,10 +15,12 @@ export const RadioWrapper = styled.default.div<{disabled?: boolean}>` padding: ${paddings.small}; display: flex; - ${({disabled}) => disabled && styled.css` - pointer-events: none; - opacity: .5; - `} + ${({disabled}) => + disabled && + styled.css` + pointer-events: none; + opacity: 0.5; + `} `; export const RadioButtonContainer = styled.default.div` @@ -43,15 +42,17 @@ export const VisibleCheckBox = styled.default.div<{checked?: boolean}>` height: ${primaryFontSize}; border-radius: 50%; - ${({checked}) => checked && styled.css` - border: none; - background-color: ${colors.red}; + ${({checked}) => + checked && + styled.css` + border: none; + background-color: ${colors.red}; - div { - background-color: ${colors.black}; - width: 5px; - height: 5px; - border-radius: 50%; - } - `} -`; \ No newline at end of file + div { + background-color: ${colors.black}; + width: 5px; + height: 5px; + border-radius: 50%; + } + `} +`; diff --git a/src/components/buttons/scroll-buttons/index.tsx b/src/components/buttons/scroll-buttons/index.tsx index ee70658..e64083d 100644 --- a/src/components/buttons/scroll-buttons/index.tsx +++ b/src/components/buttons/scroll-buttons/index.tsx @@ -1,15 +1,11 @@ /** * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. */ +import React from 'react'; import * as styled from 'styled-components'; import {theme} from 'components/shared/theme'; import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; -import { - faBackward, - faFastBackward, - faFastForward, - faForward -} from '@fortawesome/free-solid-svg-icons'; +import {faBackward, faFastBackward, faFastForward, faForward} from '@fortawesome/free-solid-svg-icons'; const {colors, spacing} = theme; const ScrollButton = styled.default.button` @@ -30,8 +26,8 @@ const TwinButtons = styled.default.div` flex-direction: column; `; -export const ScrollButtons = ({current}: {current: HTMLDivElement}): JSX.Element => { - const getScrollStep = current => { +export const ScrollButtons = ({current}: {current: HTMLDivElement}): React.JSX.Element => { + const getScrollStep = (current: HTMLDivElement) => { const tableViewHeight = current.offsetHeight; return tableViewHeight / 2; @@ -77,4 +73,4 @@ export const ScrollButtons = ({current}: {current: HTMLDivElement}): JSX.Element ); -}; \ No newline at end of file +}; diff --git a/src/components/channel-icon-menu/delete-channel/delete-channel-form.tsx b/src/components/channel-icon-menu/delete-channel/delete-channel-form.tsx new file mode 100644 index 0000000..8bdfd78 --- /dev/null +++ b/src/components/channel-icon-menu/delete-channel/delete-channel-form.tsx @@ -0,0 +1,67 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import React, {useState, useEffect, ChangeEvent, useCallback} from 'react'; +import {faQuestionCircle} from '@fortawesome/free-solid-svg-icons'; +import {documentationLinks} from 'constants/links'; + +import {NewTabLink} from 'components/new-tab-link'; +import Input from 'components/forms/Input'; +import {CopyIconButton} from 'components/buttons/copy-icon-button'; +import {DialogForm, Error} from 'components/modal/modal-form-response/style'; + +const DeleteChannelForm = ({setIsValid, alias}: {setIsValid: (isValid: boolean) => void; alias: string}): React.JSX.Element => { + const [error, setError] = useState(null); + const [enteredAlias, setEnteredAlias] = useState(''); + + const validate = useCallback((): boolean => { + if (!enteredAlias) { + setError('Please enter a channel alias'); + setIsValid(false); + + return false; + } + + if (enteredAlias !== alias) { + setError('Entered alias does not match the channels alias'); + setIsValid(false); + + return false; + } + + setError(null); + setIsValid(true); + + return true; + }, [enteredAlias, alias, setIsValid]); + + useEffect(() => { + if (enteredAlias.length) { + validate(); + } + }, [enteredAlias, validate]); + + const handleEnteredAlias = (event: ChangeEvent): void => { + if (error) { + setError(null); + } + + setEnteredAlias(event.target.value); + }; + + return ( + +

+ Delete Channel +

+

To delete channel, please enter the channel alias:

+ + + + + {error && {error}} +
+ ); +}; + +export default DeleteChannelForm; diff --git a/src/components/channel-icon-menu/delete-channel/delete-channel-modal.tsx b/src/components/channel-icon-menu/delete-channel/delete-channel-modal.tsx new file mode 100644 index 0000000..22de2ec --- /dev/null +++ b/src/components/channel-icon-menu/delete-channel/delete-channel-modal.tsx @@ -0,0 +1,111 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import React, {useState} from 'react'; +import {useDispatch} from 'react-redux'; + +import LoggerFactory from 'services/logger/LoggerFactory'; +import {deleteChannel} from 'services/channel.service'; +import {listChannels} from 'store/action/channels'; + +import {transformToPortalError} from 'utility/error-handler'; +import {deleteChannelErrorMessages} from 'constants/error-messages'; + +import {MultiStepModal} from 'components/modal/multi-step-modal'; + +import DeleteChannelForm from './delete-channel-form'; +import {FormResponse} from 'components/modal/modal-form-response'; + +interface IDeleteChannelModal { + isOpen: boolean; + setIsOpen: React.Dispatch>; + channelId: string; + alias: string; + redirect?: () => void; +} + +export const DeleteChannelModal = ({isOpen, setIsOpen, channelId, alias, redirect}: IDeleteChannelModal): React.JSX.Element => { + const logger = LoggerFactory.getLogger('components/channel-icon-menu/delete-channel/DeleteChannelModal'); + const dispatch = useDispatch(); + const [isFormValid, setIsFormValid] = useState(false); + const [isFetching, setIsFetching] = useState(false); + const [deleteChannelResponse, setDeleteChannelResponse] = useState<{error: string | boolean | Error; status: string | number; data?: any} | null>(null); + const handleSubmit = async () => { + if (!isFormValid) { + return; + } + + try { + setIsFetching(true); + + logger.info('Deleting a channel [%s][%s]', alias, channelId); + + const response = await deleteChannel({channelId, alias}); + + logger.info('Channel [%s][%s] was successfully deleted', alias, channelId); + + setDeleteChannelResponse({status: 'ok', error: false, data: response}); + setIsFetching(false); + } catch (e) { + const {status, message, requestPayload, statusCode} = transformToPortalError(e); + + setIsFetching(false); + + const errorMessage = (deleteChannelErrorMessages as Record)[status] || message || deleteChannelErrorMessages['default']; + setDeleteChannelResponse({ + status: statusCode || 'error', + error: errorMessage + }); + + logger.error(`${errorMessage} [%s]`, status, requestPayload); + } + }; + + const handleCloseModal = (): void => { + setIsOpen(false); + }; + + const onDeleteSuccess = async (): Promise => { + setIsOpen(false); + + logger.info('Updating the list of channels after the [%s][%s] channel was deleted', alias, channelId); + + await dispatch(listChannels() as any); + + logger.info('The list of channels was updated successfully'); + + if (redirect) { + redirect(); + } + }; + + return ( + , + saveButton: { + text: 'Delete Channel', + className: 'testId-deleteChannel', + disabled: !isFormValid || isFetching, + onClick: handleSubmit + } + }, + { + title: 'Delete Channel', + component: , + cancelDisabled: true, + saveButton: { + className: 'testId-doneButton', + onClick: onDeleteSuccess + } + } + ]} + /> + ); +}; + +export default DeleteChannelModal; diff --git a/src/components/channel-icon-menu/delete-channel/index.tsx b/src/components/channel-icon-menu/delete-channel/index.tsx new file mode 100644 index 0000000..8f009b6 --- /dev/null +++ b/src/components/channel-icon-menu/delete-channel/index.tsx @@ -0,0 +1,4 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +export {default} from './delete-channel-modal'; diff --git a/src/components/channel-icon-menu/fork-channel/fork-channel-form.tsx b/src/components/channel-icon-menu/fork-channel/fork-channel-form.tsx new file mode 100644 index 0000000..b372fc5 --- /dev/null +++ b/src/components/channel-icon-menu/fork-channel/fork-channel-form.tsx @@ -0,0 +1,107 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import React, {useState, useEffect, useCallback} from 'react'; +import {faQuestionCircle} from '@fortawesome/free-solid-svg-icons'; +import {CapabilitiesType} from 'constants/capabilities'; +import {documentationLinks} from 'constants/links'; +import {Label} from 'components/forms/label'; +import Checkbox from 'components/forms/Checkbox'; +import {NewTabLink} from 'components/new-tab-link'; +import {Dropdown} from 'components/drop-down'; +import {InputWithTags} from 'components/ui/input-with-tags'; +import {DialogForm, Error, Options} from 'components/modal/modal-form-response/style'; +import {Capabilities} from 'components/create-token-components'; +import Theme from 'theme'; + +const forkChannelOption = ['force', 'additive']; +const ForkChannelForm = ({setFormData, setIsValid, channelList, alias}: {setFormData: (data: any) => void; setIsValid: (isValid: boolean) => void; channelList: any[]; alias: string}): React.JSX.Element => { + const [error, setError] = useState(null); + const [tags, setTags] = useState([]); + const [forkOptions, setForkOptions] = useState([]); + const [destinationChannelId, setDestinationChannelId] = useState(''); + const [selectedCapabilities, setSelectedCapabilities] = useState([]); + const [force, additive] = forkChannelOption; + const destinationChannelsList = channelList.filter(channel => channel.alias !== alias); + + const validate = useCallback((): boolean => { + if (!destinationChannelId) { + setIsValid(false); + + return false; + } + + setError(null); + setIsValid(true); + setFormData({ + streamCapabilities: selectedCapabilities.map(({value}) => value), + streamTags: tags, + options: forkOptions, + destinationChannelId + }); + + return true; + }, [destinationChannelId, selectedCapabilities, tags, forkOptions, setIsValid, setFormData]); + + useEffect(() => { + validate(); + }, [validate]); + + const handleForkOptions = (value: string) => { + if (forkOptions.indexOf(value) > -1) { + const currentForkOptions = forkOptions.filter(item => item !== value); + + setForkOptions(currentForkOptions); + } else { + setForkOptions([...forkOptions, value]); + } + }; + + const handleSetDestinationChannelId = (channelAlias: string): void => { + const channels = channelList.filter(channel => channel.alias === channelAlias); + + if (channels[0]) { + const {channelId} = channels[0]; + + setDestinationChannelId(channelId); + setError(null); + } + }; + + return ( + +

+ Fork Channel +

+

+ Fork "{alias}" to destination channel: +

+ + {error && Please select a Channel from the list} + +
+ ); +}; + +export default ForkChannelForm; diff --git a/src/components/channel-icon-menu/fork-channel/fork-channel-modal.tsx b/src/components/channel-icon-menu/fork-channel/fork-channel-modal.tsx new file mode 100644 index 0000000..3ef929e --- /dev/null +++ b/src/components/channel-icon-menu/fork-channel/fork-channel-modal.tsx @@ -0,0 +1,113 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import React, {useState} from 'react'; +import {useSelector} from 'react-redux'; + +import LoggerFactory from 'services/logger/LoggerFactory'; +import {forkChannel} from 'services/channel.service'; +import {AppStore} from 'store'; +import {channelsSelector} from 'store/action/channels'; + +import {transformToPortalError} from 'utility/error-handler'; +import {forkChannelErrorMessages} from 'constants/error-messages'; + +import {MultiStepModal} from 'components/modal/multi-step-modal'; + +import ForkChannelForm from './fork-channel-form'; +import {FormResponse} from 'components/modal/modal-form-response'; + +interface IForkChannelModal { + isOpen: boolean; + setIsOpen: React.Dispatch>; + channelId: string; + alias: string; +} + +export const ForkChannelModal = ({isOpen, setIsOpen, channelId, alias}: IForkChannelModal): React.JSX.Element => { + const logger = LoggerFactory.getLogger('components/channel-icon-menu/fork-channel/ForkChannelModal'); + const channelsState = useSelector((state: AppStore) => channelsSelector(state)); + const channelList = channelsState.channels || []; + const [formData, setFormData] = useState({ + streamCapabilities: [] as string[], + streamTags: [] as string[], + options: [] as string[], + destinationChannelId: '' + }); + const [isFormValid, setIsFormValid] = useState(false); + const [isFetching, setIsFetching] = useState(false); + const [forkResponse, setForkResponse] = useState<{error: string | boolean | Error; status: string | number; data?: any} | null>(null); + const handleSubmit = async () => { + if (!isFormValid) { + return; + } + + try { + setIsFetching(true); + + const {streamCapabilities, streamTags, options, destinationChannelId} = formData; + + logger.info('Forking a channel [%s] to [%s]', channelId, destinationChannelId); + + const response = await forkChannel({ + sourceChannelId: channelId, + destinationChannelId, + streamCapabilities, + streamTags, + options + }); + + logger.info('The channel [%s] was successfully forked to [%s]', channelId, destinationChannelId); + + setForkResponse({ + status: 'ok', + error: false, + data: response + }); + setIsFetching(false); + } catch (e) { + const {status, message, requestPayload, statusCode} = transformToPortalError(e); + + setIsFetching(false); + + const errorMessage = (forkChannelErrorMessages as Record)[status] || message || forkChannelErrorMessages['default']; + setForkResponse({ + status: statusCode || 'error', + error: errorMessage + }); + + logger.error(`${errorMessage} [%s]`, status, requestPayload); + } + }; + + const handleCloseModal = (): void => { + setIsOpen(false); + }; + + return ( + , + saveButton: { + text: 'Fork Channel', + className: 'testId-forkChannel', + disabled: !isFormValid || isFetching, + onClick: handleSubmit + } + }, + { + title: 'Fork Channel', + component: , + cancelDisabled: true, + saveButton: {className: 'testId-doneButton'} + } + ]} + /> + ); +}; + +export default ForkChannelModal; diff --git a/src/components/channel-icon-menu/fork-channel/index.tsx b/src/components/channel-icon-menu/fork-channel/index.tsx new file mode 100644 index 0000000..260e58f --- /dev/null +++ b/src/components/channel-icon-menu/fork-channel/index.tsx @@ -0,0 +1,4 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +export {default} from './fork-channel-modal'; diff --git a/src/components/channel-icon-menu/index.tsx b/src/components/channel-icon-menu/index.tsx new file mode 100644 index 0000000..7c8fe07 --- /dev/null +++ b/src/components/channel-icon-menu/index.tsx @@ -0,0 +1,65 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import React, {useState} from 'react'; +import {IconDefinition} from '@fortawesome/free-solid-svg-icons'; + +import {IconMenu} from 'components/icon-menu'; +import {IconMenuPosition} from 'components/icon-menu/types'; + +import ForkChannelModal from './fork-channel'; +import DeleteChannelModal from './delete-channel'; +import KillChannelModal from './kill-channel'; + +interface IChannelIconMenu { + data: { + name: string; + channelId: string; + applicationId: string; + alias: string; + }; + redirect?: () => void; + showTail?: boolean; + position?: IconMenuPosition; + icon?: IconDefinition; + margin?: number; +} + +export const ChannelIconMenu = (props: IChannelIconMenu): React.JSX.Element => { + const {data, icon, redirect, showTail, position, margin} = props; + const {alias, channelId} = data; + const [isForkModalOpen, setIsForkModalOpen] = useState(false); + const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); + const [isKillModalOpen, setIsKillModalOpen] = useState(false); + const items = [ + { + value: 'delete', + title: 'Delete', + className: 'testId-deleteMenuItem', + onClick: () => setIsDeleteModalOpen(true) + }, + { + value: 'kill', + title: 'Kill', + className: 'testId-killMenuItem', + onClick: () => setIsKillModalOpen(true) + }, + { + value: 'fork', + title: 'Fork', + className: 'testId-forkMenuItem', + onClick: () => setIsForkModalOpen(true) + } + ]; + + return ( + <> + + {isForkModalOpen && } + {isDeleteModalOpen && ( + + )} + {isKillModalOpen && } + + ); +}; diff --git a/src/components/channel-icon-menu/kill-channel/index.tsx b/src/components/channel-icon-menu/kill-channel/index.tsx new file mode 100644 index 0000000..268ac49 --- /dev/null +++ b/src/components/channel-icon-menu/kill-channel/index.tsx @@ -0,0 +1,4 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +export {default} from './kill-channel-modal'; diff --git a/src/components/channel-icon-menu/kill-channel/kill-channel-form.tsx b/src/components/channel-icon-menu/kill-channel/kill-channel-form.tsx new file mode 100644 index 0000000..d88382a --- /dev/null +++ b/src/components/channel-icon-menu/kill-channel/kill-channel-form.tsx @@ -0,0 +1,129 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import React, {useState, useEffect, ChangeEvent, useCallback} from 'react'; +import {faQuestionCircle} from '@fortawesome/free-solid-svg-icons'; + +import {documentationLinks} from 'constants/links'; + +import Checkbox from 'components/forms/Checkbox'; +import {Label} from 'components/label'; +import {NewTabLink} from 'components/new-tab-link'; +import {DialogForm, Error, Options} from 'components/modal/modal-form-response/style'; +import {CopyIconButton} from 'components/buttons/copy-icon-button'; +import {Tooltip, Position} from 'components/tooltip'; +import {Input} from 'components/ui'; + +const keepStreams = 'keep-streams'; +const keepStreamsTooltipMessage = 'Keeps the removed streams alive'; +const destroyRequired = 'destroy-required'; +const destroyRequiredTooltipMessage = 'Returns an error if destroying of a stream fails'; +const defaultReason = 'portal:killed'; +const KillChannelForm = ({setFormData, setIsValid, alias}: {setFormData: (data: any) => void; setIsValid: (isValid: boolean) => void; alias: string}): React.JSX.Element => { + const [error, setError] = useState(null); + const [enteredAlias, setEnteredAlias] = useState(''); + const [reason, setReason] = useState(defaultReason); + const [options, setOptions] = useState([]); + + const validate = useCallback((): boolean => { + if (!enteredAlias) { + setError('Please enter a channel alias'); + setIsValid(false); + + return false; + } + + if (enteredAlias !== alias) { + setError('Entered alias does not match the channels alias'); + setIsValid(false); + + return false; + } + + setError(null); + setIsValid(true); + setFormData({ + reason, + options, + enteredAlias + }); + + return true; + }, [enteredAlias, alias, reason, options, setIsValid, setFormData, setError]); + + useEffect(() => { + if (enteredAlias.length) { + validate(); + } + }, [enteredAlias, validate]); + + const handleAlias = (event: ChangeEvent): void => { + if (error) { + setError(null); + } + + setEnteredAlias(event.target.value); + }; + + const handleKillOptions = (value: string) => { + if (options.indexOf(value) > -1) { + const currentOptions = options.filter(item => item !== value); + + setOptions(currentOptions); + } else { + setOptions([...options, value]); + } + }; + + const handleReason = (event: ChangeEvent): void => { + if (error) { + setError(null); + } + + setReason(event.target.value); + }; + + return ( + +

+ Kill Channel +

+

Terminates all streams and removes them from the channel.

+

To kill the channel, please enter the channel alias:

+ + + + + {error && ( + + Please enter the channel alias {alias} + + )} +
Kill options:
+ + + handleKillOptions(keepStreams)} + checked={options.indexOf(keepStreams) > -1} + label={keepStreams} + /> + + + handleKillOptions(destroyRequired)} + checked={options.indexOf(destroyRequired) > -1} + label={destroyRequired} + /> + + +
+ ); +}; + +export default KillChannelForm; diff --git a/src/components/channel-icon-menu/kill-channel/kill-channel-modal.tsx b/src/components/channel-icon-menu/kill-channel/kill-channel-modal.tsx new file mode 100644 index 0000000..82e85b6 --- /dev/null +++ b/src/components/channel-icon-menu/kill-channel/kill-channel-modal.tsx @@ -0,0 +1,106 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import React, {useState} from 'react'; + +import LoggerFactory from 'services/logger/LoggerFactory'; +import {killChannel} from 'services/channel.service'; + +import {transformToPortalError} from 'utility/error-handler'; +import {killChannelErrorMessages} from 'constants/error-messages'; + +import {MultiStepModal} from 'components/modal/multi-step-modal'; + +import KillChannelForm from './kill-channel-form'; +import {FormResponse} from 'components/modal/modal-form-response'; + +interface IKillChannelModal { + isOpen: boolean; + setIsOpen: React.Dispatch>; + channelId: string; + alias: string; +} + +export const KillChannelModal = ({isOpen, setIsOpen, channelId, alias}: IKillChannelModal): React.JSX.Element => { + const logger = LoggerFactory.getLogger('components/channel-icon-menu/kill-channel/KillChannelModal'); + const [formData, setFormData] = useState({ + reason: '', + options: [] as string[], + enteredAlias: '' + }); + const [isFormValid, setIsFormValid] = useState(false); + const [isFetching, setIsFetching] = useState(false); + const [killResponse, setKillResponse] = useState<{error: string | boolean | Error; status: string | number; data?: any} | null>(null); + const handleSubmit = async () => { + if (!isFormValid) { + return; + } + + try { + setIsFetching(true); + + const {reason, options} = formData; + + logger.info('Killing a channel [%s] with reason [%s]', channelId, reason); + + const response = await killChannel({ + channelId, + reason, + options, + enteredAlias: formData.enteredAlias + }); + + logger.info('The channel [%s] was successfully killed', channelId); + + setKillResponse({ + status: 'ok', + error: false, + data: response + }); + setIsFetching(false); + } catch (e) { + const {status, message, requestPayload, statusCode} = transformToPortalError(e); + + setIsFetching(false); + + const errorMessage = (killChannelErrorMessages as Record)[status] || message || killChannelErrorMessages['default']; + setKillResponse({ + status: statusCode || 'error', + error: errorMessage + }); + + logger.error(`${errorMessage} [%s]`, status, requestPayload); + } + }; + + const handleCloseModal = (): void => { + setIsOpen(false); + }; + + return ( + , + saveButton: { + text: 'Kill Channel', + className: 'testId-killChannel', + disabled: !isFormValid || isFetching, + onClick: handleSubmit + } + }, + { + title: 'Kill Channel', + component: , + cancelDisabled: true, + saveButton: {className: 'testId-doneButton'} + } + ]} + /> + ); +}; + +export default KillChannelModal; diff --git a/src/components/create-token-components/capabilities.tsx b/src/components/create-token-components/capabilities.tsx new file mode 100644 index 0000000..ae0de22 --- /dev/null +++ b/src/components/create-token-components/capabilities.tsx @@ -0,0 +1,62 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import {JSX, useEffect, useState} from 'react'; + +import {faQuestionCircle} from '@fortawesome/free-solid-svg-icons'; + +import {documentationLinks} from 'constants/links'; +import {CapabilitiesType, capabilities} from 'constants/capabilities'; + +import {AdvancedSelect, IAdvancedSelectItem} from 'components/ui/advanced-select'; +import {NewTabLink} from 'components/new-tab-link'; +import Theme from 'theme'; + +interface ICapabilities { + selectedItems: IAdvancedSelectItem[]; + setSelectedItems: (items: IAdvancedSelectItem[]) => void; + data?: IAdvancedSelectItem[]; + label?: string; + labelColor?: string; + iconColor?: string; + capabilitiesSetTitle?: string; + className?: string; + allowMultiple?: boolean; +} + +export const Capabilities = ({ + label, + labelColor = Theme.colors.white, + iconColor = Theme.colors.white, + data = capabilities, + selectedItems, + setSelectedItems, + capabilitiesSetTitle = '', + className, + allowMultiple = true +}: ICapabilities): JSX.Element => { + const [capabilitiesSet, setCapabilitiesSet] = useState(data); + + useEffect(() => { + const filteredCapabilities = data.filter(capability => { + return capabilitiesSetTitle ? capability.type.includes(capabilitiesSetTitle) : true; + }); + + setCapabilitiesSet(filteredCapabilities); + }, [capabilitiesSetTitle]); + + return ( + : undefined} + data={capabilitiesSet} + selectedItems={selectedItems} + setSelectedItems={setSelectedItems} + className={className} + /> + ); +}; + +export default Capabilities; \ No newline at end of file diff --git a/src/components/create-token-components/index.ts b/src/components/create-token-components/index.ts new file mode 100644 index 0000000..2f9503d --- /dev/null +++ b/src/components/create-token-components/index.ts @@ -0,0 +1,8 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +export {default as Capabilities} from './capabilities'; +export {default as ValidityTimeComponent} from './validity-time'; +export * from './validity-time'; +export {default as LabelIconTooltip} from './label-icon-tooltip'; +export * from './styles'; \ No newline at end of file diff --git a/src/components/create-token-components/index.tsx b/src/components/create-token-components/index.tsx new file mode 100644 index 0000000..64dee45 --- /dev/null +++ b/src/components/create-token-components/index.tsx @@ -0,0 +1,44 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import React from 'react'; +import {AdvancedSelect, IAdvancedSelectItem} from '../ui/advanced-select'; +import {Label} from '../forms/label'; + +interface CapabilitiesProps { + label: string; + labelColor?: string; + iconColor?: string; + capabilitiesSetTitle: string; + selectedItems: IAdvancedSelectItem[]; + setSelectedItems: (items: IAdvancedSelectItem[]) => void; +} + +export const Capabilities: React.FC = ({ + label, + labelColor, + iconColor, + capabilitiesSetTitle, + selectedItems, + setSelectedItems +}) => { + // Mock capabilities data - in a real app this would come from constants/capabilities + const mockCapabilities: IAdvancedSelectItem[] = [ + { value: 'streaming', text: 'Streaming' }, + { value: 'recording', text: 'Recording' }, + { value: 'analytics', text: 'Analytics' }, + { value: 'transcoding', text: 'Transcoding' } + ]; + + return ( +
+
+ ); +}; \ No newline at end of file diff --git a/src/components/create-token-components/label-icon-tooltip.tsx b/src/components/create-token-components/label-icon-tooltip.tsx new file mode 100644 index 0000000..ee7916c --- /dev/null +++ b/src/components/create-token-components/label-icon-tooltip.tsx @@ -0,0 +1,26 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import React from 'react'; +import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; +import {faQuestionCircle, IconDefinition} from '@fortawesome/free-solid-svg-icons'; + +import {Tooltip, Position} from 'components/tooltip'; + +interface ILabelIconTooltip { + message: string; + icon?: IconDefinition; + position?: Position; +} + +export const LabelIconTooltip = ({message, icon, position}: ILabelIconTooltip): React.JSX.Element => ( + + + +); + +export default LabelIconTooltip; \ No newline at end of file diff --git a/src/components/create-token-components/styles.ts b/src/components/create-token-components/styles.ts new file mode 100644 index 0000000..e382a3e --- /dev/null +++ b/src/components/create-token-components/styles.ts @@ -0,0 +1,60 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import * as styled from 'styled-components'; + +import {theme} from 'components/shared/theme'; +import {RadioGroup} from 'components/buttons/radio-button/style'; +// import Input from 'components/forms/Input'; + +const { + spacing, + colors +} = theme; + +export const CreateTokenContainer = styled.default.div` + margin: 0.5rem 0 0; +`; + +export const FormWell = styled.default.div` + display: flex; + flex-wrap: wrap; + width: 100%; +`; + +export const RadioButtonContainer = styled.default.div` + display: flex; + flex-direction: column; + margin-top: ${spacing.small} 0; + label { + font-size: 14px; + color: ${colors.white}; + } + ${RadioGroup}{ + flex-direction: column; + .reason-input { + display: flex; + flex-grow: 1; + } + } +`; + +export const InputGroup = styled.default.div` + margin: 0 1rem 1rem 0; + input { + width: 200px; + padding-left: ${spacing.small}; + } + > label { + display: block; + } + select { + width: 200px; + } +`; + +export const RowsWrapper = styled.default.div` + width: 100%; + display: flex; + justify-content: space-between; +`; \ No newline at end of file diff --git a/src/components/create-token-components/validity-time.tsx b/src/components/create-token-components/validity-time.tsx new file mode 100644 index 0000000..3a37e79 --- /dev/null +++ b/src/components/create-token-components/validity-time.tsx @@ -0,0 +1,60 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import React, {Fragment} from 'react'; + +import moment from 'moment'; + +import {ISelectItemWithClassOptions} from 'interfaces'; + +import RadioButtonGroup from 'components/buttons/radio-button'; +import {Label} from 'components/label'; + +import {RadioButtonContainer} from '.'; + +export const validityTimeOptions: ISelectItemWithClassOptions = { + hour: { + label: '1 Hour', + value: `${moment.duration(1, 'hour').asSeconds()}` + }, + day: { + label: '1 Day', + value: `${moment.duration(1, 'day').asSeconds()}` + }, + week: { + label: '1 Week', + value: `${moment.duration(1, 'week').asSeconds()}` + }, + month: { + label: '1 Month', + value: `${moment.duration(1, 'month').asSeconds()}` + }, + year: { + label: '1 Year', + value: `${moment.duration(1, 'year').asSeconds()}` + }, + decade: { + label: '10 Years', + value: `${moment.duration(10, 'year').asSeconds()}` + } +}; + +interface IValidityTimeComponent { + onChange: (value: string) => void; + currentValue: string; +} + +export const ValidityTimeComponent = ({currentValue, onChange}: IValidityTimeComponent): React.JSX.Element => ( + + +); + +export default ValidityTimeComponent; \ No newline at end of file diff --git a/src/components/date-render-component/index.tsx b/src/components/date-render-component/index.tsx new file mode 100644 index 0000000..929bedc --- /dev/null +++ b/src/components/date-render-component/index.tsx @@ -0,0 +1,51 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import {JSX, useEffect, useState} from 'react'; +import {useSelector} from 'react-redux'; +import {Moment} from 'moment'; +import {AppStore} from 'store'; +import {getTimezoneAbbreviation, isoTimeFormat} from 'utility/date'; + +export const DateComponent = ({ + date, + className +}: { + date: Moment; + className?: string; +}): JSX.Element => { + const preferredTimeFormat = useSelector((state: AppStore) => state.preferredTimeFormat.timeFormat); + const isUTC = preferredTimeFormat === 'utc'; + const utcDate = date.isValid() ? date.format(`${isoTimeFormat} UTC`) : ''; + const localDate = date.isValid() ? `${date.clone().local().format(isoTimeFormat)} ${getTimezoneAbbreviation(date.toDate())}` : ''; + const defaultDate = isUTC ? utcDate : localDate; + const hoverDate = isUTC ? localDate : utcDate; + const [currentDate, setCurrentDate] = useState(defaultDate); + + useEffect(() => { + setCurrentDate(defaultDate); + }, [date, preferredTimeFormat]); + + const onMouseEnter = () => { + setCurrentDate(hoverDate); + }; + + const onMouseOut = () => { + setCurrentDate(defaultDate); + }; + + const onBlur = () => { + setCurrentDate(defaultDate); + }; + + return ( +

+ {currentDate} +

+ ); +}; \ No newline at end of file diff --git a/src/components/drop-down/index.tsx b/src/components/drop-down/index.tsx new file mode 100644 index 0000000..cedc8f7 --- /dev/null +++ b/src/components/drop-down/index.tsx @@ -0,0 +1,212 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import React, {useState, useEffect, useRef} from 'react'; + +import {IChannel} from 'interfaces'; +import {Label} from 'components/label'; + +import {DropdownContainer, DropdownInput, DropdownMenu, DropdownMenuItem} from './style'; + +const keys = ['ArrowDown', 'ArrowUp', 'Enter', 'Escape']; + +interface IDropdown { + itemKey: string; + searchTerm?: string; + onSelect: (key: string) => void; + items: IChannel[]; + label: string; + name: string; + className?: string; +} +const maxNumOfItemsShown = 30; + +export const Dropdown = (props: IDropdown): React.JSX.Element => { + const {itemKey, searchTerm, onSelect, items, label, name, className} = props; + const [showDropdownMenu, setShowDropdownMenu] = useState(false); + const [input, setInput] = useState(searchTerm || ''); + const [filteredItems, setFilteredItems] = useState(items); + const [selectedIndex, setSelectedIndex] = useState(0); + const allItemsRef = useRef([]); + const parentElementRef = useRef(null); + const scrollSelectedItemInView = (index: number) => { + if (!parentElementRef.current) { + return; + } + + const dropdownMenu = parentElementRef.current; + const menuItems = allItemsRef.current; + + if (!menuItems) { + return; + } + + const menuItem = menuItems[index]; + + if (!menuItem) { + return; + } + + const isOutOfUpperView = menuItem.offsetTop < dropdownMenu.scrollTop; + const isOutOfLowerView = (menuItem.offsetTop + menuItem.clientHeight) > (dropdownMenu.scrollTop + dropdownMenu.clientHeight); + + if (isOutOfUpperView) { + dropdownMenu.scrollTop = menuItem.offsetTop; + } else if (isOutOfLowerView) { + dropdownMenu.scrollTop = (menuItem.offsetTop + menuItem.clientHeight) - dropdownMenu.clientHeight; + } + }; + + const setSelectInput = (value: string) => { + setInput(value); + onSelect(value); + }; + + const handleClickOutside = (event: MouseEvent) => { + if (!parentElementRef.current || parentElementRef.current.contains(event.target as Node)) { + return; + } + + if (!filteredItems.length) { + setSelectInput(''); + } + + setShowDropdownMenu(false); + onSelect(input); + }; + + useEffect(() => { + scrollSelectedItemInView(selectedIndex); + }, [selectedIndex]); + + useEffect(() => { + document.addEventListener('click', handleClickOutside, true); + + return () => { + document.removeEventListener('click', handleClickOutside, true); + }; + }); + + useEffect(() => { + const filteredItems = items.filter(item => { + if ((item as any)[itemKey].toLowerCase().indexOf(input.toLowerCase()) > -1) { + return true; + } + + return false; + }); + + if (filteredItems.length > 0) { + setSelectedIndex(0); + } + + setFilteredItems(filteredItems); + }, [input, items, itemKey]); + + const selectItemInFocusBy = (offset: number) => { + const lastIndex = filteredItems.length - 1; + const nextIndex = selectedIndex + offset; + + if (nextIndex > lastIndex) { + setSelectedIndex(0); + } else if (nextIndex < 0) { + setSelectedIndex(lastIndex); + } else { + setSelectedIndex(nextIndex); + } + }; + + const handleOnKeyDown = (event: React.KeyboardEvent) => { + if (keys.indexOf(event.key) === -1) { + return; + } + + const [arrDown, arrUp, enter, escape] = keys; + const moves = { + [arrDown]: 1, + [arrUp]: -1 + }; + const move = moves[event.key]; + + if (move !== undefined) { + event.preventDefault(); + selectItemInFocusBy(move); + } + + if (event.key === enter) { + if (filteredItems[selectedIndex]) { + setSelectInput((filteredItems[selectedIndex] as any)[itemKey]); + setShowDropdownMenu(false); + } + } + + if (event.key === escape) { + event.preventDefault(); + setShowDropdownMenu(false); + } + }; + + const selectItem = (index: number) => { + setSelectInput((filteredItems[index] as any)[itemKey]); + setSelectedIndex(index); + setShowDropdownMenu(false); + }; + + const generateMenuOptions = () => { + return filteredItems.length + ? filteredItems.slice(0, maxNumOfItemsShown).map((item, index) => { + return ( + { + allItemsRef.current[index] = ref; + }} + selected={selectedIndex === index} + key={`dropdown-menu-item-${index}`} + onClick={() => selectItem(index)} + > + {(item as any)[itemKey]} + + ); + }) + : ( + + No results found + + ); + }; + + const handleInput = (event: React.ChangeEvent) => { + const {target} = event; + setInput(target.value); + + if (!showDropdownMenu) { + setShowDropdownMenu(true); + } + }; + + const toggleDropdownMenu = () => setShowDropdownMenu(!showDropdownMenu); + + return ( + + + ); +}; \ No newline at end of file diff --git a/src/components/drop-down/style.ts b/src/components/drop-down/style.ts new file mode 100644 index 0000000..55c734b --- /dev/null +++ b/src/components/drop-down/style.ts @@ -0,0 +1,59 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import * as styled from 'styled-components'; +import Input from 'components/forms/Input'; +import Theme from 'theme'; + +const {spacing, colors, typography, primaryBorderRadius} = Theme; + +export const DropdownContainer = styled.default.div` + width: 100%; + position: relative; + margin: ${spacing.xSmall} 0; +`; + +export const DropdownInput = styled.default(Input)<{showMenu?: boolean}>` + ${({showMenu}) => showMenu && styled.css` + border-bottom-left-radius: 0px; + border-bottom-right-radius: 0px; + border-bottom-width: 0; + `} +`; + +export const DropdownMenu = styled.default.div` + width: 100%; + overflow-x: hidden; + overflow-y: auto; + top: calc(100% - 4px); + position: absolute; + height: auto; + max-height: 210px; + border: 1px solid ${colors.gray400}; + border-top-width: 0; + z-index: 4; + background-color: ${colors.white}; + border-bottom-left-radius: ${primaryBorderRadius}; + border-bottom-right-radius: ${primaryBorderRadius}; +`; + +export const DropdownMenuItem = styled.default.div<{ + active?: boolean; + disabled?: boolean; + selected?: boolean; +}>` + line-height: ${spacing.large}; + padding: ${spacing.xsmall} ${spacing.medium}; + font-size: ${typography.fontSizeS}; + word-wrap: break-word; + ${({active, selected, disabled}) => styled.css` + background-color: ${active || selected ? colors.gray300 : 'transparent'}; + font-weight: ${selected ? 'bold' : 'normal'}; + color: ${disabled ? colors.gray500 : colors.gray900} + + :hover{ + background-color: ${disabled ? colors.white : colors.gray300}; + cursor: ${disabled ? 'text' : 'pointer'}; + } + `} +`; \ No newline at end of file diff --git a/src/components/error-renderer/index.tsx b/src/components/error-renderer/index.tsx new file mode 100644 index 0000000..0c66c71 --- /dev/null +++ b/src/components/error-renderer/index.tsx @@ -0,0 +1,12 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import {toast} from 'react-toastify'; + +export const toastErrorRenderer = (error: string): void => { + toast.error(String(error), { + autoClose: 10000, + draggable: false, + hideProgressBar: true + }); +}; diff --git a/src/components/error-renderer/style.ts b/src/components/error-renderer/style.ts new file mode 100644 index 0000000..a5cf060 --- /dev/null +++ b/src/components/error-renderer/style.ts @@ -0,0 +1,23 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import * as styled from 'styled-components'; +import Theme from 'theme'; + +const {headerAllowance, dangerColor, typography} = Theme; + +export const Error = styled.default.div` + height: ${window.innerHeight - headerAllowance}px; + width: 100%; + display: grid; + align-content: center; + justify-content: center; + text-align: center; + color: ${dangerColor}; + font-size: ${typography.fontSizeL}; +`; + +export const ErrorSubMessage = styled.default.div` + font-size: ${typography.fontSizeS}; + color: ${dangerColor}; +`; diff --git a/src/components/forms/Checkbox.tsx b/src/components/forms/Checkbox.tsx new file mode 100644 index 0000000..e16e9a9 --- /dev/null +++ b/src/components/forms/Checkbox.tsx @@ -0,0 +1,83 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import React, {ChangeEvent, MouseEvent} from 'react'; +import styled from 'styled-components'; + +import {Label} from 'components/label'; +import {theme} from 'components/shared/theme'; + +const {colors, spacing} = theme; +const Container = styled.div` + display: flex; + flex-direction: row; + align-items: center; + label { + margin-left: ${spacing.xxSmall}; + margin-right: ${spacing.xxSmall}; + } +`; +const CheckboxContainer = styled.div` + display: inline-block; + vertical-align: middle; + outline: none; + height: 1rem; +`; +const Icon = styled.svg` + fill: none; + stroke: ${colors.black}; + stroke-width: 2px; +`; +const HiddenCheckbox = styled.input.attrs({type: 'checkbox'})` + border: 0; + clip: rect(0 0 0 0); + clip-path: inset(50%); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + white-space: nowrap; + width: 1px; +`; +const StyledCheckbox = styled.div<{checked?: boolean}>` + display: inline-block; + width: 1rem; + height: 1rem; + background: ${({checked}) => checked ? colors.red : colors.transparent}; + border-radius: 3px; + transition: all 150ms; + outline: none; + border: 1px solid ${({checked}) => checked ? 'none' : colors.gray400}; + + ${Icon} { + visibility: ${({checked}) => checked ? 'visible' : 'hidden'} + } +`; +const Checkbox = ( + props: { + value: string; + id?: string; + checked?: boolean; + onChange: (event: ChangeEvent | MouseEvent) => void; + label?: string; + } +): React.JSX.Element => { + const {checked, onChange, label, id} = props; + + return ( + + + + + + + + + + {label && + ); +}; + +export default Checkbox; \ No newline at end of file diff --git a/src/components/forms/Checkbox/index.tsx b/src/components/forms/Checkbox/index.tsx new file mode 100644 index 0000000..216f3c7 --- /dev/null +++ b/src/components/forms/Checkbox/index.tsx @@ -0,0 +1,88 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import React, {ChangeEvent} from 'react'; +import styled from 'styled-components'; +import {theme} from 'components/shared/theme'; + +const CheckboxContainer = styled.div` + display: flex; + align-items: center; + margin-bottom: ${theme.spacing.small}; +`; + +const HiddenCheckbox = styled.input.attrs({type: 'checkbox'})` + position: absolute; + opacity: 0; + cursor: pointer; + height: 0; + width: 0; +`; + +const StyledCheckbox = styled.div<{checked: boolean}>` + display: inline-block; + width: 16px; + height: 16px; + background: ${props => (props.checked ? theme.colors.red : theme.colors.white)}; + border: 2px solid ${theme.colors.gray400}; + border-radius: 3px; + transition: all 150ms; + cursor: pointer; + margin-right: ${theme.spacing.small}; + + &::after { + content: ''; + position: relative; + display: ${props => (props.checked ? 'block' : 'none')}; + left: 3px; + top: 0px; + width: 4px; + height: 8px; + border: solid ${theme.colors.white}; + border-width: 0 2px 2px 0; + transform: rotate(45deg); + } +`; + +const Label = styled.label` + cursor: pointer; + color: ${theme.colors.gray900}; + font-size: ${theme.typography.primaryFontSize}; + user-select: none; +`; + +interface CheckboxProps { + id: string; + checked: boolean; + onChange: (event: ChangeEvent) => void; + label?: string; + value?: string; + disabled?: boolean; + className?: string; +} + +const Checkbox: React.FC = ({ + id, + checked, + onChange, + label, + value, + disabled = false, + className +}) => { + return ( + + + + {label && } + + ); +}; + +export default Checkbox; \ No newline at end of file diff --git a/src/components/forms/Input.tsx b/src/components/forms/Input.tsx index 949b07e..d96128e 100644 --- a/src/components/forms/Input.tsx +++ b/src/components/forms/Input.tsx @@ -1,58 +1,48 @@ /** * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. */ -import {ChangeEvent, forwardRef, ForwardedRef, InputHTMLAttributes} from 'react'; +import React, {ChangeEvent, forwardRef, ForwardedRef, InputHTMLAttributes} from 'react'; import * as styled from 'styled-components'; import Theme from 'theme'; -import {Label} from '../label'; +import {Label} from './label'; export interface IInput extends InputHTMLAttributes { onChange?: (event: ChangeEvent) => void; error?: boolean; - icon?: JSX.Element; + icon?: React.JSX.Element; imagePath?: string; imageAltText?: string; label?: string; labelColor?: string; - labelIcon?: JSX.Element; + labelIcon?: React.JSX.Element; labelClassName?: string; helperText?: string; helperTextClassName?: string; width?: number | string; } -const { - colors, - typography, - formFieldWidth, - formFieldMaxWidth, - primaryBorderColor, - primaryBorderRadius, - primaryInputHeight, - inputIconWidth, - spacing -} = Theme; +const {colors, typography, formFieldWidth, formFieldMaxWidth, primaryBorderColor, primaryBorderRadius, primaryInputHeight, inputIconWidth, spacing} = Theme; export const InputElement = styled.default.input` background-color: ${colors.white}; - border: 1px solid ${({error}) => error ? colors.lightRed : primaryBorderColor}; + border: 1px solid ${({error}) => (error ? colors.lightRed : primaryBorderColor)}; border-radius: ${primaryBorderRadius}; display: block; font-size: ${typography.primaryFontSize}; height: ${primaryInputHeight}; line-height: ${typography.primaryLineHeight}; outline: none; - padding: ${spacing.small} ${({icon, imagePath}) => (icon || imagePath) ? spacing.xlarge : spacing.small}; + padding: ${spacing.small} ${({icon, imagePath}) => (icon || imagePath ? spacing.xlarge : spacing.small)}; transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out; background-position: 1rem center; background-repeat: no-repeat; width: inherit; - opacity: ${({disabled}) => disabled ? 0.8 : 1}; + opacity: ${({disabled}) => (disabled ? 0.8 : 1)}; cursor: ${({disabled}) => disabled && 'not-allowed'}; -webkit-text-fill-color: ${({disabled}) => disabled && colors.gray800}; `; const HelperText = styled.default.p` - color: ${({error}) => error ? colors.lightRed : colors.gray600}; + color: ${({error}) => (error ? colors.lightRed : colors.gray600)}; font-weight: 400; font-size: ${typography.fontSizeS}; margin-top: ${spacing.xxSmall}; @@ -79,56 +69,49 @@ const InputWrapper = styled.default.div` export const InputComponentWrapper = styled.default.div` position: relative; - width: ${({width}) => width && isNaN(+width) ? width : ((width || formFieldWidth) + 'px')}; + width: ${({width}) => (width && isNaN(+width) ? width : (width || formFieldWidth) + 'px')}; max-width: ${formFieldMaxWidth}px; display: flex; flex-direction: column; `; -export const InputComponent = forwardRef(( - { - label, - labelColor, - labelIcon, - labelClassName, - icon, - imagePath, - imageAltText = '', - helperText, - helperTextClassName, - error, - width, - disabled, - name, - ...props - }: IInput, ref: ForwardedRef): JSX.Element => { - const InputIcon = icon || (imagePath && {imageAltText}); +export const InputComponent = forwardRef( + ( + { + label, + labelColor, + labelIcon, + labelClassName, + icon, + imagePath, + imageAltText = '', + helperText, + helperTextClassName, + error, + width, + disabled, + name, + ...props + }: IInput, + ref: ForwardedRef + ): React.JSX.Element => { + const InputIcon = icon || (imagePath && {imageAltText}); - return ( - - {!!label && ( - - ); -}); + return ( + + {!!label && + ); + } +); -export default InputComponent; \ No newline at end of file +export default InputComponent; +export const Input = InputComponent; diff --git a/src/components/forms/SearchInput.tsx b/src/components/forms/SearchInput.tsx new file mode 100644 index 0000000..9ccb416 --- /dev/null +++ b/src/components/forms/SearchInput.tsx @@ -0,0 +1,77 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import * as styled from 'styled-components'; +import {JSX, useState, useEffect, ChangeEvent} from 'react'; +import moment from 'moment'; +import {IInput} from './Input'; +import Input from './Input'; +import Theme from 'theme'; +import searchImage from 'assets/images/search-150x150.png'; + +const searchWaitTimeout = moment.duration(1, 'seconds').asMilliseconds(); + +interface ISearchInput extends IInput { + search: (str: string) => void; + defaultValue?: string; + minLengthForSearch?: number; +} + +const SearchInput = styled.default(Input)` + min-width: 100%; + padding-left: ${Theme.spacing.xlarge}; +`; + +export const SearchInputWrapper = styled.default.div` + position: relative; + display: flex; + & div { + width: 100%; + position: relative; + align-self: center; + & img { + width: 1rem; + height: 1rem; + top: 50%; + transform: translateY(-50%); + left: 0.5rem; + position: absolute; + } + } +`; + +export const Search = ({ + search, + defaultValue = '', + minLengthForSearch = 2 +}: ISearchInput): JSX.Element => { + const [currentSearchTerm, setCurrentSearchTerm] = useState(defaultValue); + const onChange = (event: ChangeEvent): void => { + setCurrentSearchTerm(event.target.value); + }; + + useEffect(() => { + let timeout = null; + + if (currentSearchTerm.length >= minLengthForSearch || currentSearchTerm.length === 0) { + timeout = setTimeout(() => search(currentSearchTerm), searchWaitTimeout); + } + + return () => { + if (timeout) { + clearInterval(timeout); + } + }; + }, [currentSearchTerm, minLengthForSearch, search]); + + return ( + +
+ {'searchImage'} + +
+
+ ); +}; + +export default Search; \ No newline at end of file diff --git a/src/components/forms/label/index.ts b/src/components/forms/label/index.ts new file mode 100644 index 0000000..301fbde --- /dev/null +++ b/src/components/forms/label/index.ts @@ -0,0 +1 @@ +export * from './label'; diff --git a/src/components/forms/label/index.tsx b/src/components/forms/label/label.tsx similarity index 68% rename from src/components/forms/label/index.tsx rename to src/components/forms/label/label.tsx index 9c4ff54..01def2a 100644 --- a/src/components/forms/label/index.tsx +++ b/src/components/forms/label/label.tsx @@ -1,23 +1,19 @@ /** * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. */ -import {JSX} from 'react'; +import React from 'react'; import {Label as StyledLabel} from './style'; interface ILabel { text: string; htmlFor?: string; color?: string; - icon?: JSX.Element; + icon?: React.JSX.Element; className?: string; } -export const Label = ({text, htmlFor, color, icon, className}: ILabel): JSX.Element => ( - +export const Label = ({text, htmlFor, color, icon, className}: ILabel): React.JSX.Element => ( + {text} {icon} -); \ No newline at end of file +); diff --git a/src/components/forms/label/style.ts b/src/components/forms/label/style.ts index 6ef8d51..972b6d7 100644 --- a/src/components/forms/label/style.ts +++ b/src/components/forms/label/style.ts @@ -8,8 +8,8 @@ const {spacing, colors, typography} = Theme; export const Label = styled.default.label<{color?: string}>` font-size: ${typography.fontSizeS}; - color: ${({color}) => (color || colors.gray900)}; + color: ${({color}) => color || colors.gray900}; font-weight: bold; margin: ${spacing.xxSmall} 0; display: block; -`; \ No newline at end of file +`; diff --git a/src/components/icon-menu/icon-menu.tsx b/src/components/icon-menu/icon-menu.tsx new file mode 100644 index 0000000..21b601f --- /dev/null +++ b/src/components/icon-menu/icon-menu.tsx @@ -0,0 +1,198 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import React, {useEffect, useRef, useState, ReactNode} from 'react'; +import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; +import {IconDefinition, IconProp} from '@fortawesome/fontawesome-svg-core'; + +import {useComponentVisible, useCurrentWidth} from 'utility/custom-hooks'; +import {IconMenuWrapper, IconMenuDropDownWrapper, IconMenuContent, IconMenuPointer, DropdownIcon, IconMenuDropDownItem} from './style'; +import {IconMenuPosition, defaultArrowWidth, defaultArrowEdgeGap} from './types'; + +interface IIconMenuItems { + title: string; + value: string; + className?: string; + onSelect?: () => void; + onClick?: () => void; + modal?: { + component: ReactNode; + action?: () => void; + }; +} + +interface IMenuPointerStyle { + left?: number | string; + right?: number | string; + top?: number | string; + bottom?: number | string; + width?: number | string; + height?: number | string; +} + +interface IIconMenu { + items: IIconMenuItems[]; + icon?: IconDefinition | IconProp; + iconClassName?: string; + iconColor?: string; + title?: string; + menuVisible?: boolean; + showTail?: boolean; + position?: IconMenuPosition; + hasPointer?: boolean; + dropdownMargin?: number; + margin?: number | string; + disabled?: boolean; +} + +const IconMenu = ({ + items = [], + icon, + iconClassName, + iconColor = 'white', + menuVisible = false, + title, + showTail = true, + position = IconMenuPosition.BottomLeft, + hasPointer = true, + dropdownMargin = 0, + margin, + disabled +}: IIconMenu): React.JSX.Element => { + const dropdownRef = useRef(null); + const [dropdownStyle, setDropdownStyle] = useState(null); + const [menuPointerStyle, setMenuPointerStyle] = useState({ + right: -defaultArrowWidth / 2, + top: '50%' + }); + const {ref, isComponentVisible, setIsComponentVisible} = useComponentVisible(menuVisible); + const width = useCurrentWidth(); + + useEffect(() => { + if (!isComponentVisible) { + setDropdownStyle(null); + } + }, [isComponentVisible]); + + useEffect(() => { + if (ref.current && dropdownRef.current && isComponentVisible && position) { + const refRect = (ref.current as HTMLElement).getBoundingClientRect(); + const dropdownRefRect = (dropdownRef.current as HTMLElement).getBoundingClientRect(); + const newArrowPosition: IMenuPointerStyle = { + width: `${defaultArrowWidth}px`, + height: `${defaultArrowWidth}px` + }; + const pointerMargin = Math.sqrt((defaultArrowWidth * defaultArrowWidth) / 2); + let top = 0; + let left = 0; + + switch (position) { + case IconMenuPosition.Right: { + newArrowPosition.top = `calc(50% - ${defaultArrowWidth / 2}px)`; + newArrowPosition.left = `-${defaultArrowWidth / 2}px`; + top = refRect.top + refRect.height / 2 - dropdownRefRect.height / 2; + left = refRect.left + refRect.width + pointerMargin + dropdownMargin; + + break; + } + + case IconMenuPosition.Top: { + newArrowPosition.left = '50%'; + newArrowPosition.bottom = `-${defaultArrowWidth / 2}px`; + top = refRect.top - dropdownRefRect.height - pointerMargin - dropdownMargin; + left = refRect.left + refRect.width / 2 - dropdownRefRect.width / 2; + + break; + } + + case IconMenuPosition.TopLeft: { + newArrowPosition.right = `${defaultArrowEdgeGap}px`; + newArrowPosition.bottom = `-${defaultArrowWidth / 2}px`; + top = refRect.top - dropdownRefRect.height - pointerMargin - dropdownMargin; + left = refRect.left + refRect.width / 2 - dropdownRefRect.width + defaultArrowWidth / 2 + defaultArrowEdgeGap; + + break; + } + + case IconMenuPosition.TopRight: { + newArrowPosition.left = `${defaultArrowEdgeGap}px`; + newArrowPosition.bottom = `-${defaultArrowWidth / 2}px`; + top = refRect.top - dropdownRefRect.height - pointerMargin - dropdownMargin; + left = refRect.left + refRect.width / 2 - defaultArrowWidth / 2 - defaultArrowEdgeGap; + + break; + } + + case IconMenuPosition.Bottom: { + newArrowPosition.left = '50%'; + newArrowPosition.top = `-${defaultArrowWidth / 2}px`; + top = refRect.top + refRect.height + pointerMargin + dropdownMargin; + left = refRect.left + refRect.width / 2 - dropdownRefRect.width / 2; + + break; + } + + case IconMenuPosition.BottomLeft: { + newArrowPosition.right = `${defaultArrowEdgeGap}px`; + newArrowPosition.top = `-${defaultArrowWidth / 2}px`; + top = refRect.top + refRect.height + pointerMargin + dropdownMargin; + left = refRect.left + refRect.width / 2 - dropdownRefRect.width + defaultArrowWidth / 2 + defaultArrowEdgeGap; + + break; + } + + case IconMenuPosition.BottomRight: { + newArrowPosition.left = `${defaultArrowEdgeGap}px`; + newArrowPosition.top = `-${defaultArrowWidth / 2}px`; + top = refRect.top + refRect.height + pointerMargin + dropdownMargin; + left = refRect.left + refRect.width / 2 - defaultArrowWidth / 2 - defaultArrowEdgeGap; + + break; + } + + case IconMenuPosition.Left: + default: { + newArrowPosition.top = `calc(50% - ${defaultArrowWidth / 2}px)`; + newArrowPosition.right = `-${defaultArrowWidth / 2}px`; + top = refRect.top + refRect.height / 2 - dropdownRefRect.height / 2; + left = refRect.left - dropdownRefRect.width - pointerMargin - dropdownMargin; + } + } + + setDropdownStyle({ + top, + left + }); + setMenuPointerStyle(newArrowPosition); + } + }, [isComponentVisible, ref, position, dropdownMargin, width]); + + const handleClickIcon = () => { + setIsComponentVisible(!isComponentVisible); + }; + + return ( + <> + + + {title} + {icon && } + + {isComponentVisible && ( + + + {!!hasPointer && } + {items.map((item, i) => ( + + {item.title} + + ))} + + + )} + + + ); +}; + +export default IconMenu; diff --git a/src/components/icon-menu/index.tsx b/src/components/icon-menu/index.tsx new file mode 100644 index 0000000..60371a5 --- /dev/null +++ b/src/components/icon-menu/index.tsx @@ -0,0 +1,4 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +export {default as IconMenu} from './icon-menu'; diff --git a/src/components/icon-menu/style.ts b/src/components/icon-menu/style.ts new file mode 100644 index 0000000..8c703bd --- /dev/null +++ b/src/components/icon-menu/style.ts @@ -0,0 +1,79 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import * as styled from 'styled-components'; +import Theme from 'theme'; +import caretUp from 'assets/images/caret-up.svg'; + +const {colors, spacing} = Theme; + +export const IconMenuWrapper = styled.default.div<{margin?: number | string}>` + margin: ${({margin}) => (margin !== undefined ? margin : '.5rem 0 .5rem 1rem')}; + div { + outline: none; + } + & img{ + width: 24px; + height: 24px; + cursor: pointer; + } +`; +export const IconMenuDropDownWrapper = styled.default.div<{showTail?: boolean; visible?: boolean}>` + position: fixed; + width: 200px; + min-height: 31px; + right: 2.5rem; + ${({showTail}) => + showTail && + styled.css` + background-image: url(${caretUp}); + `}; + background-position: top 0 right .5rem; + background-repeat: no-repeat; + z-index: 9999; + visibility: hidden; + ${({visible}) => + visible && + styled.css` + visibility: visible; + `} +`; +export const IconMenuContent = styled.default.div` + background-color: ${colors.gray100}; + border: 1px solid ${colors.gray200}; + width: 200px; + overflow: auto; + border-radius: ${spacing.xxSmall}; + padding: ${spacing.small} 0; + z-index: 10; +`; + +export const IconMenuDropDownItem = styled.default.div` + padding: ${spacing.small}; + text-decoration: none; + display: flex; + align-items: center; + font-size: 16px; + cursor: pointer; + color: ${colors.black}; + background-color: ${colors.white}; + &:hover { + background-color: ${colors.gray400}; + } +`; +export const DropdownIcon = styled.default.div<{disabled?: boolean}>` + display: flex; + justify-content: center; + cursor: pointer; + min-width: 1rem; + + &.disabled { + pointer-events: none; + opacity: 0.5; + } +`; +export const IconMenuPointer = styled.default.div` + position: absolute; + background-color: ${colors.gray100}; + transform: rotate(45deg); +`; diff --git a/src/components/icon-menu/types.ts b/src/components/icon-menu/types.ts new file mode 100644 index 0000000..b500f47 --- /dev/null +++ b/src/components/icon-menu/types.ts @@ -0,0 +1,19 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ + +export enum IconMenuPosition { + Left = 'left', + Right = 'right', + Top = 'top', + TopLeft = 'top-left', + TopRight = 'top-right', + Bottom = 'bottom', + BottomLeft = 'bottom-left', + BottomRight = 'bottom-right' +} + +const defaultArrowWidth = 12; +const defaultArrowEdgeGap = 8; + +export {defaultArrowWidth, defaultArrowEdgeGap}; diff --git a/src/components/index.ts b/src/components/index.ts index a124ebd..07d9ca9 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -1,4 +1,16 @@ export * from './buttons'; +export * from './channel-icon-menu'; +export * from './error-renderer'; +export * from './layout'; export * from './loaders'; +export * from './modal'; +export * from './new-tab-link'; +export * from './pre-formatted-code'; +export * from './tags'; +export * from './table-screen-header'; +export * from './table-with-pagination'; +export * from './ui'; +export * from './tooltip'; export * from './ProtectedRoute'; -export * from './typography'; \ No newline at end of file +export * from './table'; +export * from './typography'; diff --git a/src/components/indicator-component/indicators/index.ts b/src/components/indicator-component/indicators/index.ts new file mode 100644 index 0000000..9216d82 --- /dev/null +++ b/src/components/indicator-component/indicators/index.ts @@ -0,0 +1,4 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +export * from './indicators'; \ No newline at end of file diff --git a/src/components/indicator-component/indicators/indicators.tsx b/src/components/indicator-component/indicators/indicators.tsx new file mode 100644 index 0000000..c64a5cb --- /dev/null +++ b/src/components/indicator-component/indicators/indicators.tsx @@ -0,0 +1,11 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import {JSX} from 'react'; +import {LoadingWheel as Loader} from 'components/loaders'; +import {SingleStreamSymbol, OfflineSymbol, MultipleStreamSymbol, Indicator} from './style'; + +export const OfflineIndicator = (): JSX.Element => ; +export const SingleStreamIndicator = (): JSX.Element => ; +export const MultiStreamIndicator = (): JSX.Element => ; +export const LoadingIndicator = (): JSX.Element => ; \ No newline at end of file diff --git a/src/components/indicator-component/indicators/style.ts b/src/components/indicator-component/indicators/style.ts new file mode 100644 index 0000000..3376622 --- /dev/null +++ b/src/components/indicator-component/indicators/style.ts @@ -0,0 +1,43 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import * as styled from 'styled-components'; + +import {LoadingWheel as Loader} from 'components'; + +export const Indicator = styled.default.div` + display: flex; + align-items: center; + justify-content: center; + + ${Loader} { + flex: 0; + margin: 0; + + & span { + margin: 0; + } + } +`; + +export const IndicatorOutline = styled.default.div` + width: 20px; + height: 20px; + border-radius: 50%; +`; + +export const OfflineSymbol = styled.default(IndicatorOutline)` + border: 3px solid #707070; + background-color: transparent; +`; + +export const SingleStreamSymbol = styled.default(IndicatorOutline)` + background-color: #08BD0B; +`; + +export const MultipleStreamSymbol = styled.default(SingleStreamSymbol)` + width: 1rem; + height: 1rem; + margin-left: -2px; + box-shadow: 9px 0 0 0 #08BD0B; +`; \ No newline at end of file diff --git a/src/components/indicator-component/publishing-state-indicator.tsx b/src/components/indicator-component/publishing-state-indicator.tsx new file mode 100644 index 0000000..ce16536 --- /dev/null +++ b/src/components/indicator-component/publishing-state-indicator.tsx @@ -0,0 +1,41 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import {JSX} from 'react'; +import {useSelector} from 'react-redux'; + +import {AppStore} from 'store'; +import {DataRowType} from 'components/table'; +import {SingleStreamIndicator, OfflineIndicator, MultiStreamIndicator, LoadingIndicator} from './indicators'; + +interface IPublishingStateIndicator { + row: DataRowType; + publishingStateKey: string; + idKey: string; +} + +const PublishingStateIndicator = ({ + row, + publishingStateKey, + idKey +}: IPublishingStateIndicator): JSX.Element => { + const id = row[idKey]; + const publishingState = useSelector((state: AppStore) => publishingStateKey && state[publishingStateKey as keyof AppStore]?.publishingState); + const rowPublishingState = publishingState.find((record: Record) => record[idKey] === id); + + if (!rowPublishingState) { + return ; + } + + if (!rowPublishingState.isOnline) { + return ; + } + + if (rowPublishingState.multipleStreams) { + return ; + } + + return ; +}; + +export default PublishingStateIndicator; \ No newline at end of file diff --git a/src/components/label/index.ts b/src/components/label/index.ts new file mode 100644 index 0000000..3c36259 --- /dev/null +++ b/src/components/label/index.ts @@ -0,0 +1 @@ +export * from '../forms/label'; \ No newline at end of file diff --git a/src/components/layout/index.tsx b/src/components/layout/index.tsx new file mode 100644 index 0000000..6a5a4ea --- /dev/null +++ b/src/components/layout/index.tsx @@ -0,0 +1,57 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import * as styled from 'styled-components'; +import Theme from 'theme'; + +interface IColumn { + align?: string; + size?: number; + padding?: string; +} + +const {footerHeight} = Theme; + +export const AppContainer = styled.default.div` + margin: 3.5rem 0 ${footerHeight}; + height: calc(100vh - 3.5rem - ${footerHeight}); + overflow: auto; + display: flex; + overflow-x: hidden; +`; + +export const Body = styled.default.div` + width: 100%; + margin: 4rem 0; + padding: 0 ${Theme.spacing.xlarge}; + background: ${Theme.colors.gray900}; + border-radius: 8px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + min-height: calc(100vh - 2rem); + overflow: auto; + max-height: calc(100vh - 2rem); + max-width: calc(100vw - 2rem); +`; + +export const Row = styled.default.div` + display: flex; +`; + +export const Column = styled.default.div` + flex: ${({size}): number => size || 1}; + text-align: ${({align}): string => align || 'right'}; + ${({padding}) => + padding && + styled.css` + padding: ${padding}; + `} +`; + +export const Main = styled.default.div` + height: 100%; + width: 100%; + display: flex; + align-items: center; + justify-content: center; + padding: 2rem; +`; diff --git a/src/components/loaders/LoadingWheel.tsx b/src/components/loaders/LoadingWheel.tsx index 282d79b..ab3c09d 100644 --- a/src/components/loaders/LoadingWheel.tsx +++ b/src/components/loaders/LoadingWheel.tsx @@ -2,7 +2,7 @@ * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. */ import * as styled from 'styled-components'; -import Theme from 'theme'; +import Theme from 'theme'; interface LoadingWheelProps { size?: 'small' | 'medium' | 'large'; @@ -15,11 +15,11 @@ const LoadingWheelContainer = styled.default.div<{ color: string; }>` display: inline-block; - width: ${({ size }) => size}px; - height: ${({ size }) => size}px; - border: 3px solid ${({ color }) => color}20; + width: ${({size}) => size}px; + height: ${({size}) => size}px; + border: 3px solid ${({color}) => color}20; border-radius: 50%; - border-top-color: ${({ color }) => color}; + border-top-color: ${({color}) => color}; animation: spin 1s ease-in-out infinite; @keyframes spin { @@ -29,26 +29,14 @@ const LoadingWheelContainer = styled.default.div<{ } `; -export const LoadingWheel: React.FC = ({ - size = 'medium', - color = Theme.colors.white, - className -}) => { +export const LoadingWheel: React.FC = ({size = 'medium', color = Theme.colors.white, className}) => { const sizeMap = { small: Theme.loaderSize.small, medium: Theme.loaderSize.medium, large: Theme.loaderSize.large }; - return ( - - ); + return ; }; export default LoadingWheel; diff --git a/src/components/loaders/index.ts b/src/components/loaders/index.ts index 4db1d87..1e7bc61 100644 --- a/src/components/loaders/index.ts +++ b/src/components/loaders/index.ts @@ -1,4 +1,4 @@ /** * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. */ -export * from './LoadingWheel'; \ No newline at end of file +export * from './LoadingWheel'; diff --git a/src/components/modal/index.ts b/src/components/modal/index.ts new file mode 100644 index 0000000..06488f2 --- /dev/null +++ b/src/components/modal/index.ts @@ -0,0 +1,5 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ + +export {default as Modal} from './modal'; diff --git a/src/components/modal/modal-form-response/form-response.tsx b/src/components/modal/modal-form-response/form-response.tsx new file mode 100644 index 0000000..f641bd9 --- /dev/null +++ b/src/components/modal/modal-form-response/form-response.tsx @@ -0,0 +1,40 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import {LoadingWheel as Loader} from 'components'; +import PreFormattedCode from 'components/pre-formatted-code'; +import okImage from 'assets/images/icon/ok.svg'; +import errorImage from 'assets/images/icon/error.svg'; +import React from 'react'; + +import {DialogResponse, StatusCode, FormLoaderContainer} from './style'; + +interface IFormResponseComponent { + response: { + error: string | boolean | Error; + status: number | string; + data?: any; //eslint-disable-line + }; +} + +const FormResponse = (props: IFormResponseComponent): React.JSX.Element => { + const {response} = props; + + return !response ? ( + + + + ) : ( + +

{response.error ? 'Error' : 'Success'}

+
+ status icon +
+ Status: {response.status} + {response.data && typeof response.data === 'object' && } + {response.error && typeof response.error === 'string' && } +
+ ); +}; + +export default FormResponse; diff --git a/src/components/modal/modal-form-response/index.tsx b/src/components/modal/modal-form-response/index.tsx new file mode 100644 index 0000000..bc4b598 --- /dev/null +++ b/src/components/modal/modal-form-response/index.tsx @@ -0,0 +1,4 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +export {default as FormResponse} from './form-response'; diff --git a/src/components/modal/modal-form-response/style.ts b/src/components/modal/modal-form-response/style.ts new file mode 100644 index 0000000..d1bdfc5 --- /dev/null +++ b/src/components/modal/modal-form-response/style.ts @@ -0,0 +1,175 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import * as styled from 'styled-components'; +import Theme from 'theme'; +import {InputComponentWrapper} from 'components/forms/Input'; +// import {AdvancedSelectContainer, ComponentWrapper} from 'components/ui/advanced-select/advanced-select'; +// import InputWithTagsWrapper from 'components/ui/input-with-tags/input-with-tags'; +// import TagContainer from 'components/ui/input-with-tags/input-with-tags'; +// import TagWrapper from 'components/ui/input-with-tags/input-with-tags'; + +const {spacing, blackWithOpacity, typography, colors, primaryBorderRadius, primaryBorderColor} = Theme; + +export const DialogContent = styled.default.div` + display: flex; + width: 400px; + margin: ${spacing.small}; +`; + +export const DialogForm = styled.default.div` + display: flex; + flex-direction: column; + width: 100%; + /* stylelint-disable */ + & ${InputComponentWrapper} { + width: 100%; + max-width: 100%; + } + /* TagWrapper { + & > div { + width: 100%; + max-width: 100%; + } + } */ + /* stylelint-enable */ + h3 { + color: ${colors.gray700}; + font-size: ${typography.fontSizeXl}; + line-height: 24px; + font-weight: 500; + letter-spacing: 0.36px; + display: flex; + align-items: flex-start; + a { + font-size: ${typography.fontSizeS}; + margin: 0 0 0 0.5rem; + } + } + > p { + color: ${blackWithOpacity}; + font-size: ${typography.primaryFontSize}; + margin-top: ${spacing.small}; + line-height: 24px; + i { + font-weight: bold; + padding: 0 ${spacing.xsmall}; + } + a { + color: ${colors.lightBlue}; + text-decoration: underline; + } + } + strong { + p { + margin-top: 0; + margin-bottom: ${spacing.xSmall}; + } + svg { + margin: 0 ${spacing.xxSmall}; + color: ${colors.lightBlue}; + } + } + select { + background: ${colors.transparent}; + border: 1px solid ${primaryBorderColor} !important; + } + input { + padding: ${spacing.small}; + margin-bottom: ${spacing.xSmall}; + } + .button-group { + display: flex; + margin-top: ${spacing.small}; + justify-content: center; + } + .error-text { + font-size: ${typography.fontSizeXS}; + color: ${colors.lightRed}; + } + .loading { + width: 100%; + position: absolute; + top: 0; + right: 0; + background-color: rgba(0,0,0,0.5); + display: flex; + align-items: center; + justify-content: center; + } +`; + +export const Options = styled.default.div` + display: flex; + align-items: flex-end; + + &>div { + margin: 0 1rem 0 0; + } +`; + +export const DialogResponse = styled.default(DialogContent)<{error?: string | boolean | Error}>` + width: 100%; + margin: 0; + flex-direction: column; + align-items: center; + justify-content: center; + h3 { + color: ${colors.green}; + font-size: ${typography.fontSizeXl}; + line-height: 24px; + font-weight: 500; + letter-spacing: 0.36px; + ${({error}) => + error && + styled.css` + color: ${colors.lightRed}; + `} + } + .response-icon{ + img { + width: 100px; + height: 100px; + margin: ${spacing.small} 0; + } + } + .json-renderer { + margin-top: ${spacing.small}; + width: 100%; + height: auto; + height: 300px; + padding: ${spacing.small}; + overflow: auto; + background-color: ${colors.gray200}; + font-size: ${typography.fontSizeS}; + } +`; + +export const StatusCode = styled.default.div<{error?: string | boolean | Error}>` + display: flex; + justify-content: center; + width: 100%; + margin: ${spacing.xxSmall} 0; + padding: ${spacing.xsmall} 0; + color: ${colors.green}; + border-radius: ${primaryBorderRadius}; + border: 1px solid ${colors.green}; + ${({error}) => + error && + styled.css` + border-color: ${colors.lightRed}; + color: ${colors.lightRed}; + `} +`; + +export const Error = styled.default.div` + font-size: ${typography.fontSizeXS}; + color: ${colors.lightRed}; +`; + +export const FormLoaderContainer = styled.default.div` + height: 430px; + display: flex; + justify-content: center; + align-items: center; +`; diff --git a/src/components/modal/modal.tsx b/src/components/modal/modal.tsx new file mode 100644 index 0000000..a5210f0 --- /dev/null +++ b/src/components/modal/modal.tsx @@ -0,0 +1,87 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import React from 'react'; +import {createPortal} from 'react-dom'; + +import {ConfirmButton} from 'components/buttons'; +import {theme} from 'components/shared/theme'; + +import {ModalOverlay, ModalContainer, ModalButtonsContaier, CloseButton} from './style'; + +interface IModal { + children: React.JSX.Element; + close: () => void; + className?: string; + submitButton?: { + onClick: () => void; + label?: string; + className?: string; + disabled?: boolean; + textColor?: string; + backgroundColor?: string; + borderColor?: string; + }; + cancelButton?: { + onClick?: () => void; + label?: string; + className?: string; + disabled?: boolean; + textColor?: string; + backgroundColor?: string; + borderColor?: string; + }; +} + +const Modal = (props: IModal): React.JSX.Element => { + const {children, className, close} = props; + const submitButton = { + onClick: props.submitButton?.onClick || null, + label: 'Submit', + disabled: false, + textColor: theme.colors.gray700, + backgroundColor: theme.colors.white, + borderColor: theme.colors.gray700, + ...props.submitButton + }; + const cancelButton = { + label: 'Cancel', + disabled: false, + textColor: theme.colors.white, + backgroundColor: theme.colors.gray700, + borderColor: theme.colors.gray700, + ...props.cancelButton + }; + const handleCancel = () => { + if (cancelButton?.onClick) { + cancelButton.onClick(); + } else { + close(); + } + }; + + const clickModalContainer = (e: React.MouseEvent) => { + e.stopPropagation(); + }; + + return createPortal( + + + + {children} + + {submitButton.onClick && {submitButton.label}} + {!props.cancelButton || + (!cancelButton.disabled && ( + + {cancelButton.label} + + ))} + + + , + document.body + ); +}; + +export default Modal; diff --git a/src/components/modal/multi-step-modal/index.ts b/src/components/modal/multi-step-modal/index.ts new file mode 100644 index 0000000..fa7a973 --- /dev/null +++ b/src/components/modal/multi-step-modal/index.ts @@ -0,0 +1,5 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ + +export {default as MultiStepModal} from './multi-step-modal'; diff --git a/src/components/modal/multi-step-modal/multi-step-modal.tsx b/src/components/modal/multi-step-modal/multi-step-modal.tsx new file mode 100644 index 0000000..0911f34 --- /dev/null +++ b/src/components/modal/multi-step-modal/multi-step-modal.tsx @@ -0,0 +1,66 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ + +import React, {useState} from 'react'; + +import {Modal} from 'components/modal'; + +interface IMultiStepModal { + isOpen: boolean; + closeModal: () => void; + steps: { + title: string; + component: React.JSX.Element; + saveButton?: { + onClick?: () => void; + text?: string; + disabled?: boolean; + className?: string; + }; + cancel?: () => void; + cancelDisabled?: boolean; + }[]; +} + +const MultiStepModal = ({isOpen, closeModal, steps}: IMultiStepModal): React.JSX.Element => { + const [currentStep, setCurrentStep] = useState(0); + const isLastStep = steps.length - 1 === currentStep; + const saveButtonText = isLastStep ? 'Done' : 'Next'; + const handleCloseModal = () => { + closeModal(); + setCurrentStep(0); + }; + + const handleSave = () => { + if (steps[currentStep]?.saveButton?.onClick) { + steps[currentStep].saveButton.onClick(); + } + + if (isLastStep) { + handleCloseModal(); + } else { + setCurrentStep(currentStep + 1); + } + }; + + if (isOpen) { + return ( + + {steps[currentStep]?.component || null} + + ); + } + + return null; +}; + +export default MultiStepModal; diff --git a/src/components/modal/style.ts b/src/components/modal/style.ts new file mode 100644 index 0000000..354b366 --- /dev/null +++ b/src/components/modal/style.ts @@ -0,0 +1,80 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import * as styled from 'styled-components'; + +import {theme, paddings} from 'components/shared/theme'; +import {ConfirmButton} from 'components/buttons'; + +const {colors} = theme; + +export const ModalOverlay = styled.default.div` + position: fixed; + width: 100%; + height: 100vh; + display: flex; + justify-content: center; + align-items: center; + background-color: ${colors.halfTransparentBlack}; + top: 0; + left: 0; + z-index: 9999; +`; + +export const ModalContainer = styled.default.div` + width: 60%; + max-width: 800px; + border-radius: 4px; + padding: ${paddings.xlarge}; + background-color: ${colors.white}; + position: relative; + max-height: 90%; + overflow: auto; + + &.full-width { + width: auto; + max-width: 100%; + overflow-x: hidden; + } + + &.dark { + background-color: ${colors.gray1000} + } +`; + +export const CloseButton = styled.default.span` + cursor: pointer; + height: 1rem; + width: 1rem; + color: ${colors.gray700}; + position: absolute; + top: 0.5rem; + right: 0.5rem; + + &:before, + &:after { + position: absolute; + left: 0.4rem; + content: ' '; + height: 1rem; + width: 0.2rem; + background-color: ${colors.gray700}; + } + &:before { + transform: rotate(45deg); + } + &:after { + transform: rotate(-45deg); + } +`; + +export const ModalButtonsContaier = styled.default.div` + display: flex; + justify-content: center; + align-items: center; + margin: 24px 0 0; + + ${ConfirmButton} { + margin: 0 0.5rem; + } +`; diff --git a/src/components/new-tab-link/index.tsx b/src/components/new-tab-link/index.tsx new file mode 100644 index 0000000..341e200 --- /dev/null +++ b/src/components/new-tab-link/index.tsx @@ -0,0 +1,26 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import React from 'react'; +import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; +import {IconDefinition} from '@fortawesome/fontawesome-svg-core'; + +interface ILink { + icon?: IconDefinition; + text?: string; + iconColor?: string; + link: string; +} + +export const NewTabLink = (props: ILink & Partial): React.JSX.Element => { + const {icon, className, text, link, iconColor = 'white'} = props; + + return ( + + {icon && } + {text} + + ); +}; + +export default NewTabLink; diff --git a/src/components/pagination/index.ts b/src/components/pagination/index.ts new file mode 100644 index 0000000..912d7ca --- /dev/null +++ b/src/components/pagination/index.ts @@ -0,0 +1,5 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +export * from './pagination'; +export {default as Pagination} from './pagination'; \ No newline at end of file diff --git a/src/components/pagination/pagination.tsx b/src/components/pagination/pagination.tsx new file mode 100644 index 0000000..b446f35 --- /dev/null +++ b/src/components/pagination/pagination.tsx @@ -0,0 +1,87 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import {Fragment} from 'react'; +import { + PaginationWrapper, + ItemRange, + PaginationContainer, + PageButton +} from './style'; + +interface IPagination { + currentPageNumber: number; + numberOfItems: number; + itemsPerPage: number; + setCurrentPage: (page: number) => void; + itemText?: string; +} + +export const Pagination = (props: IPagination): JSX.Element => { + const maxNumberOfButtonsToShow = 3; + const LowerBoundLimit = 2; + const higherBoundLimit = 1; + const {currentPageNumber, numberOfItems, itemsPerPage, setCurrentPage, itemText} = props; + const totalNumberOfPages = Math.ceil(numberOfItems / itemsPerPage); + const setPage = (page: number): void => { + setCurrentPage(page); + }; + + const minimumItemBoundPerPage = ((currentPageNumber - 1) * itemsPerPage) + 1; + const maximumItemBoundPerPage = (currentPageNumber) * itemsPerPage; + const generateButtons = (bounds = 1): JSX.Element[] => { + const buttonToShow = maxNumberOfButtonsToShow > totalNumberOfPages ? totalNumberOfPages : maxNumberOfButtonsToShow; + const buttons = []; + let count: number; + + if (currentPageNumber <= bounds) { + count = 1; + } else if ((currentPageNumber + bounds) > totalNumberOfPages) { + count = currentPageNumber - (buttonToShow - (totalNumberOfPages - currentPageNumber + 1)); + } else { + count = currentPageNumber - bounds; + } + + for (let y = 0; y < buttonToShow; y++) { + buttons.push( + setPage(count + y)} + active={currentPageNumber === count + y}> + {count + y} + + ); + } + + return buttons; + }; + + return ( + + {numberOfItems ? ( + + {(currentPageNumber >= LowerBoundLimit) && ( + + {currentPageNumber > 2 && totalNumberOfPages !== 3 && setPage(1)}>1} + {(currentPageNumber > LowerBoundLimit) && currentPageNumber !== 3 &&

...

} +
+ )} + {generateButtons()} + {(currentPageNumber <= totalNumberOfPages - higherBoundLimit) && ( + + {(currentPageNumber < totalNumberOfPages - higherBoundLimit) && currentPageNumber + 2 !== totalNumberOfPages &&

...

} + {currentPageNumber + 1 !== totalNumberOfPages && totalNumberOfPages !== 3 && setPage(totalNumberOfPages)}> + {totalNumberOfPages} + } +
+ )} +
+ ) : null} + + {numberOfItems > 0 ? minimumItemBoundPerPage : 0} - {maximumItemBoundPerPage > numberOfItems ? numberOfItems : maximumItemBoundPerPage} of {numberOfItems} {itemText ? itemText : `channels`} + +
+ ); +}; + +export default Pagination; \ No newline at end of file diff --git a/src/components/pagination/style.tsx b/src/components/pagination/style.tsx new file mode 100644 index 0000000..5b9d99e --- /dev/null +++ b/src/components/pagination/style.tsx @@ -0,0 +1,45 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import * as styled from 'styled-components'; +import {theme, paddings} from 'components/shared/theme'; + +const { + colors, + fontSizeS, + spacing, + primaryThemeColor +} = theme; + +export const PaginationContainer = styled.default.div` + display: flex; + width: 100%; + align-items: center; + flex-wrap: wrap; + margin: ${spacing.small} 0; +`; + +export const PaginationWrapper = styled.default.div` + display: flex; + flex-wrap: wrap; +`; + +export const ItemRange = styled.default.div` + display: flex; + justify-content: flex-end; + margin-left: auto; + font-size: ${fontSizeS}; + color: ${colors.lightBlue}; +`; + +export const PageButton = styled.default.button <{active?: boolean}>` + margin: 0 ${paddings.xsmall} ${paddings.xsmall} 0; + font-size: ${fontSizeS}; + border: 1px solid ${primaryThemeColor}; + border-radius: 4px; + height: 28px; + width: 36px; + cursor: pointer; + background-color: ${({active}) => active ? primaryThemeColor : 'transparent'}; + color: ${({active}) => active ? colors.white : primaryThemeColor}; +`; \ No newline at end of file diff --git a/src/components/pre-formatted-code/index.tsx b/src/components/pre-formatted-code/index.tsx new file mode 100644 index 0000000..6b40b31 --- /dev/null +++ b/src/components/pre-formatted-code/index.tsx @@ -0,0 +1,5 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ + +export {default} from './pre-formatted-code'; diff --git a/src/components/pre-formatted-code/pre-formatted-code.tsx b/src/components/pre-formatted-code/pre-formatted-code.tsx new file mode 100644 index 0000000..88c26b6 --- /dev/null +++ b/src/components/pre-formatted-code/pre-formatted-code.tsx @@ -0,0 +1,58 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import React, {Fragment, useState} from 'react'; +import {faCopy, faCheck} from '@fortawesome/free-solid-svg-icons'; + +import IconButton from 'components/buttons/icon-button'; + +import {CodeContainer} from './styles'; + +interface IPreFormattedCode { + data: Record | Array; // eslint-disable-line + prefixCharacter?: string; + color?: string; + showCopyIcon?: boolean; +} + +const iconChangeTimeout = 2000; +const PreFormattedCode = ({data, prefixCharacter, color, showCopyIcon = true}: IPreFormattedCode): React.JSX.Element => { + const [copied, setCopied] = useState(false); + const json = JSON.stringify(data, null, 2); + const lines = json.split('\n'); + const text = lines.map(line => line.replace(/^< /, '')).join('\n'); + const copyJsonToClipboard = (text: string): void => { + navigator.clipboard.writeText(text); + setCopied(true); + + setTimeout(() => setCopied(false), iconChangeTimeout); + }; + + const handleCopy = event => { + const originalString = event.target.textContent; + const modifiedString = originalString.replace(/[<>]/g, ''); + + event.clipboardData.setData('text/plain', modifiedString); + event.preventDefault(); + }; + + const handleCopyIconClick = () => copyJsonToClipboard(text); + + return ( + +
+        
+          {lines.map((line, index) => (
+            
+              {prefixCharacter} {line} 
+ {index === lines.length - 1 && prefixCharacter} +
+ ))} +
+
+ {showCopyIcon && } +
+ ); +}; + +export default PreFormattedCode; diff --git a/src/components/pre-formatted-code/styles.ts b/src/components/pre-formatted-code/styles.ts new file mode 100644 index 0000000..83a1732 --- /dev/null +++ b/src/components/pre-formatted-code/styles.ts @@ -0,0 +1,34 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import * as styled from 'styled-components'; +import Theme from 'theme'; + +const {colors} = Theme; + +export const CodeContainer = styled.default.div<{color?: string}>` + background-color: ${colors.gray200}; + padding: 1rem; + margin: 1rem 0 0; + display: flex; + color: ${({color}) => color || colors.black}; + position: relative; + width: 100%; + + &>span { + position: absolute; + right: 0.5rem; + top: 0.5rem; + } + + pre { + width: 100%; + white-space: pre-wrap; + max-height: 40vh; + overflow: auto; + } + + code { + word-wrap: break-word; + } +`; diff --git a/src/components/restricted-text/index.ts b/src/components/restricted-text/index.ts new file mode 100644 index 0000000..2402e4f --- /dev/null +++ b/src/components/restricted-text/index.ts @@ -0,0 +1,6 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +export {default as RestrictedTextWithLabel} from './restricted-text-with-label'; +export {default as RestrictedText} from './restricted-text'; +export * from './restricted-text'; \ No newline at end of file diff --git a/src/components/restricted-text/restricted-text-with-label.tsx b/src/components/restricted-text/restricted-text-with-label.tsx new file mode 100644 index 0000000..2b1b9c9 --- /dev/null +++ b/src/components/restricted-text/restricted-text-with-label.tsx @@ -0,0 +1,34 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import {JSX} from 'react'; +import {RestrictedRowLabel, RestrictedRowText, RestrictedRowWrapper} from './style'; + +import {RestrictedText} from '.'; + +interface IRestrictedTextWithLabel { + label: string; + text: string; + isLink?: boolean; + linkClassName?: string; + labelIcon?: JSX.Element; +} + +const RestrictedTextWithLabel = ({ + label, + text, + labelIcon, + isLink = false, + linkClassName = '' +}: IRestrictedTextWithLabel): JSX.Element => { + return ( + + {label} {labelIcon} + + + + + ); +}; + +export default RestrictedTextWithLabel; \ No newline at end of file diff --git a/src/components/restricted-text/restricted-text.tsx b/src/components/restricted-text/restricted-text.tsx new file mode 100644 index 0000000..f59b04c --- /dev/null +++ b/src/components/restricted-text/restricted-text.tsx @@ -0,0 +1,115 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import {JSX, useEffect, useRef, useState} from 'react'; +import {faEye, faEyeSlash} from '@fortawesome/free-regular-svg-icons'; + +import {Link} from 'components/ui'; +import IconButton from 'components/buttons/icon-button'; +import {CopyIconButton} from 'components/buttons/copy-icon-button'; +import NewTabLink from 'components/new-tab-link'; + +import {RestrictedDiv, MeasuringBlock, TruncatedBlock} from './style'; + +export interface IRestrictedText { + text: string; + hasViewOption?: boolean; + hasCopyOption?: boolean; + isLink?: boolean; + linkValue?: string; + linkClassName?: string; + index?: number; + fullWidth?: boolean; +} + +const iconButtonsWidth = 48; + +export const RestrictedText = ({ + text, + hasViewOption = true, + hasCopyOption = true, + isLink = false, + linkValue, + linkClassName = '', + fullWidth = true +}: IRestrictedText): JSX.Element => { + const restrictedDivRef = useRef(null); + const measuringRef = useRef(null); + const [showValue, setShowValue] = useState(false); + const [showEyeIcon, setShowEyeIcon] = useState(hasViewOption); + + useEffect(() => { + const handleResize = () => { + handleShowEyeIcon(); + }; + + window.addEventListener('resize', handleResize); + + handleShowEyeIcon(); + + return () => { + window.removeEventListener('resize', handleResize); + }; + }, []); + + const handleShowEyeIcon = () => { + if (!restrictedDivRef.current || !measuringRef.current) { + return; + } + + const containerWidth = restrictedDivRef.current.clientWidth - iconButtonsWidth; + const fullTextWidth = measuringRef.current.getBoundingClientRect()?.width; + + setShowEyeIcon(fullTextWidth > containerWidth); + }; + + const handleShowValueChange = () => setShowValue(!showValue); + const CurrentTextView = (): JSX.Element => { + if (isLink && !linkValue) { + return ( + + ); + } + + if (isLink && linkValue) { + return ( + + {text} + + ); + } + + return <>{text}; + }; + + return ( + + {text} + + + +
+ {showEyeIcon && ( + + )} + {hasCopyOption && ( + + )} +
+
+ ); +}; + +export default RestrictedText; \ No newline at end of file diff --git a/src/components/restricted-text/style.ts b/src/components/restricted-text/style.ts new file mode 100644 index 0000000..13d2173 --- /dev/null +++ b/src/components/restricted-text/style.ts @@ -0,0 +1,96 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import * as styled from 'styled-components'; + +import Theme from 'theme'; + +const { + colors, + typography, + spacing, +} = Theme; + +export const RestrictedDiv = styled.default.div` + display: flex; + align-items: center; + justify-content: start; + word-wrap: break-word; + &.full-width { + width: 100%; + } + & div { + display: flex; + align-items: center; + justify-content: center; + align-content: center; + & span { + color: ${Theme.primaryThemeColor}; + display: none; + cursor: pointer; + outline: none; + } + .icon-button { + width: 1.5rem; + height: 1.5rem; + } + } + &:hover { + & span { + display: block; + } + } +`; + +export const TruncatedBlock = styled.default.p` + overflow: hidden; + padding: ${spacing.small} 0; + text-overflow: ellipsis; + + &.truncated { + white-space: nowrap; + } +`; + +export const MeasuringBlock = styled.default.p` + position: fixed; + visibility: hidden; + opacity: 0; + white-space: nowrap; +`; + +export const RestrictedRowWrapper = styled.default.div` + display: flex; +`; + +export const RestrictedRowLabel = styled.default.div` + width: 135px; + display: flex; + align-self: center; + color: ${colors.gray300}; + font-size: ${typography.fontSizeS}; + padding: ${spacing.small}; + + a { + margin: 0 0.25rem; + } + + span { + margin: 0 2px; + } +`; + +export const RestrictedRowText = styled.default.div` + color: ${colors.gray300}; + font-size: ${typography.fontSizeS}; + border-bottom: 1px solid ${colors.gray700}; + padding: ${spacing.small}; + width: calc(100% - 135px); + + a { + color: ${colors.lightBlue}; + overflow-wrap: anywhere; + text-decoration: none; + font-size: ${typography.fontSizeS}; + } +`; \ No newline at end of file diff --git a/src/components/shared/theme.ts b/src/components/shared/theme.ts new file mode 100644 index 0000000..bb860ec --- /dev/null +++ b/src/components/shared/theme.ts @@ -0,0 +1,2 @@ +export {default, theme, Theme} from '../../theme'; +export * from '../../theme'; diff --git a/src/components/shared/utils.ts b/src/components/shared/utils.ts index bcda305..9205bdd 100644 --- a/src/components/shared/utils.ts +++ b/src/components/shared/utils.ts @@ -12,9 +12,9 @@ export const truncateWord = (word = '', length = 30): string => { return word; }; -export const isEqual = (a: any, b: any): boolean => { // eslint-disable-line - if (typeof(a) === typeof(b)) { - if (typeof(a) === 'object') { +export const isEqual = (a: unknown, b: unknown): boolean => { + if (typeof a === typeof b) { + if (typeof a === 'object') { return JSON.stringify(a) === JSON.stringify(b); } @@ -39,8 +39,8 @@ export const mergeSimilarCSVFiles = (formerCSV: string, latterCSV: string): stri return formerCSV; }; -export const chunk = (array: any[], size: number = 1) => { // eslint-disable-line - const arrayChunks = []; +export const chunk = (array: T[], size: number = 1): T[][] => { + const arrayChunks: T[][] = []; for (let i = 0; i < array.length; i += size) { const arrayChunk = array.slice(i, i + size); @@ -66,10 +66,7 @@ export const getRangeByInterval = (start: Date, end: Date, intervalAmount: Durat export const getBrowserLimits = (): IBrowserLimits => browserLimits[PlatformDetectionService.browserName.toLowerCase()]; -export const getMaxByPropertyName = ( - array: Record[], - propertyName: string -): number => { +export const getMaxByPropertyName = (array: Record[], propertyName: string): number => { let length = array.length; let max = -Infinity; @@ -82,4 +79,4 @@ export const getMaxByPropertyName = ( } return max; -}; \ No newline at end of file +}; diff --git a/src/components/table-screen-header/index.ts b/src/components/table-screen-header/index.ts new file mode 100644 index 0000000..230cbc2 --- /dev/null +++ b/src/components/table-screen-header/index.ts @@ -0,0 +1,4 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +export {default as TableScreenHeader} from './table-screen-header'; \ No newline at end of file diff --git a/src/components/table-screen-header/style.tsx b/src/components/table-screen-header/style.tsx new file mode 100644 index 0000000..76a45b8 --- /dev/null +++ b/src/components/table-screen-header/style.tsx @@ -0,0 +1,37 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import * as styled from 'styled-components'; +import Theme from 'theme'; + +const {colors} = Theme; + +export const ScreenHeader = styled.default.div` + display: flex; + justify-content: space-between; + align-items: baseline; + flex-wrap: wrap; + width: 100%; + margin: 0 0 .5rem; +`; + +export const ScreenHeaderControls = styled.default.div` + display: flex; + align-items: center; +`; + +export const HeaderControlWrapper = styled.default.div` + margin-left: 12px; +`; + +export const HeaderTitle = styled.default.div` + display: flex; + align-items: baseline; + h2 { + color: ${colors.white}; + margin: 0 .5rem 0 0; + } + p { + color: ${colors.gray200}; + } +`; \ No newline at end of file diff --git a/src/components/table-screen-header/table-screen-header.tsx b/src/components/table-screen-header/table-screen-header.tsx new file mode 100644 index 0000000..cf1c39f --- /dev/null +++ b/src/components/table-screen-header/table-screen-header.tsx @@ -0,0 +1,48 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import {JSX} from 'react'; +import { + ITableWithLoadMoreHeader, + ITableWithPaginationHeader, + TableHeaderKey +} from 'interfaces/tableProps'; +import {ScreenHeader, ScreenHeaderControls, HeaderControlWrapper, HeaderTitle} from './style'; + +type ScreenHeaderProps = ITableWithLoadMoreHeader | ITableWithPaginationHeader; + +export interface ITableScreenHeader { + title: string; + subtitle?: string; + screenHeader: ScreenHeaderProps; + renderControl: (screenHeader: ScreenHeaderProps, key: TableHeaderKey) => JSX.Element | null; +} + +export const TableScreenHeader = ({ + title, + subtitle = '', + screenHeader, + renderControl +}: ITableScreenHeader): JSX.Element => { + return ( + + +

{title}

+ {subtitle &&

{subtitle}

} +
+ + {Object.keys(screenHeader).map(key => { + const headerControl = screenHeader[key].render + ? screenHeader[key].render(key) + : renderControl(screenHeader, key as TableHeaderKey); + + return headerControl ? ( + {headerControl} + ) : null; + })} + +
+ ); +}; + +export default TableScreenHeader; \ No newline at end of file diff --git a/src/components/table-with-pagination/index.ts b/src/components/table-with-pagination/index.ts new file mode 100644 index 0000000..ce59abe --- /dev/null +++ b/src/components/table-with-pagination/index.ts @@ -0,0 +1,6 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +export * from 'components/table'; +export {default as TableWithPagination} from './table-with-pagination'; +export {default as Pagination} from '../pagination/pagination'; \ No newline at end of file diff --git a/src/components/table-with-pagination/table-with-pagination.tsx b/src/components/table-with-pagination/table-with-pagination.tsx new file mode 100644 index 0000000..ea4fe7e --- /dev/null +++ b/src/components/table-with-pagination/table-with-pagination.tsx @@ -0,0 +1,205 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import {useEffect, useState} from 'react'; + +import { + DataRowType, + Table, + TableHeaderKey, + ITable, + ITableWithPaginationHeader, + ITableSort +} from 'components/table'; +import {isEqual} from 'utility/validators'; +import SearchInput from 'components/forms/SearchInput'; +import {compare} from 'utility/sort'; +import {TableScreenHeader} from 'components/table-screen-header/table-screen-header'; +import {AddButton} from 'components/buttons/icon-buttons'; +import {Pagination} from 'components/pagination/pagination' ; +import {Select} from 'components/ui/select'; + +import {useSort, useSearch} from 'utility/custom-hooks'; + +interface ITableWithPagination extends ITable { + screenHeader: ITableWithPaginationHeader; + paginationItemText?: string; + getCurrentDisplayList?: (data: Record[]) => void; +} + +const TableWithPagination = ({ + title = '', + screenHeader, + columns, + data, + sortColumn, + sortDirection, + style, + paginationItemText, + errorMessage, + getCurrentDisplayList, + changeSortProps, + searchValue: propsSearchValue = '', + changeSearch +}: ITableWithPagination): JSX.Element => { + const [currentPageNumber, setCurrentPageNumber] = useState(1); + const [currentData, setCurrentData] = useState([]); + const [filteredData, setFilteredData] = useState(data || []); + const [total, setTotal] = useState(data ? data.length : 0); + const [rowsCount, setRowsCount] = useState(10); + const [sortData, setSortData] = useSort({ + sortColumn, + sortDirection + }); + const [searchValue, setSearchValue] = useSearch(propsSearchValue); + const amendMarginsInElementsHeight = (selector: string, action: 'add' | 'remove') => { + const element = document.querySelector(selector); + let elementHeight = element?.clientHeight || 0; + + if (!element) { + return; + } + + if (action === 'add') { + elementHeight += parseInt(window?.getComputedStyle(element).getPropertyValue('margin-top')); + elementHeight += parseInt(window?.getComputedStyle(element).getPropertyValue('margin-bottom')); + } else { + elementHeight -= parseInt(window?.getComputedStyle(element).getPropertyValue('margin-top')); + elementHeight -= parseInt(window?.getComputedStyle(element).getPropertyValue('margin-bottom')); + } + + return elementHeight; + }; + + const calculateRowsCount = () => { + const tableContainerHeight = amendMarginsInElementsHeight('.table-container', 'remove') || 0; + const paginationHeight = amendMarginsInElementsHeight('.pagination-container', 'add') || 0; + const tableHeaderHeight = amendMarginsInElementsHeight('.table-header', 'add') || 0; + const tableRow = document.querySelector('.table-row') || {clientHeight: 50}; + const rowHeight = tableRow?.clientHeight || 50; + const newRowsCount = Math.round((tableContainerHeight - paginationHeight - tableHeaderHeight) / rowHeight); + + setRowsCount(newRowsCount || rowsCount); + }; + + useEffect(() => { + let pxRatioBeforeZoom = window.devicePixelRatio; + let windowHeightBeforeResize = window.innerHeight; + const trackResize = e => { + const pxRatioAfterZoom = e.devicePixelRatio; + const windowHeightAfterResize = e.target.innerHeight; + + if (pxRatioAfterZoom !== pxRatioBeforeZoom || windowHeightAfterResize !== windowHeightBeforeResize) { + pxRatioBeforeZoom = pxRatioAfterZoom; + windowHeightBeforeResize = windowHeightAfterResize; + + calculateRowsCount(); + } + }; + + calculateRowsCount(); + + window.addEventListener('resize', trackResize); + + return () => { + window.removeEventListener('resize', trackResize); + }; + }, []); + + useEffect(() => { + let newData = Array.isArray(data) ? [...data] : []; + + if (searchValue && Array.isArray(data)) { + newData = data.filter(prop => { + return Object.keys(columns).some(key => { + return String(prop[key]).toLowerCase().includes(searchValue.toLowerCase()); + }); + }); + } + + if (!isEqual(newData, filteredData)) { + setFilteredData(newData); + } + + if (!isEqual(total, newData.length)) { + setTotal(newData.length); + } + }, [data, searchValue, rowsCount, columns]); + + useEffect(() => { + const start = (currentPageNumber - 1) * rowsCount; + const sortedData = sortData + ? filteredData.sort((a, b) => compare(a, b, sortData.sortDirection, sortData.sortColumn)) + : filteredData; + const newCurrentData = sortedData.slice(start, start + rowsCount); + + if (!isEqual(newCurrentData, currentData)) { + setCurrentData(newCurrentData); + + if (getCurrentDisplayList) { + getCurrentDisplayList(newCurrentData); + } + } + }, [filteredData, currentPageNumber, rowsCount, sortData]); + + const search = (val: string) => { + if (val !== searchValue) { + if (changeSearch) { + changeSearch({searchValue: val}); + } else { + setSearchValue(val); + } + + setCurrentPageNumber(1); + } + }; + + const sort = (data: ITableSort) => { + if (changeSortProps) { + changeSortProps(data); + } else { + setSortData(data); + } + }; + + const renderControl = (screenHeader: ITableWithPaginationHeader, key: TableHeaderKey) => { + switch (key) { + case TableHeaderKey.Search: + return ; + case TableHeaderKey.AddRow: + return ; + case TableHeaderKey.SelectType: + return setTagInput(target.value)} + value={tagInput} + onKeyDown={handleOnKeyDown} + name="testId-downloadInputField" + className="testId-streamTags" + helperText={helperText} + helperTextClassName={helperTextClassName} + error={error} + /> + + Add + + + {tags.length > 0 && ( + + {tags.map(tag => ( + onClose(tag)} /> + ))} + + )} + + ); +}; + +export default InputWithTags; diff --git a/src/components/ui/input-with-tags/style.ts b/src/components/ui/input-with-tags/style.ts new file mode 100644 index 0000000..15af0e4 --- /dev/null +++ b/src/components/ui/input-with-tags/style.ts @@ -0,0 +1,48 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import * as styled from 'styled-components'; +import {theme} from 'components/shared/theme'; +import {InputElement} from 'components/ui/input'; + +const {spacing, colors, formFieldMaxHeight, formFieldWidth, formFieldMaxWidth, primaryBorderRadius} = theme; + +export const InputWithTagsWrapper = styled.default.div<{width: number | string}>` + position: relative; + width: ${({width}) => (width && isNaN(+width) ? width : (width || formFieldWidth) + 'px')}; + max-width: ${formFieldMaxWidth}px; + display: flex; + flex-direction: column; + ${InputElement} { + padding-right: 58px; + } +`; + +export const TagContainer = styled.default.div` + display: flex; + width: 100%; + max-width: ${formFieldWidth}px; + max-height: ${formFieldMaxHeight - 50}px; + overflow-y: auto; + flex-wrap: wrap; + margin: ${spacing.xxSmall} 0; +`; + +export const TagButton = styled.default.button` + position: absolute; + background-color: ${colors.gray500}; + top: 3px; + right: 3px; + width: 50px; + height: 30px; + border: none; + border-radius: ${primaryBorderRadius}; + :hover { + box-shadow: 0 4px 15px rgba(0,0,0,.1); + } +`; + +export const TagWrapper = styled.default.div` + position: relative; + width: 100%; +`; diff --git a/src/components/ui/input.tsx b/src/components/ui/input.tsx new file mode 100644 index 0000000..142768f --- /dev/null +++ b/src/components/ui/input.tsx @@ -0,0 +1,128 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import React, {ChangeEvent, forwardRef, ForwardedRef, InputHTMLAttributes} from 'react'; +import * as styled from 'styled-components'; +import {paddings, theme} from 'components/shared/theme'; +import {Label} from '../label'; + +export interface IInput extends InputHTMLAttributes { + onChange?: (event: ChangeEvent) => void; + error?: boolean; + icon?: React.JSX.Element; + imagePath?: string; + imageAltText?: string; + label?: string; + labelColor?: string; + labelIcon?: React.JSX.Element; + labelClassName?: string; + helperText?: string; + helperTextClassName?: string; + width?: number | string; +} + +const { + colors, + fontSizeS, + formFieldWidth, + formFieldMaxWidth, + primaryBorderColor, + primaryBorderRadius, + primaryFontSize, + primaryLineHeight, + primaryInputHeight, + inputIconWidth, + spacing +} = theme; + +export const InputElement = styled.default.input` + background-color: ${colors.white}; + border: 1px solid ${({error}) => (error ? colors.lightRed : primaryBorderColor)}; + border-radius: ${primaryBorderRadius}; + display: block; + font-size: ${primaryFontSize}; + height: ${primaryInputHeight}; + line-height: ${primaryLineHeight}; + outline: none; + padding: ${paddings.small} ${({icon, imagePath}) => (icon || imagePath ? paddings.xlarge : paddings.small)}; + transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out; + background-position: 1rem center; + background-repeat: no-repeat; + width: inherit; + opacity: ${({disabled}) => (disabled ? 0.8 : 1)}; + cursor: ${({disabled}) => disabled && 'not-allowed'}; + -webkit-text-fill-color: ${({disabled}) => disabled && colors.gray800}; +`; +const HelperText = styled.default.p` + color: ${({error}) => (error ? colors.lightRed : colors.gray600)}; + font-weight: 400; + font-size: ${fontSizeS}; + margin-top: ${spacing.xxSmall}; +`; +const ImageWrapper = styled.default.div` + width: ${inputIconWidth}px; + height: ${inputIconWidth}px; + z-index: 1; + top: calc(50% - ${inputIconWidth / 2}px); + left: 8px; + position: absolute; + display: flex; + align-items: center; + + & img, svg { + width: ${inputIconWidth}px; + height: ${inputIconWidth}px; + } +`; +const InputWrapper = styled.default.div` + width: 100%; + position: relative; +`; + +export const InputComponentWrapper = styled.default.div` + position: relative; + width: ${({width}) => (width && isNaN(+width) ? width : (width || formFieldWidth) + 'px')}; + max-width: ${formFieldMaxWidth}px; + display: flex; + flex-direction: column; +`; +export const InputComponent = forwardRef( + ( + { + label, + labelColor, + labelIcon, + labelClassName, + icon, + imagePath, + imageAltText = '', + helperText, + helperTextClassName, + error, + width, + disabled, + name, + ...props + }: IInput, + ref: ForwardedRef + ): React.JSX.Element => { + const InputIcon = icon || (imagePath && {imageAltText}); + + return ( + + {!!label && + ); + } +); + +export default InputComponent; diff --git a/src/components/ui/link/index.tsx b/src/components/ui/link/index.tsx new file mode 100644 index 0000000..44c9c1b --- /dev/null +++ b/src/components/ui/link/index.tsx @@ -0,0 +1,4 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +export {default as Link} from './link'; diff --git a/src/components/ui/link/link.tsx b/src/components/ui/link/link.tsx new file mode 100644 index 0000000..d6d0a0a --- /dev/null +++ b/src/components/ui/link/link.tsx @@ -0,0 +1,18 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import React from 'react'; +import {Link, LinkProps, useLocation} from 'react-router-dom'; + +const LinkWithSearch = (props: LinkProps): React.JSX.Element => { + const {to, children} = props; + const {search} = useLocation(); + + return ( + + {children} + + ); +}; + +export default LinkWithSearch; diff --git a/src/components/ui/link/styles.ts b/src/components/ui/link/styles.ts new file mode 100644 index 0000000..1239565 --- /dev/null +++ b/src/components/ui/link/styles.ts @@ -0,0 +1,33 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import * as styled from 'styled-components'; + +import {Link} from 'components/ui'; +import {theme, paddings} from 'components/shared/theme'; + +const {colors} = theme; + +export const InnerLinksContainer = styled.default.div` + display: flex; + justify-content: center; + align-items: center; + position: relative; + z-index: 1; +`; + +export const InnerLink = styled.default(Link)` + padding: 0 0; + background-color: transparent; + font-size: 1rem; + cursor: pointer; + outline: none; + border: none; + text-decoration: none; + color: white; + margin: ${paddings.small}; + border-bottom: 2px solid ${(props: {selected: boolean}): string => (props.selected ? colors.lightRed : 'none')}; + &:active { + border-bottom: 2px solid ${(props: {selected: boolean}): string => (props.selected ? colors.lightRed : 'none')}; + } +`; diff --git a/src/components/ui/multi-select/index.ts b/src/components/ui/multi-select/index.ts new file mode 100644 index 0000000..ab23693 --- /dev/null +++ b/src/components/ui/multi-select/index.ts @@ -0,0 +1,5 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +export {default as MultiSelect} from './multi-select'; +export * from './multi-select'; diff --git a/src/components/ui/multi-select/multi-select.tsx b/src/components/ui/multi-select/multi-select.tsx new file mode 100644 index 0000000..ad64fcf --- /dev/null +++ b/src/components/ui/multi-select/multi-select.tsx @@ -0,0 +1,175 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import {useState, useRef, useEffect, ChangeEvent} from 'react'; +import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; +import {faCaretDown} from '@fortawesome/free-solid-svg-icons'; + +import {Tag} from 'components/tags'; +import {Label} from 'components/label'; +import Checkbox from 'components/forms/Checkbox'; +import {Input} from 'components/forms/Input'; + +import {ISelectItem} from 'interfaces'; + +import {SelectContainer, Select, DropDownIcon, SelectDropDown, SelectDropDownItem, SelectItemsContainer, SelectedTagsContainer, SubLabel} from './style'; + +interface IMultiSelectComponent { + label?: string; + labelColor?: string; + items: ISelectItem[]; + searchable?: boolean; + onSelect: (item: ISelectItem[]) => void; + defaultItems?: ISelectItem[]; + subLabel?: string; +} + +const filterItems = (items: ISelectItem[], searchInput) => { + return items.filter(({label}) => { + return label.toLowerCase().indexOf(searchInput.toLowerCase()) > -1; + }); +}; + +const MultiSelect = ({label, items, onSelect, searchable = false, defaultItems, subLabel, labelColor}: IMultiSelectComponent): React.JSX.Element => { + const [selectedItems, setSelectedItems] = useState(defaultItems || []); + const [focusOnSelectComponent, setFocusOnSelectComponent] = useState(false); + const [filteredItems, setFilteredItems] = useState(items); + const [showDropDown, setShowDropDown] = useState(false); + const [searchInput, setSearchInput] = useState(''); + const selectRef = useRef(null); + const ref = useRef(null); + const optsRef = useRef([]); + const handleClickOutside = event => { + if (ref.current && !ref.current.contains(event.target)) { + if (selectRef.current && !selectRef.current.contains(event.target)) { + setShowDropDown(false); + } + } + }; + + useEffect(() => { + document.addEventListener('click', handleClickOutside, true); + + return () => { + document.removeEventListener('click', handleClickOutside, true); + }; + }); + + useEffect(() => { + onSelect(selectedItems); + }, [selectedItems, onSelect]); + + useEffect(() => { + setFilteredItems(() => filterItems(items, searchInput)); + }, [searchInput, items]); + + const isChecked = item => { + return selectedItems.map(({value}) => value).indexOf(item) > -1; + }; + + useEffect(() => { + if (optsRef.current[0]) { + optsRef.current[0].focus(); + } + }, [focusOnSelectComponent]); + + const handleFocus = () => { + setShowDropDown(true); + setFocusOnSelectComponent(true); + }; + + const handleOnCheck = (event, item) => { + if (event) { + event.stopPropagation(); + } + + if (selectedItems.map(({value}) => value).indexOf(item.value) > -1) { + setSelectedItems(selectedItems.filter(selectedItem => selectedItem.value !== item.value)); + } else { + setSelectedItems([...selectedItems, item]); + } + }; + + const generateOptions = () => { + return filteredItems.map(({label, value}, index) => ( + + ) => + handleOnCheck(event, { + label, + value + }) + } + checked={isChecked(value)} + /> +
(optsRef.current[index] = ref)} + tabIndex={0} + onKeyPress={() => null} + onClick={e => + handleOnCheck(e, { + label, + value + }) + }> + {label} +
+
+ )); + }; + + const generateTags = () => { + return selectedItems.map(({label, value}) => ( + + handleOnCheck(event, { + label, + value + }) + } + /> + )); + }; + + const onInputChange = ({target}) => { + setSearchInput(target.value); + }; + + const handleOnClickSelect = () => { + if (focusOnSelectComponent) { + setFocusOnSelectComponent(!focusOnSelectComponent); + + return; + } + + setShowDropDown(!showDropDown); + }; + + return ( + + {!!label && + ); +}; + +export default MultiSelect; diff --git a/src/components/ui/multi-select/style.ts b/src/components/ui/multi-select/style.ts new file mode 100644 index 0000000..13c9fb3 --- /dev/null +++ b/src/components/ui/multi-select/style.ts @@ -0,0 +1,117 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import * as styled from 'styled-components'; +import {theme, paddings} from 'components/shared/theme'; +import {Input} from 'components/forms/Input'; + +const {colors, spacing, primaryBorderRadius, fontSizeS, primaryInputHeight} = theme; + +export const DropDownIcon = styled.default.span` + position: absolute; + top: .65rem; + right: .8rem; + color: ${colors.gray500}; +`; + +export const SimpleSelect = styled.default.select` + margin: 4px 0; +`; + +export const Select = styled.default.div<{showMenu?: boolean}>` + border: 0; + border-radius: ${primaryBorderRadius}; + + ${({showMenu}) => + showMenu && + styled.css` + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + border-bottom-width: 0; + + ${DropDownIcon} { + transform: rotate(180deg); + } + `} +`; + +/* Stylelint-disable property-no-vendor-prefix */ +export const SelectContainer = styled.default.div` + select, ${Select} { + padding: 0 ${paddings.small}; + width: 100%; + min-width: 12.25rem; + height: ${primaryInputHeight}; + display: flex; + align-items: center; + position: relative; + flex-wrap: wrap; + background-color: ${colors.white}; + border: none; + cursor: pointer; + } + + select { + border-radius: ${primaryBorderRadius}; + appearance: none; + } + + label { + display: block; + } +`; +/* Stylelint-enable property-no-vendor-prefix */ + +export const SelectedTagsContainer = styled.default.div` + display: flex; + flex-wrap: wrap; +`; + +export const SelectDropDown = styled.default.div` + position: absolute; + top: 100%; + left: 0; + width: 100%; + max-height: 300px; + border: 1px solid ${colors.gray400}; + z-index: 4; + background-color: ${colors.white}; + display: flex; + flex-direction: column; + padding: ${paddings.small}; + ${Input} { + width: 100%; + display: inline-block; + } + border-top-width: 0; + border-bottom-left-radius: ${primaryBorderRadius}; + border-bottom-right-radius: ${primaryBorderRadius}; +`; + +export const SelectItemsContainer = styled.default.div<{searchable?: boolean}>` + ${({searchable}) => + searchable && + styled.css` + max-height: calc(300px - 2.4rem); + overflow-y: auto; + `} +`; + +export const SelectDropDownItem = styled.default.div` + width: 100%; + display: flex; + height: ${primaryInputHeight}; + padding: ${paddings.xsmall}; + align-items: center; + .drop-down-text { + top: 0; + margin: 0 ${spacing.xxSmall}; + } +`; + +export const SubLabel = styled.default.p` + color: ${colors.gray600}; + font-weight: 400; + font-size: ${fontSizeS}; + margin-top: ${spacing.xxSmall}; +`; diff --git a/src/components/ui/radio-button/index.ts b/src/components/ui/radio-button/index.ts new file mode 100644 index 0000000..a4d8fe5 --- /dev/null +++ b/src/components/ui/radio-button/index.ts @@ -0,0 +1,4 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +export * from './radio-button'; diff --git a/src/components/ui/radio-button/radio-button.tsx b/src/components/ui/radio-button/radio-button.tsx new file mode 100644 index 0000000..069d2e8 --- /dev/null +++ b/src/components/ui/radio-button/radio-button.tsx @@ -0,0 +1,105 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import React, {Fragment} from 'react'; + +import {Tooltip, Position} from 'components/tooltip'; +import {Label} from 'components/label'; +import {ComponentWrapper, HelperText, RadioGroup, RadioWrapper, RadioButtonContainer, VisibleRadioButton} from './style'; + +interface IRadioItem { + label: string; + value: string; + tooltipMessage?: string; + tooltipPosition?: Position; + className?: string; + children?: React.JSX.Element; + disabled?: boolean; +} + +interface IRadioButtonGroup { + label?: string; + labelColor?: string; + labelIcon?: React.JSX.Element; + labelClassName?: string; + items: IRadioItem[]; + onChange: (value) => void; + currentValue: string; + error?: boolean; + helperText?: string; + helperTextClassName?: string; + width?: number | string; // TODO check after refactoring if it possible to restrict width + className?: string; + radioGroupClassName?: string; +} + +interface IRadioButton { + currentValue: string; + value: string; +} + +export const RadioButton = ({currentValue, value}: IRadioButton) => ( + + + +
+ + +); + +export const RadioButtonGroup = ({ + label: propLabel, + labelColor, + labelIcon, + labelClassName, + items, + onChange, + currentValue, + helperText, + helperTextClassName, + error, + width, + className: propClassName, + radioGroupClassName +}: IRadioButtonGroup): React.JSX.Element => { + return ( + + {!!propLabel && + ); +}; diff --git a/src/components/ui/radio-button/style.ts b/src/components/ui/radio-button/style.ts new file mode 100644 index 0000000..cfaf433 --- /dev/null +++ b/src/components/ui/radio-button/style.ts @@ -0,0 +1,81 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import * as styled from 'styled-components'; +import {theme, paddings} from 'components/shared/theme'; +import {IInput} from '../input'; + +const formInputWidth = 350; +const {spacing, primaryFontSize, colors, fontSizeS} = theme; + +export const ComponentWrapper = styled.default.div<{width: number | string}>` + position: relative; + width: ${({width}) => (width && isNaN(+width) ? width : (width || formInputWidth) + 'px')}; + display: flex; + flex-direction: column; +`; + +export const RadioGroup = styled.default.div<{color?: string}>` + display: flex; + flex-direction: column; + margin-top: ${spacing.small} 0; + label { + font-size: ${fontSizeS}; + color: ${({color}) => color}; + cursor: pointer; + } +`; + +export const RadioWrapper = styled.default.div<{disabled?: boolean}>` + padding: ${paddings.small}; + display: flex; + + ${({disabled}) => + disabled && + styled.css` + pointer-events: none; + opacity: 0.5; + `} +`; + +export const RadioButtonContainer = styled.default.div` + margin-right: ${spacing.xSmall}; + align-self: center; + + input { + position: absolute; + visibility: hidden; + } +`; + +export const VisibleRadioButton = styled.default.div<{checked?: boolean}>` + border: 2px solid ${colors.gray400}; + display: flex; + align-items: center; + justify-content: center; + width: ${primaryFontSize}; + height: ${primaryFontSize}; + border-radius: 50%; + cursor: pointer; + + ${({checked}) => + checked && + styled.css` + border: none; + background-color: ${colors.red}; + + div { + background-color: ${colors.black}; + width: 5px; + height: 5px; + border-radius: 50%; + } + `} +`; + +export const HelperText = styled.default.p` + color: ${({error}) => (error ? colors.lightRed : colors.gray600)}; + font-weight: 400; + font-size: ${fontSizeS}; + margin-top: ${spacing.xxSmall}; +`; diff --git a/src/components/ui/select/index.ts b/src/components/ui/select/index.ts new file mode 100644 index 0000000..e9a6b79 --- /dev/null +++ b/src/components/ui/select/index.ts @@ -0,0 +1,5 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +export {default as Select} from './select'; +export * from './select'; diff --git a/src/components/ui/select/select.tsx b/src/components/ui/select/select.tsx new file mode 100644 index 0000000..3b44b7c --- /dev/null +++ b/src/components/ui/select/select.tsx @@ -0,0 +1,68 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import React, {useState, useRef, useEffect, ChangeEvent} from 'react'; + +import {Label} from 'components/label'; + +import {ISelectItem} from 'interfaces'; + +import {SelectContainer, SubLabel} from './style'; + +export interface ISelectComponent { + label?: string; + labelColor?: string; + labelHtmlFor?: string; + items: ISelectItem[]; + onSelect: (item: ISelectItem) => void; + defaultItems: ISelectItem[]; // TODO change to defaultItem: ISelectItem and change subLabel to helperText (#CC-526) + subLabel?: string; + width?: number | string; // TODO check after refactoring if it possible restrict width +} + +const SelectComponent = ({label, items, onSelect, defaultItems, subLabel, labelColor, labelHtmlFor, width}: ISelectComponent): React.JSX.Element => { + const [selectedItems, setSelectedItems] = useState(defaultItems); + const [focusOnSelectComponent, setFocusOnSelectComponent] = useState(false); + const optsRef = useRef([]); + + useEffect(() => { + onSelect(selectedItems[0]); + }, [selectedItems, onSelect]); + + useEffect(() => { + if (optsRef.current[0]) { + optsRef.current[0].focus(); + } + }, [focusOnSelectComponent]); + + const handleFocus = () => { + setFocusOnSelectComponent(true); + }; + + const generateOptions = () => + items.map(({label, value}) => ( + + )); + const onSelectItem = (event: ChangeEvent) => { + const {target} = event; + const item = items.filter(({value}) => { + return target.value === value; + })[0]; + + setSelectedItems([item]); + }; + + return ( + + {!!label && + ); +}; + +export default SelectComponent; diff --git a/src/components/ui/select/style.ts b/src/components/ui/select/style.ts new file mode 100644 index 0000000..651fd47 --- /dev/null +++ b/src/components/ui/select/style.ts @@ -0,0 +1,39 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import * as styled from 'styled-components'; +import {theme, paddings} from 'components/shared/theme'; + +const {colors, spacing, primaryBorderRadius, fontSizeS, primaryInputHeight, formFieldWidth} = theme; + +/* Stylelint-disable property-no-vendor-prefix */ +export const SelectContainer = styled.default.div<{width?: number | string}>` + width: ${({width}) => (width && isNaN(+width) ? width : (width || formFieldWidth) + 'px')}; + + select { + padding: 0 ${paddings.small}; + width: 100%; + min-width: 12.25rem; + height: ${primaryInputHeight}; + display: flex; + align-items: center; + position: relative; + flex-wrap: wrap; + background-color: ${colors.white}; + border: none; + cursor: pointer; + border-radius: ${primaryBorderRadius}; + appearance: none; + } + + label { + display: block; + } +`; + +export const SubLabel = styled.default.p` + color: ${colors.gray600}; + font-weight: 400; + font-size: ${fontSizeS}; + margin-top: ${spacing.xxSmall}; +`; diff --git a/src/components/ui/styles.ts b/src/components/ui/styles.ts new file mode 100644 index 0000000..98e8038 --- /dev/null +++ b/src/components/ui/styles.ts @@ -0,0 +1,19 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import * as styled from 'styled-components'; + +export const FlexContainer = styled.default.div` + display: flex; + flex-wrap: wrap; +`; + +export const WideFlexContainer = styled.default.div` + display: flex; + flex-wrap: wrap; + width: 100%; +`; + +export const FormInputWrapper = styled.default.div` + margin: 0 1rem 1rem 0; + `; diff --git a/src/components/ui/textarea/index.ts b/src/components/ui/textarea/index.ts new file mode 100644 index 0000000..1ca2f3a --- /dev/null +++ b/src/components/ui/textarea/index.ts @@ -0,0 +1,5 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +export {default as Textarea} from './textarea'; +export * from './textarea'; diff --git a/src/components/ui/textarea/style.ts b/src/components/ui/textarea/style.ts new file mode 100644 index 0000000..7188931 --- /dev/null +++ b/src/components/ui/textarea/style.ts @@ -0,0 +1,43 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import {TextareaHTMLAttributes} from 'react'; +import * as styled from 'styled-components'; + +import {theme, paddings} from 'components/shared/theme'; +import {ConfirmButton} from 'components/buttons'; + +const formInputWidth = 350; +const {colors, spacing, primaryBorderRadius, fontSizeS} = theme; + +/* Stylelint-disable property-no-vendor-prefix */ +export const TextareaContainer = styled.default.div<{width: number | string}>` + position: relative; + width: ${({width}) => (width && isNaN(+width) ? width : (width || formInputWidth) + 'px')}; + display: flex; + flex-direction: column; +`; + +export const Textarea = styled.default.textarea & {error?: boolean}>` + width: 100%; + padding: ${paddings.medium}; + color: ${({color}) => color}; + background-color: ${colors.white}; + border-color: ${({error}) => (error ? colors.lightRed : 'transparent')}; + border-width: 1px; + border-style: solid; + border-radius: ${primaryBorderRadius}; + outline: none; + transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out; + + ~${ConfirmButton} { + margin: 1rem 0; + } +`; + +export const HelperText = styled.default.p<{error?: boolean}>` + color: ${({error}) => (error ? colors.lightRed : colors.gray600)}; + font-weight: 400; + font-size: ${fontSizeS}; + margin-top: ${spacing.xxSmall}; +`; diff --git a/src/components/ui/textarea/textarea.tsx b/src/components/ui/textarea/textarea.tsx new file mode 100644 index 0000000..80dadeb --- /dev/null +++ b/src/components/ui/textarea/textarea.tsx @@ -0,0 +1,47 @@ +/** + * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved. + */ +import React, {TextareaHTMLAttributes} from 'react'; + +import {Label} from 'components/label'; + +import {TextareaContainer, Textarea, HelperText} from './style'; + +interface ITextareaComponent extends TextareaHTMLAttributes { + label?: string; + labelColor?: string; + labelIcon?: React.JSX.Element; + labelClassName?: string; + error?: boolean; + helperText?: string; + helperTextClassName?: string; + width?: number | string; // TODO check after refactoring if it possible to restrict width +} + +const TextareaComponent = ({ + label, + labelColor, + labelIcon, + labelClassName, + value, + onChange, + color, + error, + helperText, + helperTextClassName, + width +}: ITextareaComponent): React.JSX.Element => { + return ( + + {!!label &&