├── .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 | // setMessage(null)}
49 | // >
50 | // Dismiss
51 | //
52 |
53 | // {message === 'Update downloaded.' && (
54 | //
58 | // Update
59 | //
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 |
graphQLController.introspect(url, headers, cookies)}
34 | >
35 | Introspect
36 |
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 | importDoc()}
21 | >
22 | Load Document
23 |
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 |
26 | OpenAPI
27 |
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 |
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 |
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 |
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 |
31 | GET
32 | POST
33 | PUT
34 | PATCH
35 | DELETE
36 |
37 |
38 |
46 |
50 | Send
51 |
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 |
64 |
65 |
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 |
42 | {`Add New ${type}`}
43 |
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 | Key
41 | Value
42 |
43 |
44 | {cookies}
45 |
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 |
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 |
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 |
28 | Prettify
29 |
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 |
14 | Add to Workspace
15 |
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 |
18 | {buttonText}
19 |
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 |
58 | {menuItems}
59 |
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 |
38 | Clear History
39 |
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 |
18 |
19 |
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 |
49 |
50 |
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 |
25 |
26 |
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 | {
21 | ReqResCtrl.clearAllReqRes();
22 | ReqResCtrl.clearAllGraph();
23 | }}
24 | >
25 | Clear Workspace
26 |
27 |
28 | {
33 | setShowModal(true);
34 | }}
35 | >
36 | Save or Create New Workspace
37 |
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 |
56 | collectionsController.exportCollection(localWorkspaces)
57 | }
58 | >
59 | Files
60 |
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 |
--------------------------------------------------------------------------------