├── .babelrc ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── codeql-analysis.yml │ ├── createPackages.yml │ └── unit-tests.yml ├── .gitignore ├── .prettierignore ├── .prettierrc ├── CONTRIBUTING.md ├── Dockerfile-dev ├── ISSUE_TEMPLATE.md ├── LICENSE.txt ├── README.md ├── ReactDevToolsWebExtDep ├── icons │ ├── 128-deadcode.png │ ├── 128-development.png │ ├── 128-disabled.png │ ├── 128-outdated.png │ ├── 128-production.png │ ├── 128-restricted.png │ ├── 128-unminified.png │ ├── 16-deadcode.png │ ├── 16-development.png │ ├── 16-disabled.png │ ├── 16-outdated.png │ ├── 16-production.png │ ├── 16-restricted.png │ ├── 16-unminified.png │ ├── 32-deadcode.png │ ├── 32-development.png │ ├── 32-disabled.png │ ├── 32-outdated.png │ ├── 32-production.png │ ├── 32-restricted.png │ ├── 32-unminified.png │ ├── 48-deadcode.png │ ├── 48-development.png │ ├── 48-disabled.png │ ├── 48-outdated.png │ ├── 48-production.png │ ├── 48-restricted.png │ ├── 48-unminified.png │ ├── deadcode.svg │ ├── development.svg │ ├── disabled.svg │ ├── outdated.svg │ ├── production.svg │ └── restricted.svg ├── main.html ├── manifest.json ├── panel.html ├── popups │ ├── deadcode.html │ ├── development.html │ ├── disabled.html │ ├── outdated.html │ ├── production.html │ ├── restricted.html │ ├── shared.css │ ├── shared.js │ └── unminified.html └── rbuild │ ├── background.js │ ├── importFile.worker.worker.js │ ├── installHook.js │ ├── main.js │ ├── panel.js │ ├── parseHookNames.chunk.js │ ├── parseSourceAndMetadata.worker.worker.js │ ├── prepareInjection.js │ ├── proxy.js │ ├── react_devtools_backend.js │ ├── renderer.js │ └── vendors~parseHookNames.chunk.js ├── ReadMeGifs ├── Gifs │ ├── Assertion-Testing.gif │ ├── DarkMode.gif │ ├── FileUploadAndDarkMode.gif │ ├── GQL-introspection.gif │ ├── GraphQL.gif │ ├── GraphQLTest.gif │ ├── HttpStressTest.gif │ ├── HttpTesting.gif │ ├── MockServer.gif │ ├── ServerSideEvents.gif │ ├── SimpleResponseTest.gif │ ├── Websockets.gif │ ├── gRPC-responses.gif │ ├── gRPC.gif │ ├── openapi.gif │ ├── trpc.gif │ └── webrtc.gif └── Videos │ ├── Long Feature Videos │ ├── 720-MP4s │ │ ├── GRPCResponses.mp4 │ │ ├── GraphQL.mp4 │ │ ├── Http2Streams.mp4 │ │ ├── Response History.mp4 │ │ ├── RestRequests.mp4 │ │ ├── SavedWorkspaces.mp4 │ │ └── WebSockets.mp4 │ └── Original_Format │ │ ├── GRPCResponses.mov │ │ ├── GraphQL.mov │ │ ├── Http2Streams.mov │ │ ├── Response History.mov │ │ ├── RestRequests.mov │ │ ├── SavedWorkspaces.mov │ │ └── WebSockets.mov │ └── Short Feature Videos │ ├── 720-MP4s │ ├── ConcurrentStreams.mp4 │ ├── CopyToComposer.mp4 │ ├── GQL-introspection.mp4 │ ├── History.mp4 │ ├── Intelligent GraphQL completion.mp4 │ ├── SSE.mp4 │ └── SavedWorkspace.mp4 │ └── Original_Format │ ├── ConcurrentStreams.mov │ ├── CopyToComposer.mov │ ├── GQL-introspection.mov │ ├── History.mov │ ├── Intelligent GraphQL completion.mov │ ├── SSE.mov │ └── SavedWorkspace.mov ├── build ├── 512x512.png ├── background.png ├── background@2x.png ├── config.gypi ├── icon.icns ├── icon.ico ├── icon.png └── icons │ ├── 512x512.png │ ├── mac │ └── Swell.icns │ ├── png │ ├── 1024x1024.png │ ├── 128x128.png │ ├── 16x16.png │ ├── 24x24.png │ ├── 256x256.png │ ├── 32x32.png │ ├── 48x48.png │ ├── 512x512.png │ ├── 64x64.png │ └── 96x96.png │ └── win │ └── Swell.ico ├── docs ├── DEV-README.md ├── How to test GRPC ├── vcxsrv_alt_disable_access_control.png ├── vcxsrv_client_startup.png ├── vcxsrv_disable_access_control.png └── vcxsrv_display_settings.png ├── electron-builder.yml ├── index-csp.html ├── jest.config.js ├── main.js ├── main_process ├── SSEController.js ├── main_graphqlController.js ├── main_grpcController.js ├── main_httpController.js ├── main_mockController.js ├── main_testingController.js ├── main_touchbar.js ├── main_trpcController.js ├── main_wsController.js ├── openapiParser.js └── protoParser.js ├── menu └── mainMenu.js ├── package.json ├── patches └── istanbul+0.4.5.patch ├── preload.js ├── src ├── assets │ ├── icons │ │ ├── 64x64.png │ │ ├── arrow_drop_down_white_192x192.png │ │ ├── caret-down-tests.svg │ │ ├── caret-down-white.svg │ │ ├── caret-down.svg │ │ ├── caret-left-white.svg │ │ ├── caret-left.svg │ │ ├── caret-right-white.svg │ │ ├── caret-right.svg │ │ ├── caret-up-tests.svg │ │ ├── caret-up-white.svg │ │ ├── caret-up.svg │ │ ├── clipboard-icon.svg │ │ ├── night-mode.svg │ │ └── sun.svg │ ├── img │ │ ├── Trashcan.png │ │ ├── horizontal-logo-lockup.png │ │ ├── swell-logo-faded.avif │ │ └── swell-logo-faded.png │ └── style │ │ ├── App.scss │ │ ├── WebRtc.css │ │ ├── base.scss │ │ ├── colors.scss │ │ ├── darkMode.scss │ │ ├── infinite.css │ │ ├── responsepane.scss │ │ ├── sidebar.scss │ │ ├── webSocketResponse.scss │ │ └── workspace.scss ├── client │ ├── components │ │ ├── .DS_Store │ │ ├── App.tsx │ │ ├── Versions.tsx │ │ ├── customMuiStyles │ │ │ └── tooltip.tsx │ │ ├── legacy-components │ │ │ ├── HistoryConatainerBackup.tsx │ │ │ ├── Http2Body.tsx │ │ │ ├── Http2MetaData.tsx │ │ │ ├── HttpBodyTypeSelect.tsx │ │ │ ├── MainContainer.backup │ │ │ └── UpdatePopUpContainer.jsx │ │ ├── main │ │ │ ├── GRPC-composer │ │ │ │ ├── GRPCAutoInputForm.tsx │ │ │ │ ├── GRPCBodyEntryForm.tsx │ │ │ │ ├── GRPCBodyStream.tsx │ │ │ │ ├── GRPCComposer.tsx │ │ │ │ ├── GRPCProtoEntryForm.tsx │ │ │ │ ├── GRPCServiceOrRequestSelect.tsx │ │ │ │ └── GRPCTypeAndEndpointEntryForm.tsx │ │ │ ├── GraphQL-composer │ │ │ │ ├── GraphQLBodyEntryForm.tsx │ │ │ │ ├── GraphQLComposer.tsx │ │ │ │ ├── GraphQLIntrospectionLog.tsx │ │ │ │ ├── GraphQLMethodAndEndpointEntryForm.tsx │ │ │ │ └── GraphQLVariableEntryForm.tsx │ │ │ ├── MainContainer.tsx │ │ │ ├── MockServer-composer │ │ │ │ └── MockServerComposer.tsx │ │ │ ├── OpenAPI-composer │ │ │ │ ├── OpenAPIComposer.tsx │ │ │ │ ├── OpenAPIDocumentEntryForm.tsx │ │ │ │ ├── OpenAPIEntryForm.tsx │ │ │ │ ├── OpenAPIMetadata.tsx │ │ │ │ └── OpenAPIServerForm.tsx │ │ │ ├── TRPC-composer │ │ │ │ ├── TRPCBodyEntryForm.tsx │ │ │ │ ├── TRPCComposer.tsx │ │ │ │ ├── TRPCMethodAndEndpointEntryForm.tsx │ │ │ │ ├── TRPCPrceduresEndPoint.tsx │ │ │ │ ├── TRPCProcedure.tsx │ │ │ │ ├── TRPCProceduresContainer.tsx │ │ │ │ ├── TRPCSubscriptionContainer.tsx │ │ │ │ └── TRPCVariableForm.tsx │ │ │ ├── WebHook-composer │ │ │ │ └── WebhookComposer.tsx │ │ │ ├── WebRTC-composer │ │ │ │ ├── WebRTCAudioBox.tsx │ │ │ │ ├── WebRTCComposer.tsx │ │ │ │ ├── WebRTCServerEntryForm.tsx │ │ │ │ ├── WebRTCSessionEntryForm.tsx │ │ │ │ └── WebRTCVideoBox.tsx │ │ │ ├── WebSocket-composer │ │ │ │ ├── WSEndpointEntryForm.tsx │ │ │ │ └── WebSocketComposer.tsx │ │ │ ├── http2-composer │ │ │ │ ├── Http2Composer.tsx │ │ │ │ ├── Http2EndpointForm.tsx │ │ │ │ ├── KeyValueForm.tsx │ │ │ │ ├── KeyValueTable.tsx │ │ │ │ └── RestMethodAndEndpointEntryForm.jsx │ │ │ ├── response-composer │ │ │ │ ├── CookieContainer.tsx │ │ │ │ ├── CookiesContainer.tsx │ │ │ │ ├── EmptyState.tsx │ │ │ │ ├── EventPreview.tsx │ │ │ │ ├── EventsContainer.tsx │ │ │ │ ├── HeadersContainer.tsx │ │ │ │ ├── ResponsePaneContainer.tsx │ │ │ │ ├── ResponseTime.tsx │ │ │ │ ├── SingleTestContainer.tsx │ │ │ │ ├── StatusButtons.tsx │ │ │ │ ├── TestsContainer.tsx │ │ │ │ ├── WebSocketMessage.tsx │ │ │ │ ├── WebSocketWindow.tsx │ │ │ │ └── webRTCResponseComponents │ │ │ │ │ ├── WebRTCTextContainer.tsx │ │ │ │ │ └── WebRTCTextItem.tsx │ │ │ └── sharedComponents │ │ │ │ ├── JSONTextArea.tsx │ │ │ │ ├── TextCodeArea.tsx │ │ │ │ ├── requestButtons │ │ │ │ ├── BinaryUploadFile.tsx │ │ │ │ ├── BodyTypeSelect.tsx │ │ │ │ ├── JSONPrettifyButton.tsx │ │ │ │ ├── NewRequestButton.tsx │ │ │ │ ├── RawBodyTypeSelect.tsx │ │ │ │ └── SendRequestButton.tsx │ │ │ │ ├── requestForms │ │ │ │ ├── BodyEntryForm.tsx │ │ │ │ ├── ContentReqRowComposer.tsx │ │ │ │ ├── CookieEntryForm.tsx │ │ │ │ ├── HeaderEntryForm.tsx │ │ │ │ ├── TestEntryForm.tsx │ │ │ │ └── WWWForm.tsx │ │ │ │ └── stressTest │ │ │ │ ├── LoadTest.ts │ │ │ │ ├── RestTestSnippets.tsx │ │ │ │ ├── TestContainer.tsx │ │ │ │ ├── TestSnippetsButton.tsx │ │ │ │ └── WebsocketTestSnippets.tsx │ │ ├── navbar │ │ │ ├── DarkModeSelect.tsx │ │ │ ├── GeneralInfo.tsx │ │ │ ├── NavBarContainer.tsx │ │ │ └── ProtocolSelect.tsx │ │ ├── utilities │ │ │ └── ErrorBoundary │ │ │ │ └── ErrorBoundary.tsx │ │ └── workspace │ │ │ ├── History.tsx │ │ │ ├── HistoryContainer.tsx │ │ │ ├── HistoryDate.tsx │ │ │ ├── HistoryOrWorkspaceContainer.tsx │ │ │ ├── WorkspaceCollectionElement.jsx │ │ │ ├── WorkspaceCollectionsContainer.tsx │ │ │ ├── WorkspaceContainer.tsx │ │ │ ├── WorkspaceContextMenu.tsx │ │ │ ├── WorkspaceSelect.tsx │ │ │ ├── buttons │ │ │ ├── ClearHistoryBtn.tsx │ │ │ ├── DeleteRequestButton.tsx │ │ │ ├── DeleteWorkspaceButton.tsx │ │ │ ├── ImportExportWorkspaceButton.tsx │ │ │ └── WorkspaceContainerButtons.tsx │ │ │ └── modals │ │ │ ├── SaveModalSavedWorkspaces.tsx │ │ │ ├── SaveWorkspaceModal.tsx │ │ │ ├── export-workspace │ │ │ └── ExportWorkspaceModal.tsx │ │ │ ├── import-export-workspace │ │ │ └── ImportExportWorkspaceModal.tsx │ │ │ └── import-workspace │ │ │ └── ImportWorkspaceModal.tsx │ ├── controllers │ │ ├── LoadTestController.ts │ │ ├── collectionsController.ts │ │ ├── graphQLController.ts │ │ ├── grpcController.ts │ │ ├── historyController.ts │ │ ├── openApiController.ts │ │ ├── reqResController.ts │ │ └── webrtcPeerController.ts │ ├── db.ts │ └── toolkit-refactor │ │ ├── hooks.ts │ │ ├── rootReducer.ts │ │ ├── slices │ │ ├── collectionsSlice.ts │ │ ├── graphPointsSlice.ts │ │ ├── historySlice.ts │ │ ├── introspectionDataSlice.ts │ │ ├── mockServerSlice.ts │ │ ├── newRequestFieldsSlice.ts │ │ ├── newRequestOpenApiSlice.ts │ │ ├── newRequestSlice.ts │ │ ├── reqResSlice.ts │ │ ├── uiSlice.ts │ │ └── warningMessageSlice.ts │ │ └── store.ts ├── declarations.d.ts ├── helpers.ts ├── images.d.ts ├── index.js ├── server │ ├── mockServer.js │ ├── server.js │ └── server.ts ├── svg.d.ts └── types.ts ├── test ├── HTTP2_cert.pem ├── HTTP2_private.pem ├── HTTP2_server.js ├── IntegrationTests │ ├── graphqlIntegrationTests.js │ ├── grpcIntegrationTests.js │ ├── httpIntegrationTests.js │ ├── tRPCIntegrationTests.js │ ├── webRTCIntegrationTests.js │ └── websocketIntegrationTests.js ├── SSE_HTTP1_server.js ├── __mockTestData │ ├── famousRandQuotesApi.yaml │ └── openAPITestDefinition.yaml ├── __mocks__ │ ├── electronMock.js │ ├── fileMock.js │ ├── styleMocks.js │ └── windowMock.js ├── __tests__ │ ├── SSEControllerTest.js │ ├── collectionsSliceTest.js │ ├── dbTests.js │ ├── graphQLcontrollerTest.js │ ├── helperTest.js │ ├── historyControllerTest.js │ ├── historySliceTest.js │ ├── httpTest.js │ ├── introspectionDataSliceTest.js │ ├── loadTestControllerTest.js │ ├── mockServerSliceTest.js │ ├── newReqOpenApiSliceTest.js │ ├── newRequestFieldsSliceTest.js │ ├── newRequestSliceTest.js │ ├── openAPIParserTest.js │ ├── protoParserTests.js │ ├── reqResControllerTest.js │ ├── uiSliceTest.js │ ├── utils │ │ └── reduxTestingUtils.tsx │ └── warningMessageSliceTest.js ├── graphqlServer.mjs ├── grpcServer.js ├── grpc_mockData │ ├── client.js │ ├── mock_protos │ │ ├── hw2.proto │ │ └── hw2_multi_service.proto │ ├── server.js │ └── testServer.js ├── httpServer.js ├── hw2.proto ├── subSuites │ ├── appOpens.js │ ├── collectionTest.js │ ├── darkModeToggleTest.js │ ├── graphqlTest.js │ ├── graphqlTestingTest.js │ ├── grpcTest.js │ ├── grpcTestingTest.js │ ├── httpTest.js │ ├── httpTestingTest.js │ ├── mockServerTest.js │ ├── openAPITest.js │ ├── reqInputTests.js │ ├── testHelper.js │ ├── webRTCTest.js │ └── websocketTest.js ├── tRPC_Test_Servers │ ├── Express Test Server │ │ ├── client │ │ │ ├── .gitignore │ │ │ ├── index.html │ │ │ ├── package.json │ │ │ ├── src │ │ │ │ ├── main.ts │ │ │ │ └── vite-env.d.ts │ │ │ └── tsconfig.json │ │ ├── server │ │ │ ├── api.ts │ │ │ ├── package.json │ │ │ ├── routers │ │ │ │ ├── index.ts │ │ │ │ └── users.ts │ │ │ └── trpc.ts │ │ └── tsconfig.json │ ├── Express_Test_Server │ │ ├── client │ │ │ ├── .gitignore │ │ │ ├── index.html │ │ │ ├── package.json │ │ │ ├── src │ │ │ │ ├── main.ts │ │ │ │ └── vite-env.d.ts │ │ │ └── tsconfig.json │ │ ├── server │ │ │ ├── api.ts │ │ │ ├── package.json │ │ │ ├── routers │ │ │ │ ├── index.ts │ │ │ │ └── users.ts │ │ │ └── trpc.ts │ │ └── tsconfig.json │ └── WebSocket Test Server │ │ ├── README.md │ │ ├── package.json │ │ ├── sandbox.config.json │ │ ├── src │ │ ├── client.ts │ │ └── server.ts │ │ └── tsconfig.json ├── testSuite.js ├── webrtcWSServer.js └── websocketServer.js ├── tsconfig.json ├── webpack.config.js ├── webpack.development.js └── webpack.production.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "production": { 4 | "plugins": ["transform-remove-console"] 5 | } 6 | }, 7 | "presets": [ 8 | "@babel/preset-env", 9 | "@babel/preset-react", 10 | "@babel/preset-typescript" 11 | ], 12 | "plugins": [ 13 | ["@babel/transform-runtime"], 14 | ["@babel/proposal-class-properties"], 15 | ["@babel/proposal-object-rest-spread"] 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | end_of_line = crlf 8 | indent_size = 2 9 | indent_style = space 10 | insert_final_newline = true 11 | trim_trailing_whitespace = true 12 | 13 | [*.md] 14 | trim_trailing_whitespace = false 15 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | /dist 2 | /build 3 | /node_modules -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | --- 8 | 9 | **Describe the bug** 10 | A clear and concise description of what the bug is. 11 | 12 | **To Reproduce** 13 | Steps to reproduce the behavior: 14 | 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | 28 | - OS: [e.g. iOS] 29 | - Browser [e.g. chrome, safari] 30 | - Version [e.g. 22] 31 | 32 | **Additional context** 33 | Add any other context about the problem here. 34 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | --- 8 | 9 | **Is your feature request related to a problem? Please describe.** 10 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 11 | 12 | **Describe the solution you'd like** 13 | A clear and concise description of what you want to happen. 14 | 15 | **Describe alternatives you've considered** 16 | A clear and concise description of any alternative solutions or features you've considered. 17 | 18 | **Additional context** 19 | Add any other context or screenshots about the feature request here. 20 | -------------------------------------------------------------------------------- /.github/workflows/unit-tests.yml: -------------------------------------------------------------------------------- 1 | name: Unit Tests 2 | 3 | on: [pull_request_target] 4 | 5 | jobs: 6 | tests: 7 | strategy: 8 | matrix: 9 | node-version: [18.20.6] 10 | os: [macos-latest, ubuntu-latest, windows-latest] 11 | runs-on: ${{ matrix.os }} 12 | steps: 13 | - name: Checkout repo 14 | uses: actions/checkout@v3 15 | - name: Use Node.js ${{ matrix.node-version }} 16 | uses: actions/setup-node@v3 17 | with: 18 | node-version: ${{ matrix.node-version }} 19 | - name: Install dependencies 20 | run: npm i && npm ci 21 | - name: Apply patches 22 | env: 23 | NODE_ENV: --no-node-snapshot 24 | run: npx patch-package 25 | - name: Run unit tests 26 | uses: coactions/setup-xvfb@v1 27 | with: 28 | run: npm run test-jest 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Build folder and files # 2 | ########################## 3 | build/ 4 | release/ 5 | 6 | # Development folders and files # 7 | ################################# 8 | .tmp/ 9 | dist/ 10 | node_modules 11 | *.compiled.* 12 | package-lock.json 13 | coverage/ 14 | .vscode 15 | src/client/docs/ 16 | test/failedTests 17 | .nyc_output 18 | jest-coverage 19 | mocha-coverage 20 | total-coverage 21 | 22 | # Folder config file # 23 | ###################### 24 | Desktop.ini 25 | 26 | # Folder notes # 27 | ################ 28 | _ignore/ 29 | 30 | # Log files & folders # 31 | ####################### 32 | logs/ 33 | *.log 34 | npm-debug.log* 35 | .npm 36 | 37 | # Packages # 38 | ############ 39 | # it's better to unpack these files and commit the raw source 40 | # git has its own built in compression methods 41 | *.7z 42 | *.dmg 43 | *.gz 44 | *.iso 45 | *.jar 46 | *.rar 47 | *.tar 48 | *.zip 49 | 50 | # Photoshop & Illustrator files # 51 | ################################# 52 | *.ai 53 | *.eps 54 | *.psd 55 | 56 | # Windows & Mac file caches # 57 | ############################# 58 | .DS_Store 59 | Thumbs.db 60 | ehthumbs.db 61 | 62 | # Windows shortcuts # 63 | ##################### 64 | *.lnk 65 | 66 | # proto files # 67 | ##################### 68 | protos/ 69 | 70 | # testing # 71 | test/subSuites/*.png 72 | test/failedTests/* 73 | .nyc_output 74 | # //! DELETE AFTER DONE, THESE ARENT PERMANENT 75 | # test/testSuite.js 76 | 77 | 78 | 79 | # db # 80 | .env 81 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | /build 2 | /dist 3 | /node_modules -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 80, 3 | "tabWidth": 2, 4 | "singleQuote": true, 5 | "arrowParens": "always" 6 | } -------------------------------------------------------------------------------- /Dockerfile-dev: -------------------------------------------------------------------------------- 1 | From node:18.20 2 | RUN npm install -g webpack 3 | Workdir /app 4 | Copy package*.json /app 5 | Run npm install 6 | Expose 8080 -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # Issue Template 2 | 3 | ## Prerequisites 4 | 5 | Please answer the following questions for yourself before submitting an issue. 6 | 7 | - [ ] I am running the latest version 8 | - [ ] I checked the documentation and found no answer 9 | - [ ] I checked to make sure that this issue has not already been filed 10 | - [ ] I'm reporting the issue to the correct repository (for multi-repository projects) 11 | 12 | ## Expected Behavior 13 | 14 | Please describe the behavior you are expecting 15 | 16 | ## Current Behavior 17 | 18 | What is the current behavior? 19 | 20 | ## Failure Information (for bugs) 21 | 22 | Please help provide information about the failure if this is a bug. If it is not a bug, please remove the rest of this template. 23 | 24 | ### Steps to Reproduce 25 | 26 | Please provide detailed steps for reproducing the issue. 27 | 28 | 1. step 1 29 | 2. step 2 30 | 3. and so on... 31 | 32 | ### Failure Logs 33 | 34 | Please include any relevant log snippets or files here. 35 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Swell 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /ReactDevToolsWebExtDep/icons/128-deadcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReactDevToolsWebExtDep/icons/128-deadcode.png -------------------------------------------------------------------------------- /ReactDevToolsWebExtDep/icons/128-development.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReactDevToolsWebExtDep/icons/128-development.png -------------------------------------------------------------------------------- /ReactDevToolsWebExtDep/icons/128-disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReactDevToolsWebExtDep/icons/128-disabled.png -------------------------------------------------------------------------------- /ReactDevToolsWebExtDep/icons/128-outdated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReactDevToolsWebExtDep/icons/128-outdated.png -------------------------------------------------------------------------------- /ReactDevToolsWebExtDep/icons/128-production.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReactDevToolsWebExtDep/icons/128-production.png -------------------------------------------------------------------------------- /ReactDevToolsWebExtDep/icons/128-restricted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReactDevToolsWebExtDep/icons/128-restricted.png -------------------------------------------------------------------------------- /ReactDevToolsWebExtDep/icons/128-unminified.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReactDevToolsWebExtDep/icons/128-unminified.png -------------------------------------------------------------------------------- /ReactDevToolsWebExtDep/icons/16-deadcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReactDevToolsWebExtDep/icons/16-deadcode.png -------------------------------------------------------------------------------- /ReactDevToolsWebExtDep/icons/16-development.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReactDevToolsWebExtDep/icons/16-development.png -------------------------------------------------------------------------------- /ReactDevToolsWebExtDep/icons/16-disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReactDevToolsWebExtDep/icons/16-disabled.png -------------------------------------------------------------------------------- /ReactDevToolsWebExtDep/icons/16-outdated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReactDevToolsWebExtDep/icons/16-outdated.png -------------------------------------------------------------------------------- /ReactDevToolsWebExtDep/icons/16-production.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReactDevToolsWebExtDep/icons/16-production.png -------------------------------------------------------------------------------- /ReactDevToolsWebExtDep/icons/16-restricted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReactDevToolsWebExtDep/icons/16-restricted.png -------------------------------------------------------------------------------- /ReactDevToolsWebExtDep/icons/16-unminified.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReactDevToolsWebExtDep/icons/16-unminified.png -------------------------------------------------------------------------------- /ReactDevToolsWebExtDep/icons/32-deadcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReactDevToolsWebExtDep/icons/32-deadcode.png -------------------------------------------------------------------------------- /ReactDevToolsWebExtDep/icons/32-development.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReactDevToolsWebExtDep/icons/32-development.png -------------------------------------------------------------------------------- /ReactDevToolsWebExtDep/icons/32-disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReactDevToolsWebExtDep/icons/32-disabled.png -------------------------------------------------------------------------------- /ReactDevToolsWebExtDep/icons/32-outdated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReactDevToolsWebExtDep/icons/32-outdated.png -------------------------------------------------------------------------------- /ReactDevToolsWebExtDep/icons/32-production.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReactDevToolsWebExtDep/icons/32-production.png -------------------------------------------------------------------------------- /ReactDevToolsWebExtDep/icons/32-restricted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReactDevToolsWebExtDep/icons/32-restricted.png -------------------------------------------------------------------------------- /ReactDevToolsWebExtDep/icons/32-unminified.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReactDevToolsWebExtDep/icons/32-unminified.png -------------------------------------------------------------------------------- /ReactDevToolsWebExtDep/icons/48-deadcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReactDevToolsWebExtDep/icons/48-deadcode.png -------------------------------------------------------------------------------- /ReactDevToolsWebExtDep/icons/48-development.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReactDevToolsWebExtDep/icons/48-development.png -------------------------------------------------------------------------------- /ReactDevToolsWebExtDep/icons/48-disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReactDevToolsWebExtDep/icons/48-disabled.png -------------------------------------------------------------------------------- /ReactDevToolsWebExtDep/icons/48-outdated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReactDevToolsWebExtDep/icons/48-outdated.png -------------------------------------------------------------------------------- /ReactDevToolsWebExtDep/icons/48-production.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReactDevToolsWebExtDep/icons/48-production.png -------------------------------------------------------------------------------- /ReactDevToolsWebExtDep/icons/48-restricted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReactDevToolsWebExtDep/icons/48-restricted.png -------------------------------------------------------------------------------- /ReactDevToolsWebExtDep/icons/48-unminified.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReactDevToolsWebExtDep/icons/48-unminified.png -------------------------------------------------------------------------------- /ReactDevToolsWebExtDep/icons/disabled.svg: -------------------------------------------------------------------------------- 1 | disabled -------------------------------------------------------------------------------- /ReactDevToolsWebExtDep/icons/outdated.svg: -------------------------------------------------------------------------------- 1 | outdated -------------------------------------------------------------------------------- /ReactDevToolsWebExtDep/icons/production.svg: -------------------------------------------------------------------------------- 1 | production -------------------------------------------------------------------------------- /ReactDevToolsWebExtDep/icons/restricted.svg: -------------------------------------------------------------------------------- 1 | disabled -------------------------------------------------------------------------------- /ReactDevToolsWebExtDep/main.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /ReactDevToolsWebExtDep/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 2, 3 | "name": "React Developer Tools", 4 | "description": "Adds React debugging tools to the Firefox Developer Tools.\n\nCreated from revision f7d56173f on 1/27/2023.", 5 | "version": "4.27.1", 6 | "version_name": "4.27.1 (1/27/2023)", 7 | "minimum_chrome_version": "60", 8 | "icons": { 9 | "16": "icons/16-production.png", 10 | "32": "icons/32-production.png", 11 | "48": "icons/48-production.png", 12 | "128": "icons/128-production.png" 13 | }, 14 | "browser_action": { 15 | "default_icon": { 16 | "16": "icons/16-disabled.png", 17 | "32": "icons/32-disabled.png", 18 | "48": "icons/48-disabled.png", 19 | "128": "icons/128-disabled.png" 20 | }, 21 | "default_popup": "popups/disabled.html", 22 | "browser_style": true 23 | }, 24 | "devtools_page": "main.html", 25 | "content_security_policy": "script-src 'self' 'unsafe-eval' blob:; object-src 'self'", 26 | "web_accessible_resources": [ 27 | "main.html", 28 | "panel.html", 29 | "rbuild/react_devtools_backend.js", 30 | "rbuild/proxy.js", 31 | "rbuild/renderer.js", 32 | "rbuild/installHook.js" 33 | ], 34 | "background": { 35 | "scripts": [ 36 | "rbuild/background.js" 37 | ] 38 | }, 39 | "permissions": [ 40 | "file:///*", 41 | "http://*/*", 42 | "https://*/*" 43 | ], 44 | "content_scripts": [ 45 | { 46 | "matches": [ 47 | "" 48 | ], 49 | "js": [ 50 | "rbuild/prepareInjection.js" 51 | ], 52 | "run_at": "document_start" 53 | } 54 | ] 55 | } -------------------------------------------------------------------------------- /ReactDevToolsWebExtDep/panel.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 26 | 27 | 28 | 29 |
Unable to find React on the page.
30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /ReactDevToolsWebExtDep/popups/deadcode.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 |

14 | This page includes an extra development build of React. 🚧 15 |

16 |

17 | The React build on this page includes both development and production versions because dead code elimination has not been applied correctly. 18 |
19 |
20 | This makes its size larger, and causes React to run slower. 21 |
22 |
23 | Make sure to set up dead code elimination before deployment. 24 |

25 |
26 |

27 | Open the developer tools, and "Components" and "Profiler" tabs will appear to the right. 28 |

29 | -------------------------------------------------------------------------------- /ReactDevToolsWebExtDep/popups/development.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 |

14 | This page is using the development build of React. 🚧 15 |

16 |

17 | Note that the development build is not suitable for production. 18 |
19 | Make sure to use the production build before deployment. 20 |

21 |
22 |

23 | Open the developer tools, and "Components" and "Profiler" tabs will appear to the right. 24 |

25 | -------------------------------------------------------------------------------- /ReactDevToolsWebExtDep/popups/disabled.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 |

14 | This page doesn’t appear to be using React. 15 |
16 | If this seems wrong, follow the troubleshooting instructions. 17 |

18 | -------------------------------------------------------------------------------- /ReactDevToolsWebExtDep/popups/outdated.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 |

14 | This page is using an outdated version of React. ⌛ 15 |

16 |

17 | We recommend updating React to ensure that you receive important bugfixes and performance improvements. 18 |
19 |
20 | You can find the upgrade instructions on the React blog. 21 |

22 |
23 |

24 | Open the developer tools, and "Components" and "Profiler" tabs will appear to the right. 25 |

26 | -------------------------------------------------------------------------------- /ReactDevToolsWebExtDep/popups/production.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 |

14 | This page is using the production build of React. ✅ 15 |
16 | Open the developer tools, and "Components" and "Profiler" tabs will appear to the right. 17 |

18 | -------------------------------------------------------------------------------- /ReactDevToolsWebExtDep/popups/restricted.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 |

11 | This is a restricted browser page. 12 |
13 | React devtools cannot access this page. 14 |

15 | -------------------------------------------------------------------------------- /ReactDevToolsWebExtDep/popups/shared.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | font-size: 14px; 3 | } 4 | 5 | body { 6 | margin: 8px; 7 | } -------------------------------------------------------------------------------- /ReactDevToolsWebExtDep/popups/shared.js: -------------------------------------------------------------------------------- 1 | /* globals chrome */ 2 | 3 | 'use strict'; 4 | 5 | document.addEventListener('DOMContentLoaded', function() { 6 | // Make links work 7 | const links = document.getElementsByTagName('a'); 8 | for (let i = 0; i < links.length; i++) { 9 | (function() { 10 | const ln = links[i]; 11 | const location = ln.href; 12 | ln.onclick = function() { 13 | chrome.tabs.create({active: true, url: location}); 14 | return false; 15 | }; 16 | })(); 17 | } 18 | 19 | // Work around https://bugs.chromium.org/p/chromium/issues/detail?id=428044 20 | document.body.style.opacity = 0; 21 | document.body.style.transition = 'opacity ease-out .4s'; 22 | requestAnimationFrame(function() { 23 | document.body.style.opacity = 1; 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /ReactDevToolsWebExtDep/popups/unminified.html: -------------------------------------------------------------------------------- 1 | 2 | 17 |

18 | This page is using an unminified build of React. 🚧 19 |

20 |

21 | The React build on this page appears to be unminified. 22 |
23 | This makes its size larger, and causes React to run slower. 24 |
25 |
26 | Make sure to set up minification before deployment. 27 |

28 |
29 |

30 | Open the developer tools, and "Components" and "Profiler" tabs will appear to the right. 31 |

32 | -------------------------------------------------------------------------------- /ReadMeGifs/Gifs/Assertion-Testing.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReadMeGifs/Gifs/Assertion-Testing.gif -------------------------------------------------------------------------------- /ReadMeGifs/Gifs/DarkMode.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReadMeGifs/Gifs/DarkMode.gif -------------------------------------------------------------------------------- /ReadMeGifs/Gifs/FileUploadAndDarkMode.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReadMeGifs/Gifs/FileUploadAndDarkMode.gif -------------------------------------------------------------------------------- /ReadMeGifs/Gifs/GQL-introspection.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReadMeGifs/Gifs/GQL-introspection.gif -------------------------------------------------------------------------------- /ReadMeGifs/Gifs/GraphQL.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReadMeGifs/Gifs/GraphQL.gif -------------------------------------------------------------------------------- /ReadMeGifs/Gifs/GraphQLTest.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReadMeGifs/Gifs/GraphQLTest.gif -------------------------------------------------------------------------------- /ReadMeGifs/Gifs/HttpStressTest.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReadMeGifs/Gifs/HttpStressTest.gif -------------------------------------------------------------------------------- /ReadMeGifs/Gifs/HttpTesting.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReadMeGifs/Gifs/HttpTesting.gif -------------------------------------------------------------------------------- /ReadMeGifs/Gifs/MockServer.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReadMeGifs/Gifs/MockServer.gif -------------------------------------------------------------------------------- /ReadMeGifs/Gifs/ServerSideEvents.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReadMeGifs/Gifs/ServerSideEvents.gif -------------------------------------------------------------------------------- /ReadMeGifs/Gifs/SimpleResponseTest.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReadMeGifs/Gifs/SimpleResponseTest.gif -------------------------------------------------------------------------------- /ReadMeGifs/Gifs/Websockets.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReadMeGifs/Gifs/Websockets.gif -------------------------------------------------------------------------------- /ReadMeGifs/Gifs/gRPC-responses.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReadMeGifs/Gifs/gRPC-responses.gif -------------------------------------------------------------------------------- /ReadMeGifs/Gifs/gRPC.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReadMeGifs/Gifs/gRPC.gif -------------------------------------------------------------------------------- /ReadMeGifs/Gifs/openapi.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReadMeGifs/Gifs/openapi.gif -------------------------------------------------------------------------------- /ReadMeGifs/Gifs/trpc.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReadMeGifs/Gifs/trpc.gif -------------------------------------------------------------------------------- /ReadMeGifs/Gifs/webrtc.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReadMeGifs/Gifs/webrtc.gif -------------------------------------------------------------------------------- /ReadMeGifs/Videos/Long Feature Videos/720-MP4s/GRPCResponses.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReadMeGifs/Videos/Long Feature Videos/720-MP4s/GRPCResponses.mp4 -------------------------------------------------------------------------------- /ReadMeGifs/Videos/Long Feature Videos/720-MP4s/GraphQL.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReadMeGifs/Videos/Long Feature Videos/720-MP4s/GraphQL.mp4 -------------------------------------------------------------------------------- /ReadMeGifs/Videos/Long Feature Videos/720-MP4s/Http2Streams.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReadMeGifs/Videos/Long Feature Videos/720-MP4s/Http2Streams.mp4 -------------------------------------------------------------------------------- /ReadMeGifs/Videos/Long Feature Videos/720-MP4s/Response History.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReadMeGifs/Videos/Long Feature Videos/720-MP4s/Response History.mp4 -------------------------------------------------------------------------------- /ReadMeGifs/Videos/Long Feature Videos/720-MP4s/RestRequests.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReadMeGifs/Videos/Long Feature Videos/720-MP4s/RestRequests.mp4 -------------------------------------------------------------------------------- /ReadMeGifs/Videos/Long Feature Videos/720-MP4s/SavedWorkspaces.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReadMeGifs/Videos/Long Feature Videos/720-MP4s/SavedWorkspaces.mp4 -------------------------------------------------------------------------------- /ReadMeGifs/Videos/Long Feature Videos/720-MP4s/WebSockets.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReadMeGifs/Videos/Long Feature Videos/720-MP4s/WebSockets.mp4 -------------------------------------------------------------------------------- /ReadMeGifs/Videos/Long Feature Videos/Original_Format/GRPCResponses.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReadMeGifs/Videos/Long Feature Videos/Original_Format/GRPCResponses.mov -------------------------------------------------------------------------------- /ReadMeGifs/Videos/Long Feature Videos/Original_Format/GraphQL.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReadMeGifs/Videos/Long Feature Videos/Original_Format/GraphQL.mov -------------------------------------------------------------------------------- /ReadMeGifs/Videos/Long Feature Videos/Original_Format/Http2Streams.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReadMeGifs/Videos/Long Feature Videos/Original_Format/Http2Streams.mov -------------------------------------------------------------------------------- /ReadMeGifs/Videos/Long Feature Videos/Original_Format/Response History.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReadMeGifs/Videos/Long Feature Videos/Original_Format/Response History.mov -------------------------------------------------------------------------------- /ReadMeGifs/Videos/Long Feature Videos/Original_Format/RestRequests.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReadMeGifs/Videos/Long Feature Videos/Original_Format/RestRequests.mov -------------------------------------------------------------------------------- /ReadMeGifs/Videos/Long Feature Videos/Original_Format/SavedWorkspaces.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReadMeGifs/Videos/Long Feature Videos/Original_Format/SavedWorkspaces.mov -------------------------------------------------------------------------------- /ReadMeGifs/Videos/Long Feature Videos/Original_Format/WebSockets.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReadMeGifs/Videos/Long Feature Videos/Original_Format/WebSockets.mov -------------------------------------------------------------------------------- /ReadMeGifs/Videos/Short Feature Videos/720-MP4s/ConcurrentStreams.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReadMeGifs/Videos/Short Feature Videos/720-MP4s/ConcurrentStreams.mp4 -------------------------------------------------------------------------------- /ReadMeGifs/Videos/Short Feature Videos/720-MP4s/CopyToComposer.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReadMeGifs/Videos/Short Feature Videos/720-MP4s/CopyToComposer.mp4 -------------------------------------------------------------------------------- /ReadMeGifs/Videos/Short Feature Videos/720-MP4s/GQL-introspection.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReadMeGifs/Videos/Short Feature Videos/720-MP4s/GQL-introspection.mp4 -------------------------------------------------------------------------------- /ReadMeGifs/Videos/Short Feature Videos/720-MP4s/History.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReadMeGifs/Videos/Short Feature Videos/720-MP4s/History.mp4 -------------------------------------------------------------------------------- /ReadMeGifs/Videos/Short Feature Videos/720-MP4s/Intelligent GraphQL completion.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReadMeGifs/Videos/Short Feature Videos/720-MP4s/Intelligent GraphQL completion.mp4 -------------------------------------------------------------------------------- /ReadMeGifs/Videos/Short Feature Videos/720-MP4s/SSE.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReadMeGifs/Videos/Short Feature Videos/720-MP4s/SSE.mp4 -------------------------------------------------------------------------------- /ReadMeGifs/Videos/Short Feature Videos/720-MP4s/SavedWorkspace.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReadMeGifs/Videos/Short Feature Videos/720-MP4s/SavedWorkspace.mp4 -------------------------------------------------------------------------------- /ReadMeGifs/Videos/Short Feature Videos/Original_Format/ConcurrentStreams.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReadMeGifs/Videos/Short Feature Videos/Original_Format/ConcurrentStreams.mov -------------------------------------------------------------------------------- /ReadMeGifs/Videos/Short Feature Videos/Original_Format/CopyToComposer.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReadMeGifs/Videos/Short Feature Videos/Original_Format/CopyToComposer.mov -------------------------------------------------------------------------------- /ReadMeGifs/Videos/Short Feature Videos/Original_Format/GQL-introspection.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReadMeGifs/Videos/Short Feature Videos/Original_Format/GQL-introspection.mov -------------------------------------------------------------------------------- /ReadMeGifs/Videos/Short Feature Videos/Original_Format/History.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReadMeGifs/Videos/Short Feature Videos/Original_Format/History.mov -------------------------------------------------------------------------------- /ReadMeGifs/Videos/Short Feature Videos/Original_Format/Intelligent GraphQL completion.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReadMeGifs/Videos/Short Feature Videos/Original_Format/Intelligent GraphQL completion.mov -------------------------------------------------------------------------------- /ReadMeGifs/Videos/Short Feature Videos/Original_Format/SSE.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReadMeGifs/Videos/Short Feature Videos/Original_Format/SSE.mov -------------------------------------------------------------------------------- /ReadMeGifs/Videos/Short Feature Videos/Original_Format/SavedWorkspace.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/ReadMeGifs/Videos/Short Feature Videos/Original_Format/SavedWorkspace.mov -------------------------------------------------------------------------------- /build/512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/build/512x512.png -------------------------------------------------------------------------------- /build/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/build/background.png -------------------------------------------------------------------------------- /build/background@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/build/background@2x.png -------------------------------------------------------------------------------- /build/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/build/icon.icns -------------------------------------------------------------------------------- /build/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/build/icon.ico -------------------------------------------------------------------------------- /build/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/build/icon.png -------------------------------------------------------------------------------- /build/icons/512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/build/icons/512x512.png -------------------------------------------------------------------------------- /build/icons/mac/Swell.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/build/icons/mac/Swell.icns -------------------------------------------------------------------------------- /build/icons/png/1024x1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/build/icons/png/1024x1024.png -------------------------------------------------------------------------------- /build/icons/png/128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/build/icons/png/128x128.png -------------------------------------------------------------------------------- /build/icons/png/16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/build/icons/png/16x16.png -------------------------------------------------------------------------------- /build/icons/png/24x24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/build/icons/png/24x24.png -------------------------------------------------------------------------------- /build/icons/png/256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/build/icons/png/256x256.png -------------------------------------------------------------------------------- /build/icons/png/32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/build/icons/png/32x32.png -------------------------------------------------------------------------------- /build/icons/png/48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/build/icons/png/48x48.png -------------------------------------------------------------------------------- /build/icons/png/512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/build/icons/png/512x512.png -------------------------------------------------------------------------------- /build/icons/png/64x64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/build/icons/png/64x64.png -------------------------------------------------------------------------------- /build/icons/png/96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/build/icons/png/96x96.png -------------------------------------------------------------------------------- /build/icons/win/Swell.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/build/icons/win/Swell.ico -------------------------------------------------------------------------------- /docs/How to test GRPC: -------------------------------------------------------------------------------- 1 | To use GRPC with a local express server on port 30051: 2 | 1. Ensure all dependencies are installed (npm install) 3 | 2. Uncomment line 133 in test/grpcServer.js 4 | 3. npm run dev 5 | 4. npm run server-grpc 6 | 5. In Swell (dev) app, select the GRPC composer 7 | 6. Enter Stream: 0.0.0.0:30051 8 | 7. Load test proto: swell/test/hw2.proto 9 | 8. Select a service below. All of them should work. 10 | 9. Click add to workspace 11 | 10. Send! You should receive an appropriate response 12 | 13 | Note: from my research, GRPC is mainly used between shared backend microservices so I think it would be difficult to test outside of this environment. -------------------------------------------------------------------------------- /docs/vcxsrv_alt_disable_access_control.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/docs/vcxsrv_alt_disable_access_control.png -------------------------------------------------------------------------------- /docs/vcxsrv_client_startup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/docs/vcxsrv_client_startup.png -------------------------------------------------------------------------------- /docs/vcxsrv_disable_access_control.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/docs/vcxsrv_disable_access_control.png -------------------------------------------------------------------------------- /docs/vcxsrv_display_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/docs/vcxsrv_display_settings.png -------------------------------------------------------------------------------- /electron-builder.yml: -------------------------------------------------------------------------------- 1 | appId: com.getswell.swell.app 2 | publish: 3 | provider: github 4 | token: b9e252e0b0404c2d8fbe403ca2a42dbd6dd13334 -------------------------------------------------------------------------------- /index-csp.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | <%= htmlWebpackPlugin.options.title %> 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | verbose: true, 3 | // runner: "@kayahr/jest-electron-runner/main", // deprecated? 4 | testEnvironment: 'jsdom',//'@kayahr/jest-electron-runner/environment', 5 | moduleNameMapper: { 6 | // "collectCoverage": true, 7 | electron: '/__mocks__/electronMock.js', 8 | '\\.(css|less|sass|scss)$': '/__mocks__/styleMocks.js', 9 | '\\.(gif|ttf|eot|svg|png)$': '/test/__mocks__/fileMock.js', 10 | '^dexie$': '/node_modules/dexie' 11 | }, 12 | testPathIgnorePatterns: [ 13 | '/node_modules/', 14 | '/test/__tests__/utils/reduxTestingUtils.tsx', 15 | ], 16 | collectCoverage: true, 17 | coverageDirectory: './test/coverage/jest-coverage', 18 | coverageReporters: ['json', 'text', 'html'], 19 | resolver: null, 20 | }; 21 | -------------------------------------------------------------------------------- /main_process/main_mockController.js: -------------------------------------------------------------------------------- 1 | const { ipcMain } = require('electron'); 2 | const { fetch } = require('cross-fetch'); 3 | 4 | const mockController = { 5 | /** 6 | * Sends a POST request to the mock server to create new mock endpoints. 7 | * @param {*} event - The Electron event object that triggered the submission of the mock request. 8 | * @param {*} postData - the JSON stringified object from the renderer that contains a "method", "endpoint" and "response" keys that will be used to create the mock endpoint. 9 | */ 10 | submitMockRequest: async (event, postData) => { 11 | try { 12 | const result = await fetch('http://localhost:9990/mock/', { 13 | method: 'POST', 14 | headers: { 15 | 'Content-Type': 'application/json', 16 | }, 17 | body: postData, 18 | }); 19 | console.log('Result: ', result); 20 | } catch (err) { 21 | console.log('Error submitting endpoint: ', err); 22 | } 23 | }, 24 | }; 25 | 26 | module.exports = () => { 27 | ipcMain.on('submit-mock-request', async (event, postData) => { 28 | mockController.submitMockRequest(event, postData); 29 | }); 30 | }; 31 | -------------------------------------------------------------------------------- /main_process/openapiParser.js: -------------------------------------------------------------------------------- 1 | const YAML = require('yamljs'); 2 | 3 | // TODO The security keys need to be implmented into the OpenApi request 4 | 5 | const openapiParserFunc = (input) => { 6 | 7 | if (input === undefined || input === null) { 8 | throw new ReferenceError('OpenAPI Document not found.'); 9 | } 10 | // Parse the input into JSON or YAML 11 | let doc; 12 | try { 13 | doc = JSON.parse(input); 14 | } catch (SyntaxError) { 15 | doc = YAML.parse(input); 16 | } 17 | 18 | const { info, servers, tags, paths, components } = doc; 19 | 20 | info.openapi = doc.openapi; 21 | 22 | let serverUrls 23 | if (servers) { 24 | serverUrls = [...servers.map((server) => server.url)]; 25 | } else { 26 | serverUrls = [] 27 | } 28 | let id = 0; 29 | 30 | const openapiReqArray = []; 31 | Object.entries(paths).forEach(([endpoint, pathObj]) => { 32 | Object.entries(pathObj).forEach(([method, operationObj]) => { 33 | id += 1; 34 | const { 35 | summary, 36 | description, 37 | operationId, 38 | tags, 39 | parameters, // security 40 | } = operationObj; 41 | 42 | const request = { 43 | id, 44 | // enabled: true, 45 | reqTags: tags, 46 | summary, 47 | description, 48 | operationId, 49 | method: method.toUpperCase(), 50 | reqServers: [], 51 | endpoint, 52 | parameters, 53 | body: new Map(), 54 | headers: {}, 55 | cookies: {}, 56 | // params: {}, 57 | // queries: {}, 58 | urls: [], 59 | }; 60 | openapiReqArray.push(request); 61 | }); 62 | }); 63 | 64 | const openapiMetadata = { info, tags, serverUrls }; 65 | 66 | return { openapiMetadata, openapiReqArray } || 'Enter a valid Open API Format'; 67 | }; 68 | 69 | module.exports = openapiParserFunc; 70 | -------------------------------------------------------------------------------- /patches/istanbul+0.4.5.patch: -------------------------------------------------------------------------------- 1 | diff --git a/node_modules/istanbul/lib/report/html.js b/node_modules/istanbul/lib/report/html.js 2 | index 1dab26d..5128165 100644 3 | --- a/node_modules/istanbul/lib/report/html.js 4 | +++ b/node_modules/istanbul/lib/report/html.js 5 | @@ -202,7 +202,7 @@ function annotateStatements(fileCoverage, structuredText) { 6 | closeSpan = lt + '/span' + gt, 7 | text; 8 | 9 | - if (type === 'no') { 10 | + if (type === 'no' && structuredText[startLine] && structuredText[startLine].text) { 11 | if (endLine !== startLine) { 12 | endLine = startLine; 13 | endCol = structuredText[startLine].text.originalLength(); 14 | @@ -233,7 +233,7 @@ function annotateFunctions(fileCoverage, structuredText) { 15 | closeSpan = lt + '/span' + gt, 16 | text; 17 | 18 | - if (type === 'no') { 19 | + if (type === 'no' && structuredText[startLine] && structuredText[startLine].text) { 20 | if (endLine !== startLine) { 21 | endLine = startLine; 22 | endCol = structuredText[startLine].text.originalLength(); 23 | @@ -280,7 +280,7 @@ function annotateBranches(fileCoverage, structuredText) { 24 | openSpan = lt + 'span class="branch-' + i + ' ' + (meta.skip ? 'cbranch-skip' : 'cbranch-no') + '"' + title('branch not covered') + gt; 25 | closeSpan = lt + '/span' + gt; 26 | 27 | - if (count === 0) { //skip branches taken 28 | + if (count === 0 && structuredText[startLine] && structuredText[startLine].text) { //skip branches taken 29 | if (endLine !== startLine) { 30 | endLine = startLine; 31 | endCol = structuredText[startLine].text.originalLength(); 32 | -------------------------------------------------------------------------------- /src/assets/icons/64x64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/src/assets/icons/64x64.png -------------------------------------------------------------------------------- /src/assets/icons/arrow_drop_down_white_192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/src/assets/icons/arrow_drop_down_white_192x192.png -------------------------------------------------------------------------------- /src/assets/icons/caret-down-tests.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/assets/icons/caret-down-white.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/assets/icons/caret-down.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/assets/icons/caret-left-white.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/assets/icons/caret-left.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/assets/icons/caret-right-white.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/assets/icons/caret-right.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/assets/icons/caret-up-tests.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/assets/icons/caret-up-white.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/assets/icons/caret-up.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/assets/icons/clipboard-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/assets/icons/night-mode.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/sun.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/img/Trashcan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/src/assets/img/Trashcan.png -------------------------------------------------------------------------------- /src/assets/img/horizontal-logo-lockup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/src/assets/img/horizontal-logo-lockup.png -------------------------------------------------------------------------------- /src/assets/img/swell-logo-faded.avif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/src/assets/img/swell-logo-faded.avif -------------------------------------------------------------------------------- /src/assets/img/swell-logo-faded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/src/assets/img/swell-logo-faded.png -------------------------------------------------------------------------------- /src/assets/style/App.scss: -------------------------------------------------------------------------------- 1 | @import 'colors'; 2 | @import 'darkMode'; 3 | @import 'infinite'; 4 | @import 'base'; 5 | @import 'sidebar'; 6 | @import 'workspace'; 7 | @import 'webSocketResponse'; 8 | @import 'responsepane'; 9 | @import 'bulma'; 10 | @import '~bulma-switch'; 11 | @import '~bulma-checkradio'; 12 | 13 | -------------------------------------------------------------------------------- /src/assets/style/WebRtc.css: -------------------------------------------------------------------------------- 1 | .toggle-refresh-container { 2 | display: flex; 3 | justify-content: space-between; 4 | align-items: center; 5 | padding: 10px; 6 | min-height: 40px; 7 | } 8 | 9 | .refresh-button { 10 | width: 70px; 11 | height: 40px; 12 | border-radius: 30px; 13 | border-style: none; 14 | background-color: #58a4b0; 15 | } 16 | 17 | .refresh-button:hover { 18 | box-shadow: 2px 2px 1px rgba(0, 0, 0, 0.75); 19 | } 20 | 21 | .Audio-Toggle-Container { 22 | display: flex; 23 | justify-content: flex-start; 24 | align-items: center; 25 | gap: 10px; 26 | min-width: 150px; 27 | } 28 | 29 | .switch { 30 | position: relative; 31 | display: inline-block; 32 | width: 60px; 33 | height: 34px; 34 | } 35 | 36 | .switch input { 37 | opacity: 0; 38 | width: 0; 39 | height: 0; 40 | } 41 | 42 | .slider { 43 | position: absolute; 44 | cursor: pointer; 45 | top: 0; 46 | left: 0; 47 | right: 0; 48 | bottom: 0; 49 | background-color: #ccc; 50 | -webkit-transition: 0.4s; 51 | transition: 0.4s; 52 | } 53 | 54 | .slider-on { 55 | background-color: #58a4b0 !important; 56 | } 57 | 58 | .slider:before { 59 | position: absolute; 60 | content: ''; 61 | height: 26px; 62 | width: 26px; 63 | left: 4px; 64 | bottom: 4px; 65 | background-color: white; 66 | -webkit-transition: 0.4s; 67 | transition: 0.4s; 68 | } 69 | 70 | input:focus + .slider { 71 | box-shadow: 0 0 1px #ccc; 72 | } 73 | 74 | input:checked + .slider:before { 75 | -webkit-transform: translateX(26px); 76 | -ms-transform: translateX(26px); 77 | transform: translateX(26px); 78 | } 79 | 80 | .slider.round { 81 | border-radius: 5px; 82 | } 83 | 84 | .slider.round:before { 85 | border-radius: 50%; 86 | } 87 | 88 | /* .is-3rem-footer.is-clickable.is-margin-top-auto { 89 | display: flex; 90 | justify-content: flex-end; 91 | padding: 0; 92 | } 93 | */ 94 | 95 | -------------------------------------------------------------------------------- /src/assets/style/base.scss: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | font-size: 13px; 4 | } 5 | 6 | // BULMA ADJUSTMENTS 7 | .hero { 8 | height: 2.5rem; // nothing happened when changed 9 | padding-top: 0.5rem; // makes purple banner change height 10 | } 11 | 12 | .hero h3 { 13 | font-family: 'Source Sans Pro', sans-serif; 14 | font-weight: 600; // font boldness in banner (composer, workspace responses) 15 | } 16 | 17 | input:focus { 18 | outline: none; 19 | } 20 | 21 | .input:focus { 22 | outline: none; 23 | } 24 | 25 | #root { 26 | height: 100%; 27 | overflow-y: hidden; 28 | } 29 | 30 | #update-modal { 31 | position: relative; 32 | width: 100%; 33 | background-color: $neutral-500; 34 | color: $neutral-100; 35 | display: flex; 36 | align-items: center; 37 | justify-content: space-between; 38 | height: 2.5rem !important; 39 | opacity: 0.8; 40 | margin: 0; 41 | padding: 0; 42 | top: 0; 43 | } 44 | 45 | .modal-button { 46 | min-width: 20% !important; 47 | background-color: $neutral-500 !important; 48 | color: $neutral-300 !important; 49 | } 50 | 51 | .modal-button-update { 52 | min-width: 20% !important; 53 | background-color: $primary-100 !important; 54 | color: $neutral-500 !important; 55 | border-color: $neutral-500; 56 | } 57 | 58 | .is-tall { 59 | height: 100% !important; 60 | } 61 | 62 | .is-tall-message { 63 | height: calc(100% - 2.5rem) !important; 64 | margin-bottom: 0 !important; 65 | } 66 | 67 | body { 68 | height: 100%; 69 | } 70 | 71 | html { 72 | height: 100% !important; 73 | } 74 | 75 | .header_entry-form { 76 | width: 100%; 77 | } 78 | .header_entry-form input { 79 | width: 100%; 80 | } 81 | 82 | .full-width { 83 | width: 100%; 84 | } 85 | 86 | $switch-focus: 5px solid red; 87 | 88 | .add-vertical-scroll { 89 | overflow-y: auto !important; 90 | } 91 | 92 | .gutter { 93 | background-color: $primary-500; 94 | background-position: 50%; 95 | } 96 | 97 | // cursorStyles not working 98 | .gutter.gutter-horizontal { 99 | height: 100%; 100 | } 101 | 102 | .gutter.gutter-horizontal:hover { 103 | cursor: col-resize; 104 | } 105 | .gutter.gutter-vertical:hover { 106 | cursor: row-resize; 107 | } 108 | 109 | .no-focus-outline:focus { 110 | outline: none; 111 | } 112 | 113 | -------------------------------------------------------------------------------- /src/assets/style/darkMode.scss: -------------------------------------------------------------------------------- 1 | $neutral-100: #aeaeae; 2 | $neutral-200: #9c9cb1; 3 | $neutral-300: #575757; 4 | $neutral-400: #1f282e; 5 | $neutral-500: #434343; 6 | $neutral-600: #000000; 7 | $text: #1e3163; 8 | $text-dark: #000000; 9 | $text-dark-placeholder: #558a78; 10 | 11 | .is-dark-mode { 12 | background-color: $neutral-500 !important; 13 | color: white; 14 | } 15 | 16 | .is-dark-500 { 17 | background-color: $neutral-500 !important; 18 | color: white; 19 | //scrollbar-color: grey !important; 20 | } 21 | 22 | .is-dark-400 { 23 | background-color: $neutral-400 !important; 24 | color: white; 25 | // sidebar container: 64 26 | // contents container: 39 27 | // ResponsePaneContainer: 56 28 | } 29 | 30 | .is-dark-300 { 31 | background-color: $neutral-300 !important; 32 | color: white; 33 | outline: 1px solid $neutral-200 !important; 34 | } 35 | 36 | .is-dark-200 { 37 | background-color: $neutral-200 !important; 38 | color: white; 39 | } 40 | 41 | .is-dark-100 { 42 | background-color: $neutral-100 !important; 43 | color: white; 44 | } 45 | 46 | .dark-text { 47 | color: $text-dark !important; 48 | } 49 | .dark-address-input { 50 | background-color: $neutral-300 !important; 51 | color: white !important; 52 | } 53 | .dark-address-input::placeholder { 54 | color: $text-dark-placeholder !important; 55 | } 56 | .dark-divider { 57 | // this is the divider underneath tabs -Prince 58 | border-left: 1px solid $neutral-300; 59 | border-right: 1px solid $neutral-300; 60 | } 61 | 62 | -------------------------------------------------------------------------------- /src/assets/style/infinite.css: -------------------------------------------------------------------------------- 1 | /* Make the element pulse (grow large and small slowly) */ 2 | /* Usage 3 | .myElement { 4 | animation: pulsate 1s ease-out; 5 | animation-iteration-count: infinite; 6 | opacity: 1; 7 | } 8 | */ 9 | @-webkit-keyframes pulsate { 10 | 0% { 11 | -webkit-transform: scale(0.1, 0.1); 12 | opacity: 0; 13 | } 14 | 50% { 15 | opacity: 1; 16 | } 17 | 100% { 18 | -webkit-transform: scale(1.2, 1.2); 19 | opacity: 0; 20 | } 21 | } 22 | 23 | /* Make the element's opacity pulse*/ 24 | /* Usage 25 | .myElement { 26 | animation: opacityPulse 1s ease-out; 27 | animation-iteration-count: infinite; 28 | opacity: 0; 29 | } 30 | */ 31 | @-webkit-keyframes opacityPulse { 32 | 0% { 33 | opacity: 0; 34 | } 35 | 50% { 36 | opacity: 1; 37 | } 38 | 100% { 39 | opacity: 0; 40 | } 41 | } 42 | 43 | /* Make the element's background pulse. I call this alertPulse because it is red. You can call it something more generic. */ 44 | /* Usage 45 | .myElement { 46 | animation: alertPulse 1s ease-out; 47 | animation-iteration-count: infinite; 48 | opacity: 1; 49 | } 50 | */ 51 | @-webkit-keyframes alertPulse { 52 | 0% { 53 | background-color: #9a2727; 54 | opacity: 1; 55 | } 56 | 50% { 57 | opacity: red; 58 | opacity: 0.75; 59 | } 60 | 100% { 61 | opacity: #9a2727; 62 | opacity: 1; 63 | } 64 | } 65 | 66 | /* Make the element rotate infinitely. */ 67 | /* 68 | Usage 69 | .myElement { 70 | animation: rotating 3s linear infinite; 71 | } 72 | */ 73 | @keyframes rotating { 74 | from { 75 | -ms-transform: rotate(0deg); 76 | -moz-transform: rotate(0deg); 77 | -webkit-transform: rotate(0deg); 78 | -o-transform: rotate(0deg); 79 | transform: rotate(0deg); 80 | } 81 | to { 82 | -ms-transform: rotate(360deg); 83 | -moz-transform: rotate(360deg); 84 | -webkit-transform: rotate(360deg); 85 | -o-transform: rotate(360deg); 86 | transform: rotate(360deg); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/assets/style/webSocketResponse.scss: -------------------------------------------------------------------------------- 1 | .client-background { 2 | background-color: #3734a9; 3 | display: inline-block; 4 | padding: 4px 8px; 5 | border: 0px; 6 | border-radius: 8px; 7 | } 8 | 9 | .server-background { 10 | background-color: #21d4a4; 11 | display: inline-block; 12 | padding: 4px 8px; 13 | border: 0px; 14 | border-radius: 8px; 15 | } 16 | 17 | .client { 18 | color: #737581; 19 | font-size: 0.7rem; 20 | text-align: right; 21 | margin-right: 0.25rem; 22 | font-style: italic; 23 | } 24 | 25 | .server { 26 | color: #737581; 27 | font-size: 0.7rem; 28 | margin-left: 0.25rem; 29 | font-style: italic; 30 | } 31 | 32 | .websocket_message_container { 33 | position: relative; 34 | overflow-y: scroll; 35 | max-height: 80vh; 36 | width: 100%; 37 | height: 100%; 38 | padding-right: 17px; 39 | 40 | box-sizing: content-box; 41 | } 42 | 43 | .overflow-parent-container { 44 | overflow: hidden; 45 | width: 100%; 46 | height: 100%; 47 | } 48 | 49 | .websocket_message-client { 50 | padding: 4px 8x; 51 | color: #fff; 52 | text-align: right; 53 | } 54 | 55 | .websocket_message-server { 56 | color: #fff; 57 | display: block; 58 | position: relative; 59 | } 60 | 61 | .showWebsocketFileWarning { 62 | color: red; 63 | align-self: flex-end; 64 | } 65 | 66 | .animatedmain { 67 | position: relative; 68 | width: 200px; 69 | height: 50px; 70 | background: #f66b61; 71 | border-radius: 5px; 72 | border: 2px solid white; 73 | overflow: hidden; 74 | } 75 | 76 | .animatedfill { 77 | position: absolute; 78 | top: 0; 79 | left: 0; 80 | width: 100%; 81 | height: 100%; 82 | background: #21d4a4; 83 | } 84 | 85 | .animatedcontent { 86 | position: absolute; 87 | top: 0; 88 | left: 0; 89 | width: 100%; 90 | height: 100%; 91 | display: flex; 92 | align-items: center; 93 | justify-content: center; 94 | color: white; 95 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, 96 | Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; 97 | } 98 | -------------------------------------------------------------------------------- /src/client/components/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-source-labs/Swell/a231bbe07e0c9ae1deeab82b029d162356a75ac7/src/client/components/.DS_Store -------------------------------------------------------------------------------- /src/client/components/Versions.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { useState } from 'react'; 3 | 4 | declare global { 5 | interface Window { 6 | api: { 7 | versions: { 8 | electron: string; 9 | chrome: string; 10 | node: string; 11 | }; 12 | }; 13 | } 14 | } 15 | 16 | function Versions(): JSX.Element { 17 | const [versions] = useState(window.api.versions); 18 | 19 | return ( 20 |
    21 |
  • Electron v{versions.electron}
  • 22 |
  • Chromium v{versions.chrome}
  • 23 |
  • Node v{versions.node}
  • 24 |
25 | ); 26 | } 27 | 28 | export default Versions; 29 | 30 | -------------------------------------------------------------------------------- /src/client/components/customMuiStyles/tooltip.tsx: -------------------------------------------------------------------------------- 1 | import { Tooltip, TooltipProps, styled, tooltipClasses } from '@mui/material'; 2 | import React from 'react'; 3 | 4 | const FONTSIZE: number = 13; 5 | 6 | export const SwellTooltip = styled(({ className, ...props }: TooltipProps) => ( 7 | 8 | ))({ 9 | [`& .${tooltipClasses.tooltip}`]: { 10 | maxWidth: 'none', 11 | fontSize: FONTSIZE, 12 | }, 13 | }); 14 | 15 | export const SwellWrappedTooltip = styled( 16 | ({ className, ...props }: TooltipProps) => ( 17 | 18 | ) 19 | )({ 20 | [`& .${tooltipClasses.tooltip}`]: { 21 | fontSize: FONTSIZE, 22 | textAlign: 'center', 23 | }, 24 | }); 25 | 26 | -------------------------------------------------------------------------------- /src/client/components/legacy-components/UpdatePopUpContainer.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | This Component is used to auto update the app, but it doesn't really work. 3 | When migrating to gitHub Actions, it was disabled, but we didn't want to delete 4 | it if it turnes out to be useful for future iterators. That being said, if the 5 | app has solved the update task without it, this comp and the code in main.js ought to be 6 | deleted. 7 | */ 8 | 9 | // import React, { useEffect, useState } from 'react'; 10 | 11 | // const { api } = window; 12 | 13 | // const UpdatePopUpContainer = () => { 14 | // // Used to toggle the "update" pop-up. 15 | // const [message, setMessage] = useState(null); 16 | 17 | // useEffect(() => { 18 | // api.receive('message', (e, text) => { 19 | // console.log('AUTO-UPDATER STATUS: ' + e); 20 | // if (text) setMessage(text); 21 | // }); 22 | // }); 23 | 24 | // if (!message) { 25 | // return null; 26 | // } 27 | 28 | // const handleUpdateClick = () => { 29 | // api.send('quit-and-install'); 30 | // setMessage(null); 31 | // }; 32 | 33 | // return ( 34 | //
35 | // {message} 36 | 37 | // {message === 'Update downloaded.' && ( 38 | // <> 39 | // 40 | // Do you want to restart and install now? (If not, will auto-install 41 | // on restart.) 42 | // 43 | // 44 | // )} 45 | 46 | // 52 | 53 | // {message === 'Update downloaded.' && ( 54 | // 60 | // )} 61 | //
62 | // ); 63 | // }; 64 | 65 | // export default UpdatePopUpContainer; 66 | -------------------------------------------------------------------------------- /src/client/components/main/GraphQL-composer/GraphQLBodyEntryForm.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import { useAppDispatch, useAppSelector } from '../../../toolkit-refactor/hooks'; 3 | import TextCodeArea from '../sharedComponents/TextCodeArea'; 4 | import { NewRequestBody, NewRequestBodySet } from '../../../../types'; 5 | 6 | interface Props { 7 | newRequestBody: NewRequestBody 8 | newRequestBodySet: NewRequestBodySet; 9 | warningMessage: { body: string } | null; 10 | introspectionData: Record | null; 11 | } 12 | 13 | const GraphQLBodyEntryForm: React.FC = (props) => { 14 | const { 15 | newRequestBody, 16 | newRequestBody: { bodyContent, bodyIsNew }, 17 | newRequestBodySet, 18 | warningMessage, 19 | introspectionData, 20 | } = props; 21 | 22 | const [cmValue, setValue] = useState(bodyContent); 23 | 24 | // set a new value for codemirror only if loading from history or changing query type 25 | useEffect(() => { 26 | if (!bodyIsNew) setValue(bodyContent); 27 | }, [bodyContent, bodyIsNew]); 28 | 29 | const isDark = useAppSelector((store: { ui: { isDark: boolean } }) => store.ui.isDark); 30 | 31 | return ( 32 |
33 | { 34 | // conditionally render warning message 35 | warningMessage ?
{warningMessage.body}
: null 36 | } 37 |
Body
38 |
39 | { 43 | newRequestBodySet({ 44 | ...newRequestBody, 45 | bodyContent: value, 46 | bodyIsNew: true, 47 | }); 48 | }} 49 | /> 50 |
51 |
52 | ); 53 | }; 54 | 55 | export default GraphQLBodyEntryForm; 56 | -------------------------------------------------------------------------------- /src/client/components/main/GraphQL-composer/GraphQLIntrospectionLog.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useAppDispatch, useAppSelector } from '../../../toolkit-refactor/hooks'; 3 | import { GraphQLSchema } from 'graphql'; 4 | 5 | import graphQLController from '../../../controllers/graphQLController'; 6 | import TextCodeArea from '../sharedComponents/TextCodeArea'; 7 | import { RootState } from '../../../toolkit-refactor/store'; 8 | 9 | interface IntrospectionData { 10 | schemaSDL: string | null; 11 | clientSchema: GraphQLSchema | null; 12 | } 13 | 14 | const GraphQLIntrospectionLog: React.FC = () => { 15 | const headers = useAppSelector( 16 | (store: RootState) => store.newRequest.newRequestHeaders.headersArr 17 | ); 18 | const cookies = useAppSelector( 19 | (store: RootState) => store.newRequest.newRequestCookies.cookiesArr 20 | ); 21 | const introspectionData: (IntrospectionData | string) = useAppSelector( 22 | (store: RootState) => store.introspectionData 23 | ); 24 | const url: string = useAppSelector( 25 | (store: RootState) => store.newRequestFields.url 26 | ); 27 | const isDark: boolean = useAppSelector((store: RootState) => store.ui.isDark); 28 | 29 | return ( 30 |
31 | 37 |
38 | {/* added the .schemaSDL and toString() below to fix type errors. Not sure the intent of the original engineer */} 39 | {introspectionData.schemaSDL === 'Error: Please enter a valid GraphQL API URI' && ( 40 |
{introspectionData.toString()}
41 | )} 42 | {!!introspectionData.schemaSDL && ( 43 | {}} 47 | readOnly={true} 48 | /> 49 | )} 50 |
51 |
52 | ); 53 | }; 54 | 55 | export default GraphQLIntrospectionLog; 56 | -------------------------------------------------------------------------------- /src/client/components/main/GraphQL-composer/GraphQLVariableEntryForm.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import { useAppDispatch, useAppSelector } from '../../../toolkit-refactor/hooks'; 3 | import TextCodeArea from '../sharedComponents/TextCodeArea'; 4 | import { NewRequestBody, NewRequestBodySet } from '../../../../types'; 5 | 6 | interface GraphQLVariableEntryFormProps { 7 | newRequestBody: NewRequestBody; 8 | newRequestBodySet: NewRequestBodySet; 9 | } 10 | 11 | const GraphQLVariableEntryForm: React.FC = ({ 12 | newRequestBody: { bodyVariables, bodyIsNew }, 13 | newRequestBody, 14 | newRequestBodySet, 15 | }) => { 16 | const [cmValue, setValue] = useState(bodyVariables); 17 | 18 | // set a new value for codemirror only if loading from history or changing gQL type 19 | useEffect(() => { 20 | if (!bodyIsNew) setValue(bodyVariables); 21 | }, [bodyVariables, bodyIsNew]); 22 | 23 | const isDark = useAppSelector((store: { ui: { isDark: boolean } }) => store.ui.isDark); 24 | return ( 25 |
26 |
Variables
27 |
28 | { 34 | setValue(value); 35 | newRequestBodySet({ 36 | ...newRequestBody, 37 | bodyVariables: value, 38 | bodyIsNew: true, 39 | }); 40 | }} 41 | /> 42 |
43 |
44 | ); 45 | }; 46 | 47 | export default GraphQLVariableEntryForm; -------------------------------------------------------------------------------- /src/client/components/main/OpenAPI-composer/OpenAPIDocumentEntryForm.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useAppDispatch, useAppSelector } from '../../../toolkit-refactor/hooks'; 3 | import openApiController from '../../../controllers/openApiController'; 4 | 5 | // this component is working as intended 6 | 7 | const OpenAPIDocumentEntryForm: React.FC = () => { 8 | const isDark = useAppSelector((store: { ui: { isDark: boolean } }) => store.ui.isDark); 9 | 10 | const importDoc = (): void => { 11 | openApiController.sendDocument(); 12 | openApiController.importDocument(); 13 | } 14 | 15 | return ( 16 |
17 |
18 | 24 |
25 |
26 | ); 27 | }; 28 | 29 | export default OpenAPIDocumentEntryForm; 30 | -------------------------------------------------------------------------------- /src/client/components/main/OpenAPI-composer/OpenAPIEntryForm.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useAppDispatch, useAppSelector } from '../../../toolkit-refactor/hooks'; 3 | import { $TSFixMe } from '../../../../types'; 4 | 5 | interface Props { 6 | warningMessage: { 7 | uri?: string; 8 | }; 9 | newRequestsOpenAPI: $TSFixMe 10 | primaryServer: string 11 | } 12 | 13 | // This component is working as intended, though needs to have the TS tightened up 14 | const OpenAPIEntryForm: React.FC = ({ 15 | warningMessage, 16 | newRequestsOpenAPI, 17 | primaryServer 18 | }) => { 19 | // This loads the input field at the top of the page 20 | const isDark = useAppSelector((store: { ui: { isDark: boolean } }) => store.ui.isDark); 21 | 22 | return ( 23 |
25 | 28 | {return 'testTest'}} 36 | /> 37 | {warningMessage.uri && ( 38 |
{warningMessage.uri}
39 | )} 40 |
41 | ); 42 | }; 43 | 44 | export default OpenAPIEntryForm; 45 | -------------------------------------------------------------------------------- /src/client/components/main/OpenAPI-composer/OpenAPIMetadata.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { $TSFixMe } from '../../../../types'; 3 | 4 | interface Props { 5 | newRequestsOpenAPI: $TSFixMe; 6 | } 7 | 8 | // This component is working as intended, but need the TS tightened up 9 | 10 | const OpenAPIMetaData: React.FC = (props: Props) => { 11 | 12 | const { newRequestsOpenAPI } = props 13 | 14 | const conditionalChecker = (key: string) => { 15 | if (newRequestsOpenAPI.openapiMetadata) { 16 | return newRequestsOpenAPI.openapiMetadata.info[key] ? newRequestsOpenAPI.openapiMetadata.info[key] : ''; 17 | } 18 | return ''; 19 | } 20 | 21 | return ( 22 |
23 |
24 |
Metadata
25 |
26 | 27 |
28 |
Title
29 | {conditionalChecker('title')} 30 |
31 | 32 |
33 |
Description
34 | {conditionalChecker('description')} 35 |
36 | 37 |
38 |
Version
39 | {conditionalChecker('version')} 40 |
41 | 42 |
43 |
OpenAPI
44 | {conditionalChecker('openapi')} 45 |
46 |
47 |
48 | ); 49 | } 50 | 51 | export default OpenAPIMetaData; 52 | -------------------------------------------------------------------------------- /src/client/components/main/TRPC-composer/TRPCBodyEntryForm.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import { useAppDispatch, useAppSelector } from '../../../toolkit-refactor/hooks'; 3 | import { RootState } from '../../../toolkit-refactor/store'; 4 | import TextCodeArea from '../sharedComponents/TextCodeArea'; 5 | 6 | /** 7 | * renders entry form for TRPC request 8 | */ 9 | 10 | const TRPCBodyEntryForm = (props: any) => { 11 | const { newRequestBodySet } = props; 12 | const dispatch = useAppDispatch(); 13 | const newRequestBody = useAppSelector( 14 | (store: RootState) => store.newRequest.newRequestBody 15 | ); 16 | const { bodyContent } = newRequestBody; 17 | 18 | const isDark = useAppSelector((store: { ui: { isDark: boolean } }) => store.ui.isDark); 19 | const [cmValue, setValue] = useState(bodyContent); 20 | 21 | return ( 22 |
23 |
Body
24 |
25 | { 29 | dispatch( 30 | newRequestBodySet({ 31 | ...newRequestBody, 32 | bodyContent: value, 33 | bodyIsNew: true, 34 | }) 35 | ); 36 | }} 37 | /> 38 |
39 |
40 | ); 41 | }; 42 | 43 | export default TRPCBodyEntryForm; 44 | 45 | -------------------------------------------------------------------------------- /src/client/components/main/TRPC-composer/TRPCMethodAndEndpointEntryForm.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable jsx-a11y/anchor-is-valid */ 2 | /* eslint-disable jsx-a11y/no-static-element-interactions */ 3 | /* eslint-disable jsx-a11y/click-events-have-key-events */ 4 | import React, { useState, useRef, useEffect } from 'react'; 5 | import { useAppDispatch, useAppSelector } from '../../../toolkit-refactor/hooks'; 6 | 7 | import { RootState } from '../../../toolkit-refactor/store'; 8 | import { fieldsReplaced } from '../../../toolkit-refactor/slices/newRequestFieldsSlice'; 9 | 10 | const TRPCMethodAndEndpointEntryForm = (props: any) => { 11 | const requestFields = useAppSelector( 12 | (state: RootState) => state.newRequestFields 13 | ); 14 | 15 | const isDark = useAppSelector((store: { ui: { isDark: boolean } }) => store.ui.isDark); 16 | 17 | const dispatch = useAppDispatch(); 18 | const clearWarningIfApplicable = () => { 19 | if (props.warningMessage.uri) props.setWarningMessage({}); 20 | }; 21 | const urlChangeHandler = (e: React.ChangeEvent) => { 22 | clearWarningIfApplicable(); 23 | //update global redux store everytime user make changes to url 24 | const url: string = e.target.value; 25 | 26 | dispatch( 27 | fieldsReplaced({ 28 | ...requestFields, 29 | url: url, 30 | }) 31 | ); 32 | }; 33 | return ( 34 | <> 35 |
39 |
40 | tRPC 41 |
42 | { 50 | urlChangeHandler(e); 51 | }} 52 | /> 53 |
54 | {props.warningMessage.uri && ( 55 |
{props.warningMessage.uri}
56 | )} 57 | 58 | ); 59 | }; 60 | 61 | export default TRPCMethodAndEndpointEntryForm; 62 | 63 | -------------------------------------------------------------------------------- /src/client/components/main/TRPC-composer/TRPCProcedure.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import TRPCVariableForm from './TRPCVariableForm'; 3 | import TRPCPrceduresEndPoint from './TRPCPrceduresEndPoint'; 4 | 5 | export default function TRPCProcedure(props) { 6 | //renders each procedure 7 | return ( 8 |
9 | 14 | 15 | 20 |
21 | ); 22 | } 23 | 24 | const container = { 25 | padding: '10px 0px', 26 | }; 27 | 28 | -------------------------------------------------------------------------------- /src/client/components/main/TRPC-composer/TRPCProceduresContainer.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import TRPCProcedure from './TRPCProcedure'; 3 | 4 | export default function TRPCProceduresContainer(props) { 5 | //renders all of the procedures inside the procedures array 6 | const proceduresJSX = props.procedures.map((procedure, index) => { 7 | return ( 8 | 14 | ); 15 | }); 16 | return ( 17 |
18 |

Your Procedure/s

19 | {proceduresJSX} 20 |
21 | ); 22 | } 23 | 24 | const h3Styles = { 25 | display: 'block', 26 | fontSize: '1.17em', 27 | fontWeight: 'bold', 28 | }; 29 | 30 | -------------------------------------------------------------------------------- /src/client/components/main/TRPC-composer/TRPCVariableForm.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import TextCodeArea from '../sharedComponents/TextCodeArea'; 3 | import { useAppDispatch, useAppSelector } from '../../../toolkit-refactor/hooks'; 4 | import { vscodeDark } from '@uiw/codemirror-theme-vscode'; 5 | //TODO: implicit and literal any used in this file 6 | export default function TRPCVariableForm(props) { 7 | // input for for user to attach argument with their procedures 8 | const isDark = useAppSelector((store: { ui: { isDark: boolean } }) => store.ui.isDark); 9 | const onChangeHandler = (string: string) => { 10 | // this function dispatch action to the main reducer function inside of trpc composer 11 | props.proceduresDipatch({ 12 | type: 'VARIABLE', 13 | payload: { index: props.index, value: string }, 14 | }); 15 | }; 16 | return ( 17 |
18 |
19 | 26 |
27 |
28 | ); 29 | } 30 | 31 | -------------------------------------------------------------------------------- /src/client/components/main/WebRTC-composer/WebRTCAudioBox.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | // possibly not the best practice implementation for audio playback ? 3 | interface Props { 4 | streamType: 'localstream' | 'remotestream'; 5 | } 6 | const WebRTCAudioBox: React.FC = (props: Props) => { 7 | const { streamType } = props; 8 | return ( 9 | 23 | ); 24 | }; 25 | 26 | export default WebRTCAudioBox; 27 | 28 | -------------------------------------------------------------------------------- /src/client/components/main/WebRTC-composer/WebRTCVideoBox.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | interface Props { 4 | streamType: 'localstream' | 'remotestream' 5 | } 6 | const WebRTCVideoBox: React.FC = (props: Props) => { 7 | const { streamType } = props 8 | return ( 9 |
13 | 19 | {streamType} 20 |
21 | ); 22 | }; 23 | 24 | export default WebRTCVideoBox; 25 | -------------------------------------------------------------------------------- /src/client/components/main/WebSocket-composer/WSEndpointEntryForm.tsx: -------------------------------------------------------------------------------- 1 | 2 | import React from 'react'; 3 | import { useAppDispatch, useAppSelector } from '../../../toolkit-refactor/hooks'; 4 | 5 | interface Props { 6 | warningMessage: Record; 7 | setWarningMessage: React.Dispatch>>; 8 | fieldsReplaced: (newFields: Record) => void; 9 | newRequestFields: Record; 10 | } 11 | 12 | const WSEndpointEntryForm: React.FC = ({ 13 | warningMessage, 14 | setWarningMessage, 15 | fieldsReplaced, 16 | newRequestFields, 17 | }) => { 18 | const warningCheck = () => { 19 | if (warningMessage.uri) { 20 | const warningMessageCopy = { ...warningMessage }; 21 | delete warningMessageCopy.uri; 22 | setWarningMessage({ ...warningMessageCopy }); 23 | } 24 | }; 25 | 26 | const urlChangeHandler = (e: React.ChangeEvent) => { 27 | warningCheck(); 28 | const url = e.target.value; 29 | fieldsReplaced({ 30 | ...newRequestFields, 31 | wsUrl: url, 32 | url, 33 | }); 34 | }; 35 | 36 | const isDark = useAppSelector((store: { ui: { isDark: boolean } }) => store.ui.isDark); 37 | 38 | return ( 39 |
43 |
44 | WS 45 |
46 | 56 | {warningMessage.uri && ( 57 |
{warningMessage.uri}
58 | )} 59 |
60 | ); 61 | }; 62 | 63 | export default WSEndpointEntryForm; 64 | -------------------------------------------------------------------------------- /src/client/components/main/http2-composer/Http2EndpointForm.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | // Import MUI components 3 | import { Box, Button, MenuItem, FormControl, Select, SelectChangeEvent, TextField } from '@mui/material' 4 | 5 | export default function Http2EndpointForm({ http2Method, setHttp2Method, http2Uri, setHttp2Uri }) { 6 | // const [method, setMethod] = React.useState('get'); 7 | const handleMethodSelect = (event: SelectChangeEvent) => { 8 | setHttp2Method(event.target.value as string); 9 | }; 10 | // const [uri, setUri] = React.useState(''); 11 | const handleUriInput = (event: React.ChangeEvent) => { 12 | setHttp2Uri(event.target.value as string); 13 | }; 14 | return( 15 | 20 | 26 | 37 | 38 | 46 | 52 | 53 | ) 54 | } 55 | -------------------------------------------------------------------------------- /src/client/components/main/http2-composer/KeyValueForm.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | // Import MUI components 3 | import { Box, Button, TextField, Checkbox } from '@mui/material'; 4 | import ClearRoundedIcon from '@mui/icons-material/ClearRounded'; 5 | 6 | export default function KeyValueForm({ type, index, state, setState }) { 7 | const [key, setKey] = useState(state[index].key) 8 | const [value, setValue] = useState(state[index].value) 9 | 10 | const handleKeyInput = (event: React.ChangeEvent) => { 11 | state[index].key = event.target.value; 12 | setKey(state[index].key) 13 | setState([...state]); 14 | } 15 | 16 | const handleValueInput = (event: React.ChangeEvent) => { 17 | state[index].value = event.target.value; 18 | setValue(state[index].value) 19 | setState([...state]); 20 | } 21 | 22 | const handleDelete = () => { 23 | state.splice(index, 1) 24 | setState([...state]); 25 | } 26 | 27 | const handleToggle = () => { 28 | state[index].toggle = !state[index].toggle; 29 | setState([...state]); 30 | } 31 | 32 | return( 33 | 40 | 46 | 52 | 58 | 66 | 67 | ) 68 | } 69 | -------------------------------------------------------------------------------- /src/client/components/main/http2-composer/KeyValueTable.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { v4 as uuid } from 'uuid'; 3 | // Import local components 4 | import KeyValueForm from './KeyValueForm'; 5 | // Import MUI components 6 | import { Box, Button } from '@mui/material'; 7 | 8 | export default function KeyValueTable({ type, state, setState }) { 9 | console.log(`${type} state`, state) 10 | 11 | const keyValueForms = []; 12 | for (let i = 0; i < state.length; i += 1) { 13 | keyValueForms.push( 14 | 21 | ); 22 | } 23 | 24 | const handleAddNewForm = () => { 25 | state.push({ id: uuid(), key: '', value: '', toggle: false }) 26 | setState([...state]) 27 | } 28 | 29 | return( 30 | 37 | {keyValueForms} 38 | 44 | 45 | ) 46 | } 47 | -------------------------------------------------------------------------------- /src/client/components/main/response-composer/CookieContainer.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable array-callback-return */ 2 | /* eslint-disable jsx-a11y/no-noninteractive-element-interactions */ 3 | /* eslint-disable jsx-a11y/click-events-have-key-events */ 4 | import React, { useState } from 'react'; 5 | import { useAppDispatch, useAppSelector } from '../../../toolkit-refactor/hooks'; 6 | 7 | interface CookieProps { 8 | className?: string; 9 | cookie: { 10 | [key: string]: any; 11 | }; 12 | } 13 | 14 | export default function CookieContainer({ className, cookie }: CookieProps) { 15 | const [showCookie, setShowCookie] = useState(false); 16 | const isDark = useAppSelector((store: { ui: { isDark: boolean } }) => store.ui.isDark); 17 | 18 | const cookies = Object.entries(cookie).map(([key, value], index) => { 19 | if (!key || !value) return null; 20 | if ((showCookie === true && index > 1) || (index <= 1)) { 21 | return ( 22 | 23 | {key} 24 | {value.toString()} 25 | 26 | ); 27 | } 28 | return null; 29 | }); 30 | 31 | return ( 32 | { 35 | setShowCookie(showCookie === false); 36 | }} 37 | > 38 | 39 | 40 | 41 | 42 | 43 | 44 | {cookies} 45 |
KeyValue
46 | ); 47 | } 48 | 49 | -------------------------------------------------------------------------------- /src/client/components/main/response-composer/CookiesContainer.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import EmptyState from './EmptyState'; 3 | import CookieContainer from './CookieContainer'; 4 | 5 | interface CookiesContainerProps { 6 | currentResponse: { 7 | response?: { 8 | cookies?: Array<{ 9 | [key: string]: any; 10 | }>; 11 | }; 12 | }; 13 | } 14 | 15 | export default function CookiesContainer({ currentResponse }: CookiesContainerProps) { 16 | if ( 17 | !currentResponse.response || 18 | !currentResponse.response.cookies || 19 | !currentResponse.response.cookies.length 20 | ) { 21 | return ; 22 | } 23 | 24 | const responseCookies = currentResponse.response.cookies.map( 25 | (cookie, index) => { 26 | return ( 27 | 32 | ); 33 | } 34 | ); 35 | 36 | return
{responseCookies}
; 37 | } 38 | -------------------------------------------------------------------------------- /src/client/components/main/response-composer/EmptyState.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import logofaded from '../../../../assets/img/swell-logo-faded.avif'; 3 | import { useAppSelector } from '../../../toolkit-refactor/hooks'; 4 | 5 | interface EmptyStateProps { 6 | connection?: any; 7 | } 8 | 9 | export default function EmptyState({ connection }: EmptyStateProps) { 10 | const isDark = useAppSelector((store: { ui: { isDark: boolean } }) => store.ui.isDark); 11 | 12 | return ( 13 |
14 | faded-logo 20 |
21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /src/client/components/main/response-composer/ResponseTime.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | interface Props { 4 | currentResponse: { 5 | timeReceived?: number; 6 | timeSent?: number; 7 | response?: { 8 | messages?: any[]; 9 | }; 10 | request?: { 11 | messages?: any[]; 12 | }; 13 | }; 14 | } 15 | 16 | function ResponseTime({ currentResponse }: Props) { 17 | if ( 18 | currentResponse && 19 | currentResponse.timeReceived && 20 | currentResponse.timeSent 21 | ) { 22 | const responseTime = 23 | currentResponse.timeReceived - currentResponse.timeSent; 24 | 25 | return
{`${responseTime}ms`}
; 26 | } 27 | 28 | //websocket: 29 | if ( 30 | currentResponse && 31 | currentResponse.response && 32 | currentResponse.response.messages && 33 | currentResponse.request?.messages && 34 | currentResponse.response.messages.length > 0 && 35 | currentResponse.response.messages.length === 36 | currentResponse.request.messages.length 37 | ) { 38 | const leng = currentResponse.request.messages.length; 39 | const requestTime = currentResponse.request.messages[leng - 1].timeReceived; 40 | 41 | const responseTime = 42 | currentResponse.response.messages[leng - 1].timeReceived; 43 | 44 | const lagTime = responseTime - requestTime; 45 | return
{`${lagTime}ms`}
; 46 | } 47 | 48 | return null; 49 | } 50 | 51 | export default ResponseTime; -------------------------------------------------------------------------------- /src/client/components/main/response-composer/StatusButtons.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | interface Props { 4 | currentResponse: { 5 | error?: boolean; 6 | graphQL?: boolean; 7 | response?: { 8 | headers?: { 9 | [key: string]: string; 10 | }; 11 | }; 12 | }; 13 | } 14 | 15 | const StatusButtons: React.FC = ({ currentResponse }) => { 16 | if (currentResponse.error || !currentResponse) { 17 | return
Error
; 18 | } 19 | 20 | // STATUS FOR GRAPHQL 21 | if (currentResponse.graphQL === true && currentResponse.response) { 22 | return
Success
; 23 | } 24 | 25 | if ( 26 | !currentResponse.response || 27 | !currentResponse.response.headers || 28 | Object.keys(currentResponse.response.headers).length === 0 || 29 | !currentResponse.response.headers[':status'] 30 | ) { 31 | return null; 32 | } 33 | 34 | // RECEIVING STATUS CODE AND CONVERTING INTO STRING 35 | const statusCode = currentResponse.response.headers[':status'].toString(); 36 | 37 | if (statusCode.startsWith('2')) { 38 | return
{statusCode}
; 39 | } 40 | 41 | return
{statusCode}
; 42 | }; 43 | 44 | export default StatusButtons; -------------------------------------------------------------------------------- /src/client/components/main/response-composer/TestsContainer.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import EmptyState from './EmptyState'; 3 | import SingleTestContainer from './SingleTestContainer'; 4 | import { ReqRes, TestResult } from '../../../../types'; 5 | 6 | interface Props { 7 | currentResponse: ReqRes; 8 | } 9 | 10 | const TestsContainer: React.FC = ({ currentResponse }) => { 11 | return currentResponse.response?.testResult?.length ? ( 12 | 13 | ) : ( 14 | 15 | ); 16 | }; 17 | 18 | export default TestsContainer; 19 | -------------------------------------------------------------------------------- /src/client/components/main/response-composer/WebSocketMessage.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-unsafe-assignment */ 2 | /* eslint-disable @typescript-eslint/restrict-template-expressions */ 3 | /* eslint-disable camelcase */ 4 | import React from 'react'; 5 | 6 | interface WebSocketMessageProps { 7 | source: 'server' | 'client'; 8 | data: 'ArrayBuffer' | 'ArrayBufferView'; 9 | timeReceived: number; 10 | index: number; 11 | } 12 | 13 | const WebSocketMessage = ({ source, timeReceived, data, index }: WebSocketMessageProps) => { 14 | const webSocketMessageClassNames = 15 | source === 'server' 16 | ? 'websocket_message websocket_message-server' 17 | : 'websocket_message websocket_message-client'; 18 | const webSocketMessageIDNames = 19 | source === 'server' 20 | ? 'id_websocket_message-server' 21 | : 'id_websocket_message-client'; 22 | 23 | const message_background = 24 | source === 'server' ? 'server-background' : 'client-background'; 25 | const message_sender = source === 'server' ? 'server' : 'client'; 26 | 27 | const buildTime = (time: number): string => { 28 | const hours = new Date(time).getHours(); 29 | const h = hours >= 10 ? `${hours}` : `0${JSON.stringify(hours)}`; 30 | const minutes = new Date(time).getMinutes(); 31 | const m = minutes >= 10 ? `${minutes}` : `0${JSON.stringify(minutes)}`; 32 | const seconds = new Date(time).getSeconds(); 33 | const s = seconds >= 10 ? `${seconds}` : `0${JSON.stringify(seconds)}`; 34 | return `${h}:${m}:${s}`; 35 | }; 36 | 37 | const decodedData = typeof data === 'object' ? new TextDecoder('utf-8').decode(data) : data; 38 | 39 | return ( 40 |
41 |
42 |
43 |
44 | {typeof data === 'object' ? ( 45 | // decode buffer to dataURI 46 | img 47 | ) : ( 48 |
{data}
49 | )} 50 |
51 |
52 | {buildTime(timeReceived)} 53 |
54 |
55 |
56 |
{message_sender}
57 |
58 | ); 59 | }; 60 | 61 | export default WebSocketMessage; 62 | -------------------------------------------------------------------------------- /src/client/components/main/response-composer/webRTCResponseComponents/WebRTCTextItem.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { $TSFixMe } from '../../../../../types'; 3 | 4 | const WebRTCTextItem = (props: $TSFixMe) => { 5 | const { source, timeReceived, data } = props; 6 | const webSocketMessageClassNames = 7 | source === 'local' 8 | ? 'websocket_message websocket_message-client' 9 | : 'websocket_message websocket_message-server'; 10 | const webSocketMessageIDNames = 11 | source === 'local' 12 | ? 'id_websocket_message-client' 13 | : 'id_websocket_message-server'; 14 | 15 | const message_background = 16 | source === 'local' ? 'server-background' : 'client-background'; 17 | const message_sender = source === 'local' ? 'localstream' : 'remotestream'; 18 | 19 | const buildTime = (time: number): string => { 20 | const hours = new Date(time).getHours(); 21 | const h = hours >= 10 ? `${hours}` : `0${JSON.stringify(hours)}`; 22 | const minutes = new Date(time).getMinutes(); 23 | const m = minutes >= 10 ? `${minutes}` : `0${JSON.stringify(minutes)}`; 24 | const seconds = new Date(time).getSeconds(); 25 | const s = seconds >= 10 ? `${seconds}` : `0${JSON.stringify(seconds)}`; 26 | return `${h}:${m}:${s}`; 27 | }; 28 | 29 | return ( 30 |
31 |
32 |
{data}
33 | {buildTime(timeReceived)} 34 |
35 |
{message_sender}
36 |
37 | ); 38 | }; 39 | 40 | export default WebRTCTextItem; 41 | 42 | -------------------------------------------------------------------------------- /src/client/components/main/sharedComponents/JSONTextArea.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from 'react'; 2 | import TextCodeArea from './TextCodeArea'; 3 | import { NewRequestBody, NewRequestBodySet } from '../../../../types'; 4 | 5 | interface JSONTextAreaProps { 6 | newRequestBody: NewRequestBody 7 | newRequestBodySet: NewRequestBodySet 8 | } 9 | 10 | export default function JSONTextArea({ 11 | newRequestBody, 12 | newRequestBodySet, 13 | }: JSONTextAreaProps) { 14 | useEffect(() => { 15 | try { 16 | JSON.parse(newRequestBody.bodyContent); 17 | if (!newRequestBody.JSONFormatted) { 18 | newRequestBodySet({ 19 | ...newRequestBody, 20 | JSONFormatted: true, 21 | }); 22 | } 23 | } catch (error) { 24 | if (newRequestBody.JSONFormatted) { 25 | newRequestBodySet({ 26 | ...newRequestBody, 27 | JSONFormatted: false, 28 | }); 29 | } 30 | } 31 | }, [newRequestBody.bodyContent]); 32 | 33 | return ( 34 | { 37 | newRequestBodySet({ 38 | ...newRequestBody, 39 | bodyContent: value, 40 | }); 41 | }} 42 | value={newRequestBody.bodyContent} 43 | /> 44 | ); 45 | } 46 | -------------------------------------------------------------------------------- /src/client/components/main/sharedComponents/TextCodeArea.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import CodeMirror from '@uiw/react-codemirror'; 3 | import { vscodeDark } from '@uiw/codemirror-theme-vscode'; 4 | import { javascript } from '@codemirror/lang-javascript'; 5 | import { xml } from '@codemirror/lang-xml'; 6 | import { json } from '@codemirror/lang-json'; 7 | import { html } from '@codemirror/lang-html'; 8 | import { EditorView, ViewUpdate } from '@codemirror/view'; 9 | import { LanguageSupport } from '@codemirror/language'; 10 | 11 | interface TextCodeAreaProps { 12 | value: string; 13 | mode: string; 14 | onChange: (value: string, viewUpdate: ViewUpdate) => void; 15 | height?: string; 16 | width?: string; 17 | placeholder?: string; 18 | readOnly?: boolean; 19 | } 20 | 21 | const langs: { [key: string]: () => LanguageSupport } = { 22 | json: json, 23 | xml: xml, 24 | html: html, 25 | javascript: javascript, 26 | 27 | /** 28 | * @todo plaintext language is not yet supported in react-codemirror 29 | * (currently slated to be added in v6?), please update when it becomes 30 | * available 31 | */ 32 | plain: xml, 33 | }; 34 | 35 | export default function TextCodeArea({ 36 | value, 37 | mode, 38 | onChange, 39 | height = '200px', 40 | placeholder = 'Enter body here', 41 | readOnly = false, 42 | width, 43 | }: TextCodeAreaProps) { 44 | const lang: string = mode.substring(mode.indexOf('/') + 1); // Grab language mode based on value passed in 45 | return ( 46 |
47 | 57 |
58 | ); 59 | } 60 | 61 | -------------------------------------------------------------------------------- /src/client/components/main/sharedComponents/requestButtons/JSONPrettifyButton.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { NewRequestBody, NewRequestBodySet } from '../../../../../types'; 3 | 4 | interface Props { 5 | newRequestBodySet: NewRequestBodySet 6 | newRequestBody: NewRequestBody 7 | } 8 | 9 | function JSONPrettify({ newRequestBodySet, newRequestBody }: Props) { 10 | const prettyPrintJSON = () => { 11 | if (!newRequestBody.bodyContent) return; 12 | const prettyString = JSON.stringify( 13 | JSON.parse(newRequestBody.bodyContent), 14 | null, 15 | 4 16 | ); 17 | newRequestBodySet({ 18 | ...newRequestBody, 19 | bodyContent: prettyString, 20 | }); 21 | }; 22 | 23 | return ( 24 | 30 | ); 31 | } 32 | 33 | export default JSONPrettify; 34 | 35 | -------------------------------------------------------------------------------- /src/client/components/main/sharedComponents/requestButtons/NewRequestButton.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | interface Props { 4 | onClick: () => void; 5 | } 6 | 7 | const NewRequestButton: React.FC = ({ onClick }) => ( 8 | 16 | ); 17 | 18 | export default NewRequestButton; 19 | -------------------------------------------------------------------------------- /src/client/components/main/sharedComponents/requestButtons/SendRequestButton.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const SendRequestButton = ({ 4 | onClick, 5 | buttonText = 'Send Request', 6 | }: { 7 | onClick: () => void; 8 | buttonText?: string; 9 | }) => { 10 | return ( 11 | 20 | ); 21 | }; 22 | 23 | export default SendRequestButton; 24 | 25 | -------------------------------------------------------------------------------- /src/client/components/main/sharedComponents/requestForms/TestEntryForm.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import { useAppDispatch, useAppSelector } from '../../../../toolkit-refactor/hooks'; 3 | import TextCodeArea from '../TextCodeArea'; 4 | import RestTestSnippets from '../stressTest/RestTestSnippets'; 5 | import WebsocketTestSnippets from '../stressTest/WebsocketTestSnippets'; 6 | 7 | interface Props { 8 | isWebSocket?: boolean; 9 | testContent: string; 10 | newTestContentSet: (value: string) => void; 11 | } 12 | 13 | const TestEntryForm: React.FC = ({ 14 | isWebSocket, 15 | testContent, 16 | newTestContentSet, 17 | }) => { 18 | const isDark = useAppSelector((store: { ui: { isDark: boolean } }) => store.ui.isDark); 19 | 20 | const [showTests, setShowTests] = useState(false); 21 | const handleShowTests = () => setShowTests(!showTests); 22 | 23 | return ( 24 |
25 | {isWebSocket ? ( 26 | 31 | ) : ( 32 | 37 | )} 38 |
44 | {showTests === true && ( 45 | <> 46 | Hide Assertion Tests 47 | 48 | )} 49 | {showTests === false && ( 50 | <> 51 | View Assertion Tests 52 | 53 | )} 54 |
55 | {showTests === true && ( 56 |
57 | { 61 | newTestContentSet(value); 62 | }} 63 | /> 64 |
65 | )} 66 |
67 | ); 68 | }; 69 | 70 | export default TestEntryForm; 71 | -------------------------------------------------------------------------------- /src/client/components/main/sharedComponents/stressTest/RestTestSnippets.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable jsx-a11y/no-static-element-interactions */ 2 | /* eslint-disable jsx-a11y/click-events-have-key-events */ 3 | import React, { useState } from 'react'; 4 | import TestSnippetsButton from './TestSnippetsButton'; 5 | import { AppDispatch } from '../../../../toolkit-refactor/store'; 6 | 7 | export default function RestTestSnippets({ 8 | setShowTests, 9 | newTestContentSet, 10 | }: { 11 | setShowTests: (arg: boolean) => AppDispatch; 12 | newTestContentSet: (arg: string) => AppDispatch; 13 | }) { 14 | const [showSnippets, setShowSnippets] = useState(false); 15 | 16 | const handleShowSnippets = (): void => { 17 | setShowSnippets(!showSnippets); 18 | }; 19 | 20 | const snippets: { [key: string]: string } = { 21 | 'Assert response status code is 200': 22 | "assert.strictEqual(response.status, 200, 'response is 200')", 23 | 24 | 'Assert cookies are accessible from the response object': 25 | "assert.exists(response.cookies, 'cookies exists on response object')", 26 | }; 27 | 28 | const handleClick = (event: React.MouseEvent) => { 29 | setShowTests(true); 30 | newTestContentSet(snippets[`${(event.target as HTMLElement).innerHTML}`]); 31 | }; 32 | 33 | return ( 34 |
35 | 39 | 40 | {showSnippets === true && ( 41 |
42 |
43 | Click on the following example to create assertion test below! 44 |
45 | Assert response status code is 200 46 | 47 | Assert cookies are accessible from the response object 48 | 49 |
50 | )} 51 |
52 | ); 53 | } 54 | -------------------------------------------------------------------------------- /src/client/components/main/sharedComponents/stressTest/TestSnippetsButton.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable jsx-a11y/no-static-element-interactions */ 2 | /* eslint-disable jsx-a11y/click-events-have-key-events */ 3 | import React from 'react'; 4 | import { useAppDispatch, useAppSelector } from '../../../../toolkit-refactor/hooks'; 5 | 6 | export default function TestSnippetsButton({ 7 | showSnippets, 8 | handleShowSnippets, 9 | }: { 10 | showSnippets: boolean; 11 | handleShowSnippets: () => void; 12 | }) { 13 | const isDark = useAppSelector((store: { ui: { isDark: boolean } }) => store.ui.isDark); 14 | return ( 15 |
21 | {showSnippets === true && ( 22 | <> 23 | Hide Sample Assertion Test Snippets 24 | 25 | )} 26 | 27 | {showSnippets === false && ( 28 | <> 29 | View Sample Assertion Test Snippets 30 | 31 | )} 32 |
33 | ); 34 | } 35 | 36 | -------------------------------------------------------------------------------- /src/client/components/main/sharedComponents/stressTest/WebsocketTestSnippets.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable jsx-a11y/no-static-element-interactions */ 2 | /* eslint-disable jsx-a11y/click-events-have-key-events */ 3 | import React, { useState } from 'react'; 4 | import TestSnippetsButton from './TestSnippetsButton'; 5 | import { AppDispatch } from '../../../../toolkit-refactor/store'; 6 | 7 | export default function WebsocketTestSnippets({ 8 | setShowTests, 9 | newTestContentSet, 10 | }: { 11 | setShowTests: (arg: boolean) => AppDispatch; 12 | newTestContentSet: (arg: string) => AppDispatch; 13 | }) { 14 | const [showSnippets, setShowSnippets] = useState(false); 15 | 16 | const handleShowSnippets = (): void => { 17 | setShowSnippets(!showSnippets); 18 | }; 19 | 20 | const snippets: { [key: string]: string } = { 21 | 'Assert connection is open': 22 | "assert.strictEqual(response.connection, 'open', 'response is open')", 23 | }; 24 | 25 | const handleClick = (event: React.MouseEvent) => { 26 | setShowTests(true); 27 | newTestContentSet(snippets[`${(event.target as HTMLElement).innerHTML}`]); 28 | }; 29 | 30 | return ( 31 |
32 | 36 | 37 | {showSnippets === true && ( 38 |
39 |
40 | Click on the following example to create assertion test below! 41 |
42 | Assert connection is open 43 |
44 | )} 45 |
46 | ); 47 | } 48 | -------------------------------------------------------------------------------- /src/client/components/navbar/DarkModeSelect.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Box from '@mui/material/Box'; 3 | import IconButton from '@mui/material/IconButton'; 4 | import Brightness4Icon from '@mui/icons-material/Brightness4'; // Icon for light mode 5 | import Brightness7Icon from '@mui/icons-material/Brightness7'; // Icon for dark mode 6 | import { useAppDispatch, useAppSelector } from '../../toolkit-refactor/hooks'; 7 | import { toggleDarkMode } from '../../toolkit-refactor/slices/uiSlice'; 8 | 9 | export default function DarkModeToggle() { 10 | const dispatch = useAppDispatch(); 11 | const isDark = useAppSelector((store: { ui: { isDark: boolean } }) => store.ui.isDark); 12 | 13 | const handleToggleDarkMode = () => { 14 | dispatch(toggleDarkMode(!isDark)); 15 | }; 16 | 17 | return ( 18 | 28 | 32 | {/* Conditionally render the icon based on the isDark state */} 33 | {isDark ? : } 34 | 35 | 36 | ); 37 | } 38 | -------------------------------------------------------------------------------- /src/client/components/navbar/GeneralInfo.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Box from '@mui/material/Box'; 3 | import GitHubButton from 'react-github-btn'; 4 | 5 | export default function GeneralInfo() { 6 | return ( 7 | 17 | {/** 18 | * @todo This GitHub button comes from a component library. Should build 19 | * your own or find one that supports TS types. 20 | */} 21 | 22 | {/* @ts-ignore:next-line */} 23 | 29 | 30 | 31 | 32 | ); 33 | } 34 | -------------------------------------------------------------------------------- /src/client/components/navbar/NavBarContainer.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | // Import MUI components 4 | import { Box } from '@mui/material'; 5 | // Import local components. 6 | import ProtocolSelect from './ProtocolSelect'; 7 | import GeneralInfo from './GeneralInfo'; 8 | import DarkMode from './DarkModeSelect'; 9 | 10 | export default function NavBarContainer() { 11 | return ( 12 | 16 | {/* Protocol select buttons. */} 17 | 18 | {/* General information about Swell. */} 19 | 20 | 21 | 22 | ); 23 | } 24 | -------------------------------------------------------------------------------- /src/client/components/utilities/ErrorBoundary/ErrorBoundary.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Defines a generic error boundary component for catching and containing 3 | * errors in a React app. This is basically a try/catch for React apps; if this 4 | * catches an error, it gracefully breaks just a specific part of the app, 5 | * instead of the whole thing. 6 | * 7 | * As of 5/13/23, error boundaries can still only be implemented in class 8 | * components. A hooks version is in the works, but don't try to convert this 9 | * until that hook is actually available. 10 | * 11 | * {@link https://reactjs.org/docs/error-boundaries.html} 12 | */ 13 | 14 | import React, { Component, ReactNode, ErrorInfo } from 'react'; 15 | 16 | interface Props { 17 | /** Component children. */ 18 | children?: ReactNode; 19 | } 20 | 21 | interface State { 22 | /** Indicates whether the boundary has caught an error. */ 23 | hasError: boolean; 24 | } 25 | 26 | class ErrorBoundary extends Component { 27 | state: State = { hasError: false }; 28 | 29 | /** 30 | * Returns new state slice to merge into the component state, in the event 31 | * that an error happens. This must be a static method. 32 | */ 33 | static getDerivedStateFromError(): Partial & { hasError: true } { 34 | return { hasError: true }; 35 | } 36 | 37 | /** 38 | * Defines functionality to run if an error boundary's children run into an 39 | * error. 40 | * 41 | * @todo If this app ever gets big enough (in terms of users), this function 42 | * should be beefed up to do more than just log an error. 43 | */ 44 | componentDidCatch(error: Error, info: ErrorInfo): void { 45 | console.error('ErrorBoundary caught an error', error, info); 46 | } 47 | 48 | /** 49 | * Conditionally renders children based on whether the error boundary itself 50 | * caught an error. 51 | */ 52 | render() { 53 | if (!this.state.hasError) { 54 | return this.props.children; 55 | } 56 | 57 | return ( 58 |

59 | There was an error with this component. The error has been logged. 60 |

61 | ); 62 | } 63 | } 64 | 65 | export default ErrorBoundary; 66 | 67 | -------------------------------------------------------------------------------- /src/client/components/workspace/WorkspaceContainer.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @todo Change the workspace container to have adjustable width sizing via 3 | * user dragging 4 | */ 5 | import React from 'react'; 6 | 7 | // Local components 8 | import WorkspaceContainerButtons from './buttons/WorkspaceContainerButtons'; 9 | import WorkspaceSelect from './WorkspaceSelect'; 10 | import DeleteWorkspaceButton from './buttons/DeleteWorkspaceButton'; 11 | import ImportExportWorkspaceButton from './buttons/ImportExportWorkspaceButton'; 12 | 13 | // MUI components and SVG icons 14 | import { Box, Typography, Divider } from '@mui/material'; 15 | import { WorkspaceContainerProps } from '../../../types'; 16 | 17 | export default function WorkspaceContainer(props: WorkspaceContainerProps) { 18 | return ( 19 | 23 | {/* 24 | The display for your current workspace. Contains functionality for 25 | saving, importing, exporting workspace to your local machine. */} 26 | 27 | {/* The below select menu should contain all saved workspaces in the Swell app. */} 28 | 29 | 30 | 31 | 32 | 33 | Requests 34 | 35 | 36 | 37 | 38 | ); 39 | } 40 | -------------------------------------------------------------------------------- /src/client/components/workspace/WorkspaceSelect.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Collection, ReqRes, WorkspaceContainerProps } from '../../../types'; 3 | 4 | import { useAppDispatch, useAppSelector } from '../../toolkit-refactor/hooks'; 5 | 6 | import { reqResReplaced } from '../../toolkit-refactor/slices/reqResSlice'; 7 | 8 | import { 9 | Box, 10 | Select, 11 | MenuItem, 12 | FormControl, 13 | FormHelperText, 14 | SelectChangeEvent, 15 | } from '@mui/material'; 16 | import { RootState } from '../../toolkit-refactor/store'; 17 | 18 | export default function WorkspaceSelect({ 19 | currentWorkspaceId, 20 | setWorkspace, 21 | }: WorkspaceContainerProps) { 22 | const dispatch = useAppDispatch(); 23 | 24 | const handleWorkspaceChange = (event: SelectChangeEvent) => { 25 | setWorkspace(event.target.value as string); 26 | }; 27 | 28 | const updateReqRes = (reqResArray: ReqRes[]) => { 29 | dispatch(reqResReplaced(reqResArray)); 30 | }; 31 | 32 | const workspaces: Collection[] = useAppSelector( 33 | (store: RootState) => store.collections 34 | ); 35 | 36 | const menuItems = 37 | workspaces.length > 0 38 | ? workspaces.map((workspace) => ( 39 | updateReqRes(workspace.reqResArray)} 43 | > 44 | {workspace.name} 45 | 46 | )) 47 | : []; 48 | 49 | return ( 50 | 51 | 52 | 60 | Current Workspace 61 | 62 | 63 | ); 64 | } 65 | -------------------------------------------------------------------------------- /src/client/components/workspace/buttons/ClearHistoryBtn.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from 'react'; 2 | import { useAppDispatch, useAppSelector } from '../../../toolkit-refactor/hooks'; 3 | import historyController from '../../../controllers/historyController'; 4 | 5 | import { WindowExt, WindowAPI } from '../../../../types' 6 | 7 | // utilizing API we created in preload.js for node-free IPC communication 8 | const { api } = window as any; 9 | 10 | interface Props { 11 | historyCleared: () => void 12 | }; 13 | 14 | const ClearHistoryBtn = (props: Props): JSX.Element => { 15 | const { historyCleared } = props; 16 | 17 | // cleanup api.receive event listener on dismount 18 | useEffect(() => { 19 | api.receive('clear-history-response', (res: { response: number }) => { 20 | // a response of 0 from main means user has selected 'confirm' 21 | if (res.response === 0) { 22 | historyController.clearHistoryFromIndexedDb(); 23 | historyCleared(); 24 | } 25 | }); 26 | }, []); 27 | 28 | const isDark = useAppSelector((store: { ui: { isDark: boolean } }) => store.ui.isDark); 29 | 30 | const handleClick = () => { 31 | api.send('confirm-clear-history'); 32 | }; 33 | return ( 34 | 40 | ); 41 | }; 42 | 43 | export default ClearHistoryBtn; 44 | -------------------------------------------------------------------------------- /src/client/components/workspace/buttons/DeleteRequestButton.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ClearRoundedIcon from '@mui/icons-material/ClearRounded'; 3 | import { Button } from '@mui/material'; 4 | 5 | export default function DeleteRequestButton(props: any): JSX.Element { 6 | const handleDeleteRequest = (event: any) => { 7 | console.log(event); 8 | return null; 9 | } 10 | 11 | return( 12 | 20 | ) 21 | } 22 | -------------------------------------------------------------------------------- /src/client/components/workspace/buttons/DeleteWorkspaceButton.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useAppDispatch, useAppSelector } from '../../../toolkit-refactor/hooks'; 3 | 4 | import { collectionDeleted } from '../../../toolkit-refactor/slices/collectionsSlice'; 5 | 6 | import ClearRoundedIcon from '@mui/icons-material/ClearRounded'; 7 | import collectionsController from '../../../controllers/collectionsController'; 8 | import { Button } from '@mui/material'; 9 | import { SwellTooltip } from '../../customMuiStyles/tooltip'; 10 | import { Collection, WorkspaceContainerProps } from '../../../../types'; 11 | import { RootState } from '../../../toolkit-refactor/store'; 12 | 13 | export default function DeleteRequestButton({ 14 | currentWorkspaceId, 15 | setWorkspace, 16 | }: WorkspaceContainerProps) { 17 | const dispatch = useAppDispatch(); 18 | // Grab all of the workspaces from the Redux store. Hopefully this is O(1)... 19 | const allWorkspaces = useAppSelector((store: RootState) => store.collections); 20 | 21 | const currentWorkspace = (): Collection => { 22 | const workspace: Collection | undefined = allWorkspaces.find( 23 | (workspace: Collection) => { 24 | return workspace.id === currentWorkspaceId; 25 | } 26 | ); 27 | return workspace || ({} as Collection); 28 | }; 29 | 30 | const deleteWorkspace = () => { 31 | dispatch(collectionDeleted(currentWorkspace())); 32 | collectionsController.deleteCollectionFromIndexedDb(currentWorkspaceId); 33 | setWorkspace(''); 34 | }; 35 | 36 | return ( 37 | 38 | 51 | 52 | ); 53 | } 54 | -------------------------------------------------------------------------------- /src/client/components/workspace/buttons/ImportExportWorkspaceButton.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Button } from '@mui/material'; 3 | import ImportExportIcon from '@mui/icons-material/ImportExport'; 4 | import ImportExportWorkspaceModal from '../modals/import-export-workspace/ImportExportWorkspaceModal'; 5 | import { SwellTooltip } from '../../customMuiStyles/tooltip'; 6 | 7 | export default function ImportExportWorkspaceButton() { 8 | const [open, setOpen] = React.useState(false); 9 | const handleOpen = () => setOpen(true); 10 | const handleClose = () => setOpen(false); 11 | 12 | return ( 13 |
14 | 15 | 27 | 28 | 29 |
30 | ); 31 | } 32 | 33 | -------------------------------------------------------------------------------- /src/client/components/workspace/buttons/WorkspaceContainerButtons.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import { useAppDispatch, useAppSelector } from '../../../toolkit-refactor/hooks'; 3 | import ReqResCtrl from '../../../controllers/reqResController'; 4 | import WorkspaceCollectionsContainer from '../WorkspaceCollectionsContainer'; 5 | import SaveWorkspaceModal from '../modals/SaveWorkspaceModal'; 6 | // Import MUI components 7 | 8 | export default function WorkspaceContainerButtons () { 9 | const [showModal, setShowModal] = useState(false); 10 | const isDark = useAppSelector((store: { ui: { isDark: boolean }}) => store.ui.isDark); 11 | 12 | return ( 13 |
14 | {/* NAV BAR */} 15 |
16 | 27 | 28 | 38 |
39 | 40 | 41 | {/* REQUEST CARDS */} 42 | 43 |
44 | ); 45 | } -------------------------------------------------------------------------------- /src/client/components/workspace/modals/SaveModalSavedWorkspaces.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable jsx-a11y/no-static-element-interactions */ 2 | /* eslint-disable jsx-a11y/click-events-have-key-events */ 3 | import React from 'react'; 4 | 5 | interface Props { 6 | name: string, 7 | inputID: string, 8 | updateCollection: (name: string, inputID: string) => void 9 | } 10 | 11 | function SaveModalSavedWorkspaces({ name, inputID, updateCollection }: Props) { 12 | return ( 13 |
14 |
15 |
{ 18 | updateCollection(name, inputID); 19 | }} 20 | > 21 | {name} 22 |
23 |
24 |
25 | ); 26 | } 27 | 28 | export default SaveModalSavedWorkspaces; 29 | -------------------------------------------------------------------------------- /src/client/components/workspace/modals/export-workspace/ExportWorkspaceModal.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { useAppDispatch, useAppSelector } from '../../../../toolkit-refactor/hooks'; 3 | import Backdrop from '@mui/material/Backdrop'; 4 | import Box from '@mui/material/Box'; 5 | import { Button } from '@mui/material'; 6 | import Modal from '@mui/material/Modal'; 7 | import Fade from '@mui/material/Fade'; 8 | import Typography from '@mui/material/Typography'; 9 | import collectionsController from '../../../../controllers/collectionsController'; 10 | import { RootState } from '../../../../toolkit-refactor/store'; 11 | 12 | const style = { 13 | display: 'flex', 14 | flexDirection: 'row', 15 | alignItems: 'center', 16 | position: 'absolute', 17 | top: '50%', 18 | left: '50%', 19 | transform: 'translate(-50%, -50%)', 20 | width: 400, 21 | bgcolor: 'background.paper', 22 | boxShadow: 24, 23 | p: 1, 24 | justifyContent: 'space-around', 25 | }; 26 | //TODO: fix implicit any props and look at exportCollection method 27 | export default function ExportWorkspaceModal({ open, handleClose }) { 28 | const localWorkspaces = useAppSelector((store: RootState) => store.collections); 29 | const isDark = useAppSelector((store: { ui: { isDark: boolean } }) => store.ui.isDark); 30 | 31 | return ( 32 | 43 | 44 | 45 | 50 | Export to 51 | 52 | 61 | 62 | 63 | 64 | ); 65 | } 66 | 67 | -------------------------------------------------------------------------------- /src/client/controllers/openApiController.ts: -------------------------------------------------------------------------------- 1 | const YAML = require('yamljs'); 2 | import { 3 | WindowExt, 4 | $TSFixMe 5 | } from '../../types'; 6 | 7 | import { appDispatch } from '../toolkit-refactor/store'; 8 | const { api } = window as unknown as WindowExt; 9 | import { openApiRequestsReplaced } from '../toolkit-refactor/slices/newRequestOpenApiSlice' 10 | 11 | const openApiController: $TSFixMe = { 12 | 13 | importDocument(): void { 14 | api.removeAllListeners('openapi-info'); 15 | api.receive('openapi-info', async (data_in: $TSFixMe) => { 16 | try { 17 | 18 | appDispatch(openApiRequestsReplaced(data_in)); 19 | } catch (err) { 20 | // If swell ever gets big enough, this needs to be built out 21 | console.log('Error in openAPI Controller: ', err) 22 | } 23 | }) 24 | }, 25 | sendDocument(): void { 26 | api.send('import-openapi'); 27 | }, 28 | } 29 | 30 | export default openApiController; -------------------------------------------------------------------------------- /src/client/toolkit-refactor/hooks.ts: -------------------------------------------------------------------------------- 1 | import { useDispatch, useSelector, TypedUseSelectorHook } from 'react-redux'; 2 | import type { RootState, AppDispatch } from './store'; 3 | 4 | /** 5 | * A type-safe version of React-Redux's useDispatch hook. 6 | */ 7 | // Separated hooks from store.ts in -- Below are Type safe hooks to use 8 | 9 | // export const useAppDispatch : () => AppDispatch = useDispatch; 10 | export const useAppDispatch = () => useDispatch(); 11 | export const useAppSelector: TypedUseSelectorHook = useSelector; 12 | 13 | // Latest version of React-Redux (9.x) introduces withTypes, currently not working in 8.0.1 14 | // export const useAppDispatch = useDispatch.withTypes() 15 | // export const useAppSelector = useSelector.withTypes() -------------------------------------------------------------------------------- /src/client/toolkit-refactor/rootReducer.ts: -------------------------------------------------------------------------------- 1 | import { combineReducers } from '@reduxjs/toolkit'; 2 | 3 | import UiReducer from './slices/uiSlice'; 4 | import HistoryReducer from './slices/historySlice'; 5 | import GraphPointsReducer from './slices/graphPointsSlice'; 6 | import CollectionsReducer from './slices/collectionsSlice'; 7 | import ReqResReducer from './slices/reqResSlice'; 8 | import NewRequestReducer from './slices/newRequestSlice'; 9 | import NewRequestFieldsReducer from './slices/newRequestFieldsSlice'; 10 | import NewRequestOpenApiReducer from './slices/newRequestOpenApiSlice'; 11 | import IntrospectionDataReducer from './slices/introspectionDataSlice'; 12 | import WarningMessageReducer from './slices/warningMessageSlice'; 13 | import MockServerReducer from './slices/mockServerSlice'; 14 | 15 | // Note: There was previously a currentTab prop in the Redux store; it wasn't 16 | // used anywhere, and there was no info about it other than it was a string. We 17 | // dropped it from the store, but it might make sense to add it back at some 18 | // point 19 | const rootReducer = combineReducers({ 20 | history: HistoryReducer, 21 | newRequest: NewRequestReducer, 22 | graphPoints: GraphPointsReducer, 23 | collections: CollectionsReducer, 24 | newRequestFields: NewRequestFieldsReducer, 25 | newRequestOpenApi: NewRequestOpenApiReducer, 26 | reqRes: ReqResReducer, 27 | ui: UiReducer, 28 | introspectionData: IntrospectionDataReducer, 29 | warningMessage: WarningMessageReducer, 30 | mockServer: MockServerReducer, 31 | }); 32 | 33 | export default rootReducer; 34 | 35 | -------------------------------------------------------------------------------- /src/client/toolkit-refactor/slices/introspectionDataSlice.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Slice for managing introspection data from GraphQL. 3 | */ 4 | import { createSlice, PayloadAction } from '@reduxjs/toolkit'; 5 | import { $NotUsed, IntrospectionData } from '../../../types'; 6 | 7 | const initialState: IntrospectionData = { 8 | schemaSDL: null, 9 | clientSchema: null, 10 | }; 11 | 12 | const introspectionDataSlice = createSlice({ 13 | name: 'introspectionData', 14 | initialState, 15 | reducers: { 16 | //Before toolkit conversion was SET_INTROSPECTION_DATA or setIntrospectionData 17 | introspectionDataChanged: ( 18 | _state: $NotUsed, 19 | action: PayloadAction 20 | ) => { 21 | return action.payload; 22 | }, 23 | }, 24 | }); 25 | 26 | export const { introspectionDataChanged } = introspectionDataSlice.actions; 27 | export default introspectionDataSlice.reducer; 28 | 29 | -------------------------------------------------------------------------------- /src/client/toolkit-refactor/slices/mockServerSlice.ts: -------------------------------------------------------------------------------- 1 | import { createSlice } from '@reduxjs/toolkit'; 2 | 3 | const mockServerSlice = createSlice({ 4 | name: 'mockServer', 5 | initialState: { 6 | isServerStarted: false, 7 | }, 8 | reducers: { 9 | startServer: (state) => { 10 | state.isServerStarted = true; 11 | }, 12 | stopServer: (state) => { 13 | state.isServerStarted = false; 14 | }, 15 | }, 16 | }); 17 | 18 | export const { startServer, stopServer } = mockServerSlice.actions; 19 | 20 | export default mockServerSlice.reducer; -------------------------------------------------------------------------------- /src/client/toolkit-refactor/slices/uiSlice.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Defines state management for just the UI part of the app. 3 | * 4 | * If all the properties here are non-model state, this file might be overkill, 5 | * and could maybe be deleted in favor of using the React context API and non- 6 | * global/hooks-based state. 7 | */ 8 | import { createSlice, PayloadAction } from '@reduxjs/toolkit'; 9 | 10 | interface UiState { 11 | sidebarActiveTab: string; 12 | workspaceActiveTab: string; 13 | responsePaneActiveTab: string; 14 | /** 15 | * @todo - dark mode not enabled or implemented, either complete feature or 16 | * remove this piece of state and it's references, but make sure all other 17 | * functionality still good 18 | * */ 19 | isDark: boolean; 20 | } 21 | 22 | const initialState: UiState = { 23 | sidebarActiveTab: 'composer', 24 | workspaceActiveTab: 'workspace', 25 | responsePaneActiveTab: 'events', 26 | isDark: false, 27 | }; 28 | 29 | const uiSlice = createSlice({ 30 | name: 'ui', 31 | initialState, 32 | reducers: { 33 | setSidebarActiveTab(state, action: PayloadAction) { 34 | state.sidebarActiveTab = action.payload; 35 | }, 36 | setWorkspaceActiveTab(state, action: PayloadAction) { 37 | state.workspaceActiveTab = action.payload; 38 | }, 39 | setResponsePaneActiveTab(state, action: PayloadAction) { 40 | state.responsePaneActiveTab = action.payload; 41 | }, 42 | toggleDarkMode(state, action: PayloadAction) { 43 | state.isDark = action.payload; 44 | }, 45 | }, 46 | }); 47 | 48 | export const { 49 | setSidebarActiveTab, 50 | setWorkspaceActiveTab, 51 | setResponsePaneActiveTab, 52 | toggleDarkMode, 53 | } = uiSlice.actions; 54 | 55 | export default uiSlice.reducer; 56 | 57 | -------------------------------------------------------------------------------- /src/client/toolkit-refactor/slices/warningMessageSlice.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Defines the Redux Toolkit slice for working with the Warning Message 3 | * object and associated values. 4 | */ 5 | import { createSlice, PayloadAction } from '@reduxjs/toolkit'; 6 | import { $NotUsed } from '../../../types'; 7 | 8 | //define type for warning message object 9 | 10 | // //from test file 11 | // const fakeWarningMessage = { 12 | // err: `you can't do this to me`, 13 | // }; 14 | // if (warningMessage.uri) { //so warning message obj has uri property?? 15 | // {warningMessage ?
{warningMessage.body}
: null} //has body property?? 16 | 17 | type WarningMessage = Partial<{ 18 | err: string; 19 | uri: string; 20 | body: string; 21 | }>; 22 | 23 | //initialize warning message state 24 | const initialState: WarningMessage = {}; 25 | 26 | const warningMessageSlice = createSlice({ 27 | name: 'warningMessage', 28 | initialState, 29 | reducers: { 30 | //previously was SET_COMPOSER_WARNING_MESSAGE or setComposerWarningMessage 31 | setWarningMessage(_state: $NotUsed, action: PayloadAction) { 32 | return action.payload; 33 | }, 34 | }, 35 | }); 36 | 37 | export const { setWarningMessage } = warningMessageSlice.actions; 38 | export default warningMessageSlice.reducer; 39 | 40 | -------------------------------------------------------------------------------- /src/client/toolkit-refactor/store.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Defines the top-level Redux store that should be used throughout the entire 3 | * app for non-model data. 4 | * {@link https://redux-toolkit.js.org/} 5 | * 6 | * Please do not put temporary form state in the store. All of that can be done 7 | * with local state management, via things like React hooks and the Context API. 8 | * 9 | * @todo Replace all instances of Date objects in the Redux store with timestamp 10 | * strings. Redux will complain that the data isn't serializable, because Dates 11 | * aren't part of the JSON spec, but when you call JSON.stringify on an object 12 | * that contains Dates, they'll automatically have their .toString method 13 | * called, turning them into timestamp strings. 14 | * 15 | * So basically, the data technically is serializable, but Redux can't tell that 16 | * and will keep yelling at you in the console until all the Dates are replaced. 17 | */ 18 | import { configureStore } from '@reduxjs/toolkit'; 19 | import rootReducer from './rootReducer'; 20 | 21 | /** 22 | * The top-level redux store. serializableCheck was previously turned off, which 23 | * stops Redux from complaining at you, but the Redux store should only have 24 | * serializable JSON values where possible. 25 | * 26 | * @todo Remove any non-serializable values from the store (namely, replace 27 | * Date objects with Date strings). 28 | */ 29 | const store = configureStore({ 30 | reducer: rootReducer, 31 | devTools: process.env.NODE_ENV !== 'production', 32 | middleware: (getDefaultMiddleware) => 33 | getDefaultMiddleware({ 34 | serializableCheck: false, 35 | }), 36 | }); 37 | 38 | 39 | /** 40 | * A type-safe version of React-Redux's useDispatch hook. 41 | * Moved to hooks.ts 42 | */ 43 | // Infer the `RootState` and `AppDispatch` types from the store itself 44 | export type RootState = ReturnType; 45 | // Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState} 46 | export type AppDispatch = typeof store.dispatch; 47 | /** 48 | * The Redux store's dispatch function, exposed directly; needed for files that 49 | * are not React functional components. 50 | */ 51 | export const appDispatch = store.dispatch; 52 | export default store; 53 | 54 | -------------------------------------------------------------------------------- /src/declarations.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.svg' { 2 | const content: any; 3 | export default content; 4 | } -------------------------------------------------------------------------------- /src/helpers.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Defines general-purpose functions that can be used anywhere. 3 | */ 4 | 5 | /** 6 | * During runtime, this just throws an error. For development, this will make 7 | * sure that every single argument passed in is of type never. 8 | * 9 | * @example Say you have a variable x, whose type is a union of the discrete 10 | * string values "A" | "B" | "C". You can use this function with x to make sure 11 | * you're taking care of all three cases properly. 12 | * 13 | * switch (x) { 14 | * case "A": { 15 | * return; 16 | * } 17 | * case "B": { 18 | * return; 19 | * } 20 | * default: { 21 | * checkTypeExhaustion(x); 22 | * } 23 | * } 24 | * 25 | * In the above example, VS Code will yell at you because you didn't have 26 | * anything for case "C". So the type of x can still be the string literal "C", 27 | * which has no overlap with type never. You'd have to add a case for "C" to get 28 | * VS Code to stop yelling at you. 29 | */ 30 | export function assertTypeExhaustion(..._: never[]): never { 31 | throw new Error('Not all types have been exhausted properly'); 32 | } 33 | 34 | -------------------------------------------------------------------------------- /src/images.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.png' { 2 | const value: any; 3 | export default value; 4 | } -------------------------------------------------------------------------------- /src/svg.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*.svg" { 2 | const content: any; 3 | export default content; 4 | } -------------------------------------------------------------------------------- /test/HTTP2_cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIEpDCCAowCCQCJAu83+jlwvTANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAls 3 | b2NhbGhvc3QwHhcNMjAxMTA3MjAxMzEwWhcNMjAxMjA3MjAxMzExWjAUMRIwEAYD 4 | VQQDDAlsb2NhbGhvc3QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDI 5 | /rDqYGNup8CKLQMM5J7qdEUIf/pWgx9va8YFPhxeSYWK7fgQEmpTnnw9bBTzzFi6 6 | dHambPGdbKpW0dEQguMPxmUUjmOf8m2rAyy6L9ppV5llnpFjoAgBo1uwgqkpa+eK 7 | jy82VBDWLS/80gRsnGz5Q+Zw4+JWAGeIt8eEG0HmH3cLjbZjvVlG2FVeoOiSi9tj 8 | yZ/BStXodBeUC8FcpIcB1ugDgkA5WsXeXFMKPxyxOk1K2vFUVCFTHjtKX16wAoJT 9 | cBwsb6tGxYDOTc6Hao1FeGPncZ+5z6MHofyGSvvg7fwUIuZojaUmsyX9bFeS9XQi 10 | 0clgX9fy93JKP1lMmnXSxqEgRKVjxAie4XoZNwjs+AUtYpKVnfn7xBHCVSFQcmNJ 11 | UIAgF1JkSmyqgXcXPSzZkPIf9EamP8W/j9MEr5ebSta/4vvpGzF71gU1c0ZByaYx 12 | rE6ObgqWaNDv5PCzEoThI9O17l9uSt7NRmx3K/CahB2WFHpHUTSe2zg6KaJLL8Id 13 | 12bCOYNcNnhATRKOcAy1bR27Y4hmj6RWYmpQLVyFr+Q3H6bl9YI4FtFbi/Pxoo1a 14 | ourdrxbXkIt1eDUQsfgFn9steubjhoyqFQlQ+cx2bRBtUX4D6eaxGL4Ma4hLfjAR 15 | Ba+SjnQcg/ll6VI6qWh0W/hSYUAyq7PdVUryEHKPQwIDAQABMA0GCSqGSIb3DQEB 16 | CwUAA4ICAQBFhQNfVNqqXBAwKoSGK1lZA9lrDq6H24arfc/X7UqF61b9pqxFJc2f 17 | g3u7PF70JpTs7iPaTtydYtv4ahvnh+6YRZXYJlSPt8gOH4xImvQEhlapRGnZ9B2D 18 | l9dFjXE9F1zoTwTCJ6j/lLG3VJF+0nYuDCMfMarS3qSAvHPxxaJM0yGO0y5YK2do 19 | aT1aF44XCou6oC9GNcqIzF1xnKNWhNBh3ZDIPVm/6fQGLcOhs3nOMg7f6QqskosE 20 | e2udXTsLftjO1QDng6oRkvfuvkfMSn+WKkCb5Gp2qtzARJ2Y2dAisEW5+kVesV5A 21 | +mQhpOkNTk+qsXo3evPIBzBNvnC8m/QzLigL8VOJZw5/xtPGTw5IOEQkY5l9Oj6J 22 | dZsIlVAFB24XG6aMLb3KWdnICGesaBwhNp0aWVdrx4KN4xUY4s9gitqroTJ/Q3eu 23 | NCTWsqRRt5oiojdwXUhjeilxATWAZM6VrgXZ068Mr+HjdEOAdUZkrDfrLCYYclWs 24 | Q0V3JEci7kBlE8++Xo6Khe/oge9hlYQXwP9UmaTvN02IRATErzB0ELVfwNXFGUNk 25 | 9iyUi9leCcAZ+jw8YKjoK1nbklcsbm9WFS3lNCZZ/OO72vQhCkHF5pcZYL/yzrNf 26 | 3QtbMlQlwZonqRZp5wo39OrZa2T5rgCPltM9xYdovF1vFbFzTd8E+g== 27 | -----END CERTIFICATE----- 28 | -------------------------------------------------------------------------------- /test/HTTP2_server.js: -------------------------------------------------------------------------------- 1 | const http2 = require('http2'); 2 | const fs = require('fs'); 3 | const path = require('path'); 4 | const PORT = 8443; 5 | 6 | const CERT_PATH = path.join(__dirname, '/HTTP2_cert.pem'); 7 | const PRIV_PATH = path.join(__dirname, 'HTTP2_private.pem'); 8 | 9 | const server = http2.createSecureServer({ 10 | cert: fs.readFileSync(CERT_PATH), 11 | key: fs.readFileSync(PRIV_PATH), 12 | }); 13 | 14 | server.on('error', (err) => console.error(err)); 15 | 16 | const dispatch = (stream, headers, body = '') => { 17 | // respond with SSE stream if request accepts stream in headers 18 | if (headers.accept && headers.accept.includes('stream')) { 19 | sendStreamToClient(stream, body); 20 | return; 21 | } 22 | 23 | // else send a single event 24 | stream.respond({ 25 | 'content-type': 'application/json; charset=utf-8', 26 | ':status': 200, 27 | }); 28 | stream.end(JSON.stringify({ data: `hello and goodbye${body}` })); 29 | }; 30 | 31 | server.on('stream', (stream, headers) => { 32 | // dispatch async if there's a body 33 | if (headers[':method'] !== 'GET') { 34 | stream.on('data', (chunk) => { 35 | dispatch(stream, headers, `- ${chunk}`); 36 | }); 37 | } else { 38 | // otherwise dispatch sync 39 | dispatch(stream, headers); 40 | } 41 | }); 42 | 43 | const sendStreamToClient = (stream, body) => { 44 | const STREAM_INTERVAL = 500; 45 | let count = 0; 46 | let streamIsOpen = true; 47 | 48 | stream.on('close', () => { 49 | streamIsOpen = false; 50 | console.log('stream closed'); 51 | }); 52 | 53 | stream.respond({ 54 | 'content-type': 'text/event-stream; charset=utf-8', 55 | ':status': 200, 56 | }); 57 | 58 | const sendEvent = (stream) => { 59 | if (!streamIsOpen) { 60 | count = 0; 61 | return; 62 | } 63 | count += 1; 64 | if (count < 50) { 65 | stream.write(`id: ${count}\nevent: testMessage\ndata: hello${body}\n\n`); 66 | setTimeout(() => sendEvent(stream), STREAM_INTERVAL); 67 | } else { 68 | stream.end(`id: ${count}\nevent: testMessage\ndata: goodbye${body}\n\n`); 69 | streamIsOpen = false; 70 | count = 0; 71 | } 72 | }; 73 | 74 | sendEvent(stream); 75 | }; 76 | 77 | server.listen(PORT, () => 78 | console.log(`HTTP2 Test Server: listening on PORT ${PORT}`) 79 | ); 80 | -------------------------------------------------------------------------------- /test/SSE_HTTP1_server.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const SSE = require('express-sse'); 3 | 4 | const app = express(); 5 | const PORT = 3001; 6 | 7 | const sse = new SSE(['first message']); 8 | 9 | app.use(express.json()); 10 | app.use(express.urlencoded({ extended: true })); 11 | 12 | const timeInterval = 3000; 13 | 14 | const sendStream = () => { 15 | // if listeners are gone, connection is closed 16 | if (sse.listenerCount('data') < 1) { 17 | console.log(`HTTP1 SSE Server: closed by client`); 18 | return; 19 | } 20 | 21 | sse.send(`the time is: ${Date.now()}`); 22 | setTimeout(sendStream, timeInterval); 23 | }; 24 | 25 | const dispatchStreamOrHeaders = (req, res, next) => { 26 | if (req.headers.accept === 'text/event-stream') { 27 | setTimeout(sendStream, timeInterval); 28 | return next(); 29 | } 30 | 31 | res.set({ 32 | Connection: 'keep-alive', 33 | 'Content-Type': 'text/event-stream', 34 | 'Cache-Control': 'no-cache', 35 | 'Access-Control-Allow-Origin': '*', 36 | }); 37 | res.status(201); 38 | return res.send(); 39 | }; 40 | 41 | app.get('/', dispatchStreamOrHeaders, sse.init); 42 | 43 | app.listen(PORT, () => { 44 | console.log(`HTTP1 SSE Server: listening on PORT ${PORT}`); 45 | }); 46 | -------------------------------------------------------------------------------- /test/__mockTestData/famousRandQuotesApi.yaml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.0 2 | info: 3 | title: Random Famous Quotes API 4 | version: 1.0.0 5 | description: API for retrieving random famous quotes 6 | servers: 7 | - url: 'https://andruxnet-random-famous-quotes.p.rapidapi.com/' 8 | paths: 9 | /: 10 | get: 11 | summary: Get random famous quotes 12 | responses: 13 | '200': 14 | description: Successful response 15 | content: 16 | application/json: 17 | schema: 18 | type: array 19 | items: 20 | type: object 21 | properties: 22 | quote: 23 | type: string 24 | author: 25 | type: string 26 | security: 27 | - RapidAPIKeyHeader: ['andruxnet-random-famous-quotes.p.rapidapi.com'] 28 | components: 29 | securitySchemes: 30 | RapidAPIKeyHeader: 31 | type: apiKey 32 | name: X-RapidAPI-Key 33 | in: header 34 | description: RapidAPI Key 35 | RapidAPIHostHeader: 36 | type: apiKey 37 | name: X-RapidAPI-Host 38 | in: header 39 | description: RapidAPI Host 40 | 41 | -------------------------------------------------------------------------------- /test/__mockTestData/openAPITestDefinition.yaml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.0 2 | info: 3 | title: Sample API 4 | description: Test file for debugging Swell's openAPI feature 5 | version: 0.1.9 6 | servers: 7 | - url: http://www.example.com/v1 8 | description: Optional server description, e.g. Main (production) server 9 | - url: http://www.example.com/v2 10 | description: Optional server description, e.g. Internal staging server for testing 11 | paths: 12 | /users/1: 13 | get: 14 | summary: Returns a user by ID. 15 | parameters: 16 | - name: 1 17 | in: path 18 | required: true 19 | description: The ID of the user to return. 20 | schema: 21 | type: integer 22 | format: int64 23 | minimum: 1 24 | responses: 25 | '200': 26 | description: A user object. 27 | content: 28 | application/json: 29 | schema: 30 | type: object 31 | properties: 32 | id: 33 | type: integer 34 | format: int64 35 | example: 4 36 | name: 37 | type: string 38 | example: Jessica Smith 39 | '400': 40 | description: The specified user ID is invalid (not a number). 41 | '404': 42 | description: A user with the specified ID was not found. 43 | default: 44 | description: Unexpected error 45 | 46 | -------------------------------------------------------------------------------- /test/__mocks__/electronMock.js: -------------------------------------------------------------------------------- 1 | export const ipcRenderer = { 2 | on: jest.fn(), 3 | }; 4 | -------------------------------------------------------------------------------- /test/__mocks__/fileMock.js: -------------------------------------------------------------------------------- 1 | // see jest.config 2 | module.exports = 'test-file-stub'; 3 | -------------------------------------------------------------------------------- /test/__mocks__/styleMocks.js: -------------------------------------------------------------------------------- 1 | // see jest.config 2 | 3 | module.exports = {}; 4 | -------------------------------------------------------------------------------- /test/__mocks__/windowMock.js: -------------------------------------------------------------------------------- 1 | const apiMock = { 2 | receive: jest.fn(), 3 | removeAllListeners: jest.fn(), 4 | send: jest.fn(), 5 | }; 6 | 7 | global.window = { 8 | api: apiMock, 9 | }; -------------------------------------------------------------------------------- /test/__tests__/dbTests.js: -------------------------------------------------------------------------------- 1 | // started dexie testing set up. 2 | // I would suggest continue TDD by writing some collection tests, then 3 | // importing the actual controllers and testing directlyerly 4 | //testing 5 | 6 | // const collectionsController = require("../src/client/controllers/collectionsController"); 7 | // const historyController = require("../src/client/controllers/historyController"); 8 | 9 | const Dexie = require('dexie'); 10 | 11 | // https://stackoverflow.com/questions/47934383/indexeddb-testing-with-jest-enzyme-referenceerror-indexeddb-is-not-defined 12 | Dexie.dependencies.indexedDB = require('fake-indexeddb'); 13 | Dexie.dependencies.IDBKeyRange = require('fake-indexeddb/lib/FDBKeyRange'); 14 | 15 | const db = new Dexie('test'); 16 | 17 | db.version(2).stores({ 18 | history: 'id, createdAt', 19 | collections: 'id, createdAt, &name', 20 | }); 21 | 22 | db.version(1).stores({ 23 | history: 'id, createdAt', 24 | }); 25 | 26 | //delete 27 | const thisIsForTest = "test"; 28 | // now we have db.history and db.collections 29 | 30 | // for setup and teardown tasks that are asynchronous, take care to RETURN the promise 31 | describe('db test', () => { 32 | beforeEach(() => db.history.clear().catch((err) => console.log(err))); 33 | afterEach(() => db.history.clear().catch((err) => console.log(err))); 34 | describe('history tests', () => { 35 | it('can add history with id', async () => { 36 | await db.history.put({ id: 8 }); 37 | const count = await db.history.count(); 38 | const arr = await db.history.toArray(); 39 | expect(count).toEqual(1); 40 | expect(arr[0].id).toEqual(8); 41 | }); 42 | 43 | it('will not add history with an empty object', async () => { 44 | db.history.put({}).catch((err) => expect(err.name).toEqual('DataError')); 45 | const count = await db.history.count(); 46 | expect(count).toEqual(0); 47 | }); 48 | 49 | it('will not add history without an id', async () => { 50 | await db.history 51 | .put({ createdAt: Date.now() }) 52 | .catch((err) => expect(err.name).toEqual('DataError')); 53 | const count = await db.history.count(); 54 | expect(count).toEqual(0); 55 | }); 56 | }); 57 | }); 58 | -------------------------------------------------------------------------------- /test/__tests__/helperTest.js: -------------------------------------------------------------------------------- 1 | import { assertTypeExhaustion } from '../../src/helpers.ts'; 2 | 3 | describe('assertTypeExhaustion', () => { 4 | test('throws error when all types are not exhausted', () => { 5 | expect(() => assertTypeExhaustion('string')).toThrowError('Not all types have been exhausted properly'); 6 | }); 7 | 8 | // test('does not throw error when all types are exhausted', () => { 9 | // expect(() => assertTypeExhaustion()).not.toThrowError(); 10 | // }); 11 | }); -------------------------------------------------------------------------------- /test/__tests__/introspectionDataSliceTest.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @todo - Check for possible edge cases 3 | * Covereage is all at 100%, so possibly no need to update testing 4 | * unless the slice itself was updated/edge cases found. 5 | */ 6 | 7 | import IntrospectionDataReducer, 8 | { initialState, 9 | introspectionDataChanged } from '../../src/client/toolkit-refactor/slices/introspectionDataSlice'; 10 | 11 | describe('introspectionDataSlice', () => { 12 | it('state should be updated via new information received', () => { 13 | const testIntrospectionData = { 14 | schemaSDL: 'test one', 15 | clientSchema: { 16 | name: 'graphQL Schema name test', 17 | id: 1 18 | } 19 | } 20 | const action = introspectionDataChanged(testIntrospectionData); 21 | const sliceInitialState = IntrospectionDataReducer(initialState, action); 22 | expect(sliceInitialState).toBe(testIntrospectionData); 23 | }); 24 | }); -------------------------------------------------------------------------------- /test/__tests__/mockServerSliceTest.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Test to determine if the mockServerSlice reducer switches work. 3 | * @todo - Check for possible edge cases 4 | * Covereage is all at 100%, so possibly no need to update testing 5 | * unless the slice itself was updated/edge cases found. 6 | * **/ 7 | 8 | import mockServerReducer, 9 | { initialState, 10 | startServer, 11 | stopServer } from '../../src/client/toolkit-refactor/slices/mockServerSlice'; 12 | 13 | describe('mockServerSlice', () => { 14 | it('state should be updated on server start', () => { 15 | const action = startServer(); 16 | const sliceNewState = mockServerReducer(initialState, action); 17 | expect(sliceNewState.isServerStarted).toBe(true); 18 | }); 19 | 20 | it('state should be updated on server stop', () => { 21 | const action = stopServer(); 22 | const sliceNewState = mockServerReducer(initialState, action); 23 | expect(sliceNewState.isServerStarted).toBe(false); 24 | }); 25 | }); -------------------------------------------------------------------------------- /test/__tests__/openAPIParserTest.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | 4 | import openapiParserFunc from '../../main_process/openapiParser'; 5 | 6 | /** @todo Test the actual contents of the parser */ 7 | describe('openAPI Parser tests', () => { 8 | const file = fs.readFileSync( 9 | path.resolve(__dirname + '/../__mockTestData/openAPITestDefinition.yaml') 10 | ); 11 | 12 | it('should be able to parse a yaml file', () => { 13 | const { openapiMetadata, openapiReqArray } = openapiParserFunc( 14 | String(file) 15 | ); 16 | expect(openapiMetadata).toBeDefined(); 17 | expect(openapiReqArray).toBeDefined(); 18 | }); 19 | 20 | it('should error on undefined input', () => { 21 | expect(() => openapiParserFunc(null)).toThrow(ReferenceError); 22 | expect(() => openapiParserFunc(undefined)).toThrow(ReferenceError); 23 | }); 24 | 25 | it('should parse the openAPI document correctly', () => { 26 | const { openapiMetadata, openapiReqArray } = openapiParserFunc( 27 | String(file) 28 | ); 29 | 30 | // Check if the metadata is parsed correctly 31 | expect(openapiMetadata.info.title).toBe('Sample API'); 32 | expect(openapiMetadata.info.version).toBe('0.1.9'); 33 | 34 | // Check if the requests are parsed correctly 35 | expect(openapiReqArray.length).toBe(1); 36 | expect(openapiReqArray[0].method).toBe('GET'); 37 | expect(openapiReqArray[0].endpoint).toBe('/users/1'); 38 | }); 39 | }); 40 | 41 | -------------------------------------------------------------------------------- /test/__tests__/uiSliceTest.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Test to determine the state management for the given windows (sidebar, workspace, response pane) in the UI. 3 | * 4 | * Currently, updating the state is working properly. 5 | * Possibly @todo - testing for actual updates when the rendering occurs real-time? 6 | * 7 | */ 8 | 9 | import uiSliceReducer, 10 | { initialState, 11 | setSidebarActiveTab, 12 | setWorkspaceActiveTab, 13 | setResponsePaneActiveTab, 14 | toggleDarkMode } from '../../src/client/toolkit-refactor/slices/uiSlice'; 15 | 16 | describe('uiSlice', () => { 17 | it('sidebar active window should be updated when changed', () => { 18 | const action = setSidebarActiveTab('composer'); 19 | const sliceNewState = uiSliceReducer(initialState, action); 20 | expect(sliceNewState.sidebarActiveTab).toBe('composer'); 21 | }); 22 | 23 | it('workspace active window should be updated when changed', () => { 24 | const action = setWorkspaceActiveTab('workspace'); 25 | const sliceNewState = uiSliceReducer(initialState, action); 26 | expect(sliceNewState.workspaceActiveTab).toBe('workspace'); 27 | }); 28 | 29 | it('response pane active window should be updated when changed', () => { 30 | const action = setResponsePaneActiveTab('events'); 31 | const sliceNewState = uiSliceReducer(initialState, action); 32 | expect(sliceNewState.responsePaneActiveTab).toBe('events'); 33 | }); 34 | 35 | it('dark-mode switch should toggle correctly', () => { 36 | const actionOff = toggleDarkMode(false); 37 | const actionOn = toggleDarkMode(true); 38 | let sliceNewState = uiSliceReducer(initialState, actionOff); 39 | expect(sliceNewState.isDark).toBe(false); 40 | sliceNewState = uiSliceReducer(initialState, actionOn); 41 | expect(sliceNewState.isDark).toBe(true); 42 | }); 43 | }); 44 | 45 | -------------------------------------------------------------------------------- /test/__tests__/utils/reduxTestingUtils.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * This component is the custom render function to test Redux (More info: https://redux.js.org/usage/writing-tests). 3 | * The gist: We are creating a new Redux store instance every time the function is 4 | * called - in this scenario exery time we run a test. We COULD pass in the already established 5 | * store instance, but I believe since Swell is currently mutating state directly it's better to create a new store 6 | * for testing purposes. 7 | * 8 | * @todo This test is currently written in JS - to update to TS. 9 | * @todo For now, Jest is configured to ignore this file. 10 | * Without tests included here, Jest reports this file as failing because it expects it to have tests. 11 | * This file has been added to the testPathIgnorePatterns option in jest.config.js. 12 | * Remove this file from the testPathIgnorePatterns option when tests are added. 13 | * 14 | * Log from github CI jest testing, when file has no tests and is not ignored: 15 | * FAIL test/__tests__/utils/reduxTestingUtils.tsx 16 | * ● Test suite failed to run 17 | * Your test suite must contain at least one test. 18 | **/ 19 | 20 | 21 | import React from 'react' 22 | import { render } from '@testing-library/react' 23 | import { configureStore } from '@reduxjs/toolkit' 24 | import { Provider } from 'react-redux' 25 | // As a basic setup, import your same slice reducers 26 | import IntrospectionDataReducer from '../../../src/client/toolkit-refactor/slices/introspectionDataSlice' 27 | 28 | export function renderWithProviders( 29 | ui, 30 | { 31 | preloadedState = {}, 32 | // Automatically create a store instance if no store was passed in 33 | store = configureStore({ reducer: { user: IntrospectionDataReducer }, preloadedState }), 34 | ...renderOptions 35 | } = {} 36 | ) { 37 | function Wrapper({ children }) { 38 | return {children} 39 | } 40 | 41 | // Return an object with the store and all of RTL's query functions 42 | return { store, ...render(ui, { wrapper: Wrapper, ...renderOptions }) } 43 | } -------------------------------------------------------------------------------- /test/__tests__/warningMessageSliceTest.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Test to determine if the mockServerSlice reducer switches work. 3 | * This test has been completed. 4 | * **/ 5 | 6 | import warningMessageReducer, 7 | { initialState, 8 | setWarningMessage } from '../../src/client/toolkit-refactor/slices/warningMessageSlice'; 9 | 10 | describe('warningMessageSlice', () => { 11 | it('state should be updated on server start', () => { 12 | const warningMessageExample = { 13 | paylod: { 14 | err: 'error message', 15 | uri: 'uri link', 16 | body: 'body message' 17 | } 18 | }; 19 | const action = setWarningMessage(warningMessageExample); 20 | const sliceNewState = warningMessageReducer(initialState, action); 21 | expect(sliceNewState).toBe(warningMessageExample); 22 | }); 23 | }); -------------------------------------------------------------------------------- /test/grpc_mockData/mock_protos/hw2.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helloworld; 4 | 5 | // The greeting service definition. 6 | service Greeter { 7 | // Sends a greeting 8 | rpc SayHello (HelloRequest) returns (HelloReply) {} // single unary stream 9 | rpc SayHelloNested (HelloNestedRequest) returns (HelloNestedReply) {} // nested unary stream 10 | rpc SayHellosSs (HelloRequest) returns (stream HelloReply) {} 11 | rpc SayHelloCS (stream HelloRequest) returns (HelloReply) {} 12 | rpc SayHelloBidi (stream HelloRequest) returns (stream HelloReply) {} 13 | } 14 | 15 | // The request message containing the user's name. 16 | message HelloRequest { 17 | string name = 1; 18 | } 19 | 20 | // The response message containing the greetings 21 | message HelloReply { 22 | string message = 1; 23 | } 24 | 25 | message HelloNestedRequest { 26 | HelloRequest firstPerson = 1; 27 | HelloRequest secondPerson = 2; 28 | } 29 | 30 | message HelloNestedReply { 31 | // create array of nested server response 32 | repeated HelloReply serverMessage = 1; 33 | 34 | } 35 | // The request message containing the user's name. 36 | message HelloHowOldRequest { 37 | int32 age = 1; 38 | } 39 | message HelloAge { 40 | int32 age = 1; 41 | } 42 | -------------------------------------------------------------------------------- /test/grpc_mockData/mock_protos/hw2_multi_service.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helloworld; 4 | 5 | // The greeting service definition. 6 | service Greeter { 7 | // Sends a greeting 8 | rpc SayHello (HelloRequest) returns (HelloReply) {} 9 | rpc SayHelloCS (stream HelloRequest) returns (HelloReply) {} 10 | rpc SayHellos (HelloRequest) returns (stream HelloReply) {} 11 | rpc SayHelloBidi (stream HelloRequest) returns (stream HelloReply) {} 12 | } 13 | 14 | service Butler { 15 | // Sends a greeting 16 | rpc SayHello (HelloRequest) returns (HelloReply) {} 17 | rpc SayHelloCS (stream HelloRequest) returns (HelloReply) {} 18 | rpc SayHellos (HelloRequest) returns (stream HelloReply) {} 19 | rpc SayHelloBidi (stream HelloRequest) returns (stream HelloReply) {} 20 | } 21 | // The request message containing the user's name. 22 | message HelloRequest { 23 | string name = 1; 24 | } 25 | 26 | // The response message containing the greetings 27 | message HelloReply { 28 | string message = 1; 29 | } 30 | -------------------------------------------------------------------------------- /test/grpc_mockData/testServer.js: -------------------------------------------------------------------------------- 1 | // an example of making a test server without Mali and pure @grpc 2 | 3 | const path = require('path'); 4 | const grpc = require('@grpc/grpc-js'); 5 | const protoLoader = require('@grpc/proto-loader'); 6 | 7 | // change PROTO_PATH to load a different mock proto file 8 | const PROTO_PATH = path.resolve(__dirname, 'protos/helloworld.proto'); 9 | const PORT = 'localhost:50051'; 10 | 11 | const proto = protoLoader.loadSync(PROTO_PATH); 12 | const definition = grpc.loadPackageDefinition(proto); 13 | 14 | const greetMe = (call, callback) => { 15 | callback(null, { reply: `Hey ${call.request.name}!` }); 16 | }; 17 | 18 | const server = new grpc.Server(); 19 | 20 | server.addService(definition.HelloWorldService.service, { greetMe }); 21 | 22 | server.bindAsync(PORT, grpc.ServerCredentials.createInsecure(), (port) => { 23 | server.start(); 24 | console.log(`grpc server running on port ${PORT}`); 25 | }); 26 | -------------------------------------------------------------------------------- /test/httpServer.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const bodyParser = require('body-parser'); 3 | const cors = require('cors'); 4 | 5 | const app = express(); 6 | 7 | const PORT = 3004; 8 | 9 | let mockDB = []; 10 | 11 | app.use(bodyParser.json()); 12 | app.use(bodyParser.urlencoded({ extended: true })); 13 | 14 | 15 | 16 | app.get('/clear', (req, res) => { 17 | mockDB = []; 18 | res.sendStatus(200); 19 | }); 20 | 21 | // selectively enable cors to facilitate E2E testing 22 | app.get('/book', cors(), (req, res) => res.status(200).json(mockDB)); 23 | 24 | app.post('/book', (req, res) => { 25 | const { title, author, pages } = req.body; 26 | const book = { title, author, pages }; 27 | mockDB.push(book); 28 | res.status(200).json(book); 29 | }); 30 | 31 | app.put('/book/:title', (req, res) => { 32 | const { title } = req.params; 33 | const { author, pages } = req.body; 34 | let index; 35 | mockDB.forEach((book, i) => { 36 | if ((book.title = title)) { 37 | book.title = title; 38 | book.author = author; 39 | book.pages = pages; 40 | index = i; 41 | } 42 | }); 43 | res.status(200).json(mockDB[index]); 44 | }); 45 | 46 | app.patch('/book/:title', (req, res) => { 47 | const { title } = req.params; 48 | const { author } = req.body; 49 | let index; 50 | mockDB.forEach((book, i) => { 51 | if ((book.title = title)) { 52 | book.title = title; 53 | book.author = author; 54 | index = i; 55 | } 56 | }); 57 | res.status(200).json(mockDB[index]); 58 | }); 59 | 60 | app.delete('/book/:title', (req, res) => { 61 | let targetBook; 62 | const { title } = req.params; 63 | mockDB.forEach((book, i) => { 64 | if ((book.title = title)) { 65 | targetBook = book; 66 | mockDB = mockDB.slice(0, i).concat(mockDB.slice(i + 1)); 67 | index = i; 68 | } 69 | }); 70 | res.status(200).json(targetBook); 71 | }); 72 | 73 | 74 | const httpApp = app.listen(PORT, () => { 75 | console.log(`HTTP Test Server: listening on PORT ${PORT}`); 76 | }); 77 | 78 | module.exports = httpApp; 79 | -------------------------------------------------------------------------------- /test/hw2.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package helloworld; 4 | service Greeter { 5 | rpc SayHello (HelloRequest) returns (HelloReply) {} 6 | rpc SayHelloNested (HelloNestedRequest) returns (HelloNestedReply) {} 7 | rpc SayHellosSs (HelloRequest) returns (stream HelloReply) {} 8 | rpc SayHelloCS (stream HelloRequest) returns (HelloReply) {} 9 | rpc SayHelloBidi (stream HelloRequest) returns (stream HelloReply) {} 10 | } 11 | 12 | message HelloRequest { 13 | string name = 1; 14 | } 15 | 16 | message HelloReply { 17 | string message = 1; 18 | } 19 | 20 | message HelloNestedRequest { 21 | HelloRequest firstPerson = 1; 22 | HelloRequest secondPerson = 2; 23 | } 24 | 25 | message HelloNestedReply { 26 | repeated HelloReply serverMessage = 1; 27 | 28 | } 29 | message HelloHowOldRequest { 30 | int32 age = 1; 31 | } 32 | message HelloAge { 33 | int32 age = 1; 34 | } 35 | -------------------------------------------------------------------------------- /test/tRPC_Test_Servers/Express Test Server/client/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /test/tRPC_Test_Servers/Express Test Server/client/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Vite + TS 7 | 8 | 9 | 10 |

Hello we are in our file

11 | 12 | 13 | -------------------------------------------------------------------------------- /test/tRPC_Test_Servers/Express Test Server/client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "client", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc && vite build", 9 | "preview": "vite preview" 10 | }, 11 | "devDependencies": { 12 | "typescript": "^4.9.3", 13 | "vite": "^4.0.0" 14 | }, 15 | "dependencies": { 16 | "@trpc/client": "^10.9.1" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /test/tRPC_Test_Servers/Express Test Server/client/src/main.ts: -------------------------------------------------------------------------------- 1 | import { createTRPCProxyClient, httpBatchLink } from "@trpc/client" 2 | import type { AppRouter } from "../../server/routers" 3 | 4 | const client = createTRPCProxyClient({ 5 | links: [ 6 | httpBatchLink({ 7 | url: "http://localhost:3000/trpc", 8 | }), 9 | ], 10 | }) 11 | 12 | async function main() { 13 | // const result = await client.greeting.query({ name: "Kyle" }) 14 | // console.log(result) 15 | 16 | // await client.error.query().catch(e => console.error(e)) 17 | 18 | // const users = await Promise.all([ 19 | // client.users.byId.query("1"), 20 | // client.users.byId.query("2"), 21 | // client.users.byId.query("3"), 22 | // client.users.byId.query("4"), 23 | // client.users.byId.query("5"), 24 | // client.users.byId.query("6"), 25 | // ]) 26 | // console.log(users) 27 | 28 | const newUser = await client.users.create.mutate({ name: "John", age: 12 }) 29 | console.log(newUser) 30 | 31 | const newUserGot = await client.users.byId.query(newUser.id) 32 | console.log(newUserGot) 33 | } 34 | 35 | main() 36 | -------------------------------------------------------------------------------- /test/tRPC_Test_Servers/Express Test Server/client/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /test/tRPC_Test_Servers/Express Test Server/client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "module": "ESNext", 6 | "lib": ["ESNext", "DOM"], 7 | "moduleResolution": "Node", 8 | "strict": true, 9 | "resolveJsonModule": true, 10 | "isolatedModules": true, 11 | "esModuleInterop": true, 12 | "noEmit": true, 13 | "noUnusedLocals": true, 14 | "noUnusedParameters": true, 15 | "noImplicitReturns": true, 16 | "skipLibCheck": true 17 | }, 18 | "include": ["src"] 19 | } 20 | -------------------------------------------------------------------------------- /test/tRPC_Test_Servers/Express Test Server/server/api.ts: -------------------------------------------------------------------------------- 1 | import { createExpressMiddleware } from "@trpc/server/adapters/express" 2 | import express from "express" 3 | import cors from "cors" 4 | import { appRouter } from "./routers" 5 | 6 | const app = express() 7 | app.use(cors({ origin: "http://localhost:8080" })) 8 | 9 | app.use( 10 | "/trpc", 11 | createExpressMiddleware({ 12 | router: appRouter, 13 | createContext: ({ req, res }) => { 14 | return {} 15 | }, 16 | }) 17 | ) 18 | app.listen(3001) 19 | -------------------------------------------------------------------------------- /test/tRPC_Test_Servers/Express Test Server/server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "server", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "scripts": { 6 | "start": "nodemon api.ts" 7 | }, 8 | "keywords": [], 9 | "author": "", 10 | "license": "ISC", 11 | "description": "", 12 | "devDependencies": { 13 | "@types/cors": "^2.8.13", 14 | "@types/express": "^4.17.14", 15 | "@types/node": "^18.11.14", 16 | "@types/ws": "^8.5.4", 17 | "nodemon": "^2.0.20", 18 | "ts-node": "^10.9.1" 19 | }, 20 | "dependencies": { 21 | "@trpc/client": "^10.9.1", 22 | "@trpc/server": "^10.5.0", 23 | "cors": "^2.8.5", 24 | "express": "^4.18.2", 25 | "ws": "^8.12.1", 26 | "zod": "^3.20.6" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /test/tRPC_Test_Servers/Express Test Server/server/routers/index.ts: -------------------------------------------------------------------------------- 1 | import { t } from "../trpc" 2 | import { z } from "zod" 3 | import { usersRouter } from "./users" 4 | 5 | export const appRouter = t.router({ 6 | greeting: t.procedure 7 | .input(z.object({ name: z.string() })) 8 | .query(requestObj => { 9 | console.log(requestObj) 10 | return `Hello ${requestObj.input.name}` 11 | }), 12 | errors: t.procedure.query(() => { 13 | throw new Error("This is an error message") 14 | }), 15 | users: usersRouter, 16 | }) 17 | 18 | export type AppRouter = typeof appRouter 19 | -------------------------------------------------------------------------------- /test/tRPC_Test_Servers/Express Test Server/server/routers/users.ts: -------------------------------------------------------------------------------- 1 | import { t } from "../trpc" 2 | import { z } from "zod" 3 | import { randomUUID } from "crypto" 4 | import { observable } from "@trpc/server/observable" 5 | import { EventEmitter } from "events"; 6 | import * as trpc from '@trpc/server' 7 | 8 | const ee = new EventEmitter(); 9 | 10 | type User = { 11 | id: string 12 | name: string 13 | age: number 14 | } 15 | 16 | const USERS: User[] = [ 17 | { id: "1", name: "Kyle", age: 27 }, 18 | { id: "2", name: "Julie", age: 45 }, 19 | ] 20 | 21 | export const usersRouter = t.router({ 22 | byId: t.procedure.input(z.string()).query(req => { 23 | return USERS.find(user => user.id === req.input) 24 | }), 25 | create: t.procedure 26 | .input(z.object({ name: z.string(), age: z.number() })) 27 | .mutation(req => { 28 | const { name, age } = req.input 29 | const user: User = { id: randomUUID(), name, age } 30 | USERS.push(user) 31 | return user 32 | }), 33 | randomNumber: t.procedure.subscription(() => { 34 | return observable<{ randomNumber: number }>((emit) => { 35 | const timer = setInterval(() => { 36 | // emits a number every second 37 | emit.next({ randomNumber: Math.random() }); 38 | }, 200); 39 | 40 | return () => { 41 | clearInterval(timer); 42 | }; 43 | }); 44 | }), 45 | }) 46 | -------------------------------------------------------------------------------- /test/tRPC_Test_Servers/Express Test Server/server/trpc.ts: -------------------------------------------------------------------------------- 1 | import { initTRPC } from "@trpc/server" 2 | 3 | export const t = initTRPC.create() 4 | -------------------------------------------------------------------------------- /test/tRPC_Test_Servers/Express Test Server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "moduleResolution": "node", 4 | "target": "ES6", 5 | "esModuleInterop": true, 6 | "strict": true, 7 | "outDir": "dist" 8 | }, 9 | "include": ["server"] 10 | } 11 | -------------------------------------------------------------------------------- /test/tRPC_Test_Servers/Express_Test_Server/client/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /test/tRPC_Test_Servers/Express_Test_Server/client/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Vite + TS 7 | 8 | 9 | 10 |

Hello we are in our file

11 | 12 | 13 | -------------------------------------------------------------------------------- /test/tRPC_Test_Servers/Express_Test_Server/client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "client", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc && vite build", 9 | "preview": "vite preview" 10 | }, 11 | "devDependencies": { 12 | "typescript": "^4.9.3", 13 | "vite": "^4.0.0" 14 | }, 15 | "dependencies": { 16 | "@trpc/client": "^10.9.1" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /test/tRPC_Test_Servers/Express_Test_Server/client/src/main.ts: -------------------------------------------------------------------------------- 1 | import { createTRPCProxyClient, httpBatchLink } from "@trpc/client" 2 | import type { AppRouter } from "../../server/routers" 3 | 4 | const client = createTRPCProxyClient({ 5 | links: [ 6 | httpBatchLink({ 7 | url: "http://localhost:3000/trpc", 8 | }), 9 | ], 10 | }) 11 | 12 | async function main() { 13 | // const result = await client.greeting.query({ name: "Kyle" }) 14 | // console.log(result) 15 | 16 | // await client.error.query().catch(e => console.error(e)) 17 | 18 | // const users = await Promise.all([ 19 | // client.users.byId.query("1"), 20 | // client.users.byId.query("2"), 21 | // client.users.byId.query("3"), 22 | // client.users.byId.query("4"), 23 | // client.users.byId.query("5"), 24 | // client.users.byId.query("6"), 25 | // ]) 26 | // console.log(users) 27 | 28 | const newUser = await client.users.create.mutate({ name: "John", age: 12 }) 29 | console.log(newUser) 30 | 31 | const newUserGot = await client.users.byId.query(newUser.id) 32 | console.log(newUserGot) 33 | } 34 | 35 | main() 36 | -------------------------------------------------------------------------------- /test/tRPC_Test_Servers/Express_Test_Server/client/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /test/tRPC_Test_Servers/Express_Test_Server/client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "module": "ESNext", 6 | "lib": ["ESNext", "DOM"], 7 | "moduleResolution": "Node", 8 | "strict": true, 9 | "resolveJsonModule": true, 10 | "isolatedModules": true, 11 | "esModuleInterop": true, 12 | "noEmit": true, 13 | "noUnusedLocals": true, 14 | "noUnusedParameters": true, 15 | "noImplicitReturns": true, 16 | "skipLibCheck": true 17 | }, 18 | "include": ["src"] 19 | } 20 | -------------------------------------------------------------------------------- /test/tRPC_Test_Servers/Express_Test_Server/server/api.ts: -------------------------------------------------------------------------------- 1 | import { createExpressMiddleware } from "@trpc/server/adapters/express" 2 | import express from "express" 3 | import cors from "cors" 4 | import { appRouter } from "./routers" 5 | 6 | const app = express() 7 | app.use(cors({ origin: "http://localhost:8080" })) 8 | 9 | app.use( 10 | "/trpc", 11 | createExpressMiddleware({ 12 | router: appRouter, 13 | createContext: ({ req, res }) => { 14 | return {} 15 | }, 16 | }) 17 | ) 18 | 19 | const server = app.listen(3001, () => { 20 | console.log('tRPC Server running on port 3001'); 21 | }) 22 | 23 | module.exports = { server } 24 | -------------------------------------------------------------------------------- /test/tRPC_Test_Servers/Express_Test_Server/server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "server", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "scripts": { 6 | "start": "nodemon api.ts" 7 | }, 8 | "keywords": [], 9 | "author": "", 10 | "license": "ISC", 11 | "description": "", 12 | "devDependencies": { 13 | "@types/cors": "^2.8.13", 14 | "@types/express": "^4.17.14", 15 | "@types/node": "^18.11.14", 16 | "@types/ws": "^8.5.4", 17 | "nodemon": "^2.0.20", 18 | "ts-node": "^10.9.1" 19 | }, 20 | "dependencies": { 21 | "@trpc/client": "^10.9.1", 22 | "@trpc/server": "^10.5.0", 23 | "cors": "^2.8.5", 24 | "express": "^4.18.2", 25 | "ws": "^8.12.1", 26 | "zod": "^3.20.6" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /test/tRPC_Test_Servers/Express_Test_Server/server/routers/index.ts: -------------------------------------------------------------------------------- 1 | import { t } from "../trpc" 2 | import { z } from "zod" 3 | import { usersRouter } from "./users" 4 | 5 | export const appRouter = t.router({ 6 | greeting: t.procedure 7 | .input(z.object({ name: z.string() })) 8 | .query(requestObj => { 9 | console.log(requestObj) 10 | return `Hello ${requestObj.input.name}` 11 | }), 12 | errors: t.procedure.query(() => { 13 | throw new Error("This is an error message") 14 | }), 15 | users: usersRouter, 16 | }) 17 | 18 | export type AppRouter = typeof appRouter 19 | -------------------------------------------------------------------------------- /test/tRPC_Test_Servers/Express_Test_Server/server/routers/users.ts: -------------------------------------------------------------------------------- 1 | import { t } from "../trpc" 2 | import { z } from "zod" 3 | import { randomUUID } from "crypto" 4 | import { observable } from "@trpc/server/observable" 5 | import { EventEmitter } from "events"; 6 | import * as trpc from '@trpc/server' 7 | 8 | const ee = new EventEmitter(); 9 | 10 | type User = { 11 | id: string 12 | name: string 13 | age: number 14 | } 15 | 16 | const USERS: User[] = [ 17 | { id: "1", name: "Kyle", age: 27 }, 18 | { id: "2", name: "Julie", age: 45 }, 19 | ] 20 | 21 | export const usersRouter = t.router({ 22 | byId: t.procedure.input(z.string()).query(req => { 23 | return USERS.find(user => user.id === req.input) 24 | }), 25 | create: t.procedure 26 | .input(z.object({ name: z.string(), age: z.number() })) 27 | .mutation(req => { 28 | const { name, age } = req.input 29 | const user: User = { id: randomUUID(), name, age } 30 | USERS.push(user) 31 | return user 32 | }), 33 | randomNumber: t.procedure.subscription(() => { 34 | return observable<{ randomNumber: number }>((emit) => { 35 | const timer = setInterval(() => { 36 | // emits a number every second 37 | emit.next({ randomNumber: Math.random() }); 38 | }, 200); 39 | 40 | return () => { 41 | clearInterval(timer); 42 | }; 43 | }); 44 | }), 45 | }) 46 | -------------------------------------------------------------------------------- /test/tRPC_Test_Servers/Express_Test_Server/server/trpc.ts: -------------------------------------------------------------------------------- 1 | import { initTRPC } from "@trpc/server" 2 | 3 | export const t = initTRPC.create() 4 | -------------------------------------------------------------------------------- /test/tRPC_Test_Servers/Express_Test_Server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "moduleResolution": "node", 4 | "target": "ES6", 5 | "esModuleInterop": true, 6 | "strict": true, 7 | "outDir": "dist" 8 | }, 9 | "include": ["server"] 10 | } 11 | -------------------------------------------------------------------------------- /test/tRPC_Test_Servers/WebSocket Test Server/README.md: -------------------------------------------------------------------------------- 1 | Bare-minimum example. 2 | 3 | - Standalone HTTP-server + WebSocket 4 | - Vanilla `TRPCClient` in node 5 | 6 | Try in StackBlitz: https://stackblitz.com/github/trpc/trpc/tree/main/examples/standalone-server?file=src%2Fserver.ts,src%2Fclient.ts&view=editor&terminal=dev 7 | 8 | --- 9 | 10 | ### Get started 11 | 12 | Created by [@alexdotjs](https://twitter.com/alexdotjs). 13 | -------------------------------------------------------------------------------- /test/tRPC_Test_Servers/WebSocket Test Server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@examples/standalone-server", 3 | "version": "10.11.1", 4 | "private": true, 5 | "scripts": { 6 | "dev:server": "tsx watch src/server", 7 | "dev:client": "wait-port 2022 && tsx watch src/client", 8 | "dev": "run-p dev:* --print-label", 9 | "start": "pnpm dev", 10 | "build": "tsc", 11 | "lint": "eslint --ext \".js,.ts,.tsx\" --report-unused-disable-directives src", 12 | "test-dev": "start-server-and-test 'tsx src/server' 2022 'tsx src/client'", 13 | "test-start": "start-server-and-test 'node dist/server' 2022 'node dist/client'" 14 | }, 15 | "dependencies": { 16 | "@trpc/client": "^10.11.1", 17 | "@trpc/react-query": "^10.11.1", 18 | "@trpc/server": "^10.11.1", 19 | "@types/node-fetch": "^2.5.11", 20 | "cors": "^2.8.5", 21 | "express": "^4.18.2", 22 | "node-fetch": "^2.6.1", 23 | "ws": "^8.0.0", 24 | "zod": "^3.0.0" 25 | }, 26 | "alias": { 27 | "scheduler/tracing": "../../node_modules/scheduler/tracing-profiling" 28 | }, 29 | "devDependencies": { 30 | "@types/cors": "^2.8.13", 31 | "@types/express": "^4.17.17", 32 | "@types/node": "^18.7.20", 33 | "@types/ws": "^8.2.0", 34 | "eslint": "^8.30.0", 35 | "npm-run-all": "^4.1.5", 36 | "start-server-and-test": "^1.12.0", 37 | "tsx": "^3.9.0", 38 | "typescript": "^4.8.3", 39 | "wait-port": "^1.0.1" 40 | }, 41 | "publishConfig": { 42 | "access": "restricted" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /test/tRPC_Test_Servers/WebSocket Test Server/sandbox.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "view": "console", 3 | "container": { 4 | "node": "14" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/tRPC_Test_Servers/WebSocket Test Server/src/client.ts: -------------------------------------------------------------------------------- 1 | import { 2 | createTRPCProxyClient, 3 | createWSClient, 4 | httpLink, 5 | splitLink, 6 | wsLink, 7 | } from '@trpc/client'; 8 | import fetch from 'node-fetch'; 9 | import ws from 'ws'; 10 | import type { AppRouter } from './server'; 11 | 12 | 13 | 14 | 15 | // polyfill fetch & websocket 16 | const globalAny = global as any; 17 | globalAny.fetch = fetch; 18 | globalAny.WebSocket = ws; 19 | 20 | const wsClient = createWSClient({ 21 | url: `ws://localhost:2022`, 22 | }); 23 | const trpc = createTRPCProxyClient({ 24 | links: [ 25 | // call subscriptions through websockets and the rest over http 26 | splitLink({ 27 | condition(op) { 28 | return op.type === 'subscription'; 29 | }, 30 | true: wsLink({ 31 | client: wsClient, 32 | }), 33 | false: httpLink({ 34 | url: `http://localhost:2022`, 35 | }), 36 | }), 37 | ], 38 | }); 39 | 40 | // async function main() { 41 | // const helloResponse = await trpc.greeting.hello.query({ 42 | // name: 'world', 43 | // }) 44 | 45 | // console.log('helloResponse', helloResponse); 46 | 47 | // const createPostRes = await trpc.post.createPost.mutate({ 48 | // title: 'hello world', 49 | // text: 'check out https://tRPC.io', 50 | // }); 51 | // console.log('createPostResponse', createPostRes); 52 | 53 | let count = 0; 54 | async function main() { 55 | let count = 0; 56 | await new Promise((resolve) => { 57 | const subscription = client.post.randomNumber.subscribe(undefined, { 58 | onData(data) { 59 | // ^ note that `data` here is inferred 60 | console.log('received', data); 61 | count++; 62 | if (count > 6) { 63 | // stop after 3 pulls 64 | subscription.unsubscribe(); 65 | resolve(); 66 | } 67 | }, 68 | onError(err) { 69 | console.error('error', err); 70 | }, 71 | }); 72 | }); 73 | wsClient.close(); 74 | } 75 | 76 | main(); 77 | -------------------------------------------------------------------------------- /test/tRPC_Test_Servers/WebSocket Test Server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "./dist", 4 | "lib": ["ES2019", "DOM"], 5 | "module": "commonjs", 6 | "target": "ES2019", 7 | "declaration": true, 8 | "esModuleInterop": true, 9 | "strict": true 10 | }, 11 | "include": ["src"], 12 | "exclude": ["node_modules"] 13 | } 14 | -------------------------------------------------------------------------------- /webpack.development.js: -------------------------------------------------------------------------------- 1 | const merge = require('webpack-merge').merge; 2 | const base = require('./webpack.config'); 3 | const { spawn } = require('child_process'); 4 | 5 | module.exports = merge(base, { 6 | mode: 'development', 7 | devtool: 'source-map', 8 | devServer: { 9 | host: '127.0.0.1', 10 | port: '8080', 11 | open: '/dev', 12 | hot: true, 13 | compress: true, 14 | proxy: { 15 | '/webhookServer': { 16 | target: 'http://localhost:3001', 17 | }, 18 | '/webhook': { 19 | target: 'http://localhost:3001', 20 | }, 21 | '/api': { 22 | target: 'http://localhost:3001', 23 | /** 24 | * @todo Change secure option to true, and refactor code to account for 25 | * change // https://github.com/electron/electron/issues/19775 ??? maybe this is the solution 26 | */ 27 | secure: false, 28 | }, 29 | }, 30 | setupMiddlewares: (middlewares, devServer) => { 31 | if (!devServer) { 32 | throw new Error('webpack-dev-server is not defined'); 33 | } 34 | // console.log('Setting up middlewares...:', middlewares); 35 | middlewares.unshift({ 36 | // unshift does not work, ends in infinite calls to this function 37 | name: 'run-in-electron', 38 | path: '/dev', 39 | middleware: (req, res) => { 40 | spawn('npx electron --dev .', { 41 | shell: true, 42 | env: process.env, 43 | stdio: 'inherit', 44 | }) 45 | .on('close', () => process.exit(130)) 46 | .on('error', (spawnError) => console.error(spawnError)); 47 | return res 48 | .status(200) 49 | .send('Opened the Electron app in development mode.'); 50 | }, 51 | }); 52 | return middlewares; 53 | }, 54 | }, 55 | }); 56 | -------------------------------------------------------------------------------- /webpack.production.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const merge = require('webpack-merge').merge; 3 | const base = require('./webpack.config'); 4 | 5 | module.exports = merge(base, { 6 | mode: 'production', 7 | output: { 8 | path: path.resolve(__dirname, 'dist'), 9 | filename: 'bundle.js', 10 | publicPath: './', 11 | }, 12 | devtool: 'nosources-source-map', 13 | }); 14 | --------------------------------------------------------------------------------