├── .eslintignore ├── .eslintrc.json ├── .gitignore ├── .prettierignore ├── .prettierrc ├── LICENSE ├── README.md ├── images ├── ConfigPage_Advanced.png ├── ConfigPage_Base.png ├── ConfigPage_Configuring.png ├── ConfigPage_Disconnect.png ├── DockerMetrics.png ├── DockerMetrics_Paused.png ├── DockerMetrics_Unpausing.png ├── KSQL_CLI_Example.png ├── KSQL_Stream.gif ├── Metrics_PartitionMetrics.png ├── Overview.png ├── Paused.png ├── Pausing.png ├── Test_Messages_KSQL.png ├── Tests_KSQL.png ├── Tests_Messages.png ├── Tests_Topics.png ├── Unpausing.png ├── banner.png ├── banner_800x450.png ├── docker-metrics.gif ├── export-disconnect.gif ├── home-configuration.gif ├── kafka-metrics.gif ├── testing.gif ├── xkite-banner.png ├── xkite-core-banner.svg └── xkite-core-banner_28h.png ├── next-env.d.ts ├── next.config.js ├── next.d.ts ├── package.json ├── pages ├── 404.tsx ├── _app.tsx ├── _document.tsx ├── api │ ├── checkPort.ts │ ├── docker.ts │ ├── download.ts │ ├── grafana.ts │ ├── kite │ │ ├── connect │ │ │ └── kafka.ts │ │ ├── create.ts │ │ ├── deploy.ts │ │ ├── disconnect.ts │ │ ├── getConfig.ts │ │ ├── getConfigFile.ts │ │ ├── getKiteState.ts │ │ ├── getPackageBuild.ts │ │ ├── getSetup.ts │ │ ├── pause.ts │ │ ├── shutdown.ts │ │ └── unpause.ts │ ├── monitor.ts │ ├── socket.ts │ └── spring │ │ └── index.ts ├── components │ ├── accordions │ │ └── index.tsx │ ├── avatars │ │ └── index.tsx │ ├── badges │ │ └── index.tsx │ ├── buttons │ │ └── index.tsx │ ├── cards │ │ └── index.tsx │ ├── tabs │ │ └── index.tsx │ └── tooltips │ │ └── index.tsx ├── configuration │ └── index.tsx ├── connect │ └── index.tsx ├── dockerMetrics │ └── index.tsx ├── index.tsx ├── metrics │ ├── index.tsx │ └── logs │ │ └── index.tsx ├── status │ └── 500 │ │ └── index.tsx └── tests │ └── index.tsx ├── public ├── _redirects ├── android-chrome-192x192.png ├── android-chrome-512x512.png ├── apple-touch-icon.png ├── browserconfig.xml ├── favicon.ico ├── icon-16x16.png ├── icon-192x192.png ├── icon-256x256.png ├── icon-32x32.png ├── icon-512x512.png ├── manifest.json ├── mstile-150x150.png ├── robots.txt ├── safari-pinned-tab.svg ├── site.webmanifest ├── spinner.svg └── static │ └── images │ ├── avatars │ ├── 1.jpg │ ├── 2.jpg │ ├── 3.jpg │ ├── 4.jpg │ └── 5.jpg │ ├── logo │ ├── fake.png │ ├── fake2.png │ ├── google.svg │ ├── material-ui.svg │ ├── next-js.svg │ ├── typescript.svg │ └── xkite-logo.png │ ├── overview │ ├── accent_header.png │ ├── accent_sidebar.png │ ├── bottom_navigation.png │ ├── boxed_sidebar.png │ ├── collapsed_sidebar.png │ ├── extended_sidebar.png │ ├── figma.svg │ ├── hero-screenshot.png │ ├── management_screen_1.png │ ├── management_screen_2.png │ ├── management_screen_3.png │ ├── performance.png │ ├── rtl-preview.jpg │ ├── sketch.svg │ ├── tokyo-logo.png │ └── top_navigation.png │ ├── placeholders │ ├── covers │ │ ├── 1.jpg │ │ ├── 2.jpg │ │ ├── 3.jpg │ │ ├── 4.jpg │ │ ├── 5.jpg │ │ ├── 6.jpg │ │ ├── 7.jpg │ │ ├── automation-bg.jpg │ │ └── garden_camera.jpg │ ├── fitness │ │ ├── 1.jpg │ │ ├── 2.jpg │ │ ├── 3.jpg │ │ └── 4.jpg │ ├── illustrations │ │ ├── 1.svg │ │ ├── 2.png │ │ ├── 3.svg │ │ ├── 4.svg │ │ ├── 5.svg │ │ ├── 6.png │ │ ├── analysis.svg │ │ ├── authentication.svg │ │ ├── businessman.svg │ │ ├── handshake.svg │ │ ├── moving.svg │ │ ├── partly-cloudy-day-rain.svg │ │ ├── pressure-high.svg │ │ ├── security.svg │ │ ├── time.svg │ │ └── wireframe.svg │ ├── logo │ │ ├── adobe.jpg │ │ ├── airbnb-icon.svg │ │ ├── airbnb.svg │ │ ├── autodesk.jpg │ │ ├── bankofamerica.svg │ │ ├── bitcoin.png │ │ ├── cardano.png │ │ ├── coinbase.svg │ │ ├── deutschebank.svg │ │ ├── deutschebank_light.svg │ │ ├── discord-icon.svg │ │ ├── discord.svg │ │ ├── dribbble-icon.svg │ │ ├── ea.jpg │ │ ├── ethereum.png │ │ ├── facebook.svg │ │ ├── google-icon.svg │ │ ├── google-logo.jpg │ │ ├── google.svg │ │ ├── hp.jpg │ │ ├── ibm.jpg │ │ ├── ing.jpg │ │ ├── instagram-icon.svg │ │ ├── instagram.svg │ │ ├── mastercard.png │ │ ├── microsoft-icon.svg │ │ ├── microsoft.svg │ │ ├── netflix-icon.svg │ │ ├── netflix-logo.jpg │ │ ├── netflix.svg │ │ ├── oracle.jpg │ │ ├── orange.jpg │ │ ├── pinterest-icon.svg │ │ ├── ripple.png │ │ ├── slack-big.svg │ │ ├── slack-icon.svg │ │ ├── slack.svg │ │ ├── spotify copy.svg │ │ ├── spotify-icon.svg │ │ ├── spotify.svg │ │ ├── stripe.svg │ │ ├── tesla.svg │ │ ├── uipath.jpg │ │ ├── visa.png │ │ └── wellsfargo.svg │ └── products │ │ ├── 1.png │ │ ├── 10.png │ │ ├── 2.png │ │ ├── 3.png │ │ ├── 4.png │ │ ├── 5.png │ │ ├── 6.png │ │ ├── 7.png │ │ ├── 8.png │ │ └── 9.png │ └── status │ ├── 404.svg │ ├── 500.svg │ ├── coming-soon.svg │ └── maintenance.svg ├── src ├── common │ ├── constants │ │ └── index.ts │ ├── kafkaConnector │ │ ├── ConsumerFactory.ts │ │ ├── ProducerFactory.ts │ │ ├── index.ts │ │ └── types │ │ │ └── kafkaConnector.d.ts │ ├── monitor │ │ └── monitor.ts │ ├── types │ │ └── io.ts │ └── utilities │ │ ├── consumerUtil.ts │ │ ├── index.ts │ │ └── producerUtil.ts ├── components │ ├── Chart │ │ └── index.tsx │ ├── Footer │ │ └── index.tsx │ ├── Label │ │ └── index.tsx │ ├── Link │ │ └── index.tsx │ ├── Logo │ │ └── index.tsx │ ├── LogoSign │ │ └── index.tsx │ ├── PageTitle │ │ └── index.tsx │ ├── PageTitleWrapper │ │ └── index.tsx │ ├── Scrollbar │ │ └── index.tsx │ └── Text │ │ └── index.tsx ├── content │ ├── Applications │ │ └── Messenger │ │ │ ├── BottomBarContent.tsx │ │ │ ├── ChatContent.tsx │ │ │ ├── SidebarContent.tsx │ │ │ └── TopBarContent.tsx │ ├── Dashboards │ │ └── Tasks │ │ │ ├── ExportConfigBtn.tsx │ │ │ ├── PageHeader.tsx │ │ │ └── ShutdownBtn.tsx │ └── Overview │ │ └── Hero │ │ └── index.tsx ├── contexts │ └── SidebarContext.tsx ├── createEmotionCache.ts ├── layouts │ ├── BaseLayout │ │ └── index.tsx │ └── SidebarLayout │ │ ├── Header │ │ ├── Menu │ │ │ └── index.tsx │ │ └── index.tsx │ │ ├── Sidebar │ │ ├── SidebarMenu │ │ │ └── index.tsx │ │ └── index.tsx │ │ └── index.tsx ├── theme │ ├── ThemeProvider.tsx │ ├── base.ts │ └── schemes │ │ ├── DarkSpacesTheme.ts │ │ ├── GreenFieldsTheme.ts │ │ └── NebulaFighterTheme.ts ├── types.ts └── workers │ ├── configWorker.ts │ ├── ksqlWorker.ts │ └── testWorker.ts └── tsconfig.json /.eslintignore: -------------------------------------------------------------------------------- 1 | # .estlintignore file 2 | dist 3 | .next 4 | build 5 | node_modules/ -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["next/core-web-vitals", "plugin:prettier/recommended"], 3 | "rules": { 4 | "prettier/prettier": "off", 5 | "@next/next/no-img-element": "off", 6 | "jsx-a11y/alt-text": "off", 7 | "react/display-name": "off", 8 | "eslint-disable-next-line": "off", 9 | "react-hooks/exhaustive-deps": "off", 10 | "react/no-unescaped-entities": "off", 11 | "react/jsx-max-props-per-line": [ 12 | 1, 13 | { 14 | "maximum": 2, 15 | "when": "multiline" 16 | } 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # misc 7 | .DS_Store 8 | .env.local 9 | .env.development.local 10 | .env.test.local 11 | .env.production.local 12 | .env 13 | 14 | npm-debug.log* 15 | yarn-debug.log* 16 | yarn-error.log* 17 | 18 | # Next.js build output 19 | .next 20 | out 21 | 22 | # Nuxt.js build / generate output 23 | .nuxt 24 | dist 25 | 26 | # Gatsby files 27 | .cache/ 28 | # Comment in the public line in if your project uses Gatsby and not Next.js 29 | # https://nextjs.org/blog/next-9-1#public-directory-support 30 | # public 31 | 32 | # vuepress build output 33 | .vuepress/dist 34 | 35 | # vuepress v2.x temp and cache directory 36 | .temp 37 | 38 | # Docusaurus cache and generated files 39 | .docusaurus 40 | 41 | # Serverless directories 42 | .serverless/ 43 | 44 | # FuseBox cache 45 | .fusebox/ 46 | 47 | # DynamoDB Local files 48 | .dynamodb/ 49 | 50 | # TernJS port file 51 | .tern-port 52 | 53 | # Stores VSCode versions used for testing VSCode extensions 54 | .vscode-test 55 | 56 | # yarn v2 57 | .yarn/cache 58 | .yarn/unplugged 59 | .yarn/build-state.yml 60 | .yarn/install-state.gz 61 | .pnp.* 62 | 63 | ## Mac Files 64 | # General 65 | .DS_Store 66 | .AppleDouble 67 | .LSOverride 68 | 69 | # Icon must end with two \r 70 | Icon 71 | 72 | # Thumbnails 73 | ._* 74 | 75 | # Files that might appear in the root of a volume 76 | .DocumentRevisions-V100 77 | .fseventsd 78 | .Spotlight-V100 79 | .TemporaryItems 80 | .Trashes 81 | .VolumeIcon.icns 82 | .com.apple.timemachine.donotpresent 83 | 84 | # Directories potentially created on remote AFP share 85 | .AppleDB 86 | .AppleDesktop 87 | Network Trash Folder 88 | Temporary Items 89 | .apdisk 90 | 91 | 92 | ## Webstorm 93 | .idea 94 | 95 | # vscode 96 | .vscode 97 | 98 | package-lock.json 99 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Ignore artifacts: 2 | dist 3 | .next 4 | build 5 | node_modules/ -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "bracketSpacing": true, 3 | "printWidth": 80, 4 | "singleQuote": true, 5 | "trailingComma": "none", 6 | "tabWidth": 2, 7 | "useTabs": false, 8 | "bracketSameLine": false 9 | } 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /images/ConfigPage_Advanced.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/images/ConfigPage_Advanced.png -------------------------------------------------------------------------------- /images/ConfigPage_Base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/images/ConfigPage_Base.png -------------------------------------------------------------------------------- /images/ConfigPage_Configuring.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/images/ConfigPage_Configuring.png -------------------------------------------------------------------------------- /images/ConfigPage_Disconnect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/images/ConfigPage_Disconnect.png -------------------------------------------------------------------------------- /images/DockerMetrics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/images/DockerMetrics.png -------------------------------------------------------------------------------- /images/DockerMetrics_Paused.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/images/DockerMetrics_Paused.png -------------------------------------------------------------------------------- /images/DockerMetrics_Unpausing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/images/DockerMetrics_Unpausing.png -------------------------------------------------------------------------------- /images/KSQL_CLI_Example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/images/KSQL_CLI_Example.png -------------------------------------------------------------------------------- /images/KSQL_Stream.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/images/KSQL_Stream.gif -------------------------------------------------------------------------------- /images/Metrics_PartitionMetrics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/images/Metrics_PartitionMetrics.png -------------------------------------------------------------------------------- /images/Overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/images/Overview.png -------------------------------------------------------------------------------- /images/Paused.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/images/Paused.png -------------------------------------------------------------------------------- /images/Pausing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/images/Pausing.png -------------------------------------------------------------------------------- /images/Test_Messages_KSQL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/images/Test_Messages_KSQL.png -------------------------------------------------------------------------------- /images/Tests_KSQL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/images/Tests_KSQL.png -------------------------------------------------------------------------------- /images/Tests_Messages.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/images/Tests_Messages.png -------------------------------------------------------------------------------- /images/Tests_Topics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/images/Tests_Topics.png -------------------------------------------------------------------------------- /images/Unpausing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/images/Unpausing.png -------------------------------------------------------------------------------- /images/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/images/banner.png -------------------------------------------------------------------------------- /images/banner_800x450.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/images/banner_800x450.png -------------------------------------------------------------------------------- /images/docker-metrics.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/images/docker-metrics.gif -------------------------------------------------------------------------------- /images/export-disconnect.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/images/export-disconnect.gif -------------------------------------------------------------------------------- /images/home-configuration.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/images/home-configuration.gif -------------------------------------------------------------------------------- /images/kafka-metrics.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/images/kafka-metrics.gif -------------------------------------------------------------------------------- /images/testing.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/images/testing.gif -------------------------------------------------------------------------------- /images/xkite-banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/images/xkite-banner.png -------------------------------------------------------------------------------- /images/xkite-core-banner_28h.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/images/xkite-core-banner_28h.png -------------------------------------------------------------------------------- /next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | // const withImages = require('next-images'); 2 | 3 | // const redirects = { 4 | // async redirects() { 5 | // return [ 6 | // { 7 | // source: '/dashboards', 8 | // destination: '/dashboards/tasks', 9 | // permanent: true 10 | // } 11 | // ]; 12 | // } 13 | // }; 14 | 15 | // module.exports = withImages(redirects); 16 | /** @type {import('next').NextConfig} */ 17 | const nextConfig = { 18 | reactStrictMode: true, 19 | experimental: { 20 | nextScriptWorkers: true 21 | } 22 | }; 23 | 24 | module.exports = nextConfig; 25 | 26 | 27 | -------------------------------------------------------------------------------- /next.d.ts: -------------------------------------------------------------------------------- 1 | import type { ReactElement, ReactNode } from 'react'; 2 | import type { 3 | NextComponentType, 4 | NextPageContext 5 | } from 'next/dist/shared/lib/utils'; 6 | 7 | declare module 'next' { 8 | export declare type NextPage

= NextComponentType< 9 | NextPageContext, 10 | IP, 11 | P 12 | > & { 13 | getLayout?: (page: ReactElement) => ReactNode; 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "xkite", 3 | "version": "1.0.0", 4 | "title": "xkite: Kafka Integrated Testing Environment", 5 | "description": "A comprehensive prototyping, testing, and monitoring toolset built for Apache Kafka.", 6 | "author": "xkite Team- OpenSource Labs", 7 | "license": "MIT", 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/oslabs-beta/xkite" 11 | }, 12 | "scripts": { 13 | "next-dev": "next dev", 14 | "dev:6662": "next dev -p 6662", 15 | "dev": "concurrently \"next dev\" \"open http://localhost:3000\"", 16 | "build": "next build", 17 | "start": "next start", 18 | "lint": "next lint" 19 | }, 20 | "bin": { 21 | "xkite": "npm start" 22 | }, 23 | "keywords": [ 24 | "apache", 25 | "kafka", 26 | "kafkajs", 27 | "docker", 28 | "react", 29 | "nextjs", 30 | "typescript", 31 | "zookeeper", 32 | "xkite-core", 33 | "GUI" 34 | ], 35 | "dependencies": { 36 | "@builder.io/partytown": "^0.7.5", 37 | "@emotion/cache": "11.7.1", 38 | "@emotion/react": "11.9.0", 39 | "@emotion/server": "11.4.0", 40 | "@emotion/styled": "11.8.1", 41 | "@mui/core": "5.0.0-alpha.54", 42 | "@mui/icons-material": "5.8.2", 43 | "@mui/lab": "5.0.0-alpha.84", 44 | "@mui/material": "5.8.2", 45 | "@mui/styles": "5.8.0", 46 | "@next/font": "13.0.6", 47 | "@reduxjs/toolkit": "^1.9.3", 48 | "@types/next": "^9.0.0", 49 | "@types/nprogress": "0.2.0", 50 | "@types/numeral": "2.0.2", 51 | "@types/react": "17.0.40", 52 | "@types/react-dom": "17.0.13", 53 | "@types/kafkajs": "^1.9.0", 54 | "@types/socket.io-client": "^1.4.35", 55 | "apexcharts": "3.35.3", 56 | "clsx": "1.1.1", 57 | "concurrently": "^7.6.0", 58 | "date-fns": "2.28.0", 59 | "eslint": "8.34.0", 60 | "eslint-config-next": "13.0.6", 61 | "get-port": "^6.1.2", 62 | "i": "^0.3.7", 63 | "next": "12.1.6", 64 | "next-images": "1.8.4", 65 | "npm": "^9.6.0", 66 | "nprogress": "0.2.0", 67 | "numeral": "2.0.6", 68 | "react": "17.0.2", 69 | "react-apexcharts": "1.4.0", 70 | "react-custom-scrollbars-2": "4.4.0", 71 | "react-dom": "17.0.2", 72 | "react-flow-renderer": "^10.3.17", 73 | "react-spinners": "^0.13.8", 74 | "reactflow": "^11.5.6", 75 | "socket.io": "^4.6.1", 76 | "socket.io-client": "^3.1.2", 77 | "typescript": "4.7.3", 78 | "xkite-core": "^1.0.27", 79 | "child_process": "^1.0.2", 80 | "net": "^1.0.2", 81 | "kafkajs": "^2.2.3" 82 | }, 83 | "devDependencies": { 84 | "@types/node": "^18.14.6", 85 | "eslint": "8.17.0", 86 | "eslint-config-next": "12.1.6", 87 | "eslint-config-prettier": "8.5.0", 88 | "eslint-plugin-prettier": "4.0.0", 89 | "prettier": "^2.8.4", 90 | "prettier-eslint": "^15.0.1" 91 | }, 92 | "browser": { 93 | "child_process": false, 94 | "fs": false, 95 | "path": false 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /pages/404.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Box, 3 | Card, 4 | Typography, 5 | Container, 6 | Divider, 7 | Button, 8 | FormControl, 9 | OutlinedInput, 10 | InputAdornment, 11 | styled 12 | } from '@mui/material'; 13 | import Head from 'next/head'; 14 | import SearchTwoToneIcon from '@mui/icons-material/SearchTwoTone'; 15 | import type { ReactElement } from 'react'; 16 | import BaseLayout from 'src/layouts/BaseLayout'; 17 | 18 | const MainContent = styled(Box)( 19 | () => ` 20 | height: 100%; 21 | display: flex; 22 | flex: 1; 23 | flex-direction: column; 24 | ` 25 | ); 26 | 27 | const TopWrapper = styled(Box)( 28 | ({ theme }) => ` 29 | display: flex; 30 | width: 100%; 31 | flex: 1; 32 | align-items: center; 33 | justify-content: center; 34 | padding: ${theme.spacing(6)}; 35 | ` 36 | ); 37 | 38 | const OutlinedInputWrapper = styled(OutlinedInput)( 39 | ({ theme }) => ` 40 | background-color: ${theme.colors.alpha.white[100]}; 41 | ` 42 | ); 43 | 44 | const ButtonSearch = styled(Button)( 45 | ({ theme }) => ` 46 | margin-right: -${theme.spacing(1)}; 47 | ` 48 | ); 49 | 50 | function Status404() { 51 | return ( 52 | <> 53 | 54 | Status - 404 55 | 56 | 57 | 58 | 59 | 60 | 404 61 | 62 | The page you were looking for doesn't exist. 63 | 64 | 70 | It's on us, we moved the content to a different page. The search 71 | below should help! 72 | 73 | 74 | 75 | 76 | 77 | 82 | 83 | Search 84 | 85 | 86 | } 87 | startAdornment={ 88 | 89 | 90 | 91 | } 92 | /> 93 | 94 | OR 95 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | ); 105 | } 106 | 107 | export default Status404; 108 | 109 | Status404.getLayout = function getLayout(page: ReactElement) { 110 | return {page}; 111 | }; 112 | -------------------------------------------------------------------------------- /pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import type { ReactElement, ReactNode } from 'react'; 2 | 3 | import type { NextPage } from 'next'; 4 | import type { AppProps } from 'next/app'; 5 | import Head from 'next/head'; 6 | import Router from 'next/router'; 7 | import nProgress from 'nprogress'; 8 | import 'nprogress/nprogress.css'; 9 | import ThemeProvider from 'src/theme/ThemeProvider'; 10 | import CssBaseline from '@mui/material/CssBaseline'; 11 | import { CacheProvider, EmotionCache } from '@emotion/react'; 12 | import createEmotionCache from 'src/createEmotionCache'; 13 | import { SidebarProvider } from 'src/contexts/SidebarContext'; 14 | import AdapterDateFns from '@mui/lab/AdapterDateFns'; 15 | import LocalizationProvider from '@mui/lab/LocalizationProvider'; 16 | 17 | const clientSideEmotionCache = createEmotionCache(); 18 | 19 | type NextPageWithLayout = NextPage & { 20 | getLayout?: (page: ReactElement) => ReactNode; 21 | }; 22 | 23 | interface xKiteAppProps extends AppProps { 24 | emotionCache?: EmotionCache; 25 | Component: NextPageWithLayout; 26 | } 27 | 28 | function xKiteApp(props: xKiteAppProps) { 29 | const { Component, emotionCache = clientSideEmotionCache, pageProps } = props; 30 | const getLayout = Component.getLayout ?? ((page) => page); 31 | 32 | Router.events.on('routeChangeStart', nProgress.start); 33 | Router.events.on('routeChangeError', nProgress.done); 34 | Router.events.on('routeChangeComplete', nProgress.done); 35 | 36 | return ( 37 | 38 | 39 | xkite: Kafka Integrated Testing Environment 40 | 44 | 45 | 46 | 47 | 48 | 49 | {getLayout()} 50 | 51 | 52 | 53 | 54 | ); 55 | } 56 | 57 | export default xKiteApp; 58 | -------------------------------------------------------------------------------- /pages/_document.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import Document, { Html, Head, Main, NextScript } from 'next/document'; 3 | import createEmotionServer from '@emotion/server/create-instance'; 4 | import createEmotionCache from 'src/createEmotionCache'; 5 | 6 | export default class MyDocument extends Document { 7 | render() { 8 | return ( 9 | 10 | 11 | 12 | 13 | 17 | 18 | 19 |

20 | 21 | 22 | 23 | ); 24 | } 25 | } 26 | 27 | // `getInitialProps` belongs to `_document` (instead of `_app`), 28 | // it's compatible with static-site generation (SSG). 29 | MyDocument.getInitialProps = async (ctx) => { 30 | // Resolution order 31 | // 32 | // On the server: 33 | // 1. app.getInitialProps 34 | // 2. page.getInitialProps 35 | // 3. document.getInitialProps 36 | // 4. app.render 37 | // 5. page.render 38 | // 6. document.render 39 | // 40 | // On the server with error: 41 | // 1. document.getInitialProps 42 | // 2. app.render 43 | // 3. page.render 44 | // 4. document.render 45 | // 46 | // On the client 47 | // 1. app.getInitialProps 48 | // 2. page.getInitialProps 49 | // 3. app.render 50 | // 4. page.render 51 | 52 | const originalRenderPage = ctx.renderPage; 53 | 54 | // You can consider sharing the same emotion cache between all the SSR requests to speed up performance. 55 | // However, be aware that it can have global side effects. 56 | const cache = createEmotionCache(); 57 | const { extractCriticalToChunks } = createEmotionServer(cache); 58 | 59 | ctx.renderPage = () => 60 | originalRenderPage({ 61 | enhanceApp: (App: any) => (props) => 62 | 63 | }); 64 | 65 | const initialProps = await Document.getInitialProps(ctx); 66 | // This is important. It prevents emotion to render invalid HTML. 67 | // See https://github.com/mui-org/material-ui/issues/26561#issuecomment-855286153 68 | const emotionStyles = extractCriticalToChunks(initialProps.html); 69 | const emotionStyleTags = emotionStyles.styles.map((style) => ( 70 | Imported Layers -------------------------------------------------------------------------------- /public/static/images/placeholders/logo/deutschebank_light.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/static/images/placeholders/logo/discord-icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/static/images/placeholders/logo/discord.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/static/images/placeholders/logo/dribbble-icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/static/images/placeholders/logo/ea.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/public/static/images/placeholders/logo/ea.jpg -------------------------------------------------------------------------------- /public/static/images/placeholders/logo/ethereum.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/public/static/images/placeholders/logo/ethereum.png -------------------------------------------------------------------------------- /public/static/images/placeholders/logo/facebook.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/static/images/placeholders/logo/google-icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/static/images/placeholders/logo/google-logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/public/static/images/placeholders/logo/google-logo.jpg -------------------------------------------------------------------------------- /public/static/images/placeholders/logo/google.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/static/images/placeholders/logo/hp.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/public/static/images/placeholders/logo/hp.jpg -------------------------------------------------------------------------------- /public/static/images/placeholders/logo/ibm.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/public/static/images/placeholders/logo/ibm.jpg -------------------------------------------------------------------------------- /public/static/images/placeholders/logo/ing.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/public/static/images/placeholders/logo/ing.jpg -------------------------------------------------------------------------------- /public/static/images/placeholders/logo/instagram-icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/static/images/placeholders/logo/mastercard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/public/static/images/placeholders/logo/mastercard.png -------------------------------------------------------------------------------- /public/static/images/placeholders/logo/microsoft-icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/static/images/placeholders/logo/microsoft.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/static/images/placeholders/logo/netflix-icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/static/images/placeholders/logo/netflix-logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/public/static/images/placeholders/logo/netflix-logo.jpg -------------------------------------------------------------------------------- /public/static/images/placeholders/logo/netflix.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/static/images/placeholders/logo/oracle.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/public/static/images/placeholders/logo/oracle.jpg -------------------------------------------------------------------------------- /public/static/images/placeholders/logo/orange.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/public/static/images/placeholders/logo/orange.jpg -------------------------------------------------------------------------------- /public/static/images/placeholders/logo/pinterest-icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/static/images/placeholders/logo/ripple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/public/static/images/placeholders/logo/ripple.png -------------------------------------------------------------------------------- /public/static/images/placeholders/logo/slack-big.svg: -------------------------------------------------------------------------------- 1 | backgroundLayer 1 -------------------------------------------------------------------------------- /public/static/images/placeholders/logo/slack-icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/static/images/placeholders/logo/slack.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /public/static/images/placeholders/logo/spotify-icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/static/images/placeholders/logo/spotify.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/static/images/placeholders/logo/stripe.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/static/images/placeholders/logo/tesla.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/static/images/placeholders/logo/uipath.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/public/static/images/placeholders/logo/uipath.jpg -------------------------------------------------------------------------------- /public/static/images/placeholders/logo/visa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/public/static/images/placeholders/logo/visa.png -------------------------------------------------------------------------------- /public/static/images/placeholders/products/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/public/static/images/placeholders/products/1.png -------------------------------------------------------------------------------- /public/static/images/placeholders/products/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/public/static/images/placeholders/products/10.png -------------------------------------------------------------------------------- /public/static/images/placeholders/products/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/public/static/images/placeholders/products/2.png -------------------------------------------------------------------------------- /public/static/images/placeholders/products/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/public/static/images/placeholders/products/3.png -------------------------------------------------------------------------------- /public/static/images/placeholders/products/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/public/static/images/placeholders/products/4.png -------------------------------------------------------------------------------- /public/static/images/placeholders/products/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/public/static/images/placeholders/products/5.png -------------------------------------------------------------------------------- /public/static/images/placeholders/products/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/public/static/images/placeholders/products/6.png -------------------------------------------------------------------------------- /public/static/images/placeholders/products/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/public/static/images/placeholders/products/7.png -------------------------------------------------------------------------------- /public/static/images/placeholders/products/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/public/static/images/placeholders/products/8.png -------------------------------------------------------------------------------- /public/static/images/placeholders/products/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/xkite/683bc6c344b6e9298141e01b14a5bd7b34e03885/public/static/images/placeholders/products/9.png -------------------------------------------------------------------------------- /src/common/constants/index.ts: -------------------------------------------------------------------------------- 1 | import type { KiteConfig, YAMLServicesDefaultSetup } from 'xkite-core'; 2 | export const _ports_: YAMLServicesDefaultSetup = { 3 | postgresql: { internal: 5432, external: 5432 }, 4 | ksql: { internal: 8088, external: 8088 }, 5 | ksql_schema: { internal: 8085, external: 8085 }, 6 | spark: { 7 | webui: { internal: 8080, external: 8090 }, 8 | rpc: { internal: 7077, external: 7077 } 9 | }, 10 | spring: { internal: 8080, external: 8080 }, 11 | prometheus: { internal: 9090, external: 9099 }, 12 | grafana: { internal: 3000, external: 3050 }, 13 | jupyter: { internal: 8000, external: 8000 }, 14 | kafkaconnect_src: { internal: 8083, external: 8083 }, 15 | kafkaconnect_sink: { internal: 8083, external: 8084 }, 16 | zookeeper: { 17 | client: { internal: 2182, external: 2182 }, 18 | peer: { internal: 2888, external: 3888 } // only internal docker net 19 | }, 20 | kafka: { 21 | jmx: 9991, // only internal 22 | broker: { internal: 9092, external: 9092 }, 23 | spring: 9095, // only internal 24 | metrics: 29092, // only internal 25 | ksql: 9096, // only internal 26 | connect_src: 9097, 27 | connect_sink: 9098 28 | }, 29 | jmx: { internal: 5556, external: 5566 }, 30 | docker: { internal: 9323, external: 9323 } 31 | }; 32 | 33 | export const defaultCfg: KiteConfig = { 34 | kafka: { 35 | brokers: { 36 | size: 2, 37 | replicas: 2 38 | }, 39 | zookeepers: { 40 | size: 2 41 | }, 42 | jmx: { 43 | ports: [_ports_.jmx.external, _ports_.jmx.external + 1] 44 | }, 45 | spring: { 46 | port: _ports_.spring.external 47 | } 48 | }, 49 | db: { 50 | name: 'ksql', 51 | port: _ports_.ksql.external, 52 | kafkaconnect: { port: _ports_.kafkaconnect_src.external } 53 | }, 54 | sink: { 55 | name: 'spark', 56 | port: _ports_.spark.webui.external, 57 | rpc_port: _ports_.spark.rpc.external, 58 | kafkaconnect: { port: _ports_.kafkaconnect_sink.external } 59 | }, 60 | grafana: { 61 | port: _ports_.grafana.external 62 | }, 63 | prometheus: { 64 | scrape_interval: 20, 65 | evaluation_interval: 10, 66 | port: _ports_.prometheus.external 67 | } 68 | }; 69 | -------------------------------------------------------------------------------- /src/common/kafkaConnector/ConsumerFactory.ts: -------------------------------------------------------------------------------- 1 | import { Consumer, ConsumerSubscribeTopics, EachBatchPayload, Kafka, EachMessagePayload, KafkaConfig, Admin } from 'kafkajs' 2 | import { KafkaSetup } from './types/kafkaConnector' 3 | 4 | export default class ConsumerFactory { 5 | private kafkaConsumer: Consumer 6 | private admin: Admin 7 | //private messageProcessor: ExampleMessageProcessor 8 | 9 | public constructor(kafkaSetup: KafkaSetup) { 10 | //this.messageProcessor = messageProcessor 11 | this.kafkaConsumer = this.createKafkaConsumer(kafkaSetup.brokers, kafkaSetup.clientId) 12 | this.admin = this.createKafkaAdmin(kafkaSetup.brokers, kafkaSetup.clientId) 13 | } 14 | 15 | public async startConsumer(topicToFollow: string): Promise { 16 | console.log('starting consumer...') 17 | const topic: ConsumerSubscribeTopics = { 18 | topics: [topicToFollow], 19 | fromBeginning: false 20 | } 21 | 22 | try { 23 | await this.kafkaConsumer.connect() 24 | await this.kafkaConsumer.subscribe(topic) 25 | console.log('connecting') 26 | await this.kafkaConsumer.run({ 27 | eachMessage: async (messagePayload: EachMessagePayload) => { 28 | const { topic, partition, message } = messagePayload 29 | const prefix = `${topic}[${partition} | ${message.offset}] / ${message.timestamp}` 30 | console.log(`- ${prefix} ${message.key}#${message.value}`, 'from line 30 of consumerUtil') 31 | } 32 | }) 33 | } catch (error) { 34 | console.log('Error: ', error) 35 | } 36 | } 37 | 38 | public async startBatchConsumer(topicsToFollow: string[]): Promise { 39 | const topic: ConsumerSubscribeTopics = { 40 | topics: [...topicsToFollow], 41 | fromBeginning: false 42 | } 43 | 44 | try { 45 | await this.kafkaConsumer.connect() 46 | await this.kafkaConsumer.subscribe(topic) 47 | await this.kafkaConsumer.run({ 48 | eachBatch: async (eachBatchPayload: EachBatchPayload) => { 49 | const { batch } = eachBatchPayload 50 | for (const message of batch.messages) { 51 | const prefix = `${batch.topic}[${batch.partition} | ${message.offset}] / ${message.timestamp}` 52 | console.log(`- ${prefix} ${message.key}#${message.value}`, 'from line 52 of consumerUtil') 53 | } 54 | } 55 | }) 56 | } catch (error) { 57 | console.log('Error: ', error) 58 | } 59 | } 60 | 61 | public async listTopics(): Promise { 62 | 63 | try { 64 | const topics = await this.admin.listTopics() 65 | console.log(topics) 66 | return topics 67 | } catch (error) { 68 | console.log('Error: ', error) 69 | } 70 | } 71 | 72 | public async shutdown(): Promise { 73 | await this.kafkaConsumer.disconnect() 74 | } 75 | 76 | private createKafkaConsumer(brokers: string[], clientId: string): Consumer { 77 | const kafka = new Kafka({ 78 | clientId, 79 | brokers 80 | }) 81 | const consumer = kafka.consumer({ groupId: 'myGroup2' }) 82 | return consumer 83 | } 84 | 85 | private createKafkaAdmin(brokers: string[], clientId: string): Admin { 86 | const kafka = new Kafka({ 87 | clientId, 88 | brokers 89 | }) 90 | const admin = kafka.admin() 91 | return admin 92 | } 93 | } -------------------------------------------------------------------------------- /src/common/kafkaConnector/types/kafkaConnector.d.ts: -------------------------------------------------------------------------------- 1 | export interface KafkaSetup { 2 | clientId: string; 3 | brokers: Array; 4 | ssl?: boolean; 5 | } 6 | 7 | export interface msg { 8 | value: string; 9 | partition?: number | 0; 10 | } 11 | -------------------------------------------------------------------------------- /src/common/monitor/monitor.ts: -------------------------------------------------------------------------------- 1 | //Monitor class to help connect to Kafka monitoring 2 | const { spawn } = require('child_process'); 3 | 4 | export default class Monitor { 5 | public static initiate() { 6 | const port: number = parseInt(process.env.PORT2!, 10) || 6662; 7 | const child = spawn('open', [`http://localhost:${port}/display`]); 8 | child.on('error', (err: any) => { 9 | console.error('Failed to open localhost:', err); 10 | }); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/common/types/io.ts: -------------------------------------------------------------------------------- 1 | import { Server as NetServer, Socket } from "net"; 2 | import { NextApiResponse } from "next/types"; 3 | import { Server as SocketIOServer } from "socket.io"; 4 | 5 | export type NextApiResponseServerIO = NextApiResponse & { 6 | socket: Socket & { 7 | server: NetServer & { 8 | io: SocketIOServer 9 | }; 10 | }; 11 | }; 12 | -------------------------------------------------------------------------------- /src/common/utilities/consumerUtil.ts: -------------------------------------------------------------------------------- 1 | import { Consumer, ConsumerSubscribeTopics, EachBatchPayload, Kafka, EachMessagePayload, Admin } from 'kafkajs' 2 | 3 | export default class ExampleConsumer { 4 | private kafkaConsumer: Consumer 5 | private admin: Admin 6 | //private messageProcessor: ExampleMessageProcessor 7 | 8 | public constructor(brokers: string[], clientId: string) { 9 | //this.messageProcessor = messageProcessor 10 | this.kafkaConsumer = this.createKafkaConsumer(brokers, clientId) 11 | this.admin = this.createKafkaAdmin(brokers, clientId) 12 | } 13 | 14 | public async startConsumer(topicToFollow: string): Promise { 15 | console.log('starting consumer...') 16 | const topic: ConsumerSubscribeTopics = { 17 | topics: [topicToFollow], 18 | fromBeginning: false 19 | } 20 | 21 | try { 22 | await this.kafkaConsumer.connect() 23 | await this.kafkaConsumer.subscribe(topic) 24 | console.log('connecting') 25 | await this.kafkaConsumer.run({ 26 | eachMessage: async (messagePayload: EachMessagePayload) => { 27 | const { topic, partition, message } = messagePayload 28 | const prefix = `${topic}[${partition} | ${message.offset}] / ${message.timestamp}` 29 | console.log(`- ${prefix} ${message.key}#${message.value}`, 'from line 30 of consumerUtil') 30 | } 31 | }) 32 | } catch (error) { 33 | console.log('Error: ', error) 34 | } 35 | } 36 | 37 | public async startBatchConsumer(topicToFollow: string): Promise { 38 | const topic: ConsumerSubscribeTopics = { 39 | topics: [topicToFollow], 40 | fromBeginning: false 41 | } 42 | 43 | try { 44 | await this.kafkaConsumer.connect() 45 | await this.kafkaConsumer.subscribe(topic) 46 | await this.kafkaConsumer.run({ 47 | eachBatch: async (eachBatchPayload: EachBatchPayload) => { 48 | const { batch } = eachBatchPayload 49 | for (const message of batch.messages) { 50 | const prefix = `${batch.topic}[${batch.partition} | ${message.offset}] / ${message.timestamp}` 51 | console.log(`- ${prefix} ${message.key}#${message.value}`, 'from line 52 of consumerUtil') 52 | } 53 | } 54 | }) 55 | } catch (error) { 56 | console.log('Error: ', error) 57 | } 58 | } 59 | 60 | public async listTopics(): Promise { 61 | 62 | try { 63 | await this.admin.connect() 64 | const topics = await this.admin.listTopics() 65 | await this.admin.disconnect() 66 | console.log(topics); 67 | return topics; 68 | } catch (error) { 69 | console.log('Error: ', error) 70 | } 71 | } 72 | 73 | public async shutdown(): Promise { 74 | await this.kafkaConsumer.disconnect() 75 | } 76 | 77 | private createKafkaConsumer(brokers: string[], clientId: string): Consumer { 78 | const kafka = new Kafka({ 79 | clientId, 80 | brokers 81 | }) 82 | const consumer = kafka.consumer({ groupId: 'myGroup2' }) 83 | return consumer 84 | } 85 | 86 | private createKafkaAdmin(brokers: string[], clientId: string): Admin { 87 | const kafka = new Kafka({ 88 | clientId, 89 | brokers 90 | }) 91 | const admin = kafka.admin(); 92 | return admin; 93 | } 94 | } -------------------------------------------------------------------------------- /src/common/utilities/index.ts: -------------------------------------------------------------------------------- 1 | import { Readable } from 'stream'; 2 | import { networkInterfaces } from 'os'; 3 | 4 | // get first ipAddress on machine 5 | export function getIPAddress(): Function { 6 | let ipAddr!: string; 7 | const ifaces: any = networkInterfaces(); 8 | return () => { 9 | if (ipAddr !== undefined) return ipAddr; 10 | 11 | for (const dev in ifaces) { 12 | if (ipAddr) break; 13 | ifaces[dev].filter((details: any) => { 14 | if (details.family === 'IPv4' && details.internal === false) { 15 | ipAddr = details.address; 16 | } 17 | }); 18 | } 19 | return ipAddr; 20 | }; 21 | } 22 | 23 | export default class ReadableString extends Readable { 24 | private sent = false; 25 | 26 | constructor(private str: string | Buffer) { 27 | super(); 28 | } 29 | 30 | _read() { 31 | if (!this.sent) { 32 | if (!Buffer.isBuffer(this.str)) 33 | this.push(Buffer.from(this.str)); 34 | else 35 | this.push(this.str); 36 | this.sent = true; 37 | } else { 38 | this.push(null); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/common/utilities/producerUtil.ts: -------------------------------------------------------------------------------- 1 | import { Kafka, Message, Producer, ProducerBatch, TopicMessages } from 'kafkajs' 2 | 3 | interface Messageformat { a: string } 4 | 5 | export default class ProducerFactory { 6 | private producer: Producer 7 | 8 | constructor(brokers: string[], clientId: string) { 9 | this.producer = this.createProducer(brokers, clientId) 10 | } 11 | 12 | public async start(): Promise { 13 | try { 14 | await this.producer.connect() 15 | } catch (error) { 16 | console.log('Error connecting the producer: ', error) 17 | } 18 | } 19 | 20 | public async shutdown(): Promise { 21 | await this.producer.disconnect() 22 | } 23 | 24 | 25 | public async sendBatch(messages: Array, topic: string): Promise { 26 | const kafkaMessages: Array = messages.map((message) => { 27 | return { 28 | value: JSON.stringify(message) 29 | } 30 | }) 31 | 32 | const topicMessages: TopicMessages = { 33 | topic, 34 | messages: kafkaMessages 35 | } 36 | 37 | const batch: ProducerBatch = { 38 | topicMessages: [topicMessages] 39 | } 40 | 41 | await this.producer.sendBatch(batch) 42 | } 43 | 44 | private createProducer(brokers: string[], clientId: string) : Producer { 45 | 46 | const kafka = new Kafka({ 47 | clientId, 48 | brokers 49 | }) 50 | 51 | return kafka.producer() 52 | } 53 | } -------------------------------------------------------------------------------- /src/components/Chart/index.tsx: -------------------------------------------------------------------------------- 1 | import dynamic from 'next/dynamic'; 2 | 3 | export const Chart = dynamic(() => import('react-apexcharts'), { ssr: false }); 4 | -------------------------------------------------------------------------------- /src/components/Footer/index.tsx: -------------------------------------------------------------------------------- 1 | import { Box, Container, Typography, styled } from '@mui/material'; 2 | 3 | const FooterWrapper = styled(Container)( 4 | ({ theme }) => ` 5 | margin-top: ${theme.spacing(4)}; 6 | ` 7 | ); 8 | 9 | function Footer() { 10 | return ( 11 | 12 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | ); 27 | } 28 | 29 | export default Footer; 30 | -------------------------------------------------------------------------------- /src/components/Label/index.tsx: -------------------------------------------------------------------------------- 1 | import { FC, ReactNode } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { styled } from '@mui/material/styles'; 4 | 5 | interface LabelProps { 6 | className?: string; 7 | color?: 8 | | 'primary' 9 | | 'black' 10 | | 'secondary' 11 | | 'error' 12 | | 'warning' 13 | | 'success' 14 | | 'info'; 15 | children?: ReactNode; 16 | } 17 | 18 | const LabelWrapper = styled('span')( 19 | ({ theme }) => ` 20 | background-color: ${theme.colors.alpha.black[5]}; 21 | padding: ${theme.spacing(0.5, 1)}; 22 | font-size: ${theme.typography.pxToRem(13)}; 23 | border-radius: ${theme.general.borderRadius}; 24 | display: inline-flex; 25 | align-items: center; 26 | justify-content: center; 27 | max-height: ${theme.spacing(3)}; 28 | 29 | &.MuiLabel { 30 | &-primary { 31 | background-color: ${theme.colors.primary.lighter}; 32 | color: ${theme.palette.primary.main} 33 | } 34 | 35 | &-black { 36 | background-color: ${theme.colors.alpha.black[100]}; 37 | color: ${theme.colors.alpha.white[100]}; 38 | } 39 | 40 | &-secondary { 41 | background-color: ${theme.colors.secondary.lighter}; 42 | color: ${theme.palette.secondary.main} 43 | } 44 | 45 | &-success { 46 | background-color: ${theme.colors.success.lighter}; 47 | color: ${theme.palette.success.main} 48 | } 49 | 50 | &-warning { 51 | background-color: ${theme.colors.warning.lighter}; 52 | color: ${theme.palette.warning.main} 53 | } 54 | 55 | &-error { 56 | background-color: ${theme.colors.error.lighter}; 57 | color: ${theme.palette.error.main} 58 | } 59 | 60 | &-info { 61 | background-color: ${theme.colors.info.lighter}; 62 | color: ${theme.palette.info.main} 63 | } 64 | } 65 | ` 66 | ); 67 | 68 | const Label: FC = ({ 69 | className, 70 | color = 'secondary', 71 | children, 72 | ...rest 73 | }) => { 74 | return ( 75 | 76 | {children} 77 | 78 | ); 79 | }; 80 | 81 | Label.propTypes = { 82 | children: PropTypes.node, 83 | className: PropTypes.string, 84 | color: PropTypes.oneOf([ 85 | 'primary', 86 | 'black', 87 | 'secondary', 88 | 'error', 89 | 'warning', 90 | 'success', 91 | 'info' 92 | ]) 93 | }; 94 | 95 | export default Label; 96 | -------------------------------------------------------------------------------- /src/components/Link/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import clsx from 'clsx'; 3 | import { useRouter } from 'next/router'; 4 | import NextLink, { LinkProps as NextLinkProps } from 'next/link'; 5 | import MuiLink, { LinkProps as MuiLinkProps } from '@mui/material/Link'; 6 | import { styled } from '@mui/material/styles'; 7 | 8 | // Add support for the sx prop for consistency with the other branches. 9 | const Anchor = styled('a')({}); 10 | 11 | interface NextLinkComposedProps 12 | extends Omit, 'href'>, 13 | Omit { 14 | to: NextLinkProps['href']; 15 | linkAs?: NextLinkProps['as']; 16 | } 17 | 18 | export const NextLinkComposed = React.forwardRef< 19 | HTMLAnchorElement, 20 | NextLinkComposedProps 21 | >(function NextLinkComposed(props, ref) { 22 | const { to, linkAs, replace, scroll, shallow, prefetch, locale, ...other } = 23 | props; 24 | 25 | return ( 26 | 36 | 37 | 38 | ); 39 | }); 40 | 41 | export type LinkProps = { 42 | activeClassName?: string; 43 | as?: NextLinkProps['as']; 44 | href: NextLinkProps['href']; 45 | linkAs?: NextLinkProps['as']; // Useful when the as prop is shallow by styled(). 46 | noLinkStyle?: boolean; 47 | } & Omit & 48 | Omit; 49 | 50 | // A styled version of the Next.js Link component: 51 | // https://nextjs.org/docs/api-reference/next/link 52 | const Link = React.forwardRef(function Link( 53 | props, 54 | ref 55 | ) { 56 | const { 57 | activeClassName = 'active', 58 | as, 59 | className: classNameProps, 60 | href, 61 | linkAs: linkAsProp, 62 | locale, 63 | noLinkStyle, 64 | prefetch, 65 | replace, 66 | role, // Link don't have roles. 67 | scroll, 68 | shallow, 69 | ...other 70 | } = props; 71 | 72 | const router = useRouter(); 73 | const pathname = typeof href === 'string' ? href : href.pathname; 74 | const className = clsx(classNameProps, { 75 | [activeClassName]: router.pathname === pathname && activeClassName 76 | }); 77 | 78 | const isExternal = 79 | typeof href === 'string' && 80 | (href.indexOf('http') === 0 || href.indexOf('mailto:') === 0); 81 | 82 | if (isExternal) { 83 | if (noLinkStyle) { 84 | return ; 85 | } 86 | 87 | return ; 88 | } 89 | 90 | const linkAs = linkAsProp || as; 91 | const nextjsProps = { 92 | to: href, 93 | linkAs, 94 | replace, 95 | scroll, 96 | shallow, 97 | prefetch, 98 | locale 99 | }; 100 | 101 | if (noLinkStyle) { 102 | return ( 103 | 109 | ); 110 | } 111 | 112 | return ( 113 | 120 | ); 121 | }); 122 | 123 | export default Link; 124 | -------------------------------------------------------------------------------- /src/components/Logo/index.tsx: -------------------------------------------------------------------------------- 1 | import { Box, styled, Tooltip } from '@mui/material'; 2 | import Link from 'src/components/Link'; 3 | 4 | const LogoWrapper = styled(Link)( 5 | ({ theme }) => ` 6 | color: ${theme.palette.text.primary}; 7 | padding: ${theme.spacing(0, 1, 0, 0)}; 8 | display: flex; 9 | text-decoration: none; 10 | font-weight: ${theme.typography.fontWeightBold}; 11 | 12 | &:hover { 13 | text-decoration: none; 14 | } 15 | ` 16 | ); 17 | 18 | const LogoSignWrapper = styled(Box)( 19 | () => ` 20 | width: 52px; 21 | height: 38px; 22 | margin-top: 4px; 23 | transform: scale(.8); 24 | ` 25 | ); 26 | 27 | const LogoSign = styled(Box)( 28 | ({ theme }) => ` 29 | background: ${theme.general.reactFrameworkColor}; 30 | width: 18px; 31 | height: 18px; 32 | border-radius: ${theme.general.borderRadiusSm}; 33 | position: relative; 34 | transform: rotate(45deg); 35 | top: 3px; 36 | left: 17px; 37 | 38 | &:after, 39 | &:before { 40 | content: ""; 41 | display: block; 42 | width: 18px; 43 | height: 18px; 44 | position: absolute; 45 | top: -1px; 46 | right: -20px; 47 | transform: rotate(0deg); 48 | border-radius: ${theme.general.borderRadiusSm}; 49 | } 50 | 51 | &:before { 52 | background: ${theme.palette.primary.main}; 53 | right: auto; 54 | left: 0; 55 | top: 20px; 56 | } 57 | 58 | &:after { 59 | background: ${theme.palette.secondary.main}; 60 | } 61 | ` 62 | ); 63 | 64 | const LogoSignInner = styled(Box)( 65 | ({ theme }) => ` 66 | width: 16px; 67 | height: 16px; 68 | position: absolute; 69 | top: 12px; 70 | left: 12px; 71 | z-index: 5; 72 | border-radius: ${theme.general.borderRadiusSm}; 73 | background: ${theme.header.background}; 74 | ` 75 | ); 76 | 77 | const LogoTextWrapper = styled(Box)( 78 | ({ theme }) => ` 79 | padding-left: ${theme.spacing(1)}; 80 | ` 81 | ); 82 | 83 | const VersionBadge = styled(Box)( 84 | ({ theme }) => ` 85 | background: ${theme.palette.success.main}; 86 | color: ${theme.palette.success.contrastText}; 87 | padding: ${theme.spacing(0.4, 1)}; 88 | border-radius: ${theme.general.borderRadiusSm}; 89 | text-align: center; 90 | display: inline-block; 91 | line-height: 1; 92 | font-size: ${theme.typography.pxToRem(11)}; 93 | ` 94 | ); 95 | // @ts-ignore 96 | const LogoText = styled(Box)( 97 | ({ theme }) => ` 98 | font-size: ${theme.typography.pxToRem(15)}; 99 | font-weight: ${theme.typography.fontWeightBold}; 100 | ` 101 | ); 102 | 103 | function Logo() { 104 | return ( 105 | 106 | 107 | 108 | 109 | 110 | 111 | 117 | 118 | 119 | 1.0 120 | 121 | 122 | 123 | 124 | 125 | ); 126 | } 127 | 128 | export default Logo; 129 | -------------------------------------------------------------------------------- /src/components/LogoSign/index.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Tooltip, 3 | Badge, 4 | TooltipProps, 5 | tooltipClasses, 6 | styled, 7 | useTheme 8 | } from '@mui/material'; 9 | import Link from 'src/components/Link'; 10 | 11 | const LogoWrapper = styled(Link)( 12 | ({ theme }) => ` 13 | color: ${theme.palette.text.primary}; 14 | display: flex; 15 | text-decoration: none; 16 | width: 0px; 17 | margin: auto; 18 | font-weight: ${theme.typography.fontWeightBold}; 19 | ` 20 | ); 21 | 22 | const TooltipWrapper = styled(({ className, ...props }: TooltipProps) => ( 23 | 24 | ))(({ theme }) => ({ 25 | [`& .${tooltipClasses.tooltip}`]: { 26 | backgroundColor: theme.colors.alpha.trueWhite[100], 27 | color: theme.palette.getContrastText(theme.colors.alpha.trueWhite[100]), 28 | fontSize: theme.typography.pxToRem(12), 29 | fontWeight: 'bold', 30 | borderRadius: theme.general.borderRadiusSm, 31 | boxShadow: 32 | '0 .2rem .8rem rgba(7,9,25,.18), 0 .08rem .15rem rgba(7,9,25,.15)' 33 | }, 34 | [`& .${tooltipClasses.arrow}`]: { 35 | color: theme.colors.alpha.trueWhite[100] 36 | } 37 | })); 38 | 39 | function Logo() { 40 | 41 | return ( 42 | 46 | 47 | 48 | 500 52 | 53 | 54 | 55 | ); 56 | } 57 | 58 | export default Logo; 59 | -------------------------------------------------------------------------------- /src/components/PageTitle/index.tsx: -------------------------------------------------------------------------------- 1 | import { FC } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { Typography, Grid } from '@mui/material'; 4 | 5 | interface PageTitleProps { 6 | heading?: string; 7 | subHeading?: string; 8 | docs?: string; 9 | } 10 | 11 | const PageTitle: FC = ({ 12 | heading = '', 13 | subHeading = '', 14 | docs = '', 15 | ...rest 16 | }) => { 17 | return ( 18 | 24 | 25 | 26 | {heading} 27 | 28 | {subHeading} 29 | 30 | 31 | 32 | 33 | ); 34 | }; 35 | 36 | PageTitle.propTypes = { 37 | heading: PropTypes.string, 38 | subHeading: PropTypes.string, 39 | docs: PropTypes.string 40 | }; 41 | 42 | export default PageTitle; 43 | -------------------------------------------------------------------------------- /src/components/PageTitleWrapper/index.tsx: -------------------------------------------------------------------------------- 1 | import { FC, ReactNode } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { Box, Container, styled } from '@mui/material'; 4 | 5 | const PageTitle = styled(Box)( 6 | ({ theme }) => ` 7 | padding: ${theme.spacing(4)}; 8 | ` 9 | ); 10 | 11 | interface PageTitleWrapperProps { 12 | children?: ReactNode; 13 | } 14 | 15 | const PageTitleWrapper: FC = ({ children }) => { 16 | return ( 17 | 18 | {children} 19 | 20 | ); 21 | }; 22 | 23 | PageTitleWrapper.propTypes = { 24 | children: PropTypes.node.isRequired 25 | }; 26 | 27 | export default PageTitleWrapper; 28 | -------------------------------------------------------------------------------- /src/components/Scrollbar/index.tsx: -------------------------------------------------------------------------------- 1 | import { FC, ReactNode } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { Scrollbars } from 'react-custom-scrollbars-2'; 4 | 5 | import { Box, useTheme } from '@mui/material'; 6 | 7 | interface ScrollbarProps { 8 | className?: string; 9 | children?: ReactNode; 10 | } 11 | 12 | const Scrollbar: FC = ({ className, children, ...rest }) => { 13 | const theme = useTheme(); 14 | 15 | return ( 16 | { 20 | return ( 21 | 33 | ); 34 | }} 35 | {...rest} 36 | > 37 | {children} 38 | 39 | ); 40 | }; 41 | 42 | Scrollbar.propTypes = { 43 | children: PropTypes.node, 44 | className: PropTypes.string 45 | }; 46 | 47 | export default Scrollbar; 48 | -------------------------------------------------------------------------------- /src/components/Text/index.tsx: -------------------------------------------------------------------------------- 1 | import { FC, ReactNode } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { styled } from '@mui/material/styles'; 4 | import clsx from 'clsx'; 5 | 6 | interface TextProps { 7 | className?: string; 8 | color?: 9 | | 'primary' 10 | | 'secondary' 11 | | 'error' 12 | | 'warning' 13 | | 'success' 14 | | 'info' 15 | | 'black'; 16 | flex?: boolean; 17 | children?: ReactNode; 18 | } 19 | 20 | const TextWrapper = styled('span')( 21 | ({ theme }) => ` 22 | display: inline-block; 23 | align-items: center; 24 | 25 | &.flexItem { 26 | display: inline-flex; 27 | } 28 | 29 | &.MuiText { 30 | 31 | &-black { 32 | color: ${theme.palette.common.black} 33 | } 34 | 35 | &-primary { 36 | color: ${theme.palette.primary.main} 37 | } 38 | 39 | &-secondary { 40 | color: ${theme.palette.secondary.main} 41 | } 42 | 43 | &-success { 44 | color: ${theme.palette.success.main} 45 | } 46 | 47 | &-warning { 48 | color: ${theme.palette.warning.main} 49 | } 50 | 51 | &-error { 52 | color: ${theme.palette.error.main} 53 | } 54 | 55 | &-info { 56 | color: ${theme.palette.info.main} 57 | } 58 | } 59 | ` 60 | ); 61 | 62 | const Text: FC = ({ 63 | className, 64 | color = 'secondary', 65 | flex, 66 | children, 67 | ...rest 68 | }) => { 69 | return ( 70 | 74 | {children} 75 | 76 | ); 77 | }; 78 | 79 | Text.propTypes = { 80 | children: PropTypes.node, 81 | className: PropTypes.string, 82 | color: PropTypes.oneOf([ 83 | 'primary', 84 | 'secondary', 85 | 'error', 86 | 'warning', 87 | 'success', 88 | 'info', 89 | 'black' 90 | ]) 91 | }; 92 | 93 | export default Text; 94 | -------------------------------------------------------------------------------- /src/content/Applications/Messenger/BottomBarContent.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Avatar, 3 | Tooltip, 4 | IconButton, 5 | Box, 6 | Button, 7 | styled, 8 | InputBase, 9 | useTheme 10 | } from '@mui/material'; 11 | import AttachFileTwoToneIcon from '@mui/icons-material/AttachFileTwoTone'; 12 | import SendTwoToneIcon from '@mui/icons-material/SendTwoTone'; 13 | 14 | const MessageInputWrapper = styled(InputBase)( 15 | ({ theme }) => ` 16 | font-size: ${theme.typography.pxToRem(18)}; 17 | padding: ${theme.spacing(1)}; 18 | width: 100%; 19 | ` 20 | ); 21 | 22 | const Input = styled('input')({ 23 | display: 'none' 24 | }); 25 | 26 | function BottomBarContent() { 27 | const theme = useTheme(); 28 | 29 | const user = { 30 | name: 'Catherine Pike', 31 | avatar: '/static/images/avatars/1.jpg' 32 | }; 33 | 34 | return ( 35 | 43 | 44 | 49 | 54 | 55 | 56 | 57 | 61 | 😀 62 | 63 | 64 | 65 | 66 | 71 | 72 | 75 | 76 | 77 | ); 78 | } 79 | 80 | export default BottomBarContent; 81 | -------------------------------------------------------------------------------- /src/content/Dashboards/Tasks/ExportConfigBtn.tsx: -------------------------------------------------------------------------------- 1 | import { SyntheticEvent, useState } from 'react'; 2 | import {Button} from '@mui/material'; 3 | 4 | 5 | export default function ExportConfigBtn() { 6 | const [exporting, setExport] = useState(false); 7 | 8 | async function exportConfigHandler(event: SyntheticEvent) { 9 | event.preventDefault(); 10 | setExport(true); 11 | 12 | console.log('Getting Config Zip…'); 13 | // const openWindow = window.open('/api/kite/getPackageBuild', '_blank'); 14 | fetch('/api/kite/getPackageBuild', { 15 | method: 'GET', 16 | headers: { Accept: 'application/zip' }, 17 | }) 18 | .then((response) => { 19 | if (!response.ok) { 20 | throw new Error('Network response was not ok'); 21 | } 22 | return response.blob(); 23 | }) 24 | .then((blob) => { 25 | const url = window.URL.createObjectURL(new Blob([blob])); 26 | const link = document.createElement('a'); 27 | link.href = url; 28 | link.setAttribute('download', 'package.zip'); 29 | document.body.appendChild(link); 30 | link.click(); 31 | link.remove(); 32 | setExport(false); 33 | }) 34 | .catch((error) => console.error(error)); 35 | } 36 | 37 | return ( 38 | 41 | ); 42 | } 43 | -------------------------------------------------------------------------------- /src/content/Dashboards/Tasks/PageHeader.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Typography, 3 | Button, 4 | Box, 5 | alpha, 6 | lighten, 7 | Avatar, 8 | styled 9 | } from '@mui/material'; 10 | import DocumentScannerTwoToneIcon from '@mui/icons-material/DocumentScannerTwoTone'; 11 | import AddAlertTwoToneIcon from '@mui/icons-material/AddAlertTwoTone'; 12 | 13 | const AvatarPageTitle = styled(Avatar)( 14 | ({ theme }) => ` 15 | width: ${theme.spacing(8)}; 16 | height: ${theme.spacing(8)}; 17 | color: ${theme.colors.primary.main}; 18 | margin-right: ${theme.spacing(2)}; 19 | background: ${ 20 | theme.palette.mode === 'dark' 21 | ? theme.colors.alpha.trueWhite[10] 22 | : theme.colors.alpha.white[50] 23 | }; 24 | box-shadow: ${ 25 | theme.palette.mode === 'dark' 26 | ? '0 1px 0 ' + 27 | alpha(lighten(theme.colors.primary.main, 0.8), 0.2) + 28 | ', 0px 2px 4px -3px rgba(0, 0, 0, 0.3), 0px 5px 16px -4px rgba(0, 0, 0, .5)' 29 | : '0px 2px 4px -3px ' + 30 | alpha(theme.colors.alpha.black[100], 0.4) + 31 | ', 0px 5px 16px -4px ' + 32 | alpha(theme.colors.alpha.black[100], 0.2) 33 | }; 34 | ` 35 | ); 36 | 37 | function PageHeader() { 38 | const user = { 39 | name: 'Catherine Pike', 40 | avatar: '/static/images/avatars/1.jpg' 41 | }; 42 | 43 | return ( 44 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | Welcome, {user.name}! 57 | 58 | 59 | Manage your day to day tasks with style! Enjoy a well built UI 60 | system. 61 | 62 | 63 | 64 | 65 | 68 | 69 | 70 | ); 71 | } 72 | 73 | export default PageHeader; 74 | -------------------------------------------------------------------------------- /src/content/Dashboards/Tasks/ShutdownBtn.tsx: -------------------------------------------------------------------------------- 1 | import { SyntheticEvent, useState } from 'react'; 2 | import { Button } from '@mui/material'; 3 | 4 | interface ShutDownBtnProps { 5 | id?: string; 6 | onClick: () => void; 7 | } 8 | 9 | export default function ShutDownBtn({ id }: ShutDownBtnProps) { 10 | const [shuttingDown, setShuttingDown] = useState(false); 11 | 12 | async function disconnectHandler(event: SyntheticEvent): Promise { 13 | setShuttingDown(true); 14 | console.log('Disconnecting…'); 15 | try { 16 | const response = await fetch('/api/kite/shutdown', { method: 'DELETE' }); 17 | console.log(response); 18 | } catch (error) { 19 | console.error('Error occurred during shutdown:', error); 20 | } 21 | setShuttingDown(false); 22 | } 23 | 24 | return ( 25 | 35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /src/content/Overview/Hero/index.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Box, 3 | Button, 4 | Container, 5 | Grid, 6 | Typography, 7 | styled 8 | } from '@mui/material'; 9 | 10 | import Link from 'src/components/Link'; 11 | 12 | const TypographyH1 = styled(Typography)( 13 | ({ theme }) => ` 14 | font-size: ${theme.typography.pxToRem(70)}; 15 | ` 16 | ); 17 | 18 | const TypographyH12 = styled(Typography)( 19 | ({ theme }) => ` 20 | font-size: ${theme.typography.pxToRem(55)}; 21 | ` 22 | ); 23 | 24 | const TypographyH2 = styled(Typography)( 25 | ({ theme }) => ` 26 | font-size: ${theme.typography.pxToRem(22)}; 27 | ` 28 | ); 29 | 30 | const LabelWrapper = styled(Box)( 31 | ({ theme }) => ` 32 | background-color: ${theme.colors.success.main}; 33 | color: ${theme.palette.success.contrastText}; 34 | font-weight: bold; 35 | border-radius: 30px; 36 | text-transform: uppercase; 37 | display: inline-block; 38 | font-size: ${theme.typography.pxToRem(11)}; 39 | padding: ${theme.spacing(0.5)} ${theme.spacing(1.5)}; 40 | margin-bottom: ${theme.spacing(2)}; 41 | ` 42 | ); 43 | 44 | function Hero() { 45 | return ( 46 | 47 | 53 | 54 | Version 1.0.0 55 | 56 | xkite: 57 | 58 | 59 | Kafka Integrated Testing Environment 60 | 61 | 67 | A comprehensive prototyping, testing, and monitoring toolset built for Apache Kafka. Use xKite to bootstrap your next project, or install 68 | our library into an existing project. Built by (and for) developers. 69 | 70 | 78 | 87 | 88 | 89 | xkite-logo 93 | 94 | ); 95 | } 96 | 97 | export default Hero; 98 | -------------------------------------------------------------------------------- /src/contexts/SidebarContext.tsx: -------------------------------------------------------------------------------- 1 | import { useState, ReactNode, createContext } from 'react'; 2 | type SidebarContext = { 3 | sidebarToggle: any; 4 | toggleSidebar: () => void; 5 | closeSidebar: () => void; 6 | }; 7 | 8 | // eslint-disable-next-line @typescript-eslint/no-redeclare 9 | export const SidebarContext = createContext( 10 | {} as SidebarContext 11 | ); 12 | 13 | type Props = { 14 | children: ReactNode; 15 | }; 16 | 17 | export function SidebarProvider({ children }: Props) { 18 | const [sidebarToggle, setSidebarToggle] = useState(false); 19 | const toggleSidebar = () => { 20 | setSidebarToggle(!sidebarToggle); 21 | }; 22 | 23 | const closeSidebar = () => { 24 | setSidebarToggle(false); 25 | }; 26 | 27 | return ( 28 | 31 | {children} 32 | 33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /src/createEmotionCache.ts: -------------------------------------------------------------------------------- 1 | import createCache from '@emotion/cache'; 2 | 3 | export default function createEmotionCache() { 4 | return createCache({ 5 | key: 'css' 6 | }); 7 | } 8 | -------------------------------------------------------------------------------- /src/layouts/BaseLayout/index.tsx: -------------------------------------------------------------------------------- 1 | import { FC, ReactNode } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { Box } from '@mui/material'; 4 | 5 | interface BaseLayoutProps { 6 | children?: ReactNode; 7 | } 8 | 9 | const BaseLayout: FC = ({ children }) => { 10 | return ( 11 | 18 | {children} 19 | 20 | ); 21 | }; 22 | 23 | BaseLayout.propTypes = { 24 | children: PropTypes.node 25 | }; 26 | 27 | export default BaseLayout; 28 | -------------------------------------------------------------------------------- /src/layouts/SidebarLayout/Header/index.tsx: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | 3 | import { 4 | Box, 5 | alpha, 6 | Stack, 7 | lighten, 8 | Divider, 9 | IconButton, 10 | Tooltip, 11 | styled, 12 | useTheme 13 | } from '@mui/material'; 14 | import MenuTwoToneIcon from '@mui/icons-material/MenuTwoTone'; 15 | import { SidebarContext } from 'src/contexts/SidebarContext'; 16 | import CloseTwoToneIcon from '@mui/icons-material/CloseTwoTone'; 17 | 18 | import HeaderMenu from './Menu'; 19 | 20 | const HeaderWrapper = styled(Box)( 21 | ({ theme }) => ` 22 | height: ${theme.header.height}; 23 | color: ${theme.header.textColor}; 24 | padding: ${theme.spacing(0, 2)}; 25 | right: 0; 26 | z-index: 6; 27 | background-color: ${alpha(theme.header.background, 0.95)}; 28 | backdrop-filter: blur(3px); 29 | position: fixed; 30 | justify-content: space-between; 31 | width: 100%; 32 | @media (min-width: ${theme.breakpoints.values.lg}px) { 33 | left: ${theme.sidebar.width}; 34 | width: auto; 35 | } 36 | ` 37 | ); 38 | 39 | function Header() { 40 | const { sidebarToggle, toggleSidebar } = useContext(SidebarContext); 41 | const theme = useTheme(); 42 | 43 | return ( 44 | 63 | } 66 | alignItems="center" 67 | spacing={2} 68 | > 69 | 70 | 71 | 72 | 79 | 80 | 81 | {!sidebarToggle ? ( 82 | 83 | ) : ( 84 | 85 | )} 86 | 87 | 88 | 89 | 90 | 91 | ); 92 | } 93 | 94 | export default Header; 95 | -------------------------------------------------------------------------------- /src/layouts/SidebarLayout/Sidebar/index.tsx: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react'; 2 | import Scrollbar from 'src/components/Scrollbar'; 3 | import { SidebarContext } from 'src/contexts/SidebarContext'; 4 | 5 | import { 6 | Box, 7 | Drawer, 8 | alpha, 9 | styled, 10 | Divider, 11 | useTheme, 12 | Button, 13 | lighten, 14 | darken 15 | } from '@mui/material'; 16 | 17 | import SidebarMenu from './SidebarMenu'; 18 | import Logo from 'src/components/LogoSign'; 19 | 20 | const SidebarWrapper = styled(Box)( 21 | ({ theme }) => ` 22 | width: ${theme.sidebar.width}; 23 | min-width: ${theme.sidebar.width}; 24 | color: ${theme.colors.alpha.trueWhite[70]}; 25 | position: relative; 26 | z-index: 7; 27 | height: 100%; 28 | padding-bottom: 68px; 29 | ` 30 | ); 31 | 32 | function Sidebar() { 33 | const { sidebarToggle, toggleSidebar } = useContext(SidebarContext); 34 | const closeSidebar = () => toggleSidebar(); 35 | const theme = useTheme(); 36 | 37 | return ( 38 | <> 39 | 56 | 57 | 58 | 64 | 65 | 66 | 67 | 74 | 75 | 76 | 81 | 82 | 92 | 100 | 101 | 102 | 108 | 109 | 110 | 111 | 118 | 119 | 120 | 121 | 122 | 123 | ); 124 | } 125 | 126 | export default Sidebar; 127 | -------------------------------------------------------------------------------- /src/layouts/SidebarLayout/index.tsx: -------------------------------------------------------------------------------- 1 | import { FC, ReactNode } from 'react'; 2 | import { Box, alpha, lighten, useTheme } from '@mui/material'; 3 | import PropTypes from 'prop-types'; 4 | 5 | import Sidebar from './Sidebar'; 6 | import Header from './Header'; 7 | 8 | interface SidebarLayoutProps { 9 | children?: ReactNode; 10 | } 11 | 12 | const SidebarLayout: FC = ({ children }) => { 13 | const theme = useTheme(); 14 | 15 | return ( 16 | <> 17 | 44 |
45 | 46 | 58 | {children} 59 | 60 | 61 | 62 | ); 63 | }; 64 | 65 | SidebarLayout.propTypes = { 66 | children: PropTypes.node 67 | }; 68 | 69 | export default SidebarLayout; 70 | -------------------------------------------------------------------------------- /src/theme/ThemeProvider.tsx: -------------------------------------------------------------------------------- 1 | import { FC, useState, createContext, useEffect } from 'react'; 2 | import { ThemeProvider } from '@mui/material'; 3 | import { themeCreator } from './base'; 4 | import { StylesProvider } from '@mui/styles'; 5 | 6 | export const ThemeContext = createContext((_themeName: string): void => {}); 7 | 8 | const ThemeProviderWrapper: FC = (props) => { 9 | const [themeName, _setThemeName] = useState('GreenFieldsTheme'); 10 | 11 | useEffect(() => { 12 | const curThemeName = 13 | window.localStorage.getItem('appTheme') || 'GreenFieldsTheme'; 14 | _setThemeName(curThemeName); 15 | }, []); 16 | 17 | const theme = themeCreator(themeName); 18 | const setThemeName = (themeName: string): void => { 19 | window.localStorage.setItem('appTheme', themeName); 20 | _setThemeName(themeName); 21 | }; 22 | 23 | return ( 24 | 25 | 26 | {props.children} 27 | 28 | 29 | ); 30 | }; 31 | 32 | export default ThemeProviderWrapper; 33 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | export type state = { 2 | httpLink: string 3 | } 4 | 5 | export type interactiveNode = { 6 | key: string, 7 | id: string, 8 | type?: 'input' | 'output', 9 | data: { label: JSX.Element }, 10 | position: { x: number, y: number } 11 | } -------------------------------------------------------------------------------- /src/workers/configWorker.ts: -------------------------------------------------------------------------------- 1 | // const query = { 2 | // ksql: 'LIST STREAMS;', //optional 3 | // sql: `SELECT * FROM ridersNearMountainView EMIT CHANGES;`, 4 | // }; 5 | 6 | // addEventListener('message', (event: MessageEvent) => { 7 | // postMessage(client.getData(event.data)) 8 | // }) 9 | 10 | // addEventListener('message', (event: MessageEvent) => { 11 | // console.log(JSON.stringify(event)); 12 | // client.request(event.data); 13 | // postMessage(client.getData); 14 | // }); 15 | import type { KiteState, KiteSetup, KiteConfig } from 'xkite-core'; 16 | 17 | globalThis.onmessage = async (event: MessageEvent) => { 18 | queryBackEnd(); 19 | 20 | const interval = setInterval(queryBackEnd, event.data); 21 | async function queryBackEnd() { 22 | try { 23 | const state = await fetch('/api/kite/getKiteState').then((data) => 24 | data.text() 25 | ); 26 | postMessage({ state }); 27 | const config: KiteConfig = await fetch('/api/kite/getConfig').then( 28 | (data) => data.json() 29 | ); 30 | 31 | let metricsReady = false; 32 | if (state === 'Running') { 33 | if (config.kafka.jmx?.ports !== undefined) { 34 | console.log(`http://localhost:${config.kafka.jmx.ports[0]}`); 35 | const resp = await fetch( 36 | `http://localhost:${config.kafka.jmx.ports[0]}`, 37 | { 38 | method: 'GET', 39 | mode: 'no-cors' 40 | } 41 | ); 42 | console.log(resp.status); 43 | metricsReady = resp.status === 0; 44 | if (metricsReady) clearInterval(interval); 45 | postMessage({ metricsReady }); 46 | // const text = await resp.text(); 47 | // console.log(text); 48 | // const expression = /jmx_scrape_error(\d+)./i; 49 | // const match = expression.exec(text); 50 | // metricsReady = match[1] === '0'; 51 | } 52 | } 53 | postMessage({ metricsReady }); 54 | } catch (err) { 55 | console.log(err); 56 | } 57 | } 58 | }; 59 | 60 | export {}; 61 | -------------------------------------------------------------------------------- /src/workers/ksqlWorker.ts: -------------------------------------------------------------------------------- 1 | // const query = { 2 | // ksql: 'LIST STREAMS;', //optional 3 | // sql: `SELECT * FROM ridersNearMountainView EMIT CHANGES;`, 4 | // }; 5 | 6 | // addEventListener('message', (event: MessageEvent) => { 7 | // postMessage(client.getData(event.data)) 8 | // }) 9 | 10 | // addEventListener('message', (event: MessageEvent) => { 11 | // console.log(JSON.stringify(event)); 12 | // client.request(event.data); 13 | // postMessage(client.getData); 14 | // }); 15 | 16 | globalThis.onmessage = async (event: MessageEvent<{ type: string; ksql: string }>) => { 17 | try { 18 | const resp = await fetch('/api/kite/getSetup'); 19 | const setup = await resp.json(); 20 | const isKSQL = (setup.dBSetup?.name ?? 'none') === 'ksql'; 21 | if (!isKSQL) { 22 | postMessage('KSQL DB not configured'); 23 | return; 24 | } 25 | const port = setup.dBSetup?.port ?? 8088; 26 | let url: string = `http://localhost:${port}/${ 27 | event.data.type ?? '/query-stream' 28 | }`; 29 | console.log(url); 30 | const response = await fetch(url, { 31 | method: 'POST', 32 | headers: { 33 | Accept: 'application/vnd.ksql.v1+json', 34 | 'Content-Type': 'application/vnd.ksql.v1+json' 35 | }, 36 | body: JSON.stringify({ 37 | ksql: event.data.ksql 38 | // streamsProperties: { 39 | // 'ksql.streams.auto.offset.reset': 'earliest' 40 | // } 41 | }) 42 | }); 43 | const reader = response.body?.getReader(); 44 | function push() { 45 | reader?.read().then(({ done, value }) => { 46 | if (done) { 47 | return; 48 | } 49 | //post chunk to main thread 50 | const streamData = new TextDecoder().decode(value); 51 | postMessage(streamData); 52 | //try to read message 53 | push(); 54 | }); 55 | } 56 | push(); 57 | } catch (err) { 58 | console.log(err); 59 | } 60 | } 61 | 62 | export {}; 63 | -------------------------------------------------------------------------------- /src/workers/testWorker.ts: -------------------------------------------------------------------------------- 1 | // const query = { 2 | // ksql: 'LIST STREAMS;', //optional 3 | // sql: `SELECT * FROM ridersNearMountainView EMIT CHANGES;`, 4 | // }; 5 | 6 | // addEventListener('message', (event: MessageEvent) => { 7 | // postMessage(client.getData(event.data)) 8 | // }) 9 | 10 | // addEventListener('message', (event: MessageEvent) => { 11 | // console.log(JSON.stringify(event)); 12 | // client.request(event.data); 13 | // postMessage(client.getData); 14 | // }); 15 | globalThis.onmessage = async (event: MessageEvent) => { 16 | try { 17 | const state = await fetch('/api/kite/getKiteState').then((data) => 18 | data.text() 19 | ); 20 | const setup = await fetch('/api/kite/getSetup').then((data) => data.json()); 21 | //send message to existing topic (commented out version is if you want to access spring endpoint directly) 22 | if (event.data.newMessage) { 23 | // await fetch(`http://localhost:${setup.spring.port}/api/kafka/publish`, { 24 | // method: 'POST', 25 | // headers: { 26 | // 'Content-Type': 'application/json' 27 | // }, 28 | // body: JSON.stringify({ 29 | // timestamp: Date.now.toString(), 30 | // message: event.data.newMessage 31 | // }) 32 | // }); 33 | await fetch('/api/kite/connect/kafka', { 34 | method: 'POST', 35 | headers: { 36 | 'Content-Type': 'application/json' 37 | }, 38 | body: JSON.stringify({ 39 | method: 'sendMessage', 40 | messages: [{ value: event.data.newMessage }], 41 | topic: event.data.topic 42 | }) 43 | }).then((data) => data.json()); 44 | } 45 | //creating a new topic 46 | else if (event.data.newTopic) { 47 | await fetch('/api/kite/connect/kafka', { 48 | method: 'POST', 49 | headers: { 50 | 'Content-Type': 'application/json' 51 | }, 52 | body: JSON.stringify({ 53 | method: 'createTopics', 54 | topic: event.data.newTopic 55 | }) 56 | }).then((data) => data.json()); 57 | } 58 | 59 | const topics = await fetch('/api/kite/connect/kafka', { 60 | method: 'POST', 61 | headers: { 62 | 'Content-Type': 'application/json' 63 | }, 64 | body: JSON.stringify({ 65 | method: 'getTopics' 66 | }) 67 | }).then((data) => data.json()); 68 | postMessage({ state, setup, topics }); 69 | } catch (err) { 70 | console.log(err); 71 | } 72 | }; 73 | 74 | export {}; 75 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "typeRoots": [ 5 | "./src/common/types", 6 | "node_modules/@types" 7 | ], 8 | "paths": { 9 | "@/*": [ 10 | "./src/*" 11 | ], 12 | "@/public/*": [ 13 | "./public/*" 14 | ] 15 | }, 16 | "allowJs": true, 17 | "allowSyntheticDefaultImports": true, 18 | "jsx": "preserve", 19 | "lib": [ 20 | "dom", 21 | "es2022" 22 | ], 23 | "module": "esnext", 24 | "moduleResolution": "node", 25 | "noEmit": true, 26 | "preserveConstEnums": true, 27 | "removeComments": false, 28 | "skipLibCheck": true, 29 | "sourceMap": true, 30 | "strict": true, 31 | "strictPropertyInitialization": false, 32 | "strictNullChecks": false, 33 | "target": "esnext", 34 | "forceConsistentCasingInFileNames": true, 35 | "esModuleInterop": true, 36 | "resolveJsonModule": true, 37 | "isolatedModules": true, 38 | "noFallthroughCasesInSwitch": true, 39 | "incremental": true, 40 | "noImplicitAny": true 41 | }, 42 | "exclude": [ 43 | "node_modules" 44 | ], 45 | "include": [ 46 | "src", 47 | "next-env.d.ts", 48 | "**/*.ts", 49 | "**/*.tsx" 50 | ] 51 | } 52 | --------------------------------------------------------------------------------