diff --git a/.markdownlint.json b/.markdownlint.json new file mode 100644 index 0000000..72cf5dd --- /dev/null +++ b/.markdownlint.json @@ -0,0 +1,15 @@ +{ + "MD033": { + "allowed_elements": [ + "div", + "img", + "br", + "b", + "sup", + "a" + ] + }, + "MD013": { + "line_length" : 200 + } +} diff --git a/CHANGELOG.md b/CHANGELOG.md index ede6f81..8f0db72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,31 @@ All notable changes to the "Fetch Client" extension will be documented in this file. +## v1.6.0 - August, 2024 +### πŸŽ‰ New Features +- Added menu for directly run the requests +- Added headers and pre-requests in the collection settings. +- Added headers in the folder settings. +- Added option for skip parent headers and parent pre-requests in the request panel. +- Implemented run the parent(collection/folder) pre-requests for all requests in "Run All" section. +- Added support for import "Thunder Client" collection(v1.2) and variables(v1.2). +- Added backup for change location from global storage to workspace path. +- By default response code and time will be logged in the logs. +- New menu added for navigate to `Fetch Client` documentation. + +### πŸ› Bug Fixes +- URL issue fixed when url has query parameter. + +### πŸ”— Miscellaneous +- Documentation updated about the `Fetch Client`. + +### Requirements +- Minimum required version of **VSCode** is `v1.75.0` +- Minimum **Node** version is `18.20.3` + ## v1.5.2 - July, 2024 ### πŸ› Bug Fixes -- New request loadind fix +- New request loading fix ### Requirements - Minimum required version of VSCode is v1.75.0 @@ -27,7 +49,7 @@ All notable changes to the "Fetch Client" extension will be documented in this f ### πŸ› Bug Fixes - import from Curl ([#5](https://github.com/Ganesan-Chandran/vscode-fetch-client/issues/5)). - POST method not properly set just after creating new Http Request in a collection ([#8](https://github.com/Ganesan-Chandran/vscode-fetch-client/issues/8)) -- Bug fix in RunAll section +- Bug fix in "Run All" section - Bug fix in filter search in collection section in the sidebar ### Requirements @@ -40,7 +62,7 @@ All notable changes to the "Fetch Client" extension will be documented in this f - OAuth2 added for request authorization. - Pre-requests(Pre-Fetch) and conditions are added for Request execution. - Tests and Variables are moved to PostFetch section. -- Types genreation added for JSON response. +- Types generation added for JSON response. - Added auto refresh in the request tabs when variables are modified. - Added log for request and response in the output window. - Added "View Log" button in the sidebar panel to open the log output window. @@ -84,7 +106,7 @@ All notable changes to the "Fetch Client" extension will be documented in this f - "Inherit auth from parent" option added in the Auth section. - Support Reorder and disable the request in the "Run All" Collection. - File option added in Form in the request body. -- Full screen mode is added for resonse section. +- Full screen mode is added for response section. ### πŸ› Bug Fixes @@ -119,11 +141,11 @@ All notable changes to the "Fetch Client" extension will be documented in this f - Various post body which are Form, Form-Encoded, Raw (Json, Plain Text, XML), Binary File and GraphQL. - Syntax highlight for Response data. - Tree view for JSON and XML responses and HTML preview for HTML responses. -- History, Collection, Enivronment Variable are supported. +- History, Collection, Environment Variable are supported. - Test the API request and response data without any scripts/code. - Generate code snippet for various languages. - Save response and test results as File. -- Export/Import the Fecth Client's collections and environment variables. +- Export/Import the Fetch Client's collections and environment variables. - Add documentation/feedback for each request. ### πŸ› Bug Fixes diff --git a/README.md b/README.md index 6705f29..92c3b0e 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Fetch Client
- + Fetch Client Icon
@@ -18,7 +18,7 @@ Fetch Client is Visual Studio Code extension which is used to test the Rest API. * UI Customization and support VSCode Themes. * Test Rest API request with GET, POST, PUT, PATCH, DELETE, HEAD and OPTIONS methods. * Run curl requests. -* Various authorization mechcanisms such as Basic Auth, Bearer Token, API Key and AWS Signature. +* Various authorization mechanisms such as Basic Auth, Bearer Token, API Key and AWS Signature. * Various post body which are Form, Form-Encoded, Raw (Json, Plain Text, XML), Binary File and GraphQL. * Syntax highlight for Response data. * Tree view for JSON and XML responses and HTML preview for HTML responses. @@ -26,19 +26,24 @@ Fetch Client is Visual Studio Code extension which is used to test the Rest API. * Test the API request and response data without any scripts/code. * Generate code snippet for various languages. * Save response and test results as File. -* Export/Import the Fetch Client's collections and environment variables. +* Export/Import the Fetch Client/Postman/Thunder Client's collections and environment variables. * Add documentation/feedback for each request. * Set the environment variable data from the response. * Manage the Cookies. +* Pre-requests in request level as well as collection/folder level. +* Run all the requests in the collection using single click. +* Save all request data in the custom/workspace folder (Team collaboration). +* Supports system variables +* View request and response logs. ## πŸ“¦ How to Install ? - * Install via VSCode Extensions - * Open VSCode Extensions panel using `Ctrl+Shift+X` shortcut. - * Type `Fetch Client` in Search bar. - * Select the `Fetch Client` and install the extension. +* Install via VSCode Extensions + * Open VSCode Extensions panel using `Ctrl+Shift+X` shortcut. + * Type `Fetch Client` in Search bar. + * Select the `Fetch Client` and install the extension.
- + Fetch Client Extension
@@ -49,8 +54,9 @@ Fetch Client is Visual Studio Code extension which is used to test the Rest API. * Select the `Http method` and enter the `URL` and other parameters such as query parameters, headers, auth details, request body (if required) and click the `Send` button. * The response data will be displayed in the `Response` section. We can view the response data in the Tree view format for `JSON` and `XML` responses and HTML preview for `HTML` responses. * All existing requests are available in the `History` section in the Quick Access Bar. +
- + Fetch Client Extension
Fetch Client v1.0.0
@@ -67,122 +73,139 @@ Fetch Client is Visual Studio Code extension which is used to test the Rest API. * [Set Environment Variable](#setvar) * [Response Data](#resdata) * [Test Results](#testresults) +* [Pre-requests](#prerequests) * [Notes](#notes) * [Code Snippet](#codesnippet) * [Request Cancel](#reqcancel) * [Quick Access](#quickaccess) - * [History](#history) - * [Collection](#collection) - * [Environment Variable](#envvar) + * [History](#history) + * [Collection](#collection) + * [Environment Variable](#envvar) * [Run All requests](#runall) * [Manage Cookies](#managecookies) * [Run/Import Curl Request](#runcurl) +* [System variables](#systemvariables) +* [Logs](#logs) + ### 1) UI Customization We can customize the UI in different modes. - * Horizontal mode - * Accordian View - * Split View - * Vertical mode - * Split View + +* Horizontal mode + * Accordion View + * Split View +* Vertical mode + * Split View
- + Fetch Client-Horizontal mode(Accordion View)
- Horizontal mode - Accordian View + Horizontal mode - Accordion View

- + Fetch Client-Horizontal mode(Split View)
Horizontal mode - Split View

- + Fetch Client-Vertical mode(Split View)
Vertical mode - Split View
+ ### 2) Different HTTP Methods Fetch client supports to test the Rest API request with various HTTP methods such as GET, POST, PUT, PATCH, DELETE, HEAD and OPTIONS. + ### 3) Query Parameter Fetch client supports to test the Rest API request with query parameter. + ### 4) Authorization + Fetch client supports below authorization methods for Rest API testing. + * Basic Auth * Bearer Token * API Key * AWS Signature +* OAuth 2.0 + ### 5) Headers We can add the headers for API testing. Fetch Client gives the suggestion on various headers and corresponding values in the header section.

- + Header search

- + Header suggestion
+ ### 6) Request Body - * Fetch client supports below request body. - * Form - * Form-Encoded - * Raw ( JSON, Plain Text, XML ) - * Binary File - * GraphQL - * `Content-Type` header will be automatically added based on binary file type. +* Fetch client supports below request body. + * Form + * Form-Encoded + * Raw ( JSON, Plain Text, XML ) + * Binary File + * GraphQL +* `Content-Type` header will be automatically added based on binary file type.

- + Body request(Binary format)
+ ### 7) Test - * We can test the API request and response data without any scripts/code in the Fetch client. - * It supports to test the below data, - * Response Code - * Response Body - * Response Time - * Content-Type - * Content-Length - * Content-Encoding - * Specific Response Header value - * Specific JSON property value in the JSON response +* We can test the API request and response data without any scripts/code in the Fetch client. +* It supports to test the below data, + * Response Code + * Response Body + * Response Time + * Content-Type + * Content-Length + * Content-Encoding + * Specific Response Header value + * Specific JSON property value in the JSON response

- + Visual test editor + Visual test case and test results
Fetch Client - Test Case/Test Results
+ ### 8) Set Environment Variable * Fetch client supports the set the environment variable data from the response, headers and cookies.

- + assign variables
+ ### 9) Response Data * Fetch client supports Syntax highlight for Response data. @@ -193,10 +216,11 @@ We can add the headers for API testing. Fetch Client gives the suggestion on var * View response headers.
- + response view
+ ### 10) Test Results * Once request is processed, Fetch client executes the test cases and display the test result with expected value and actual value. @@ -204,146 +228,264 @@ We can add the headers for API testing. Fetch Client gives the suggestion on var

- + Test results +
+ + + +### 11) Pre-requests + +* Add list of pre-requests at request, folder and collection level. +* Run pre-requests with/without the conditions. +* We can configure the dependency between main request with pre-requests in the `Fetch Client` settings. + +
+ Pre-requests
-### 11) Notes + +### 12) Notes Notes section is used to add the notes or documentation regarding the request. Fetch client has simple editor to add the documentation.
- + notes
-### 12) Code Snippet - -Fetch client supports code snippet generation for various languages. Generate code snippets to send request from another application. Open request view and click icon (right side of the response section) for code snippet generation. The code snippet generation is available for following languages. - * C - * C# - * Go - * Java - * JavaScript - * Node - * PHP - * Python - * Shell + +### 13) Code Snippet + +Fetch client supports code snippet generation for various languages. +Generate code snippets to send request from another application. +Open request view and click icon (right side of the response section) for code snippet generation. +The code snippet generation is available for following languages. + +* C +* C# +* Go +* Java +* JavaScript +* Node +* PHP +* Python +* Shell
- + code snippet generation
-### 13) Request Cancel + +### 14) Request Cancel Fetch client provides the feature for cancel the request. If you want to cancel the processing request then click then "Cancel Request" button in the response section. -### 14) Quick Access + +### 15) Quick Access Fetch client provides the quick access of History, collection and Environment variables in the side bar. - * ### History - * Automatic saving of requests in History. - * Save the history item to the collections. - * Delete all history items or specific history item. + +* ### History + + * Automatic saving of requests in History. + * Save the history item to the collections. + * Delete all history items or specific history item. - * ### Collection - * Save requests to a collection. - * Organize the request using the collections. - * Run all the requests in the collection using `Run All` options and download the results as file. - * Attach the Environment variable to collections. - * `Export` the collections as JSON file. - * `Import` the Fetch Client collections from above exported JSON file. (It is used to share the collections between team members.) - * Duplicate the collection items. - ### How to Import Collection - * Select the `Collection` tab from the sidebar - * Click Menu icon and Select `Import` option. - * Now select `Fetch Client` collection file. + +* ### Collection + + * Save requests to a collection. + * Organize the request using the collections. + * Run all the requests in the collection using `Run All` options and download the results as file. + * Attach the Environment variable to collections. + * `Export` the collections as JSON file. + * `Import` the Fetch Client collections from above exported JSON file. (It is used to share the collections between team members.) + * Duplicate the collection items. + +
+
+ Collection menu +
+ +### How to Import Collection + +* Select the `Collection` tab from the sidebar +* Click Menu icon and Select `Import` option. +* Now select `Fetch Client`/`Postman(v2.1)`/`ThunderClient(v1.2)` collection file. +* Supports settings in each collection + * Authorization + * Headers + * Pre-requests + +
+
+ Import Collection +
- * ### Environment Variable - * Create and set variables at multiple scopes - * Global Level - * Collection level - * Request level - * It is simple key value pair combination. - * Use environment variables in URL, Query Param, Authorization, Header, Request Body (Form and Form-Encoded), Test sections. - * `Export` variables as JSON file. - * `Import` the Fetch Client variables from above exported JSON file. - * In the input, enter a variable name in the `{{variableName}}` format. - ### How to Import Variable - * Select the `Variable` tab from the sidebar - * Click Menu icon and Select `Import` option. - * Now select `Fetch Client` variable file. + +* ### Environment Variable + + * Create and set variables at multiple scopes + * Global Level + * Collection level + * Request level + * It is simple key value pair combination. + * Use environment variables in URL, Query Param, Authorization, Header, Request Body (Form and Form-Encoded), Test sections. + * `Export` variables as JSON file. + * `Import` the Fetch Client variables from above exported JSON file. + * In the input, enter a variable name in the `{{variableName}}` format. + +### How to Import Variable + +* Select the `Variable` tab from the sidebar +* Click Menu icon and Select `Import` option. +* Now select `Fetch Client`/`Postman(v2.1)`/`ThunderClient(v1.2)` variable file.

- + Sidebar quick access
-### 15) Run All requests + +### 16) Run All requests * Run all the requests in the collection using "Run All" options and download the results as file. +* Change the execution order of the requests in the 'Run All' section. +* Execute the request either in a sequential or parallel manner. * Once completed the all request, export the test result as `JSON` or `CSV`. * If you click the particular request from the table, it will open the corresponding request view.

- - - + Run All menu + Run All UI + Run All settings
-### 16) Manage Cookies + +### 17) Manage Cookies + * View/Delete the cookies in the Manage Cookies Page. * Cookie header will automatically added if cookies are available for that request. * You can modify the cookies using the `cookie` header.

- - + Manage Cookies Menu + Manage Cookies UI
-### 17) Run/Import Curl Request + +### 18) Run/Import Curl Request

- + Import Curl Menu
- + Import Curl
Import Curl Request
- + Run Curl Command
Run Curl Request
+ + +### 19) System variables + +* System variable is used to generate dynamic data and use query parameters and request body (formdata, formurlencoded) . +* Below are supported system variables. + * {{#num}} - Generate random number between 1 to 999999 + * {{#num, min, max}} - Generate random number between given min and max value + * {{#str}} - Generate random string(only alphabets) with max length of 15 + * {{#strspl}} - Generate random string(alphabets and special characters) with max length of 15 + * {{#strnum}} - Generate random string(alphabets and numbers) with max length of 15 + * {{#char}} - Generate random character + * {{#rdate}} - Generate random date between 01/01/1900 to 01/01/2100 + * {{#date}} - Generate current date + * {{#dateISO}} - Generate current date with ISO format + * {{#date, 'format'}} - Generate current date with given format + * {{#email}} - Generate email with random characters + * {{#guid}} - Generate random guid + * {{#bool}} - Generate random boolean value (true/false) + +
+
+ System variables +
+
+ + + +### 20) Logs + +* Click `View Log` button in the sidebar to view the logs. +* View the logs in the Output Window (Choose `Fetch Client` option in the dropdown). +* Customize the logs in the Fetch Client settings. By Default `request details` will be logged. If the setting is enabled, both `request and response` details will be logged. + +
+
+ Logs +
+
+ +
+
+ Logs settings +
+
+ + + +### 21) Workspace + +* Save all requests data into the current workspace path. +* `Fetch Client` will create `fetch-client` folder in the root of the workspace and all the request files are saved into this folder. +* Enable this option using the below `Fetch Client` setting. + +
+
+ Workspace settings +
+
+ +DO NOT ENTER/EDIT MANUALLY in the below settings. Configuration will be done automatically. Manual editing may lead to data loss. +
+
+ Workspace settings +
+
+ ## ⌨ Keyboard Shortcuts + * `Ctl+Shift+P` (Open Command Palette) * Fetch Client - New Request * `Ctl+Alt+N` - Open `Fetch Client` View -* `Enter` on url textbox to send request +* `Enter` on URL text box to send request * `Cmd/Ctrl + s` - Save Request without run ## βš™οΈ Configuration -* Open VSCode settings View, then search for `Fetch Client` or click `Extension Settings` in the menu item. +* Open VSCode settings View, then search for `Fetch Client` or click `Fetch Client Settings` in the menu item.

- + Fetch Client settings
-* Fetch Client has below configurations. +* Fetch Client has below configurations. |Name | Setting | Default | Description | |-----|---------|------------|------------| @@ -352,15 +494,17 @@ Fetch client provides the quick access of History, collection and Environment va |SSL Check|fetch-client.SSLCheck|true|Enable Strict SSL Check for API Request| |History Limit|fetch-client.historyLimit|25|Number of items to be displayed in the History| |Time Out|fetch-client.timeOut|5 min|Request Timeout| -|Default Protocol|fetch-client.defaultProtocol|http|Which protocol to add with url (if url has no protocol)| +|Default Protocol|fetch-client.defaultProtocol|http|Which protocol to add with URL (if URL has no protocol)|

- + Fetch Client settings
## πŸš€ Tech Stack + Fetch Client is created with below tech stacks. + * Extension : [VS Code Extension API](https://code.visualstudio.com/api) * UI : [React JS](https://reactjs.org/), [TypeScript](https://www.typescriptlang.org/), [JavaScript](https://www.w3schools.com/js/), [CSS](https://www.w3schools.com/css/default.asp) * Editor : [Monaco Editor](https://microsoft.github.io/monaco-editor/) @@ -368,22 +512,29 @@ Fetch Client is created with below tech stacks. * Code Snippet Generation : [httpsnippet](https://github.com/Kong/httpsnippet/) ## πŸ–₯️ Running the extension locally for development + * Clone the [vscode-fetch-client](https://github.com/Ganesan-Chandran/vscode-fetch-client) repo. * Run `npm install` command to install dependencies. -* Press `F5` to open a extension developement window with `fetch-client` extension loaded. +* Press `F5` to open an extension development window with `fetch-client` extension loaded. ## πŸ”’ Privacy + * Fetch client **`DOES NOT`** collect any your personal or request data. -* Fetch client has no backend storage and all your data are stored **`LOCALLY`** on your computer. +* Fetch client has no back-end storage and all your data are stored **`LOCALLY`** on your computer. ## πŸ“ Changelog + See the [release notes](https://github.com/Ganesan-Chandran/vscode-fetch-client/blob/main/CHANGELOG.md) for the full set of changes. ## βœ’οΈ Author + [Ganesan Chandran](https://ganesan-chandran.github.io/) ## πŸ“œ License + See the [license](https://github.com/Ganesan-Chandran/vscode-fetch-client/blob/main/LICENSE) details. ## πŸ‘ Contribution -Feel free to submit a pull request if you find any bugs or new feature (To see a list of active issues/feature request, visit the [Issues section](https://github.com/Ganesan-Chandran/vscode-fetch-client/issues)). Please make sure all commits are properly documented. + +Feel free to submit a pull request if you find any bugs or new feature (To see a list of active issues/feature request, +visit the [Issues section](https://github.com/Ganesan-Chandran/vscode-fetch-client/issues)). Please make sure all commits are properly documented. diff --git a/dictionary.txt b/dictionary.txt new file mode 100644 index 0000000..28703f1 --- /dev/null +++ b/dictionary.txt @@ -0,0 +1,45 @@ +.env +auth +Auth +authorization +Authorization +Authorization +bool +Chandran +Changelog +Customization +customize +Customize +dateISO +dropdown +formdata +formurlencoded +Ganesan +GraphQL +guid +Http +isJson +JS +json +Json +JSON +notContains +num +OAuth +OAuth2 +Organize +Param +PostFetch +pre-requests +Pre-requests +rdate +repo +SSL +str +strnum +strnum +strspl +UI +url +VSCode +vscode-fetch-client diff --git a/images/collection-menu.png b/images/collection-menu.png new file mode 100644 index 0000000..94d20af Binary files /dev/null and b/images/collection-menu.png differ diff --git a/images/extension-settings-menu.png b/images/extension-settings-menu.png index 8dadaca..f39dd65 100644 Binary files a/images/extension-settings-menu.png and b/images/extension-settings-menu.png differ diff --git a/images/import-col-menu.png b/images/import-col-menu.png new file mode 100644 index 0000000..a4c5d3c Binary files /dev/null and b/images/import-col-menu.png differ diff --git a/images/logs-settings.png b/images/logs-settings.png new file mode 100644 index 0000000..894888c Binary files /dev/null and b/images/logs-settings.png differ diff --git a/images/logs.png b/images/logs.png new file mode 100644 index 0000000..25c28b7 Binary files /dev/null and b/images/logs.png differ diff --git a/images/prerequests.png b/images/prerequests.png new file mode 100644 index 0000000..22b56c2 Binary files /dev/null and b/images/prerequests.png differ diff --git a/images/setvar.png b/images/setvar.png index bbd7615..e56fb95 100644 Binary files a/images/setvar.png and b/images/setvar.png differ diff --git a/images/systemvariables.png b/images/systemvariables.png new file mode 100644 index 0000000..56c00d5 Binary files /dev/null and b/images/systemvariables.png differ diff --git a/images/test-menu.png b/images/test-menu.png new file mode 100644 index 0000000..89c05b3 Binary files /dev/null and b/images/test-menu.png differ diff --git a/images/workspace.png b/images/workspace.png new file mode 100644 index 0000000..b69936f Binary files /dev/null and b/images/workspace.png differ diff --git a/images/workspace1.png b/images/workspace1.png new file mode 100644 index 0000000..8a9a4d6 Binary files /dev/null and b/images/workspace1.png differ diff --git a/package-lock.json b/package-lock.json index 9ca02d9..a9c41a9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "fetch-client", - "version": "1.5.2", + "version": "1.6.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "fetch-client", - "version": "1.5.2", + "version": "1.6.0", "license": "MIT", "dependencies": { "aws4": "^1.11.0", diff --git a/package.json b/package.json index d236fb5..10abb71 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "fetch-client", "displayName": "Fetch Client", "description": "Rest API Client for VS Code which is used to test your API's within VS Code.", - "version": "1.5.2", + "version": "1.6.0", "publisher": "GanesanChandran", "author": { "name": "Ganesan Chandran " @@ -34,7 +34,14 @@ "api testing", "rest testing", "http", - "rest api" + "rest api", + "fetchclient", + "apiclient", + "restclient", + "httpclient", + "apitesting", + "resttesting", + "restapi" ], "license": "MIT", "homepage": "https://github.com/Ganesan-Chandran/vscode-fetch-client", @@ -74,14 +81,25 @@ }, { "command": "fetch-client.openSettings", - "title": "Extension Settings", + "title": "Fetch Client Settings", "category": "Fetch Client" }, { "command": "fetch-client.openErrorLog", "title": "View Error Log", "category": "Fetch Client" - } + }, + { + "command": "fetch-client.reloadData", + "title": "Reload", + "icon": "$(refresh)", + "category": "Fetch Client" + }, + { + "command": "fetch-client.documentation", + "title": "Documentation", + "category": "Fetch Client" + } ], "viewsContainers": { "activitybar": [ @@ -221,7 +239,7 @@ "type": "boolean", "default": false, "scope": "resource", - "markdownDescription": "Save all the data into the current workspace location", + "markdownDescription": "Save all the data into the `current workspace` location", "order": 12 }, "fetch-client.workspacePath": { @@ -250,7 +268,17 @@ "command": "fetch-client.openSettings", "when": "view == fetch-client.sideBar", "group": "group2@2" - } + }, + { + "command": "fetch-client.reloadData", + "when": "view == fetch-client.sideBar", + "group": "navigation" + }, + { + "command": "fetch-client.documentation", + "group": "group2@3", + "when": "view == fetch-client.sideBar" + } ], "commandPalette": [ { @@ -264,7 +292,15 @@ { "command": "fetch-client.openErrorLog", "when": "false" - } + }, + { + "command": "fetch-client.reloadData", + "when": "false" + }, + { + "command": "fetch-client.documentation", + "when": "false" + } ] } }, @@ -278,7 +314,10 @@ "pretest": "npm run compile-tests && npm run compile && npm run lint", "lint-check": "eslint src --ext .ts,.tsx", "lint-fix": "eslint src --ext .ts,.tsx --fix", - "pre-commit": "npm run eclint-check && npm run md-lint && npm run md-spellcheck", + "md-lint": "markdownlint *.md ./**/*.md ./**/**/*.md --ignore node_modules --ignore CHANGELOG.md", + "md-lint-fix": "markdownlint *.md ./**/*.md ./**/**/*.md --ignore node_modules --ignore CHANGELOG.md --fix", + "md-spellcheck": "spellchecker -f *.md ./**/*.md -d dictionary.txt --language en-GB", + "pre-commit": "npm run lint-check && npm run md-lint && npm run md-spellcheck", "test": "node ./out/test/runTest.js" }, "devDependencies": { diff --git a/src/extension.ts b/src/extension.ts index 92cf718..4800a99 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -18,6 +18,9 @@ import { pubSubTypes } from './utils/configuration'; import { collectionDBPath, cookieDBPath, historyDBPath, mainDBPath, variableDBPath } from "./utils/db/dbPaths"; import { getExtDbPath, setGlobalStorageUri } from './utils/db/getExtDbPath'; import { transferDbConfig } from './utils/db/transferDBConfig'; +import { GetAllCollections } from './utils/db/collectionDBUtil'; +import { GetAllHistory } from './utils/db/historyDBUtil'; +import { GetAllVariable } from './utils/db/varDBUtil'; export var pubSub: PubSub; export var vsCodeLogger: VSCodeLogger; @@ -59,7 +62,7 @@ export function OpenCurlUI() { } export function OpenColSettings(colId: string, folderId: string, name: string, type: string, varId: string) { - vscode.commands.executeCommand("fetch-client.addToCol", colId, folderId, name, "colsettings:" + type, varId); + vscode.commands.executeCommand("fetch-client.addToCol", colId, folderId, name, "colsettings@:@" + type, varId); } export function activate(context: vscode.ExtensionContext) { @@ -126,6 +129,16 @@ export function activate(context: vscode.ExtensionContext) { } }) ); + + context.subscriptions.push(vscode.commands.registerCommand('fetch-client.reloadData', () => { + GetAllCollections(sideBarProvider?.view?.webview); + GetAllHistory(sideBarProvider?.view); + GetAllVariable(sideBarProvider?.view?.webview); + })); + + context.subscriptions.push(vscode.commands.registerCommand('fetch-client.documentation', () => { + vscode.env.openExternal(vscode.Uri.parse('https://github.com/Ganesan-Chandran/vscode-fetch-client/wiki')); + })); } export function getStorageManager(): LocalStorageService { diff --git a/src/fetch-client-ui/components/Collection/AddTo/addTo.tsx b/src/fetch-client-ui/components/Collection/AddTo/addTo.tsx index 8bb274e..e7eda14 100644 --- a/src/fetch-client-ui/components/Collection/AddTo/addTo.tsx +++ b/src/fetch-client-ui/components/Collection/AddTo/addTo.tsx @@ -47,7 +47,7 @@ const AddToCollection = () => { }); vscode.postMessage({ type: requestTypes.getAllCollectionNameRequest, data: "addtocol" }); - let id = document.title.split(":")[1]; + let id = document.title.split("@:@")[1]; vscode.postMessage({ type: requestTypes.getHistoryItemRequest, data: id }); }, []); @@ -164,7 +164,7 @@ const AddToCollection = () => {
{history.method.toUpperCase()}
-
{history.url}
+
{history.url?.length > 50 ? history.url.substring(0, 50) + "..." : history.url}
{formatDate(history.createdTime)}
diff --git a/src/fetch-client-ui/components/Collection/AttachVariable/attachVariable.tsx b/src/fetch-client-ui/components/Collection/AttachVariable/attachVariable.tsx index 17da1a9..cc4f122 100644 --- a/src/fetch-client-ui/components/Collection/AttachVariable/attachVariable.tsx +++ b/src/fetch-client-ui/components/Collection/AttachVariable/attachVariable.tsx @@ -15,9 +15,9 @@ const AttachVariable = () => { const [isDone, setDone] = useState(false); useEffect(() => { - const id = document.title.split(":")[1]; + const id = document.title.split("@:@")[1]; setColId(id); - const name = document.title.split(":")[3]; + const name = document.title.split("@:@")[3]; setColName(name); window.addEventListener("message", (event) => { @@ -71,7 +71,7 @@ const AttachVariable = () => { - Selected Collection : + Selected Collection @@ -79,7 +79,7 @@ const AttachVariable = () => { - Variable : + Variable onSelectChange(e)} + /> Skip parent headers + + + + ); +}; \ No newline at end of file diff --git a/src/fetch-client-ui/components/RequestUI/OptionsPanel/Options/PreFetch/index.tsx b/src/fetch-client-ui/components/RequestUI/OptionsPanel/Options/PreFetch/index.tsx index 618fd65..dfd7f99 100644 --- a/src/fetch-client-ui/components/RequestUI/OptionsPanel/Options/PreFetch/index.tsx +++ b/src/fetch-client-ui/components/RequestUI/OptionsPanel/Options/PreFetch/index.tsx @@ -4,13 +4,18 @@ import { InitialTest } from "../../../redux/reducer"; import { IRootState } from "../../../../../reducer/combineReducer"; import { PreRequest } from "./preRequest"; import { useDispatch, useSelector } from "react-redux"; -import React from "react"; +import React, { useEffect } from "react"; import "./style.css"; -export const PreFetch = () => { +export interface IPreFecthProps { + settingsMode?: boolean; +} + +export const PreFetch = (props: IPreFecthProps) => { const dispatch = useDispatch(); const { preFetch } = useSelector((state: IRootState) => state.requestData); + const { skipParentPreFetch } = useSelector((state: IRootState) => state.reqSettings); function onAddReqClick() { let newPreReq: IRunRequest = { @@ -23,6 +28,18 @@ export const PreFetch = () => { dispatch(Actions.SetAddPreRequestAction(newPreReq)); }; + useEffect(() => { + if (preFetch?.requests?.length <= 0) { + let newPreReq: IRunRequest = { + reqId: "", + parentId: "", + colId: "", + order: preFetch && preFetch?.requests ? preFetch.requests.length + 1 : 1, + condition: JSON.parse(JSON.stringify(InitialTest)) + }; + dispatch(Actions.SetAddPreRequestAction(newPreReq)); + } + }, []); const makeRequests = (reqs: IRunRequest[]) => { return ( @@ -32,9 +49,36 @@ export const PreFetch = () => { ); }; + const isDisabled = () => { + return props.settingsMode ? preFetch?.requests?.length > 1 : preFetch?.requests?.length > 4; + }; + + function onSelectChange(evt: React.ChangeEvent) { + dispatch(Actions.SetSkipPreFetchAction(evt.currentTarget.checked)); + } + return (
-
* Max 5 request
+
+
+ {props?.settingsMode ? "* Max 2 request (It is recommended that each request does not contain any PreFetch requests. If there are any PreFetch requests, then they won't be executed.)" : "* Max 5 request"} +
+ +
+ {!props?.settingsMode ? +
+ +
+ : + <> + + } { makeRequests(preFetch?.requests) } diff --git a/src/fetch-client-ui/components/RequestUI/OptionsPanel/Options/PreFetch/preRequest.tsx b/src/fetch-client-ui/components/RequestUI/OptionsPanel/Options/PreFetch/preRequest.tsx index 7198630..079b665 100644 --- a/src/fetch-client-ui/components/RequestUI/OptionsPanel/Options/PreFetch/preRequest.tsx +++ b/src/fetch-client-ui/components/RequestUI/OptionsPanel/Options/PreFetch/preRequest.tsx @@ -1,13 +1,13 @@ -import { Actions } from "../../../redux"; -import { IColRequest, IRequestList, IRunRequest, ITest } from "../../../redux/types"; -import { IRootState } from "../../../../../reducer/combineReducer"; -import { preConditionActions, preConditions } from "./consts"; +import React, { useEffect, useState } from "react"; +import { useDispatch, useSelector } from "react-redux"; import { ReactComponent as BinLogo } from '../../../../../../../icons/bin.svg'; import { requestTypes, responseTypes } from "../../../../../../utils/configuration"; +import { IRootState } from "../../../../../reducer/combineReducer"; import { TextEditor } from "../../../../Common/TextEditor/TextEditor"; -import { useDispatch, useSelector } from "react-redux"; -import React, { useEffect, useState } from "react"; import vscode from "../../../../Common/vscodeAPI"; +import { Actions } from "../../../redux"; +import { IColRequest, IRequestList, IRunRequest, ITest } from "../../../redux/types"; +import { preConditionActions, preConditions } from "./consts"; import "./style.css"; export interface IPreRequestProps { diff --git a/src/fetch-client-ui/components/RequestUI/OptionsPanel/Options/PreFetch/style.css b/src/fetch-client-ui/components/RequestUI/OptionsPanel/Options/PreFetch/style.css index d72d90d..2a7b0af 100644 --- a/src/fetch-client-ui/components/RequestUI/OptionsPanel/Options/PreFetch/style.css +++ b/src/fetch-client-ui/components/RequestUI/OptionsPanel/Options/PreFetch/style.css @@ -1,87 +1,97 @@ -.preReq-container{ - display: grid; - padding: 10px 0 5px 0; +.preReq-container { + display: grid; + padding: 10px 0 5px 0; } + .preReq-panel { - padding: 3px 0px 2px 0; + padding: 3px 0px 2px 0; } .preReq-delete-panel { - float: right; + float: right; } .preReq-condition-panel { - display: flex; - padding: 3px 0 7px 0; + display: flex; + padding: 3px 0 7px 0; } .preReq-select { - padding: 2px 4px 4px 4px !important; - border : 1px solid !important; + padding: 2px 4px 4px 4px !important; + border: 1px solid !important; } .preReq-condition-param-panel { - width : 30%; - margin-right: 10px; + width: 30%; + margin-right: 10px; } .preReq-condition-param-panel .public-DraftEditorPlaceholder-inner { - padding: 2px 4px 4px 4px; + padding: 2px 4px 4px 4px; } .preReq-condition-param-panel .DraftEditor-editorContainer { - padding : 2px 4px 4px 4px; - border : var(--border-size) solid var(--border-color); - border-radius: 2px; + padding: 2px 4px 4px 4px; + border: var(--border-size) solid var(--border-color); + border-radius: 2px; } .preReq-condition-delete-panel { - display : flex; - align-items: center; + display: flex; + align-items: center; } .preReq-condition-delete-btn { - transform: scale(0.80); + transform: scale(0.80); } .preReq-col-select { - height : 30px; - outline : none; - border-radius : 3px; - background-color: var(--background-color); - color : var(--text-color); - width : 170px !important; + height: 30px; + outline: none; + border-radius: 3px; + background-color: var(--background-color); + color: var(--text-color); + width: 170px !important; } .preReq-col-select option { - background-color: var(--background-color); - color : var(--text-color); + background-color: var(--background-color); + color: var(--text-color); } .preReq-col-select:focus, .preReq-col-select:hover { - outline: none; + outline: none; } .preReq-col-select:invalid { - color: var(--input-unchecked); + color: var(--input-unchecked); } .preReq-col-select option[value=""][disabled] { - display: none; + display: none; } .preReq-field-panel { - margin-top: 3px + margin-top: 3px } .preReq-text-panel { - display: flex; - padding : 5px 5px 5px 0; - max-width: 100%; + display: flex; + padding: 5px 5px 5px 0; + max-width: 100%; } .max-req { float: left; color: red; + padding-bottom: 7px; +} + +fieldset { + border: 1px solid rgb(161 161 161) !important; } + +.request-prefetch-panel { + padding: 5px 0 10px 0; +} \ No newline at end of file diff --git a/src/fetch-client-ui/components/RequestUI/OptionsPanel/index.tsx b/src/fetch-client-ui/components/RequestUI/OptionsPanel/index.tsx index d8b672e..27d71c9 100644 --- a/src/fetch-client-ui/components/RequestUI/OptionsPanel/index.tsx +++ b/src/fetch-client-ui/components/RequestUI/OptionsPanel/index.tsx @@ -1,17 +1,16 @@ -import { allAuthTypes, basicAuthTypes } from "./Options/Auth/consts"; -import { AuthPanel } from "./Options/Auth"; -import { Body } from "./Options/Body"; -import { HeadersPanel } from "./Options/Headers"; +import React, { useState } from "react"; +import { useSelector } from "react-redux"; import { IRootState } from "../../../reducer/combineReducer"; import { OptionsTab } from "./OptionTab"; +import { AuthPanel } from "./Options/Auth"; +import { allAuthTypes, basicAuthTypes } from "./Options/Auth/consts"; +import { Body } from "./Options/Body"; +import { RequestHeadersPanel } from "./Options/Headers/requestHeaders"; import { PostFetch } from "./Options/PostFetch"; import { PreFetch } from "./Options/PreFetch"; import { QueryParams } from "./Options/QueryParams"; -import { requestOptions } from "./consts"; import { Settings } from "./Options/Settings"; -import { useSelector } from "react-redux"; -import { useState } from "react"; -import React from "react"; +import { requestOptions } from "./consts"; import "./style.css"; export const OptionsPanel = () => { @@ -20,7 +19,7 @@ export const OptionsPanel = () => { const { colId } = useSelector((state: IRootState) => state.reqColData); const { runItem } = useSelector((state: IRootState) => state.uiData); - const [selectedTab, setSelectedTab] = useState(runItem ? "tests" : "params"); + const [selectedTab, setSelectedTab] = useState(runItem ? "postFetch" : "params"); const renderOptionsUI = (tab: string) => { switch (tab) { @@ -29,7 +28,7 @@ export const OptionsPanel = () => { case 'authorization': return ; case 'headers': - return ; + return ; case 'body': return ; case 'settings': diff --git a/src/fetch-client-ui/components/RequestUI/OptionsPanel/style.css b/src/fetch-client-ui/components/RequestUI/OptionsPanel/style.css index 5e5caaa..4a960d8 100644 --- a/src/fetch-client-ui/components/RequestUI/OptionsPanel/style.css +++ b/src/fetch-client-ui/components/RequestUI/OptionsPanel/style.css @@ -59,4 +59,16 @@ .settings-menu-clicked path { fill: var(--button-background-color); -} \ No newline at end of file +} + +.request-header-panel { + padding-top: 10px; +} + +.request-header-panel-text{ + display: flex; +} + +.request-header-panel-option{ + margin-right: 5px; +} diff --git a/src/fetch-client-ui/components/RequestUI/RequestPanel/common.ts b/src/fetch-client-ui/components/RequestUI/RequestPanel/common.ts new file mode 100644 index 0000000..6da8269 --- /dev/null +++ b/src/fetch-client-ui/components/RequestUI/RequestPanel/common.ts @@ -0,0 +1,28 @@ +import { Dispatch } from "redux"; +import { v4 as uuidv4 } from 'uuid'; +import { requestTypes } from "../../../../utils/configuration"; +import { formatDate } from "../../../../utils/helper"; +import { GetDataFromHTML, notesMaxLimit } from "../../Common/helper"; +import vscode from "../../Common/vscodeAPI"; +import { ResponseActions } from "../../ResponseUI/redux"; +import { ISettings, IVariable } from "../../SideBar/redux/types"; +import { Actions } from "../redux"; +import { IReqSettings, IRequestModel } from "../redux/types"; + +export const SendRequest = (dispatch: Dispatch, newReq: boolean, colId: string, requestData: IRequestModel, selectedVariable: IVariable, parentSettings: ISettings, reqSettings: IReqSettings) => { + dispatch(ResponseActions.SetResponseLoadingAction(true)); + + let reqData = { ...requestData }; + + if (newReq) { + reqData.id = uuidv4(); + reqData.name = reqData.url.trim(); + reqData.createdTime = formatDate(); + dispatch(Actions.SetRequestAction(reqData)); + } + + const data = GetDataFromHTML(reqData.notes); + reqData.notes = data.length > notesMaxLimit ? "" : reqData.notes; + + vscode.postMessage({ type: requestTypes.apiRequest, data: { reqData: reqData, isNew: newReq, variableData: selectedVariable, settings: parentSettings, colId: colId, reqSettings: reqSettings } }); +}; diff --git a/src/fetch-client-ui/components/RequestUI/RequestPanel/index.tsx b/src/fetch-client-ui/components/RequestUI/RequestPanel/index.tsx index a411fe3..626df08 100644 --- a/src/fetch-client-ui/components/RequestUI/RequestPanel/index.tsx +++ b/src/fetch-client-ui/components/RequestUI/RequestPanel/index.tsx @@ -1,34 +1,35 @@ import React, { useEffect, useState } from 'react'; import { useDispatch, useSelector } from "react-redux"; import { v4 as uuidv4 } from 'uuid'; +import { requestTypes } from '../../../../utils/configuration'; +import { formatDate } from '../../../../utils/helper'; import { IRootState } from "../../../reducer/combineReducer"; +import { GetDataFromHTML, GetDomainName, notesMaxLimit } from '../../Common/helper'; +import { ITableData } from '../../Common/Table/types'; +import { TextEditor } from '../../Common/TextEditor/TextEditor'; +import vscode from '../../Common/vscodeAPI'; +import { CookiesActions } from '../../Cookies/redux'; +import { ICookie } from '../../Cookies/redux/types'; import { ResponseActions } from "../../ResponseUI/redux"; +import { executeTests, setVariable } from '../../TestUI/TestPanel/helper'; import { Actions } from "../redux"; import { MethodType } from "../redux/types"; +import { SendRequest } from './common'; import { requestMethods } from "./consts"; -import vscode from '../../Common/vscodeAPI'; import "./style.css"; -import { requestTypes } from '../../../../utils/configuration'; -import { executeTests, setVariable } from '../../TestUI/TestPanel/helper'; -import { formatDate } from '../../../../utils/helper'; -import { GetDataFromHTML, GetDomainName, notesMaxLimit } from '../../Common/helper'; -import { TextEditor } from '../../Common/TextEditor/TextEditor'; -import { ICookie } from '../../Cookies/redux/types'; -import { CookiesActions } from '../../Cookies/redux'; -import { ITableData } from '../../Common/Table/types'; export const RequestPanel = () => { const dispatch = useDispatch(); const [newReq, setNewReq] = useState(false); - const [forceUpdate, setForceUpdate] = useState(false); const requestData = useSelector((state: IRootState) => state.requestData); const responseData = useSelector((state: IRootState) => state.responseData); const { selectedVariable } = useSelector((state: IRootState) => state.variableData); const { cookies } = useSelector((state: IRootState) => state.cookieData); const { parentSettings, colId } = useSelector((state: IRootState) => state.reqColData); + const reqSettings = useSelector((state: IRootState) => state.reqSettings); const selectRequestMethod = (evt: React.ChangeEvent): void => { dispatch(Actions.SetRequestMethodAction(evt.target.value as MethodType)); @@ -108,21 +109,7 @@ export const RequestPanel = () => { }, [cookies]); const onSendClick = () => { - dispatch(ResponseActions.SetResponseLoadingAction(true)); - - let reqData = { ...requestData }; - - if (newReq) { - reqData.id = uuidv4(); - reqData.name = reqData.url.trim(); - reqData.createdTime = formatDate(); - dispatch(Actions.SetRequestAction(reqData)); - } - - const data = GetDataFromHTML(reqData.notes); - reqData.notes = data.length > notesMaxLimit ? "" : reqData.notes; - - vscode.postMessage({ type: requestTypes.apiRequest, data: { reqData: reqData, isNew: newReq, variableData: selectedVariable?.data, settings: parentSettings, colId: colId } }); + SendRequest(dispatch, newReq, colId, requestData, selectedVariable, parentSettings, reqSettings); setNewReq(false); }; @@ -170,7 +157,7 @@ export const RequestPanel = () => { }, [responseData.cookies]); useEffect(() => { - let reqId = document.title.split(":")[0]; + let reqId = document.title.split("@:@")[0]; if (reqId === "undefined") { setNewReq(true); } @@ -215,7 +202,7 @@ export const RequestPanel = () => {
- { + { selectedVariable.id && item.key)} placeholder="Enter request URL" diff --git a/src/fetch-client-ui/components/RequestUI/redux/actions.ts b/src/fetch-client-ui/components/RequestUI/redux/actions.ts index 9a3ee19..e4b4185 100644 --- a/src/fetch-client-ui/components/RequestUI/redux/actions.ts +++ b/src/fetch-client-ui/components/RequestUI/redux/actions.ts @@ -6,7 +6,10 @@ import { FETCH_CLIENT_SET_REQ_BINARY_DATA, FETCH_CLIENT_SET_REQ_BODY, FETCH_CLIENT_SET_REQ_COL_DETAILS, FETCH_CLIENT_SET_REQ_FORM_DATA_BODY, FETCH_CLIENT_SET_REQ_HEADERS, FETCH_CLIENT_SET_REQ_ID, FETCH_CLIENT_SET_REQ_METHOD, FETCH_CLIENT_SET_REQ_PARAMS, FETCH_CLIENT_SET_REQ_PARENT_SETTINGS, FETCH_CLIENT_SET_REQ_RAW, FETCH_CLIENT_SET_REQ_RAW_LANG, FETCH_CLIENT_SET_REQ_RESET_BODY, FETCH_CLIENT_SET_REQ_URL, FETCH_CLIENT_SET_SET_VAR, - FETCH_CLIENT_SET_TEST, IAuth, IBodyData, ICollection, IColRequest, IRequestModel, IRunRequest, ISetVar, ITest, MethodType, RequestActionTypes + FETCH_CLIENT_SET_TEST, IAuth, IBodyData, ICollection, IColRequest, IRequestModel, IRunRequest, ISetVar, ITest, MethodType, RequestActionTypes, + FETCH_CLIENT_SET_PREFETCH, IPreFetch, + FETCH_CLIENT_SET_SKIP_PARENT_PREFETCH, + FETCH_CLIENT_SET_SKIP_PARENT_HEADERS } from "./types"; export const SetRequestAction = (value: IRequestModel): RequestActionTypes => { @@ -253,3 +256,31 @@ export const SetSelectedReqAction = (reqId: string, reqIndex: number, parentId: } }; }; + +export const SetPreFetchAction = (value: IPreFetch): RequestActionTypes => { + return { + type: FETCH_CLIENT_SET_PREFETCH, + payload: { + preFetch: value + } + }; +}; + + +export const SetSkipPreFetchAction = (value: boolean): RequestActionTypes => { + return { + type: FETCH_CLIENT_SET_SKIP_PARENT_PREFETCH, + payload: { + skip: value + } + }; +}; + +export const SetSkipHeadersAction = (value: boolean): RequestActionTypes => { + return { + type: FETCH_CLIENT_SET_SKIP_PARENT_HEADERS, + payload: { + skip: value + } + }; +}; diff --git a/src/fetch-client-ui/components/RequestUI/redux/reducer.ts b/src/fetch-client-ui/components/RequestUI/redux/reducer.ts index 383a336..3740f34 100644 --- a/src/fetch-client-ui/components/RequestUI/redux/reducer.ts +++ b/src/fetch-client-ui/components/RequestUI/redux/reducer.ts @@ -4,7 +4,7 @@ import { requestBodyRaw } from '../OptionsPanel/Options/Body/consts'; import { ClientAuth, FETCH_CLIENT_SET_ADD_PREREQUEST, FETCH_CLIENT_SET_COL_ID, FETCH_CLIENT_SET_DELETE_PRECONDITION, FETCH_CLIENT_SET_DELETE_PREREQUEST, - FETCH_CLIENT_SET_NOTES, FETCH_CLIENT_SET_OAUTH_TOKEN, FETCH_CLIENT_SET_PRECONDITION, FETCH_CLIENT_SET_REQ, + FETCH_CLIENT_SET_NOTES, FETCH_CLIENT_SET_OAUTH_TOKEN, FETCH_CLIENT_SET_PRECONDITION, FETCH_CLIENT_SET_PREFETCH, FETCH_CLIENT_SET_REQ, FETCH_CLIENT_SET_REQ_AUTH, FETCH_CLIENT_SET_REQ_BINARY_DATA, FETCH_CLIENT_SET_REQ_BODY, FETCH_CLIENT_SET_REQ_FORM_DATA_BODY, FETCH_CLIENT_SET_REQ_HEADERS, FETCH_CLIENT_SET_REQ_ID, FETCH_CLIENT_SET_REQ_METHOD, FETCH_CLIENT_SET_REQ_PARAMS, FETCH_CLIENT_SET_REQ_RAW, FETCH_CLIENT_SET_REQ_RAW_LANG, FETCH_CLIENT_SET_REQ_RESET_BODY, FETCH_CLIENT_SET_REQ_URL, FETCH_CLIENT_SET_SET_VAR, FETCH_CLIENT_SET_TEST, @@ -325,6 +325,12 @@ export const RequestReducer: (state?: IRequestModel, } }; } + case FETCH_CLIENT_SET_PREFETCH: { + return { + ...state, + preFetch: action.payload.preFetch + }; + } default: { return state; } @@ -375,16 +381,30 @@ function deleteRequest(requests: IRunRequest[], reqIndex: number): IRunRequest[] return localRequests; } +// function updateURL(url: string, params: ITableData[]): string { +// let searchParams = new URLSearchParams(); + +// params.forEach((param: ITableData, index) => { +// if (param.key.trim() && param.isChecked && !param.isFixed) { +// searchParams.append(param.key.trim(), param.value.trim()); +// } +// }); + +// let combineUrl = searchParams.toString().length > 0 ? decodeURIComponent(url.split("?")[0] + "?" + searchParams.toString()) : decodeURIComponent(url.split("?")[0]); + +// return combineUrl; +// } + function updateURL(url: string, params: ITableData[]): string { - let searchParams = new URLSearchParams(); + let searchParams: string = ""; - params.forEach((param: ITableData, index) => { + params.forEach((param: ITableData) => { if (param.key.trim() && param.isChecked && !param.isFixed) { - searchParams.append(param.key.trim(), param.value.trim()); + searchParams = (searchParams ? (searchParams + "&") : searchParams) + param.key.trim() + (param.value ? "=" + param.value.trim() : ""); } }); - let combineUrl = searchParams.toString().length > 0 ? decodeURIComponent(url.split("?")[0] + "?" + searchParams.toString()) : decodeURIComponent(url.split("?")[0]); + let combineUrl = searchParams ? url.split("?")[0] + "?" + searchParams : url.split("?")[0]; return combineUrl; } @@ -403,7 +423,7 @@ function updateQueryParams(url: string, params: ITableData[]) { key: p[0] ? p[0].trim() : "", value: p[1] ? p[1].trim() : "", }; - queryParams.splice(params.length === 0 ? 0 : params.length - 1, 0, queryParam); + queryParams.splice(queryParams.length === 0 ? 0 : queryParams.length, 0, queryParam); } } } diff --git a/src/fetch-client-ui/components/RequestUI/redux/reqSettingsReducer.ts b/src/fetch-client-ui/components/RequestUI/redux/reqSettingsReducer.ts new file mode 100644 index 0000000..b55ede0 --- /dev/null +++ b/src/fetch-client-ui/components/RequestUI/redux/reqSettingsReducer.ts @@ -0,0 +1,29 @@ +import { FETCH_CLIENT_SET_SKIP_PARENT_HEADERS, FETCH_CLIENT_SET_SKIP_PARENT_PREFETCH, IReqSettings, RequestActionTypes } from "./types"; + +export const InitialState: IReqSettings = { + skipParentHeaders: false, + skipParentPreFetch: false +}; + +export const ReqSettingsReducer: (state?: IReqSettings, + action?: RequestActionTypes) => IReqSettings = + (state: IReqSettings = InitialState, + action: RequestActionTypes = {} as RequestActionTypes): IReqSettings => { + switch (action.type) { + case FETCH_CLIENT_SET_SKIP_PARENT_PREFETCH: { + return { + ...state, + skipParentPreFetch: action.payload.skip + }; + } + case FETCH_CLIENT_SET_SKIP_PARENT_HEADERS: { + return { + ...state, + skipParentHeaders: action.payload.skip + }; + } + default: { + return state; + } + } + }; diff --git a/src/fetch-client-ui/components/RequestUI/redux/types.ts b/src/fetch-client-ui/components/RequestUI/redux/types.ts index 913a05e..e3b80fb 100644 --- a/src/fetch-client-ui/components/RequestUI/redux/types.ts +++ b/src/fetch-client-ui/components/RequestUI/redux/types.ts @@ -139,6 +139,11 @@ export interface IReqColModel { colRequestList: IColRequest[] } +export interface IReqSettings { + skipParentHeaders: boolean; + skipParentPreFetch: boolean; +} + export const FETCH_CLIENT_SET_REQ_URL: "FETCH_CLIENT_SET_REQ_URL" = "FETCH_CLIENT_SET_REQ_URL"; export const FETCH_CLIENT_SET_REQ_METHOD: "FETCH_CLIENT_SET_REQ_METHOD" = "FETCH_CLIENT_SET_REQ_METHOD"; export const FETCH_CLIENT_SET_REQ_PARAMS: "FETCH_CLIENT_SET_REQ_PARAMS" = "FETCH_CLIENT_SET_REQ_PARAMS"; @@ -165,6 +170,9 @@ export const FETCH_CLIENT_SET_COLLECTION_LIST: "FETCH_CLIENT_SET_COLLECTION_LIST export const FETCH_CLIENT_SET_COL_REQUEST_LIST: "FETCH_CLIENT_SET_COL_REQUEST_LIST" = "FETCH_CLIENT_SET_COL_REQUEST_LIST"; export const FETCH_CLIENT_SET_COL_ID: "FETCH_CLIENT_SET_COL_ID" = "FETCH_CLIENT_SET_COL_ID"; export const FETCH_CLIENT_SET_REQ_ID: "FETCH_CLIENT_SET_REQ_ID" = "FETCH_CLIENT_SET_REQ_ID"; +export const FETCH_CLIENT_SET_PREFETCH: "FETCH_CLIENT_SET_PREFETCH" = "FETCH_CLIENT_SET_PREFETCH"; +export const FETCH_CLIENT_SET_SKIP_PARENT_PREFETCH: "FETCH_CLIENT_SET_SKIP_PARENT_PREFETCH" = "FETCH_CLIENT_SET_SKIP_PARENT_PREFETCH"; +export const FETCH_CLIENT_SET_SKIP_PARENT_HEADERS: "FETCH_CLIENT_SET_SKIP_PARENT_HEADERS" = "FETCH_CLIENT_SET_SKIP_PARENT_HEADERS"; export interface ISetTest { type: typeof FETCH_CLIENT_SET_TEST; @@ -352,11 +360,32 @@ export interface ISetSelectedRequest { payload: { reqId: string; index: number; - parentId:string; + parentId: string; + } +} + +export interface ISetPreFetch { + type: typeof FETCH_CLIENT_SET_PREFETCH; + payload: { + preFetch: IPreFetch; + } +} + +export interface ISetSkipPreFetch { + type: typeof FETCH_CLIENT_SET_SKIP_PARENT_PREFETCH; + payload: { + skip: boolean; + } +} + +export interface ISetSkipHeaders { + type: typeof FETCH_CLIENT_SET_SKIP_PARENT_HEADERS + payload: { + skip: boolean; } } export type RequestActionTypes = | ISetURL | ISetMethod | ISetParams | ISetAuth | ISetHeaders | ISetBody | ISetRequest | ISetTest | ISetRawLang | ISetResetBody | ISetRawValue | ISetBinaryData | ISetNotes | ISetAddVar | ISetReqColDetails | ISetReqParentSettings | ISetFormDataBody | ISetOAuthToken | ISetPreCondition | ISetAddPreRequest | ISetDeletePreRequest | ISetDeletePreCondition | ISetCollectionList | ISetColRequestList | - ISetSelectedCol | ISetSelectedRequest; \ No newline at end of file + ISetSelectedCol | ISetSelectedRequest | ISetPreFetch | ISetSkipPreFetch | ISetSkipHeaders; \ No newline at end of file diff --git a/src/fetch-client-ui/components/SideBar/Collection/index.tsx b/src/fetch-client-ui/components/SideBar/Collection/index.tsx index 2c4090f..69deac8 100644 --- a/src/fetch-client-ui/components/SideBar/Collection/index.tsx +++ b/src/fetch-client-ui/components/SideBar/Collection/index.tsx @@ -1,19 +1,19 @@ import React, { useEffect, useRef, useState } from "react"; -import { ReactComponent as DotsLogo } from '../../../../../icons/dots.svg'; import { useSelector } from "react-redux"; +import { v4 as uuidv4 } from 'uuid'; +import { ReactComponent as DotsLogo } from '../../../../../icons/dots.svg'; import { requestTypes, responseTypes } from "../../../../utils/configuration"; +import { formatDate } from "../../../../utils/helper"; import { IRootState } from "../../../reducer/combineReducer"; +import { SettingsType } from "../../Collection/consts"; +import { getColFolDotMenu, getPlusIconSVG } from "../../Common/icons"; import vscode from "../../Common/vscodeAPI"; +import { InitialState } from "../../RequestUI/redux/reducer"; +import { IRequestModel } from "../../RequestUI/redux/types"; +import { InitialSettings } from "../redux/reducer"; import { ICollections, IFolder, IHistory } from "../redux/types"; import { getDays, getMethodClassName, getMethodName, isFolder } from "../util"; -import { v4 as uuidv4 } from 'uuid'; -import { formatDate } from "../../../../utils/helper"; -import { IRequestModel } from "../../RequestUI/redux/types"; -import { InitialState } from "../../RequestUI/redux/reducer"; import "./style.css"; -import { SettingsType } from "../../Collection/consts"; -import { InitialSettings } from "../redux/reducer"; -import { getColFolDotMenu, getPlusIconSVG } from "../../Common/icons"; export interface ICollectionProps { filterCondition: string; @@ -260,6 +260,15 @@ export const CollectionBar = (props: ICollectionProps) => { vscode.postMessage({ type: requestTypes.openHistoryItemRequest, data: { colId: colId, folderId: folderId, id: itemId, name: name, varId: variableId, isNewTab: isNewTab } }); } + function onRunClick(evt: React.MouseEvent, colId: string, folderId: string, itemId: string, name: string, variableId: string) { + evt.preventDefault(); + evt.stopPropagation(); + setSelectedItem(itemId); + vscode.postMessage({ type: requestTypes.openAndRunItemRequest, data: { colId: colId, folderId: folderId, id: itemId, name: name, varId: variableId, isNewTab: false } }); + setCurrentIndex(""); + setCurrentHeadIndex(""); + } + function findData(source: any, dest: any) { let folders = source.data.filter((item: any) => item.data !== undefined); let histories = source.data.filter((item: any) => item.data === undefined); @@ -475,6 +484,9 @@ export const CollectionBar = (props: ICollectionProps) => { { e.stopPropagation(); e.preventDefault(); }} onClick={(e) => openMoreMenu(e, listItem.id, true)} />
+ + +
@@ -554,6 +566,7 @@ export const CollectionBar = (props: ICollectionProps) => {
+
diff --git a/src/fetch-client-ui/components/SideBar/History/index.tsx b/src/fetch-client-ui/components/SideBar/History/index.tsx index 9c25642..bbf2b9d 100644 --- a/src/fetch-client-ui/components/SideBar/History/index.tsx +++ b/src/fetch-client-ui/components/SideBar/History/index.tsx @@ -120,6 +120,14 @@ export const HistoryBar = (props: IHistoryProps) => { openContextMenu(index); } + function onRunClick(evt: React.MouseEvent, itemId: string, name: string) { + evt.preventDefault(); + evt.stopPropagation(); + setSelectedItem(itemId); + vscode.postMessage({ type: requestTypes.openAndRunItemRequest, data: { id: itemId, name: name, isNewTab: false } }); + setCurrentIndex(-1); + } + function getActivityBody() { if (props.filterCondition) { return ( @@ -163,6 +171,7 @@ export const HistoryBar = (props: IHistoryProps) => {
+
diff --git a/src/fetch-client-ui/components/SideBar/index.tsx b/src/fetch-client-ui/components/SideBar/index.tsx index cdb0020..d6901f1 100644 --- a/src/fetch-client-ui/components/SideBar/index.tsx +++ b/src/fetch-client-ui/components/SideBar/index.tsx @@ -23,7 +23,13 @@ const SideBar = () => { const [isColLoading, setColLoading] = useState(true); const [isVarLoading, setVarLoading] = useState(true); const [isViewLogOpen, setViewLogOpen] = useState(false); - const [selectedItem, setSelectedItem] = useState({ colId: "", foldId: "", itemId: "", }); + const [selectedItem, _setSelectedItem] = useState({ colId: "", foldId: "", itemId: "", }); + + const refSelectedItem = useRef(selectedItem); + const setSelectedItem = (data: { colId: string; foldId: string; itemId: string; }) => { + refSelectedItem.current = data; + _setSelectedItem(refSelectedItem.current); + }; const wrapperRef = useRef(null); @@ -141,6 +147,14 @@ const SideBar = () => { foldId: event.data.folId, itemId: event.data.id }); + } else if (event.data && event.data.type === requestTypes.closeItemRequest) { + if (event.data.id && refSelectedItem.current.itemId === event.data.id) { + setSelectedItem({ + colId: "", + foldId: "", + itemId: "" + }); + } } else if (event.data && event.data.type === responseTypes.themeResponse) { dispatch(UIActions.SetThemeAction(event.data.theme)); } else if (event.data && event.data.type === pubSubTypes.themeChanged) { diff --git a/src/fetch-client-ui/components/SideBar/redux/reducer.ts b/src/fetch-client-ui/components/SideBar/redux/reducer.ts index 54488f2..891a171 100644 --- a/src/fetch-client-ui/components/SideBar/redux/reducer.ts +++ b/src/fetch-client-ui/components/SideBar/redux/reducer.ts @@ -1,4 +1,4 @@ -import { InitialAuth } from "../../RequestUI/redux/reducer"; +import { InitialAuth, InitialPreFetch, InitialRequestHeaders } from "../../RequestUI/redux/reducer"; import { isFolder } from "../util"; import { FETCH_CLIENT_SET_ACTIVE_INACTIVE_VARIABLE, FETCH_CLIENT_SET_ATTACH_DETACH_VARIABLE, FETCH_CLIENT_SET_CLEAR_COLLECTION, @@ -15,7 +15,9 @@ import { export const InitialSettings: ISettings = { - auth: InitialAuth + auth: InitialAuth, + preFetch: InitialPreFetch, + headers: InitialRequestHeaders }; export const InitialState: ISideBarModel = { diff --git a/src/fetch-client-ui/components/SideBar/redux/types.ts b/src/fetch-client-ui/components/SideBar/redux/types.ts index 5231fbb..4c637e9 100644 --- a/src/fetch-client-ui/components/SideBar/redux/types.ts +++ b/src/fetch-client-ui/components/SideBar/redux/types.ts @@ -1,5 +1,5 @@ import { ITableData } from "../../Common/Table/types"; -import { IAuth } from "../../RequestUI/redux/types"; +import { IAuth, IPreFetch } from "../../RequestUI/redux/types"; export interface IHistory { id: string; @@ -11,6 +11,8 @@ export interface IHistory { export interface ISettings { auth: IAuth; + preFetch?: IPreFetch; + headers?: ITableData[]; } export interface ICollections { diff --git a/src/fetch-client-ui/components/SideBar/style.css b/src/fetch-client-ui/components/SideBar/style.css index f2be5a2..83dd13b 100644 --- a/src/fetch-client-ui/components/SideBar/style.css +++ b/src/fetch-client-ui/components/SideBar/style.css @@ -7,6 +7,10 @@ cursor : pointer; } +.sidebar-tab-menu-settings { + padding : 10px 20px 10px 20px; +} + .selected { border-bottom: 2.5px solid var(--button-background-color) !important; } diff --git a/src/fetch-client-ui/components/TestUI/TestPanel/helper.ts b/src/fetch-client-ui/components/TestUI/TestPanel/helper.ts index 6330d05..12ad43f 100644 --- a/src/fetch-client-ui/components/TestUI/TestPanel/helper.ts +++ b/src/fetch-client-ui/components/TestUI/TestPanel/helper.ts @@ -1,5 +1,5 @@ /* eslint-disable eqeqeq */ -import { replaceDataWithVariable, replaceValueWithVariable } from "../../../../utils/helper"; +import { replaceDataWithVariable } from "../../../../utils/helper"; import { ITableData } from "../../Common/Table/types"; import { ISetVar, ITest } from "../../RequestUI/redux/types"; import { IReponseModel, ITestResult } from "../../ResponseUI/redux/types"; diff --git a/src/fetch-client-ui/components/Variables/index.tsx b/src/fetch-client-ui/components/Variables/index.tsx index 4112fe4..2565d09 100644 --- a/src/fetch-client-ui/components/Variables/index.tsx +++ b/src/fetch-client-ui/components/Variables/index.tsx @@ -82,7 +82,7 @@ const Variables = (props: IVariableProps) => { } }); - let id = document.title.split(":")[1]; + let id = document.title.split("@:@")[1]; if (id !== "undefined") { vscode.postMessage({ type: requestTypes.getVariableItemRequest, data: { id: id, isGlobal: false } }); setNew(false); diff --git a/src/fetch-client-ui/reducer/combineReducer.ts b/src/fetch-client-ui/reducer/combineReducer.ts index b213974..c748647 100644 --- a/src/fetch-client-ui/reducer/combineReducer.ts +++ b/src/fetch-client-ui/reducer/combineReducer.ts @@ -5,13 +5,14 @@ import { UIReducer } from "../components/MainUI/redux/reducer"; import { ICommonConfig } from "../components/MainUI/redux/types"; import { ReqColReducer } from "../components/RequestUI/redux/colReducer"; import { RequestReducer } from "../components/RequestUI/redux/reducer"; -import { IReqColModel, IRequestModel } from "../components/RequestUI/redux/types"; +import { IReqColModel, IReqSettings, IRequestModel } from "../components/RequestUI/redux/types"; import { ResponseReducer } from "../components/ResponseUI/redux"; import { IReponseModel } from "../components/ResponseUI/redux/types"; import { SideBarReducer } from "../components/SideBar/redux"; import { ISideBarModel } from "../components/SideBar/redux/types"; import { VariableReducer } from "../components/Variables/redux/reducer"; import { IVariableModel } from "../components/Variables/redux/types"; +import { ReqSettingsReducer } from "../components/RequestUI/redux/reqSettingsReducer"; export interface IRootState { requestData: IRequestModel, @@ -20,7 +21,8 @@ export interface IRootState { sideBarData: ISideBarModel, variableData: IVariableModel, cookieData: ICookiesModel, - reqColData: IReqColModel + reqColData: IReqColModel, + reqSettings: IReqSettings } const createRootReducer: () => Reducer = @@ -31,7 +33,8 @@ const createRootReducer: () => Reducer = sideBarData: SideBarReducer, variableData: VariableReducer, cookieData: CookieReducer, - reqColData: ReqColReducer + reqColData: ReqColReducer, + reqSettings: ReqSettingsReducer }); export default createRootReducer; \ No newline at end of file diff --git a/src/utils/ImportDataValidator.ts b/src/utils/ImportDataValidator.ts deleted file mode 100644 index 3b5b764..0000000 --- a/src/utils/ImportDataValidator.ts +++ /dev/null @@ -1,1277 +0,0 @@ -// Stores the currently-being-typechecked object for error messages. -let obj: any = null; -export class FetchClientDataProxy { - public readonly app: string; - public readonly id: string; - public readonly name: string; - public readonly version: string; - public readonly type: string; - public readonly createdTime: string; - public readonly exportedDate: string; - public readonly data: DataEntityProxy[] | null; - public static Parse(d: string): FetchClientDataProxy { - return FetchClientDataProxy.Create(JSON.parse(d)); - } - public static Create(d: any, field: string = 'root'): FetchClientDataProxy { - if (!field) { - obj = d; - field = "root"; - } - if (d === null || d === undefined) { - throwNull2NonNull(field, d); - } else if (typeof(d) !== 'object') { - throwNotObject(field, d, false); - } else if (Array.isArray(d)) { - throwIsArray(field, d, false); - } - checkString(d.app, false, field + ".app"); - checkStringValue(d.app, field + ".app", "Fetch Client"); - checkString(d.id, false, field + ".id"); - checkString(d.name, false, field + ".name"); - checkString(d.version, false, field + ".version"); - checkString(d.type, false, field + ".type"); - checkStringValue(d.type, field + ".type", "collections"); - checkString(d.createdTime, false, field + ".createdTime"); - checkString(d.exportedDate, false, field + ".exportedDate"); - checkArray(d.data, field + ".data"); - if (d.data) { - for (let i = 0; i < d.data.length; i++) { - d.data[i] = DataEntityProxy.Create(d.data[i], field + ".data" + "[" + i + "]"); - } - } - if (d.data === undefined) { - d.data = null; - } - return new FetchClientDataProxy(d); - } - private constructor(d: any) { - this.app = d.app; - this.id = d.id; - this.name = d.name; - this.version = d.version; - this.type = d.type; - this.createdTime = d.createdTime; - this.exportedDate = d.exportedDate; - this.data = d.data; - } -} - -export class DataEntityProxy { - public readonly id: string; - public readonly name: string; - public readonly type: string | null; - public readonly createdTime: string; - public readonly data: DataEntity1Proxy[] | null; - public readonly settings: SettingsProxy | null; - public readonly url: string | null; - public readonly method: string | null; - public readonly params: ParamsEntityOrHeadersEntityOrFormdataEntityOrUrlencodedEntityProxy[] | null; - public readonly auth: AuthProxy | null; - public readonly headers: ParamsEntityOrHeadersEntityOrFormdataEntityOrUrlencodedEntityProxy[] | null; - public readonly body: BodyProxy | null; - public readonly tests: TestsEntityProxy[] | null; - public readonly setvar: SetvarEntityProxy[] | null; - public readonly notes: string | null; - public static Parse(d: string): DataEntityProxy { - return DataEntityProxy.Create(JSON.parse(d)); - } - public static Create(d: any, field: string = 'root'): DataEntityProxy { - if (!field) { - obj = d; - field = "root"; - } - if (d === null || d === undefined) { - throwNull2NonNull(field, d); - } else if (typeof(d) !== 'object') { - throwNotObject(field, d, false); - } else if (Array.isArray(d)) { - throwIsArray(field, d, false); - } - checkString(d.id, false, field + ".id"); - checkString(d.name, false, field + ".name"); - checkString(d.type, true, field + ".type"); - if (d.type === undefined) { - d.type = null; - } - checkString(d.createdTime, false, field + ".createdTime"); - checkArray(d.data, field + ".data"); - if (d.data) { - for (let i = 0; i < d.data.length; i++) { - d.data[i] = DataEntity1Proxy.Create(d.data[i], field + ".data" + "[" + i + "]"); - } - } - if (d.data === undefined) { - d.data = null; - } - d.settings = SettingsProxy.Create(d.settings, field + ".settings"); - if (d.settings === undefined) { - d.settings = null; - } - checkString(d.url, true, field + ".url"); - if (d.url === undefined) { - d.url = null; - } - checkString(d.method, true, field + ".method"); - if (d.method === undefined) { - d.method = null; - } - checkArray(d.params, field + ".params"); - if (d.params) { - for (let i = 0; i < d.params.length; i++) { - d.params[i] = ParamsEntityOrHeadersEntityOrFormdataEntityOrUrlencodedEntityProxy.Create(d.params[i], field + ".params" + "[" + i + "]"); - } - } - if (d.params === undefined) { - d.params = null; - } - d.auth = AuthProxy.Create(d.auth, field + ".auth"); - if (d.auth === undefined) { - d.auth = null; - } - checkArray(d.headers, field + ".headers"); - if (d.headers) { - for (let i = 0; i < d.headers.length; i++) { - d.headers[i] = ParamsEntityOrHeadersEntityOrFormdataEntityOrUrlencodedEntityProxy.Create(d.headers[i], field + ".headers" + "[" + i + "]"); - } - } - if (d.headers === undefined) { - d.headers = null; - } - d.body = BodyProxy.Create(d.body, field + ".body"); - if (d.body === undefined) { - d.body = null; - } - checkArray(d.tests, field + ".tests"); - if (d.tests) { - for (let i = 0; i < d.tests.length; i++) { - d.tests[i] = TestsEntityProxy.Create(d.tests[i], field + ".tests" + "[" + i + "]"); - } - } - if (d.tests === undefined) { - d.tests = null; - } - checkArray(d.setvar, field + ".setvar"); - if (d.setvar) { - for (let i = 0; i < d.setvar.length; i++) { - d.setvar[i] = SetvarEntityProxy.Create(d.setvar[i], field + ".setvar" + "[" + i + "]"); - } - } - if (d.setvar === undefined) { - d.setvar = null; - } - checkString(d.notes, true, field + ".notes"); - if (d.notes === undefined) { - d.notes = null; - } - return new DataEntityProxy(d); - } - private constructor(d: any) { - this.id = d.id; - this.name = d.name; - this.type = d.type; - this.createdTime = d.createdTime; - this.data = d.data; - this.settings = d.settings; - this.url = d.url; - this.method = d.method; - this.params = d.params; - this.auth = d.auth; - this.headers = d.headers; - this.body = d.body; - this.tests = d.tests; - this.setvar = d.setvar; - this.notes = d.notes; - } -} - -export class DataEntity1Proxy { - public readonly id: string; - public readonly name: string; - public readonly type: string | null; - public readonly createdTime: string; - public readonly data: DataEntity2Proxy[] | null; - public readonly settings: Settings1Proxy | null; - public readonly url: string | null; - public readonly method: string | null; - public readonly params: ParamsEntityOrHeadersEntityOrFormdataEntityOrUrlencodedEntityProxy[] | null; - public readonly auth: Auth1Proxy | null; - public readonly headers: ParamsEntityOrHeadersEntityOrFormdataEntityOrUrlencodedEntityProxy[] | null; - public readonly body: Body1Proxy | null; - public readonly tests: TestsEntityProxy[] | null; - public readonly setvar: SetvarEntityProxy[] | null; - public readonly notes: string | null; - public static Parse(d: string): DataEntity1Proxy { - return DataEntity1Proxy.Create(JSON.parse(d)); - } - public static Create(d: any, field: string = 'root'): DataEntity1Proxy { - if (!field) { - obj = d; - field = "root"; - } - if (d === null || d === undefined) { - throwNull2NonNull(field, d); - } else if (typeof(d) !== 'object') { - throwNotObject(field, d, false); - } else if (Array.isArray(d)) { - throwIsArray(field, d, false); - } - checkString(d.id, false, field + ".id"); - checkString(d.name, false, field + ".name"); - checkString(d.type, true, field + ".type"); - if (d.type === undefined) { - d.type = null; - } - checkString(d.createdTime, false, field + ".createdTime"); - checkArray(d.data, field + ".data"); - if (d.data) { - for (let i = 0; i < d.data.length; i++) { - d.data[i] = DataEntity2Proxy.Create(d.data[i], field + ".data" + "[" + i + "]"); - } - } - if (d.data === undefined) { - d.data = null; - } - d.settings = Settings1Proxy.Create(d.settings, field + ".settings"); - if (d.settings === undefined) { - d.settings = null; - } - checkString(d.url, true, field + ".url"); - if (d.url === undefined) { - d.url = null; - } - checkString(d.method, true, field + ".method"); - if (d.method === undefined) { - d.method = null; - } - checkArray(d.params, field + ".params"); - if (d.params) { - for (let i = 0; i < d.params.length; i++) { - d.params[i] = ParamsEntityOrHeadersEntityOrFormdataEntityOrUrlencodedEntityProxy.Create(d.params[i], field + ".params" + "[" + i + "]"); - } - } - if (d.params === undefined) { - d.params = null; - } - d.auth = Auth1Proxy.Create(d.auth, field + ".auth"); - if (d.auth === undefined) { - d.auth = null; - } - checkArray(d.headers, field + ".headers"); - if (d.headers) { - for (let i = 0; i < d.headers.length; i++) { - d.headers[i] = ParamsEntityOrHeadersEntityOrFormdataEntityOrUrlencodedEntityProxy.Create(d.headers[i], field + ".headers" + "[" + i + "]"); - } - } - if (d.headers === undefined) { - d.headers = null; - } - d.body = Body1Proxy.Create(d.body, field + ".body"); - if (d.body === undefined) { - d.body = null; - } - checkArray(d.tests, field + ".tests"); - if (d.tests) { - for (let i = 0; i < d.tests.length; i++) { - d.tests[i] = TestsEntityProxy.Create(d.tests[i], field + ".tests" + "[" + i + "]"); - } - } - if (d.tests === undefined) { - d.tests = null; - } - checkArray(d.setvar, field + ".setvar"); - if (d.setvar) { - for (let i = 0; i < d.setvar.length; i++) { - d.setvar[i] = SetvarEntityProxy.Create(d.setvar[i], field + ".setvar" + "[" + i + "]"); - } - } - if (d.setvar === undefined) { - d.setvar = null; - } - checkString(d.notes, true, field + ".notes"); - if (d.notes === undefined) { - d.notes = null; - } - return new DataEntity1Proxy(d); - } - private constructor(d: any) { - this.id = d.id; - this.name = d.name; - this.type = d.type; - this.createdTime = d.createdTime; - this.data = d.data; - this.settings = d.settings; - this.url = d.url; - this.method = d.method; - this.params = d.params; - this.auth = d.auth; - this.headers = d.headers; - this.body = d.body; - this.tests = d.tests; - this.setvar = d.setvar; - this.notes = d.notes; - } -} - -export class DataEntity2Proxy { - public readonly id: string; - public readonly name: string; - public readonly type: string | null; - public readonly createdTime: string; - public readonly data: DataEntity3Proxy[] | null; - public readonly settings: Settings2Proxy | null; - public readonly url: string | null; - public readonly method: string | null; - public readonly params: ParamsEntityOrHeadersEntityOrFormdataEntityOrUrlencodedEntityProxy[] | null; - public readonly auth: Auth2Proxy | null; - public readonly headers: ParamsEntityOrHeadersEntityOrFormdataEntityOrUrlencodedEntityProxy[] | null; - public readonly body: Body2Proxy | null; - public readonly tests: TestsEntityProxy[] | null; - public readonly setvar: SetvarEntityProxy[] | null; - public readonly notes: string | null; - public static Parse(d: string): DataEntity2Proxy { - return DataEntity2Proxy.Create(JSON.parse(d)); - } - public static Create(d: any, field: string = 'root'): DataEntity2Proxy { - if (!field) { - obj = d; - field = "root"; - } - if (d === null || d === undefined) { - throwNull2NonNull(field, d); - } else if (typeof(d) !== 'object') { - throwNotObject(field, d, false); - } else if (Array.isArray(d)) { - throwIsArray(field, d, false); - } - checkString(d.id, false, field + ".id"); - checkString(d.name, false, field + ".name"); - checkString(d.type, true, field + ".type"); - if (d.type === undefined) { - d.type = null; - } - checkString(d.createdTime, false, field + ".createdTime"); - checkArray(d.data, field + ".data"); - if (d.data) { - for (let i = 0; i < d.data.length; i++) { - d.data[i] = DataEntity3Proxy.Create(d.data[i], field + ".data" + "[" + i + "]"); - } - } - if (d.data === undefined) { - d.data = null; - } - d.settings = Settings2Proxy.Create(d.settings, field + ".settings"); - if (d.settings === undefined) { - d.settings = null; - } - checkString(d.url, true, field + ".url"); - if (d.url === undefined) { - d.url = null; - } - checkString(d.method, true, field + ".method"); - if (d.method === undefined) { - d.method = null; - } - checkArray(d.params, field + ".params"); - if (d.params) { - for (let i = 0; i < d.params.length; i++) { - d.params[i] = ParamsEntityOrHeadersEntityOrFormdataEntityOrUrlencodedEntityProxy.Create(d.params[i], field + ".params" + "[" + i + "]"); - } - } - if (d.params === undefined) { - d.params = null; - } - d.auth = Auth2Proxy.Create(d.auth, field + ".auth"); - if (d.auth === undefined) { - d.auth = null; - } - checkArray(d.headers, field + ".headers"); - if (d.headers) { - for (let i = 0; i < d.headers.length; i++) { - d.headers[i] = ParamsEntityOrHeadersEntityOrFormdataEntityOrUrlencodedEntityProxy.Create(d.headers[i], field + ".headers" + "[" + i + "]"); - } - } - if (d.headers === undefined) { - d.headers = null; - } - d.body = Body2Proxy.Create(d.body, field + ".body"); - if (d.body === undefined) { - d.body = null; - } - checkArray(d.tests, field + ".tests"); - if (d.tests) { - for (let i = 0; i < d.tests.length; i++) { - d.tests[i] = TestsEntityProxy.Create(d.tests[i], field + ".tests" + "[" + i + "]"); - } - } - if (d.tests === undefined) { - d.tests = null; - } - checkArray(d.setvar, field + ".setvar"); - if (d.setvar) { - for (let i = 0; i < d.setvar.length; i++) { - d.setvar[i] = SetvarEntityProxy.Create(d.setvar[i], field + ".setvar" + "[" + i + "]"); - } - } - if (d.setvar === undefined) { - d.setvar = null; - } - checkString(d.notes, true, field + ".notes"); - if (d.notes === undefined) { - d.notes = null; - } - return new DataEntity2Proxy(d); - } - private constructor(d: any) { - this.id = d.id; - this.name = d.name; - this.type = d.type; - this.createdTime = d.createdTime; - this.data = d.data; - this.settings = d.settings; - this.url = d.url; - this.method = d.method; - this.params = d.params; - this.auth = d.auth; - this.headers = d.headers; - this.body = d.body; - this.tests = d.tests; - this.setvar = d.setvar; - this.notes = d.notes; - } -} - -export class DataEntity3Proxy { - public readonly id: string; - public readonly url: string; - public readonly name: string; - public readonly createdTime: string; - public readonly method: string; - public readonly params: ParamsEntityOrHeadersEntityOrFormdataEntityOrUrlencodedEntityProxy[] | null; - public readonly auth: Auth3Proxy; - public readonly headers: ParamsEntityOrHeadersEntityOrFormdataEntityOrUrlencodedEntityProxy[] | null; - public readonly body: Body3Proxy; - public readonly tests: TestsEntityProxy[] | null; - public readonly setvar: SetvarEntityProxy[] | null; - public readonly notes: string; - public static Parse(d: string): DataEntity3Proxy { - return DataEntity3Proxy.Create(JSON.parse(d)); - } - public static Create(d: any, field: string = 'root'): DataEntity3Proxy { - if (!field) { - obj = d; - field = "root"; - } - if (d === null || d === undefined) { - throwNull2NonNull(field, d); - } else if (typeof(d) !== 'object') { - throwNotObject(field, d, false); - } else if (Array.isArray(d)) { - throwIsArray(field, d, false); - } - checkString(d.id, false, field + ".id"); - checkString(d.url, false, field + ".url"); - checkString(d.name, false, field + ".name"); - checkString(d.createdTime, false, field + ".createdTime"); - checkString(d.method, false, field + ".method"); - checkArray(d.params, field + ".params"); - if (d.params) { - for (let i = 0; i < d.params.length; i++) { - d.params[i] = ParamsEntityOrHeadersEntityOrFormdataEntityOrUrlencodedEntityProxy.Create(d.params[i], field + ".params" + "[" + i + "]"); - } - } - if (d.params === undefined) { - d.params = null; - } - d.auth = Auth3Proxy.Create(d.auth, field + ".auth"); - checkArray(d.headers, field + ".headers"); - if (d.headers) { - for (let i = 0; i < d.headers.length; i++) { - d.headers[i] = ParamsEntityOrHeadersEntityOrFormdataEntityOrUrlencodedEntityProxy.Create(d.headers[i], field + ".headers" + "[" + i + "]"); - } - } - if (d.headers === undefined) { - d.headers = null; - } - d.body = Body3Proxy.Create(d.body, field + ".body"); - checkArray(d.tests, field + ".tests"); - if (d.tests) { - for (let i = 0; i < d.tests.length; i++) { - d.tests[i] = TestsEntityProxy.Create(d.tests[i], field + ".tests" + "[" + i + "]"); - } - } - if (d.tests === undefined) { - d.tests = null; - } - checkArray(d.setvar, field + ".setvar"); - if (d.setvar) { - for (let i = 0; i < d.setvar.length; i++) { - d.setvar[i] = SetvarEntityProxy.Create(d.setvar[i], field + ".setvar" + "[" + i + "]"); - } - } - if (d.setvar === undefined) { - d.setvar = null; - } - checkString(d.notes, false, field + ".notes"); - return new DataEntity3Proxy(d); - } - private constructor(d: any) { - this.id = d.id; - this.url = d.url; - this.name = d.name; - this.createdTime = d.createdTime; - this.method = d.method; - this.params = d.params; - this.auth = d.auth; - this.headers = d.headers; - this.body = d.body; - this.tests = d.tests; - this.setvar = d.setvar; - this.notes = d.notes; - } -} - -export class ParamsEntityOrHeadersEntityOrFormdataEntityOrUrlencodedEntityProxy { - public readonly isChecked: boolean; - public readonly key: string; - public readonly value: string; - public static Parse(d: string): ParamsEntityOrHeadersEntityOrFormdataEntityOrUrlencodedEntityProxy { - return ParamsEntityOrHeadersEntityOrFormdataEntityOrUrlencodedEntityProxy.Create(JSON.parse(d)); - } - public static Create(d: any, field: string = 'root'): ParamsEntityOrHeadersEntityOrFormdataEntityOrUrlencodedEntityProxy { - if (!field) { - obj = d; - field = "root"; - } - if (d === null || d === undefined) { - throwNull2NonNull(field, d); - } else if (typeof(d) !== 'object') { - throwNotObject(field, d, false); - } else if (Array.isArray(d)) { - throwIsArray(field, d, false); - } - checkBoolean(d.isChecked, false, field + ".isChecked"); - checkString(d.key, false, field + ".key"); - checkString(d.value, false, field + ".value"); - return new ParamsEntityOrHeadersEntityOrFormdataEntityOrUrlencodedEntityProxy(d); - } - private constructor(d: any) { - this.isChecked = d.isChecked; - this.key = d.key; - this.value = d.value; - } -} - -export class Auth3Proxy { - public readonly authType: string; - public readonly userName: string; - public readonly password: string; - public readonly addTo: string; - public readonly showPwd: boolean; - public readonly tokenPrefix: string; - public readonly aws: AwsProxy; - public static Parse(d: string): Auth3Proxy { - return Auth3Proxy.Create(JSON.parse(d)); - } - public static Create(d: any, field: string = 'root'): Auth3Proxy { - if (!field) { - obj = d; - field = "root"; - } - if (d === null || d === undefined) { - throwNull2NonNull(field, d); - } else if (typeof(d) !== 'object') { - throwNotObject(field, d, false); - } else if (Array.isArray(d)) { - throwIsArray(field, d, false); - } - checkString(d.authType, false, field + ".authType"); - checkString(d.userName, false, field + ".userName"); - checkString(d.password, false, field + ".password"); - checkString(d.addTo, false, field + ".addTo"); - checkBoolean(d.showPwd, false, field + ".showPwd"); - checkString(d.tokenPrefix, false, field + ".tokenPrefix"); - d.aws = AwsProxy.Create(d.aws, field + ".aws"); - return new Auth3Proxy(d); - } - private constructor(d: any) { - this.authType = d.authType; - this.userName = d.userName; - this.password = d.password; - this.addTo = d.addTo; - this.showPwd = d.showPwd; - this.tokenPrefix = d.tokenPrefix; - this.aws = d.aws; - } -} - -export class AwsProxy { - public readonly service: string; - public readonly region: string; - public readonly accessKey: string; - public readonly secretAccessKey: string; - public readonly sessionToken: string; - public static Parse(d: string): AwsProxy { - return AwsProxy.Create(JSON.parse(d)); - } - public static Create(d: any, field: string = 'root'): AwsProxy { - if (!field) { - obj = d; - field = "root"; - } - if (d === null || d === undefined) { - throwNull2NonNull(field, d); - } else if (typeof(d) !== 'object') { - throwNotObject(field, d, false); - } else if (Array.isArray(d)) { - throwIsArray(field, d, false); - } - checkString(d.service, false, field + ".service"); - checkString(d.region, false, field + ".region"); - checkString(d.accessKey, false, field + ".accessKey"); - checkString(d.secretAccessKey, false, field + ".secretAccessKey"); - checkString(d.sessionToken, false, field + ".sessionToken"); - return new AwsProxy(d); - } - private constructor(d: any) { - this.service = d.service; - this.region = d.region; - this.accessKey = d.accessKey; - this.secretAccessKey = d.secretAccessKey; - this.sessionToken = d.sessionToken; - } -} - -export class Body3Proxy { - public readonly bodyType: string; - public readonly formdata: ParamsEntityOrHeadersEntityOrFormdataEntityOrUrlencodedEntityProxy[] | null; - public readonly urlencoded: ParamsEntityOrHeadersEntityOrFormdataEntityOrUrlencodedEntityProxy[] | null; - public readonly raw: RawProxy; - public readonly binary: BinaryProxy; - public readonly graphql: GraphqlProxy; - public static Parse(d: string): Body3Proxy { - return Body3Proxy.Create(JSON.parse(d)); - } - public static Create(d: any, field: string = 'root'): Body3Proxy { - if (!field) { - obj = d; - field = "root"; - } - if (d === null || d === undefined) { - throwNull2NonNull(field, d); - } else if (typeof(d) !== 'object') { - throwNotObject(field, d, false); - } else if (Array.isArray(d)) { - throwIsArray(field, d, false); - } - checkString(d.bodyType, false, field + ".bodyType"); - checkArray(d.formdata, field + ".formdata"); - if (d.formdata) { - for (let i = 0; i < d.formdata.length; i++) { - d.formdata[i] = ParamsEntityOrHeadersEntityOrFormdataEntityOrUrlencodedEntityProxy.Create(d.formdata[i], field + ".formdata" + "[" + i + "]"); - } - } - if (d.formdata === undefined) { - d.formdata = null; - } - checkArray(d.urlencoded, field + ".urlencoded"); - if (d.urlencoded) { - for (let i = 0; i < d.urlencoded.length; i++) { - d.urlencoded[i] = ParamsEntityOrHeadersEntityOrFormdataEntityOrUrlencodedEntityProxy.Create(d.urlencoded[i], field + ".urlencoded" + "[" + i + "]"); - } - } - if (d.urlencoded === undefined) { - d.urlencoded = null; - } - d.raw = RawProxy.Create(d.raw, field + ".raw"); - d.binary = BinaryProxy.Create(d.binary, field + ".binary"); - d.graphql = GraphqlProxy.Create(d.graphql, field + ".graphql"); - return new Body3Proxy(d); - } - private constructor(d: any) { - this.bodyType = d.bodyType; - this.formdata = d.formdata; - this.urlencoded = d.urlencoded; - this.raw = d.raw; - this.binary = d.binary; - this.graphql = d.graphql; - } -} - -export class RawProxy { - public readonly data: string; - public readonly lang: string; - public static Parse(d: string): RawProxy { - return RawProxy.Create(JSON.parse(d)); - } - public static Create(d: any, field: string = 'root'): RawProxy { - if (!field) { - obj = d; - field = "root"; - } - if (d === null || d === undefined) { - throwNull2NonNull(field, d); - } else if (typeof(d) !== 'object') { - throwNotObject(field, d, false); - } else if (Array.isArray(d)) { - throwIsArray(field, d, false); - } - checkString(d.data, false, field + ".data"); - checkString(d.lang, false, field + ".lang"); - return new RawProxy(d); - } - private constructor(d: any) { - this.data = d.data; - this.lang = d.lang; - } -} - -export class BinaryProxy { - public readonly fileName: string; - public readonly data: DataProxy; - public readonly contentTypeOption: string; - public static Parse(d: string): BinaryProxy { - return BinaryProxy.Create(JSON.parse(d)); - } - public static Create(d: any, field: string = 'root'): BinaryProxy { - if (!field) { - obj = d; - field = "root"; - } - if (d === null || d === undefined) { - throwNull2NonNull(field, d); - } else if (typeof(d) !== 'object') { - throwNotObject(field, d, false); - } else if (Array.isArray(d)) { - throwIsArray(field, d, false); - } - checkString(d.fileName, false, field + ".fileName"); - d.data = DataProxy.Create(d.data, field + ".data"); - checkString(d.contentTypeOption, false, field + ".contentTypeOption"); - return new BinaryProxy(d); - } - private constructor(d: any) { - this.fileName = d.fileName; - this.data = d.data; - this.contentTypeOption = d.contentTypeOption; - } -} - -export class DataProxy { - public static Parse(d: string): DataProxy { - return DataProxy.Create(JSON.parse(d)); - } - public static Create(d: any, field: string = 'root'): DataProxy { - if (!field) { - obj = d; - field = "root"; - } - if (d === null || d === undefined) { - throwNull2NonNull(field, d); - } else if (typeof(d) !== 'object') { - throwNotObject(field, d, false); - } else if (Array.isArray(d)) { - throwIsArray(field, d, false); - } - return new DataProxy(d); - } - private constructor(d: any) { - } -} - -export class GraphqlProxy { - public readonly query: string; - public readonly variables: string; - public static Parse(d: string): GraphqlProxy { - return GraphqlProxy.Create(JSON.parse(d)); - } - public static Create(d: any, field: string = 'root'): GraphqlProxy { - if (!field) { - obj = d; - field = "root"; - } - if (d === null || d === undefined) { - throwNull2NonNull(field, d); - } else if (typeof(d) !== 'object') { - throwNotObject(field, d, false); - } else if (Array.isArray(d)) { - throwIsArray(field, d, false); - } - checkString(d.query, false, field + ".query"); - checkString(d.variables, false, field + ".variables"); - return new GraphqlProxy(d); - } - private constructor(d: any) { - this.query = d.query; - this.variables = d.variables; - } -} - -export class TestsEntityProxy { - public readonly parameter: string; - public readonly action: string; - public readonly expectedValue: string; - public static Parse(d: string): TestsEntityProxy { - return TestsEntityProxy.Create(JSON.parse(d)); - } - public static Create(d: any, field: string = 'root'): TestsEntityProxy { - if (!field) { - obj = d; - field = "root"; - } - if (d === null || d === undefined) { - throwNull2NonNull(field, d); - } else if (typeof(d) !== 'object') { - throwNotObject(field, d, false); - } else if (Array.isArray(d)) { - throwIsArray(field, d, false); - } - checkString(d.parameter, false, field + ".parameter"); - checkString(d.action, false, field + ".action"); - checkString(d.expectedValue, false, field + ".expectedValue"); - return new TestsEntityProxy(d); - } - private constructor(d: any) { - this.parameter = d.parameter; - this.action = d.action; - this.expectedValue = d.expectedValue; - } -} - -export class SetvarEntityProxy { - public readonly parameter: string; - public readonly key: string; - public readonly variableName: string; - public static Parse(d: string): SetvarEntityProxy { - return SetvarEntityProxy.Create(JSON.parse(d)); - } - public static Create(d: any, field: string = 'root'): SetvarEntityProxy { - if (!field) { - obj = d; - field = "root"; - } - if (d === null || d === undefined) { - throwNull2NonNull(field, d); - } else if (typeof(d) !== 'object') { - throwNotObject(field, d, false); - } else if (Array.isArray(d)) { - throwIsArray(field, d, false); - } - checkString(d.parameter, false, field + ".parameter"); - checkString(d.key, false, field + ".key"); - checkString(d.variableName, false, field + ".variableName"); - return new SetvarEntityProxy(d); - } - private constructor(d: any) { - this.parameter = d.parameter; - this.key = d.key; - this.variableName = d.variableName; - } -} - -export class Settings2Proxy { - public readonly auth: Auth3Proxy; - public static Parse(d: string): Settings2Proxy | null { - return Settings2Proxy.Create(JSON.parse(d)); - } - public static Create(d: any, field: string = 'root'): Settings2Proxy | null { - if (!field) { - obj = d; - field = "root"; - } - if (d === null || d === undefined) { - return null; - } else if (typeof(d) !== 'object') { - throwNotObject(field, d, true); - } else if (Array.isArray(d)) { - throwIsArray(field, d, true); - } - d.auth = Auth3Proxy.Create(d.auth, field + ".auth"); - return new Settings2Proxy(d); - } - private constructor(d: any) { - this.auth = d.auth; - } -} - -export class Auth2Proxy { - public readonly authType: string; - public readonly userName: string; - public readonly password: string; - public readonly addTo: string; - public readonly showPwd: boolean; - public readonly tokenPrefix: string; - public readonly aws: AwsProxy; - public static Parse(d: string): Auth2Proxy | null { - return Auth2Proxy.Create(JSON.parse(d)); - } - public static Create(d: any, field: string = 'root'): Auth2Proxy | null { - if (!field) { - obj = d; - field = "root"; - } - if (d === null || d === undefined) { - return null; - } else if (typeof(d) !== 'object') { - throwNotObject(field, d, true); - } else if (Array.isArray(d)) { - throwIsArray(field, d, true); - } - checkString(d.authType, false, field + ".authType"); - checkString(d.userName, false, field + ".userName"); - checkString(d.password, false, field + ".password"); - checkString(d.addTo, false, field + ".addTo"); - checkBoolean(d.showPwd, false, field + ".showPwd"); - checkString(d.tokenPrefix, false, field + ".tokenPrefix"); - d.aws = AwsProxy.Create(d.aws, field + ".aws"); - return new Auth2Proxy(d); - } - private constructor(d: any) { - this.authType = d.authType; - this.userName = d.userName; - this.password = d.password; - this.addTo = d.addTo; - this.showPwd = d.showPwd; - this.tokenPrefix = d.tokenPrefix; - this.aws = d.aws; - } -} - -export class Body2Proxy { - public readonly bodyType: string; - public readonly formdata: ParamsEntityOrHeadersEntityOrFormdataEntityOrUrlencodedEntityProxy[] | null; - public readonly urlencoded: ParamsEntityOrHeadersEntityOrFormdataEntityOrUrlencodedEntityProxy[] | null; - public readonly raw: RawProxy; - public readonly binary: BinaryProxy; - public readonly graphql: GraphqlProxy; - public static Parse(d: string): Body2Proxy | null { - return Body2Proxy.Create(JSON.parse(d)); - } - public static Create(d: any, field: string = 'root'): Body2Proxy | null { - if (!field) { - obj = d; - field = "root"; - } - if (d === null || d === undefined) { - return null; - } else if (typeof(d) !== 'object') { - throwNotObject(field, d, true); - } else if (Array.isArray(d)) { - throwIsArray(field, d, true); - } - checkString(d.bodyType, false, field + ".bodyType"); - checkArray(d.formdata, field + ".formdata"); - if (d.formdata) { - for (let i = 0; i < d.formdata.length; i++) { - d.formdata[i] = ParamsEntityOrHeadersEntityOrFormdataEntityOrUrlencodedEntityProxy.Create(d.formdata[i], field + ".formdata" + "[" + i + "]"); - } - } - if (d.formdata === undefined) { - d.formdata = null; - } - checkArray(d.urlencoded, field + ".urlencoded"); - if (d.urlencoded) { - for (let i = 0; i < d.urlencoded.length; i++) { - d.urlencoded[i] = ParamsEntityOrHeadersEntityOrFormdataEntityOrUrlencodedEntityProxy.Create(d.urlencoded[i], field + ".urlencoded" + "[" + i + "]"); - } - } - if (d.urlencoded === undefined) { - d.urlencoded = null; - } - d.raw = RawProxy.Create(d.raw, field + ".raw"); - d.binary = BinaryProxy.Create(d.binary, field + ".binary"); - d.graphql = GraphqlProxy.Create(d.graphql, field + ".graphql"); - return new Body2Proxy(d); - } - private constructor(d: any) { - this.bodyType = d.bodyType; - this.formdata = d.formdata; - this.urlencoded = d.urlencoded; - this.raw = d.raw; - this.binary = d.binary; - this.graphql = d.graphql; - } -} - -export class Settings1Proxy { - public readonly auth: Auth3Proxy; - public static Parse(d: string): Settings1Proxy | null { - return Settings1Proxy.Create(JSON.parse(d)); - } - public static Create(d: any, field: string = 'root'): Settings1Proxy | null { - if (!field) { - obj = d; - field = "root"; - } - if (d === null || d === undefined) { - return null; - } else if (typeof(d) !== 'object') { - throwNotObject(field, d, true); - } else if (Array.isArray(d)) { - throwIsArray(field, d, true); - } - d.auth = Auth3Proxy.Create(d.auth, field + ".auth"); - return new Settings1Proxy(d); - } - private constructor(d: any) { - this.auth = d.auth; - } -} - -export class Auth1Proxy { - public readonly authType: string; - public readonly userName: string; - public readonly password: string; - public readonly addTo: string; - public readonly showPwd: boolean; - public readonly tokenPrefix: string; - public readonly aws: AwsProxy; - public static Parse(d: string): Auth1Proxy | null { - return Auth1Proxy.Create(JSON.parse(d)); - } - public static Create(d: any, field: string = 'root'): Auth1Proxy | null { - if (!field) { - obj = d; - field = "root"; - } - if (d === null || d === undefined) { - return null; - } else if (typeof(d) !== 'object') { - throwNotObject(field, d, true); - } else if (Array.isArray(d)) { - throwIsArray(field, d, true); - } - checkString(d.authType, false, field + ".authType"); - checkString(d.userName, false, field + ".userName"); - checkString(d.password, false, field + ".password"); - checkString(d.addTo, false, field + ".addTo"); - checkBoolean(d.showPwd, false, field + ".showPwd"); - checkString(d.tokenPrefix, false, field + ".tokenPrefix"); - d.aws = AwsProxy.Create(d.aws, field + ".aws"); - return new Auth1Proxy(d); - } - private constructor(d: any) { - this.authType = d.authType; - this.userName = d.userName; - this.password = d.password; - this.addTo = d.addTo; - this.showPwd = d.showPwd; - this.tokenPrefix = d.tokenPrefix; - this.aws = d.aws; - } -} - -export class Body1Proxy { - public readonly bodyType: string; - public readonly formdata: ParamsEntityOrHeadersEntityOrFormdataEntityOrUrlencodedEntityProxy[] | null; - public readonly urlencoded: ParamsEntityOrHeadersEntityOrFormdataEntityOrUrlencodedEntityProxy[] | null; - public readonly raw: RawProxy; - public readonly binary: BinaryProxy; - public readonly graphql: GraphqlProxy; - public static Parse(d: string): Body1Proxy | null { - return Body1Proxy.Create(JSON.parse(d)); - } - public static Create(d: any, field: string = 'root'): Body1Proxy | null { - if (!field) { - obj = d; - field = "root"; - } - if (d === null || d === undefined) { - return null; - } else if (typeof(d) !== 'object') { - throwNotObject(field, d, true); - } else if (Array.isArray(d)) { - throwIsArray(field, d, true); - } - checkString(d.bodyType, false, field + ".bodyType"); - checkArray(d.formdata, field + ".formdata"); - if (d.formdata) { - for (let i = 0; i < d.formdata.length; i++) { - d.formdata[i] = ParamsEntityOrHeadersEntityOrFormdataEntityOrUrlencodedEntityProxy.Create(d.formdata[i], field + ".formdata" + "[" + i + "]"); - } - } - if (d.formdata === undefined) { - d.formdata = null; - } - checkArray(d.urlencoded, field + ".urlencoded"); - if (d.urlencoded) { - for (let i = 0; i < d.urlencoded.length; i++) { - d.urlencoded[i] = ParamsEntityOrHeadersEntityOrFormdataEntityOrUrlencodedEntityProxy.Create(d.urlencoded[i], field + ".urlencoded" + "[" + i + "]"); - } - } - if (d.urlencoded === undefined) { - d.urlencoded = null; - } - d.raw = RawProxy.Create(d.raw, field + ".raw"); - d.binary = BinaryProxy.Create(d.binary, field + ".binary"); - d.graphql = GraphqlProxy.Create(d.graphql, field + ".graphql"); - return new Body1Proxy(d); - } - private constructor(d: any) { - this.bodyType = d.bodyType; - this.formdata = d.formdata; - this.urlencoded = d.urlencoded; - this.raw = d.raw; - this.binary = d.binary; - this.graphql = d.graphql; - } -} - -export class SettingsProxy { - public readonly auth: Auth3Proxy; - public static Parse(d: string): SettingsProxy | null { - return SettingsProxy.Create(JSON.parse(d)); - } - public static Create(d: any, field: string = 'root'): SettingsProxy | null { - if (!field) { - obj = d; - field = "root"; - } - if (d === null || d === undefined) { - return null; - } else if (typeof(d) !== 'object') { - throwNotObject(field, d, true); - } else if (Array.isArray(d)) { - throwIsArray(field, d, true); - } - d.auth = Auth3Proxy.Create(d.auth, field + ".auth"); - return new SettingsProxy(d); - } - private constructor(d: any) { - this.auth = d.auth; - } -} - -export class AuthProxy { - public readonly authType: string; - public readonly userName: string; - public readonly password: string; - public readonly addTo: string; - public readonly showPwd: boolean; - public readonly tokenPrefix: string; - public readonly aws: AwsProxy; - public static Parse(d: string): AuthProxy | null { - return AuthProxy.Create(JSON.parse(d)); - } - public static Create(d: any, field: string = 'root'): AuthProxy | null { - if (!field) { - obj = d; - field = "root"; - } - if (d === null || d === undefined) { - return null; - } else if (typeof(d) !== 'object') { - throwNotObject(field, d, true); - } else if (Array.isArray(d)) { - throwIsArray(field, d, true); - } - checkString(d.authType, false, field + ".authType"); - checkString(d.userName, false, field + ".userName"); - checkString(d.password, false, field + ".password"); - checkString(d.addTo, false, field + ".addTo"); - checkBoolean(d.showPwd, false, field + ".showPwd"); - checkString(d.tokenPrefix, false, field + ".tokenPrefix"); - d.aws = AwsProxy.Create(d.aws, field + ".aws"); - return new AuthProxy(d); - } - private constructor(d: any) { - this.authType = d.authType; - this.userName = d.userName; - this.password = d.password; - this.addTo = d.addTo; - this.showPwd = d.showPwd; - this.tokenPrefix = d.tokenPrefix; - this.aws = d.aws; - } -} - -export class BodyProxy { - public readonly bodyType: string; - public readonly formdata: ParamsEntityOrHeadersEntityOrFormdataEntityOrUrlencodedEntityProxy[] | null; - public readonly urlencoded: ParamsEntityOrHeadersEntityOrFormdataEntityOrUrlencodedEntityProxy[] | null; - public readonly raw: RawProxy; - public readonly binary: BinaryProxy; - public readonly graphql: GraphqlProxy; - public static Parse(d: string): BodyProxy | null { - return BodyProxy.Create(JSON.parse(d)); - } - public static Create(d: any, field: string = 'root'): BodyProxy | null { - if (!field) { - obj = d; - field = "root"; - } - if (d === null || d === undefined) { - return null; - } else if (typeof(d) !== 'object') { - throwNotObject(field, d, true); - } else if (Array.isArray(d)) { - throwIsArray(field, d, true); - } - checkString(d.bodyType, false, field + ".bodyType"); - checkArray(d.formdata, field + ".formdata"); - if (d.formdata) { - for (let i = 0; i < d.formdata.length; i++) { - d.formdata[i] = ParamsEntityOrHeadersEntityOrFormdataEntityOrUrlencodedEntityProxy.Create(d.formdata[i], field + ".formdata" + "[" + i + "]"); - } - } - if (d.formdata === undefined) { - d.formdata = null; - } - checkArray(d.urlencoded, field + ".urlencoded"); - if (d.urlencoded) { - for (let i = 0; i < d.urlencoded.length; i++) { - d.urlencoded[i] = ParamsEntityOrHeadersEntityOrFormdataEntityOrUrlencodedEntityProxy.Create(d.urlencoded[i], field + ".urlencoded" + "[" + i + "]"); - } - } - if (d.urlencoded === undefined) { - d.urlencoded = null; - } - d.raw = RawProxy.Create(d.raw, field + ".raw"); - d.binary = BinaryProxy.Create(d.binary, field + ".binary"); - d.graphql = GraphqlProxy.Create(d.graphql, field + ".graphql"); - return new BodyProxy(d); - } - private constructor(d: any) { - this.bodyType = d.bodyType; - this.formdata = d.formdata; - this.urlencoded = d.urlencoded; - this.raw = d.raw; - this.binary = d.binary; - this.graphql = d.graphql; - } -} - -function throwNull2NonNull(field: string, d: any): never { - return errorHelper(field, d, "non-nullable object", false); -} -function throwNotObject(field: string, d: any, nullable: boolean): never { - return errorHelper(field, d, "object", nullable); -} -function throwIsArray(field: string, d: any, nullable: boolean): never { - return errorHelper(field, d, "object", nullable); -} -function checkArray(d: any, field: string): void { - if (!Array.isArray(d) && d !== null && d !== undefined) { - errorHelper(field, d, "array", true); - } -} -function checkBoolean(d: any, nullable: boolean, field: string): void { - if (typeof(d) !== 'boolean' && (!nullable || (nullable && d !== null && d !== undefined))) { - errorHelper(field, d, "boolean", nullable); - } -} -function checkString(d: any, nullable: boolean, field: string): void { - if (typeof(d) !== 'string' && (!nullable || (nullable && d !== null && d !== undefined))) { - errorHelper(field, d, "string", nullable); - } -} -function errorHelper(field: string, d: any, type: string, nullable: boolean): never { - if (nullable) { - type += ", null, or undefined"; - } - throw new TypeError("Expected '" + type + "' at '" + field + "' but found: " + JSON.stringify(d) + "\nFull object:\n" + JSON.stringify(obj)); -} -function checkStringValue(d: any, field: string, value: string): void { - if (d !== value) { - errorHelper(field, d, value, false); - } -} diff --git a/src/utils/ImportVariableValidator.ts b/src/utils/ImportVariableValidator.ts deleted file mode 100644 index 910406e..0000000 --- a/src/utils/ImportVariableValidator.ts +++ /dev/null @@ -1,126 +0,0 @@ -let obj: any = null; -export class FetchClientVariableProxy { - public readonly app: string; - public readonly id: string; - public readonly name: string; - public readonly version: string; - public readonly type: string; - public readonly createdTime: string; - public readonly exportedDate: string; - public readonly isActive: boolean; - public readonly data: DataEntityProxy[] | null; - public static Parse(d: string): FetchClientVariableProxy { - return FetchClientVariableProxy.Create(JSON.parse(d)); - } - public static Create(d: any, field: string = 'root'): FetchClientVariableProxy { - if (!field) { - obj = d; - field = "root"; - } - if (d === null || d === undefined) { - throwNull2NonNull(field, d); - } else if (typeof(d) !== 'object') { - throwNotObject(field, d, false); - } else if (Array.isArray(d)) { - throwIsArray(field, d, false); - } - checkString(d.app, false, field + ".app"); - checkStringValue(d.app, field + ".app", "Fetch Client"); - checkString(d.id, false, field + ".id"); - checkString(d.name, false, field + ".name"); - checkString(d.version, false, field + ".version"); - checkString(d.type, false, field + ".type"); - checkStringValue(d.type, field + ".type", "variables"); - checkString(d.createdTime, false, field + ".createdTime"); - checkString(d.exportedDate, false, field + ".exportedDate"); - checkBoolean(d.isActive, false, field + ".isActive"); - checkArray(d.data, field + ".data"); - if (d.data) { - for (let i = 0; i < d.data.length; i++) { - d.data[i] = DataEntityProxy.Create(d.data[i], field + ".data" + "[" + i + "]"); - } - } - if (d.data === undefined) { - d.data = null; - } - return new FetchClientVariableProxy(d); - } - private constructor(d: any) { - this.app = d.app; - this.id = d.id; - this.name = d.name; - this.version = d.version; - this.type = d.type; - this.createdTime = d.createdTime; - this.exportedDate = d.exportedDate; - this.isActive = d.isActive; - this.data = d.data; - } -} - -export class DataEntityProxy { - public readonly isChecked: boolean; - public readonly key: string; - public readonly value: string; - public static Parse(d: string): DataEntityProxy { - return DataEntityProxy.Create(JSON.parse(d)); - } - public static Create(d: any, field: string = 'root'): DataEntityProxy { - if (!field) { - obj = d; - field = "root"; - } - if (d === null || d === undefined) { - throwNull2NonNull(field, d); - } else if (typeof(d) !== 'object') { - throwNotObject(field, d, false); - } else if (Array.isArray(d)) { - throwIsArray(field, d, false); - } - checkBoolean(d.isChecked, false, field + ".isChecked"); - checkString(d.key, false, field + ".key"); - checkString(d.value, false, field + ".value"); - return new DataEntityProxy(d); - } - private constructor(d: any) { - this.isChecked = d.isChecked; - this.key = d.key; - this.value = d.value; - } -} - -function throwNull2NonNull(field: string, d: any): never { - return errorHelper(field, d, "non-nullable object", false); -} -function throwNotObject(field: string, d: any, nullable: boolean): never { - return errorHelper(field, d, "object", nullable); -} -function throwIsArray(field: string, d: any, nullable: boolean): never { - return errorHelper(field, d, "object", nullable); -} -function checkArray(d: any, field: string): void { - if (!Array.isArray(d) && d !== null && d !== undefined) { - errorHelper(field, d, "array", true); - } -} -function checkBoolean(d: any, nullable: boolean, field: string): void { - if (typeof(d) !== 'boolean' && (!nullable || (nullable && d !== null && d !== undefined))) { - errorHelper(field, d, "boolean", nullable); - } -} -function checkString(d: any, nullable: boolean, field: string): void { - if (typeof(d) !== 'string' && (!nullable || (nullable && d !== null && d !== undefined))) { - errorHelper(field, d, "string", nullable); - } -} -function errorHelper(field: string, d: any, type: string, nullable: boolean): never { - if (nullable) { - type += ", null, or undefined"; - } - throw new TypeError("Expected '" + type + "' at '" + field + "' but found:\n" + JSON.stringify(d) + "\n\nFull object:\n" + JSON.stringify(obj)); -} -function checkStringValue(d: any, field: string, value: string): void { - if (d !== value) { - errorHelper(field, d, value, false); - } -} \ No newline at end of file diff --git a/src/utils/PreFetchRunner.ts b/src/utils/PreFetchRunner.ts index e1f7578..711e4e6 100644 --- a/src/utils/PreFetchRunner.ts +++ b/src/utils/PreFetchRunner.ts @@ -1,12 +1,12 @@ -import { apiFetch, FetchConfig } from "./fetchUtil"; -import { executeTests, setVariable } from "../fetch-client-ui/components/TestUI/TestPanel/helper"; -import { GetParentSettingsSync, GetVariableByColId } from "./db/collectionDBUtil"; -import { GetRequestItem } from "./db/mainDBUtil"; -import { GetVariableByIdSync, UpdateVariable } from "./db/varDBUtil"; -import { InitialResponse } from "../fetch-client-ui/components/ResponseUI/redux/reducer"; import { IPreFetch, IRequestModel } from "../fetch-client-ui/components/RequestUI/redux/types"; +import { InitialResponse } from "../fetch-client-ui/components/ResponseUI/redux/reducer"; import { IReponseModel } from "../fetch-client-ui/components/ResponseUI/redux/types"; import { ISettings, IVariable } from "../fetch-client-ui/components/SideBar/redux/types"; +import { executeTests, setVariable } from "../fetch-client-ui/components/TestUI/TestPanel/helper"; +import { GetParentSettingsSync, GetVariableByColId } from "./db/collectionDBUtil"; +import { GetRequestItem } from "./db/mainDBUtil"; +import { GetVariableByIdSync, UpdateVariable, UpdateVariableSync } from "./db/varDBUtil"; +import { apiFetch, FetchConfig } from "./fetchUtil"; export class PreFetchRunner { @@ -28,7 +28,7 @@ export class PreFetchRunner { this.fetchConfig = fetchConfig; } - RunPreRequests = async (preFetch: IPreFetch, fetchIndex: number, reqIndex: number, parentName: string) => { + RunPreRequests = async (preFetch: IPreFetch, fetchIndex: number, reqIndex: number, parentName: string, isCollectionPreRequest: boolean) => { let request: IRequestModel; let parentSettings: ISettings; let updateVariable: IVariable; @@ -81,11 +81,11 @@ export class PreFetchRunner { parentSettings = await GetParentSettingsSync(colId, parentId); } - request = await GetRequestItem(reqId); + request = await GetRequestItem(reqId); if (request && this.allow) { - if (request.preFetch?.requests?.length > 0) { - await this.RunPreRequests(request.preFetch, fetchIndex + 1, 0, request.name); + if (request.preFetch?.requests?.length > 0 && !isCollectionPreRequest) { + await this.RunPreRequests(request.preFetch, fetchIndex + 1, 0, request.name, isCollectionPreRequest); if (!this.allow) { return; } @@ -93,30 +93,29 @@ export class PreFetchRunner { if (index !== -1) { this.executingRequests.splice(index); } - let res = await apiFetch(request, variable.data, parentSettings, this.fetchConfig); + let res = await apiFetch(request, variable?.data, parentSettings, null, this.fetchConfig); this.response.response = res.response; this.response.headers = res.headers; this.response.cookies = res.cookies; - updateVariable = this.updateVariable(request, variable); + updateVariable = await this.updateVariable(request, variable); } else { - let res = await apiFetch(request, variable.data, parentSettings, this.fetchConfig); + let res = await apiFetch(request, variable?.data, parentSettings, null, this.fetchConfig); this.response.response = res.response; this.response.headers = res.headers; this.response.cookies = res.cookies; - updateVariable = this.updateVariable(request, variable); + updateVariable = await this.updateVariable(request, variable); } } } }; - updateVariable = (request: IRequestModel, variable: IVariable): IVariable => { + updateVariable = async (request: IRequestModel, variable: IVariable): Promise => { if (this.response.response.status !== 0 && this.response.response.status <= 399 && request.setvar.length - 1 > 0 && variable?.id) { - let variableResult = setVariable(variable, request.setvar, this.response); - UpdateVariable(variableResult, null); + let variables = setVariable(variable, request.setvar, this.response); + let variableResult = await UpdateVariableSync(variables); return variableResult; - } else { - return variable; } + return variable; }; } diff --git a/src/utils/configuration.ts b/src/utils/configuration.ts index e48c345..a81a9bf 100644 --- a/src/utils/configuration.ts +++ b/src/utils/configuration.ts @@ -5,6 +5,7 @@ export const requestTypes = { attachVariableRequest: "attachVariableRequest", cancelRequest: "cancelRequest", clearRequest: "clearRequest", + closeItemRequest: "closeItemRequest", configRequest: "configRequest", convertCurlToJsonRequest: "convertCurlToJsonRequest", copyItemRequest: "copyItemRequest", @@ -39,6 +40,7 @@ export const requestTypes = { getCookiesByIdRequest: "getCookiesByIdRequest", getErrorLogRequest: "getErrorLogRequest", getHistoryItemRequest: "getHistoryItemRequest", + getOpenAndRunItemDataRequest: "getOpenAndRunItemDataRequest", getParentSettingsRequest: "getParentSettingsRequest", getRunItemDataRequest: "getRunItemDataRequest", getVariableItemRequest: "getVariableItemRequest", @@ -50,6 +52,7 @@ export const requestTypes = { newCollectionRequest: "newCollectionRequest", newRequest: "newRequest", newVariableRequest: "newVariableRequest", + openAndRunItemRequest: "openAndRunItemRequest", openColSettingsRequest: "openColSettingsRequest", openExistingItemRequest: "openExistingItemRequest", openHistoryItemRequest: "openHistoryItemRequest", @@ -80,7 +83,7 @@ export const requestTypes = { themeRequest: "themeRequest", tokenRequest: "tokenRequest", updateVariableRequest: "updateVariableRequest", - viewLogRequest: "viewLogRequest", + viewLogRequest: "viewLogRequest" }; export const responseTypes = { @@ -123,6 +126,7 @@ export const responseTypes = { getCookiesByIdResponse: "getCookiesByIdResponse", getErrorLogResponse: "getErrorLogResponse", getHistoryItemResponse: "getHistoryItemResponse", + getOpenAndRunItemDataResponse: "getOpenAndRunItemDataResponse", getParentSettingsResponse: "getParentSettingsResponse", getRunItemDataResponse: "getRunItemDataResponse", getVariableItemResponse: "getVariableItemResponse", diff --git a/src/utils/db/collectionDBUtil.ts b/src/utils/db/collectionDBUtil.ts index 3099fc9..88f7643 100644 --- a/src/utils/db/collectionDBUtil.ts +++ b/src/utils/db/collectionDBUtil.ts @@ -1,22 +1,23 @@ -import * as vscode from 'vscode'; import loki, { LokiFsAdapter } from 'lokijs'; import { v4 as uuidv4 } from 'uuid'; -import { ICollections, ISettings, IFolder, IHistory } from "../../fetch-client-ui/components/SideBar/redux/types"; -import { pubSubTypes, responseTypes } from '../configuration'; -import { CopyExitingItems, DeleteExitingItems, GetColsRequests, RenameRequestItem } from './mainDBUtil'; -import { IRequestModel } from '../../fetch-client-ui/components/RequestUI/redux/types'; -import { writeLog } from '../logger/logger'; -import { formatDate } from '../helper'; +import * as vscode from 'vscode'; import { pubSub } from '../../extension'; -import { isFolder } from '../../fetch-client-ui/components/SideBar/util'; import { SettingsType } from '../../fetch-client-ui/components/Collection/consts'; +import { IRequestModel } from '../../fetch-client-ui/components/RequestUI/redux/types'; import { InitialSettings } from '../../fetch-client-ui/components/SideBar/redux/reducer'; +import { ICollections, IFolder, IHistory, ISettings } from "../../fetch-client-ui/components/SideBar/redux/types"; +import { isFolder } from '../../fetch-client-ui/components/SideBar/util'; +import { pubSubTypes, responseTypes } from '../configuration'; import { apiFetch, FetchConfig } from '../fetchUtil'; +import { formatDate } from '../helper'; +import { writeLog } from '../logger/logger'; import { collectionDBPath, mainDBPath } from './dbPaths'; +import { CopyExitingItems, DeleteExitingItems, GetColsRequests, RenameRequestItem } from './mainDBUtil'; function getDB(): loki { const idbAdapter = new LokiFsAdapter(); const db = new loki(collectionDBPath(), { adapter: idbAdapter }); + db.autosaveDisable(); return db; } @@ -62,8 +63,7 @@ function findParent(source: any, id: string) { } } - -function findParentSettings(source: any, id: string, prevSettings: any) { +function findParentSettings(source: any, id: string, prevSettings: any = null) { let pos = source.data.findIndex((el: any) => el.id === id); let curSettings = source.settings; @@ -79,7 +79,8 @@ function findParentSettings(source: any, id: string, prevSettings: any) { if (pos !== -1) { if (source.data[pos].settings) { if (source.data[pos].settings.auth.authType === "inherit") { - return curSettings; + source.data[pos].settings.auth = curSettings.auth; + return source.data[pos].settings; } else { return source.data[pos].settings; } @@ -88,7 +89,7 @@ function findParentSettings(source: any, id: string, prevSettings: any) { } } - let folders = source.data.filter(item => item.data !== undefined); + let folders = source.data.filter((item: any) => item.data !== undefined); for (let i = 0; i < folders.length; i++) { const result: any = findParentSettings(folders[i], id, curSettings); @@ -497,7 +498,7 @@ export function GetAllCollectionName(webview: vscode.Webview, from: string) { }); } catch (err) { - writeLog("error::GetAllHistory(): " + err); + writeLog("error::GetAllCollectionName(): " + err); } } @@ -511,7 +512,7 @@ export function GetAllCollections(webview: vscode.Webview) { }); } catch (err) { - writeLog("error::GetAllHistory(): " + err); + writeLog("error::GetAllCollections(): " + err); } } @@ -740,15 +741,32 @@ export function GetAllCollectionsById(colId: string, folderId: string, type: str db.loadDatabase({}, function () { let ids = []; let paths: any; - let results = db.getCollection('userCollections').by('id', colId); + let settings: ISettings; + + let colItem = db.getCollection('userCollections').by('id', colId); if (type === "col") { - ({ paths, ids } = getPath(results, "", {}, [], "source")); + ({ paths, ids } = getPath(colItem, "", {}, [], "source")); } else { - let item = findItem(results, folderId); + let item = findItem(colItem, folderId); ({ paths, ids } = getPath(item, "", {}, [], "source")); } ids = ids.reverse(); - GetColsRequests(ids, paths, webview); + GetColsRequests(ids, paths, webview); + + if (colItem) { + if (folderId) { + settings = findParentSettings(colItem, folderId); + if (!settings) { + settings = JSON.parse(JSON.stringify(InitialSettings)) as ISettings; + } + } else { + settings = colItem.settings ? colItem.settings : JSON.parse(JSON.stringify(InitialSettings));; + } + + if (webview) { + webview.postMessage({ type: responseTypes.getParentSettingsResponse, settings: settings }); + } + } }); } catch (err) { @@ -883,7 +901,7 @@ export function GetCollectionSettings(webview: vscode.Webview, colId: string, fo } if (webview) { - webview.postMessage({ type: responseTypes.getColSettingsResponse, data: { settings: settings, type: folderId ? SettingsType.Folder : SettingsType.Collection } }); + webview.postMessage({ type: responseTypes.getColSettingsResponse, data: { settings: settings, type: folderId ? SettingsType.Folder : SettingsType.Collection, variableId: colItem.variableId } }); } } }); @@ -898,15 +916,15 @@ export function GetParentSettings(colId: string, folderId: string, webview: vsco const db = getDB(); db.loadDatabase({}, function () { - let settings: any; + let settings: ISettings; const colItem = db.getCollection('userCollections').by("id", colId); if (colItem) { if (folderId) { - settings = findParentSettings(colItem, folderId, null); + settings = findParentSettings(colItem, folderId); if (!settings) { - settings = JSON.parse(JSON.stringify(InitialSettings)); + settings = JSON.parse(JSON.stringify(InitialSettings)) as ISettings; } } else { settings = colItem.settings ? colItem.settings : JSON.parse(JSON.stringify(InitialSettings));; @@ -940,7 +958,7 @@ export function GetParentSettingsSync(colId: string, folderId: string) { if (colItem) { if (folderId) { - settings = findParentSettings(colItem, folderId, null); + settings = findParentSettings(colItem, folderId); if (!settings) { settings = JSON.parse(JSON.stringify(InitialSettings)); } @@ -970,7 +988,7 @@ export function ExecuteRequest(reqData: any, fetchConfig: FetchConfig, webview: if (colItem) { if (reqData.data.folderId) { - settings = findParentSettings(colItem, reqData.data.folderId, null); + settings = findParentSettings(colItem, reqData.data.folderId); if (!settings) { settings = JSON.parse(JSON.stringify(InitialSettings)); } @@ -978,7 +996,7 @@ export function ExecuteRequest(reqData: any, fetchConfig: FetchConfig, webview: settings = colItem.settings ? colItem.settings : JSON.parse(JSON.stringify(InitialSettings));; } - apiFetch(reqData.data.reqData, reqData.data.variableData, settings, fetchConfig).then((data) => { + apiFetch(reqData.data.reqData, reqData.data.variableData, settings, null, fetchConfig).then((data) => { webview.postMessage(data); }); } @@ -1009,7 +1027,7 @@ export function ExecuteMultipleRequest(reqData: any, fetchConfig: FetchConfig, w } if (id) { - settings = findParentSettings(colItem, id, null); + settings = findParentSettings(colItem, id); if (!settings) { settings = JSON.parse(JSON.stringify(InitialSettings)); } @@ -1017,10 +1035,10 @@ export function ExecuteMultipleRequest(reqData: any, fetchConfig: FetchConfig, w settings = colItem.settings ? colItem.settings : JSON.parse(JSON.stringify(InitialSettings));; } - requests.push(apiFetch(item, reqData.data.variableData, settings, fetchConfig)); + requests.push(apiFetch(item, reqData.data.variableData, settings, null, fetchConfig)); } } else { - requests.push(apiFetch(item, reqData.data.variableData, null, fetchConfig)); + requests.push(apiFetch(item, reqData.data.variableData, null, null, fetchConfig)); } }); diff --git a/src/utils/db/constants.ts b/src/utils/db/constants.ts index da70bbb..e23f4f8 100644 --- a/src/utils/db/constants.ts +++ b/src/utils/db/constants.ts @@ -1,9 +1,11 @@ export enum ImportType { FetchClient_1_0 = "FetchClient_1_0", Postman_2_1 = "Postman_2_1", + ThunderClient_1_2 = "ThunderClient_1_2" } export enum VariableImportType { FetchClient_Variable_1_0 = "FetchClient_Variable_1_0", Postman_Variable_2_1 = "Postman_Variable_2_1", + ThunderClient_Variable_1_2 = "ThunderClient_Variable_1_2" } diff --git a/src/utils/db/cookieDBUtil.ts b/src/utils/db/cookieDBUtil.ts index 8517425..b952e74 100644 --- a/src/utils/db/cookieDBUtil.ts +++ b/src/utils/db/cookieDBUtil.ts @@ -1,13 +1,14 @@ -import * as vscode from 'vscode'; import loki, { LokiFsAdapter } from 'lokijs'; +import * as vscode from 'vscode'; +import { ICookie } from '../../fetch-client-ui/components/Cookies/redux/types'; import { responseTypes } from '../configuration'; import { writeLog } from '../logger/logger'; -import { ICookie } from '../../fetch-client-ui/components/Cookies/redux/types'; import { cookieDBPath } from './dbPaths'; function getDB(): loki { const idbAdapter = new LokiFsAdapter(); - const db = new loki(cookieDBPath(), { adapter: idbAdapter }); + const db = new loki(cookieDBPath(), { adapter: idbAdapter, autosave: true, autosaveInterval: 1000 }); + db.autosaveEnable(); return db; } diff --git a/src/utils/db/dbUtil.ts b/src/utils/db/dbUtil.ts index f74975b..17eeee9 100644 --- a/src/utils/db/dbUtil.ts +++ b/src/utils/db/dbUtil.ts @@ -20,7 +20,7 @@ export function CreateHistoryDB(): any { autoload: true, autoloadCallback: dbInitialize, autosave: true, - autosaveInterval: 4000, + autosaveInterval: 1000, serializationMethod: "normal", adapter: idbAdapter, }); @@ -53,7 +53,7 @@ export function CreateCollectionDB(): any { autoload: true, autoloadCallback: dbInitialize, autosave: true, - autosaveInterval: 4000, + autosaveInterval: 1000, serializationMethod: "normal", adapter: idbAdapter, }); @@ -87,7 +87,7 @@ export function CreateMainDB(): any { autoload: true, autoloadCallback: dbInitialize, autosave: true, - autosaveInterval: 4000, + autosaveInterval: 1000, serializationMethod: "normal", adapter: idbAdapter, }); @@ -118,7 +118,7 @@ export function CreateVariableDB(): any { autoload: true, autoloadCallback: dbInitialize, autosave: true, - autosaveInterval: 4000, + autosaveInterval: 1000, serializationMethod: "normal", adapter: idbAdapter, }); @@ -150,7 +150,7 @@ export function CreateCookieDB(): any { autoload: true, autoloadCallback: dbInitialize, autosave: true, - autosaveInterval: 4000, + autosaveInterval: 1000, serializationMethod: "normal", adapter: idbAdapter, }); diff --git a/src/utils/db/historyDBUtil.ts b/src/utils/db/historyDBUtil.ts index 399b93f..a065ba4 100644 --- a/src/utils/db/historyDBUtil.ts +++ b/src/utils/db/historyDBUtil.ts @@ -1,16 +1,17 @@ -import * as vscode from "vscode"; import loki, { LokiFsAdapter } from "lokijs"; +import * as vscode from "vscode"; import { IHistory } from "../../fetch-client-ui/components/SideBar/redux/types"; import { responseTypes } from '../configuration'; -import { getHistoryLimitConfiguration } from '../vscodeConfig'; -import { DeleteExitingItem, DeleteExitingItems, RenameRequestItem } from './mainDBUtil'; import { writeLog } from '../logger/logger'; +import { getHistoryLimitConfiguration } from '../vscodeConfig'; import { historyDBPath } from "./dbPaths"; +import { DeleteExitingItem, DeleteExitingItems, RenameRequestItem } from './mainDBUtil'; function getDB(): loki { const idbAdapter = new LokiFsAdapter(); - const db = new loki(historyDBPath(), { adapter: idbAdapter }); + const db = new loki(historyDBPath(), { adapter: idbAdapter, autosave: true, autosaveInterval: 1000 }); + db.autosaveEnable(); return db; } diff --git a/src/utils/db/mainDBUtil.ts b/src/utils/db/mainDBUtil.ts index d4edf2b..67ce018 100644 --- a/src/utils/db/mainDBUtil.ts +++ b/src/utils/db/mainDBUtil.ts @@ -1,36 +1,41 @@ -import * as vscode from "vscode"; import fs from "fs"; import loki, { LokiFsAdapter } from "lokijs"; -import { FetchClientDataProxy } from '../validators/fetchClientCollectionValidator'; -import { fetchClientImporter } from '../importers/fetchClientImporter_1_0'; -import { formatDate } from '../helper'; -import { ICollections, IFolder, IHistory } from '../../fetch-client-ui/components/SideBar/redux/types'; -import { InitialSettings } from '../../fetch-client-ui/components/SideBar/redux/reducer'; +import * as vscode from "vscode"; import { IRequestModel } from '../../fetch-client-ui/components/RequestUI/redux/types'; +import { InitialSettings } from '../../fetch-client-ui/components/SideBar/redux/reducer'; +import { ICollections, IFolder, IHistory } from '../../fetch-client-ui/components/SideBar/redux/types'; import { isFolder } from '../../fetch-client-ui/components/SideBar/util'; import { isJson } from '../../fetch-client-ui/components/TestUI/TestPanel/helper'; -import { postmanImporter } from '../importers/postmanImporter_2_1'; -import { PostmanSchema_2_1, POSTMAN_SCHEMA_V2_1 } from '../importers/postman_2_1.types'; import { responseTypes } from '../configuration'; +import { formatDate } from '../helper'; +import { fetchClientImporter } from '../importers/fetchClient/fetchClientImporter_1_0'; +import { postmanImporter } from '../importers/postman/postmanImporter_2_1'; +import { POSTMAN_SCHEMA_V2_1, PostmanSchema_2_1 } from '../importers/postman/postman_2_1.types'; import { writeLog } from '../logger/logger'; -import { collectionDBPath, mainDBPath, variableDBPath } from "./dbPaths"; +import { FetchClientDataProxy } from '../validators/fetchClientCollectionValidator'; import { ImportType } from "./constants"; +import { collectionDBPath, mainDBPath, variableDBPath } from "./dbPaths"; +import { thunderClientImporter } from "../importers/thunderClient/thunderClientImporter_1_2"; +import { ThunderClient_Schema_1_2 } from "../importers/thunderClient/thunderClient_1_2_types"; function getDB(): loki { const idbAdapter = new LokiFsAdapter(); const db = new loki(mainDBPath(), { adapter: idbAdapter }); + db.autosaveDisable(); return db; } function getCollectionDB(): loki { const idbAdapter = new LokiFsAdapter(); const db = new loki(collectionDBPath(), { adapter: idbAdapter }); + db.autosaveDisable(); return db; } function getVariableDB(): loki { const idbAdapter = new LokiFsAdapter(); const db = new loki(variableDBPath(), { adapter: idbAdapter }); + db.autosaveDisable(); return db; } @@ -93,14 +98,14 @@ export function GetRequestItem(reqId: string) { } } -export function GetExitingItem(webview: vscode.Webview, id: string, callback: any = null) { +export function GetExitingItem(webview: vscode.Webview, id: string, callback: any = null, type: string = null) { try { const db = getDB(); db.loadDatabase({}, function () { const results = db.getCollection("apiRequests").chain().find({ 'id': id }).data(); if (webview) { - webview.postMessage({ type: responseTypes.openExistingItemResponse, item: results }); + webview.postMessage({ type: type === "OpenAndRun" ? responseTypes.getOpenAndRunItemDataResponse : responseTypes.openExistingItemResponse, item: results }); } if (callback) { @@ -129,6 +134,7 @@ export function CopyExitingItems(oldIds: string[], ids: any) { if (results && results.length > 0) { results.forEach(item => { item.id = ids[item.id]; + item.name = item.name + " (Copy)"; }); apiRequests.insert(results); @@ -308,6 +314,16 @@ function ValidateData(data: string): ImportType | null { if (postmanData.info?._postman_id && postmanData.info?.schema === POSTMAN_SCHEMA_V2_1) { return ImportType.Postman_2_1; } + + let thunderClientData = JSON.parse(data) as ThunderClient_Schema_1_2; + if (thunderClientData.clientName = "Thunder Client") { + if (thunderClientData.version !== "1.2") { + vscode.window.showErrorMessage("Could not import the variable - Invalid version.", { modal: true }); + return null; + } + return ImportType.ThunderClient_1_2; + } + return null; } } @@ -338,6 +354,9 @@ export function Import(webviewView: vscode.WebviewView, path: string) { case ImportType.Postman_2_1: ImportPostman(webviewView, data); break; + case ImportType.ThunderClient_1_2: + ImportThunderClient(webviewView, data); + break; default: vscode.window.showErrorMessage("Could not import the collection - Invalid data.", { modal: true }); } @@ -382,6 +401,29 @@ function ImportPostman(webviewView: vscode.WebviewView, data: string) { } } +function ImportThunderClient(webviewView: vscode.WebviewView, data: string) { + try { + const convertedData = thunderClientImporter(data); + if (!convertedData || !convertedData.fcCollection || !convertedData.fcRequests) { + return; + } + + const db = getDB(); + const colDB = getCollectionDB(); + + db.loadDatabase({}, function () { + const apiRequests = db.getCollection("apiRequests"); + apiRequests.insert(convertedData.fcRequests); + db.saveDatabase(); + + insertCollections(colDB, webviewView, convertedData.fcCollection); + }); + } catch (err) { + vscode.window.showErrorMessage("Could not import the collection - Invalid data.", { modal: true }); + writeLog("error::ImportThunderClient(): - Error Message : " + err); + } +} + function ImportFC(webviewView: vscode.WebviewView, data: string) { try { const parsedData = JSON.parse(data); diff --git a/src/utils/db/transferDBConfig.ts b/src/utils/db/transferDBConfig.ts index 684cf44..9d44d57 100644 --- a/src/utils/db/transferDBConfig.ts +++ b/src/utils/db/transferDBConfig.ts @@ -13,24 +13,46 @@ import path from "path"; * And the db files should be moved to the global path if the option is disabled. */ export const transferDbConfig = () => { - let customPath = getExtLocalDbPath(); - + const customPath = getExtLocalDbPath(); const pathState = getSaveToWorkspaceConfiguration(); - const actualPath = getGlobalStorageUri(); + const files = ['fetchClientCookies.db', 'fetchClientHistory.db', 'fetchClientCollection.db', 'fetchClient.db', 'fetchClientVariable.db', 'fetch-client.log']; + const dbFile = path.resolve(customPath, "fetchClientCollection.db"); if (actualPath && customPath && actualPath !== customPath) { if (pathState) { - // First time taking bakeup of the data + // First time taking bakeup of the data in actual global path let bkpPath = getExtDbBKPPath(); if (!fs.existsSync(bkpPath)) { fs.cpSync(actualPath, bkpPath, { recursive: true }); } - fs.renameSync(actualPath, customPath); + + // Check if files are already available in the workspace path + if (fs.existsSync(dbFile)) { + let customBKPPath = path.resolve(customPath, "BKP"); + if (!fs.existsSync(customBKPPath)) { + fs.mkdirSync(customBKPPath, { recursive: true }); + } + + // Copy all files to backup path in custom folder + files.forEach(file => { + fs.cpSync(path.resolve(customPath, file), path.resolve(customBKPPath, file), { recursive: true, force: true }); + }); + } + + // Copy all files to custom folder + files.forEach(file => { + fs.cpSync(path.resolve(actualPath, file), path.resolve(customPath, file), { recursive: true, force: true }); + fs.unlinkSync(path.resolve(actualPath, file)); + }); updateWorkspacePathConfiguration(customPath); } else { - - fs.renameSync(customPath, actualPath); + + // Copy all files to actual global path + files.forEach(file => { + fs.cpSync(path.resolve(customPath, file), path.resolve(actualPath, file), { recursive: true, force: true }); + fs.unlinkSync(path.resolve(customPath, file)); + }); updateWorkspacePathConfiguration(""); } } diff --git a/src/utils/db/varDBUtil.ts b/src/utils/db/varDBUtil.ts index 6f7fa03..b3a9db8 100644 --- a/src/utils/db/varDBUtil.ts +++ b/src/utils/db/varDBUtil.ts @@ -1,23 +1,24 @@ -import * as vscode from 'vscode'; -import loki, { LokiFsAdapter } from 'lokijs'; import fs from "fs"; +import loki, { LokiFsAdapter } from 'lokijs'; import { v4 as uuidv4 } from 'uuid'; +import * as vscode from 'vscode'; +import { pubSub } from '../../extension'; +import { ITableData } from '../../fetch-client-ui/components/Common/Table/types'; import { IVariable } from "../../fetch-client-ui/components/SideBar/redux/types"; import { pubSubTypes, responseTypes } from '../configuration'; +import { formatDate } from '../helper'; +import { PostmanVariableSchema_2_1 } from '../importers/postman/postman_2_1.variable_types'; import { writeLog } from '../logger/logger'; -import { pubSub } from '../../extension'; import { FetchClientVariableProxy } from '../validators/fetchClientVariableValidator'; -import { formatDate } from '../helper'; import { RemoveVariable } from './collectionDBUtil'; +import { VariableImportType } from './constants'; import { variableDBPath } from './dbPaths'; -import { ImportType, VariableImportType } from './constants'; -import { IValue, PostmanVariableSchema_2_1 } from '../importers/postman_2_1.variable_types'; -import { ITableData } from '../../fetch-client-ui/components/Common/Table/types'; - +import { ThunderClientVariableSchema_1_2 } from "../importers/thunderClient/thunderClient_1_2.variable_types"; function getDB(): loki { const idbAdapter = new LokiFsAdapter(); const db = new loki(variableDBPath(), { adapter: idbAdapter }); + db.autosaveDisable(); return db; } @@ -87,15 +88,17 @@ export function UpdateVariable(item: IVariable, webview: vscode.Webview) { db.loadDatabase({}, function () { db.getCollection("userVariables").findAndUpdate({ 'id': item.id }, itm => { itm.data = item.data; }); - db.saveDatabase(); - - if (webview) { - webview.postMessage({ type: responseTypes.updateVariableResponse }); - } + db.saveDatabase(function (err) { + if (!err) { + if (webview) { + webview.postMessage({ type: responseTypes.updateVariableResponse }); + } - if (pubSub.size > 0) { - pubSub.publish({ messageType: pubSubTypes.updateVariables }); - } + if (pubSub.size > 0) { + pubSub.publish({ messageType: pubSubTypes.updateVariables }); + } + } + }); }); } catch (err) { @@ -103,6 +106,25 @@ export function UpdateVariable(item: IVariable, webview: vscode.Webview) { } } +export function UpdateVariableSync(item: IVariable) { + try { + return new Promise(async (resolve, _reject) => { + const db = getDB(); + db.loadDatabase({}, function () { + db.getCollection("userVariables").findAndUpdate({ 'id': item.id }, itm => { itm.data = item.data; }); + db.saveDatabase(function (err) { + if (!err) { + let vars = db.getCollection("userVariables").find({ 'id': item.id }); + resolve(vars && vars.length > 0 ? vars[0] as IVariable : null); + } + }); + }); + }); + } catch (err) { + writeLog("error::UpdateVariableSync(): " + err); + } +} + export function GetAllVariable(webview: vscode.Webview) { try { const db = getDB(); @@ -133,17 +155,14 @@ export function GetVariableById(id: string, isGlobal: boolean, webview: vscode.W export function GetVariableByIdSync(id: string) { try { - return new Promise((resolve, _reject) => { + return new Promise(async (resolve, _reject) => { const db = getDB(); - - db.loadDatabase({}, function (err: any) { - if (err) { - resolve(null); - } - let userVariables = db.getCollection("userVariables").find(id ? { 'id': id } : { 'name': 'Global' }); + db.loadDatabase({}, function () { + let userVariables = db.getCollection("userVariables").find({ 'id': id }); resolve(userVariables && userVariables.length > 0 ? userVariables[0] as IVariable : null); }); }); + } catch (err) { writeLog("error::GetVariableByIdSync(): " + err); } @@ -249,9 +268,19 @@ function ValidateData(data: string): VariableImportType | null { return VariableImportType.FetchClient_Variable_1_0; } catch (err) { let postmanData = JSON.parse(data) as PostmanVariableSchema_2_1; - if (postmanData._postman_variable_scope && postmanData._postman_exported_using) { + if (postmanData?._postman_variable_scope && postmanData?._postman_exported_using) { return VariableImportType.Postman_Variable_2_1; } + + let thunderClientData = JSON.parse(data) as ThunderClientVariableSchema_1_2; + if (thunderClientData?.clientName === "Thunder Client" && thunderClientData?.ref) { + if (thunderClientData?.version !== "1.2") { + vscode.window.showErrorMessage("Could not import the variable - Invalid version.", { modal: true }); + return null; + } + return VariableImportType.ThunderClient_Variable_1_2; + } + return null; } } @@ -273,6 +302,9 @@ export function ImportVariableFromJsonFile(webviewView: vscode.WebviewView, path case VariableImportType.Postman_Variable_2_1: ImportPostmanVariable(webviewView, data); break; + case VariableImportType.ThunderClient_Variable_1_2: + ImportThunderClientVariable(webviewView, data); + break; default: vscode.window.showErrorMessage("Could not import the collection - Invalid type.", { modal: true }); } @@ -292,31 +324,57 @@ function ImportFetchClientVariable(webviewView: vscode.WebviewView, data: string function ImportPostmanVariable(webviewView: vscode.WebviewView, data: string) { const parsedData = JSON.parse(data) as PostmanVariableSchema_2_1; - let convertedData: IVariable; - let varData: ITableData[] = []; - for (let i = 0; i < parsedData.values.length; i++) { - varData.push({ - isChecked: parsedData.values[i].enabled, - key: parsedData.values[i].key, - value: parsedData.values[i].value - }); - } - - if (parsedData._postman_exported_using.includes("Postman/") && parsedData._postman_variable_scope.includes("environment")) { - convertedData = { - id: uuidv4(), - createdTime: formatDate(), - name: parsedData.name, - isActive: true, - data: varData - }; - } else { + if (!parsedData?._postman_exported_using?.includes("Postman/") || !parsedData?._postman_variable_scope?.includes("environment")) { writeLog("error::ImportPostmanVariable(): - Error Mesaage : Could not import the variable - Invalid data."); throw new Error("Could not import the variable - Invalid data."); } + for (let i = 0; i < parsedData.values?.length; i++) { + if (parsedData.values[i].key) { + varData.push({ + isChecked: parsedData.values[i].enabled, + key: parsedData.values[i].key, + value: parsedData.values[i].value + }); + } + } + + let convertedData: IVariable = { + id: uuidv4(), + createdTime: formatDate(), + name: parsedData.name, + isActive: true, + data: varData + }; + + ImportVariable(webviewView, convertedData); +} + +function ImportThunderClientVariable(webviewView: vscode.WebviewView, data: string) { + const parsedData = JSON.parse(data) as ThunderClientVariableSchema_1_2; + + let varData: ITableData[] = []; + + for (let i = 0; i < parsedData.variables?.length; i++) { + if (parsedData.variables[i].name) { + varData.push({ + isChecked: true, + key: parsedData.variables[i].name, + value: parsedData.variables[i].value + }); + } + } + + let convertedData: IVariable = { + id: uuidv4(), + createdTime: formatDate(), + name: parsedData.environmentName, + isActive: true, + data: varData + }; + ImportVariable(webviewView, convertedData); } diff --git a/src/utils/fetchUtil.ts b/src/utils/fetchUtil.ts index 4929eb9..273d4f5 100644 --- a/src/utils/fetchUtil.ts +++ b/src/utils/fetchUtil.ts @@ -1,6 +1,6 @@ -import { getErrorResponse, getFileType, getRandomNumber, isFileType, replaceAuthSettingsInRequest, replaceValueWithVariable } from "./helper"; +import { getErrorResponse, getFileType, getRandomNumber, isFileType, replaceAuthSettingsInRequest, replaceHeaderSettingsInRequest, replaceValueWithVariable } from "./helper"; import { getProtocolConfiguration, getSSLConfiguration } from "./vscodeConfig"; -import { IRequestModel } from "../fetch-client-ui/components/RequestUI/redux/types"; +import { IReqSettings, IRequestModel } from "../fetch-client-ui/components/RequestUI/redux/types"; import { ISettings } from "../fetch-client-ui/components/SideBar/redux/types"; import { ITableData } from "../fetch-client-ui/components/Common/Table/types"; import { logDetails } from "./logger/requestLog"; @@ -27,27 +27,33 @@ export const updateAuthSettings = (requestData: IRequestModel, settings?: ISetti return requestData; }; +export const updateHeaderSettings = (requestData: IRequestModel, settings?: ISettings): IRequestModel => { + if (settings?.headers && settings?.headers?.length > 0) { + let copyData = JSON.parse(JSON.stringify(requestData)); + return replaceHeaderSettingsInRequest(copyData, settings); + } + return requestData; +}; + export const updateVariables = (requestData: IRequestModel, variableData?: ITableData[]): IRequestModel => { let varData = {}; if (variableData?.length > 0) { variableData.forEach(item => { varData[item.key] = item.value; }); - let copy = JSON.parse(JSON.stringify(requestData)); - return replaceValueWithVariable(copy, varData); } - - return requestData; + let copy = JSON.parse(JSON.stringify(requestData)); + return replaceValueWithVariable(copy, varData); }; export const apiFetch = async ( requestData: IRequestModel, variableData: ITableData[], settings: ISettings, + reqSettings: IReqSettings, fetchConfig: FetchConfig, resType: string = responseTypes.apiResponse ) => { - const reqHeaders = {}; let startTime: number, fetchDuration: number; let reqData: any = ""; @@ -56,6 +62,10 @@ export const apiFetch = async ( let request = updateAuthSettings(requestData, settings); request = updateVariables(request, variableData); + if (!reqSettings || reqSettings?.skipParentHeaders === false) { + request = updateHeaderSettings(request, settings); + } + try { if (request.auth.authType === "bearertoken") { reqHeaders[fetchConfig.headersCase ? "Authorization" : "authorization"] = `${request.auth.tokenPrefix} ${request.auth.password}`; @@ -115,7 +125,7 @@ export const apiFetch = async ( if (request.body.bodyType !== "none" && !reqHeaders["Content-Type"] && !reqHeaders["content-type"]) { reqHeaders[fetchConfig.headersCase ? "Content-Type" : "content-type"] = getContentType(request.body.bodyType, request.body.bodyType === "raw" ? request.body.raw.lang : ""); } - } + } https.globalAgent.options.rejectUnauthorized = getSSLConfiguration(); @@ -256,8 +266,8 @@ export const apiFetch = async ( } setTimeout(() => { - logDetails(request, reqHeaders, reqData, resp.status, respHeaders, isFile ? "View Response is not supported for 'file' type in the log window." : responseData); - }, 1000); + logDetails(request, reqHeaders, reqData, resp.status, respHeaders, isFile ? "View Response is not supported for 'file' type in the log window." : responseData, fetchDuration); + }, 500); return apiResponse = { type: resType, @@ -283,7 +293,7 @@ export const apiFetch = async ( apiResponse = getErrorResponse(); setTimeout(() => { - logDetails(request, reqHeaders, reqData, apiResponse.response.status, apiResponse.headers, err.message); + logDetails(request, reqHeaders, reqData, apiResponse.response.status, apiResponse.headers, err.message, fetchDuration); }, 1000); if (axios.isCancel(err)) { diff --git a/src/utils/helper.ts b/src/utils/helper.ts index 80a311b..fb04769 100644 --- a/src/utils/helper.ts +++ b/src/utils/helper.ts @@ -1,4 +1,4 @@ -import { checkSysVariable, getSysVariableWithValue, SysVariables } from "../fetch-client-ui/components/Common/Consts/sysVariables"; +import { checkSysVariable, getSysVariableWithValue } from "../fetch-client-ui/components/Common/Consts/sysVariables"; import { ITableData } from "../fetch-client-ui/components/Common/Table/types"; import { IRequestModel } from "../fetch-client-ui/components/RequestUI/redux/types"; import { ISettings } from "../fetch-client-ui/components/SideBar/redux/types"; @@ -221,6 +221,21 @@ export function replaceAuthSettingsInRequest(request: IRequestModel, settings: I return request; } +export function replaceHeaderSettingsInRequest(request: IRequestModel, settings: ISettings): IRequestModel { + if (settings.headers) { + settings.headers.forEach((header) => { + if (header.isChecked && header.key) { + let index = request.headers.findIndex(item => (item.key.toLowerCase() === header.key.toLowerCase()) && item.isChecked); + if (index === -1) { + request.headers.push(header); + } + } + }); + } + + return request; +} + function replaceTableDataWithVariable(data: ITableData[], varData: any) { const re = new RegExp("({{([^}}]+)}})"); data.forEach(item => { @@ -261,11 +276,13 @@ function updateVariable(item: string, data: string, varData: any) { data = data.replace(item, value?.toString()); } } else { - let replacedValue = varData[item.replace("{{", "").replace("}}", "")]; - if (replacedValue && checkVariableMatch(replacedValue)) { - data = data.replace(item, replaceDataWithVariable(replacedValue, varData)); - } else { - data = data.replace(item, varData[item.replace("{{", "").replace("}}", "")]); + if (varData && Object.keys(varData).length > 0) { + let replacedValue = varData[item.replace("{{", "").replace("}}", "")]; + if (replacedValue && checkVariableMatch(replacedValue)) { + data = data.replace(item, replaceDataWithVariable(replacedValue, varData)); + } else { + data = data.replace(item, varData[item.replace("{{", "").replace("}}", "")]); + } } } diff --git a/src/utils/importers/fetchClientImporter_1_0.ts b/src/utils/importers/fetchClient/fetchClientImporter_1_0.ts similarity index 84% rename from src/utils/importers/fetchClientImporter_1_0.ts rename to src/utils/importers/fetchClient/fetchClientImporter_1_0.ts index a9f82e0..b8df233 100644 --- a/src/utils/importers/fetchClientImporter_1_0.ts +++ b/src/utils/importers/fetchClient/fetchClientImporter_1_0.ts @@ -1,10 +1,10 @@ -import { formatDate } from "../helper"; -import { ICollections, IFolder, IHistory } from "../../fetch-client-ui/components/SideBar/redux/types"; -import { InitialSettings } from "../../fetch-client-ui/components/SideBar/redux/reducer"; -import { IRequestModel } from "../../fetch-client-ui/components/RequestUI/redux/types"; -import { isFolder } from "../../fetch-client-ui/components/SideBar/util"; import { v4 as uuidv4 } from "uuid"; -import { writeLog } from "../logger/logger"; +import { IRequestModel } from "../../../fetch-client-ui/components/RequestUI/redux/types"; +import { InitialSettings } from "../../../fetch-client-ui/components/SideBar/redux/reducer"; +import { ICollections, IFolder, IHistory } from "../../../fetch-client-ui/components/SideBar/redux/types"; +import { isFolder } from "../../../fetch-client-ui/components/SideBar/util"; +import { formatDate } from "../../helper"; +import { writeLog } from "../../logger/logger"; export const fetchClientImporter = (parsedData: any): { fcCollection: ICollections, fcRequests: IRequestModel[] } | null => { try { diff --git a/src/utils/importers/postmanImporter_2_1.ts b/src/utils/importers/postman/postmanImporter_2_1.ts similarity index 92% rename from src/utils/importers/postmanImporter_2_1.ts rename to src/utils/importers/postman/postmanImporter_2_1.ts index 705c3eb..fab4489 100644 --- a/src/utils/importers/postmanImporter_2_1.ts +++ b/src/utils/importers/postman/postmanImporter_2_1.ts @@ -1,14 +1,14 @@ -import { ICollections, IFolder, IHistory, ISettings, IVariable } from "../../fetch-client-ui/components/SideBar/redux/types"; -import { Auth, Header, Items, PostmanSchema_2_1, RequestObject, URLObject, Variable, Body, POSTMAN_SCHEMA_V2_1 } from "./postman_2_1.types"; -import { v4 as uuidv4 } from "uuid"; -import { formatDate } from "../helper"; -import { InitialSettings } from "../../fetch-client-ui/components/SideBar/redux/reducer"; -import { ClientAuth, GrantType, IAuth, IBodyData, IRequestModel, MethodType } from "../../fetch-client-ui/components/RequestUI/redux/types"; -import { InitialAuth, InitialBody, InitialPreFetch, InitialSetVar, InitialTest } from "../../fetch-client-ui/components/RequestUI/redux/reducer"; -import { ITableData } from "../../fetch-client-ui/components/Common/Table/types"; -import { isJson } from "../../fetch-client-ui/components/TestUI/TestPanel/helper"; import { XMLValidator } from "fast-xml-parser"; -import { writeLog } from "../logger/logger"; +import { v4 as uuidv4 } from "uuid"; +import { ITableData } from "../../../fetch-client-ui/components/Common/Table/types"; +import { InitialAuth, InitialBody, InitialPreFetch, InitialSetVar, InitialTest } from "../../../fetch-client-ui/components/RequestUI/redux/reducer"; +import { ClientAuth, GrantType, IAuth, IBodyData, IRequestModel, MethodType } from "../../../fetch-client-ui/components/RequestUI/redux/types"; +import { InitialSettings } from "../../../fetch-client-ui/components/SideBar/redux/reducer"; +import { ICollections, IFolder, IHistory, ISettings, IVariable } from "../../../fetch-client-ui/components/SideBar/redux/types"; +import { isJson } from "../../../fetch-client-ui/components/TestUI/TestPanel/helper"; +import { formatDate } from "../../helper"; +import { writeLog } from "../../logger/logger"; +import { Auth, Body, Header, Items, POSTMAN_SCHEMA_V2_1, PostmanSchema_2_1, RequestObject, URLObject, Variable } from "./postman_2_1.types"; export class PostmanImport { private collection: PostmanSchema_2_1; @@ -400,9 +400,21 @@ export class PostmanImport { }; }; - importSettings = (auth: Auth | undefined | null) : ISettings => { + importSettings = (auth: Auth | undefined | null): ISettings => { let settings: ISettings = { - auth: this.getAuthDetails(auth) + auth: this.getAuthDetails(auth), + preFetch: { + requests: [] + }, + headers: [{ + key: "User-Agent", + value: "Fetch Client", + isChecked: true, + }, { + key: "", + value: "", + isChecked: false, + }] }; return settings; diff --git a/src/utils/importers/postman_2_1.types.ts b/src/utils/importers/postman/postman_2_1.types.ts similarity index 100% rename from src/utils/importers/postman_2_1.types.ts rename to src/utils/importers/postman/postman_2_1.types.ts diff --git a/src/utils/importers/postman_2_1.variable_types.ts b/src/utils/importers/postman/postman_2_1.variable_types.ts similarity index 100% rename from src/utils/importers/postman_2_1.variable_types.ts rename to src/utils/importers/postman/postman_2_1.variable_types.ts diff --git a/src/utils/importers/thunderClient/thunderClientImporter_1_2.ts b/src/utils/importers/thunderClient/thunderClientImporter_1_2.ts new file mode 100644 index 0000000..9ac0553 --- /dev/null +++ b/src/utils/importers/thunderClient/thunderClientImporter_1_2.ts @@ -0,0 +1,414 @@ +import { XMLValidator } from "fast-xml-parser"; +import { v4 as uuidv4 } from "uuid"; +import { ITableData } from "../../../fetch-client-ui/components/Common/Table/types"; +import { InitialAuth, InitialBody, InitialPreFetch, InitialRequestHeaders, InitialSetVar, InitialTest } from "../../../fetch-client-ui/components/RequestUI/redux/reducer"; +import { ClientAuth, GrantType, IAuth, IBodyData, IRequestModel, MethodType } from "../../../fetch-client-ui/components/RequestUI/redux/types"; +import { ICollections, IFolder, IHistory, ISettings } from "../../../fetch-client-ui/components/SideBar/redux/types"; +import { isFolder } from "../../../fetch-client-ui/components/SideBar/util"; +import { isJson } from "../../../fetch-client-ui/components/TestUI/TestPanel/helper"; +import { formatDate } from "../../helper"; +import { writeLog } from "../../logger/logger"; +import { Auth, BodyEntity, FoldersEntity, HeadersEntityOrFormEntity, ParamsEntity, RequestsEntity, Settings, ThunderClient_Schema_1_2 } from "./thunderClient_1_2_types"; +import { InitialSettings } from "../../../fetch-client-ui/components/SideBar/redux/reducer"; + + +export class ThunderClientImport { + private collection: ThunderClient_Schema_1_2; + + constructor(collection: ThunderClient_Schema_1_2) { + this.collection = collection; + } + + getParams = (params: ParamsEntity[]): ITableData[] => { + let fcParams: ITableData[] = []; + + if (params?.length > 0) { + params.forEach(item => { + fcParams.push({ + key: item.name, + value: item.value, + isChecked: !item.isDisabled + }); + }); + } + return [...fcParams, { + isChecked: false, + key: "", + value: "" + }]; + }; + + getHeaders = (headers?: HeadersEntityOrFormEntity[]): ITableData[] => { + let fcHeaders: ITableData[] = []; + + if (headers?.length > 0) { + headers.forEach(header => { + if (header.name) { + fcHeaders.push({ + isChecked: !header.isDisabled, + key: header.name, + value: header.value + }); + } + }); + + fcHeaders.push({ + key: "", + value: "", + isChecked: false, + }); + } else { + fcHeaders = JSON.parse(JSON.stringify(InitialRequestHeaders)); + } + + return fcHeaders; + }; + + getAuthDetails = (auth?: Auth): IAuth => { + + let fcAuth: IAuth = JSON.parse(JSON.stringify(InitialAuth)); + + if (!auth) { + fcAuth.authType = "inherit"; + return fcAuth; + } + + switch (auth.type) { + case "aws": + if (!auth.aws) { + return fcAuth; + } + + fcAuth.aws.accessKey = auth.aws.accessKeyId ?? ""; + fcAuth.aws.secretAccessKey = auth.aws.secretKey ?? ""; + fcAuth.aws.service = auth.aws.service ?? ""; + fcAuth.aws.sessionToken = auth.aws.sessionToken ?? ""; + fcAuth.aws.region = auth.aws.region ?? ""; + fcAuth.authType = "aws"; + + return fcAuth; + + + case "basic": + if (!auth.basic) { + return fcAuth; + } + + fcAuth.userName = auth.basic.username ?? ""; + fcAuth.password = auth.basic.password ?? ""; + fcAuth.authType = "basic"; + + return fcAuth; + + case "bearer": + if (!auth.bearer) { + return fcAuth; + } + + fcAuth.password = auth.bearer ?? ""; + fcAuth.tokenPrefix = auth.bearerPrefix ?? ""; + fcAuth.authType = "bearertoken"; + + return fcAuth; + + case "oauth2": + if (!auth.oauth2) { + return fcAuth; + } + + let grantType = auth.oauth2.grantType ?? ""; + + if (grantType !== "client_credentials" && grantType !== "password") { + return fcAuth; + } + + let clientAuth = auth.oauth2.clientAuth; + fcAuth.oauth.clientAuth = clientAuth === "in-header" ? ClientAuth.Header : ClientAuth.Body; + fcAuth.oauth.clientId = auth.oauth2.clientId ?? ""; + fcAuth.oauth.clientSecret = auth.oauth2.clientSecret ?? ""; + fcAuth.oauth.grantType = grantType === "client_credentials" ? GrantType.Client_Crd : GrantType.PWD_Crd; + fcAuth.oauth.password = auth.oauth2.password ?? ""; + fcAuth.oauth.username = auth.oauth2.username ?? ""; + fcAuth.oauth.scope = auth.oauth2.scope ?? ""; + fcAuth.oauth.tokenUrl = auth.oauth2.tokenUrl ?? ""; + + fcAuth.oauth.advancedOpt.resource = auth.oauth2.resource ?? ""; + fcAuth.oauth.advancedOpt.audience = auth.oauth2.audience ?? ""; + + fcAuth.authType = "oauth2"; + + return fcAuth; + + default: + return fcAuth; + } + }; + + getSrc = (src: any[] | null | string): string => { + if (!src) { + return ""; + } + + if (typeof src === "string") { + return src.length > 1 ? src.substring(1) : src; + } + + if (typeof src === "object") { + return src.length > 0 ? src[0].length > 1 ? src[0].substring(1) : src[0] : ""; + } + }; + + getBody = (body: BodyEntity): IBodyData => { + + let fcBody: IBodyData = JSON.parse(JSON.stringify(InitialBody)); + + if (!body) { + return fcBody; + } + + switch (body.type) { + case 'formdata': + fcBody.bodyType = "formdata"; + fcBody.formdata.shift(); + body.form?.forEach(item => { + fcBody.formdata.push({ + isChecked: item.isDisabled === true ? false : true, + key: item.name, + value: item.value, + type: "Text" + }); + }); + + body.files?.forEach(item => { + fcBody.formdata.push({ + isChecked: item.isDisabled === true ? false : true, + key: item.name, + value: item.value, + type: "File" + }); + }); + + fcBody.formdata.push({ + isChecked: false, + key: "", + value: "", + type: "Text" + }); + + return fcBody; + + case 'formencoded': + fcBody.bodyType = "formurlencoded"; + fcBody.urlencoded.shift(); + body.form?.forEach(item => { + fcBody.urlencoded.push({ + isChecked: item.isDisabled === true ? false : true, + key: item.name, + value: item.value + }); + }); + + fcBody.urlencoded.push({ + isChecked: false, + key: "", + value: "" + }); + + return fcBody; + + case 'graphql': + fcBody.bodyType = "graphql"; + fcBody.graphql.query = JSON.stringify(body.graphql.query); + fcBody.graphql.variables = JSON.stringify(body.graphql.variables); + return fcBody; + + case 'json': + case 'xml': + case 'text': + fcBody.bodyType = "raw"; + fcBody.raw.data = body.raw; + fcBody.raw.lang = this.getRawBodyType(body.raw.replace(/(?:\\[rn]|[\r\n]+)+/g, "")); + return fcBody; + + case 'binary': + fcBody.bodyType = "binary"; + fcBody.binary.fileName = body.binary; + fcBody.binary.contentTypeOption = "manual"; + return fcBody; + + default: + return fcBody; + } + }; + + getRawBodyType = (data: string): string => { + if (isJson(data) === "true") { + return "json"; + } + if (XMLValidator.validate(data) === true) { + return "xml"; + } + if (this.isHTML(data)) { + return "html"; + } + return "text"; + }; + + isHTML = (str: string) => !(str || '') + // replace html tag with content + .replace(/<([^>]+?)([^>]*?)>(.*?)<\/\1>/ig, '') + // remove remaining self closing tags + .replace(/(<([^>]+)>)/ig, '') + // remove extra space at start and end + .trim(); + + findValueByKey = (array?: T[], key?: string,) => { + if (!array) { + return ""; + } + + const obj = array.find(o => o.key === key); + + if (obj && typeof obj.value === "string") { + return obj.value || ""; + } + + return ""; + }; + + findObjectByKey = (array?: T[], key?: string,) => { + if (!array) { + return ""; + } + + const obj = array.find(o => o.key === key); + + if (obj && typeof obj.value === "object") { + return obj.value || undefined; + } + + return {}; + }; + + getRequestItem = (req: RequestsEntity): IRequestModel => { + let request: IRequestModel = { + id: uuidv4(), + url: req.url, + name: req.name, + createdTime: formatDate(), + method: req.method.toLocaleLowerCase() as MethodType, + params: this.getParams(req.params), + auth: this.getAuthDetails(req.auth), + headers: this.getHeaders(req.headers), + body: this.getBody(req.body), + tests: JSON.parse(JSON.stringify(InitialTest)), + setvar: JSON.parse(JSON.stringify(InitialSetVar)), + notes: "", + preFetch: JSON.parse(JSON.stringify(InitialPreFetch)) + }; + return request; + }; + + importFolderItem = (item: FoldersEntity): IFolder => { + return { + id: uuidv4(), + name: item.name, + type: "folder", + createdTime: formatDate(), + data: [], + settings: item.settings ? this.importSettings(item.settings) : JSON.parse(JSON.stringify(InitialSettings)) + }; + }; + + importSettings = (parentsettings: Settings): ISettings => { + let settings: ISettings = { + auth: this.getAuthDetails(parentsettings.auth), + preFetch: { requests: [] }, + headers: this.getHeaders(parentsettings.headers) + }; + + return settings; + }; + + getParentItem = (source: ICollections | IFolder, searchId: string): IFolder => { + let pos = source.data.findIndex((el: any) => el.id === searchId); + + if (pos !== -1) { + return (source.data[pos] as IFolder); + } + + for (let i = 0; i < source.data.length; i++) { + if (isFolder(source.data[i])) { + return this.getParentItem(source.data[i] as IFolder, searchId); + } + } + }; + + importCollection = (): { fcCollection: ICollections, fcRequests: IRequestModel[] } => { + let requests: IRequestModel[] = []; + let ids: { [id: string]: string } = {}; + + let collection: ICollections = { + id: uuidv4(), + name: this.collection.collectionName, + createdTime: formatDate(), + variableId: "", + data: [], + settings: this.collection.settings ? this.importSettings(this.collection.settings) : JSON.parse(JSON.stringify(InitialSettings)) + }; + + this.collection.folders?.forEach((folderItem: FoldersEntity) => { + let fcFolder = this.importFolderItem(folderItem); + ids[folderItem._id] = fcFolder.id; + if (folderItem.containerId) { + let parentFolder = this.getParentItem(collection, ids[folderItem.containerId]); + parentFolder.data.push(fcFolder); + } + else { + collection.data.push(fcFolder); + } + }); + + this.collection.requests?.forEach((request: RequestsEntity) => { + let req = this.getRequestItem(request); + + let history: IHistory = { + id: req.id, + name: req.name, + method: req.method, + url: req.url, + createdTime: formatDate() + }; + + requests.push(req); + + if (request.containerId) { + let folder = this.getParentItem(collection, ids[request.containerId]); + folder.data.push(history); + } + else { + collection.data.push(history); + } + }); + + return { + fcCollection: collection, + fcRequests: requests + }; + }; +}; + + +export const thunderClientImporter = (rawData: string): { fcCollection: ICollections, fcRequests: IRequestModel[] } | null => { + try { + const collection = JSON.parse(rawData) as ThunderClient_Schema_1_2; + if (collection.clientName === "Thunder Client") { + return new ThunderClientImport(collection).importCollection(); + } + } catch (err) { + writeLog("error::thunderClientImporter(): - Error Message : " + err); + return null; + } + + return null; +}; \ No newline at end of file diff --git a/src/utils/importers/thunderClient/thunderClient_1_2.variable_types.ts b/src/utils/importers/thunderClient/thunderClient_1_2.variable_types.ts new file mode 100644 index 0000000..f12673a --- /dev/null +++ b/src/utils/importers/thunderClient/thunderClient_1_2.variable_types.ts @@ -0,0 +1,13 @@ +export interface ThunderClientVariableSchema_1_2 { + clientName: string; + environmentName: string; + environmentId: string; + dateExported: string; + version: string; + variables?: (VariablesEntity)[]; + ref: string; +} +export interface VariablesEntity { + name: string; + value: string; +} diff --git a/src/utils/importers/thunderClient/thunderClient_1_2_types.ts b/src/utils/importers/thunderClient/thunderClient_1_2_types.ts new file mode 100644 index 0000000..e09db4d --- /dev/null +++ b/src/utils/importers/thunderClient/thunderClient_1_2_types.ts @@ -0,0 +1,104 @@ +export interface ThunderClient_Schema_1_2 { + clientName: string; + collectionName: string; + collectionId: string; + dateExported: string; + version: string; + folders?: (FoldersEntity)[] | null; + requests?: (RequestsEntity)[] | null; + settings: Settings; + ref: string; +} + +export interface FoldersEntity { + _id: string; + name: string; + containerId: string; + created: string; + sortNum: number; + settings: Settings; +} + +export interface RequestsEntity { + _id: string; + colId: string; + containerId: string; + name: string; + url: string; + method: string; + sortNum: number; + created: string; + modified: string; + headers?: HeadersEntityOrFormEntity[]; + params?: ParamsEntity[]; + body?: BodyEntity; + auth?: Auth; +} + +export interface ParamsEntity { + name: string; + value: string; + isPath: boolean; + isDisabled?: boolean; +} + +export interface BodyEntity { + type: string; + raw: string; + form?: HeadersEntityOrFormEntity[]; + graphql?: Graphql; + binary?: string; + files?: HeadersEntityOrFormEntity[]; +} + +export interface HeadersEntityOrFormEntity { + name: string; + value: string; + isDisabled?: boolean; +} + +export interface Graphql { + query: string; + variables: string; +} + +export interface Settings { + auth: Auth; + headers?: HeadersEntityOrFormEntity[]; +} + +export interface Auth { + type: string; + bearer?: string; + bearerPrefix?: string; + oauth2?: Oauth2; + aws?: Aws; + basic?: Basic; +} + +export interface Oauth2 { + grantType: string; + tokenUrl: string; + clientId: string; + clientSecret: string; + clientAuth: string; + scope: string; + username: string; + password: string; + tokenPrefix: string; + audience: string; + resource: string; +} + +export interface Aws { + accessKeyId: string; + secretKey: string; + region: string; + service: string; + sessionToken: string; +} + +export interface Basic { + username: string; + password: string; +} \ No newline at end of file diff --git a/src/utils/logger/requestLog.ts b/src/utils/logger/requestLog.ts index 60247a8..a388495 100644 --- a/src/utils/logger/requestLog.ts +++ b/src/utils/logger/requestLog.ts @@ -1,66 +1,69 @@ import { vsCodeLogger } from "../../extension"; import { ITableData } from "../../fetch-client-ui/components/Common/Table/types"; import { IRequestModel } from "../../fetch-client-ui/components/RequestUI/redux/types"; +import { GetResponseTime } from "../../fetch-client-ui/components/ResponseUI/OptionsPanel/OptionTab/util"; import { formatDateWithMs } from "../helper"; import { getLogOption } from "../vscodeConfig"; import { writeLog } from "./logger"; -export function logDetails(request: IRequestModel, reqHeaders: {}, requestBody: any, responseStatus: number, responseHeaders: ITableData[], responseData: any) { - logRequestDeatils(request, reqHeaders, requestBody); - if (getLogOption()) { - logResponseDeatils(responseStatus, responseHeaders, responseData); - } +export function logDetails(request: IRequestModel, reqHeaders: {}, requestBody: any, responseStatus: number, responseHeaders: ITableData[], responseData: any, duration: number) { + logRequestDeatils(request, reqHeaders, requestBody); + logResponseDeatils(responseStatus, responseHeaders, responseData, duration); } function logRequestDeatils(request: IRequestModel, reqHeaders: {}, requestBody: any) { - try { - let reqLog = `\n\n-----------------------------------------------------------------------------`; - reqLog = reqLog + `\nβ–Ά ${request.method.toUpperCase()} ${request.url}\n`; - reqLog = reqLog + `-----------------------------------------------------------------------------\n`; - reqLog = reqLog + `π˜™π˜¦π˜²π˜Άπ˜¦π˜΄π˜΅ π˜‹π˜¦π˜΅π˜’π˜ͺ𝘭𝘴: \n Url: ${request.url}\n Method: ${request.method.toUpperCase()}\n`; - reqLog = reqLog + ` Time: ${formatDateWithMs()}\n`; - if (request.headers.filter(i => i.isChecked)?.length > 0) { - reqLog = reqLog + ` Request Headers:`; - for (var prop in reqHeaders) { - reqLog = reqLog + `\n ${prop}: "${reqHeaders[prop]}"`; - } - } + try { + let reqLog = `\n\n-----------------------------------------------------------------------------`; + reqLog = reqLog + `\nβ–Ά ${request.method.toUpperCase()} ${request.url}\n`; + reqLog = reqLog + `-----------------------------------------------------------------------------\n`; + reqLog = reqLog + `π˜™π˜¦π˜²π˜Άπ˜¦π˜΄π˜΅ π˜‹π˜¦π˜΅π˜’π˜ͺ𝘭𝘴: \n Url: ${request.url}\n Method: ${request.method.toUpperCase()}\n`; + reqLog = reqLog + ` Time: ${formatDateWithMs()}\n`; + if (request.headers.filter(i => i.isChecked)?.length > 0) { + reqLog = reqLog + ` Request Headers:`; + for (var prop in reqHeaders) { + reqLog = reqLog + `\n ${prop}: "${reqHeaders[prop]}"`; + } + } - if (requestBody) { - reqLog = reqLog + `\n Request Body:\n`; - if (request.body.bodyType === "binary") { - reqLog = reqLog + ` src: ${request.body.binary.fileName}\n`; - } else if (request.body.bodyType === "formurlencoded") { - reqLog = reqLog + ` ${decodeURIComponent(requestBody.toString().replace(/\+/g, ' '))}`; - } else if (request.body.bodyType === "formdata") { - reqLog = reqLog + ` ${requestBody.getBuffer()}`; - } else { - reqLog = reqLog + ` ${requestBody}`; - } - } + if (requestBody) { + reqLog = reqLog + `\n Request Body:\n`; + if (request.body.bodyType === "binary") { + reqLog = reqLog + ` src: ${request.body.binary.fileName}\n`; + } else if (request.body.bodyType === "formurlencoded") { + reqLog = reqLog + ` ${decodeURIComponent(requestBody.toString().replace(/\+/g, ' '))}`; + } else if (request.body.bodyType === "formdata") { + reqLog = reqLog + ` ${requestBody.getBuffer()}`; + } else { + reqLog = reqLog + ` ${requestBody}`; + } + } - vsCodeLogger.log("INFO", reqLog); + vsCodeLogger.log("INFO", reqLog); - } catch (err) { - writeLog("error::logRequestDeatils(): " + err); - } + } catch (err) { + writeLog("error::logRequestDeatils(): " + err); + } } -function logResponseDeatils(status: number, headers: ITableData[], responseData: any) { - try { - let resLog = `\nπ˜™π˜¦π˜΄π˜±π˜°π˜―π˜΄π˜¦ π˜‹π˜¦π˜΅π˜’π˜ͺ𝘭𝘴: \n Status: ${status} ${status <= 399 ? "βœ…" : "❌"}\n`; - if (headers.length > 0) { - resLog = resLog + ` Response Headers:\n`; - headers.forEach(({ key, value }) => { - resLog = resLog + ` ${key}: "${value}"\n`; - }); - } +function logResponseDeatils(status: number, headers: ITableData[], responseData: any, duration: number) { + try { + let resLog = `\nπ˜™π˜¦π˜΄π˜±π˜°π˜―π˜΄π˜¦ π˜‹π˜¦π˜΅π˜’π˜ͺ𝘭𝘴: \n Status: ${status} ${status <= 399 ? "βœ…" : "❌"}\n`; + resLog = resLog + ` Time: ${GetResponseTime(duration)}\n\n`; - resLog = resLog + ` Response Body:\n`; - resLog = resLog + ` ${responseData}`; + if (getLogOption()) { + if (headers.length > 0) { + resLog = resLog + ` Response Headers:\n`; + headers.forEach(({ key, value }) => { + resLog = resLog + ` ${key}: "${value}"\n`; + }); + } - vsCodeLogger.log("INFO", resLog); - } catch (err) { - writeLog("error::logResponseDeatils(): " + err); - } + resLog = resLog + ` Response Body:\n`; + resLog = resLog + ` ${responseData}`; + } + + vsCodeLogger.log("INFO", resLog); + } catch (err) { + writeLog("error::logResponseDeatils(): " + err); + } } \ No newline at end of file diff --git a/src/utils/ui/addToCollectionUIProvider.tsx b/src/utils/ui/addToCollectionUIProvider.tsx index f22852b..298d6e6 100644 --- a/src/utils/ui/addToCollectionUIProvider.tsx +++ b/src/utils/ui/addToCollectionUIProvider.tsx @@ -2,12 +2,14 @@ import * as vscode from 'vscode'; import fs from "fs"; import { getStorageManager, OpenExistingItem, sideBarProvider } from '../../extension'; import { getNonce, requestTypes, responseTypes } from '../configuration'; -import { AddToCollection, AttachVariable, CopyToCollection, ExecuteMultipleRequest, ExecuteRequest, GetAllCollectionName, GetAllCollectionsById, GetCollectionSettings, GetParentSettings, SaveCollectionSettings } from '../db/collectionDBUtil'; +import { AddToCollection, AttachVariable, CopyToCollection, ExecuteMultipleRequest, ExecuteRequest, GetAllCollectionName, GetAllCollectionsById, GetAllCollectionsByIdWithPath, GetCollectionSettings, GetParentSettings, SaveCollectionSettings } from '../db/collectionDBUtil'; import { GetHistoryById } from '../db/historyDBUtil'; import { GetAllVariable, GetVariableById, UpdateVariable } from '../db/varDBUtil'; import { apiFetch, FetchConfig } from '../fetchUtil'; import { getHeadersConfiguration, getTimeOutConfiguration } from '../vscodeConfig'; import { writeLog } from '../logger/logger'; +import axios from 'axios'; +import { ExecuteAPIRequest } from './helper'; export const AddToColUI = (extensionUri: any) => { const disposable = vscode.commands.registerCommand('fetch-client.addToCol', (colId: string, folderId: string, name: string, type: string, varId?: string) => { @@ -28,7 +30,7 @@ export const AddToColUI = (extensionUri: any) => { colPanel.iconPath = iconUri; const nonce = getNonce(); - const title = `${type}:${colId}:${folderId}:${name}:${varId}`; + const title = `${type}@:@${colId}@:@${folderId}@:@${name}@:@${varId}`; colPanel.webview.html = ` @@ -51,7 +53,7 @@ export const AddToColUI = (extensionUri: any) => { source: null }; - colPanel.webview.onDidReceiveMessage((message: any) => { + colPanel.webview.onDidReceiveMessage(async (message: any) => { if (message.type === requestTypes.getAllCollectionNameRequest) { GetAllCollectionName(colPanel.webview, message.data); } else if (message.type === requestTypes.getHistoryItemRequest) { @@ -67,14 +69,9 @@ export const AddToColUI = (extensionUri: any) => { } else if (message.type === requestTypes.getCollectionsByIdRequest) { GetAllCollectionsById(message.data.colId, message.data.folderId, message.data.type, colPanel.webview); } else if (message.type === requestTypes.apiRequest) { - if (message.data.reqData.auth.authType === "inherit") { - ExecuteRequest(message, fetchConfig, colPanel.webview); - } - else { - apiFetch(message.data.reqData, message.data.variableData, null, fetchConfig).then((data) => { - colPanel.webview.postMessage(data); - }); - } + const CancelToken = axios.CancelToken; + fetchConfig.source = CancelToken.source(); + await ExecuteAPIRequest(message, fetchConfig, colPanel.webview); } else if (message.type === requestTypes.multipleApiRequest) { ExecuteMultipleRequest(message, fetchConfig, colPanel.webview); } else if (message.type === requestTypes.getAllVariableRequest) { @@ -120,9 +117,13 @@ export const AddToColUI = (extensionUri: any) => { } else if (message.type === requestTypes.getVariableItemRequest) { GetVariableById(message.data.id, message.data.isGlobal, colPanel.webview); } else if (message.type === requestTypes.tokenRequest) { - apiFetch(message.data.reqData, message.data.variableData, message.data.settings, fetchConfig, responseTypes.tokenResponse).then((data) => { + apiFetch(message.data.reqData, message.data.variableData, message.data.settings, null, fetchConfig, responseTypes.tokenResponse).then((data) => { colPanel.webview.postMessage(data); }); + } else if (message.type === requestTypes.getCollectionsByIdWithPathRequest) { + GetAllCollectionsByIdWithPath(message.data, colPanel.webview); + } else if (message.type === requestTypes.getParentSettingsRequest) { + GetParentSettings(message.data.colId, message.data.folderId, colPanel.webview); } }); }); diff --git a/src/utils/ui/cookieUIProvider.tsx b/src/utils/ui/cookieUIProvider.tsx index 3a8f41a..e3be2dc 100644 --- a/src/utils/ui/cookieUIProvider.tsx +++ b/src/utils/ui/cookieUIProvider.tsx @@ -21,7 +21,7 @@ export const CookieUI = (extensionUri: any) => { cookiePanel.iconPath = iconUri; const nonce = getNonce(); - const title = `managecookies:${id}`; + const title = `managecookies@:@${id}`; cookiePanel.webview.html = ` diff --git a/src/utils/ui/curlUIProvider.tsx b/src/utils/ui/curlUIProvider.tsx index f6e63d8..e0d383d 100644 --- a/src/utils/ui/curlUIProvider.tsx +++ b/src/utils/ui/curlUIProvider.tsx @@ -58,7 +58,7 @@ export const CurlProviderUI = (extensionUri: any) => { curlPanel.webview.postMessage({ type: responseTypes.runCurlResponse, request: null, response: apiResponse }); return; } - apiFetch(req, null, null, fetchConfig).then((data) => { + apiFetch(req, null, null, null, fetchConfig).then((data) => { curlPanel.webview.postMessage({ type: responseTypes.runCurlResponse, request: req, response: data }); }); } else if (reqData.type === requestTypes.convertCurlToJsonRequest) { diff --git a/src/utils/ui/helper.ts b/src/utils/ui/helper.ts new file mode 100644 index 0000000..db1456e --- /dev/null +++ b/src/utils/ui/helper.ts @@ -0,0 +1,98 @@ +import { Webview } from "vscode"; +import { sideBarProvider, vsCodeLogger } from "../../extension"; +import { IPreFetch, IReqSettings, IRequestModel } from "../../fetch-client-ui/components/RequestUI/redux/types"; +import { IHistory, ISettings, IVariable } from "../../fetch-client-ui/components/SideBar/redux/types"; +import { apiFetch, FetchConfig } from "../fetchUtil"; +import { formatDate, getErrorResponse } from "../helper"; +import { PreFetchRunner } from "../PreFetchRunner"; +import { SaveRequest, UpdateRequest } from "../db/mainDBUtil"; +import { SaveHistory, UpdateHistory } from "../db/historyDBUtil"; +import { GetVariableByIdSync } from "../db/varDBUtil"; +import { writeLog } from "../logger/logger"; + +export async function ExecuteAPIRequest(message: any, fetchConfig: FetchConfig, webview: Webview) { + try { + let request = message.data.reqData as IRequestModel; + let settings = message.data.settings as ISettings; + let reqSettings = message.data.reqSettings as IReqSettings; + let isVariableUpdated: boolean = false; + let updatedVariable: IVariable = message.data.variableData; + + // Run PreRequests in the parent + if ((!reqSettings || reqSettings?.skipParentPreFetch === false) && settings?.preFetch?.requests?.length > 0) { + let continueRequest = await runPreRequest(message, settings.preFetch, true, fetchConfig, webview); + if (!continueRequest) { + return; + } + isVariableUpdated = true; + } + + // Run PreRequests in the request item + if (request.preFetch?.requests?.length > 0 && request.preFetch?.requests[0].reqId) { + let continueRequest = await runPreRequest(message, request.preFetch, false, fetchConfig, webview); + if (!continueRequest) { + return; + } + isVariableUpdated = true; + } + + if (isVariableUpdated && message.data.variableData?.data?.length > 0) { + updatedVariable = await GetVariableByIdSync(message.data.variableData?.id); + } + + _executeAPIRequest(message, updatedVariable, fetchConfig, webview); + } catch (err) { + writeLog("error::helper::ExecuteAPIRequest()" + err); + throw err; + } +} + +async function runPreRequest(message: any, preFetch: IPreFetch, isParentPreRequest: boolean, fetchConfig: FetchConfig, webview: Webview): Promise { + let request = message.data.reqData as IRequestModel; + let preFetchCollectionRunner = new PreFetchRunner(fetchConfig, request.id); + await preFetchCollectionRunner.RunPreRequests(preFetch, 0, 0, request.name, isParentPreRequest); + if (preFetchCollectionRunner.message) { + if (fetchConfig.runMainRequest === true) { + setTimeout(() => { + vsCodeLogger.log("INFO", "\n\n" + preFetchCollectionRunner.message + "\n"); + }, 500); + return true; + } else { + fetchConfig.source = null; + let errorResponse = getErrorResponse(); + errorResponse.response.responseData = preFetchCollectionRunner.message; + webview.postMessage(errorResponse); + return false; + } + } + + return true; +} + +function _executeAPIRequest(message: any, variable: IVariable, fetchConfig: FetchConfig, webview: Webview) { + apiFetch(message.data.reqData, variable?.data, message.data.settings, message.data.reqSettings, fetchConfig).then((data) => { + fetchConfig.source = null; + webview.postMessage(data); + + let item: IHistory = { + id: message.data.reqData.id, + method: message.data.reqData.method, + name: message.data.reqData.name ? message.data.reqData.name : message.data.reqData.url, + url: message.data.reqData.url, + createdTime: message.data.reqData.createdTime ? message.data.reqData.createdTime : formatDate() + }; + + let reqData = message.data.reqData as IRequestModel; + if (reqData.body.bodyType === "binary") { + reqData.body.binary.data = ""; + } + + if (message.data.isNew) { + SaveRequest(reqData); + SaveHistory(item, sideBarProvider.view); + } else { + UpdateRequest(reqData); + UpdateHistory(item); + } + }); +} \ No newline at end of file diff --git a/src/utils/ui/mainUIProvider.tsx b/src/utils/ui/mainUIProvider.tsx index 49d0ba4..0458ab2 100644 --- a/src/utils/ui/mainUIProvider.tsx +++ b/src/utils/ui/mainUIProvider.tsx @@ -1,21 +1,21 @@ -import { apiFetch, FetchConfig } from "../fetchUtil"; -import { formatDate, getErrorResponse } from "../helper"; -import { getLayoutConfiguration, getConfiguration, getHeadersConfiguration, getTimeOutConfiguration, getRequestTabOption, getVSCodeTheme, getRunMainRequestOption } from "../vscodeConfig"; -import { getNonce, pubSubTypes, requestTypes, responseTypes } from "../configuration"; -import { GetVariableById, GetAllVariable, UpdateVariable } from "../db/varDBUtil"; -import { IHistory } from "../../fetch-client-ui/components/SideBar/redux/types"; +import axios from "axios"; +import fs from "fs"; +import * as vscode from "vscode"; +import { getStorageManager, OpenCookieUI, OpenVariableUI, pubSub, sideBarProvider, vsCodeLogger } from "../../extension"; import { IRequestModel } from "../../fetch-client-ui/components/RequestUI/redux/types"; -import { SaveCookie, GetAllCookies } from "../db/cookieDBUtil"; -import { SaveHistory, UpdateHistory } from "../db/historyDBUtil"; -import { SaveRequest, UpdateRequest, GetExitingItem } from "../db/mainDBUtil"; -import { sideBarProvider, getStorageManager, OpenVariableUI, OpenCookieUI, pubSub, vsCodeLogger } from "../../extension"; +import { IHistory, ISettings } from "../../fetch-client-ui/components/SideBar/redux/types"; import { IPubSubMessage, Subscription } from "../PubSub"; -import { UpdateCollection, GetParentSettings, GetAllCollectionsByIdWithPath, GetAllCollectionName } from "../db/collectionDBUtil"; +import { getNonce, pubSubTypes, requestTypes, responseTypes } from "../configuration"; +import { GetAllCollectionName, GetAllCollectionsByIdWithPath, GetParentSettings, UpdateCollection } from "../db/collectionDBUtil"; +import { GetAllCookies, SaveCookie } from "../db/cookieDBUtil"; +import { SaveHistory, UpdateHistory } from "../db/historyDBUtil"; +import { GetExitingItem, SaveRequest, UpdateRequest } from "../db/mainDBUtil"; +import { GetAllVariable, GetVariableById, UpdateVariable } from "../db/varDBUtil"; +import { apiFetch, FetchConfig } from "../fetchUtil"; +import { formatDate, getErrorResponse } from "../helper"; import { writeLog } from "../logger/logger"; -import * as vscode from "vscode"; -import axios from "axios"; -import fs from "fs"; -import { PreFetchRunner } from "../PreFetchRunner"; +import { getConfiguration, getHeadersConfiguration, getLayoutConfiguration, getRequestTabOption, getRunMainRequestOption, getTimeOutConfiguration, getVSCodeTheme } from "../vscodeConfig"; +import { ExecuteAPIRequest } from "./helper"; export class WebAppPanel { @@ -83,7 +83,7 @@ export class WebAppPanel { this._panel.onDidDispose(() => { this._scriptionId.unsubscribe(); - this.dispose(); + this.dispose(id, colId, folderId); }, null, this._disposables); this._panel.onDidChangeViewState(function (event) { @@ -98,40 +98,16 @@ export class WebAppPanel { runMainRequest: getRunMainRequestOption() }; + // Handle messages from the webview this._panel.webview.onDidReceiveMessage( - message => { + async message => { try { if (message.type === requestTypes.apiRequest) { const CancelToken = axios.CancelToken; fetchConfig.source = CancelToken.source(); - let request = message.data.reqData as IRequestModel; - let preFetch = request.preFetch; - - if (preFetch?.requests?.length > 0 && preFetch?.requests[0].reqId) { - let preFetchRunner = new PreFetchRunner(fetchConfig, request.id); - preFetchRunner.RunPreRequests(preFetch, 0, 0, request.name).then(() => { - if (preFetchRunner.message) { - if (fetchConfig.runMainRequest === true) { - setTimeout(() => { - vsCodeLogger.log("INFO", "\n\n" + preFetchRunner.message + "\n"); - }, 1000); - this._executeAPIRequest(message, fetchConfig); - } else { - fetchConfig.source = null; - let errorResponse = getErrorResponse(); - errorResponse.response.responseData = preFetchRunner.message; - this._panel.webview.postMessage(errorResponse); - return; - } - } else { - this._executeAPIRequest(message, fetchConfig); - } - }); - } else { - this._executeAPIRequest(message, fetchConfig); - } + await ExecuteAPIRequest(message, fetchConfig, this._panel.webview); let item: IHistory = { id: message.data.reqData.id, @@ -144,6 +120,7 @@ export class WebAppPanel { if (message.data.colId) { UpdateCollection(message.data.colId, item); } + sideBarProvider.view.webview.postMessage({ type: responseTypes.updateCollectionHistoryItem, colId: message.data.colId, item: item }); } else if (message.type === requestTypes.cancelRequest) { @@ -156,6 +133,8 @@ export class WebAppPanel { this._panel.webview.postMessage(getConfiguration()); } else if (message.type === requestTypes.openExistingItemRequest) { GetExitingItem(this._panel.webview, message.data); + } else if (message.type === requestTypes.getOpenAndRunItemDataRequest) { + GetExitingItem(this._panel.webview, message.data, null, "OpenAndRun"); } else if (message.type === requestTypes.saveResponseRequest) { vscode.window.showSaveDialog({ defaultUri: vscode.Uri.file("fetch-client-response." + message.fileType) }).then((uri: vscode.Uri | undefined) => { if (uri) { @@ -267,7 +246,7 @@ export class WebAppPanel { } }); } else if (message.type === requestTypes.tokenRequest) { - apiFetch(message.data.reqData, message.data.variableData, message.data.settings, fetchConfig, responseTypes.tokenResponse).then((data) => { + apiFetch(message.data.reqData, message.data.variableData, message.data.settings, null, fetchConfig, responseTypes.tokenResponse).then((data) => { this._panel.webview.postMessage(data); }); } else if (message.type === requestTypes.themeRequest) { @@ -279,8 +258,7 @@ export class WebAppPanel { } } catch (error) { - vscode.window.showErrorMessage("Couldn't fetch the api", { modal: true }); - writeLog("error::onDidReceiveMessage()" + error.message); + writeLog("error::mainUIProvider::onDidReceiveMessage()" + error); } }, null, @@ -288,7 +266,10 @@ export class WebAppPanel { ); } - public dispose() { + public dispose(id?: string, colId?: string, folderId?: string) { + + sideBarProvider.view.webview.postMessage({ type: requestTypes.closeItemRequest, id: id, colId: colId, folderId: folderId }); + WebAppPanel.currentPanel = undefined; // Clean up our resources @@ -319,34 +300,6 @@ export class WebAppPanel { } } - private _executeAPIRequest(message: any, fetchConfig: FetchConfig) { - apiFetch(message.data.reqData, message.data.variableData, message.data.settings, fetchConfig).then((data) => { - fetchConfig.source = null; - this._panel.webview.postMessage(data); - - let item: IHistory = { - id: message.data.reqData.id, - method: message.data.reqData.method, - name: message.data.reqData.name ? message.data.reqData.name : message.data.reqData.url, - url: message.data.reqData.url, - createdTime: message.data.reqData.createdTime ? message.data.reqData.createdTime : formatDate() - }; - - let reqData = message.data.reqData as IRequestModel; - if (reqData.body.bodyType === "binary") { - reqData.body.binary.data = ""; - } - - if (message.data.isNew) { - SaveRequest(reqData); - SaveHistory(item, sideBarProvider.view); - } else { - UpdateRequest(reqData); - UpdateHistory(item); - } - }); - } - private _getHtmlForWebview(webview: vscode.Webview, id?: string, colId?: string, varId?: string, type?: string, folderId?: string) { const scriptUri = webview.asWebviewUri( @@ -364,7 +317,7 @@ export class WebAppPanel { - ${id}:${colId}:${varId}:${type}:${folderId} + ${id}@:@${colId}@:@${varId}@:@${type}@:@${folderId} diff --git a/src/utils/ui/sideBarUIProvider.tsx b/src/utils/ui/sideBarUIProvider.tsx index b293997..c93d340 100644 --- a/src/utils/ui/sideBarUIProvider.tsx +++ b/src/utils/ui/sideBarUIProvider.tsx @@ -1,25 +1,28 @@ +import * as vscode from 'vscode'; +import { + getStorageManager, OpenAddToColUI, OpenAttachVariableUI, OpenColSettings, OpenCopyToColUI, + OpenCurlUI, OpenExistingItem, OpenRunAllUI, OpenVariableUI, pubSub, vsCodeLogger +} from '../../extension'; +import { ICollections, IFolder, IHistory } from '../../fetch-client-ui/components/SideBar/redux/types'; +import { getNonce, pubSubTypes, requestTypes, responseTypes } from '../../utils/configuration'; import { AddToCollection, AttachVariable, CreateNewCollection, DeleteAllCollectionItems, DeleteCollection, DeleteCollectionItem, DuplicateItem, GetAllCollections, NewFolderToCollection, NewRequestToCollection, RemoveVariableByVariableId, RenameCollection, RenameCollectionItem } from '../../utils/db/collectionDBUtil'; +import { DeleteAllHistory, DeleteHistory, GetAllHistory, RenameHistory } from '../../utils/db/historyDBUtil'; +import { Export, Import, SaveRequest } from '../db/mainDBUtil'; import { ChangeVariableStatus, DeleteVariable, DuplicateVariable, ExportVariable, - GetAllVariable, ImportVariableFromJsonFile, ImportVariableFromEnvFile, RenameVariable + GetAllVariable, + ImportVariableFromEnvFile, + ImportVariableFromJsonFile, + RenameVariable } from '../db/varDBUtil'; -import { DeleteAllHistory, DeleteHistory, GetAllHistory, RenameHistory } from '../../utils/db/historyDBUtil'; -import { Export, Import, SaveRequest } from '../db/mainDBUtil'; import { formatDate } from '../helper'; -import { getNonce, pubSubTypes, requestTypes, responseTypes } from '../../utils/configuration'; -import { - getStorageManager, OpenAddToColUI, OpenAttachVariableUI, OpenColSettings, OpenCopyToColUI, - OpenCurlUI, OpenExistingItem, OpenRunAllUI, OpenVariableUI, pubSub, vsCodeLogger -} from '../../extension'; -import { getVSCodeTheme } from '../vscodeConfig'; -import { ICollections, IFolder, IHistory } from '../../fetch-client-ui/components/SideBar/redux/types'; import { IPubSubMessage, Subscription } from '../PubSub'; -import * as vscode from 'vscode'; +import { getVSCodeTheme } from '../vscodeConfig'; export class SideBarProvider implements vscode.WebviewViewProvider { @@ -79,6 +82,9 @@ export class SideBarProvider implements vscode.WebviewViewProvider { case requestTypes.openHistoryItemRequest: OpenExistingItem(reqData.data.id, reqData.data.name, reqData.data.colId, reqData.data.folderId, reqData.data.varId, undefined, reqData.data.isNewTab); break; + case requestTypes.openAndRunItemRequest: + OpenExistingItem(reqData.data.id, reqData.data.name, reqData.data.colId, reqData.data.folderId, reqData.data.varId, "OpenAndRun", reqData.data.isNewTab); + break; case requestTypes.addToCollectionsRequest: OpenAddToColUI(reqData.data); break; diff --git a/src/utils/ui/variableUIProvider.tsx b/src/utils/ui/variableUIProvider.tsx index 720c4fc..46f3a09 100644 --- a/src/utils/ui/variableUIProvider.tsx +++ b/src/utils/ui/variableUIProvider.tsx @@ -24,7 +24,7 @@ export const VariableUI = (extensionUri: any) => { varPanel.iconPath = iconUri; const nonce = getNonce(); - const title = `newvar:${id}`; + const title = `newvar@:@${id}`; varPanel.webview.html = ` diff --git a/vsc-extension-quickstart.md b/vsc-extension-quickstart.md index e8577b6..92c3b0e 100644 --- a/vsc-extension-quickstart.md +++ b/vsc-extension-quickstart.md @@ -1,6 +1,9 @@ # Fetch Client - +
+ Fetch Client Icon +
+
## What is Fetch Client ? @@ -14,23 +17,35 @@ Fetch Client is Visual Studio Code extension which is used to test the Rest API. * Lightweight * UI Customization and support VSCode Themes. * Test Rest API request with GET, POST, PUT, PATCH, DELETE, HEAD and OPTIONS methods. -* Various authorization mechcanisms such as Basic Auth, Bearer Token and API Key. +* Run curl requests. +* Various authorization mechanisms such as Basic Auth, Bearer Token, API Key and AWS Signature. * Various post body which are Form, Form-Encoded, Raw (Json, Plain Text, XML), Binary File and GraphQL. * Syntax highlight for Response data. * Tree view for JSON and XML responses and HTML preview for HTML responses. -* History, Collection, Enivronment Variable is supported. +* History, Collection, Environment Variable is supported. * Test the API request and response data without any scripts/code. * Generate code snippet for various languages. * Save response and test results as File. -* Export/Import the Fecth Client's collections and environment variables. +* Export/Import the Fetch Client/Postman/Thunder Client's collections and environment variables. * Add documentation/feedback for each request. +* Set the environment variable data from the response. +* Manage the Cookies. +* Pre-requests in request level as well as collection/folder level. +* Run all the requests in the collection using single click. +* Save all request data in the custom/workspace folder (Team collaboration). +* Supports system variables +* View request and response logs. ## πŸ“¦ How to Install ? - * Install via VSCode Extensions - * Open VSCode Extensions panel using `Ctrl+Shift+X` shortcut. - * Type `Fetch Client` in Search bar. - * Select the `Fetch Client` and install the extension. +* Install via VSCode Extensions + * Open VSCode Extensions panel using `Ctrl+Shift+X` shortcut. + * Type `Fetch Client` in Search bar. + * Select the `Fetch Client` and install the extension. +
+ Fetch Client Extension +
+
## πŸ’‘ How to use ? @@ -40,7 +55,11 @@ Fetch Client is Visual Studio Code extension which is used to test the Rest API. * The response data will be displayed in the `Response` section. We can view the response data in the Tree view format for `JSON` and `XML` responses and HTML preview for `HTML` responses. * All existing requests are available in the `History` section in the Quick Access Bar. -![fetch-client Screenshot](https://github.com/Ganesan-Chandran/vscode-fetch-client/blob/main/images/Horizonal_Accordian_Split.gif?raw=true) +
+ Fetch Client Extension +
+ Fetch Client v1.0.0 +
## πŸ”— Features @@ -51,99 +70,143 @@ Fetch Client is Visual Studio Code extension which is used to test the Rest API. * [Headers](#headers) * [Request Body](#reqbody) * [Test](#test) +* [Set Environment Variable](#setvar) * [Response Data](#resdata) * [Test Results](#testresults) +* [Pre-requests](#prerequests) * [Notes](#notes) * [Code Snippet](#codesnippet) * [Request Cancel](#reqcancel) * [Quick Access](#quickaccess) - * [History](#history) - * [Collection](#collection) - * [Environment Variable](#envvar) + * [History](#history) + * [Collection](#collection) + * [Environment Variable](#envvar) * [Run All requests](#runall) +* [Manage Cookies](#managecookies) +* [Run/Import Curl Request](#runcurl) +* [System variables](#systemvariables) +* [Logs](#logs) + ### 1) UI Customization We can customize the UI in different modes. - * Horizontal mode - * Accordian View - * Split View - * Vertical mode - * Split View - -| ![fetch-client Screenshot](https://github.com/Ganesan-Chandran/vscode-fetch-client/blob/main/images/Horizonal_Accordian_Split.gif?raw=true) | -|:--:| -| *Horizontal mode - Accordian View* | -| ![fetch-client Screenshot](https://github.com/Ganesan-Chandran/vscode-fetch-client/blob/main/images/Horizonal_Split.gif?raw=true) | -|:--:| -| *Horizontal mode - Split View* | - -| ![fetch-client Screenshot](https://github.com/Ganesan-Chandran/vscode-fetch-client/blob/main/images/Vertical_Split.gif?raw=true) | -|:--:| -| *Vertical mode - Split View* | +* Horizontal mode + * Accordion View + * Split View +* Vertical mode + * Split View + +
+ Fetch Client-Horizontal mode(Accordion View) +
+ Horizontal mode - Accordion View +
+
+ Fetch Client-Horizontal mode(Split View) +
+ Horizontal mode - Split View +
+
+ Fetch Client-Vertical mode(Split View) +
+ Vertical mode - Split View +
+ ### 2) Different HTTP Methods Fetch client supports to test the Rest API request with various HTTP methods such as GET, POST, PUT, PATCH, DELETE, HEAD and OPTIONS. + ### 3) Query Parameter Fetch client supports to test the Rest API request with query parameter. + ### 4) Authorization + Fetch client supports below authorization methods for Rest API testing. + * Basic Auth * Bearer Token * API Key +* AWS Signature +* OAuth 2.0 + ### 5) Headers We can add the headers for API testing. Fetch Client gives the suggestion on various headers and corresponding values in the header section. - -![fetch-client Screenshot](https://github.com/Ganesan-Chandran/vscode-fetch-client/blob/main/images/header-suggestion.png?raw=true) - -![fetch-client Screenshot](https://github.com/Ganesan-Chandran/vscode-fetch-client/blob/main/images/header-value-suggestion.png?raw=true) - +
+
+ Header search +
+
+ Header suggestion +
+ ### 6) Request Body - * Fetch client supports below request body. - * Form - * Form-Encoded - * Raw ( JSON, Plain Text, XML ) - * Binary File - * GraphQL - * `Content-Type` header will be automatically added based on binary file type. +* Fetch client supports below request body. + * Form + * Form-Encoded + * Raw ( JSON, Plain Text, XML ) + * Binary File + * GraphQL +* `Content-Type` header will be automatically added based on binary file type. -![fetch-client Screenshot](https://github.com/Ganesan-Chandran/vscode-fetch-client/blob/main/images/raw-content-type-suggestion.png?raw=true) +
+
+ Body request(Binary format) +
+ ### 7) Test - * We can test the API request and response data without any scripts/code in the Fetch client. - * It supports to test the below data, - * Response Code - * Response Body - * Response Time - * Content-Type - * Content-Length - * Content-Encoding - * Specific Response Header value - * Specific JSON property value in the JSON response - -| ![fetch-client Screenshot](https://github.com/Ganesan-Chandran/vscode-fetch-client/blob/main/images/Test.gif?raw=true) | -|:--:| -| *Fetch Client - Test Case/Test Results* | +* We can test the API request and response data without any scripts/code in the Fetch client. +* It supports to test the below data, + * Response Code + * Response Body + * Response Time + * Content-Type + * Content-Length + * Content-Encoding + * Specific Response Header value + * Specific JSON property value in the JSON response + +
+
+ Visual test editor + Visual test case and test results +
+ Fetch Client - Test Case/Test Results +
+ + + +### 8) Set Environment Variable + +* Fetch client supports the set the environment variable data from the response, headers and cookies. + +
+
+ assign variables +
+
-### 8) Response Data + +### 9) Response Data * Fetch client supports Syntax highlight for Response data. * Copy the response data using `Copy` button. @@ -152,104 +215,277 @@ We can add the headers for API testing. Fetch Client gives the suggestion on var * View the status code, response time and size of the response data. * View response headers. -![fetch-client Screenshot](https://github.com/Ganesan-Chandran/vscode-fetch-client/blob/main/images/response.png?raw=true) +
+ response view +
-### 9) Test Results + +### 10) Test Results * Once request is processed, Fetch client executes the test cases and display the test result with expected value and actual value. * We can download the test results as JSON file. -![fetch-client Screenshot](https://github.com/Ganesan-Chandran/vscode-fetch-client/blob/main/images/test-result.png?raw=true) +
+
+ Test results +
+ + + +### 11) Pre-requests + +* Add list of pre-requests at request, folder and collection level. +* Run pre-requests with/without the conditions. +* We can configure the dependency between main request with pre-requests in the `Fetch Client` settings. + +
+ Pre-requests +
-### 10) Notes + +### 12) Notes Notes section is used to add the notes or documentation regarding the request. Fetch client has simple editor to add the documentation. -![fetch-client Screenshot](https://github.com/Ganesan-Chandran/vscode-fetch-client/blob/main/images/notes.png?raw=true) +
+ notes +
-### 11) Code Snippet -Fetch client supports code snippet generation for various languages. Generate code snippets to send request from another application. Open request view and click icon (right side of the response section) for code snippet generation. The code snippet generation is available for following languages. - * C - * C# - * Go - * Java - * JavaScript - * Node - * PHP - * Python - * Shell +### 13) Code Snippet + +Fetch client supports code snippet generation for various languages. +Generate code snippets to send request from another application. +Open request view and click icon (right side of the response section) for code snippet generation. +The code snippet generation is available for following languages. + +* C +* C# +* Go +* Java +* JavaScript +* Node +* PHP +* Python +* Shell -![fetch-client Screenshot](https://github.com/Ganesan-Chandran/vscode-fetch-client/blob/main/images/code-snippet.png?raw=true) +
+ code snippet generation +
-### 11) Request Cancel + +### 14) Request Cancel Fetch client provides the feature for cancel the request. If you want to cancel the processing request then click then "Cancel Request" button in the response section. -### 12) Quick Access + +### 15) Quick Access Fetch client provides the quick access of History, collection and Environment variables in the side bar. - * ### History - * Automatic saving of requests in History. - * Save the history item to the collections. - * Delete all history items or specific history item. + +* ### History + + * Automatic saving of requests in History. + * Save the history item to the collections. + * Delete all history items or specific history item. - * ### Collection - * Save requests to a collection. - * Organize the request using the collections. - * Run all the requests in the collection using `Run All` options and download the results as file. - * Attach the Environment variable to collections. - * `Export` the collections as JSON file. - * `Import` the Fetch Client collections from above exported JSON file. (It is used to share the collections between team members.) - * Duplicate the collection items. - ### How to Import Collection - * Select the `Collection` tab from the sidebar - * Click Menu icon and Select `Import` option. - * Now select `Fetch Client` collection file. + +* ### Collection + + * Save requests to a collection. + * Organize the request using the collections. + * Run all the requests in the collection using `Run All` options and download the results as file. + * Attach the Environment variable to collections. + * `Export` the collections as JSON file. + * `Import` the Fetch Client collections from above exported JSON file. (It is used to share the collections between team members.) + * Duplicate the collection items. + +
+
+ Collection menu +
+ +### How to Import Collection + +* Select the `Collection` tab from the sidebar +* Click Menu icon and Select `Import` option. +* Now select `Fetch Client`/`Postman(v2.1)`/`ThunderClient(v1.2)` collection file. +* Supports settings in each collection + * Authorization + * Headers + * Pre-requests + +
+
+ Import Collection +
- * ### Environment Variable - * Create and set variables at multiple scopes - * Global Level - * Collection level - * Request level - * It is simple key value pair combination. - * Use environment variables in URL, Query Param, Authorization, Header, Request Body (Form and Form-Encoded), Test sections. - * `Export` variables as JSON file. - * `Import` the Fetch Client variables from above exported JSON file. - * In the input, enter a variable name in the `{{variableName}}` format. - ### How to Import Variable - * Select the `Variable` tab from the sidebar - * Click Menu icon and Select `Import` option. - * Now select `Fetch Client` variable file. + +* ### Environment Variable + + * Create and set variables at multiple scopes + * Global Level + * Collection level + * Request level + * It is simple key value pair combination. + * Use environment variables in URL, Query Param, Authorization, Header, Request Body (Form and Form-Encoded), Test sections. + * `Export` variables as JSON file. + * `Import` the Fetch Client variables from above exported JSON file. + * In the input, enter a variable name in the `{{variableName}}` format. + +### How to Import Variable + +* Select the `Variable` tab from the sidebar +* Click Menu icon and Select `Import` option. +* Now select `Fetch Client`/`Postman(v2.1)`/`ThunderClient(v1.2)` variable file. + +
+
+ Sidebar quick access +
-### 12) Run All requests + +### 16) Run All requests * Run all the requests in the collection using "Run All" options and download the results as file. +* Change the execution order of the requests in the 'Run All' section. +* Execute the request either in a sequential or parallel manner. * Once completed the all request, export the test result as `JSON` or `CSV`. * If you click the particular request from the table, it will open the corresponding request view. -![fetch-client Screenshot](https://github.com/Ganesan-Chandran/vscode-fetch-client/blob/main/images/run-all-menu.png?raw=true) -![fetch-client Screenshot](https://github.com/Ganesan-Chandran/vscode-fetch-client/blob/main/images/run-all.png?raw=true) +
+
+ Run All menu + Run All UI + Run All settings +
+ + + +### 17) Manage Cookies + +* View/Delete the cookies in the Manage Cookies Page. +* Cookie header will automatically added if cookies are available for that request. +* You can modify the cookies using the `cookie` header. + +
+
+ Manage Cookies Menu + Manage Cookies UI +
+ + + +### 18) Run/Import Curl Request + +
+
+ Import Curl Menu +
+ Import Curl +
+ Import Curl Request +
+ Run Curl Command +
+ Run Curl Request +
+ + + +### 19) System variables + +* System variable is used to generate dynamic data and use query parameters and request body (formdata, formurlencoded) . +* Below are supported system variables. + * {{#num}} - Generate random number between 1 to 999999 + * {{#num, min, max}} - Generate random number between given min and max value + * {{#str}} - Generate random string(only alphabets) with max length of 15 + * {{#strspl}} - Generate random string(alphabets and special characters) with max length of 15 + * {{#strnum}} - Generate random string(alphabets and numbers) with max length of 15 + * {{#char}} - Generate random character + * {{#rdate}} - Generate random date between 01/01/1900 to 01/01/2100 + * {{#date}} - Generate current date + * {{#dateISO}} - Generate current date with ISO format + * {{#date, 'format'}} - Generate current date with given format + * {{#email}} - Generate email with random characters + * {{#guid}} - Generate random guid + * {{#bool}} - Generate random boolean value (true/false) + +
+
+ System variables +
+
+ + + +### 20) Logs + +* Click `View Log` button in the sidebar to view the logs. +* View the logs in the Output Window (Choose `Fetch Client` option in the dropdown). +* Customize the logs in the Fetch Client settings. By Default `request details` will be logged. If the setting is enabled, both `request and response` details will be logged. + +
+
+ Logs +
+
+ +
+
+ Logs settings +
+
+ + + +### 21) Workspace + +* Save all requests data into the current workspace path. +* `Fetch Client` will create `fetch-client` folder in the root of the workspace and all the request files are saved into this folder. +* Enable this option using the below `Fetch Client` setting. + +
+
+ Workspace settings +
+
+ +DO NOT ENTER/EDIT MANUALLY in the below settings. Configuration will be done automatically. Manual editing may lead to data loss. +
+
+ Workspace settings +
+
## ⌨ Keyboard Shortcuts -* `Ctl+Shift+P`: From Command Palette + +* `Ctl+Shift+P` (Open Command Palette) * Fetch Client - New Request -* `Ctl+Alt+N` - Open Fetch Client View -* `Enter` on request url textbox to send request. +* `Ctl+Alt+N` - Open `Fetch Client` View +* `Enter` on URL text box to send request +* `Cmd/Ctrl + s` - Save Request without run ## βš™οΈ Configuration -* Open VSCode settings View, then search for `Fetch Client`. -* Fetch Client has below configurations. +* Open VSCode settings View, then search for `Fetch Client` or click `Fetch Client Settings` in the menu item. + +
+
+ Fetch Client settings +
+
+ +* Fetch Client has below configurations. |Name | Setting | Default | Description | |-----|---------|------------|------------| @@ -258,10 +494,17 @@ Fetch client provides the quick access of History, collection and Environment va |SSL Check|fetch-client.SSLCheck|true|Enable Strict SSL Check for API Request| |History Limit|fetch-client.historyLimit|25|Number of items to be displayed in the History| |Time Out|fetch-client.timeOut|5 min|Request Timeout| -|Default Protocol|fetch-client.defaultProtocol|http|Which protocol to add with url (if url has no protocol)| +|Default Protocol|fetch-client.defaultProtocol|http|Which protocol to add with URL (if URL has no protocol)| + +
+
+ Fetch Client settings +
## πŸš€ Tech Stack + Fetch Client is created with below tech stacks. + * Extension : [VS Code Extension API](https://code.visualstudio.com/api) * UI : [React JS](https://reactjs.org/), [TypeScript](https://www.typescriptlang.org/), [JavaScript](https://www.w3schools.com/js/), [CSS](https://www.w3schools.com/css/default.asp) * Editor : [Monaco Editor](https://microsoft.github.io/monaco-editor/) @@ -269,22 +512,29 @@ Fetch Client is created with below tech stacks. * Code Snippet Generation : [httpsnippet](https://github.com/Kong/httpsnippet/) ## πŸ–₯️ Running the extension locally for development + * Clone the [vscode-fetch-client](https://github.com/Ganesan-Chandran/vscode-fetch-client) repo. * Run `npm install` command to install dependencies. -* Press `F5` to open a extension developement window with `fetch-client` extension loaded. +* Press `F5` to open an extension development window with `fetch-client` extension loaded. ## πŸ”’ Privacy + * Fetch client **`DOES NOT`** collect any your personal or request data. -* Fetch client has no backend or cloud storage and all your data are stored **`LOCALLY`** on your computer. +* Fetch client has no back-end storage and all your data are stored **`LOCALLY`** on your computer. ## πŸ“ Changelog + See the [release notes](https://github.com/Ganesan-Chandran/vscode-fetch-client/blob/main/CHANGELOG.md) for the full set of changes. ## βœ’οΈ Author + [Ganesan Chandran](https://ganesan-chandran.github.io/) ## πŸ“œ License + See the [license](https://github.com/Ganesan-Chandran/vscode-fetch-client/blob/main/LICENSE) details. ## πŸ‘ Contribution -Feel free to submit a pull request if you find any bugs or new feature (To see a list of active issues/feature request, visit the [Issues section](https://github.com/Ganesan-Chandran/vscode-fetch-client/issues)). Please make sure all commits are properly documented. + +Feel free to submit a pull request if you find any bugs or new feature (To see a list of active issues/feature request, +visit the [Issues section](https://github.com/Ganesan-Chandran/vscode-fetch-client/issues)). Please make sure all commits are properly documented.