Repository: rohinivsenthil/postcode
Branch: master
Commit: 824ff7d0c2d0
Files: 97
Total size: 97.6 KB
Directory structure:
gitextract_11wa3ryc/
├── .eslintrc.json
├── .gitignore
├── .husky/
│ └── pre-push
├── .prettierignore
├── .vscode/
│ ├── launch.json
│ ├── settings.json
│ └── tasks.json
├── .vscodeignore
├── .yarnrc
├── CHANGELOG.md
├── LICENSE
├── README.md
├── package.json
├── src/
│ ├── extension.ts
│ └── test/
│ ├── runTest.ts
│ └── suite/
│ ├── extension.test.ts
│ └── index.ts
├── tsconfig.json
├── webpack.config.js
└── webview/
├── App.css
├── App.tsx
├── acquireVsCodeApi.d.ts
├── components/
│ ├── RequestBar/
│ │ ├── index.tsx
│ │ └── styles.css
│ ├── RequestOptionsBar/
│ │ ├── index.tsx
│ │ └── styles.css
│ ├── RequestOptionsWindow/
│ │ ├── index.tsx
│ │ └── styles.css
│ └── Response/
│ ├── index.tsx
│ └── styles.css
├── constants/
│ ├── request-options.ts
│ ├── response-options.ts
│ ├── response-views.ts
│ └── supported-langs.ts
├── features/
│ ├── codeGen/
│ │ ├── CodeSnippet/
│ │ │ ├── index.tsx
│ │ │ └── styles.css
│ │ └── codeGenSlice.ts
│ ├── requestAuth/
│ │ ├── BasicAuth/
│ │ │ ├── index.tsx
│ │ │ └── styles.css
│ │ ├── BearerToken/
│ │ │ ├── index.tsx
│ │ │ └── styles.css
│ │ ├── NoAuth/
│ │ │ ├── index.tsx
│ │ │ └── styles.css
│ │ ├── RequestAuth/
│ │ │ ├── index.tsx
│ │ │ └── styles.css
│ │ └── requestAuthSlice.ts
│ ├── requestBody/
│ │ ├── Binary/
│ │ │ ├── index.tsx
│ │ │ └── styles.css
│ │ ├── FormData/
│ │ │ ├── index.tsx
│ │ │ └── styles.css
│ │ ├── GraphQL/
│ │ │ ├── index.tsx
│ │ │ └── styles.css
│ │ ├── NoBody/
│ │ │ ├── index.tsx
│ │ │ └── styles.css
│ │ ├── Raw/
│ │ │ ├── index.tsx
│ │ │ └── styles.css
│ │ ├── RequestBody/
│ │ │ ├── index.tsx
│ │ │ └── styles.css
│ │ ├── UrlEncoded/
│ │ │ ├── index.tsx
│ │ │ └── styles.css
│ │ └── requestBodySlice.ts
│ ├── requestHeader/
│ │ ├── HeadersWindow/
│ │ │ ├── index.tsx
│ │ │ └── styles.css
│ │ └── requestHeaderSlice.ts
│ ├── requestMethod/
│ │ ├── RequestMethodSelector/
│ │ │ ├── index.tsx
│ │ │ └── styles.css
│ │ └── requestMethodSlice.ts
│ ├── requestOptions/
│ │ ├── RequestOptions/
│ │ │ ├── index.tsx
│ │ │ └── styles.css
│ │ └── requestOptionsSlice.ts
│ ├── requestUrl/
│ │ ├── RequestQueryParams/
│ │ │ ├── index.tsx
│ │ │ └── styles.css
│ │ ├── RequestUrl/
│ │ │ ├── index.tsx
│ │ │ └── styles.css
│ │ └── requestUrlSlice.ts
│ └── response/
│ ├── ResponseBody/
│ │ ├── index.tsx
│ │ └── styles.css
│ ├── ResponseHeaders/
│ │ ├── index.tsx
│ │ └── styles.css
│ ├── ResponseTab/
│ │ ├── index.tsx
│ │ └── styles.css
│ ├── ResponseWindow/
│ │ ├── index.tsx
│ │ └── styles.css
│ └── responseSlice.ts
├── index.css
├── index.tsx
├── pages/
│ └── Postcode/
│ ├── index.tsx
│ └── styles.css
├── prerender.tsx
├── react-app-env.d.ts
├── redux/
│ ├── hooks.ts
│ └── store.ts
├── shared/
│ ├── Editor/
│ │ ├── index.tsx
│ │ └── styles.css
│ └── KeyValueTable/
│ ├── index.tsx
│ └── styles.css
└── vscode.ts
================================================
FILE CONTENTS
================================================
================================================
FILE: .eslintrc.json
================================================
{
"env": {
"browser": true,
"es2021": true,
"node": true
},
"extends": [
"eslint:recommended",
"plugin:react/recommended",
"plugin:@typescript-eslint/recommended",
"plugin:prettier/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": 12,
"sourceType": "module"
},
"settings": {
"react": {
"version": "detect"
}
},
"ignorePatterns": ["out", "dist", "**/*.d.ts"],
"plugins": ["react", "@typescript-eslint"],
"rules": {
"@typescript-eslint/explicit-module-boundary-types": "off"
}
}
================================================
FILE: .gitignore
================================================
out
dist
node_modules
.vscode-test/
*.vsix
================================================
FILE: .husky/pre-push
================================================
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
yarn lint
================================================
FILE: .prettierignore
================================================
out
dist
================================================
FILE: .vscode/launch.json
================================================
// A launch configuration that compiles the extension and then opens it inside a new window
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
{
"version": "0.2.0",
"configurations": [
{
"name": "Run Extension",
"type": "extensionHost",
"request": "launch",
"args": ["--extensionDevelopmentPath=${workspaceFolder}"],
"outFiles": ["${workspaceFolder}/dist/**/*.js"],
"preLaunchTask": "${defaultBuildTask}"
},
{
"name": "Extension Tests",
"type": "extensionHost",
"request": "launch",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}",
"--extensionTestsPath=${workspaceFolder}/out/test/suite/index"
],
"outFiles": ["${workspaceFolder}/out/test/**/*.js"],
"preLaunchTask": "npm: test-watch"
}
]
}
================================================
FILE: .vscode/settings.json
================================================
// Place your settings in this file to overwrite default and user settings.
{
"files.exclude": {
"out": false, // set this to true to hide the "out" folder with the compiled JS files
"dist": false // set this to true to hide the "dist" folder with the compiled JS files
},
"search.exclude": {
"out": true, // set this to false to include "out" folder in search results
"dist": true // set this to false to include "dist" folder in search results
},
// Turn off tsc task auto detection since we have the necessary tasks as npm scripts
"typescript.tsc.autoDetect": "off"
}
================================================
FILE: .vscode/tasks.json
================================================
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
{
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"script": "watch",
"problemMatcher": ["$ts-webpack-watch", "$tslint-webpack-watch"],
"isBackground": true,
"presentation": {
"reveal": "never"
},
"group": {
"kind": "build",
"isDefault": true
}
},
{
"type": "npm",
"script": "test-watch",
"problemMatcher": "$tsc-watch",
"isBackground": true,
"presentation": {
"reveal": "never"
},
"group": "build"
}
]
}
================================================
FILE: .vscodeignore
================================================
.vscode/**
.vscode-test/**
out/**
node_modules/**
src/**
.gitignore
.yarnrc
vsc-extension-quickstart.md
**/tsconfig.json
**/.eslintrc.json
**/*.map
**/*.ts
dist/prerender.js
dist/*.prerender.js
dist/*.prerender.js.*
================================================
FILE: .yarnrc
================================================
--ignore-engines true
================================================
FILE: CHANGELOG.md
================================================
# Change Log
All notable changes to the "postcode" extension will be documented in this file.
Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file.
### 1.3.9
- automattically use http protocol if none is specified
- make font size relative to vscode editor font size
### 1.3.8
- display response time in response window
### 1.3.7
- add request options for strict ssl
### 1.3.6
- add beautify button for post body
### 1.3.5
- fix basic auth functionality
### 1.3.4
- Add headers tab for response
### 1.3.3
- Improve load time by pre-rendering
### 1.3.2
- Remove excess scroll
### 1.3.1
- Add copy button to code editor
### 1.3.0
- Support code-snippet generation
### 1.2.1
- Clear error when response is updated
### 1.2.0
- Support GraphQL requests
### 1.1.0
- Support formating of responses based on language
### 1.0.0
- Initial release
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2021 Rohini Senthil
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
<h1 align="center">Postcode</h1>
<div align="center">
<strong> API client for VS code 📦</strong>
<br/> <br/>
<a href="https://marketplace.visualstudio.com/items?itemName=rohinivsenthil.postcode&ssr=false#overview"><img src="https://img.shields.io/visual-studio-marketplace/i/rohinivsenthil.postcode" /></a>
<!-- <img src="https://img.shields.io/visual-studio-marketplace/d/rohinivsenthil.postcode" /> -->
<a href="https://marketplace.visualstudio.com/items?itemName=rohinivsenthil.postcode&ssr=false#version-history"><img src="https://img.shields.io/visual-studio-marketplace/v/rohinivsenthil.postcode" /></a>
<a href="https://marketplace.visualstudio.com/items?itemName=rohinivsenthil.postcode&ssr=false#review-details"><img src="https://img.shields.io/visual-studio-marketplace/r/rohinivsenthil.postcode" /></a>
</div>
<br />
Postcode is a [Visual Studio Code](https://code.visualstudio.com/) [extension](https://marketplace.visualstudio.com/VSCode) that can be used to create and test simple and complex HTTP/s requests, as well as view responses. You can find the extension available [here](https://marketplace.visualstudio.com/items?itemName=rohinivsenthil.postcode).
<div align="center">
<img src="https://user-images.githubusercontent.com/42040329/120920378-0c83c880-c6dc-11eb-814a-e667563eed95.gif"/>
<br/>
<sup>Release: 1.3.3</sup>
</div>
## Highlighted Features
- **Intuitive UI/UX** similar to Postman fitting seamlessly with any VSCode theme
- Supports **GraphQL** requests
- Supports **code snippet generation** from requests
## Quick start
**Step 1.** Install the Postcode extension for Visual Studio Code
**Step 2.** Click on the Postcode icon in the side panel OR run the following command **Postcode: Create Request**
**Step 3** Create or test your HTTP/s requests and hit Send to see the responses
## Commands
| Command | Description |
| ------------------------ | ---------------------------------------------------- |
| Postcode: Create Request | Opens a new Postcode tab to create and test requests |
## Issues, feature requests, and contributions
### Issues
- If you come across a problem with the extension, please file an [issue](https://github.com/rohinivsenthil/postcode/issues/new)
- For list of known issues, please check the [issues tab](https://github.com/rohinivsenthil/postcode/issues/new)
### Feature requests
- Find planned features for future releases marked as [feature](https://github.com/rohinivsenthil/postcode/issues?q=is%3Aissue+is%3Aopen+label%3Afeature) under issues tab.
- For new feature requests, please file an [issue](https://github.com/rohinivsenthil/postcode/issues/new)
### Contributions
Contributions are always welcome!
#### Running the extension locally for development
1. Clone the repository and install dependencies by running `yarn install`
2. Press `F5` to open a new window with your extension loaded.
3. Run your command from the command palette by pressing (`Ctrl+Shift+P` or `Cmd+Shift+P` on Mac) and typing `Postcode: Create Request`.
#### Folder structure
- **`package.json`** - this is the manifest file in which you declare your extension and command. The plugin registers a command and defines its title and command name. With this information VS Code can show the command in the command palette.
- **`webview`**: folder where you will find entire React code
- **`src/extension.ts`**: this is the main file where you will provide the implementation of your command. The file exports one function, `activate`, which is called the very first time your extension is activated (in this case by executing the command). Inside the `activate` function we call `registerCommand`. We pass the function containing the implementation of the command as the second parameter to `registerCommand`.
#### Making changes
- You can relaunch the extension from the debug toolbar after changing code in `src/extension.ts`.
- You can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes.
## Related
- Read the [launch blog](https://rohinivsenthil.medium.com/postcode-vs-code-extension-alternative-to-postman-384816d4cf07) post on Medium
- Featured #11 Product of the day on [Product Hunt](https://www.producthunt.com/posts/postcode)
- Featured in **Trending this week** on Visual Studio Code Marketplace
================================================
FILE: package.json
================================================
{
"name": "postcode",
"publisher": "rohinivsenthil",
"displayName": "Postcode",
"icon": "icons/icon.png",
"description": "An API client to test and create HTTP/s requests",
"version": "1.3.9",
"license": "MIT",
"bugs": {
"url": "https://github.com/rohinivsenthil/postcode/issues"
},
"author": {
"name": "Rohini Senthil",
"email": "rohinivsenthil@gmail.com"
},
"repository": {
"type": "git",
"url": "https://github.com/rohinivsenthil/postcode"
},
"engines": {
"vscode": "^1.56.0"
},
"categories": [
"Programming Languages"
],
"keywords": [
"api-client",
"postman",
"REST",
"graphql",
"http"
],
"activationEvents": [
"onCommand:postcode.createRequest"
],
"main": "./dist/extension.js",
"contributes": {
"commands": [
{
"command": "postcode.createRequest",
"title": "Postcode: Create Request"
}
],
"viewsContainers": {
"activitybar": [
{
"id": "postcode",
"title": "Postcode",
"icon": "webview/icons/package.svg"
}
]
},
"views": {
"postcode": [
{
"id": "postcode.request",
"name": "Request"
}
]
},
"viewsWelcome": [
{
"view": "postcode.request",
"contents": "[Create Request](command:postcode.createRequest)"
}
]
},
"scripts": {
"vscode:prepublish": "yarn run package",
"compile": "cross-env NODE_ENV=development webpack --progress",
"watch": "cross-env NODE_ENV=development webpack --progress --watch",
"package": "cross-env NODE_ENV=production webpack --progress",
"test-compile": "tsc -p ./",
"test-watch": "tsc -watch -p ./",
"pretest": "yarn run test-compile && yarn run lint",
"lint": "eslint src webview --ext .ts,.tsx",
"lint:fix": "eslint --fix src webview --ext .ts,.tsx",
"test": "node ./out/test/runTest.js",
"prepare": "husky install"
},
"devDependencies": {
"@svgr/webpack": "^5.5.0",
"@types/glob": "^7.1.3",
"@types/mocha": "^8.0.4",
"@types/node": "^12.11.7",
"@types/react": "^17.0.5",
"@types/react-dom": "^17.0.4",
"@types/react-redux": "^7.1.16",
"@types/vscode": "^1.56.0",
"@typescript-eslint/eslint-plugin": "^4.14.1",
"@typescript-eslint/parser": "^4.14.1",
"cross-env": "^7.0.3",
"css-loader": "^5.2.4",
"eslint": "^7.19.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^3.4.0",
"eslint-plugin-react": "^7.23.2",
"file-loader": "^6.2.0",
"glob": "^7.1.6",
"husky": "^7.0.1",
"mini-css-extract-plugin": "^1.6.0",
"mocha": "^8.2.1",
"monaco-editor-webpack-plugin": "^3.1.0",
"prettier": "2.3.0",
"static-site-generator-webpack-plugin": "^3.4.2",
"style-loader": "^2.0.0",
"ts-loader": "^8.0.14",
"typescript": "^4.1.3",
"url-loader": "^4.1.1",
"vscode-test": "^1.5.0",
"webpack": "^5.19.0",
"webpack-cli": "^4.4.0"
},
"dependencies": {
"@reduxjs/toolkit": "^1.5.1",
"axios": "^0.21.1",
"buffer": "^6.0.3",
"monaco-editor": "^0.24.0",
"path-browserify": "^1.0.1",
"postman-code-generators": "^1.1.5",
"postman-collection": "^3.6.11",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-icons": "^4.2.0",
"react-redux": "^7.2.4",
"url": "^0.11.0"
}
}
================================================
FILE: src/extension.ts
================================================
// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
import * as vscode from "vscode";
import * as fs from "fs";
import axios from "axios";
import * as https from "https";
import { RequestOptions } from "../webview/features/requestOptions/requestOptionsSlice";
// this method is called when your extension is activated
// your extension is activated the very first time the command is executed
export function activate(context: vscode.ExtensionContext) {
const webviewContent = fs
.readFileSync(
vscode.Uri.joinPath(context.extensionUri, "dist/index.html").fsPath,
{ encoding: "utf-8" }
)
.replace(
"styleUri",
vscode.Uri.joinPath(context.extensionUri, "/dist/main.css")
.with({ scheme: "vscode-resource" })
.toString()
)
.replace(
"scriptUri",
vscode.Uri.joinPath(context.extensionUri, "/dist/webview.js")
.with({ scheme: "vscode-resource" })
.toString()
);
// The command has been defined in the package.json file
// Now provide the implementation of the command with registerCommand
// The commandId parameter must match the command field in package.json
const disposable = vscode.commands.registerCommand(
"postcode.createRequest",
() => {
// The code you place here will be executed every time your command is executed
// Display a message box to the user
vscode.window.showInformationMessage("Welcome to Postcode!");
const panel = vscode.window.createWebviewPanel(
"postcode",
"Postcode",
vscode.ViewColumn.One,
{
enableScripts: true,
retainContextWhenHidden: true,
localResourceRoots: [
vscode.Uri.joinPath(context.extensionUri, "dist"),
],
}
);
panel.webview.html = webviewContent;
panel.iconPath = vscode.Uri.joinPath(
context.extensionUri,
"icons/icon.png"
);
panel.webview.onDidReceiveMessage(
({ method, url, headers, body, auth, options }) => {
// Options Section
const requestOptions = options as RequestOptions;
let requestStartedAt, responseDuration;
if (!url) {
panel.webview.postMessage({
type: "response",
error: { message: "Request URL is empty" },
});
vscode.window.showInformationMessage("Request URL is empty");
return;
}
const headersObj = {};
if (auth.type === "bearer") {
headersObj["Authorization"] = `Bearer ${auth.bearer.token}`;
}
headers.forEach(({ key, value, disabled }) => {
if (!disabled) {
headersObj[key] = value;
}
});
let data = "";
if (body.mode === "formdata") {
const dataObj = new URLSearchParams();
body.formdata.forEach(({ key, value, disabled }) => {
if (!disabled) {
dataObj.append(key, value);
}
});
data = dataObj.toString();
headersObj["Content-Type"] = "multipart/form-data";
} else if (body.mode === "urlencoded") {
const dataObj = new URLSearchParams();
body.urlencoded.forEach(({ key, value, disabled }) => {
if (!disabled) {
dataObj.append(key, value);
}
});
data = dataObj.toString();
headersObj["Content-Type"] = "application/x-www-form-urlencoded";
} else if (body.mode === "raw") {
data = body.raw;
headersObj["Content-Type"] = {
json: "application/json",
html: "text/html",
xml: "text/xml",
text: "text/plain",
}[body.options.raw.language];
} else if (body.mode === "file") {
data = body.fileData;
headersObj["Content-Type"] = "application/octet-stream";
} else if (body.mode === "graphql") {
data = JSON.stringify({
query: body.graphql.query,
variables: body.graphql.variables,
});
headersObj["Content-Type"] = "application/json";
}
// Option 1. StrictSSL
https.globalAgent.options.rejectUnauthorized =
requestOptions.strictSSL === "yes";
axios.interceptors.request.use((config) => {
requestStartedAt = new Date().getTime();
return config;
});
axios.interceptors.response.use((config) => {
responseDuration = new Date().getTime() - requestStartedAt;
return config;
});
axios({
method,
url,
baseURL: "",
data: data,
headers: headersObj,
auth: auth.type === "basic" ? auth.basic : undefined,
transformResponse: [(data) => data],
responseType: "text",
validateStatus: () => true,
})
.then((resp) =>
panel.webview.postMessage({
type: "response",
data: resp.data,
status: resp.status,
statusText: resp.statusText,
headers: resp.headers,
duration: responseDuration,
})
)
.catch((err) => {
panel.webview.postMessage({
type: "response",
error: err,
});
vscode.window.showInformationMessage(
"Error: Could not send request"
);
});
}
);
}
);
context.subscriptions.push(disposable);
}
// this method is called when your extension is deactivated
// eslint-disable-next-line @typescript-eslint/no-empty-function
export function deactivate() {}
================================================
FILE: src/test/runTest.ts
================================================
import * as path from "path";
import { runTests } from "vscode-test";
async function main() {
try {
// The folder containing the Extension Manifest package.json
// Passed to `--extensionDevelopmentPath`
const extensionDevelopmentPath = path.resolve(__dirname, "../../");
// The path to test runner
// Passed to --extensionTestsPath
const extensionTestsPath = path.resolve(__dirname, "./suite/index");
// Download VS Code, unzip it and run the integration test
await runTests({ extensionDevelopmentPath, extensionTestsPath });
} catch (err) {
console.error("Failed to run tests");
process.exit(1);
}
}
main();
================================================
FILE: src/test/suite/extension.test.ts
================================================
import * as assert from "assert";
// You can import and use all API from the 'vscode' module
// as well as import your extension to test it
import * as vscode from "vscode";
// import * as myExtension from '../../extension';
suite("Extension Test Suite", () => {
vscode.window.showInformationMessage("Start all tests.");
test("Sample test", () => {
assert.strictEqual(-1, [1, 2, 3].indexOf(5));
assert.strictEqual(-1, [1, 2, 3].indexOf(0));
});
});
================================================
FILE: src/test/suite/index.ts
================================================
import * as path from "path";
import * as Mocha from "mocha";
import * as glob from "glob";
export function run(): Promise<void> {
// Create the mocha test
const mocha = new Mocha({
ui: "tdd",
color: true,
});
const testsRoot = path.resolve(__dirname, "..");
return new Promise((c, e) => {
glob("**/**.test.js", { cwd: testsRoot }, (err, files) => {
if (err) {
return e(err);
}
// Add files to the test suite
files.forEach((f) => mocha.addFile(path.resolve(testsRoot, f)));
try {
// Run the mocha test
mocha.run((failures) => {
if (failures > 0) {
e(new Error(`${failures} tests failed.`));
} else {
c();
}
});
} catch (err) {
console.error(err);
e(err);
}
});
});
}
================================================
FILE: tsconfig.json
================================================
{
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"outDir": "out",
"jsx": "react",
"lib": ["es2019", "dom"],
"sourceMap": true,
"rootDir": ".",
"resolveJsonModule": true,
"strict": false /* enable all strict type-checking options */
/* Additional Checks */
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
// "noUnusedParameters": true, /* Report errors on unused parameters. */
},
"exclude": ["node_modules", ".vscode-test"]
}
================================================
FILE: webpack.config.js
================================================
/* eslint-disable @typescript-eslint/no-var-requires */
//@ts-check
"use strict";
const path = require("path");
const webpack = require("webpack");
const MonacoWebpackPlugin = require("monaco-editor-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const StaticSiteGeneratorPlugin = require("static-site-generator-webpack-plugin");
const imageInlineSizeLimit = parseInt(
process.env.IMAGE_INLINE_SIZE_LIMIT || "10000"
);
const baseConfig = (webpackEnv) => {
const isEnvDevelopment = webpackEnv === "development";
const isEnvProduction = webpackEnv === "production";
return {
mode: isEnvProduction ? "production" : isEnvDevelopment && "development",
bail: isEnvProduction,
devtool: isEnvProduction
? "source-map"
: isEnvDevelopment && "eval-cheap-module-source-map",
resolve: {
fallback: {
buffer: require.resolve("buffer"),
path: require.resolve("path-browserify"),
url: require.resolve("url"),
},
extensions: [".ts", ".tsx", ".js"],
},
module: {
rules: [
{
oneOf: [
{
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
loader: require.resolve("url-loader"),
options: {
limit: imageInlineSizeLimit,
name: "static/media/[name].[hash:8].[ext]",
},
},
{
test: /\.svg$/,
use: [
require.resolve("@svgr/webpack"),
require.resolve("url-loader"),
],
},
{
test: /\.tsx?$/,
exclude: /node_modules/,
loader: require.resolve("ts-loader"),
},
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: require.resolve("css-loader"),
options: {
importLoaders: 1,
sourceMap: isEnvProduction || isEnvDevelopment,
},
},
],
sideEffects: true,
},
{
loader: require.resolve("file-loader"),
exclude: [/\.(js|mjs|jsx|ts|tsx)$/, /\.html$/, /\.json$/],
options: {
name: "media/[name].[hash:8].[ext]",
},
},
],
},
],
},
plugins: [
new MiniCssExtractPlugin({
filename: "ignore.css",
}),
],
};
};
const extensionConfig = (webpackEnv) => {
return {
...baseConfig(webpackEnv),
target: "node",
entry: "./src/extension.ts",
output: {
path: path.resolve(__dirname, "dist"),
filename: "extension.js",
libraryTarget: "commonjs2",
},
externals: { vscode: "commonjs vscode" },
};
};
const webviewConfig = (webpackEnv) => {
return {
...baseConfig(webpackEnv),
entry: "./webview/index.tsx",
output: {
path: path.resolve(__dirname, "dist"),
filename: "webview.js",
},
plugins: [
new MiniCssExtractPlugin(),
new MonacoWebpackPlugin({
languages: [
"csharp",
"dart",
"go",
"graphql",
"html",
"java",
"typescript",
"json",
"objective-c",
"php",
"powershell",
"python",
"ruby",
"shell",
"swift",
"xml",
],
}),
new webpack.ProvidePlugin({
Buffer: ["buffer", "Buffer"],
process: "process/browser",
}),
],
};
};
const prerenderConfig = (webpackEnv) => {
const config = baseConfig(webpackEnv);
return {
...config,
target: "node",
entry: "./webview/prerender.tsx",
output: {
path: path.resolve(__dirname, "dist"),
filename: "prerender.js",
libraryTarget: "commonjs2",
},
plugins: [
new MiniCssExtractPlugin({
filename: "ignore.css",
}),
new StaticSiteGeneratorPlugin({
paths: ["/"],
}),
new webpack.ProvidePlugin({
Buffer: ["buffer", "Buffer"],
process: "process/browser",
}),
],
};
};
module.exports = [extensionConfig, webviewConfig, prerenderConfig];
================================================
FILE: webview/App.css
================================================
.App {
background-color: var(--background);
}
================================================
FILE: webview/App.tsx
================================================
import * as React from "react";
import "./App.css";
import { responseUpdated } from "./features/response/responseSlice";
import { Postcode } from "./pages/Postcode";
import { useAppDispatch } from "./redux/hooks";
const App = () => {
const dispatch = useAppDispatch();
React.useEffect(() => {
window.addEventListener("message", (event) => {
if (event.data.type === "response") {
dispatch(responseUpdated(event.data));
}
});
}, []);
return (
<div className="App">
<Postcode />
</div>
);
};
export default App;
================================================
FILE: webview/acquireVsCodeApi.d.ts
================================================
declare var acquireVsCodeApi: any;
================================================
FILE: webview/components/RequestBar/index.tsx
================================================
import * as React from "react";
import { Url } from "postman-collection";
import vscode from "../../vscode";
import { RequestMethodSelector } from "../../features/requestMethod/RequestMethodSelector";
import { RequestUrl } from "../../features/requestUrl/RequestUrl";
import { responseLoadingStarted } from "../../features/response/responseSlice";
import { selectRequestAuth } from "../../features/requestAuth/requestAuthSlice";
import { selectRequestBody } from "../../features/requestBody/requestBodySlice";
import { selectRequestHeaders } from "../../features/requestHeader/requestHeaderSlice";
import { selectRequestUrl } from "../../features/requestUrl/requestUrlSlice";
import { selectRequestMethod } from "../../features/requestMethod/requestMethodSlice";
import { selectRequestOptions } from "../../features/requestOptions/requestOptionsSlice";
import { useAppDispatch, useAppSelector } from "../../redux/hooks";
import "./styles.css";
export const RequestBar = () => {
const dispatch = useAppDispatch();
const requestMethod = useAppSelector(selectRequestMethod);
const requestHeaders = useAppSelector(selectRequestHeaders);
const requestBody = useAppSelector(selectRequestBody);
const requestUrl = useAppSelector(selectRequestUrl);
const requestAuth = useAppSelector(selectRequestAuth);
const requestOptions = useAppSelector(selectRequestOptions);
return (
<form
className="request-bar"
onSubmit={(e) => {
dispatch(responseLoadingStarted());
const { protocol } = Url.parse(requestUrl);
vscode.postMessage({
method: requestMethod,
auth: requestAuth,
body: requestBody,
headers: requestHeaders,
url: protocol ? requestUrl : `http://${requestUrl}`,
options: requestOptions,
});
e.preventDefault();
}}
>
<RequestMethodSelector />
<RequestUrl />
<button
name="request-send"
id="request-send"
type="submit"
className="button-request-send"
>
Send
</button>
</form>
);
};
================================================
FILE: webview/components/RequestBar/styles.css
================================================
.request-bar {
display: flex;
padding: 0 20px;
padding-top: 30px;
}
.input-request-url {
flex: 2;
padding: 13px 20px;
color: var(--default-text);
display: inline-block;
outline: none;
border: 0;
border-radius: 0 2px 2px 0;
background-color: var(--input-field);
font-size: var(--default-font-size);
}
.input-request-url:focus {
outline: none;
}
.input-request-url:hover {
background-color: var(--input-field-hover);
}
.button-request-send {
background-color: var(--send-button);
color: #fff;
font-weight: bold;
padding: 13px 20px;
margin: 0 0 0 12px;
display: inline-block;
outline: none;
border-radius: 5%;
border: 0;
cursor: pointer;
font-size: var(--default-font-size);
}
.button-request-send:hover {
background-color: var(--send-button-hover);
}
================================================
FILE: webview/components/RequestOptionsBar/index.tsx
================================================
import * as React from "react";
import "./styles.css";
import * as propTypes from "prop-types";
import { requestOptions } from "../../constants/request-options";
import { useAppSelector } from "../../redux/hooks";
import { selectRequestHeaders } from "../../features/requestHeader/requestHeaderSlice";
export const RequestOptionsTab = (props) => {
const { selected, setSelected } = props;
const header = useAppSelector(selectRequestHeaders);
return (
<div className="request-options-tab-wrapper">
<div className="request-options">
{requestOptions.map((option) => (
<button
key={option.value}
onClick={() => setSelected(option.value)}
className={
selected === option.value
? "request-option request-option-selected"
: "request-option"
}
>
{option.name}
{option.value === "headers" ? (
<div className="request-options-header-length">
(
{
header.filter(
({ key, value, description }) => key || value || description
).length
}
)
</div>
) : null}
</button>
))}
</div>
<button
id="request-code"
name="request-code"
className="button-request"
onClick={() => setSelected("code")}
>
Code
</button>
</div>
);
};
RequestOptionsTab.propTypes = {
selected: propTypes.string.isRequired,
setSelected: propTypes.func.isRequired,
};
================================================
FILE: webview/components/RequestOptionsBar/styles.css
================================================
.request-options-tab-wrapper {
display: flex;
justify-content: space-between;
padding: 15px 20px 0 20px;
}
.request-options {
display: flex;
}
.request-option {
padding: 0px 5px 10px 5px;
margin: 0 10px 0 0;
display: flex;
cursor: pointer;
background-color: transparent;
color: var(--default-text-light);
outline: none;
border: 3px solid transparent;
border-radius: 0;
font-weight: 500;
font-size: var(--default-font-size);
}
.request-option:hover {
color: var(--default-text);
}
.request-option-selected {
color: var(--default-text);
border-bottom: 3px solid var(--primary);
}
.request-options-header-length {
margin-left: 4px;
color: var(--tab-info);
}
.button-request {
display: inline-block;
cursor: pointer;
background-color: transparent;
color: var(--primary);
outline: none;
border: 3px solid transparent;
border-radius: 0;
font-weight: 500;
font-size: var(--default-font-size);
}
.button-request:hover {
color: var(--primary-dark);
}
.hidden {
display: none;
}
================================================
FILE: webview/components/RequestOptionsWindow/index.tsx
================================================
import * as React from "react";
import { RequestQueryParams } from "../../features/requestUrl/RequestQueryParams";
import { RequestAuth } from "../../features/requestAuth/RequestAuth";
import { Body } from "../../features/requestBody/RequestBody";
import { Headers } from "../../features/requestHeader/HeadersWindow";
import { CodeSnippet } from "../../features/codeGen/CodeSnippet";
import { RequestOptions } from "../../features/requestOptions/RequestOptions";
import * as propTypes from "prop-types";
import "./styles.css";
export const RequestOptionsWindow = (props) => {
const { selected } = props;
return (
<div className="request-options-window-wrapper">
{selected === "params" ? (
<RequestQueryParams />
) : selected === "authorization" ? (
<RequestAuth />
) : selected === "body" ? (
<Body />
) : selected === "headers" ? (
<Headers />
) : selected === "code" ? (
<CodeSnippet />
) : selected === "options" ? (
<RequestOptions />
) : null}
</div>
);
};
RequestOptionsWindow.propTypes = {
selected: propTypes.string.isRequired,
};
================================================
FILE: webview/components/RequestOptionsWindow/styles.css
================================================
.request-options-window-wrapper {
flex: 1;
padding: 5px 20px 10px 20px;
overflow: scroll;
}
================================================
FILE: webview/components/Response/index.tsx
================================================
import * as React from "react";
import { ResponseTab } from "../../features/response/ResponseTab";
import { ResponseWindow } from "../../features/response/ResponseWindow";
import { ReactComponent as PackageIcon } from "../../icons/package.svg";
import "./styles.css";
import { useAppSelector } from "../../redux/hooks";
import { selectResponse } from "../../features/response/responseSlice";
import { supportedLangs } from "../../constants/supported-langs";
export const Response = () => {
const response = useAppSelector(selectResponse);
const [selected, setSelected] = React.useState("body");
const [language, setLanguage] = React.useState(supportedLangs[0].value);
if (response.loading) {
return (
<div className="loader-wrapper">
<div>Sending request ...</div>
<div className="loader" />
</div>
);
} else if (response.initial) {
return (
<div className="initial-response-wrapper">
<div className="initial-text">Hit Send to get a response</div>
<PackageIcon className="img-initial-response" />
</div>
);
} else if (response.error) {
return (
<div className="error-response-wrapper">
<div>Could not send request</div>
<div className="error-message">{`Error: ${response.error.message}`}</div>
<PackageIcon className="img-error-response" />
</div>
);
} else {
return (
<div className="response-body-wrapper">
<ResponseTab
selected={selected}
setSelected={setSelected}
language={language}
setLanguage={setLanguage}
/>
<ResponseWindow selected={selected} language={language} />
</div>
);
}
};
================================================
FILE: webview/components/Response/styles.css
================================================
.response-body-wrapper {
display: flex;
flex-direction: column;
flex: 1;
font-size: var(--default-font-size);
border-top: var(--default-border-size) solid var(--border);
}
.error-response-wrapper {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
font-size: var(--default-font-size);
border-top: var(--default-border-size) solid var(--border);
}
.img-error-response {
margin: 15px;
fill: var(--logo-color);
width: 20%;
height: 20%;
}
.error-message {
margin: 10px;
color: var(--error-message);
}
.initial-response-wrapper {
border-top: var(--default-border-size) solid var(--border);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: var(--default-text-light);
font-size: var(--default-font-size);
flex: 1;
}
.img-initial-response {
fill: var(--logo-color);
width: 20%;
height: 20%;
}
.initial-text {
padding: 10px;
}
.loader-wrapper {
border-top: var(--default-border-size) solid var(--border);
display: flex;
flex: 1;
flex-direction: column;
justify-content: center;
align-items: center;
font-size: var(--default-font-size);
}
.loader,
.loader:before,
.loader:after {
border-radius: 50%;
width: 20px;
height: 20px;
-webkit-animation-fill-mode: both;
animation-fill-mode: both;
-webkit-animation: load7 1.8s infinite ease-in-out;
animation: load7 1.8s infinite ease-in-out;
}
.loader {
color: var(--border);
position: relative;
text-indent: -9999em;
-webkit-transform: translateZ(0);
-ms-transform: translateZ(0);
transform: translateZ(0);
-webkit-animation-delay: -0.16s;
animation-delay: -0.16s;
}
.loader:before,
.loader:after {
content: "";
position: absolute;
top: 0;
}
.loader:before {
left: -3.5em;
-webkit-animation-delay: -0.32s;
animation-delay: -0.32s;
}
.loader:after {
left: 3.5em;
}
@-webkit-keyframes load7 {
0%,
80%,
100% {
box-shadow: 0 2.5em 0 -1.3em;
}
40% {
box-shadow: 0 2.5em 0 0;
}
}
@keyframes load7 {
0%,
80%,
100% {
box-shadow: 0 2.5em 0 -1.3em;
}
40% {
box-shadow: 0 2.5em 0 0;
}
}
================================================
FILE: webview/constants/request-options.ts
================================================
export const requestOptions = [
{
name: "Params",
value: "params",
},
{
name: "Authorization",
value: "authorization",
},
{
name: "Headers",
value: "headers",
},
{
name: "Body",
value: "body",
},
{
name: "Options",
value: "options",
},
];
================================================
FILE: webview/constants/response-options.ts
================================================
export const responseOptions = [
{
name: "Body",
value: "body",
},
{
name: "Headers",
value: "headers",
},
];
================================================
FILE: webview/constants/response-views.ts
================================================
export const responseViews = [
{
name: "Pretty",
value: "pretty",
},
{
name: "Raw",
value: "raw",
},
];
================================================
FILE: webview/constants/supported-langs.ts
================================================
export const supportedLangs = [
{
name: "JSON",
value: "json",
},
{
name: "HTML",
value: "html",
},
{
name: "XML",
value: "xml",
},
{
name: "Text",
value: "text",
},
];
================================================
FILE: webview/features/codeGen/CodeSnippet/index.tsx
================================================
import * as React from "react";
import "./styles.css";
import {
codeGenLanguageUpdated,
codeGenOptions,
codeGenVariantUpdated,
selectCodeGenEditorLanguage,
selectCodeGenLanguage,
selectCodeGenLanguageKey,
selectCodeGenVariant,
selectRequest,
} from "../codeGenSlice";
import * as codegen from "postman-code-generators";
import { useAppDispatch, useAppSelector } from "../../../redux/hooks";
const Editor = React.lazy(() => import("../../../shared/Editor"));
export const CodeSnippet = () => {
const [code, setCode] = React.useState("");
const language = useAppSelector(selectCodeGenLanguage);
const variant = useAppSelector(selectCodeGenVariant);
const editorLanguage = useAppSelector(selectCodeGenEditorLanguage);
const languageKey = useAppSelector(selectCodeGenLanguageKey);
const dispatch = useAppDispatch();
const request = useAppSelector(selectRequest);
React.useEffect(() => {
codegen.convert(languageKey, variant, request, {}, (err, snippet) => {
setCode(snippet);
});
}, [languageKey, variant, request]);
return (
<div className="code-gen-wrapper">
<div className="code-gen-option">
<select
onChange={(e) => dispatch(codeGenLanguageUpdated(e.target.value))}
className="select-code-option"
value={language}
>
{codeGenOptions.map(({ language }) => (
<option key={language} value={language}>
{language}
</option>
))}
</select>
<select
onChange={(e) => dispatch(codeGenVariantUpdated(e.target.value))}
className="select-code-option"
value={variant}
>
{codeGenOptions
.filter(({ language: lang }) => lang === language)[0]
.variants.map((variant) => (
<option key={variant} value={variant}>
{variant}
</option>
))}
</select>
</div>
<div className="code-display">
<React.Suspense fallback={<div>loading</div>}>
<Editor
className="code-gen-editor"
value={code}
language={editorLanguage}
readOnly
copyButton
/>
</React.Suspense>
</div>
</div>
);
};
================================================
FILE: webview/features/codeGen/CodeSnippet/styles.css
================================================
.code-gen-wrapper {
height: 100%;
display: flex;
flex-direction: column;
}
.code-gen-options {
display: flex;
align-items: center;
}
.code-display {
height: 95%;
border-top: var(--default-border-size) solid var(--border);
margin-top: 15px;
}
.code-gen-editor {
height: 95%;
}
.select-code-option {
padding: 4px;
margin-right: 8px;
display: inline-block;
font-weight: 600;
outline: none;
border: var(--default-border-size) solid var(--border);
border-radius: 2px;
background-color: var(--background);
color: var(--default-text-light);
cursor: pointer;
font-size: var(--default-font-size);
}
.select-code-option:hover {
color: var(--default-text);
}
.select-code-option:focus {
outline: none;
}
================================================
FILE: webview/features/codeGen/codeGenSlice.ts
================================================
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { RootState } from "../../redux/store";
import { Request } from "postman-collection";
export const codeGenOptions = [
{ language: "C", variants: ["libcurl"], editor: "c", key: "c" },
{ language: "C#", variants: ["RestSharp"], editor: "csharp", key: "csharp" },
{ language: "cURL", variants: ["cURL"], editor: "shell", key: "curl" },
{ language: "Dart", variants: ["http"], editor: "dart", key: "dart" },
{ language: "Go", variants: ["Native"], editor: "go", key: "go" },
{ language: "HTTP", variants: ["HTTP"], editor: "text", key: "http" },
{ language: "Java", variants: ["OkHttp", "Unirest"], editor: "java" },
{
language: "JavaScript",
variants: ["Fetch", "jQuery", "XHR"],
editor: "javascript",
key: "javascript",
},
{
language: "NodeJs",
variants: ["Axios", "Native", "Request", "Unirest"],
editor: "javascript",
key: "nodejs",
},
{
language: "Objective-C",
variants: ["NSURLSession"],
editor: "objective-c",
key: "objective-c",
},
{ language: "OCaml", variants: ["Cohttp"], editor: "text", key: "ocaml" },
{
language: "PHP",
variants: ["cURL", "pecl_http", "HTTP_Request2"],
editor: "php",
key: "php",
},
{
language: "PowerShell",
variants: ["RestMethod"],
editor: "powershell",
key: "powershell",
},
{
language: "Python",
variants: ["http.client", "Requests"],
editor: "python",
key: "python",
},
{ language: "Ruby", variants: ["Net:HTTP"], editor: "ruby", key: "ruby" },
{
language: "Shell",
variants: ["Httpie", "wget"],
editor: "shell",
key: "shell",
},
{
language: "Swift",
variants: ["URLSession"],
editor: "swift",
key: "swift",
},
];
export interface codeGenOptionState {
language: string;
variant: string;
}
const initialState = { language: "C", variant: "libcurl" };
const codeGenSlice = createSlice({
name: "codeGenOptions",
initialState,
reducers: {
codeGenLanguageUpdated(state, action: PayloadAction<string>) {
state.language = action.payload;
state.variant = codeGenOptions.filter(
({ language }) => language === action.payload
)[0].variants[0];
},
codeGenVariantUpdated(state, action: PayloadAction<string>) {
state.variant = action.payload;
},
},
});
export const { codeGenLanguageUpdated, codeGenVariantUpdated } =
codeGenSlice.actions;
export const selectCodeGenLanguage = (state: RootState) =>
state.codeGenOptions.language;
export const selectCodeGenVariant = (state: RootState) =>
state.codeGenOptions.variant;
export const selectCodeGenEditorLanguage = (state: RootState) =>
codeGenOptions.filter(
({ language }) => language === state.codeGenOptions.language
)[0].editor;
export const selectCodeGenLanguageKey = (state: RootState) =>
codeGenOptions.filter(
({ language }) => language === state.codeGenOptions.language
)[0].key;
export const selectRequest = (state: RootState) =>
new Request({
method: state.requestMethod,
url: state.requestUrl,
header: state.requestHeader,
body: {
mode: state.requestBody.mode,
options: state.requestBody.options,
[state.requestBody.mode]: state.requestBody[state.requestBody.mode],
},
auth: {
type: state.requestAuth.type,
[state.requestAuth.type]: state.requestAuth[state.requestAuth.type],
},
});
export default codeGenSlice.reducer;
================================================
FILE: webview/features/requestAuth/BasicAuth/index.tsx
================================================
import * as React from "react";
import "./styles.css";
import { useAppDispatch, useAppSelector } from "../../../redux/hooks";
import {
requestAuthOptionsUpdated,
selectBasicAuthOptions,
} from "../requestAuthSlice";
export const BasicAuth = () => {
const basicAuthOptions = useAppSelector(selectBasicAuthOptions);
const dispatch = useAppDispatch();
return (
<div>
<div className="basic-auth-input-group">
<div className="label-basic-auth">Username</div>
<input
type="text"
id="basic-auth-username-input"
name="basic-auth-username-input"
placeholder="Username"
autoComplete="off"
className="input-basic-auth"
value={basicAuthOptions.username}
onChange={(e) =>
dispatch(
requestAuthOptionsUpdated({
username: e.target.value,
password: basicAuthOptions.password,
})
)
}
/>
</div>
<div className="basic-auth-input-group">
<div className="label-basic-auth">Password</div>
<input
type="password"
id="basic-auth-password-input"
name="basic-auth-password-input"
placeholder="Password"
autoComplete="off"
className="input-basic-auth"
value={basicAuthOptions.password}
onChange={(e) =>
dispatch(
requestAuthOptionsUpdated({
username: basicAuthOptions.username,
password: e.target.value,
})
)
}
/>
</div>
</div>
);
};
================================================
FILE: webview/features/requestAuth/BasicAuth/styles.css
================================================
.basic-auth-input-group {
padding: 15px 0 0 0;
display: flex;
align-items: center;
justify-content: center;
}
.label-basic-auth {
font-size: var(--default-font-size);
color: var(--default-text);
padding-right: 20px;
}
.input-basic-auth {
width: 60%;
padding: 13px 20px;
color: var(--default-text);
display: inline-block;
outline: none;
border: 0;
border-radius: 0 2px 2px 0;
background-color: var(--input-field);
font-size: var(--default-font-size);
}
.input-basic-auth:focus {
outline: none;
}
.input-basic-auth:hover {
background-color: var(--input-field-hover);
}
================================================
FILE: webview/features/requestAuth/BearerToken/index.tsx
================================================
import * as React from "react";
import { useAppDispatch, useAppSelector } from "../../../redux/hooks";
import {
requestAuthOptionsUpdated,
selectBearerAuthOptions,
} from "../requestAuthSlice";
import "./styles.css";
export const BearerToken = () => {
const bearerAuthOptions = useAppSelector(selectBearerAuthOptions);
const dispatch = useAppDispatch();
return (
<div className="bearer-token-wrapper">
<div className="label-bearer-token">Token</div>
<input
type="text"
id="bearer-token-input"
name="bearer-token-input"
placeholder="Token"
autoComplete="off"
className="input-bearer-token"
value={bearerAuthOptions.token}
onChange={(e) =>
dispatch(requestAuthOptionsUpdated({ token: e.target.value }))
}
/>
</div>
);
};
================================================
FILE: webview/features/requestAuth/BearerToken/styles.css
================================================
.bearer-token-wrapper {
display: flex;
justify-content: center;
align-items: center;
padding: 15px 0;
}
.label-bearer-token {
font-size: var(--default-font-size);
color: var(--default-text);
padding-right: 20px;
}
.input-bearer-token {
width: 60%;
padding: 13px 20px;
color: var(--default-text);
display: inline-block;
outline: none;
border: 0;
border-radius: 0 2px 2px 0;
background-color: var(--input-field);
font-size: var(--default-font-size);
}
.input-bearer-token:focus {
outline: none;
}
.input-bearer-token:hover {
background-color: var(--input-field-hover);
}
================================================
FILE: webview/features/requestAuth/NoAuth/index.tsx
================================================
import * as React from "react";
import "./styles.css";
export const NoAuth = () => {
return (
<div className="no-auth-wrapper">
<div className="none-prompt">
This request does not use any authorization.
</div>
</div>
);
};
================================================
FILE: webview/features/requestAuth/NoAuth/styles.css
================================================
.no-auth-wrapper {
display: flex;
justify-content: center;
}
================================================
FILE: webview/features/requestAuth/RequestAuth/index.tsx
================================================
import * as React from "react";
import "./styles.css";
import { NoAuth } from "../NoAuth";
import { BearerToken } from "../BearerToken";
import { BasicAuth } from "../BasicAuth";
import { useAppDispatch, useAppSelector } from "../../../redux/hooks";
import {
requestAuthTypes,
requestAuthTypeUpdated,
selectRequestAuthType,
} from "../requestAuthSlice";
export const RequestAuth = () => {
const requestAuthType = useAppSelector(selectRequestAuthType);
const dispatch = useAppDispatch();
return (
<div className="req-auth-wrapper">
<div className="auth-type">
<div className="label-auth-type">Authorization Type: </div>
<select
onChange={(e) => dispatch(requestAuthTypeUpdated(e.target.value))}
className="select-auth-type"
value={requestAuthType}
>
{requestAuthTypes.map(({ value, name }) => (
<option key={value} value={value}>
{name}
</option>
))}
</select>
</div>
<div className="req-auth-type-window">
{requestAuthType === "noauth" ? (
<NoAuth />
) : requestAuthType === "bearer" ? (
<BearerToken />
) : requestAuthType === "basic" ? (
<BasicAuth />
) : null}
</div>
</div>
);
};
================================================
FILE: webview/features/requestAuth/RequestAuth/styles.css
================================================
.req-auth-wrapper {
margin-top: 15px;
}
.auth-type {
display: flex;
align-items: center;
}
.label-auth-type {
font-size: var(--default-font-size);
color: var(--default-text);
padding-right: 12px;
}
.select-auth-type {
padding: 4px;
display: inline-block;
font-weight: 600;
outline: none;
border: var(--default-border-size) solid var(--border);
border-radius: 2px;
background-color: var(--background);
color: var(--default-text-light);
cursor: pointer;
font-size: var(--default-font-size);
}
.select-auth-type:hover {
color: var(--default-text);
}
.select-auth-type:focus {
outline: none;
}
.req-auth-type-window {
border-top: var(--default-border-size) solid var(--border);
margin-top: 15px;
}
================================================
FILE: webview/features/requestAuth/requestAuthSlice.ts
================================================
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { RootState } from "../../redux/store";
export const requestAuthTypes = [
{ name: "No Auth", value: "noauth" },
{ name: "Bearer Token", value: "bearer" },
{ name: "Basic Auth", value: "basic" },
];
export interface BearerAuthOptions {
token: string;
}
export interface BasicAuthOptions {
username: string;
password: string;
}
export interface RequestAuthState {
type: string;
bearer: BearerAuthOptions;
basic: BasicAuthOptions;
}
const initialState: RequestAuthState = {
type: "noauth",
bearer: { token: "" },
basic: { username: "", password: "" },
};
const requestAuthSlice = createSlice({
name: "requestAuth",
initialState,
reducers: {
requestAuthTypeUpdated(state, action: PayloadAction<string>) {
state.type = action.payload;
},
requestAuthOptionsUpdated(
state,
action: PayloadAction<BearerAuthOptions | BasicAuthOptions>
) {
state[state.type] = action.payload;
},
},
});
export const { requestAuthTypeUpdated, requestAuthOptionsUpdated } =
requestAuthSlice.actions;
export const selectRequestAuth = (state: RootState) => state.requestAuth;
export const selectRequestAuthType = (state: RootState) =>
state.requestAuth.type;
export const selectBearerAuthOptions = (state: RootState) =>
state.requestAuth.bearer;
export const selectBasicAuthOptions = (state: RootState) =>
state.requestAuth.basic;
export default requestAuthSlice.reducer;
================================================
FILE: webview/features/requestBody/Binary/index.tsx
================================================
import * as React from "react";
import "./styles.css";
import { useAppDispatch, useAppSelector } from "../../../redux/hooks";
import {
requestBodyBinaryUpdated,
selectRequestBodyFile,
} from "../requestBodySlice";
export const Binary = () => {
const binary = useAppSelector(selectRequestBodyFile);
const dispatch = useAppDispatch();
return (
<div className="binary-wrapper">
<div className="input-file-wrapper">
<input
type="file"
id="myFile"
name="filename"
className="input-file-upload"
onChange={(e) => {
if (e.target.files.length) {
e.target.files[0].text().then((data) =>
dispatch(
requestBodyBinaryUpdated({
name: e.target.files[0].name,
data,
})
)
);
}
}}
></input>
<label className="label-file-upload" htmlFor="myFile">
Select file
</label>
<div>{binary}</div>
</div>
</div>
);
};
================================================
FILE: webview/features/requestBody/Binary/styles.css
================================================
.binary-wrapper {
border-top: var(--default-border-size) solid var(--border);
display: flex;
margin-top: 15px;
color: var(--default-text-light);
font-size: var(--default-font-size);
}
.input-file-wrapper {
margin-top: 20px;
display: flex;
align-items: center;
}
.input-file-upload {
display: none;
}
.label-file-upload {
padding: 6px;
cursor: pointer;
background-color: var(--input-field);
margin-right: 10px;
}
================================================
FILE: webview/features/requestBody/FormData/index.tsx
================================================
import * as React from "react";
import "./styles.css";
import { KeyValueTable } from "../../../shared/KeyValueTable";
import { useAppDispatch, useAppSelector } from "../../../redux/hooks";
import {
selectRequestBodyFormData,
requestBodyFormDataItemAdded,
requestBodyFormDataItemDeleted,
requestBodyFormDataItemUpdated,
} from "../requestBodySlice";
export const FormData = () => {
const urlEncoded = useAppSelector(selectRequestBodyFormData);
const dispatch = useAppDispatch();
return (
<div className="form-data-wrapper">
<KeyValueTable
data={urlEncoded}
onRowAdd={(value) => dispatch(requestBodyFormDataItemAdded(value))}
onRowDelete={(idx) => dispatch(requestBodyFormDataItemDeleted(idx))}
onRowUpdate={(idx, value) =>
dispatch(requestBodyFormDataItemUpdated({ idx, value }))
}
/>
</div>
);
};
================================================
FILE: webview/features/requestBody/FormData/styles.css
================================================
.form-data-wrapper {
margin-top: 15px;
}
================================================
FILE: webview/features/requestBody/GraphQL/index.tsx
================================================
import * as React from "react";
import "./styles.css";
import { useAppDispatch, useAppSelector } from "../../../redux/hooks";
import {
requestBodyGraphqlQueryUpdated,
requestBodyGraphqlVariablesUpdated,
selectRequestBodyGraphqlQuery,
selectRequestBodyGraphqlVariables,
} from "../requestBodySlice";
const Editor = React.lazy(() => import("../../../shared/Editor"));
export const GraphQL = () => {
const query = useAppSelector(selectRequestBodyGraphqlQuery);
const variables = useAppSelector(selectRequestBodyGraphqlVariables);
const dispatch = useAppDispatch();
return (
<div className="gql-wrapper">
<div className="gql-section">
<div className="gql-section-heading">QUERY</div>
<React.Suspense fallback={<div>loading</div>}>
<Editor
className="gql-editor"
value={query}
language="graphql"
onChange={(data) => dispatch(requestBodyGraphqlQueryUpdated(data))}
/>
</React.Suspense>
</div>
<div className="gql-section">
<div className="gql-section-heading">VARIABLES</div>
<React.Suspense fallback={<div>loading</div>}>
<Editor
className="gql-editor"
value={variables}
language="json"
onChange={(data) =>
dispatch(requestBodyGraphqlVariablesUpdated(data))
}
/>
</React.Suspense>
</div>
</div>
);
};
================================================
FILE: webview/features/requestBody/GraphQL/styles.css
================================================
.gql-wrapper {
display: flex;
height: 100%;
margin-top: 10px;
}
.gql-section {
height: 95%;
padding: 0 10px 0 10px;
display: flex;
flex-direction: column;
flex: 1;
}
.gql-section-heading {
font-size: var(--default-font-size);
padding-bottom: 10px;
font-weight: 700;
}
.gql-editor {
height: 90%;
}
================================================
FILE: webview/features/requestBody/NoBody/index.tsx
================================================
import * as React from "react";
import "./styles.css";
export const None = () => {
return (
<div className="none-wrapper">
<div className="none-prompt">This request does not have a body</div>
</div>
);
};
================================================
FILE: webview/features/requestBody/NoBody/styles.css
================================================
.none-wrapper {
border-top: var(--default-border-size) solid var(--border);
display: flex;
justify-content: center;
margin-top: 15px;
}
.none-prompt {
color: var(--default-text-light);
font-size: var(--default-font-size);
margin-top: 20px;
}
================================================
FILE: webview/features/requestBody/Raw/index.tsx
================================================
import * as React from "react";
import "./styles.css";
import { useAppDispatch, useAppSelector } from "../../../redux/hooks";
import {
requestBodyRawUpdated,
selectRequestBodyRaw,
selectRequestBodyRawFormat,
selectRequestBodyRawLanguage,
} from "../requestBodySlice";
const Editor = React.lazy(() => import("../../../shared/Editor"));
export const Raw = () => {
const raw = useAppSelector(selectRequestBodyRaw);
const language = useAppSelector(selectRequestBodyRawLanguage);
const format = useAppSelector(selectRequestBodyRawFormat);
const dispatch = useAppDispatch();
return (
<div className="raw-wrapper">
<React.Suspense fallback={<div>loading</div>}>
<Editor
className="raw-editor"
value={raw}
language={language}
format={format}
onChange={(data) => dispatch(requestBodyRawUpdated(data))}
/>
</React.Suspense>
</div>
);
};
================================================
FILE: webview/features/requestBody/Raw/styles.css
================================================
.raw-wrapper {
height: 95%;
margin-top: 15px;
}
.raw-editor {
height: 95%;
}
================================================
FILE: webview/features/requestBody/RequestBody/index.tsx
================================================
import * as React from "react";
import { Binary } from "../Binary";
import { FormData } from "../FormData";
import { None } from "../NoBody";
import { Raw } from "../Raw";
import { UrlEncoded } from "../UrlEncoded";
import { GraphQL } from "../GraphQL";
import {
requestBodyModes,
requestBodyRawLanguages,
requestBodyRawLanguageUpdated,
requestBodyModeUpdated,
selectRequestBodyMode,
selectRequestBodyRawLanguage,
requestBodyRawFormatUpdated,
} from "../requestBodySlice";
import "./styles.css";
import { useAppDispatch, useAppSelector } from "../../../redux/hooks";
export const Body = () => {
const bodyMode = useAppSelector(selectRequestBodyMode);
const language = useAppSelector(selectRequestBodyRawLanguage);
const hideBeautifyButton = bodyMode === "raw" && language === "json";
const dispatch = useAppDispatch();
return (
<div className="request-body-wrapper">
<div className="body-options-wrapper">
{requestBodyModes.map(({ name, value }) => (
<div key={value} className="body-options">
<input
name="req-body-radio"
type="radio"
id={value}
value={value}
onChange={(e) =>
e.target.checked && dispatch(requestBodyModeUpdated(value))
}
className="radio-body-option"
checked={bodyMode === value ? true : false}
/>
<label className="label-body-option" htmlFor={value}>
{name}
</label>
</div>
))}
{bodyMode === "raw" ? (
<select
className="select-raw-lang"
value={language}
onChange={(e) =>
dispatch(requestBodyRawLanguageUpdated(e.target.value))
}
>
{requestBodyRawLanguages.map((type) => (
<option key={type.value} value={type.value}>
{type.name}
</option>
))}
</select>
) : null}
<button
id="request-beautify"
name="request-beautify"
className={
hideBeautifyButton ? "button-request" : "button-request hidden"
}
onClick={() => {
dispatch(requestBodyRawFormatUpdated(true));
}}
>
Beautify
</button>
</div>
<div className="request-body-window-wrapper">
{bodyMode === "none" ? (
<None />
) : bodyMode === "formdata" ? (
<FormData />
) : bodyMode === "urlencoded" ? (
<UrlEncoded />
) : bodyMode === "raw" ? (
<Raw />
) : bodyMode === "file" ? (
<Binary />
) : bodyMode === "graphql" ? (
<GraphQL />
) : null}
</div>
</div>
);
};
================================================
FILE: webview/features/requestBody/RequestBody/styles.css
================================================
.request-body-wrapper {
display: flex;
flex-direction: column;
height: 100%;
}
.request-body-window-wrapper {
flex: 1;
}
.body-options-wrapper {
display: flex;
align-items: center;
}
.body-options {
display: flex;
padding: 6px 5px 6px 0px;
margin: 0 10px 0 0;
justify-content: center;
align-items: center;
}
.radio-body-option {
cursor: pointer;
outline: none;
border-radius: 0;
margin: 0px 8px;
}
.radio-body-option:checked {
outline: none;
}
.radio-body-option:focus {
outline: none;
}
.label-body-option {
color: var(--default-text-light);
font-size: var(--default-font-size);
}
.select-raw-lang {
padding: 4px;
margin-left: 5px;
display: inline-block;
font-weight: 600;
outline: none;
border: var(--default-border-size) solid var(--border);
border-radius: 2px;
background-color: var(--background);
color: var(--default-text-light);
cursor: pointer;
font-size: var(--small-font-size);
}
.select-raw-lang:hover {
color: var(--default-text);
}
.select-raw-lang:focus {
outline: none;
}
#request-beautify {
margin-left: 10px;
}
================================================
FILE: webview/features/requestBody/UrlEncoded/index.tsx
================================================
import * as React from "react";
import "./styles.css";
import { KeyValueTable } from "../../../shared/KeyValueTable";
import { useAppDispatch, useAppSelector } from "../../../redux/hooks";
import {
selectRequestBodyUrlEncoded,
requestBodyUrlEncodedItemAdded,
requestBodyUrlEncodedItemDeleted,
requestBodyUrlEncodedItemUpdated,
} from "../requestBodySlice";
export const UrlEncoded = () => {
const urlEncoded = useAppSelector(selectRequestBodyUrlEncoded);
const dispatch = useAppDispatch();
return (
<div className="url-encoded-wrapper">
<KeyValueTable
data={urlEncoded}
onRowAdd={(value) => dispatch(requestBodyUrlEncodedItemAdded(value))}
onRowDelete={(idx) => dispatch(requestBodyUrlEncodedItemDeleted(idx))}
onRowUpdate={(idx, value) =>
dispatch(requestBodyUrlEncodedItemUpdated({ idx, value }))
}
/>
</div>
);
};
================================================
FILE: webview/features/requestBody/UrlEncoded/styles.css
================================================
.url-encoded-wrapper {
margin-top: 15px;
}
================================================
FILE: webview/features/requestBody/requestBodySlice.ts
================================================
/* eslint-disable @typescript-eslint/no-explicit-any */
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { RootState } from "../../redux/store";
export const requestBodyModes = [
{ name: "none", value: "none" },
{ name: "form-data", value: "formdata" },
{ name: "x-www-form-urlencoded", value: "urlencoded" },
{ name: "raw", value: "raw" },
{ name: "binary", value: "file" },
{ name: "GraphQL", value: "graphql" },
];
export const requestBodyRawLanguages = [
{ name: "JSON", value: "json" },
{ name: "HTML", value: "html" },
{ name: "XML", value: "xml" },
{ name: "Text", value: "text" },
];
export interface RequestBodyState {
mode?: string;
disabled: boolean;
raw: string;
file: string;
fileData: string;
formdata: { key: string; value: string; description: string }[];
urlencoded: { key: string; value: string; description: string }[];
options: any;
graphql: { query: string; variables: string };
format: boolean;
}
const initialState: RequestBodyState = {
disabled: true,
format: false,
raw: "",
file: "",
fileData: "",
formdata: [],
urlencoded: [],
options: { raw: { language: "json" } },
graphql: { query: "", variables: "{}" },
};
const requestBodySlice = createSlice({
name: "requestBody",
initialState,
reducers: {
requestBodyFormDataItemAdded(state, action: PayloadAction<any>) {
state.formdata.push(action.payload);
},
requestBodyFormDataItemDeleted(state, action: PayloadAction<number>) {
state.formdata.splice(action.payload, 1);
},
requestBodyFormDataItemUpdated(state, action: PayloadAction<any>) {
state.formdata[action.payload.idx] = action.payload.value;
},
requestBodyUrlEncodedItemAdded(state, action: PayloadAction<any>) {
state.urlencoded.push(action.payload);
},
requestBodyUrlEncodedItemDeleted(state, action: PayloadAction<number>) {
state.urlencoded.splice(action.payload, 1);
},
requestBodyUrlEncodedItemUpdated(state, action: PayloadAction<any>) {
state.urlencoded[action.payload.idx] = action.payload.value;
},
requestBodyRawUpdated(state, action: PayloadAction<string>) {
state.raw = action.payload;
},
requestBodyRawFormatUpdated(state, action: PayloadAction<boolean>) {
state.format = action.payload;
},
requestBodyRawLanguageUpdated(state, action: PayloadAction<string>) {
state.options.raw.language = action.payload;
},
requestBodyBinaryUpdated(state, action: PayloadAction<any>) {
state.file = action.payload.name;
state.fileData = action.payload.data;
},
requestBodyGraphqlQueryUpdated(state, action: PayloadAction<string>) {
state.graphql.query = action.payload;
},
requestBodyGraphqlVariablesUpdated(state, action: PayloadAction<string>) {
state.graphql.variables = action.payload;
},
requestBodyModeUpdated(state, action: PayloadAction<string>) {
if (action.payload === "none") {
state.mode = undefined;
state.disabled = true;
} else {
state.mode = action.payload;
state.disabled = false;
}
},
},
});
export const {
requestBodyBinaryUpdated,
requestBodyFormDataItemAdded,
requestBodyFormDataItemDeleted,
requestBodyFormDataItemUpdated,
requestBodyModeUpdated,
requestBodyRawUpdated,
requestBodyRawFormatUpdated,
requestBodyRawLanguageUpdated,
requestBodyUrlEncodedItemAdded,
requestBodyUrlEncodedItemDeleted,
requestBodyUrlEncodedItemUpdated,
requestBodyGraphqlQueryUpdated,
requestBodyGraphqlVariablesUpdated,
} = requestBodySlice.actions;
export const selectRequestBody = (state: RootState) => state.requestBody;
export const selectRequestBodyMode = (state: RootState) =>
state.requestBody.mode || "none";
export const selectRequestBodyRaw = (state: RootState) => state.requestBody.raw;
export const selectRequestBodyRawLanguage = (state: RootState) =>
state.requestBody.options.raw.language;
export const selectRequestBodyFile = (state: RootState) =>
state.requestBody.file;
export const selectRequestBodyFileData = (state: RootState) =>
state.requestBody.fileData;
export const selectRequestBodyFormData = (state: RootState) =>
state.requestBody.formdata;
export const selectRequestBodyUrlEncoded = (state: RootState) =>
state.requestBody.urlencoded;
export const selectRequestBodyGraphqlQuery = (state: RootState) =>
state.requestBody.graphql.query;
export const selectRequestBodyGraphqlVariables = (state: RootState) =>
state.requestBody.graphql.variables;
export const selectRequestBodyRawFormat = (state: RootState) =>
state.requestBody.format;
export default requestBodySlice.reducer;
================================================
FILE: webview/features/requestHeader/HeadersWindow/index.tsx
================================================
import * as React from "react";
import "./styles.css";
import { KeyValueTable } from "../../../shared/KeyValueTable";
import { useAppDispatch, useAppSelector } from "../../../redux/hooks";
import {
requestHeaderAdded,
requestHeaderUpdated,
requestHeaderDeleted,
selectRequestHeaders,
} from "../requestHeaderSlice";
export const Headers = () => {
const header = useAppSelector(selectRequestHeaders);
const dispatch = useAppDispatch();
return (
<div className="headers-wrapper">
<KeyValueTable
data={header}
onRowAdd={(value) => dispatch(requestHeaderAdded(value))}
onRowDelete={(idx) => dispatch(requestHeaderDeleted(idx))}
onRowUpdate={(idx, value) =>
dispatch(requestHeaderUpdated({ idx, value }))
}
/>
</div>
);
};
================================================
FILE: webview/features/requestHeader/HeadersWindow/styles.css
================================================
.headers-wrapper {
margin-top: 15px;
}
================================================
FILE: webview/features/requestHeader/requestHeaderSlice.ts
================================================
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { RootState } from "../../redux/store";
interface Header {
key: string;
value: string;
description: string;
disabled: boolean;
}
const initialState: Header[] = [
{
key: "Cache-Control",
value: "no-cache",
description: "",
disabled: false,
},
{
key: "Accept",
value: "*/*",
description: "",
disabled: false,
},
{
key: "Accept-Encoding",
value: "gzip, deflate",
description: "",
disabled: false,
},
{
key: "Connection",
value: "keep-alive",
description: "",
disabled: false,
},
];
const requestHeaderSlice = createSlice({
name: "requestHeader",
initialState,
reducers: {
requestHeaderUpdated(state, action: PayloadAction<any>) {
state[action.payload.idx] = action.payload.value;
},
requestHeaderAdded(state, action: PayloadAction<Header>) {
state.push(action.payload);
},
requestHeaderDeleted(state, action: PayloadAction<number>) {
state.splice(action.payload, 1);
},
},
});
export const {
requestHeaderAdded,
requestHeaderUpdated,
requestHeaderDeleted,
} = requestHeaderSlice.actions;
export const selectRequestHeaders = (state: RootState) => state.requestHeader;
export default requestHeaderSlice.reducer;
================================================
FILE: webview/features/requestMethod/RequestMethodSelector/index.tsx
================================================
import * as React from "react";
import { useAppDispatch, useAppSelector } from "../../../redux/hooks";
import {
requestMethodUpdated,
selectRequestMethod,
requestMethods,
} from "../requestMethodSlice";
import "./styles.css";
export const RequestMethodSelector = () => {
const requestMethod = useAppSelector(selectRequestMethod);
const dispatch = useAppDispatch();
return (
<select
className="request-method-selector"
onChange={(e) => dispatch(requestMethodUpdated(e.target.value))}
value={requestMethod}
>
{requestMethods.map(({ value, name }) => (
<option value={value} key={value}>
{name}
</option>
))}
</select>
);
};
================================================
FILE: webview/features/requestMethod/RequestMethodSelector/styles.css
================================================
.request-method-selector {
padding: 12px 20px;
display: inline-block;
font-weight: 600;
outline: none;
border: 0;
border-radius: 2px 0 0 2px;
background-color: var(--input-field);
color: var(--default-text);
cursor: pointer;
font-size: var(--default-font-size);
}
.request-method-selector:hover {
background-color: var(--input-field-hover);
}
.request-method-selector:focus {
outline: none;
}
================================================
FILE: webview/features/requestMethod/requestMethodSlice.ts
================================================
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { RootState } from "../../redux/store";
export const requestMethods = [
{ name: "GET", value: "get" },
{ name: "POST", value: "post" },
{ name: "PUT", value: "put" },
{ name: "PATCH", value: "patch" },
{ name: "DELETE", value: "delete" },
{ name: "OPTIONS", value: "options" },
{ name: "HEAD", value: "head" },
];
const initialState = "get";
const requestMethodSlice = createSlice({
name: "requestMethod",
initialState,
reducers: {
requestMethodUpdated(state, action: PayloadAction<string>) {
return action.payload;
},
},
});
export const { requestMethodUpdated } = requestMethodSlice.actions;
export const selectRequestMethod = (state: RootState) => state.requestMethod;
export default requestMethodSlice.reducer;
================================================
FILE: webview/features/requestOptions/RequestOptions/index.tsx
================================================
import * as React from "react";
import { useDispatch } from "react-redux";
import { useAppSelector } from "../../../redux/hooks";
import {
requestOptionsUpdated,
selectRequestOptions,
requestOptionsList,
} from "../requestOptionsSlice";
import "./styles.css";
export const RequestOptions = () => {
const requestOptions = useAppSelector(selectRequestOptions);
const dispatch = useDispatch();
return (
<div className="req-options-wrapper">
<div className="options">
{requestOptionsList.map(({ name, value, type, ...optionDetails }) => (
<React.Fragment key={`req-option-${value}`}>
<div className="req-option-label">{`${name}: `}</div>
{
type === "select" ? (
<select
onChange={(e) =>
dispatch(
requestOptionsUpdated({
...requestOptions,
[value]: e.target.value,
})
)
}
defaultValue={optionDetails.default}
className="req-option-switch"
>
{optionDetails.options.map(({ key, value }) => (
<option key={key} value={value}>
{value}
</option>
))}
</select>
) : null
// Note: Augment this switch later with different renderers for
// different types of options
}
</React.Fragment>
))}
</div>
</div>
);
};
================================================
FILE: webview/features/requestOptions/RequestOptions/styles.css
================================================
.req-options-wrapper {
margin-top: 15px;
}
.options {
display: flex;
align-items: center;
}
.req-option-label {
font-size: var(--default-font-size);
color: var(--default-text);
padding-right: 12px;
}
.req-option-switch {
padding: 4px;
display: inline-block;
font-weight: 600;
outline: none;
border: var(--default-border-size) solid var(--border);
border-radius: 2px;
background-color: var(--background);
color: var(--default-text-light);
cursor: pointer;
font-size: var(--default-font-size);
}
================================================
FILE: webview/features/requestOptions/requestOptionsSlice.ts
================================================
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { RootState } from "../../redux/store";
export const requestOptionsList = [
{
name: "Strict SSL",
value: "strictSSL",
type: "select",
options: [
{ key: "yes", value: "Yes" },
{ key: "no", value: "No" },
],
default: "Yes",
},
];
export interface RequestOptions {
strictSSL: string;
}
const initialState = {
strictSSL: "yes",
};
const requestOptionsSlice = createSlice({
name: "requestOptions",
initialState,
reducers: {
requestOptionsUpdated(_, action: PayloadAction<RequestOptions>) {
return action.payload;
},
},
});
export const { requestOptionsUpdated } = requestOptionsSlice.actions;
export const selectRequestOptions = (state: RootState) => state.requestOptions;
export default requestOptionsSlice.reducer;
================================================
FILE: webview/features/requestUrl/RequestQueryParams/index.tsx
================================================
import * as React from "react";
import "./styles.css";
import { KeyValueTable } from "../../../shared/KeyValueTable";
import { useAppDispatch, useAppSelector } from "../../../redux/hooks";
import {
requestQueryParamAdded,
requestQueryParamDeleted,
requestQueryParamUpdated,
selectRequestQueryParams,
} from "../requestUrlSlice";
export const RequestQueryParams = () => {
const queryParams = useAppSelector(selectRequestQueryParams);
const dispatch = useAppDispatch();
return (
<div className="params-wrapper">
<KeyValueTable
data={queryParams}
onRowAdd={(value) => dispatch(requestQueryParamAdded(value))}
onRowDelete={(idx) => dispatch(requestQueryParamDeleted(idx))}
onRowUpdate={(idx, value) =>
dispatch(requestQueryParamUpdated({ idx, value }))
}
/>
</div>
);
};
================================================
FILE: webview/features/requestUrl/RequestQueryParams/styles.css
================================================
.params-wrapper {
margin-top: 15px;
}
================================================
FILE: webview/features/requestUrl/RequestUrl/index.tsx
================================================
import * as React from "react";
import { useAppDispatch, useAppSelector } from "../../../redux/hooks";
import { requestUrlUpdated, selectRequestUrl } from "../requestUrlSlice";
import "./styles.css";
export const RequestUrl = () => {
const requestUrl = useAppSelector(selectRequestUrl);
const dispatch = useAppDispatch();
return (
<input
placeholder="Enter request URL"
className="input-request-url"
value={requestUrl}
onChange={(e) => dispatch(requestUrlUpdated(e.target.value))}
/>
);
};
================================================
FILE: webview/features/requestUrl/RequestUrl/styles.css
================================================
.input-request-url {
flex: 2;
padding: 13px 20px;
color: var(--default-text);
display: inline-block;
outline: none;
border: 0;
border-radius: 0 2px 2px 0;
background-color: var(--input-field);
font-size: var(--default-font-size);
}
.input-request-url:focus {
outline: none;
}
.input-request-url:hover {
background-color: var(--input-field-hover);
}
================================================
FILE: webview/features/requestUrl/requestUrlSlice.ts
================================================
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { RootState } from "../../redux/store";
import { Url } from "postman-collection";
interface QueryParam {
key: string;
value: string;
description: string;
disabled: boolean;
}
interface Variable {
key: string;
value: string;
description: string;
}
export interface RequestUrlState {
auth?: string;
hash?: string;
host?: string[];
path?: string[];
port?: string;
protocol?: string;
query: QueryParam[];
variables: Variable[];
}
const initialState: RequestUrlState = {
query: [],
variables: [],
};
const requestUrlSlice = createSlice({
name: "requestUrl",
initialState,
reducers: {
requestUrlUpdated(state, action: PayloadAction<string>) {
const { query, ...other } = Url.parse(action.payload);
return {
...other,
query: [
...state.query.filter(({ disabled }) => disabled),
...(query || []),
],
};
},
requestQueryParamAdded(state, action: PayloadAction<QueryParam>) {
state.query.push(action.payload);
},
requestQueryParamUpdated(state, action: PayloadAction<any>) {
state.query[action.payload.idx] = action.payload.value;
},
requestQueryParamDeleted(state, action: PayloadAction<number>) {
state.query.splice(action.payload, 1);
},
// requestUrlVariableUpdated(state, action: PayloadAction<Variable>) {},
},
});
export const {
requestUrlUpdated,
requestQueryParamAdded,
requestQueryParamUpdated,
requestQueryParamDeleted,
// requestUrlVariableUpdated,
} = requestUrlSlice.actions;
export const selectRequestUrl = (state: RootState) =>
new Url(state.requestUrl).toString();
export const selectRequestQueryParams = (state: RootState) =>
state.requestUrl.query;
export const selectRequestVariables = (state: RootState) =>
state.requestUrl.variables;
export default requestUrlSlice.reducer;
================================================
FILE: webview/features/response/ResponseBody/index.tsx
================================================
import * as React from "react";
import "./styles.css";
import { useAppSelector } from "../../../redux/hooks";
import { selectResponse } from "../responseSlice";
import * as propTypes from "prop-types";
const Editor = React.lazy(() => import("../../../shared/Editor"));
export const ResponseBody = (props) => {
const { language } = props;
const response = useAppSelector(selectResponse);
return (
<div className="response-window">
<React.Suspense fallback={<div>loading</div>}>
<Editor
className="response-editor"
value={response.data || ""}
language={language}
readOnly
copyButton
format
/>
</React.Suspense>
</div>
);
};
ResponseBody.propTypes = {
language: propTypes.string.isRequired,
};
================================================
FILE: webview/features/response/ResponseBody/styles.css
================================================
.response-window {
height: 100%;
}
.response-editor {
height: 95%;
}
================================================
FILE: webview/features/response/ResponseHeaders/index.tsx
================================================
import * as React from "react";
import { useAppSelector } from "../../../redux/hooks";
import { KeyValueTable } from "../../../shared/KeyValueTable";
import { selectResponseHeaders } from "../responseSlice";
import "./styles.css";
export const ResponseHeaders = () => {
const headers = useAppSelector(selectResponseHeaders);
return (
<div className="response-headers">
<KeyValueTable data={headers} fixed />
</div>
);
};
================================================
FILE: webview/features/response/ResponseHeaders/styles.css
================================================
.response-headers {
display: flex;
height: 80%;
}
================================================
FILE: webview/features/response/ResponseTab/index.tsx
================================================
import * as React from "react";
import "./styles.css";
import * as propTypes from "prop-types";
import { responseOptions } from "../../../constants/response-options";
import { supportedLangs } from "../../../constants/supported-langs";
import { useAppSelector } from "../../../redux/hooks";
import { selectResponse } from "../responseSlice";
const ResponseInfo = ({ responseTitle, info }) => {
return (
<>
<div>{responseTitle}</div>
<div className="text-response-info">{info}</div>
</>
);
};
export const ResponseTab = (props) => {
const { selected, setSelected, language, setLanguage } = props;
const response = useAppSelector(selectResponse);
return (
<div className="response-options-tab-wrapper">
<div className="response-options">
{responseOptions.map((option) => (
<button
key={option.value}
onClick={() => setSelected(option.value)}
className={
selected === option.value
? "response-option response-option-selected"
: "response-option"
}
>
{option.name}
</button>
))}
{selected === "body" ? (
<select
onChange={(e) => setLanguage(e.target.value)}
className="select-res-lang"
value={language}
>
{supportedLangs.map((type) => (
<option key={type.value} value={type.value}>
{type.name}
</option>
))}
</select>
) : null}
</div>
<div className="response-status">
<ResponseInfo
responseTitle="Status:"
info={`${response.status} ${response.statusText}`}
/>
<ResponseInfo
responseTitle="Duration:"
info={`${response.duration} ms`}
/>
</div>
</div>
);
};
ResponseInfo.propTypes = {
responseTitle: propTypes.string.isRequired,
info: propTypes.string.isRequired,
};
ResponseTab.propTypes = {
selected: propTypes.string.isRequired,
setSelected: propTypes.func.isRequired,
language: propTypes.string.isRequired,
setLanguage: propTypes.func.isRequired,
};
================================================
FILE: webview/features/response/ResponseTab/styles.css
================================================
.response-options-tab-wrapper {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px 20px 5px 20px;
}
.response-options {
display: flex;
}
.response-option {
padding: 5px 5px 5px 0;
margin: 0 10px 0 0;
display: flex;
cursor: pointer;
background-color: transparent;
color: var(--default-text-light);
outline: none;
border: none;
border-radius: 0;
font-weight: 500;
font-size: var(--default-font-size);
}
.response-option:hover {
color: var(--default-text);
}
.response-option-selected {
color: var(--default-text);
}
.response-options-header-length {
margin-left: 4px;
color: var(--tab-info);
}
.response-status {
font-size: var(--default-font-size);
display: flex;
align-items: center;
}
.text-response-info {
color: var(--tab-info);
margin-left: 5px;
margin-right: 5px;
}
.select-res-lang {
margin-left: 10px;
padding: 5px;
display: inline-block;
font-weight: 600;
outline: none;
border: var(--default-border-size) solid var(--border);
border-radius: 2px;
background-color: var(--background);
color: var(--default-text-light);
cursor: pointer;
font-size: var(--small-font-size);
}
.select-res-lang:hover {
color: var(--default-text);
}
.select-res-lang:focus {
outline: none;
}
================================================
FILE: webview/features/response/ResponseWindow/index.tsx
================================================
import * as React from "react";
import * as propTypes from "prop-types";
import "./styles.css";
import { ResponseBody } from "../ResponseBody";
import { ResponseHeaders } from "../ResponseHeaders";
export const ResponseWindow = (props) => {
const { selected, language } = props;
return (
<div className="response-options-window-wrapper">
{selected === "body" ? (
<ResponseBody language={language} />
) : selected === "headers" ? (
<ResponseHeaders />
) : null}
</div>
);
};
ResponseWindow.propTypes = {
selected: propTypes.string.isRequired,
language: propTypes.string.isRequired,
};
================================================
FILE: webview/features/response/ResponseWindow/styles.css
================================================
.response-options-window-wrapper {
flex: 1;
padding: 5px 20px 10px 20px;
}
================================================
FILE: webview/features/response/responseSlice.ts
================================================
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { RootState } from "../../redux/store";
export interface ResponseState {
status?: number;
statusText?: string;
data?: string;
initial: boolean;
error?: Error;
loading?: boolean;
headers?: { key: string; value: string }[];
duration?: number;
}
const initialState: ResponseState = { initial: true };
const responseSlice = createSlice({
name: "response",
initialState,
reducers: {
responseUpdated(state, action: PayloadAction<any>) {
return {
...action.payload,
headers:
action.payload.headers &&
Object.entries(action.payload.headers).map(([key, value]) => ({
key,
value,
})),
initial: false,
loading: false,
};
},
responseLoadingStarted(state) {
state.loading = true;
},
},
});
export const { responseUpdated, responseLoadingStarted } =
responseSlice.actions;
export const selectResponse = (state: RootState) => state.response;
export const selectResponseHeaders = (state: RootState) =>
state.response.headers;
export default responseSlice.reducer;
================================================
FILE: webview/index.css
================================================
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
--primary: var(--vscode-button-hoverBackground);
--primary-dark: var(--vscode-button-background);
--background: var(--vscode-editor-background);
--input-field: var(--vscode-input-background);
--input-field-focus: var(--vscode-input-background);
--input-field-hover: var(--vscode-input-background);
--input-field-unchecked: #808080;
--default-text: var(--vscode-foreground);
--default-text-light: var(--vscode-descriptionForeground);
--border: var(--vscode-tree-tableColumnsBorder);
--send-button: var(--vscode-button-background);
--send-button-hover: var(--vscode-button-hoverBackground);
--tab-info: #259c47;
--logo-color: var(--vscode-tree-tableColumnsBorder);
--error-message: var(--vscode-errorForeground);
--default-font-size: var(--vscode-editor-font-size);
--small-font-size: width: calc(var(--vscode-editor-font-size) * 0.727);;
--default-border-size: 0.1px;
}
html,
body,
#root,
.App {
height: 100%;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
monospace;
}
================================================
FILE: webview/index.tsx
================================================
import * as React from "react";
import * as ReactDOM from "react-dom";
import { Provider } from "react-redux";
import { store } from "./redux/store";
import "./index.css";
import App from "./App";
ReactDOM.hydrate(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
================================================
FILE: webview/pages/Postcode/index.tsx
================================================
/* eslint-disable @typescript-eslint/no-explicit-any */
import * as React from "react";
import "./styles.css";
import { RequestBar } from "../../components/RequestBar";
import { RequestOptionsTab } from "../../components/RequestOptionsBar";
import { RequestOptionsWindow } from "../../components/RequestOptionsWindow";
import { Response } from "../../components/Response";
import { requestOptions } from "../../constants/request-options";
export const Postcode = () => {
const [selectedOption, setSelectedOption] = React.useState(
requestOptions[0].value
);
return (
<div className="request-wrapper">
<RequestBar />
<div className="request-options-wrapper">
<RequestOptionsTab
selected={selectedOption}
setSelected={setSelectedOption}
/>
<RequestOptionsWindow selected={selectedOption} />
</div>
<div className="response-wrapper">
<Response />
</div>
</div>
);
};
================================================
FILE: webview/pages/Postcode/styles.css
================================================
.request-wrapper {
display: flex;
flex-direction: column;
height: inherit;
}
.request-options-wrapper {
display: flex;
flex-direction: column;
min-height: 50%;
}
.response-wrapper {
display: flex;
flex-direction: column;
height: 50%;
}
================================================
FILE: webview/prerender.tsx
================================================
import { Provider } from "react-redux";
import * as React from "react";
import { renderToString } from "react-dom/server";
import App from "./App";
import { store } from "./redux/store";
export default () => {
const html = renderToString(
<Provider store={store}>
<App />
</Provider>
);
const preloadedState = store.getState();
return `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link href="styleUri" rel="stylesheet" type="text/css"/>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root">${html}</div>
<script>
window.__PRELOADED_STATE__ = ${JSON.stringify(preloadedState).replace(
/</g,
"\\u003c"
)}
</script>
<script src="scriptUri"></script>
</body>
</html>
`;
};
================================================
FILE: webview/react-app-env.d.ts
================================================
/// <reference types="node" />
/// <reference types="react" />
/// <reference types="react-dom" />
declare namespace NodeJS {
interface ProcessEnv {
readonly NODE_ENV: "development" | "production" | "test";
readonly PUBLIC_URL: string;
}
}
declare module "*.avif" {
const src: string;
export default src;
}
declare module "*.bmp" {
const src: string;
export default src;
}
declare module "*.gif" {
const src: string;
export default src;
}
declare module "*.jpg" {
const src: string;
export default src;
}
declare module "*.jpeg" {
const src: string;
export default src;
}
declare module "*.png" {
const src: string;
export default src;
}
declare module "*.webp" {
const src: string;
export default src;
}
declare module "*.svg" {
import * as React from "react";
export const ReactComponent: React.FunctionComponent<
React.SVGProps<SVGSVGElement> & { title?: string }
>;
const src: string;
export default src;
}
declare module "*.module.css" {
const classes: { readonly [key: string]: string };
export default classes;
}
declare module "*.module.scss" {
const classes: { readonly [key: string]: string };
export default classes;
}
declare module "*.module.sass" {
const classes: { readonly [key: string]: string };
export default classes;
}
================================================
FILE: webview/redux/hooks.ts
================================================
import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux";
import type { RootState, AppDispatch } from "./store";
// Use throughout your app instead of plain `useDispatch` and `useSelector`
export const useAppDispatch = () => useDispatch<AppDispatch>();
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
================================================
FILE: webview/redux/store.ts
================================================
import { configureStore, ThunkAction, Action } from "@reduxjs/toolkit";
import requestAuthReducer from "../features/requestAuth/requestAuthSlice";
import requestBodyReducer from "../features/requestBody/requestBodySlice";
import requestHeaderReducer from "../features/requestHeader/requestHeaderSlice";
import requestMethodReducer from "../features/requestMethod/requestMethodSlice";
import requestUrlReducer from "../features/requestUrl/requestUrlSlice";
import responseReducer from "../features/response/responseSlice";
import codeGenOptionsReducer from "../features/codeGen/codeGenSlice";
import requestOptionsReducer from "../features/requestOptions/requestOptionsSlice";
let preloadedState;
if (typeof window !== "undefined") {
preloadedState = (window as any).__PRELOADED_STATE__;
delete (window as any).__PRELOADED_STATE__;
}
export const store = configureStore({
reducer: {
requestAuth: requestAuthReducer,
requestBody: requestBodyReducer,
requestHeader: requestHeaderReducer,
requestMethod: requestMethodReducer,
requestUrl: requestUrlReducer,
response: responseReducer,
codeGenOptions: codeGenOptionsReducer,
requestOptions: requestOptionsReducer,
},
preloadedState,
});
export type AppDispatch = typeof store.dispatch;
export type RootState = ReturnType<typeof store.getState>;
export type AppThunk<ReturnType = void> = ThunkAction<
ReturnType,
RootState,
unknown,
Action<string>
>;
================================================
FILE: webview/shared/Editor/index.tsx
================================================
import * as React from "react";
import * as monaco from "monaco-editor";
import * as propTypes from "prop-types";
import "./styles.css";
import { useAppDispatch } from "../../redux/hooks";
import { requestBodyRawFormatUpdated } from "../../features/requestBody/requestBodySlice";
const Editor = (props) => {
const { value, language, onChange, readOnly, className, copyButton, format } =
props;
const divEl = React.useRef<HTMLDivElement>(null);
const [editor, setEditor] = React.useState(undefined);
const [copy, setCopy] = React.useState("Copy");
const dispatch = useAppDispatch();
React.useEffect(() => {
if (divEl.current) {
const tmpEditor = monaco.editor.create(divEl.current, {
minimap: { enabled: false },
scrollBeyondLastLine: false,
theme: "vs-dark",
value,
language,
readOnly,
});
window.addEventListener("resize", () => {
tmpEditor.layout();
});
if (onChange) {
tmpEditor.onDidChangeModelContent(() => {
onChange(tmpEditor.getValue());
});
}
setEditor(tmpEditor);
return () => {
tmpEditor.dispose();
};
}
}, []);
React.useEffect(() => {
if (editor) {
if (editor.getValue() !== value) {
editor.setValue(value);
}
const model = editor.getModel();
monaco.editor.setModelLanguage(model, language);
if (format) {
editor.updateOptions({ readOnly: false });
setTimeout(() => {
editor
.getAction("editor.action.formatDocument")
.run()
.then(() => {
editor.updateOptions({ readOnly });
dispatch(requestBodyRawFormatUpdated(false));
});
}, 300);
}
}
}, [value, language, editor, format]);
return (
<div className={`${className} postcode-editor`} ref={divEl}>
{copyButton && (
<button
onClick={() => {
navigator.clipboard.writeText(value).then(() => {
setCopy("Copied");
setTimeout(() => setCopy("Copy"), 1000);
});
}}
className="copy-button"
>
{copy}
</button>
)}
</div>
);
};
Editor.propTypes = {
value: propTypes.string.isRequired,
language: propTypes.string.isRequired,
onChange: propTypes.func,
className: propTypes.string,
readOnly: propTypes.bool,
copyButton: propTypes.bool,
format: propTypes.bool,
};
export default Editor;
================================================
FILE: webview/shared/Editor/styles.css
================================================
.monaco-editor {
border: var(--default-border-size) solid var(--border);
}
.postcode-editor {
position: relative;
}
.copy-button {
font-size: var(--default-font-size);
background-color: rgb(51, 51, 51);
border: none;
color: #fff;
border-radius: 0.4rem;
cursor: pointer;
outline: none;
padding: 0.4rem 0.5rem;
position: absolute;
transition: opacity 0.2s ease-in-out, visibility 0.2s ease-in-out;
z-index: 10;
right: 0.5rem;
top: 0.5rem;
opacity: 0;
visibility: hidden;
}
.postcode-editor:hover .copy-button {
opacity: 1;
visibility: visible;
}
================================================
FILE: webview/shared/KeyValueTable/index.tsx
================================================
import * as React from "react";
import * as propTypes from "prop-types";
import { FaTrashAlt } from "react-icons/fa";
import "./styles.css";
export const KeyValueRow = (props) => {
const {
itemKey,
itemValue,
itemDescription,
itemDisabled,
actions,
onDelete,
onChange,
fixed,
} = props;
return (
<tr className={itemDisabled ? "kv-disabled" : null}>
{!fixed && (
<td className="kv-action-cell">
{actions && (
<input
type="checkbox"
checked={!itemDisabled}
onChange={(e) =>
onChange({
key: itemKey,
value: itemValue,
description: itemDescription,
disabled: !e.target.checked,
})
}
/>
)}
</td>
)}
<td>
<input
className="kv-input"
placeholder="Key"
value={itemKey}
disabled={fixed}
onChange={(e) =>
onChange({
key: e.target.value,
value: itemValue,
description: itemDescription,
disabled: itemDisabled,
})
}
/>
</td>
<td>
<input
className="kv-input"
placeholder="Value"
value={itemValue}
disabled={fixed}
onChange={(e) =>
onChange({
key: itemKey,
value: e.target.value,
description: itemDescription,
disabled: itemDisabled,
})
}
/>
</td>
{!fixed && (
<td>
<input
className="kv-input"
placeholder="Description"
value={itemDescription}
disabled={fixed}
onChange={(e) =>
onChange({
key: itemKey,
value: itemValue,
description: e.target.value,
disabled: itemDisabled,
})
}
/>
</td>
)}
{!fixed && (
<td className="kv-action-cell">
{actions && (
<FaTrashAlt className="kv-delete-button" onClick={onDelete} />
)}
</td>
)}
</tr>
);
};
export const KeyValueTable = (props) => {
const { data, fixed, onRowUpdate, onRowAdd, onRowDelete } = props;
return (
<table className="kv-table">
<thead>
<tr>
{!fixed && <th></th>}
<th className="kv-heading-cell">KEY</th>
<th className="kv-heading-cell">VALUE</th>
{!fixed && <th className="kv-heading-cell">DESCRIPTION</th>}
{!fixed && <th></th>}
</tr>
</thead>
<tbody>
{(fixed ? data : [...data, {}]).map(
({ key, value, description, disabled }, idx) => (
<KeyValueRow
fixed={fixed}
itemKey={key || ""}
itemValue={value || ""}
itemDescription={description || ""}
itemDisabled={disabled || false}
onDelete={() => onRowDelete(idx)}
onChange={(item) =>
idx === data.length ? onRowAdd(item) : onRowUpdate(idx, item)
}
key={idx}
actions={idx !== data.length}
/>
)
)}
</tbody>
</table>
);
};
KeyValueTable.propTypes = {
data: propTypes.array.isRequired,
fixed: propTypes.bool,
onRowDelete: propTypes.func,
onRowAdd: propTypes.func,
onRowUpdate: propTypes.func,
};
KeyValueRow.propTypes = {
fixed: propTypes.bool,
itemKey: propTypes.string.isRequired,
itemValue: propTypes.string.isRequired,
itemDescription: propTypes.string.isRequired,
itemDisabled: propTypes.bool.isRequired,
actions: propTypes.bool.isRequired,
onChange: propTypes.func.isRequired,
onDelete: propTypes.func.isRequired,
};
================================================
FILE: webview/shared/KeyValueTable/styles.css
================================================
.kv-table {
border-collapse: collapse;
width: 100%;
}
.kv-table,
td,
th {
border: var(--default-border-size) solid var(--border);
}
th,
.kv-input {
color: var(--default-text);
padding: 10px 12px;
}
th {
text-align: left;
font-weight: 700;
font-size: var(--small-font-size);
}
.kv-action-cell {
text-align: center;
width: 30px;
}
.kv-input {
box-sizing: border-box;
width: 100%;
border: 0;
background-color: transparent;
font-size: var(--default-font-size);
}
.kv-input:focus {
outline: none;
}
.kv-disabled .kv-input {
color: var(--input-field-unchecked);
}
.kv-delete-button {
cursor: pointer;
}
================================================
FILE: webview/vscode.ts
================================================
let vscode;
if (typeof acquireVsCodeApi !== "undefined") {
vscode = acquireVsCodeApi();
}
export default vscode;
gitextract_11wa3ryc/
├── .eslintrc.json
├── .gitignore
├── .husky/
│ └── pre-push
├── .prettierignore
├── .vscode/
│ ├── launch.json
│ ├── settings.json
│ └── tasks.json
├── .vscodeignore
├── .yarnrc
├── CHANGELOG.md
├── LICENSE
├── README.md
├── package.json
├── src/
│ ├── extension.ts
│ └── test/
│ ├── runTest.ts
│ └── suite/
│ ├── extension.test.ts
│ └── index.ts
├── tsconfig.json
├── webpack.config.js
└── webview/
├── App.css
├── App.tsx
├── acquireVsCodeApi.d.ts
├── components/
│ ├── RequestBar/
│ │ ├── index.tsx
│ │ └── styles.css
│ ├── RequestOptionsBar/
│ │ ├── index.tsx
│ │ └── styles.css
│ ├── RequestOptionsWindow/
│ │ ├── index.tsx
│ │ └── styles.css
│ └── Response/
│ ├── index.tsx
│ └── styles.css
├── constants/
│ ├── request-options.ts
│ ├── response-options.ts
│ ├── response-views.ts
│ └── supported-langs.ts
├── features/
│ ├── codeGen/
│ │ ├── CodeSnippet/
│ │ │ ├── index.tsx
│ │ │ └── styles.css
│ │ └── codeGenSlice.ts
│ ├── requestAuth/
│ │ ├── BasicAuth/
│ │ │ ├── index.tsx
│ │ │ └── styles.css
│ │ ├── BearerToken/
│ │ │ ├── index.tsx
│ │ │ └── styles.css
│ │ ├── NoAuth/
│ │ │ ├── index.tsx
│ │ │ └── styles.css
│ │ ├── RequestAuth/
│ │ │ ├── index.tsx
│ │ │ └── styles.css
│ │ └── requestAuthSlice.ts
│ ├── requestBody/
│ │ ├── Binary/
│ │ │ ├── index.tsx
│ │ │ └── styles.css
│ │ ├── FormData/
│ │ │ ├── index.tsx
│ │ │ └── styles.css
│ │ ├── GraphQL/
│ │ │ ├── index.tsx
│ │ │ └── styles.css
│ │ ├── NoBody/
│ │ │ ├── index.tsx
│ │ │ └── styles.css
│ │ ├── Raw/
│ │ │ ├── index.tsx
│ │ │ └── styles.css
│ │ ├── RequestBody/
│ │ │ ├── index.tsx
│ │ │ └── styles.css
│ │ ├── UrlEncoded/
│ │ │ ├── index.tsx
│ │ │ └── styles.css
│ │ └── requestBodySlice.ts
│ ├── requestHeader/
│ │ ├── HeadersWindow/
│ │ │ ├── index.tsx
│ │ │ └── styles.css
│ │ └── requestHeaderSlice.ts
│ ├── requestMethod/
│ │ ├── RequestMethodSelector/
│ │ │ ├── index.tsx
│ │ │ └── styles.css
│ │ └── requestMethodSlice.ts
│ ├── requestOptions/
│ │ ├── RequestOptions/
│ │ │ ├── index.tsx
│ │ │ └── styles.css
│ │ └── requestOptionsSlice.ts
│ ├── requestUrl/
│ │ ├── RequestQueryParams/
│ │ │ ├── index.tsx
│ │ │ └── styles.css
│ │ ├── RequestUrl/
│ │ │ ├── index.tsx
│ │ │ └── styles.css
│ │ └── requestUrlSlice.ts
│ └── response/
│ ├── ResponseBody/
│ │ ├── index.tsx
│ │ └── styles.css
│ ├── ResponseHeaders/
│ │ ├── index.tsx
│ │ └── styles.css
│ ├── ResponseTab/
│ │ ├── index.tsx
│ │ └── styles.css
│ ├── ResponseWindow/
│ │ ├── index.tsx
│ │ └── styles.css
│ └── responseSlice.ts
├── index.css
├── index.tsx
├── pages/
│ └── Postcode/
│ ├── index.tsx
│ └── styles.css
├── prerender.tsx
├── react-app-env.d.ts
├── redux/
│ ├── hooks.ts
│ └── store.ts
├── shared/
│ ├── Editor/
│ │ ├── index.tsx
│ │ └── styles.css
│ └── KeyValueTable/
│ ├── index.tsx
│ └── styles.css
└── vscode.ts
SYMBOL INDEX (47 symbols across 13 files)
FILE: src/extension.ts
function activate (line 11) | function activate(context: vscode.ExtensionContext) {
function deactivate (line 179) | function deactivate() {}
FILE: src/test/runTest.ts
function main (line 5) | async function main() {
FILE: src/test/suite/index.ts
function run (line 5) | function run(): Promise<void> {
FILE: webview/features/codeGen/codeGenSlice.ts
type codeGenOptionState (line 65) | interface codeGenOptionState {
method codeGenLanguageUpdated (line 76) | codeGenLanguageUpdated(state, action: PayloadAction<string>) {
method codeGenVariantUpdated (line 82) | codeGenVariantUpdated(state, action: PayloadAction<string>) {
FILE: webview/features/requestAuth/requestAuthSlice.ts
type BearerAuthOptions (line 10) | interface BearerAuthOptions {
type BasicAuthOptions (line 14) | interface BasicAuthOptions {
type RequestAuthState (line 19) | interface RequestAuthState {
method requestAuthTypeUpdated (line 35) | requestAuthTypeUpdated(state, action: PayloadAction<string>) {
method requestAuthOptionsUpdated (line 38) | requestAuthOptionsUpdated(
FILE: webview/features/requestBody/requestBodySlice.ts
type RequestBodyState (line 21) | interface RequestBodyState {
method requestBodyFormDataItemAdded (line 50) | requestBodyFormDataItemAdded(state, action: PayloadAction<any>) {
method requestBodyFormDataItemDeleted (line 53) | requestBodyFormDataItemDeleted(state, action: PayloadAction<number>) {
method requestBodyFormDataItemUpdated (line 56) | requestBodyFormDataItemUpdated(state, action: PayloadAction<any>) {
method requestBodyUrlEncodedItemAdded (line 59) | requestBodyUrlEncodedItemAdded(state, action: PayloadAction<any>) {
method requestBodyUrlEncodedItemDeleted (line 62) | requestBodyUrlEncodedItemDeleted(state, action: PayloadAction<number>) {
method requestBodyUrlEncodedItemUpdated (line 65) | requestBodyUrlEncodedItemUpdated(state, action: PayloadAction<any>) {
method requestBodyRawUpdated (line 68) | requestBodyRawUpdated(state, action: PayloadAction<string>) {
method requestBodyRawFormatUpdated (line 71) | requestBodyRawFormatUpdated(state, action: PayloadAction<boolean>) {
method requestBodyRawLanguageUpdated (line 74) | requestBodyRawLanguageUpdated(state, action: PayloadAction<string>) {
method requestBodyBinaryUpdated (line 77) | requestBodyBinaryUpdated(state, action: PayloadAction<any>) {
method requestBodyGraphqlQueryUpdated (line 81) | requestBodyGraphqlQueryUpdated(state, action: PayloadAction<string>) {
method requestBodyGraphqlVariablesUpdated (line 84) | requestBodyGraphqlVariablesUpdated(state, action: PayloadAction<string>) {
method requestBodyModeUpdated (line 87) | requestBodyModeUpdated(state, action: PayloadAction<string>) {
FILE: webview/features/requestHeader/requestHeaderSlice.ts
type Header (line 4) | interface Header {
method requestHeaderUpdated (line 42) | requestHeaderUpdated(state, action: PayloadAction<any>) {
method requestHeaderAdded (line 45) | requestHeaderAdded(state, action: PayloadAction<Header>) {
method requestHeaderDeleted (line 48) | requestHeaderDeleted(state, action: PayloadAction<number>) {
FILE: webview/features/requestMethod/requestMethodSlice.ts
method requestMethodUpdated (line 20) | requestMethodUpdated(state, action: PayloadAction<string>) {
FILE: webview/features/requestOptions/requestOptionsSlice.ts
type RequestOptions (line 17) | interface RequestOptions {
method requestOptionsUpdated (line 29) | requestOptionsUpdated(_, action: PayloadAction<RequestOptions>) {
FILE: webview/features/requestUrl/requestUrlSlice.ts
type QueryParam (line 5) | interface QueryParam {
type Variable (line 12) | interface Variable {
type RequestUrlState (line 18) | interface RequestUrlState {
method requestUrlUpdated (line 38) | requestUrlUpdated(state, action: PayloadAction<string>) {
method requestQueryParamAdded (line 48) | requestQueryParamAdded(state, action: PayloadAction<QueryParam>) {
method requestQueryParamUpdated (line 51) | requestQueryParamUpdated(state, action: PayloadAction<any>) {
method requestQueryParamDeleted (line 54) | requestQueryParamDeleted(state, action: PayloadAction<number>) {
FILE: webview/features/response/responseSlice.ts
type ResponseState (line 4) | interface ResponseState {
method responseUpdated (line 21) | responseUpdated(state, action: PayloadAction<any>) {
method responseLoadingStarted (line 34) | responseLoadingStarted(state) {
FILE: webview/react-app-env.d.ts
type ProcessEnv (line 6) | interface ProcessEnv {
FILE: webview/redux/store.ts
type AppDispatch (line 31) | type AppDispatch = typeof store.dispatch;
type RootState (line 32) | type RootState = ReturnType<typeof store.getState>;
type AppThunk (line 33) | type AppThunk<ReturnType = void> = ThunkAction<
Condensed preview — 97 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (112K chars).
[
{
"path": ".eslintrc.json",
"chars": 643,
"preview": "{\n \"env\": {\n \"browser\": true,\n \"es2021\": true,\n \"node\": true\n },\n \"extends\": [\n \"eslint:recommended\",\n "
},
{
"path": ".gitignore",
"chars": 43,
"preview": "out\ndist\nnode_modules\n.vscode-test/\n*.vsix\n"
},
{
"path": ".husky/pre-push",
"chars": 52,
"preview": "#!/bin/sh\n. \"$(dirname \"$0\")/_/husky.sh\"\n\nyarn lint\n"
},
{
"path": ".prettierignore",
"chars": 9,
"preview": "out\ndist\n"
},
{
"path": ".vscode/launch.json",
"chars": 956,
"preview": "// A launch configuration that compiles the extension and then opens it inside a new window\n// Use IntelliSense to learn"
},
{
"path": ".vscode/settings.json",
"chars": 599,
"preview": "// Place your settings in this file to overwrite default and user settings.\n{\n \"files.exclude\": {\n \"out\": false, // "
},
{
"path": ".vscode/tasks.json",
"chars": 655,
"preview": "// See https://go.microsoft.com/fwlink/?LinkId=733558\n// for the documentation about the tasks.json format\n{\n \"version\""
},
{
"path": ".vscodeignore",
"chars": 216,
"preview": ".vscode/**\n.vscode-test/**\nout/**\nnode_modules/**\nsrc/**\n.gitignore\n.yarnrc\nvsc-extension-quickstart.md\n**/tsconfig.json"
},
{
"path": ".yarnrc",
"chars": 21,
"preview": "--ignore-engines true"
},
{
"path": "CHANGELOG.md",
"chars": 918,
"preview": "# Change Log\n\nAll notable changes to the \"postcode\" extension will be documented in this file.\n\nCheck [Keep a Changelog]"
},
{
"path": "LICENSE",
"chars": 1071,
"preview": "MIT License\n\nCopyright (c) 2021 Rohini Senthil\n\nPermission is hereby granted, free of charge, to any person obtaining a "
},
{
"path": "README.md",
"chars": 4405,
"preview": "<h1 align=\"center\">Postcode</h1>\n<div align=\"center\">\n <strong> API client for VS code 📦</strong> \n <br/> <br/>\n <a "
},
{
"path": "package.json",
"chars": 3408,
"preview": "{\n \"name\": \"postcode\",\n \"publisher\": \"rohinivsenthil\",\n \"displayName\": \"Postcode\",\n \"icon\": \"icons/icon.png\",\n \"des"
},
{
"path": "src/extension.ts",
"chars": 6007,
"preview": "// The module 'vscode' contains the VS Code extensibility API\n// Import the module and reference it with the alias vscod"
},
{
"path": "src/test/runTest.ts",
"chars": 660,
"preview": "import * as path from \"path\";\n\nimport { runTests } from \"vscode-test\";\n\nasync function main() {\n try {\n // The folde"
},
{
"path": "src/test/suite/extension.test.ts",
"chars": 466,
"preview": "import * as assert from \"assert\";\n\n// You can import and use all API from the 'vscode' module\n// as well as import your "
},
{
"path": "src/test/suite/index.ts",
"chars": 844,
"preview": "import * as path from \"path\";\nimport * as Mocha from \"mocha\";\nimport * as glob from \"glob\";\n\nexport function run(): Prom"
},
{
"path": "tsconfig.json",
"chars": 653,
"preview": "{\n \"compilerOptions\": {\n \"module\": \"commonjs\",\n \"target\": \"es6\",\n \"outDir\": \"out\",\n \"jsx\": \"react\",\n \"li"
},
{
"path": "webpack.config.js",
"chars": 4342,
"preview": "/* eslint-disable @typescript-eslint/no-var-requires */\n//@ts-check\n\n\"use strict\";\n\nconst path = require(\"path\");\nconst "
},
{
"path": "webview/App.css",
"chars": 48,
"preview": ".App {\n background-color: var(--background);\n}\n"
},
{
"path": "webview/App.tsx",
"chars": 565,
"preview": "import * as React from \"react\";\nimport \"./App.css\";\nimport { responseUpdated } from \"./features/response/responseSlice\";"
},
{
"path": "webview/acquireVsCodeApi.d.ts",
"chars": 35,
"preview": "declare var acquireVsCodeApi: any;\n"
},
{
"path": "webview/components/RequestBar/index.tsx",
"chars": 2094,
"preview": "import * as React from \"react\";\nimport { Url } from \"postman-collection\";\nimport vscode from \"../../vscode\";\nimport { Re"
},
{
"path": "webview/components/RequestBar/styles.css",
"chars": 803,
"preview": ".request-bar {\n display: flex;\n padding: 0 20px;\n padding-top: 30px;\n}\n\n.input-request-url {\n flex: 2;\n padding: 13"
},
{
"path": "webview/components/RequestOptionsBar/index.tsx",
"chars": 1633,
"preview": "import * as React from \"react\";\nimport \"./styles.css\";\nimport * as propTypes from \"prop-types\";\nimport { requestOptions "
},
{
"path": "webview/components/RequestOptionsBar/styles.css",
"chars": 1038,
"preview": ".request-options-tab-wrapper {\n display: flex;\n justify-content: space-between;\n padding: 15px 20px 0 20px;\n}\n\n.reque"
},
{
"path": "webview/components/RequestOptionsWindow/index.tsx",
"chars": 1147,
"preview": "import * as React from \"react\";\nimport { RequestQueryParams } from \"../../features/requestUrl/RequestQueryParams\";\nimpor"
},
{
"path": "webview/components/RequestOptionsWindow/styles.css",
"chars": 98,
"preview": ".request-options-window-wrapper {\n flex: 1;\n padding: 5px 20px 10px 20px;\n overflow: scroll;\n}\n"
},
{
"path": "webview/components/Response/index.tsx",
"chars": 1709,
"preview": "import * as React from \"react\";\nimport { ResponseTab } from \"../../features/response/ResponseTab\";\nimport { ResponseWind"
},
{
"path": "webview/components/Response/styles.css",
"chars": 2152,
"preview": ".response-body-wrapper {\n display: flex;\n flex-direction: column;\n flex: 1;\n font-size: var(--default-font-size);\n "
},
{
"path": "webview/constants/request-options.ts",
"chars": 299,
"preview": "export const requestOptions = [\n {\n name: \"Params\",\n value: \"params\",\n },\n {\n name: \"Authorization\",\n val"
},
{
"path": "webview/constants/response-options.ts",
"chars": 134,
"preview": "export const responseOptions = [\n {\n name: \"Body\",\n value: \"body\",\n },\n {\n name: \"Headers\",\n value: \"head"
},
{
"path": "webview/constants/response-views.ts",
"chars": 128,
"preview": "export const responseViews = [\n {\n name: \"Pretty\",\n value: \"pretty\",\n },\n {\n name: \"Raw\",\n value: \"raw\",\n"
},
{
"path": "webview/constants/supported-langs.ts",
"chars": 217,
"preview": "export const supportedLangs = [\n {\n name: \"JSON\",\n value: \"json\",\n },\n {\n name: \"HTML\",\n value: \"html\",\n "
},
{
"path": "webview/features/codeGen/CodeSnippet/index.tsx",
"chars": 2290,
"preview": "import * as React from \"react\";\nimport \"./styles.css\";\nimport {\n codeGenLanguageUpdated,\n codeGenOptions,\n codeGenVar"
},
{
"path": "webview/features/codeGen/CodeSnippet/styles.css",
"chars": 741,
"preview": ".code-gen-wrapper {\n height: 100%;\n display: flex;\n flex-direction: column;\n}\n\n.code-gen-options {\n display: flex;\n "
},
{
"path": "webview/features/codeGen/codeGenSlice.ts",
"chars": 3500,
"preview": "import { createSlice, PayloadAction } from \"@reduxjs/toolkit\";\nimport { RootState } from \"../../redux/store\";\nimport { R"
},
{
"path": "webview/features/requestAuth/BasicAuth/index.tsx",
"chars": 1649,
"preview": "import * as React from \"react\";\nimport \"./styles.css\";\nimport { useAppDispatch, useAppSelector } from \"../../../redux/ho"
},
{
"path": "webview/features/requestAuth/BasicAuth/styles.css",
"chars": 605,
"preview": ".basic-auth-input-group {\n padding: 15px 0 0 0;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n."
},
{
"path": "webview/features/requestAuth/BearerToken/index.tsx",
"chars": 841,
"preview": "import * as React from \"react\";\nimport { useAppDispatch, useAppSelector } from \"../../../redux/hooks\";\nimport {\n reques"
},
{
"path": "webview/features/requestAuth/BearerToken/styles.css",
"chars": 607,
"preview": ".bearer-token-wrapper {\n display: flex;\n justify-content: center;\n align-items: center;\n padding: 15px 0;\n}\n\n.label-"
},
{
"path": "webview/features/requestAuth/NoAuth/index.tsx",
"chars": 256,
"preview": "import * as React from \"react\";\nimport \"./styles.css\";\n\nexport const NoAuth = () => {\n return (\n <div className=\"no-"
},
{
"path": "webview/features/requestAuth/NoAuth/styles.css",
"chars": 65,
"preview": ".no-auth-wrapper {\n display: flex;\n justify-content: center;\n}\n"
},
{
"path": "webview/features/requestAuth/RequestAuth/index.tsx",
"chars": 1314,
"preview": "import * as React from \"react\";\nimport \"./styles.css\";\nimport { NoAuth } from \"../NoAuth\";\nimport { BearerToken } from \""
},
{
"path": "webview/features/requestAuth/RequestAuth/styles.css",
"chars": 738,
"preview": ".req-auth-wrapper {\n margin-top: 15px;\n}\n\n.auth-type {\n display: flex;\n align-items: center;\n}\n\n.label-auth-type {\n "
},
{
"path": "webview/features/requestAuth/requestAuthSlice.ts",
"chars": 1505,
"preview": "import { createSlice, PayloadAction } from \"@reduxjs/toolkit\";\nimport { RootState } from \"../../redux/store\";\n\nexport co"
},
{
"path": "webview/features/requestBody/Binary/index.tsx",
"chars": 1093,
"preview": "import * as React from \"react\";\nimport \"./styles.css\";\nimport { useAppDispatch, useAppSelector } from \"../../../redux/ho"
},
{
"path": "webview/features/requestBody/Binary/styles.css",
"chars": 441,
"preview": ".binary-wrapper {\n border-top: var(--default-border-size) solid var(--border);\n display: flex;\n margin-top: 15px;\n c"
},
{
"path": "webview/features/requestBody/FormData/index.tsx",
"chars": 885,
"preview": "import * as React from \"react\";\nimport \"./styles.css\";\nimport { KeyValueTable } from \"../../../shared/KeyValueTable\";\nim"
},
{
"path": "webview/features/requestBody/FormData/styles.css",
"chars": 43,
"preview": ".form-data-wrapper {\n margin-top: 15px;\n}\n"
},
{
"path": "webview/features/requestBody/GraphQL/index.tsx",
"chars": 1459,
"preview": "import * as React from \"react\";\nimport \"./styles.css\";\nimport { useAppDispatch, useAppSelector } from \"../../../redux/ho"
},
{
"path": "webview/features/requestBody/GraphQL/styles.css",
"chars": 324,
"preview": ".gql-wrapper {\n display: flex;\n height: 100%;\n margin-top: 10px;\n}\n\n.gql-section {\n height: 95%;\n padding: 0 10px 0"
},
{
"path": "webview/features/requestBody/NoBody/index.tsx",
"chars": 224,
"preview": "import * as React from \"react\";\nimport \"./styles.css\";\n\nexport const None = () => {\n return (\n <div className=\"none-"
},
{
"path": "webview/features/requestBody/NoBody/styles.css",
"chars": 257,
"preview": ".none-wrapper {\n border-top: var(--default-border-size) solid var(--border);\n display: flex;\n justify-content: center"
},
{
"path": "webview/features/requestBody/Raw/index.tsx",
"chars": 936,
"preview": "import * as React from \"react\";\nimport \"./styles.css\";\nimport { useAppDispatch, useAppSelector } from \"../../../redux/ho"
},
{
"path": "webview/features/requestBody/Raw/styles.css",
"chars": 84,
"preview": ".raw-wrapper {\n height: 95%;\n margin-top: 15px;\n}\n\n.raw-editor {\n height: 95%;\n}\n"
},
{
"path": "webview/features/requestBody/RequestBody/index.tsx",
"chars": 2826,
"preview": "import * as React from \"react\";\nimport { Binary } from \"../Binary\";\nimport { FormData } from \"../FormData\";\nimport { Non"
},
{
"path": "webview/features/requestBody/RequestBody/styles.css",
"chars": 1101,
"preview": ".request-body-wrapper {\n display: flex;\n flex-direction: column;\n height: 100%;\n}\n\n.request-body-window-wrapper {\n f"
},
{
"path": "webview/features/requestBody/UrlEncoded/index.tsx",
"chars": 905,
"preview": "import * as React from \"react\";\nimport \"./styles.css\";\nimport { KeyValueTable } from \"../../../shared/KeyValueTable\";\nim"
},
{
"path": "webview/features/requestBody/UrlEncoded/styles.css",
"chars": 45,
"preview": ".url-encoded-wrapper {\n margin-top: 15px;\n}\n"
},
{
"path": "webview/features/requestBody/requestBodySlice.ts",
"chars": 4704,
"preview": "/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { createSlice, PayloadAction } from \"@reduxjs/toolkit\";\ni"
},
{
"path": "webview/features/requestHeader/HeadersWindow/index.tsx",
"chars": 806,
"preview": "import * as React from \"react\";\nimport \"./styles.css\";\nimport { KeyValueTable } from \"../../../shared/KeyValueTable\";\nim"
},
{
"path": "webview/features/requestHeader/HeadersWindow/styles.css",
"chars": 41,
"preview": ".headers-wrapper {\n margin-top: 15px;\n}\n"
},
{
"path": "webview/features/requestHeader/requestHeaderSlice.ts",
"chars": 1327,
"preview": "import { createSlice, PayloadAction } from \"@reduxjs/toolkit\";\nimport { RootState } from \"../../redux/store\";\n\ninterface"
},
{
"path": "webview/features/requestMethod/RequestMethodSelector/index.tsx",
"chars": 706,
"preview": "import * as React from \"react\";\nimport { useAppDispatch, useAppSelector } from \"../../../redux/hooks\";\nimport {\n reques"
},
{
"path": "webview/features/requestMethod/RequestMethodSelector/styles.css",
"chars": 417,
"preview": ".request-method-selector {\n padding: 12px 20px;\n display: inline-block;\n font-weight: 600;\n outline: none;\n border:"
},
{
"path": "webview/features/requestMethod/requestMethodSlice.ts",
"chars": 827,
"preview": "import { createSlice, PayloadAction } from \"@reduxjs/toolkit\";\nimport { RootState } from \"../../redux/store\";\n\nexport co"
},
{
"path": "webview/features/requestOptions/RequestOptions/index.tsx",
"chars": 1612,
"preview": "import * as React from \"react\";\nimport { useDispatch } from \"react-redux\";\nimport { useAppSelector } from \"../../../redu"
},
{
"path": "webview/features/requestOptions/RequestOptions/styles.css",
"chars": 562,
"preview": ".req-options-wrapper {\n margin-top: 15px;\n}\n\n.options {\n display: flex;\n align-items: center;\n}\n\n.req-option-la"
},
{
"path": "webview/features/requestOptions/requestOptionsSlice.ts",
"chars": 855,
"preview": "import { createSlice, PayloadAction } from \"@reduxjs/toolkit\";\nimport { RootState } from \"../../redux/store\";\n\nexport co"
},
{
"path": "webview/features/requestUrl/RequestQueryParams/index.tsx",
"chars": 855,
"preview": "import * as React from \"react\";\nimport \"./styles.css\";\nimport { KeyValueTable } from \"../../../shared/KeyValueTable\";\nim"
},
{
"path": "webview/features/requestUrl/RequestQueryParams/styles.css",
"chars": 40,
"preview": ".params-wrapper {\n margin-top: 15px;\n}\n"
},
{
"path": "webview/features/requestUrl/RequestUrl/index.tsx",
"chars": 532,
"preview": "import * as React from \"react\";\nimport { useAppDispatch, useAppSelector } from \"../../../redux/hooks\";\nimport { requestU"
},
{
"path": "webview/features/requestUrl/RequestUrl/styles.css",
"chars": 371,
"preview": ".input-request-url {\n flex: 2;\n padding: 13px 20px;\n color: var(--default-text);\n display: inline-block;\n outline: "
},
{
"path": "webview/features/requestUrl/requestUrlSlice.ts",
"chars": 1937,
"preview": "import { createSlice, PayloadAction } from \"@reduxjs/toolkit\";\nimport { RootState } from \"../../redux/store\";\nimport { U"
},
{
"path": "webview/features/response/ResponseBody/index.tsx",
"chars": 801,
"preview": "import * as React from \"react\";\nimport \"./styles.css\";\nimport { useAppSelector } from \"../../../redux/hooks\";\nimport { s"
},
{
"path": "webview/features/response/ResponseBody/styles.css",
"chars": 74,
"preview": ".response-window {\n height: 100%;\n}\n\n.response-editor {\n height: 95%;\n}\n"
},
{
"path": "webview/features/response/ResponseHeaders/index.tsx",
"chars": 443,
"preview": "import * as React from \"react\";\nimport { useAppSelector } from \"../../../redux/hooks\";\nimport { KeyValueTable } from \".."
},
{
"path": "webview/features/response/ResponseHeaders/styles.css",
"chars": 52,
"preview": ".response-headers {\n display: flex;\n height: 80%;\n}"
},
{
"path": "webview/features/response/ResponseTab/index.tsx",
"chars": 2204,
"preview": "import * as React from \"react\";\nimport \"./styles.css\";\nimport * as propTypes from \"prop-types\";\nimport { responseOptions"
},
{
"path": "webview/features/response/ResponseTab/styles.css",
"chars": 1292,
"preview": ".response-options-tab-wrapper {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 15p"
},
{
"path": "webview/features/response/ResponseWindow/index.tsx",
"chars": 638,
"preview": "import * as React from \"react\";\nimport * as propTypes from \"prop-types\";\nimport \"./styles.css\";\nimport { ResponseBody } "
},
{
"path": "webview/features/response/ResponseWindow/styles.css",
"chars": 79,
"preview": ".response-options-window-wrapper {\n flex: 1;\n padding: 5px 20px 10px 20px;\n}\n"
},
{
"path": "webview/features/response/responseSlice.ts",
"chars": 1172,
"preview": "import { createSlice, PayloadAction } from \"@reduxjs/toolkit\";\nimport { RootState } from \"../../redux/store\";\n\nexport in"
},
{
"path": "webview/index.css",
"chars": 1314,
"preview": "body {\n margin: 0;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Roboto\", \"Oxygen\",\n \"Ubuntu\", \"Can"
},
{
"path": "webview/index.tsx",
"chars": 307,
"preview": "import * as React from \"react\";\nimport * as ReactDOM from \"react-dom\";\nimport { Provider } from \"react-redux\";\nimport { "
},
{
"path": "webview/pages/Postcode/index.tsx",
"chars": 968,
"preview": "/* eslint-disable @typescript-eslint/no-explicit-any */\nimport * as React from \"react\";\nimport \"./styles.css\";\nimport { "
},
{
"path": "webview/pages/Postcode/styles.css",
"chars": 256,
"preview": ".request-wrapper {\n display: flex;\n flex-direction: column;\n height: inherit;\n}\n\n.request-options-wrapper {\n display"
},
{
"path": "webview/prerender.tsx",
"chars": 976,
"preview": "import { Provider } from \"react-redux\";\nimport * as React from \"react\";\nimport { renderToString } from \"react-dom/server"
},
{
"path": "webview/react-app-env.d.ts",
"chars": 1320,
"preview": "/// <reference types=\"node\" />\n/// <reference types=\"react\" />\n/// <reference types=\"react-dom\" />\n\ndeclare namespace No"
},
{
"path": "webview/redux/hooks.ts",
"chars": 350,
"preview": "import { TypedUseSelectorHook, useDispatch, useSelector } from \"react-redux\";\nimport type { RootState, AppDispatch } fro"
},
{
"path": "webview/redux/store.ts",
"chars": 1447,
"preview": "import { configureStore, ThunkAction, Action } from \"@reduxjs/toolkit\";\nimport requestAuthReducer from \"../features/requ"
},
{
"path": "webview/shared/Editor/index.tsx",
"chars": 2534,
"preview": "import * as React from \"react\";\nimport * as monaco from \"monaco-editor\";\nimport * as propTypes from \"prop-types\";\nimport"
},
{
"path": "webview/shared/Editor/styles.css",
"chars": 585,
"preview": ".monaco-editor {\n border: var(--default-border-size) solid var(--border);\n}\n\n.postcode-editor {\n position: relative;\n}"
},
{
"path": "webview/shared/KeyValueTable/index.tsx",
"chars": 3951,
"preview": "import * as React from \"react\";\nimport * as propTypes from \"prop-types\";\nimport { FaTrashAlt } from \"react-icons/fa\";\nim"
},
{
"path": "webview/shared/KeyValueTable/styles.css",
"chars": 641,
"preview": ".kv-table {\n border-collapse: collapse;\n width: 100%;\n}\n\n.kv-table,\ntd,\nth {\n border: var(--default-border-size) soli"
},
{
"path": "webview/vscode.ts",
"chars": 116,
"preview": "let vscode;\nif (typeof acquireVsCodeApi !== \"undefined\") {\n vscode = acquireVsCodeApi();\n}\n\nexport default vscode;\n"
}
]
About this extraction
This page contains the full source code of the rohinivsenthil/postcode GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 97 files (97.6 KB), approximately 27.2k tokens, and a symbol index with 47 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.