Compare commits
26 Commits
hotfix/fet
...
fix/incorr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a9814a6bce | ||
|
|
34220ba814 | ||
|
|
53ec605963 | ||
|
|
75193a7aa8 | ||
|
|
b269c239d9 | ||
|
|
72b4a1fc4e | ||
|
|
d2d1674d31 | ||
|
|
a6b57777e3 | ||
|
|
65ef4db86f | ||
|
|
7201147b55 | ||
|
|
dd143c95a9 | ||
|
|
005581ee7d | ||
|
|
1431ecc6d7 | ||
|
|
f34d896095 | ||
|
|
e95ebb9226 | ||
|
|
57365eeae0 | ||
|
|
b22bd97818 | ||
|
|
b953b32ff4 | ||
|
|
0eacd6763b | ||
|
|
8499ac7fec | ||
|
|
4adac4af38 | ||
|
|
fd162e242c | ||
|
|
3e83828722 | ||
|
|
f7dc36e3f1 | ||
|
|
a7566dfd86 | ||
|
|
d4d7a20fbd |
66
.github/workflows/release-push-docker.yml
vendored
Normal file
66
.github/workflows/release-push-docker.yml
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
name: "Push containers to Docker Hub on release"
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*.*.*'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup environment
|
||||
run: cp .env.example .env
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Build and push `${{ secrets.DOCKER_BACKEND_CONTAINER_NAME }}`
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: .
|
||||
file: ./prod.Dockerfile
|
||||
target: backend
|
||||
push: true
|
||||
tags: |
|
||||
${{ secrets.DOCKER_ORG_NAME }}/${{ secrets.DOCKER_BACKEND_CONTAINER_NAME }}:latest
|
||||
${{ secrets.DOCKER_ORG_NAME }}/${{ secrets.DOCKER_BACKEND_CONTAINER_NAME }}:${{ github.ref_name }}
|
||||
|
||||
- name: Build and push `${{ secrets.DOCKER_FRONTEND_CONTAINER_NAME }}`
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: .
|
||||
file: ./prod.Dockerfile
|
||||
target: app
|
||||
push: true
|
||||
tags: |
|
||||
${{ secrets.DOCKER_ORG_NAME }}/${{ secrets.DOCKER_FRONTEND_CONTAINER_NAME }}:latest
|
||||
${{ secrets.DOCKER_ORG_NAME }}/${{ secrets.DOCKER_FRONTEND_CONTAINER_NAME }}:${{ github.ref_name }}
|
||||
|
||||
- name: Build and push `${{ secrets.DOCKER_SH_ADMIN_CONTAINER_NAME }}`
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: .
|
||||
file: ./prod.Dockerfile
|
||||
target: sh_admin
|
||||
push: true
|
||||
tags: |
|
||||
${{ secrets.DOCKER_ORG_NAME }}/${{ secrets.DOCKER_SH_ADMIN_CONTAINER_NAME }}:latest
|
||||
${{ secrets.DOCKER_ORG_NAME }}/${{ secrets.DOCKER_SH_ADMIN_CONTAINER_NAME }}:${{ github.ref_name }}
|
||||
|
||||
- name: Build and push `${{ secrets.DOCKER_AIO_CONTAINER_NAME }}`
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: .
|
||||
file: ./prod.Dockerfile
|
||||
target: aio
|
||||
push: true
|
||||
tags: |
|
||||
${{ secrets.DOCKER_ORG_NAME }}/${{ secrets.DOCKER_AIO_CONTAINER_NAME }}:latest
|
||||
${{ secrets.DOCKER_ORG_NAME }}/${{ secrets.DOCKER_AIO_CONTAINER_NAME }}:${{ github.ref_name }}
|
||||
@@ -6,8 +6,8 @@ We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, religion, or sexual identity
|
||||
and orientation.
|
||||
nationality, personal appearance, race, caste, color, religion, or sexual
|
||||
identity and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
@@ -22,17 +22,17 @@ community include:
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the
|
||||
overall community
|
||||
* Focusing on what is best not just for us as individuals, but for the overall
|
||||
community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or
|
||||
advances of any kind
|
||||
* The use of sexualized language or imagery, and sexual attention or advances of
|
||||
any kind
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email
|
||||
address, without their explicit permission
|
||||
* Publishing others' private information, such as a physical or email address,
|
||||
without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
@@ -82,15 +82,15 @@ behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series
|
||||
of actions.
|
||||
**Community Impact**: A violation through a single incident or series of
|
||||
actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or
|
||||
permanent ban.
|
||||
like social media. Violating these terms may lead to a temporary or permanent
|
||||
ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
@@ -106,23 +106,27 @@ Violating these terms may lead to a permanent ban.
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within
|
||||
the community.
|
||||
**Consequence**: A permanent ban from any sort of public interaction within the
|
||||
community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.0, available at
|
||||
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
||||
version 2.1, available at
|
||||
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
|
||||
|
||||
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
||||
enforcement ladder](https://github.com/mozilla/diversity).
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
Community Impact Guidelines were inspired by
|
||||
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
https://www.contributor-covenant.org/faq. Translations are available at
|
||||
https://www.contributor-covenant.org/translations.
|
||||
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
|
||||
[https://www.contributor-covenant.org/translations][translations].
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
|
||||
[Mozilla CoC]: https://github.com/mozilla/diversity
|
||||
[FAQ]: https://www.contributor-covenant.org/faq
|
||||
[translations]: https://www.contributor-covenant.org/translations
|
||||
|
||||
190
README.md
190
README.md
@@ -2,23 +2,18 @@
|
||||
<a href="https://hoppscotch.io">
|
||||
<img
|
||||
src="https://avatars.githubusercontent.com/u/56705483"
|
||||
alt="Hoppscotch Logo"
|
||||
alt="Hoppscotch"
|
||||
height="64"
|
||||
/>
|
||||
</a>
|
||||
<br />
|
||||
<p>
|
||||
<h3>
|
||||
<b>
|
||||
Hoppscotch
|
||||
</b>
|
||||
</h3>
|
||||
</p>
|
||||
<p>
|
||||
<h3>
|
||||
<b>
|
||||
Open source API development ecosystem
|
||||
Hoppscotch
|
||||
</b>
|
||||
</p>
|
||||
</h3>
|
||||
<b>
|
||||
Open Source API Development Ecosystem
|
||||
</b>
|
||||
<p>
|
||||
|
||||
[](CODE_OF_CONDUCT.md) [](https://hoppscotch.io) [](https://github.com/hoppscotch/hoppscotch/actions) [](https://twitter.com/share?text=%F0%9F%91%BD%20Hoppscotch%20%E2%80%A2%20Open%20source%20API%20development%20ecosystem%20-%20Helps%20you%20create%20requests%20faster,%20saving%20precious%20time%20on%20development.&url=https://hoppscotch.io&hashtags=hoppscotch&via=hoppscotch_io)
|
||||
@@ -34,23 +29,18 @@
|
||||
</p>
|
||||
<br />
|
||||
<p>
|
||||
<a href="https://hoppscotch.io/#gh-light-mode-only" target="_blank">
|
||||
<img
|
||||
src="./packages/hoppscotch-common/public/images/banner-light.png"
|
||||
alt="Hoppscotch"
|
||||
width="100%"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://hoppscotch.io/#gh-dark-mode-only" target="_blank">
|
||||
<img
|
||||
src="./packages/hoppscotch-common/public/images/banner-dark.png"
|
||||
alt="Hoppscotch"
|
||||
width="100%"
|
||||
/>
|
||||
<a href="https://hoppscotch.io">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="./packages/hoppscotch-common/public/images/banner-dark.png">
|
||||
<source media="(prefers-color-scheme: light)" srcset="./packages/hoppscotch-common/public/images/banner-light.png">
|
||||
<img alt="Hoppscotch" src="./packages/hoppscotch-common/public/images/banner-dark.png">
|
||||
</picture>
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
_We highly recommend you take a look at the [**Hoppscotch Documentation**](https://docs.hoppscotch.io) to learn more about the app._
|
||||
|
||||
#### **Support**
|
||||
|
||||
[](https://hoppscotch.io/discord) [](https://hoppscotch.io/telegram) [](https://github.com/hoppscotch/hoppscotch/discussions)
|
||||
@@ -59,9 +49,9 @@
|
||||
|
||||
❤️ **Lightweight:** Crafted with minimalistic UI design.
|
||||
|
||||
⚡️ **Fast:** Send requests and get/copy responses in real-time.
|
||||
⚡️ **Fast:** Send requests and get responses in real time.
|
||||
|
||||
**HTTP Methods**
|
||||
🗄️ **HTTP Methods:** Request methods define the type of action you are requesting to be performed.
|
||||
|
||||
- `GET` - Requests retrieve resource information
|
||||
- `POST` - The server creates a new entry in a database
|
||||
@@ -74,17 +64,15 @@
|
||||
- `TRACE` - Performs a message loop-back test along the path to the target resource
|
||||
- `<custom>` - Some APIs use custom request methods such as `LIST`. Type in your custom methods.
|
||||
|
||||
🌈 **Make it yours:** Customizable combinations for background, foreground, and accent colors — [customize now](https://hoppscotch.io/settings).
|
||||
🌈 **Theming:** Customizable combinations for background, foreground, and accent colors — [customize now](https://hoppscotch.io/settings).
|
||||
|
||||
**Theming**
|
||||
|
||||
- Choose a theme: System (default), Light, Dark, and Black
|
||||
- Choose accent color: Green (default), Teal, Blue, Indigo, Purple, Yellow, Orange, Red, and Pink
|
||||
- Choose a theme: System preference, Light, Dark, and Black
|
||||
- Choose accent colors: Green, Teal, Blue, Indigo, Purple, Yellow, Orange, Red, and Pink
|
||||
- Distraction-free Zen mode
|
||||
|
||||
_Customized themes are synced with cloud / local session_
|
||||
_Customized themes are synced with your cloud/local session._
|
||||
|
||||
🔥 **PWA:** Install as a [PWA](https://web.dev/what-are-pwas/) on your device.
|
||||
🔥 **PWA:** Install as a [Progressive Web App](https://web.dev/progressive-web-apps) on your device.
|
||||
|
||||
- Instant loading with Service Workers
|
||||
- Offline support
|
||||
@@ -107,7 +95,7 @@ _Customized themes are synced with cloud / local session_
|
||||
|
||||
📡 **Server-Sent Events:** Receive a stream of updates from a server over an HTTP connection without resorting to polling.
|
||||
|
||||
🌩 **Socket.IO:** Send and Receive data with SocketIO server.
|
||||
🌩 **Socket.IO:** Send and Receive data with the SocketIO server.
|
||||
|
||||
🦟 **MQTT:** Subscribe and Publish to topics of an MQTT Broker.
|
||||
|
||||
@@ -127,7 +115,7 @@ _Customized themes are synced with cloud / local session_
|
||||
- OAuth 2.0
|
||||
- OIDC Access Token/PKCE
|
||||
|
||||
📢 **Headers:** Describes the format the body of your request is being sent as.
|
||||
📢 **Headers:** Describes the format the body of your request is being sent in.
|
||||
|
||||
📫 **Parameters:** Use request parameters to set varying parts in simulated requests.
|
||||
|
||||
@@ -137,14 +125,14 @@ _Customized themes are synced with cloud / local session_
|
||||
- FormData, JSON, and many more
|
||||
- Toggle between key-value and RAW input parameter list
|
||||
|
||||
👋 **Response:** Contains the status line, headers, and the message/response body.
|
||||
📮 **Response:** Contains the status line, headers, and the message/response body.
|
||||
|
||||
- Copy response to clipboard
|
||||
- Download response as a file
|
||||
- Copy the response to the clipboard
|
||||
- Download the response as a file
|
||||
- View response headers
|
||||
- View raw and preview of HTML, image, JSON, XML responses
|
||||
- View raw and preview HTML, image, JSON, and XML responses
|
||||
|
||||
⏰ **History:** Request entries are synced with cloud / local session storage to restore with a single click.
|
||||
⏰ **History:** Request entries are synced with your cloud/local session storage.
|
||||
|
||||
📁 **Collections:** Keep your API requests organized with collections and folders. Reuse them with a single click.
|
||||
|
||||
@@ -152,7 +140,32 @@ _Customized themes are synced with cloud / local session_
|
||||
- Nested folders
|
||||
- Export and import as a file or GitHub gist
|
||||
|
||||
_Collections are synced with cloud / local session storage_
|
||||
_Collections are synced with your cloud/local session storage._
|
||||
|
||||
📜 **Pre-Request Scripts:** Snippets of code associated with a request that is executed before the request is sent.
|
||||
|
||||
- Set environment variables
|
||||
- Include timestamp in the request headers
|
||||
- Send a random alphanumeric string in the URL parameters
|
||||
- Any JavaScript functions
|
||||
|
||||
👨👩👧👦 **Teams:** Helps you collaborate across your teams to design, develop, and test APIs faster.
|
||||
|
||||
- Create unlimited teams
|
||||
- Create unlimited shared collections
|
||||
- Create unlimited team members
|
||||
- Role-based access control
|
||||
- Cloud sync
|
||||
- Multiple devices
|
||||
|
||||
👥 **Workspaces:** Organize your personal and team collections environments into workspaces. Easily switch between workspaces to manage multiple projects.
|
||||
|
||||
- Create unlimited workspaces
|
||||
- Switch between personal and team workspaces
|
||||
|
||||
⌨️ **Keyboard Shortcuts:** Optimized for efficiency.
|
||||
|
||||
> **[Read our documentation on Keyboard Shortcuts](https://docs.hoppscotch.io/documentation/features/shortcuts)**
|
||||
|
||||
🌐 **Proxy:** Enable Proxy Mode from Settings to access blocked APIs.
|
||||
|
||||
@@ -161,60 +174,31 @@ _Collections are synced with cloud / local session storage_
|
||||
- Access APIs served in non-HTTPS (`http://`) endpoints
|
||||
- Use your Proxy URL
|
||||
|
||||
_Official proxy server is hosted by Hoppscotch - **[GitHub](https://github.com/hoppscotch/proxyscotch)** - **[Privacy Policy](https://docs.hoppscotch.io/support/privacy)**_
|
||||
|
||||
📜 **Pre-Request Scripts β:** Snippets of code associated with a request that is executed before the request is sent.
|
||||
|
||||
- Set environment variables
|
||||
- Include timestamp in the request headers
|
||||
- Send a random alphanumeric string in the URL parameters
|
||||
- Any JavaScript functions
|
||||
|
||||
📄 **API Documentation:** Create and share dynamic API documentation easily, quickly.
|
||||
|
||||
1. Add your requests to Collections and Folders
|
||||
2. Export Collections and easily share your APIs with the rest of your team
|
||||
3. Import Collections and Generate Documentation on-the-go
|
||||
|
||||
⌨️ **Keyboard Shortcuts:** Optimized for efficiency.
|
||||
|
||||
> **[Read our documentation on Keyboard Shortcuts](https://docs.hoppscotch.io/documentation/features/shortcuts)**
|
||||
_Official proxy server is hosted by Hoppscotch - **[GitHub](https://github.com/hoppscotch/proxyscotch)** - **[Privacy Policy](https://docs.hoppscotch.io/support/privacy)**._
|
||||
|
||||
🌎 **i18n:** Experience the app in your language.
|
||||
|
||||
Help us to translate Hoppscotch. Please read [`TRANSLATIONS`](TRANSLATIONS.md) for details on our [`CODE OF CONDUCT`](CODE_OF_CONDUCT.md), and the process for submitting pull requests to us.
|
||||
Help us to translate Hoppscotch. Please read [`TRANSLATIONS`](TRANSLATIONS.md) for details on our [`CODE OF CONDUCT`](CODE_OF_CONDUCT.md) and the process for submitting pull requests to us.
|
||||
|
||||
📦 **Add-ons:** Official add-ons for hoppscotch.
|
||||
☁️ **Auth + Sync:** Sign in and sync your data in real-time across all your devices.
|
||||
|
||||
- **[Proxy](https://github.com/hoppscotch/proxyscotch)** - A simple proxy server created for Hoppscotch
|
||||
- **[CLI β](https://github.com/hoppscotch/hopp-cli)** - A CLI solution for Hoppscotch
|
||||
- **[Browser Extensions](https://github.com/hoppscotch/hoppscotch-extension)** - Browser extensions that simplifies access to Hoppscotch
|
||||
|
||||
[ **Firefox**](https://addons.mozilla.org/en-US/firefox/addon/hoppscotch) | [ **Chrome**](https://chrome.google.com/webstore/detail/hoppscotch-extension-for-c/amknoiejhlmhancpahfcfcfhllgkpbld)
|
||||
|
||||
> **Extensions fixes `CORS` issues.**
|
||||
|
||||
- **[Hopp-Doc-Gen](https://github.com/hoppscotch/hopp-doc-gen)** - An API doc generator CLI for Hoppscotch
|
||||
|
||||
_Add-ons are developed and maintained under **[Hoppscotch Organization](https://github.com/hoppscotch)**._
|
||||
|
||||
☁️ **Auth + Sync:** Sign in and sync your data in real-time.
|
||||
|
||||
**Sign in with**
|
||||
**Sign in with:**
|
||||
|
||||
- GitHub
|
||||
- Google
|
||||
- Microsoft
|
||||
- Email
|
||||
- SSO (Single Sign-On)[^EE]
|
||||
|
||||
**Synchronize your data**
|
||||
**🔄 Synchronize your data:** Handoff to continue tasks on your other devices.
|
||||
|
||||
- Workspaces
|
||||
- History
|
||||
- Collections
|
||||
- Environments
|
||||
- Settings
|
||||
|
||||
✅ **Post-Request Tests β:** Write tests associated with a request that is executed after the request's response.
|
||||
✅ **Post-Request Tests:** Write tests associated with a request that is executed after the request's response.
|
||||
|
||||
- Check the status code as an integer
|
||||
- Filter response headers
|
||||
@@ -222,7 +206,7 @@ _Add-ons are developed and maintained under **[Hoppscotch Organization](https://
|
||||
- Set environment variables
|
||||
- Write JavaScript code
|
||||
|
||||
🌱 **Environments** : Environment variables allow you to store and reuse values in your requests and scripts.
|
||||
🌱 **Environments:** Environment variables allow you to store and reuse values in your requests and scripts.
|
||||
|
||||
- Unlimited environments and variables
|
||||
- Initialize through the pre-request script
|
||||
@@ -241,22 +225,31 @@ _Add-ons are developed and maintained under **[Hoppscotch Organization](https://
|
||||
|
||||
</details>
|
||||
|
||||
👨👩👧👦 **Teams β:** Helps you collaborate across your team to design, develop, and test APIs faster.
|
||||
|
||||
- Unlimited teams
|
||||
- Unlimited shared collections
|
||||
- Unlimited team members
|
||||
- Role-based access control
|
||||
- Cloud sync
|
||||
- Multiple devices
|
||||
|
||||
🚚 **Bulk Edit:** Edit key-value pairs in bulk.
|
||||
|
||||
- Entries are separated by newline
|
||||
- Keys and values are separated by `:`
|
||||
- Prepend `#` to any row you want to add but keep disabled
|
||||
|
||||
**For more features, please read our [documentation](https://docs.hoppscotch.io).**
|
||||
🎛️ **Admin dashboard:** Manage your team and invite members.
|
||||
|
||||
- Insights
|
||||
- Manage users
|
||||
- Manage teams
|
||||
|
||||
📦 **Add-ons:** Official add-ons for hoppscotch.
|
||||
|
||||
- **[Hoppscotch CLI](https://github.com/hoppscotch/hopp-cli)** - Command-line interface for Hoppscotch.
|
||||
- **[Proxy](https://github.com/hoppscotch/proxyscotch)** - A simple proxy server created for Hoppscotch.
|
||||
- **[Browser Extensions](https://github.com/hoppscotch/hoppscotch-extension)** - Browser extensions that enhance your Hoppscotch experience.
|
||||
|
||||
[ **Firefox**](https://addons.mozilla.org/en-US/firefox/addon/hoppscotch) | [ **Chrome**](https://chrome.google.com/webstore/detail/hoppscotch-extension-for-c/amknoiejhlmhancpahfcfcfhllgkpbld)
|
||||
|
||||
> **Extensions fix `CORS` issues.**
|
||||
|
||||
_Add-ons are developed and maintained under **[Hoppscotch Organization](https://github.com/hoppscotch)**._
|
||||
|
||||
**For a complete list of features, please read our [documentation](https://docs.hoppscotch.io).**
|
||||
|
||||
## **Demo**
|
||||
|
||||
@@ -268,18 +261,9 @@ _Add-ons are developed and maintained under **[Hoppscotch Organization](https://
|
||||
2. Click "Send" to simulate the request
|
||||
3. View the response
|
||||
|
||||
## **Built with**
|
||||
|
||||
- [HTML](https://developer.mozilla.org/en-US/docs/Web/HTML)
|
||||
- [CSS](https://developer.mozilla.org/en-US/docs/Web/CSS), [SCSS](https://sass-lang.com), [Windi CSS](https://windicss.org)
|
||||
- [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript)
|
||||
- [TypeScript](https://www.typescriptlang.org)
|
||||
- [Vue](https://vuejs.org)
|
||||
- [Vite](https://vitejs.dev)
|
||||
|
||||
## **Developing**
|
||||
|
||||
Follow our [self-hosting guide](https://docs.hoppscotch.io/documentation/self-host/getting-started) to get started with the development environment.
|
||||
Follow our [self-hosting documentation](https://docs.hoppscotch.io/documentation/self-host/getting-started) to get started with the development environment.
|
||||
|
||||
## **Contributing**
|
||||
|
||||
@@ -297,7 +281,7 @@ See the [`CHANGELOG`](CHANGELOG.md) file for details.
|
||||
|
||||
## **Authors**
|
||||
|
||||
This project exists thanks to all the people who contribute — [contribute](CONTRIBUTING.md).
|
||||
This project owes its existence to the collective efforts of all those who contribute — [contribute now](CONTRIBUTING.md).
|
||||
|
||||
<div align="center">
|
||||
<a href="https://github.com/hoppscotch/hoppscotch/graphs/contributors">
|
||||
@@ -309,4 +293,6 @@ This project exists thanks to all the people who contribute — [contribute](CON
|
||||
|
||||
## **License**
|
||||
|
||||
This project is licensed under the [MIT License](https://opensource.org/licenses/MIT) - see the [`LICENSE`](LICENSE) file for details.
|
||||
This project is licensed under the [MIT License](https://opensource.org/licenses/MIT) — see the [`LICENSE`](LICENSE) file for details.
|
||||
|
||||
[^EE]: Enterprise edition feature. [Learn more](https://docs.hoppscotch.io/documentation/self-host/getting-started).
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
|
||||
This document outlines security procedures and general policies for the Hoppscotch project.
|
||||
|
||||
1. [Reporting a security vulnerability](#reporting-a-security-vulnerability)
|
||||
3. [Incident response process](#incident-response-process)
|
||||
- [Security Policy](#security-policy)
|
||||
- [Reporting a security vulnerability](#reporting-a-security-vulnerability)
|
||||
- [Incident response process](#incident-response-process)
|
||||
|
||||
## Reporting a security vulnerability
|
||||
|
||||
|
||||
@@ -9,26 +9,24 @@ Before you start working on a new language, please look through the [open pull r
|
||||
if there is no existing translation, you can create a new one by following these steps:
|
||||
|
||||
1. **[Fork the repository](https://github.com/hoppscotch/hoppscotch/fork).**
|
||||
2. **Checkout the `i18n` branch for latest translations.**
|
||||
3. **Create a new branch for your translation with base branch `i18n`.**
|
||||
2. **Checkout the `main` branch for latest translations.**
|
||||
3. **Create a new branch for your translation with base branch `main`.**
|
||||
4. **Create target language file in the [`/packages/hoppscotch-common/locales`](https://github.com/hoppscotch/hoppscotch/tree/main/packages/hoppscotch-common/locales) directory.**
|
||||
5. **Copy the contents of the source file [`/packages/hoppscotch-common/locales/en.json`](https://github.com/hoppscotch/hoppscotch/blob/main/packages/hoppscotch-common/locales/en.json) to the target language file.**
|
||||
6. **Translate the strings in the target language file.**
|
||||
7. **Add your language entry to [`/packages/hoppscotch-common/languages.json`](https://github.com/hoppscotch/hoppscotch/blob/main/packages/hoppscotch-common/languages.json).**
|
||||
8. **Save & commit changes.**
|
||||
8. **Save and commit changes.**
|
||||
9. **Send a pull request.**
|
||||
|
||||
_You may send a pull request before all steps above are complete: e.g., you may want to ask for help with translations, or getting tests to pass. However, your pull request will not be merged until all steps above are complete._
|
||||
|
||||
`i18n` branch will be merged into `main` branch once every week.
|
||||
|
||||
Completing an initial translation of the whole site is a fairly large task. One way to break that task up is to work with other translators through pull requests on your fork. You can also [add collaborators to your fork](https://help.github.com/en/github/setting-up-and-managing-your-github-user-account/inviting-collaborators-to-a-personal-repository) if you'd like to invite other translators to commit directly to your fork and share responsibility for merging pull requests.
|
||||
|
||||
## Updating a translation
|
||||
|
||||
### Corrections
|
||||
|
||||
If you notice spelling or grammar errors, typos, or opportunities for better phrasing, open a pull request with your suggested fix. If you see a problem that you aren't sure of or don't have time to fix, open an issue.
|
||||
If you notice spelling or grammar errors, typos, or opportunities for better phrasing, open a pull request with your suggested fix. If you see a problem that you aren't sure of or don't have time to fix, [open an issue](https://github.com/hoppscotch/hoppscotch/issues/new/choose).
|
||||
|
||||
### Broken links
|
||||
|
||||
|
||||
@@ -32,5 +32,14 @@
|
||||
"@types/node": "^17.0.24",
|
||||
"cross-env": "^7.0.3",
|
||||
"http-server": "^14.1.1"
|
||||
},
|
||||
"pnpm": {
|
||||
"packageExtensions": {
|
||||
"httpsnippet@^3.0.1": {
|
||||
"peerDependencies": {
|
||||
"ajv": "6.12.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "hoppscotch-backend",
|
||||
"version": "2023.4.8",
|
||||
"version": "2023.8.0",
|
||||
"description": "",
|
||||
"author": "",
|
||||
"private": true,
|
||||
|
||||
@@ -150,7 +150,7 @@ export class ShortcodeService implements UserDataHandler, OnModuleInit {
|
||||
orderBy: {
|
||||
createdOn: 'desc',
|
||||
},
|
||||
skip: 1,
|
||||
skip: args.cursor ? 1 : 0,
|
||||
take: args.take,
|
||||
cursor: args.cursor ? { id: args.cursor } : undefined,
|
||||
});
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, religion, or sexual identity
|
||||
and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
- Demonstrating empathy and kindness toward other people
|
||||
- Being respectful of differing opinions, viewpoints, and experiences
|
||||
- Giving and gracefully accepting constructive feedback
|
||||
- Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
- Focusing on what is best not just for us as individuals, but for the
|
||||
overall community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
- The use of sexualized language or imagery, and sexual attention or
|
||||
advances of any kind
|
||||
- Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
- Public or private harassment
|
||||
- Publishing others' private information, such as a physical or email
|
||||
address, without their explicit permission
|
||||
- Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||
decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official e-mail address,
|
||||
posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at
|
||||
support@hoppscotch.io.
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence**: A private, written warning from community leaders, providing
|
||||
clarity around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series
|
||||
of actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or
|
||||
permanent ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
**Community Impact**: A serious violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
|
||||
**Consequence**: A temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified period of time. No public or
|
||||
private interaction with the people involved, including unsolicited interaction
|
||||
with those enforcing the Code of Conduct, is allowed during this period.
|
||||
Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within
|
||||
the community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.0, available at
|
||||
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
||||
|
||||
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
||||
enforcement ladder](https://github.com/mozilla/diversity).
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
https://www.contributor-covenant.org/faq. Translations are available at
|
||||
https://www.contributor-covenant.org/translations.
|
||||
@@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022
|
||||
|
||||
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.
|
||||
@@ -1,29 +1,19 @@
|
||||
<div align="center">
|
||||
<a href="https://hoppscotch.io">
|
||||
<img
|
||||
src="https://avatars.githubusercontent.com/u/56705483"
|
||||
alt="Hoppscotch Logo"
|
||||
height="64"
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
<div align="center">
|
||||
|
||||
# Hoppscotch CLI <font size=2><sup>ALPHA</sup></font>
|
||||
|
||||
</div>
|
||||
|
||||
A CLI to run Hoppscotch test scripts in CI environments.
|
||||
A CLI to run Hoppscotch Test Scripts in CI environments.
|
||||
|
||||
### **Commands:**
|
||||
|
||||
- `hopp test [options] [file]`: testing hoppscotch collection.json file
|
||||
|
||||
### **Usage:**
|
||||
```
|
||||
|
||||
```bash
|
||||
hopp [options or commands] arguments
|
||||
```
|
||||
|
||||
### **Options:**
|
||||
|
||||
- `-v`, `--ver`: see the current version of the CLI
|
||||
- `-h`, `--help`: display help for command
|
||||
|
||||
@@ -45,17 +35,21 @@ hopp [options or commands] arguments
|
||||
- Executes and outputs test-script response.
|
||||
|
||||
#### Options:
|
||||
|
||||
##### `-e <file_path>` / `--env <file_path>`
|
||||
|
||||
- Accepts path to env.json with contents in below format:
|
||||
|
||||
```json
|
||||
{
|
||||
"ENV1":"value1",
|
||||
"ENV2":"value2"
|
||||
}
|
||||
```
|
||||
|
||||
- You can now access those variables using `pw.env.get('<var_name>')`
|
||||
|
||||
Taking the above example, `pw.env.get("ENV1")` will return `"value1"`
|
||||
Taking the above example, `pw.env.get("ENV1")` will return `"value1"`
|
||||
|
||||
## Install
|
||||
|
||||
@@ -75,4 +69,59 @@ npm i -g @hoppscotch/cli
|
||||
|
||||
## **Contributing:**
|
||||
|
||||
To get started contributing to the repository, please read **[CONTRIBUTING.md](./CONTRIBUTING.md)**
|
||||
When contributing to this repository, please first discuss the change you wish to make via issue,
|
||||
email, or any other method with the owners of this repository before making a change.
|
||||
|
||||
Please note we have a code of conduct, please follow it in all your interactions with the project.
|
||||
|
||||
## Pull Request Process
|
||||
|
||||
1. Ensure any install or build dependencies are removed before the end of the layer when doing a
|
||||
build.
|
||||
2. Update the README.md with details of changes to the interface, this includes new environment
|
||||
variables, exposed ports, useful file locations and container parameters.
|
||||
3. Increase the version numbers in any examples files and the README.md to the new version that this
|
||||
Pull Request would represent. The versioning scheme we use is [SemVer](https://semver.org).
|
||||
4. You may merge the Pull Request once you have the sign-off of two other developers, or if you
|
||||
do not have permission to do that, you may request the second reviewer merge it for you.
|
||||
|
||||
## Set Up The Development Environment
|
||||
|
||||
1. After cloning the repository, execute the following commands:
|
||||
|
||||
```bash
|
||||
pnpm install
|
||||
pnpm run build
|
||||
```
|
||||
|
||||
2. In order to test locally, you can use two types of package linking:
|
||||
|
||||
1. The 'pnpm exec' way (preferred since it does not hamper your original installation of the CLI):
|
||||
|
||||
```bash
|
||||
pnpm link @hoppscotch/cli
|
||||
|
||||
// Then to use or test the CLI:
|
||||
pnpm exec hopp
|
||||
|
||||
// After testing, to remove the package linking:
|
||||
pnpm rm @hoppscotch/cli
|
||||
```
|
||||
|
||||
2. The 'global' way (warning: this might override the globally installed CLI, if exists):
|
||||
|
||||
```bash
|
||||
sudo pnpm link --global
|
||||
|
||||
// Then to use or test the CLI:
|
||||
hopp
|
||||
|
||||
// After testing, to remove the package linking:
|
||||
sudo pnpm rm --global @hoppscotch/cli
|
||||
```
|
||||
|
||||
3. To use the Typescript watch scripts:
|
||||
|
||||
```bash
|
||||
pnpm run dev
|
||||
```
|
||||
|
||||
@@ -2,7 +2,20 @@
|
||||
--font-sans: "Inter Variable", sans-serif;
|
||||
--font-icon: "Material Symbols Rounded Variable";
|
||||
--font-mono: "Roboto Mono Variable", monospace;
|
||||
--font-size-tiny: calc(var(--font-size-body) - 0.062rem);
|
||||
--font-size-body: 0.75rem;
|
||||
--font-size-tiny: 0.688rem;
|
||||
--line-height-body: 1rem;
|
||||
--upper-primary-sticky-fold: 4.125rem;
|
||||
--upper-secondary-sticky-fold: 6.188rem;
|
||||
--upper-tertiary-sticky-fold: 8.25rem;
|
||||
--upper-mobile-primary-sticky-fold: 6.625rem;
|
||||
--upper-mobile-secondary-sticky-fold: 8.688rem;
|
||||
--upper-mobile-sticky-fold: 10.75rem;
|
||||
--upper-mobile-tertiary-sticky-fold: 8.25rem;
|
||||
--lower-primary-sticky-fold: 3rem;
|
||||
--lower-secondary-sticky-fold: 5.063rem;
|
||||
--lower-tertiary-sticky-fold: 7.125rem;
|
||||
--sidebar-primary-sticky-fold: 2rem;
|
||||
}
|
||||
|
||||
@mixin dark-theme {
|
||||
@@ -200,8 +213,8 @@
|
||||
:root {
|
||||
@include base-theme;
|
||||
@include dark-theme;
|
||||
@include green-theme;
|
||||
@include dark-editor-theme;
|
||||
@include green-theme;
|
||||
}
|
||||
|
||||
:root.light {
|
||||
@@ -257,63 +270,3 @@
|
||||
:root[data-accent="yellow"] {
|
||||
@include yellow-theme;
|
||||
}
|
||||
|
||||
@mixin font-small {
|
||||
--font-size-body: 0.75rem;
|
||||
--line-height-body: 1rem;
|
||||
--upper-primary-sticky-fold: 4.125rem;
|
||||
--upper-secondary-sticky-fold: 6.188rem;
|
||||
--upper-tertiary-sticky-fold: 8.25rem;
|
||||
--upper-mobile-primary-sticky-fold: 6.625rem;
|
||||
--upper-mobile-secondary-sticky-fold: 8.688rem;
|
||||
--upper-mobile-sticky-fold: 10.75rem;
|
||||
--upper-mobile-tertiary-sticky-fold: 8.25rem;
|
||||
--lower-primary-sticky-fold: 3rem;
|
||||
--lower-secondary-sticky-fold: 5.063rem;
|
||||
--lower-tertiary-sticky-fold: 7.125rem;
|
||||
--sidebar-primary-sticky-fold: 2rem;
|
||||
}
|
||||
|
||||
@mixin font-medium {
|
||||
--font-size-body: 0.875rem;
|
||||
--line-height-body: 1.25rem;
|
||||
--upper-primary-sticky-fold: 4.375rem;
|
||||
--upper-secondary-sticky-fold: 6.688rem;
|
||||
--upper-tertiary-sticky-fold: 9rem;
|
||||
--upper-mobile-primary-sticky-fold: 7.125rem;
|
||||
--upper-mobile-secondary-sticky-fold: 9.438rem;
|
||||
--upper-mobile-sticky-fold: 11.75rem;
|
||||
--upper-mobile-tertiary-sticky-fold: 9rem;
|
||||
--lower-primary-sticky-fold: 3.25rem;
|
||||
--lower-secondary-sticky-fold: 5.563rem;
|
||||
--lower-tertiary-sticky-fold: 7.875rem;
|
||||
--sidebar-primary-sticky-fold: 2.25rem;
|
||||
}
|
||||
|
||||
@mixin font-large {
|
||||
--font-size-body: 1rem;
|
||||
--line-height-body: 1.5rem;
|
||||
--upper-primary-sticky-fold: 4.625rem;
|
||||
--upper-secondary-sticky-fold: 7.188rem;
|
||||
--upper-tertiary-sticky-fold: 9.75rem;
|
||||
--upper-mobile-primary-sticky-fold: 7.625rem;
|
||||
--upper-mobile-secondary-sticky-fold: 10.188rem;
|
||||
--upper-mobile-sticky-fold: 12.75rem;
|
||||
--upper-mobile-tertiary-sticky-fold: 9.75rem;
|
||||
--lower-primary-sticky-fold: 3.5rem;
|
||||
--lower-secondary-sticky-fold: 6.063rem;
|
||||
--lower-tertiary-sticky-fold: 8.625rem;
|
||||
--sidebar-primary-sticky-fold: 2.5rem;
|
||||
}
|
||||
|
||||
:root[data-font-size="small"] {
|
||||
@include font-small;
|
||||
}
|
||||
|
||||
:root[data-font-size="medium"] {
|
||||
@include font-medium;
|
||||
}
|
||||
|
||||
:root[data-font-size="large"] {
|
||||
@include font-large;
|
||||
}
|
||||
|
||||
@@ -653,11 +653,12 @@
|
||||
"chat": "Chat with support",
|
||||
"open_docs": "Read Documentation",
|
||||
"open_keybindings": "Keyboard shortcuts",
|
||||
"open_github": "Open GitHub repository",
|
||||
"social": "Social",
|
||||
"title": "General"
|
||||
},
|
||||
"miscellaneous": {
|
||||
"invite": "Invite people to Hoppscotch",
|
||||
"invite": "Invite your friends to Hoppscotch",
|
||||
"title": "Miscellaneous"
|
||||
},
|
||||
"request": {
|
||||
@@ -669,7 +670,13 @@
|
||||
"tab_headers": "Headers tab",
|
||||
"tab_authorization": "Authorization tab",
|
||||
"tab_pre_request_script": "Pre-request script tab",
|
||||
"tab_tests": "Tests tab"
|
||||
"tab_tests": "Tests tab",
|
||||
"tab_query": "Query tab",
|
||||
"tab_variables": "Variables tab"
|
||||
},
|
||||
"graphql": {
|
||||
"connect": "Connect to server",
|
||||
"disconnect": "Disconnect from server"
|
||||
},
|
||||
"response": {
|
||||
"copy": "Copy response",
|
||||
@@ -679,25 +686,25 @@
|
||||
"environments": {
|
||||
"new": "Create new environment",
|
||||
"new_variable": "Create a new environment variable",
|
||||
"edit": "Edit selected environment",
|
||||
"delete": "Delete selected environment",
|
||||
"duplicate": "Duplicate selected environment",
|
||||
"edit": "Edit current environment",
|
||||
"delete": "Delete current environment",
|
||||
"duplicate": "Duplicate current environment",
|
||||
"edit_global": "Edit global environment",
|
||||
"duplicate_global": "Duplicate global environment",
|
||||
"title": "Environments"
|
||||
},
|
||||
"workspace": {
|
||||
"new": "Create new team",
|
||||
"edit": "Edit selected team",
|
||||
"delete": "Delete selected team",
|
||||
"edit": "Edit current team",
|
||||
"delete": "Delete current team",
|
||||
"invite": "Invite people to team",
|
||||
"switch_to_personal": "Switch to personal workspace",
|
||||
"switch_to_personal": "Switch to your personal workspace",
|
||||
"title": "Teams"
|
||||
},
|
||||
"tab": {
|
||||
"duplicate": "Duplicate tab",
|
||||
"duplicate": "Duplicate current tab",
|
||||
"close_current": "Close current tab",
|
||||
"close_others": "Close other tabs",
|
||||
"close_others": "Close all other tabs",
|
||||
"new_tab": "Open a new tab",
|
||||
"title": "Tabs"
|
||||
},
|
||||
@@ -710,15 +717,15 @@
|
||||
"change_language": "Change Language",
|
||||
"settings": {
|
||||
"theme": {
|
||||
"black": "Black Mode",
|
||||
"dark": "Dark Mode",
|
||||
"light": "Light Mode",
|
||||
"system": "System Mode"
|
||||
"black": "Black",
|
||||
"dark": "Dark",
|
||||
"light": "Light",
|
||||
"system": "System preference"
|
||||
},
|
||||
"font": {
|
||||
"size_sm": "Change to Small",
|
||||
"size_md": "Change to Medium",
|
||||
"size_lg": "Change to Large"
|
||||
"size_sm": "Small",
|
||||
"size_md": "Medium",
|
||||
"size_lg": "Large"
|
||||
},
|
||||
"change_interceptor": "Change Interceptor",
|
||||
"change_language": "Change Language"
|
||||
|
||||
@@ -118,22 +118,22 @@
|
||||
},
|
||||
"collection": {
|
||||
"created": "Koleksi dibuat",
|
||||
"different_parent": "Cannot reorder collection with different parent",
|
||||
"different_parent": "Tidak dapat mengubah urutan koleksi dengan induk yang berbeda",
|
||||
"edit": "Mengubah Koleksi",
|
||||
"invalid_name": "Berikan nama untuk Koleksi",
|
||||
"invalid_root_move": "Collection already in the root",
|
||||
"moved": "Moved Successfully",
|
||||
"invalid_root_move": "Koleksi sudah berada di akar direktori",
|
||||
"moved": "Berhasil Dipindahkan",
|
||||
"my_collections": "Koleksi Saya",
|
||||
"name": "Koleksi Baru Saya",
|
||||
"name_length_insufficient": "Nama koleksi harus minimal 3 karakter",
|
||||
"new": "Koleksi baru",
|
||||
"order_changed": "Collection Order Updated",
|
||||
"order_changed": "Pembaruan Urutan Koleksi",
|
||||
"renamed": "Koleksi berganti nama",
|
||||
"request_in_use": "Permintaan sedang digunakan",
|
||||
"save_as": "Simpan Sebagai",
|
||||
"select": "Pilih Koleksi",
|
||||
"select_location": "Pilih lokasi",
|
||||
"select_team": "Pilih team",
|
||||
"select_team": "Pilih tim",
|
||||
"team_collections": "Koleksi Tim"
|
||||
},
|
||||
"confirm": {
|
||||
@@ -147,7 +147,7 @@
|
||||
"remove_team": "Apakah Anda yakin ingin menghapus tim ini?",
|
||||
"remove_telemetry": "Apakah Anda yakin ingin menyisih dari Telemetri?",
|
||||
"request_change": "Apakah Anda yakin ingin membuang permintaan saat ini, perubahan yang belum disimpan akan hilang.",
|
||||
"save_unsaved_tab": "Do you want to save changes made in this tab?",
|
||||
"save_unsaved_tab": "Apakah Anda ingin menyimpan perubahan yang dibuat di tab ini?",
|
||||
"sync": "Apakah Anda ingin memulihkan ruang kerja Anda dari cloud? Ini akan membuang kemajuan lokal Anda."
|
||||
},
|
||||
"count": {
|
||||
@@ -180,8 +180,8 @@
|
||||
"profile": "Masuk untuk melihat profil Anda",
|
||||
"protocols": "Protokol kosong",
|
||||
"schema": "Hubungkan ke endpoint GraphQL untuk melihat skema",
|
||||
"shortcodes": "Shortcodes are empty",
|
||||
"subscription": "Subscriptions are empty",
|
||||
"shortcodes": "Shortcodes kosong",
|
||||
"subscription": "Langganan kosong",
|
||||
"team_name": "Nama team kosong",
|
||||
"teams": "Kamu bukan di team manapun",
|
||||
"tests": "Tidak ada tes untuk permintaan ini"
|
||||
@@ -189,19 +189,19 @@
|
||||
"environment": {
|
||||
"add_to_global": "Tambahkan ke Global",
|
||||
"added": "Tambahan Environment",
|
||||
"create_new": "Membuat baru environment",
|
||||
"create_new": "Membuat environment baru",
|
||||
"created": "Environment dibuat",
|
||||
"deleted": "Environment dihapus",
|
||||
"edit": "Sunting Environment",
|
||||
"invalid_name": "Tolong beri nama untuk environment",
|
||||
"my_environments": "My Environments",
|
||||
"nested_overflow": "variabel environment bersarang dibatasi hingga 10 level",
|
||||
"my_environments": "Environment Saya",
|
||||
"nested_overflow": "Variabel environment bersarang dibatasi hingga 10 level",
|
||||
"new": "Environment Baru",
|
||||
"no_environment": "No environment",
|
||||
"no_environment_description": "Tidak ada environment yang dipilih. Pilih apa yang harus dilakukan dengan variabel berikut.",
|
||||
"select": "Pilih environment",
|
||||
"team_environments": "Team Environments",
|
||||
"title": "Environments",
|
||||
"team_environments": "Environment Tim",
|
||||
"title": "Environment",
|
||||
"updated": "Environment diperbarui",
|
||||
"variable_list": "Daftar Variable"
|
||||
},
|
||||
@@ -210,8 +210,8 @@
|
||||
"check_console_details": "Periksa console log untuk detailnya.",
|
||||
"curl_invalid_format": "cURL tidak diformat dengan benar",
|
||||
"danger_zone": "Danger zone",
|
||||
"delete_account": "Your account is currently an owner in these teams:",
|
||||
"delete_account_description": "You must either remove yourself, transfer ownership, or delete these teams before you can delete your account.",
|
||||
"delete_account": "Akun Anda saat ini merupakan pemilik dalam tim-tim ini:",
|
||||
"delete_account_description": "Anda harus menghapus diri Anda dari tim-tim ini, mentransfer kepemilikan, atau menghapus tim-tim ini sebelum Anda dapat menghapus akun Anda.",
|
||||
"empty_req_name": "Nama Permintaan Kosong",
|
||||
"f12_details": "(F12 untuk detailnya)",
|
||||
"gql_prettify_invalid_query": "Tidak dapat prettify kueri yang tidak valid, menyelesaikan kesalahan sintaksis kueri, dan coba lagi",
|
||||
@@ -294,7 +294,7 @@
|
||||
"from_json_description": "Impor dari Hoppscotch berkas koleksi",
|
||||
"from_my_collections": "Impor dari Koleksi Saya",
|
||||
"from_my_collections_description": "Impor dari Berkas Koleksi Saya",
|
||||
"from_openapi": "Import dari OpenAPI",
|
||||
"from_openapi": "Impor dari OpenAPI",
|
||||
"from_openapi_description": "Impor dari OpenAPI syarat berkas (YML/JSON)",
|
||||
"from_postman": "Impor dari Postman",
|
||||
"from_postman_description": "Impor dari Koleksi Postman",
|
||||
@@ -316,23 +316,23 @@
|
||||
"zen_mode": "Zen mode"
|
||||
},
|
||||
"modal": {
|
||||
"close_unsaved_tab": "You have unsaved changes",
|
||||
"close_unsaved_tab": "Anda memiliki perubahan yang belum disimpan",
|
||||
"collections": "Koleksi",
|
||||
"confirm": "Mengonfirmasi",
|
||||
"edit_request": "Edit Request",
|
||||
"import_export": "Impor / Ekspor"
|
||||
},
|
||||
"mqtt": {
|
||||
"already_subscribed": "You are already subscribed to this topic.",
|
||||
"clean_session": "Clean Session",
|
||||
"clear_input": "Clear input",
|
||||
"clear_input_on_send": "Clear input on send",
|
||||
"already_subscribed": "Anda sudah berlangganan topik ini.",
|
||||
"clean_session": "Sesi Bersih",
|
||||
"clear_input": "Hapus input",
|
||||
"clear_input_on_send": "Hapus input saat mengirim",
|
||||
"client_id": "Client ID",
|
||||
"color": "Pick a color",
|
||||
"color": "Pilih warna",
|
||||
"communication": "Komunikasi",
|
||||
"connection_config": "Connection Config",
|
||||
"connection_not_authorized": "This MQTT connection does not use any authentication.",
|
||||
"invalid_topic": "Please provide a topic for the subscription",
|
||||
"connection_config": "Konfigurasi Koneksi",
|
||||
"connection_not_authorized": "Koneksi MQTT ini tidak menggunakan otentikasi",
|
||||
"invalid_topic": "Harap berikan topik untuk langganan",
|
||||
"keep_alive": "Keep Alive",
|
||||
"log": "Log",
|
||||
"lw_message": "Last-Will Message",
|
||||
@@ -340,8 +340,8 @@
|
||||
"lw_retain": "Last-Will Retain",
|
||||
"lw_topic": "Last-Will Topic",
|
||||
"message": "Pesan",
|
||||
"new": "New Subscription",
|
||||
"not_connected": "Please start a MQTT connection first.",
|
||||
"new": "Langganan Baru",
|
||||
"not_connected": "Mulai koneksi MQTT terlebih dahulu",
|
||||
"publish": "Menerbitkan",
|
||||
"qos": "QoS",
|
||||
"ssl": "SSL",
|
||||
@@ -396,19 +396,19 @@
|
||||
"text": "Text"
|
||||
},
|
||||
"copy_link": "Salin tautan",
|
||||
"different_collection": "Cannot reorder requests from different collections",
|
||||
"different_collection": "Tidak dapat mengubah urutan permintaan dari koleksi yang berbeda",
|
||||
"duplicated": "Request duplicated",
|
||||
"duration": "Durasi",
|
||||
"enter_curl": "Masukkan cURL",
|
||||
"generate_code": "Generate code",
|
||||
"generated_code": "Generated code",
|
||||
"generate_code": "Hasilkan kode",
|
||||
"generated_code": "Hasilkan kode",
|
||||
"header_list": "Daftar Header",
|
||||
"invalid_name": "Harap berikan nama untuk request",
|
||||
"method": "Method",
|
||||
"moved": "Request moved",
|
||||
"name": "Request nama",
|
||||
"new": "Request baru",
|
||||
"order_changed": "Request Order Updated",
|
||||
"order_changed": "Urutan Request Diperbarui",
|
||||
"override": "Membatalkan",
|
||||
"override_help": "Set <kbd>Content-Type</kbd> in Headers",
|
||||
"overriden": "Diganti",
|
||||
@@ -453,7 +453,7 @@
|
||||
"settings": {
|
||||
"accent_color": "Accent color",
|
||||
"account": "Akun",
|
||||
"account_deleted": "Your account has been deleted",
|
||||
"account_deleted": "Akun Anda telah dihapus",
|
||||
"account_description": "Sesuaikan pengaturan akun Anda.",
|
||||
"account_email_description": "Alamat surel utama Anda.",
|
||||
"account_name_description": "Ini adalah nama tampilan Anda.",
|
||||
@@ -609,7 +609,7 @@
|
||||
"file_imported": "File diimpor",
|
||||
"finished_in": "Selesai dalam {duration} ms",
|
||||
"history_deleted": "Riwayat dihapus",
|
||||
"linewrap": "Wrap lines",
|
||||
"linewrap": "Bungkus baris",
|
||||
"loading": "Memuat...",
|
||||
"message_received": "Pesan: {message} tiba di topik: {topic}",
|
||||
"mqtt_subscription_failed": "Terjadi masalah saat berlangganan topik: {topic}",
|
||||
@@ -666,7 +666,7 @@
|
||||
"email_do_not_match": "Surel tidak cocok dengan detail akun Anda. Hubungi pemilik tim Anda.",
|
||||
"exit": "Keluar dari Tim",
|
||||
"exit_disabled": "Hanya pemilik yang tidak dapat keluar dari tim",
|
||||
"invalid_coll_id": "Invalid collection ID",
|
||||
"invalid_coll_id": "ID koleksi tidak valid",
|
||||
"invalid_email_format": "Format surel tidak valid",
|
||||
"invalid_id": "ID tim tidak valid. Hubungi pemilik tim Anda.",
|
||||
"invalid_invite_link": "Tautan undangan tidak valid",
|
||||
@@ -690,7 +690,7 @@
|
||||
"member_removed": "Pengguna dihapus",
|
||||
"member_role_updated": "Peran pengguna diperbarui",
|
||||
"members": "Anggota",
|
||||
"more_members": "+{count} more",
|
||||
"more_members": "+{count} lebih",
|
||||
"name_length_insufficient": "Nama tim harus setidaknya 6 karakter",
|
||||
"name_updated": "Nama tim diperbarui",
|
||||
"new": "Tim Baru",
|
||||
@@ -698,13 +698,13 @@
|
||||
"new_name": "Tim baru saya",
|
||||
"no_access": "Anda tidak memiliki akses edit ke collections ini",
|
||||
"no_invite_found": "Undangan tidak ditemukan. Hubungi pemilik tim Anda.",
|
||||
"no_request_found": "Request not found.",
|
||||
"no_request_found": "Request tidak ditemukan.",
|
||||
"not_found": "Tim tidak ditemukan. Hubungi pemilik tim Anda.",
|
||||
"not_valid_viewer": "Anda bukan penonton yang valid. Hubungi pemilik tim Anda.",
|
||||
"parent_coll_move": "Cannot move collection to a child collection",
|
||||
"parent_coll_move": "Tidak dapat memindahkan koleksi ke dalam koleksi anak",
|
||||
"pending_invites": "Undangan tertunda",
|
||||
"permissions": "Izin",
|
||||
"same_target_destination": "Same target and destination",
|
||||
"same_target_destination": "Sama tujuan dan destinasi",
|
||||
"saved": "Tim disimpan",
|
||||
"select_a_team": "Pilih tim",
|
||||
"title": "tim",
|
||||
@@ -712,9 +712,9 @@
|
||||
"we_sent_invite_link_description": "Minta semua undangan untuk memeriksa kotak masuk mereka. Klik tautan untuk bergabung dengan tim."
|
||||
},
|
||||
"team_environment": {
|
||||
"deleted": "Environment Deleted",
|
||||
"duplicate": "Environment Duplicated",
|
||||
"not_found": "Environment not found."
|
||||
"deleted": "Environment dihapus",
|
||||
"duplicate": "Environment diduplikasi",
|
||||
"not_found": "Environment tidak ditemukan."
|
||||
},
|
||||
"test": {
|
||||
"failed": "Tes gagal",
|
||||
@@ -734,9 +734,9 @@
|
||||
"url": "URL"
|
||||
},
|
||||
"workspace": {
|
||||
"change": "Change workspace",
|
||||
"personal": "My Workspace",
|
||||
"team": "Team Workspace",
|
||||
"change": "Beralih workspace",
|
||||
"personal": "Workspace Saya",
|
||||
"team": "Workspace Tim",
|
||||
"title": "Workspaces"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,48 +1,50 @@
|
||||
{
|
||||
"action": {
|
||||
"autoscroll": "Autoscroll",
|
||||
"autoscroll": "Автоскрол",
|
||||
"cancel": "Отменить",
|
||||
"choose_file": "Выберите файл",
|
||||
"clear": "Очистить",
|
||||
"clear_all": "Очистить все",
|
||||
"close": "Close",
|
||||
"clear_history": "Очистить всю историю",
|
||||
"close": "Закрыть",
|
||||
"connect": "Подключиться",
|
||||
"connecting": "Connecting",
|
||||
"connecting": "Соединение...",
|
||||
"copy": "Скопировать",
|
||||
"delete": "Удалить",
|
||||
"disconnect": "Отключиться",
|
||||
"dismiss": "Скрыть",
|
||||
"dont_save": "Don't save",
|
||||
"dont_save": "Не сохранять",
|
||||
"download_file": "Скачать файл",
|
||||
"drag_to_reorder": "Drag to reorder",
|
||||
"drag_to_reorder": "Перетягивайте для сортировки",
|
||||
"duplicate": "Дублировать",
|
||||
"edit": "Редактировать",
|
||||
"filter": "Filter",
|
||||
"filter": "Фильтр",
|
||||
"go_back": "Вернуться",
|
||||
"go_forward": "Go forward",
|
||||
"group_by": "Group by",
|
||||
"go_forward": "Вперёд",
|
||||
"group_by": "Сгруппировать по",
|
||||
"label": "Название",
|
||||
"learn_more": "Узнать больше",
|
||||
"less": "Less",
|
||||
"less": "Меньше",
|
||||
"more": "Больше",
|
||||
"new": "Создать новый",
|
||||
"no": "Нет",
|
||||
"open_workspace": "Open workspace",
|
||||
"paste": "Paste",
|
||||
"open_workspace": "Открыть пространство",
|
||||
"paste": "Вставить",
|
||||
"prettify": "Форматировать",
|
||||
"rename": "Переименовать",
|
||||
"remove": "Удалить",
|
||||
"restore": "Восстановить",
|
||||
"save": "Сохранить",
|
||||
"scroll_to_bottom": "Scroll to bottom",
|
||||
"scroll_to_top": "Scroll to top",
|
||||
"scroll_to_bottom": "Вниз",
|
||||
"scroll_to_top": "Вверх",
|
||||
"search": "Поиск",
|
||||
"send": "Отправить",
|
||||
"start": "Начать",
|
||||
"starting": "Starting",
|
||||
"starting": "Запускаю",
|
||||
"stop": "Стоп",
|
||||
"to_close": "to close",
|
||||
"to_navigate": "to navigate",
|
||||
"to_select": "to select",
|
||||
"to_close": "что бы закрыть",
|
||||
"to_navigate": "для навигации",
|
||||
"to_select": "выборать",
|
||||
"turn_off": "Выключить",
|
||||
"turn_on": "Включить",
|
||||
"undo": "Отменить",
|
||||
@@ -56,9 +58,9 @@
|
||||
"chat_with_us": "Связаться с нами",
|
||||
"contact_us": "Свяжитесь с нами",
|
||||
"copy": "Копировать",
|
||||
"copy_user_id": "Copy User Auth Token",
|
||||
"developer_option": "Developer options",
|
||||
"developer_option_description": "Developer tools which helps in development and maintenance of Hoppscotch.",
|
||||
"copy_user_id": "Копировать токен пользователя",
|
||||
"developer_option": "Настройки разработчика",
|
||||
"developer_option_description": "Инструмент разработчика помогает обслуживить и развивить Hoppscotch",
|
||||
"discord": "Discord",
|
||||
"documentation": "Документация",
|
||||
"github": "GitHub",
|
||||
@@ -67,11 +69,13 @@
|
||||
"invite": "Пригласить",
|
||||
"invite_description": "В Hoppscotch мы разработали простой и интуитивно понятный интерфейс для создания и управления вашими API. Hoppscotch - это инструмент, который помогает создавать, тестировать, документировать и делиться своими API.",
|
||||
"invite_your_friends": "Пригласить своих друзей",
|
||||
"social_links": "Социальные сети",
|
||||
"social_description": "Подписывайся на наши соц. сети и оставайся всегда в курсе последних новостей, обновлений и релизов.",
|
||||
"join_discord_community": "Присоединяйтесь к нашему сообществу Discord",
|
||||
"keyboard_shortcuts": "Горячие клавиши",
|
||||
"name": "Hoppscotch",
|
||||
"new_version_found": "Найдена новая версия. Перезагрузите для обновления.",
|
||||
"options": "Options",
|
||||
"options": "Настройки",
|
||||
"proxy_privacy_policy": "Политика конфиденциальности прокси",
|
||||
"reload": "Перезагрузить",
|
||||
"search": "Поиск",
|
||||
@@ -79,7 +83,7 @@
|
||||
"shortcuts": "Ярлыки",
|
||||
"spotlight": "Прожектор",
|
||||
"status": "Статус",
|
||||
"status_description": "Check the status of the website",
|
||||
"status_description": "Проверить состояние сайта",
|
||||
"terms_and_privacy": "Условия и конфиденциальность",
|
||||
"twitter": "Twitter",
|
||||
"type_a_command_search": "Введите команду или выполните поиск…",
|
||||
@@ -93,7 +97,7 @@
|
||||
"continue_with_email": "Продолжить с электронной почтой",
|
||||
"continue_with_github": "Продолжить с GitHub",
|
||||
"continue_with_google": "Продолжить с Google",
|
||||
"continue_with_microsoft": "Continue with Microsoft",
|
||||
"continue_with_microsoft": "Продолжить с Microsoft",
|
||||
"email": "Электронное письмо",
|
||||
"logged_out": "Вышли из",
|
||||
"login": "Авторизоваться",
|
||||
@@ -118,19 +122,20 @@
|
||||
},
|
||||
"collection": {
|
||||
"created": "Коллекция создана",
|
||||
"different_parent": "Cannot reorder collection with different parent",
|
||||
"different_parent": "Нельзя сортировать коллекцию с разной родительской коллекцией",
|
||||
"edit": "Редактировать коллекцию",
|
||||
"invalid_name": "Укажите допустимое название коллекции",
|
||||
"invalid_root_move": "Collection already in the root",
|
||||
"moved": "Moved Successfully",
|
||||
"invalid_root_move": "Коллекция уже в корне",
|
||||
"moved": "Перемещено успешно",
|
||||
"my_collections": "Мои коллекции",
|
||||
"name": "Новая коллекция",
|
||||
"name_length_insufficient": "Collection name should be at least 3 characters long",
|
||||
"name_length_insufficient": "Имя коллекции должно иметь 3 или более символов",
|
||||
"new": "Создать коллекцию",
|
||||
"order_changed": "Collection Order Updated",
|
||||
"order_changed": "Порядок коллекции обновлён",
|
||||
"renamed": "Коллекция переименована",
|
||||
"request_in_use": "Запрос обрабатывается",
|
||||
"save_as": "Сохранить как",
|
||||
"save_to_collection": "Сохранить в коллекцию",
|
||||
"select": "Выбрать коллекцию",
|
||||
"select_location": "Выберите местоположение",
|
||||
"select_team": "Выберите команду",
|
||||
@@ -146,10 +151,17 @@
|
||||
"remove_request": "Вы уверены, что хотите навсегда удалить этот запрос?",
|
||||
"remove_team": "Вы уверены, что хотите удалить эту команду?",
|
||||
"remove_telemetry": "Вы действительно хотите отказаться от телеметрии?",
|
||||
"request_change": "Are you sure you want to discard current request, unsaved changes will be lost.",
|
||||
"save_unsaved_tab": "Do you want to save changes made in this tab?",
|
||||
"request_change": "Вы уверены что хотите сбросить текущий запрос, все не сохранённые данные будт утеряны?",
|
||||
"save_unsaved_tab": "Вы хотите сохранить изменения в этой вкладке?",
|
||||
"close_unsaved_tab": "Вы уверены что хотите закрыть эту вкладку?",
|
||||
"close_unsaved_tabs": "ВЫ уверены что хотите закрыть все эти вкладки? Несохранённые данные {count} вкладок будут утеряны.",
|
||||
"sync": "Вы уверены, что хотите синхронизировать это рабочее пространство?"
|
||||
},
|
||||
"context_menu": {
|
||||
"set_environment_variable": "Назначить как переменную",
|
||||
"add_parameters": "Добавить в параметры",
|
||||
"open_request_in_new_tab": "Открыть в новой вкладке"
|
||||
},
|
||||
"count": {
|
||||
"header": "Заголовок {count}",
|
||||
"message": "Тело {count}",
|
||||
@@ -180,83 +192,102 @@
|
||||
"profile": "Войдите, чтобы просмотреть свой профиль",
|
||||
"protocols": "Протоколы пустые",
|
||||
"schema": "Подключиться к конечной точке GraphQL",
|
||||
"shortcodes": "Shortcodes are empty",
|
||||
"subscription": "Subscriptions are empty",
|
||||
"shortcodes": "Нет коротких ссылок",
|
||||
"subscription": "Нет подписок",
|
||||
"team_name": "Название команды пусто",
|
||||
"teams": "Команды пустые",
|
||||
"tests": "Для этого запроса нет тестов"
|
||||
},
|
||||
"environment": {
|
||||
"add_to_global": "Add to Global",
|
||||
"added": "Environment addition",
|
||||
"create_new": "Создать новую среду",
|
||||
"created": "Environment created",
|
||||
"deleted": "Environment deletion",
|
||||
"edit": "Редактировать среду",
|
||||
"invalid_name": "Укажите допустимое имя для среды",
|
||||
"my_environments": "My Environments",
|
||||
"nested_overflow": "nested environment variables are limited to 10 levels",
|
||||
"add_to_global": "Добавить в глобальное окружение",
|
||||
"added": "Окружение добавлено",
|
||||
"create_new": "Создать новое окружение",
|
||||
"created": "Окружение создано",
|
||||
"deleted": "Окружение удалено",
|
||||
"duplicated": "Окружение скопировано",
|
||||
"global": "Глобальное окружение",
|
||||
"empty_variables": "Нет переменных",
|
||||
"global_variables": "Глобальные переменные",
|
||||
"edit": "Редактировать окружение",
|
||||
"invalid_name": "Укажите допустимое имя для окружения",
|
||||
"list": "Переменные окружения",
|
||||
"my_environments": "Мои окружения",
|
||||
"name": "Название",
|
||||
"nested_overflow": "максимальный уровень вложения переменных окружения - 10",
|
||||
"new": "Новая среда",
|
||||
"no_environment": "Нет окружающей среды",
|
||||
"no_environment_description": "No environments were selected. Choose what to do with the following variables.",
|
||||
"no_active_environment": "Нет активных окружений",
|
||||
"no_environment": "Нет окружения",
|
||||
"no_environment_description": "Не выбрано окружение, выберите что делать с переменными.",
|
||||
"quick_peek": "Быстрый просмотр окружения",
|
||||
"replace_with_variable": "Заменить переменной",
|
||||
"scope": "Scope",
|
||||
"select": "Выберите среду",
|
||||
"team_environments": "Team Environments",
|
||||
"title": "Среды",
|
||||
"updated": "Environment updation",
|
||||
"set": "Выбрать окружение",
|
||||
"set_as_environment": "Установить как окружение",
|
||||
"team_environments": "Окружения команды",
|
||||
"title": "Окружения",
|
||||
"updated": "Окружение обновлено",
|
||||
"value": "Значение",
|
||||
"variable": "Переменная",
|
||||
"variable_list": "Список переменных"
|
||||
},
|
||||
"error": {
|
||||
"browser_support_sse": "Похоже, в этом браузере нет поддержки событий, отправленных сервером.",
|
||||
"check_console_details": "Подробности смотрите в журнале консоли.",
|
||||
"curl_invalid_format": "cURL неправильно отформатирован",
|
||||
"danger_zone": "Danger zone",
|
||||
"delete_account": "Your account is currently an owner in these teams:",
|
||||
"delete_account_description": "You must either remove yourself, transfer ownership, or delete these teams before you can delete your account.",
|
||||
"danger_zone": "Опасная зона",
|
||||
"delete_account": "Вы являетесь владельцем этой команды:",
|
||||
"delete_account_description": "Прежде чем удалить аккаунт вам необходимо либо назначить владельцом другого пользователя, либо удалить команды в которых вы являетесь владельцем.",
|
||||
"empty_req_name": "Пустое имя запроса",
|
||||
"f12_details": "(F12 для подробностей)",
|
||||
"gql_prettify_invalid_query": "Не удалось определить недопустимый запрос, устранить синтаксические ошибки запроса и повторить попытку.",
|
||||
"incomplete_config_urls": "Incomplete configuration URLs",
|
||||
"incorrect_email": "Incorrect email",
|
||||
"invalid_link": "Invalid link",
|
||||
"incomplete_config_urls": "Не заполнены URL конфигурации",
|
||||
"incorrect_email": "Не корректный Email",
|
||||
"invalid_link": "Не корректная ссылка",
|
||||
"invalid_link_description": "Ссылка, по которой вы перешли, - недействительна, либо срок ее действия истек.",
|
||||
"json_parsing_failed": "Invalid JSON",
|
||||
"json_parsing_failed": "Не корректный JSON",
|
||||
"json_prettify_invalid_body": "Не удалось определить недопустимое тело, устранить синтаксические ошибки json и повторить попытку.",
|
||||
"network_error": "Похоже, возникла проблема с соединением. Попробуйте еще раз.",
|
||||
"network_fail": "Не удалось отправить запрос",
|
||||
"no_duration": "Без продолжительности",
|
||||
"no_results_found": "No matches found",
|
||||
"page_not_found": "This page could not be found",
|
||||
"no_results_found": "Совпадения не найдены",
|
||||
"page_not_found": "Эта страница не найдена",
|
||||
"proxy_error": "Ошибка прокси",
|
||||
"script_fail": "Не удалось выполнить сценарий предварительного запроса",
|
||||
"something_went_wrong": "Что-то пошло не так",
|
||||
"test_script_fail": "Could not execute post-request script"
|
||||
"test_script_fail": "Не удалось выполнить тестирование запроса"
|
||||
},
|
||||
"export": {
|
||||
"as_json": "Экспорт как JSON",
|
||||
"create_secret_gist": "Создать секретный Gist",
|
||||
"gist_created": "Gist создан",
|
||||
"require_github": "Войдите через GitHub, чтобы создать секретную суть",
|
||||
"title": "Export"
|
||||
"title": "Экспорт"
|
||||
},
|
||||
"filter": {
|
||||
"all": "All",
|
||||
"none": "None",
|
||||
"starred": "Starred"
|
||||
"all": "Все",
|
||||
"none": "Не указано",
|
||||
"starred": "Отмечено"
|
||||
},
|
||||
"folder": {
|
||||
"created": "Папка создана",
|
||||
"edit": "Редактировать папку",
|
||||
"invalid_name": "Укажите имя для папки",
|
||||
"name_length_insufficient": "Folder name should be at least 3 characters long",
|
||||
"name_length_insufficient": "Имя папки должно содержать 3 или более символов",
|
||||
"new": "Новая папка",
|
||||
"renamed": "Папка переименована"
|
||||
},
|
||||
"graphql": {
|
||||
"mutations": "Мутации",
|
||||
"schema": "Схема",
|
||||
"subscriptions": "Подписки"
|
||||
"subscriptions": "Подписки",
|
||||
"switch_connection": "Изменить соединение",
|
||||
"connection_switch_url": "Вы присоединились к GraphQL, URL соединения",
|
||||
"connection_switch_new_url": "Смена вкладки разорвёт текущее GraphQL соединение. Новый URL соединения будет",
|
||||
"connection_switch_confirm": "Вы желаете соединиться с последним GraphQL сервером?"
|
||||
},
|
||||
"group": {
|
||||
"time": "Time",
|
||||
"time": "Время",
|
||||
"url": "URL"
|
||||
},
|
||||
"header": {
|
||||
@@ -273,11 +304,11 @@
|
||||
"post_request_tests": "Сценарии тестирования написаны на JavaScript и запускаются после получения ответа.",
|
||||
"pre_request_script": "Скрипты предварительного запроса написаны на JavaScript и запускаются перед отправкой запроса.",
|
||||
"script_fail": "Похоже, в скрипте предварительного запроса есть сбой. Проверьте ошибку ниже и исправьте скрипт соответствующим образом.",
|
||||
"test_script_fail": "There seems to be an error with test script. Please fix the errors and run tests again",
|
||||
"test_script_fail": "Похоже, что скрипт тестирования содержит ошибку. Пожалуйста исправьте её и попробуйте снова",
|
||||
"tests": "Напишите тестовый сценарий для автоматизации отладки."
|
||||
},
|
||||
"hide": {
|
||||
"collection": "Collapse Collection Panel",
|
||||
"collection": "Свернуть панель соединения",
|
||||
"more": "Скрыть больше",
|
||||
"preview": "Скрыть предварительный просмотр",
|
||||
"sidebar": "Скрыть боковую панель"
|
||||
@@ -287,61 +318,85 @@
|
||||
"curl": "Импортировать cURL",
|
||||
"failed": "Ошибка импорта",
|
||||
"from_gist": "Импорт из Gist",
|
||||
"from_gist_description": "Import from Gist URL",
|
||||
"from_insomnia": "Import from Insomnia",
|
||||
"from_insomnia_description": "Import from Insomnia collection",
|
||||
"from_json": "Import from Hoppscotch",
|
||||
"from_json_description": "Import from Hoppscotch collection file",
|
||||
"from_gist_description": "Импортировать через Gist URL",
|
||||
"from_insomnia": "Импортировать с Insomnia",
|
||||
"from_insomnia_description": "Импортировать из коллекции Insomnia",
|
||||
"from_json": "Импортировать из Hoppscotch",
|
||||
"from_json_description": "Импортировать из файла коллекции Hoppscotch",
|
||||
"from_my_collections": "Импортировать из моих коллекций",
|
||||
"from_my_collections_description": "Import from My Collections file",
|
||||
"from_openapi": "Import from OpenAPI",
|
||||
"from_openapi_description": "Import from OpenAPI specification file (YML/JSON)",
|
||||
"from_postman": "Import from Postman",
|
||||
"from_postman_description": "Import from Postman collection",
|
||||
"from_url": "Import from URL",
|
||||
"from_my_collections_description": "Импортировать коллекции из моего файла",
|
||||
"from_openapi": "Импортировать из OpenAPI",
|
||||
"from_openapi_description": "Импортировать из OpenAPI файла описания API (YML/JSON)",
|
||||
"from_postman": "Импортировать из Postman",
|
||||
"from_postman_description": "Импортировать из коллекции Postman",
|
||||
"from_url": "Импортировать из URL",
|
||||
"gist_url": "Введите URL-адрес Gist",
|
||||
"import_from_url_invalid_fetch": "Couldn't get data from the url",
|
||||
"import_from_url_invalid_file_format": "Error while importing collections",
|
||||
"import_from_url_invalid_type": "Unsupported type. accepted values are 'hoppscotch', 'openapi', 'postman', 'insomnia'",
|
||||
"import_from_url_success": "Collections Imported",
|
||||
"json_description": "Import collections from a Hoppscotch Collections JSON file",
|
||||
"import_from_url_invalid_fetch": "Не удалить получить данные по этому URL",
|
||||
"import_from_url_invalid_file_format": "Ошибка при импорте коллекций",
|
||||
"import_from_url_invalid_type": "Неподдерживаемый тип. Поддерживаемые типы: 'hoppscotch', 'openapi', 'postman', 'insomnia'",
|
||||
"import_from_url_success": "Коллекция импортирована",
|
||||
"json_description": "Импортировать из коллекции Hoppscotch",
|
||||
"title": "Импортировать"
|
||||
},
|
||||
"inspections": {
|
||||
"title": "Инспектор",
|
||||
"description": "Помогает обноружить возможные проблемы",
|
||||
"environment": {
|
||||
"add_environment": "Добавить в окружение",
|
||||
"not_found": "Переменная окружения “{environment}” не найдена."
|
||||
},
|
||||
"header": {
|
||||
"cookie": "Браузерная версия Hoppscotch не может использовать Cookie Header. Пока мы работаем над созданием десктоп версии Hoppscotch, пожалуйста используйте Authorization Header."
|
||||
},
|
||||
"response": {
|
||||
"401_error": "Пожалуйста проверьте ваши параметры авторизации",
|
||||
"404_error": "Пожалуйста проверьте URL и Метод вашего запроса",
|
||||
"network_error": "Пожалуйста проверьте соединение",
|
||||
"cors_error": "Пожалуйста проверьте вашу Cross-Origin Resource Sharing настройку сервера.",
|
||||
"default_error": "Проверьте ваш запрос."
|
||||
},
|
||||
"url": {
|
||||
"extension_not_installed": "Расширение не установлено",
|
||||
"extention_not_enabled": "Расширение не включено",
|
||||
"extention_enable_action": "Включить расширение браузера",
|
||||
"extension_unknown_origin": "Убедитесь что вы добавили адрес сервера в Hoppscotch расширение."
|
||||
}
|
||||
},
|
||||
"layout": {
|
||||
"collapse_collection": "Collapse or Expand Collections",
|
||||
"collapse_sidebar": "Collapse or Expand the sidebar",
|
||||
"column": "Вертикальное оформление",
|
||||
"name": "Layout",
|
||||
"row": "Горизонтальное оформление",
|
||||
"collapse_collection": "Свернуть или развернуть коллекции",
|
||||
"collapse_sidebar": "Свернуть или развернуть боковую панель",
|
||||
"column": "Вертикальная развёртка",
|
||||
"name": "Развёртка",
|
||||
"row": "Горизонтальная развертка",
|
||||
"zen_mode": "Спокойный режим"
|
||||
},
|
||||
"modal": {
|
||||
"close_unsaved_tab": "You have unsaved changes",
|
||||
"close_unsaved_tab": "У вас есть не сохранённые изменения",
|
||||
"collections": "Коллекции",
|
||||
"confirm": "Подтверждать",
|
||||
"edit_request": "Изменить запрос",
|
||||
"import_export": "Импорт Экспорт"
|
||||
},
|
||||
"mqtt": {
|
||||
"already_subscribed": "You are already subscribed to this topic.",
|
||||
"clean_session": "Clean Session",
|
||||
"clear_input": "Clear input",
|
||||
"clear_input_on_send": "Clear input on send",
|
||||
"already_subscribed": "Вы уже подписаны на этот топик",
|
||||
"clean_session": "Очистить сессию",
|
||||
"clear_input": "Очистить ввод",
|
||||
"clear_input_on_send": "Очистить ввод перед отправкой",
|
||||
"client_id": "Client ID",
|
||||
"color": "Pick a color",
|
||||
"color": "Выбрать цвет",
|
||||
"communication": "Коммуникация",
|
||||
"connection_config": "Connection Config",
|
||||
"connection_not_authorized": "This MQTT connection does not use any authentication.",
|
||||
"invalid_topic": "Please provide a topic for the subscription",
|
||||
"keep_alive": "Keep Alive",
|
||||
"connection_config": "Конфигурация соединения",
|
||||
"connection_not_authorized": "Это соединение MQTT не использует какую-либо авторизацию.",
|
||||
"invalid_topic": "Пожалуйста выберите topic для подписки",
|
||||
"keep_alive": "Поддерживать соединение",
|
||||
"log": "Лог",
|
||||
"lw_message": "Last-Will Message",
|
||||
"lw_qos": "Last-Will QoS",
|
||||
"lw_retain": "Last-Will Retain",
|
||||
"lw_topic": "Last-Will Topic",
|
||||
"message": "Сообщение",
|
||||
"new": "New Subscription",
|
||||
"not_connected": "Please start a MQTT connection first.",
|
||||
"new": "Новая подписка",
|
||||
"not_connected": "Пожалуйста, сначала запустите MQTT соединение.",
|
||||
"publish": "Публиковать",
|
||||
"qos": "QoS",
|
||||
"ssl": "SSL",
|
||||
@@ -355,7 +410,7 @@
|
||||
"navigation": {
|
||||
"doc": "Документы",
|
||||
"graphql": "GraphQL",
|
||||
"profile": "Profile",
|
||||
"profile": "Профиль",
|
||||
"realtime": "В реальном времени",
|
||||
"rest": "REST",
|
||||
"settings": "Настройки"
|
||||
@@ -363,12 +418,12 @@
|
||||
"preRequest": {
|
||||
"javascript_code": "Код JavaScript",
|
||||
"learn": "Читать документацию",
|
||||
"script": "Сценарий предварительного запроса",
|
||||
"snippets": "Фрагменты"
|
||||
"script": "Предворительный скрипт запроса",
|
||||
"snippets": "Готовый код"
|
||||
},
|
||||
"profile": {
|
||||
"app_settings": "Настройки приложения",
|
||||
"default_hopp_displayname": "Unnamed User",
|
||||
"default_hopp_displayname": "Безымянный",
|
||||
"editor": "Редактор",
|
||||
"editor_description": "Редакторы могут добавлять, редактировать, а так же удалять запросы.",
|
||||
"email_verification_mail": "На вашу электронную почту отправлено письмо для подтверждения. Перейдите по ссылке из письма, чтобы подтвердить свой электронный адрес.",
|
||||
@@ -391,13 +446,13 @@
|
||||
"choose_language": "Выберите язык",
|
||||
"content_type": "Тип содержимого",
|
||||
"content_type_titles": {
|
||||
"others": "Others",
|
||||
"structured": "Structured",
|
||||
"text": "Text"
|
||||
"others": "Другие",
|
||||
"structured": "Структурированный",
|
||||
"text": "Текст"
|
||||
},
|
||||
"copy_link": "Копировать ссылку",
|
||||
"different_collection": "Cannot reorder requests from different collections",
|
||||
"duplicated": "Request duplicated",
|
||||
"different_collection": "Нельзя изменять порядок запросов из разных коллекций",
|
||||
"duplicated": "Запрос скопирован",
|
||||
"duration": "Продолжительность",
|
||||
"enter_curl": "Введите cURL",
|
||||
"generate_code": "Сгенерировать код",
|
||||
@@ -405,13 +460,13 @@
|
||||
"header_list": "Список заголовков",
|
||||
"invalid_name": "Укажите имя для запроса",
|
||||
"method": "Методика",
|
||||
"moved": "Request moved",
|
||||
"moved": "Запрос перемещён",
|
||||
"name": "Имя запроса",
|
||||
"new": "New Request",
|
||||
"order_changed": "Request Order Updated",
|
||||
"override": "Override",
|
||||
"override_help": "Set <kbd>Content-Type</kbd> in Headers",
|
||||
"overriden": "Overridden",
|
||||
"new": "Новый запрос",
|
||||
"order_changed": "Порядок запроса изменён",
|
||||
"override": "Переопределить",
|
||||
"override_help": "Установить <kbd>Content-Type</kbd> в Заголовках",
|
||||
"overriden": "Переопределено",
|
||||
"parameter_list": "Параметры запроса",
|
||||
"parameters": "Параметры",
|
||||
"path": "Путь",
|
||||
@@ -424,17 +479,17 @@
|
||||
"save_as": "Сохранить как",
|
||||
"saved": "Запрос сохранен",
|
||||
"share": "Делиться",
|
||||
"share_description": "Share Hoppscotch with your friends",
|
||||
"share_description": "Поделиться Hoppscotch с друзьями",
|
||||
"title": "Запрос",
|
||||
"type": "Тип запроса",
|
||||
"url": "URL",
|
||||
"variables": "Переменные",
|
||||
"view_my_links": "View my links"
|
||||
"view_my_links": "Посмотреть мои ссылки"
|
||||
},
|
||||
"response": {
|
||||
"audio": "Audio",
|
||||
"audio": "Аудио",
|
||||
"body": "Тело ответа",
|
||||
"filter_response_body": "Filter JSON response body (uses JSONPath syntax)",
|
||||
"filter_response_body": "Отфильтровать ответ в формате JSON (используется синтаксис JSONPath)",
|
||||
"headers": "Заголовки",
|
||||
"html": "HTML",
|
||||
"image": "Изображение",
|
||||
@@ -446,14 +501,14 @@
|
||||
"status": "Статус",
|
||||
"time": "Время",
|
||||
"title": "Ответ",
|
||||
"video": "Video",
|
||||
"video": "Видео",
|
||||
"waiting_for_connection": "Ожидание соединения",
|
||||
"xml": "XML"
|
||||
},
|
||||
"settings": {
|
||||
"accent_color": "Основной цвет",
|
||||
"account": "Счет",
|
||||
"account_deleted": "Your account has been deleted",
|
||||
"account_deleted": "Ваш аккаунт был удалён",
|
||||
"account_description": "Настройте параметры своей учетной записи.",
|
||||
"account_email_description": "Ваш основной адрес электронной почты.",
|
||||
"account_name_description": "Это ваше отображаемое имя.",
|
||||
@@ -462,8 +517,8 @@
|
||||
"change_font_size": "Изменить размер шрифта",
|
||||
"choose_language": "Выберите язык",
|
||||
"dark_mode": "Темный",
|
||||
"delete_account": "Delete account",
|
||||
"delete_account_description": "Once you delete your account, all your data will be permanently deleted. This action cannot be undone.",
|
||||
"delete_account": "Удалить аккаунт",
|
||||
"delete_account_description": "Удаление аккаунта нельзя отменить",
|
||||
"expand_navigation": "Раскрыть панель навигации",
|
||||
"experiments": "Эксперименты",
|
||||
"experiments_notice": "Это набор экспериментов, над которыми мы работаем, которые могут оказаться полезными, интересными, и тем, и другим, или ни тем, ни другим. Они не окончательные и могут быть нестабильными, поэтому, если произойдет что-то слишком странное, не паникуйте. Просто выключи эту чертову штуку. Шутки в сторону,",
|
||||
@@ -490,8 +545,8 @@
|
||||
"proxy_use_toggle": "Используйте промежуточное ПО прокси для отправки запросов",
|
||||
"read_the": "Прочтите",
|
||||
"reset_default": "Восстановление значений по умолчанию",
|
||||
"short_codes": "Short codes",
|
||||
"short_codes_description": "Short codes which were created by you.",
|
||||
"short_codes": "Короткие ссылки",
|
||||
"short_codes_description": "Короткие ссылки, созданные вами",
|
||||
"sidebar_on_left": "Панель слева",
|
||||
"sync": "Синхронизировать",
|
||||
"sync_collections": "Коллекции",
|
||||
@@ -505,16 +560,16 @@
|
||||
"theme_description": "Настройте тему своего приложения.",
|
||||
"use_experimental_url_bar": "Использовать экспериментальную строку URL с выделением среды",
|
||||
"user": "Пользователь",
|
||||
"verified_email": "Verified email",
|
||||
"verify_email": "Подтвердить почту"
|
||||
"verified_email": "Проверенный Email",
|
||||
"verify_email": "Подтвердить Email"
|
||||
},
|
||||
"shortcodes": {
|
||||
"actions": "Actions",
|
||||
"created_on": "Created on",
|
||||
"deleted": "Shortcode deleted",
|
||||
"method": "Method",
|
||||
"not_found": "Shortcode not found",
|
||||
"short_code": "Short code",
|
||||
"actions": "Действия",
|
||||
"created_on": "Создано",
|
||||
"deleted": "Удалёна",
|
||||
"method": "Метод",
|
||||
"not_found": "Короткая ссылка не найдена",
|
||||
"short_code": "Короткая ссылка",
|
||||
"url": "URL"
|
||||
},
|
||||
"shortcut": {
|
||||
@@ -525,6 +580,10 @@
|
||||
"show_all": "Горячие клавиши",
|
||||
"title": "Общий"
|
||||
},
|
||||
"others": {
|
||||
"title": "Другие",
|
||||
"prettify": "Прекрасные редакторы"
|
||||
},
|
||||
"miscellaneous": {
|
||||
"invite": "Пригласите людей в Hoppscotch",
|
||||
"title": "Разное"
|
||||
@@ -545,6 +604,9 @@
|
||||
"delete_method": "Выберите метод DELETE",
|
||||
"get_method": "Выберите метод GET",
|
||||
"head_method": "Выберите метод HEAD",
|
||||
"rename": "Переименовать запрос",
|
||||
"import_curl": "Импорт из cURL",
|
||||
"show_code": "Сгенерировать готовый код",
|
||||
"method": "Методика",
|
||||
"next_method": "Выберите следующий метод",
|
||||
"post_method": "Выберите метод POST",
|
||||
@@ -553,35 +615,120 @@
|
||||
"reset_request": "Сбросить запрос",
|
||||
"save_to_collections": "Сохранить в коллекции",
|
||||
"send_request": "Послать запрос",
|
||||
"save_request": "Сохарнить запрос",
|
||||
"title": "Запрос"
|
||||
},
|
||||
"response": {
|
||||
"copy": "Copy response to clipboard",
|
||||
"download": "Download response as file",
|
||||
"title": "Response"
|
||||
"copy": "Копировать запрос в буфер обмена",
|
||||
"download": "Скачать запрос как файл",
|
||||
"title": "Запрос"
|
||||
},
|
||||
"theme": {
|
||||
"black": "Switch theme to black mode",
|
||||
"dark": "Switch theme to dark mode",
|
||||
"light": "Switch theme to light mode",
|
||||
"system": "Switch theme to system mode",
|
||||
"title": "Theme"
|
||||
"black": "Черный режим",
|
||||
"dark": "Тёмный режим",
|
||||
"light": "Светлый режим",
|
||||
"system": "Определяется системой",
|
||||
"title": "Тема"
|
||||
}
|
||||
},
|
||||
"show": {
|
||||
"code": "Показать код",
|
||||
"collection": "Expand Collection Panel",
|
||||
"collection": "Развернуть панель коллекций",
|
||||
"more": "Показать больше",
|
||||
"sidebar": "Показать боковую панель"
|
||||
},
|
||||
"socketio": {
|
||||
"communication": "Коммуникация",
|
||||
"connection_not_authorized": "This SocketIO connection does not use any authentication.",
|
||||
"connection_not_authorized": "Это SocketIO соединение не использует какую-либо авторизацию.",
|
||||
"event_name": "Название события",
|
||||
"events": "События",
|
||||
"log": "Лог",
|
||||
"url": "URL"
|
||||
},
|
||||
"spotlight": {
|
||||
"general": {
|
||||
"help_menu": "Помощь и поддержка",
|
||||
"chat": "Чат с поддержкой",
|
||||
"open_docs": "Прочитать документацию",
|
||||
"open_keybindings": "Горячие клавиши",
|
||||
"open_github": "Открыть GitHub репозиторий",
|
||||
"social": "Соц. сети",
|
||||
"title": "Основное"
|
||||
},
|
||||
"miscellaneous": {
|
||||
"invite": "Пригласите друзей в Hoppscotch",
|
||||
"title": "Разное"
|
||||
},
|
||||
"request": {
|
||||
"switch_to": "Перейти к",
|
||||
"select_method": "Выбрать метод",
|
||||
"save_as_new": "Сохранить как новый запрос",
|
||||
"tab_parameters": "Параметры",
|
||||
"tab_body": "Тело",
|
||||
"tab_headers": "Заголовки",
|
||||
"tab_authorization": "Авторизация",
|
||||
"tab_pre_request_script": "Пред-скрипт",
|
||||
"tab_tests": "Тесты",
|
||||
"tab_query": "Запрос",
|
||||
"tab_variables": "Переменные"
|
||||
},
|
||||
"graphql": {
|
||||
"connect": "Соединиться",
|
||||
"disconnect": "Разъединить"
|
||||
},
|
||||
"response": {
|
||||
"copy": "Копировать ответ",
|
||||
"download": "Скачать ответ",
|
||||
"title": "Ответ"
|
||||
},
|
||||
"environments": {
|
||||
"new": "Создать новое окружение",
|
||||
"new_variable": "Создать новую переменную в окружении",
|
||||
"edit": "Изменить текущее окружение",
|
||||
"delete": "Удалить текущее окружение",
|
||||
"duplicate": "Скопировать текущее окружение",
|
||||
"edit_global": "Изменить глобальное окружение",
|
||||
"duplicate_global": "Скопировать глобальное окружение",
|
||||
"title": "Окружения"
|
||||
},
|
||||
"workspace": {
|
||||
"new": "Создать новую команду",
|
||||
"edit": "Изменить текущую команду",
|
||||
"delete": "Удалить текущую команду",
|
||||
"invite": "Пригласить людей в команду",
|
||||
"switch_to_personal": "Переключиться на личное пространство",
|
||||
"title": "Команды"
|
||||
},
|
||||
"tab": {
|
||||
"duplicate": "Скопировать вкладку",
|
||||
"close_current": "Закрыть вкладку",
|
||||
"close_others": "Закрыть все кроме этой",
|
||||
"new_tab": "Открыть в новой вкладке",
|
||||
"title": "Вкладки"
|
||||
},
|
||||
"section": {
|
||||
"user": "Пользователь",
|
||||
"theme": "Тема",
|
||||
"interface": "Интерфейс",
|
||||
"interceptor": "Перехватчик"
|
||||
},
|
||||
"change_language": "Изменить язык",
|
||||
"settings": {
|
||||
"theme": {
|
||||
"black": "Чёрная",
|
||||
"dark": "Тёмная",
|
||||
"light": "Светлая",
|
||||
"system": "Определяется системой"
|
||||
},
|
||||
"font": {
|
||||
"size_sm": "Маленький",
|
||||
"size_md": "Средний",
|
||||
"size_lg": "Большой"
|
||||
},
|
||||
"change_interceptor": "Изменить перехватчик",
|
||||
"change_language": "Изменить язык"
|
||||
}
|
||||
},
|
||||
"sse": {
|
||||
"event_type": "Тип события",
|
||||
"log": "Лог",
|
||||
@@ -589,14 +736,14 @@
|
||||
},
|
||||
"state": {
|
||||
"bulk_mode": "Множественное редактирование",
|
||||
"bulk_mode_placeholder": "Entries are separated by newline\nKeys and values are separated by :\nPrepend # to any row you want to add but keep disabled",
|
||||
"bulk_mode_placeholder": "Каждый параметр должен начинаться с новой строки\nКлючи и значения разедляются двоеточием\nИспользуйте # для комментария",
|
||||
"cleared": "Очищено",
|
||||
"connected": "Связаны",
|
||||
"connected_to": "Подключено к {name}",
|
||||
"connecting_to": "Подключение к {name} ...",
|
||||
"connection_error": "Failed to connect",
|
||||
"connection_failed": "Connection failed",
|
||||
"connection_lost": "Connection lost",
|
||||
"connection_error": "Ошибка подключения",
|
||||
"connection_failed": "Не удалось установить соединение",
|
||||
"connection_lost": "Соединение утеряно",
|
||||
"copied_to_clipboard": "Скопировано в буфер обмена",
|
||||
"deleted": "Удалено",
|
||||
"deprecated": "УСТАРЕЛО",
|
||||
@@ -611,17 +758,17 @@
|
||||
"history_deleted": "История удалена",
|
||||
"linewrap": "Обернуть линии",
|
||||
"loading": "Загрузка...",
|
||||
"message_received": "Message: {message} arrived on topic: {topic}",
|
||||
"mqtt_subscription_failed": "Something went wrong while subscribing to topic: {topic}",
|
||||
"message_received": "Сообщение: {message} получено по топику: {topic}",
|
||||
"mqtt_subscription_failed": "Что-то пошло не так, при попытке подписаться на топик: {topic}",
|
||||
"none": "Никто",
|
||||
"nothing_found": "Ничего не найдено для",
|
||||
"published_error": "Something went wrong while publishing msg: {topic} to topic: {message}",
|
||||
"published_message": "Published message: {message} to topic: {topic}",
|
||||
"reconnection_error": "Failed to reconnect",
|
||||
"subscribed_failed": "Failed to subscribe to topic: {topic}",
|
||||
"subscribed_success": "Successfully subscribed to topic: {topic}",
|
||||
"unsubscribed_failed": "Failed to unsubscribe from topic: {topic}",
|
||||
"unsubscribed_success": "Successfully unsubscribed from topic: {topic}",
|
||||
"published_error": "Что-то пошло не так при попытке опубликовать сообщение в топик {topic}: {message}",
|
||||
"published_message": "Опубликовано сообщение: {message} в топик: {topic}",
|
||||
"reconnection_error": "Не удалось переподключиться",
|
||||
"subscribed_failed": "Не удалось подписаться на топик: {topic}",
|
||||
"subscribed_success": "Успешно подписался на топик: {topic}",
|
||||
"unsubscribed_failed": "Не удалось отписаться от топика: {topic}",
|
||||
"unsubscribed_success": "Успешно отписался от топика: {topic}",
|
||||
"waiting_send_request": "Ожидание отправки запроса"
|
||||
},
|
||||
"support": {
|
||||
@@ -630,7 +777,7 @@
|
||||
"community": "Задавайте вопросы и помогайте другим",
|
||||
"documentation": "Узнать больше о Hoppscotch",
|
||||
"forum": "Задавайте вопросы и получайте ответы",
|
||||
"github": "Follow us on Github",
|
||||
"github": "Подпишитесь на нас на Github",
|
||||
"shortcuts": "Просматривайте приложение быстрее",
|
||||
"team": "Свяжитесь с командой",
|
||||
"title": "Служба поддержки",
|
||||
@@ -641,15 +788,15 @@
|
||||
"body": "Тело",
|
||||
"collections": "Коллекции",
|
||||
"documentation": "Документация",
|
||||
"environments": "Environments",
|
||||
"environments": "Окружения",
|
||||
"headers": "Заголовки",
|
||||
"history": "История",
|
||||
"mqtt": "MQTT",
|
||||
"parameters": "Параметры",
|
||||
"pre_request_script": "Скрипт предварительного запроса",
|
||||
"pre_request_script": "Пред-скрипт",
|
||||
"queries": "Запросы",
|
||||
"query": "Запрос",
|
||||
"schema": "Schema",
|
||||
"schema": "Схема",
|
||||
"socketio": "Socket.IO",
|
||||
"sse": "SSE",
|
||||
"tests": "Тесты",
|
||||
@@ -666,7 +813,7 @@
|
||||
"email_do_not_match": "Электронная почта, которой Вы воспользовались не соответсвует указанной в данных Вашей учетной записи.",
|
||||
"exit": "Выйти из команды",
|
||||
"exit_disabled": "Только владелец не может выйти из команды",
|
||||
"invalid_coll_id": "Invalid collection ID",
|
||||
"invalid_coll_id": "Не верный идентификатор коллекции",
|
||||
"invalid_email_format": "Формат электронной почты недействителен",
|
||||
"invalid_id": "Некорректный ID команды. Свяжитесь с руководителем команды.",
|
||||
"invalid_invite_link": "Ссылка недействительна",
|
||||
@@ -690,7 +837,7 @@
|
||||
"member_removed": "Пользователь удален",
|
||||
"member_role_updated": "Роли пользователей обновлены",
|
||||
"members": "Участники",
|
||||
"more_members": "+{count} more",
|
||||
"more_members": "+{count}",
|
||||
"name_length_insufficient": "Название команды должно быть не менее 6 символов.",
|
||||
"name_updated": "Название команды обновлено",
|
||||
"new": "Новая команда",
|
||||
@@ -698,13 +845,13 @@
|
||||
"new_name": "Моя новая команда",
|
||||
"no_access": "У вас нет прав на редактирование этих коллекций",
|
||||
"no_invite_found": "Такое приглашение мы не смогли найти. Свяжитесь с руководителем команды.",
|
||||
"no_request_found": "Request not found.",
|
||||
"not_found": "Team not found. Contact your team owner.",
|
||||
"no_request_found": "Запрос не найден",
|
||||
"not_found": "Команда не найдена, свяжитесь с владельцем команды",
|
||||
"not_valid_viewer": "У Вас нет прав просматривать это. Свяжитесь с руководителем команды.",
|
||||
"parent_coll_move": "Cannot move collection to a child collection",
|
||||
"parent_coll_move": "Не удалось переместить коллекцию в дочернюю",
|
||||
"pending_invites": "Ожидающие приглашения",
|
||||
"permissions": "Разрешения",
|
||||
"same_target_destination": "Same target and destination",
|
||||
"same_target_destination": "Таже цель и конечная точка",
|
||||
"saved": "Команда сохранена",
|
||||
"select_a_team": "Выбрать команду",
|
||||
"title": "Команды",
|
||||
@@ -712,9 +859,9 @@
|
||||
"we_sent_invite_link_description": "Попросите тех, кого Вы пригласили, проверить их почтовые ящики. Им нужно перейди по ссылке, чтобы подтвердить вступление в эту команду."
|
||||
},
|
||||
"team_environment": {
|
||||
"deleted": "Environment Deleted",
|
||||
"duplicate": "Environment Duplicated",
|
||||
"not_found": "Environment not found."
|
||||
"deleted": "Окружение удалено",
|
||||
"duplicate": "Окружение скопировано",
|
||||
"not_found": "Окружение не найдено"
|
||||
},
|
||||
"test": {
|
||||
"failed": "Тест не пройден",
|
||||
@@ -734,9 +881,9 @@
|
||||
"url": "URL"
|
||||
},
|
||||
"workspace": {
|
||||
"change": "Change workspace",
|
||||
"personal": "My Workspace",
|
||||
"team": "Team Workspace",
|
||||
"title": "Workspaces"
|
||||
"change": "Изменить пространство",
|
||||
"personal": "Моё пространство",
|
||||
"team": "Пространство команды",
|
||||
"title": "Рабочие пространства"
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@hoppscotch/common",
|
||||
"private": true,
|
||||
"version": "2023.4.8",
|
||||
"version": "2023.8.0",
|
||||
"scripts": {
|
||||
"dev": "pnpm exec npm-run-all -p -l dev:*",
|
||||
"test": "vitest --run",
|
||||
@@ -63,7 +63,7 @@
|
||||
"graphql": "^16.8.0",
|
||||
"graphql-language-service-interface": "^2.9.1",
|
||||
"graphql-tag": "^2.12.6",
|
||||
"httpsnippet": "^2.0.0",
|
||||
"httpsnippet": "^3.0.1",
|
||||
"insomnia-importers": "^3.6.0",
|
||||
"io-ts": "^2.2.20",
|
||||
"js-yaml": "^4.1.0",
|
||||
@@ -117,6 +117,7 @@
|
||||
"@intlify/vite-plugin-vue-i18n": "^7.0.0",
|
||||
"@relmify/jest-fp-ts": "^2.1.1",
|
||||
"@rushstack/eslint-patch": "^1.3.3",
|
||||
"@types/har-format": "^1.2.12",
|
||||
"@types/js-yaml": "^4.0.5",
|
||||
"@types/lodash-es": "^4.17.8",
|
||||
"@types/lossless-json": "^1.0.1",
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 666 KiB After Width: | Height: | Size: 926 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 358 KiB After Width: | Height: | Size: 510 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 382 KiB After Width: | Height: | Size: 535 KiB |
@@ -18,6 +18,7 @@ import { HOPP_MODULES } from "@modules/."
|
||||
import { isLoadingInitialRoute } from "@modules/router"
|
||||
import { useI18n } from "@composables/i18n"
|
||||
import { APP_IS_IN_DEV_MODE } from "@helpers/dev"
|
||||
import { platform } from "./platform"
|
||||
|
||||
const t = useI18n()
|
||||
|
||||
@@ -45,4 +46,5 @@ if (APP_IS_IN_DEV_MODE) {
|
||||
|
||||
// Run module root component setup code
|
||||
HOPP_MODULES.forEach((mod) => mod.onRootSetup?.())
|
||||
platform.addedHoppModules?.forEach((mod) => mod.onRootSetup?.())
|
||||
</script>
|
||||
|
||||
@@ -17,7 +17,6 @@ import { pipe } from "fp-ts/function"
|
||||
import * as TE from "fp-ts/TaskEither"
|
||||
import { deleteTeam as backendDeleteTeam } from "~/helpers/backend/mutations/Team"
|
||||
import { defineActionHandler, invokeAction } from "~/helpers/actions"
|
||||
import { showChat } from "~/modules/crisp"
|
||||
import { useToast } from "~/composables/toast"
|
||||
import { useI18n } from "~/composables/i18n"
|
||||
|
||||
@@ -62,10 +61,6 @@ defineActionHandler("modals.login.toggle", () => {
|
||||
showLogin.value = !showLogin.value
|
||||
})
|
||||
|
||||
defineActionHandler("flyouts.chat.open", () => {
|
||||
showChat()
|
||||
})
|
||||
|
||||
defineActionHandler("modals.team.delete", ({ teamId }) => {
|
||||
teamID.value = teamId
|
||||
confirmRemove.value = true
|
||||
|
||||
@@ -10,18 +10,6 @@
|
||||
:class="{ '-rotate-180': !EXPAND_NAVIGATION }"
|
||||
@click="EXPAND_NAVIGATION = !EXPAND_NAVIGATION"
|
||||
/>
|
||||
<HoppButtonSecondary
|
||||
v-tippy="{ theme: 'tooltip' }"
|
||||
:title="`${ZEN_MODE ? t('action.turn_off') : t('action.turn_on')} ${t(
|
||||
'layout.zen_mode'
|
||||
)}`"
|
||||
:icon="ZEN_MODE ? IconMinimize : IconMaximize"
|
||||
:class="{
|
||||
'!text-accent !focus-visible:text-accentDark !hover:text-accentDark':
|
||||
ZEN_MODE,
|
||||
}"
|
||||
@click="ZEN_MODE = !ZEN_MODE"
|
||||
/>
|
||||
<tippy interactive trigger="click" theme="popover">
|
||||
<HoppButtonSecondary
|
||||
v-tippy="{ theme: 'tooltip' }"
|
||||
@@ -76,6 +64,7 @@
|
||||
}
|
||||
"
|
||||
/>
|
||||
<!--
|
||||
<HoppSmartItem
|
||||
ref="chat"
|
||||
:icon="IconMessageCircle"
|
||||
@@ -88,20 +77,34 @@
|
||||
}
|
||||
"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
:icon="IconGift"
|
||||
:label="`${t('app.whats_new')}`"
|
||||
to="https://docs.hoppscotch.io/documentation/changelog"
|
||||
blank
|
||||
@click="hide()"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
:icon="IconActivity"
|
||||
:label="t('app.status')"
|
||||
to="https://status.hoppscotch.io"
|
||||
blank
|
||||
@click="hide()"
|
||||
/>
|
||||
-->
|
||||
<template
|
||||
v-for="footerItem in platform.ui?.additionalFooterMenuItems"
|
||||
:key="footerItem.id"
|
||||
>
|
||||
<template v-if="footerItem.action.type === 'link'">
|
||||
<HoppSmartItem
|
||||
:icon="footerItem.icon"
|
||||
:label="footerItem.text(t)"
|
||||
:to="footerItem.action.href"
|
||||
blank
|
||||
@click="hide()"
|
||||
/>
|
||||
</template>
|
||||
<HoppSmartItem
|
||||
v-else
|
||||
:icon="footerItem.icon"
|
||||
:label="footerItem.text(t)"
|
||||
blank
|
||||
@click="
|
||||
() => {
|
||||
// @ts-expect-error TypeScript not understanding the type
|
||||
footerItem.action.do()
|
||||
hide()
|
||||
}
|
||||
"
|
||||
/>
|
||||
</template>
|
||||
<hr />
|
||||
<HoppSmartItem
|
||||
:icon="IconGithub"
|
||||
@@ -196,26 +199,20 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from "vue"
|
||||
import { ref } from "vue"
|
||||
import { version } from "~/../package.json"
|
||||
import IconSidebar from "~icons/lucide/sidebar"
|
||||
import IconMinimize from "~icons/lucide/minimize"
|
||||
import IconMaximize from "~icons/lucide/maximize"
|
||||
import IconZap from "~icons/lucide/zap"
|
||||
import IconShare2 from "~icons/lucide/share-2"
|
||||
import IconColumns from "~icons/lucide/columns"
|
||||
import IconSidebarOpen from "~icons/lucide/sidebar-open"
|
||||
import IconShieldCheck from "~icons/lucide/shield-check"
|
||||
import IconBook from "~icons/lucide/book"
|
||||
import IconMessageCircle from "~icons/lucide/message-circle"
|
||||
import IconGift from "~icons/lucide/gift"
|
||||
import IconActivity from "~icons/lucide/activity"
|
||||
import IconGithub from "~icons/lucide/github"
|
||||
import IconTwitter from "~icons/lucide/twitter"
|
||||
import IconUserPlus from "~icons/lucide/user-plus"
|
||||
import IconLock from "~icons/lucide/lock"
|
||||
import IconLifeBuoy from "~icons/lucide/life-buoy"
|
||||
import { showChat } from "@modules/crisp"
|
||||
import { useSetting } from "@composables/settings"
|
||||
import { useI18n } from "@composables/i18n"
|
||||
import { useReadonlyStream } from "@composables/stream"
|
||||
@@ -230,7 +227,6 @@ const showDeveloperOptions = ref(false)
|
||||
|
||||
const EXPAND_NAVIGATION = useSetting("EXPAND_NAVIGATION")
|
||||
const SIDEBAR = useSetting("SIDEBAR")
|
||||
const ZEN_MODE = useSetting("ZEN_MODE")
|
||||
const COLUMN_LAYOUT = useSetting("COLUMN_LAYOUT")
|
||||
const SIDEBAR_ON_LEFT = useSetting("SIDEBAR_ON_LEFT")
|
||||
|
||||
@@ -241,13 +237,6 @@ const currentUser = useReadonlyStream(
|
||||
platform.auth.getCurrentUser()
|
||||
)
|
||||
|
||||
watch(
|
||||
() => ZEN_MODE.value,
|
||||
() => {
|
||||
EXPAND_NAVIGATION.value = !ZEN_MODE.value
|
||||
}
|
||||
)
|
||||
|
||||
const nativeShare = () => {
|
||||
if (navigator.share) {
|
||||
navigator
|
||||
@@ -262,10 +251,6 @@ const nativeShare = () => {
|
||||
}
|
||||
}
|
||||
|
||||
const chatWithUs = () => {
|
||||
showChat()
|
||||
}
|
||||
|
||||
const showDeveloperOptionModal = () => {
|
||||
if (currentUser.value) {
|
||||
showDeveloperOptions.value = true
|
||||
|
||||
@@ -30,144 +30,55 @@
|
||||
<h2 class="p-4 font-semibold font-bold text-secondaryDark">
|
||||
{{ t("support.title") }}
|
||||
</h2>
|
||||
<HoppSmartItem
|
||||
:icon="IconBook"
|
||||
:label="t('app.documentation')"
|
||||
to="https://docs.hoppscotch.io"
|
||||
:description="t('support.documentation')"
|
||||
:info-icon="IconChevronRight"
|
||||
active
|
||||
blank
|
||||
@click="hideModal()"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
:icon="IconGift"
|
||||
:label="t('app.whats_new')"
|
||||
to="https://docs.hoppscotch.io/documentation/changelog"
|
||||
:description="t('support.changelog')"
|
||||
:info-icon="IconChevronRight"
|
||||
active
|
||||
blank
|
||||
@click="hideModal()"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
:icon="IconActivity"
|
||||
:label="t('app.status')"
|
||||
to="https://status.hoppscotch.io"
|
||||
blank
|
||||
:description="t('app.status_description')"
|
||||
:info-icon="IconChevronRight"
|
||||
active
|
||||
@click="hideModal()"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
:icon="IconLock"
|
||||
:label="`${t('app.terms_and_privacy')}`"
|
||||
to="https://docs.hoppscotch.io/support/privacy"
|
||||
blank
|
||||
:description="t('app.terms_and_privacy')"
|
||||
:info-icon="IconChevronRight"
|
||||
active
|
||||
@click="hideModal()"
|
||||
/>
|
||||
<h2 class="p-4 font-semibold font-bold text-secondaryDark">
|
||||
{{ t("settings.follow") }}
|
||||
</h2>
|
||||
<HoppSmartItem
|
||||
:icon="IconDiscord"
|
||||
:label="t('app.discord')"
|
||||
to="https://hoppscotch.io/discord"
|
||||
blank
|
||||
:description="t('app.join_discord_community')"
|
||||
:info-icon="IconChevronRight"
|
||||
active
|
||||
@click="hideModal()"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
:icon="IconTwitter"
|
||||
:label="t('app.twitter')"
|
||||
to="https://hoppscotch.io/twitter"
|
||||
blank
|
||||
:description="t('support.twitter')"
|
||||
:info-icon="IconChevronRight"
|
||||
active
|
||||
@click="hideModal()"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
:icon="IconGithub"
|
||||
:label="`${t('app.github')}`"
|
||||
to="https://github.com/hoppscotch/hoppscotch"
|
||||
blank
|
||||
:description="t('support.github')"
|
||||
:info-icon="IconChevronRight"
|
||||
active
|
||||
@click="hideModal()"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
:icon="IconMessageCircle"
|
||||
:label="t('app.chat_with_us')"
|
||||
:description="t('support.chat')"
|
||||
:info-icon="IconChevronRight"
|
||||
active
|
||||
@click="chatWithUs()"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
:icon="IconUserPlus"
|
||||
:label="`${t('app.invite')}`"
|
||||
:description="t('shortcut.miscellaneous.invite')"
|
||||
:info-icon="IconChevronRight"
|
||||
active
|
||||
@click="expandInvite()"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
v-if="navigatorShare"
|
||||
v-tippy="{ theme: 'tooltip' }"
|
||||
:icon="IconShare2"
|
||||
:label="`${t('request.share')}`"
|
||||
:description="t('request.share_description')"
|
||||
:info-icon="IconChevronRight"
|
||||
active
|
||||
@click="nativeShare()"
|
||||
/>
|
||||
<template
|
||||
v-for="item in platform.ui?.additionalSupportOptionsMenuItems"
|
||||
:key="item.id"
|
||||
>
|
||||
<HoppSmartItem
|
||||
v-if="item.action.type === 'link'"
|
||||
:icon="item.icon"
|
||||
:label="item.text(t)"
|
||||
:to="item.action.href"
|
||||
:description="item.subtitle(t)"
|
||||
:info-icon="IconChevronRight"
|
||||
active
|
||||
blank
|
||||
@click="hideModal()"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
v-else
|
||||
:icon="item.icon"
|
||||
:label="item.text(t)"
|
||||
:description="item.subtitle(t)"
|
||||
:info-icon="IconChevronRight"
|
||||
active
|
||||
@click="
|
||||
() => {
|
||||
// @ts-expect-error Typescript isn't able to understand
|
||||
item.action.do()
|
||||
hideModal()
|
||||
}
|
||||
"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</HoppSmartModal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { watch } from "vue"
|
||||
import IconSidebar from "~icons/lucide/sidebar"
|
||||
import IconSidebarOpen from "~icons/lucide/sidebar-open"
|
||||
import IconBook from "~icons/lucide/book"
|
||||
import IconGift from "~icons/lucide/gift"
|
||||
import IconActivity from "~icons/lucide/activity"
|
||||
import IconLock from "~icons/lucide/lock"
|
||||
import IconDiscord from "~icons/brands/discord"
|
||||
import IconTwitter from "~icons/brands/twitter"
|
||||
import IconGithub from "~icons/lucide/github"
|
||||
import IconMessageCircle from "~icons/lucide/message-circle"
|
||||
import IconUserPlus from "~icons/lucide/user-plus"
|
||||
import IconShare2 from "~icons/lucide/share-2"
|
||||
import IconChevronRight from "~icons/lucide/chevron-right"
|
||||
import { useSetting } from "@composables/settings"
|
||||
import { invokeAction } from "~/helpers/actions"
|
||||
import { showChat } from "@modules/crisp"
|
||||
import { useI18n } from "@composables/i18n"
|
||||
import { platform } from "~/platform"
|
||||
|
||||
const t = useI18n()
|
||||
const navigatorShare = !!navigator.share
|
||||
|
||||
const ZEN_MODE = useSetting("ZEN_MODE")
|
||||
const EXPAND_NAVIGATION = useSetting("EXPAND_NAVIGATION")
|
||||
const SIDEBAR = useSetting("SIDEBAR")
|
||||
|
||||
watch(
|
||||
() => ZEN_MODE.value,
|
||||
() => {
|
||||
EXPAND_NAVIGATION.value = !ZEN_MODE.value
|
||||
}
|
||||
)
|
||||
|
||||
defineProps<{
|
||||
show: boolean
|
||||
}>()
|
||||
@@ -176,11 +87,6 @@ const emit = defineEmits<{
|
||||
(e: "hide-modal"): void
|
||||
}>()
|
||||
|
||||
const chatWithUs = () => {
|
||||
showChat()
|
||||
hideModal()
|
||||
}
|
||||
|
||||
const expandNavigation = () => {
|
||||
EXPAND_NAVIGATION.value = !EXPAND_NAVIGATION.value
|
||||
hideModal()
|
||||
@@ -191,24 +97,6 @@ const expandCollection = () => {
|
||||
hideModal()
|
||||
}
|
||||
|
||||
const expandInvite = () => {
|
||||
invokeAction("modals.share.toggle")
|
||||
}
|
||||
|
||||
const nativeShare = () => {
|
||||
if (navigator.share) {
|
||||
navigator
|
||||
.share({
|
||||
title: "Hoppscotch",
|
||||
text: "Hoppscotch • Open source API development ecosystem - Helps you create requests faster, saving precious time on development.",
|
||||
url: "https://hoppscotch.io",
|
||||
})
|
||||
.catch(console.error)
|
||||
} else {
|
||||
// fallback
|
||||
}
|
||||
}
|
||||
|
||||
const hideModal = () => {
|
||||
emit("hide-modal")
|
||||
}
|
||||
|
||||
@@ -8,89 +8,46 @@
|
||||
>
|
||||
<template #body>
|
||||
<div class="flex flex-col space-y-2">
|
||||
<HoppSmartItem
|
||||
:icon="IconBook"
|
||||
:label="t('app.documentation')"
|
||||
to="https://docs.hoppscotch.io"
|
||||
:description="t('support.documentation')"
|
||||
:info-icon="IconChevronRight"
|
||||
active
|
||||
blank
|
||||
@click="hideModal()"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
:icon="IconZap"
|
||||
:label="t('app.keyboard_shortcuts')"
|
||||
:description="t('support.shortcuts')"
|
||||
:info-icon="IconChevronRight"
|
||||
active
|
||||
@click="showShortcuts()"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
:icon="IconGift"
|
||||
:label="t('app.whats_new')"
|
||||
to="https://docs.hoppscotch.io/documentation/changelog"
|
||||
:description="t('support.changelog')"
|
||||
:info-icon="IconChevronRight"
|
||||
active
|
||||
blank
|
||||
@click="hideModal()"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
:icon="IconMessageCircle"
|
||||
:label="t('app.chat_with_us')"
|
||||
:description="t('support.chat')"
|
||||
:info-icon="IconChevronRight"
|
||||
active
|
||||
@click="chatWithUs()"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
:icon="IconGitHub"
|
||||
:label="t('app.github')"
|
||||
to="https://hoppscotch.io/github"
|
||||
blank
|
||||
:description="t('support.github')"
|
||||
:info-icon="IconChevronRight"
|
||||
active
|
||||
@click="hideModal()"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
:icon="IconDiscord"
|
||||
:label="t('app.join_discord_community')"
|
||||
to="https://hoppscotch.io/discord"
|
||||
blank
|
||||
:description="t('support.community')"
|
||||
:info-icon="IconChevronRight"
|
||||
active
|
||||
@click="hideModal()"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
:icon="IconTwitter"
|
||||
:label="t('app.twitter')"
|
||||
to="https://hoppscotch.io/twitter"
|
||||
blank
|
||||
:description="t('support.twitter')"
|
||||
:info-icon="IconChevronRight"
|
||||
active
|
||||
@click="hideModal()"
|
||||
/>
|
||||
<template
|
||||
v-for="item in platform.ui?.additionalSupportOptionsMenuItems"
|
||||
:key="item.id"
|
||||
>
|
||||
<HoppSmartItem
|
||||
v-if="item.action.type === 'link'"
|
||||
:icon="item.icon"
|
||||
:label="item.text(t)"
|
||||
:to="item.action.href"
|
||||
:description="item.subtitle(t)"
|
||||
:info-icon="IconChevronRight"
|
||||
active
|
||||
blank
|
||||
@click="hideModal()"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
v-else
|
||||
:icon="item.icon"
|
||||
:label="item.text(t)"
|
||||
:description="item.subtitle(t)"
|
||||
:info-icon="IconChevronRight"
|
||||
active
|
||||
@click="
|
||||
() => {
|
||||
// @ts-expect-error Typescript isn't able to understand
|
||||
item.action.do()
|
||||
hideModal()
|
||||
}
|
||||
"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</HoppSmartModal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import IconTwitter from "~icons/brands/twitter"
|
||||
import IconDiscord from "~icons/brands/discord"
|
||||
import IconGitHub from "~icons/lucide/github"
|
||||
import IconMessageCircle from "~icons/lucide/message-circle"
|
||||
import IconGift from "~icons/lucide/gift"
|
||||
import IconZap from "~icons/lucide/zap"
|
||||
import IconBook from "~icons/lucide/book"
|
||||
import IconChevronRight from "~icons/lucide/chevron-right"
|
||||
import { invokeAction } from "@helpers/actions"
|
||||
import { showChat } from "@modules/crisp"
|
||||
import { useI18n } from "@composables/i18n"
|
||||
import { platform } from "~/platform"
|
||||
|
||||
const t = useI18n()
|
||||
|
||||
@@ -102,16 +59,6 @@ const emit = defineEmits<{
|
||||
(e: "hide-modal"): void
|
||||
}>()
|
||||
|
||||
const chatWithUs = () => {
|
||||
showChat()
|
||||
hideModal()
|
||||
}
|
||||
|
||||
const showShortcuts = () => {
|
||||
invokeAction("flyouts.keybinds.toggle")
|
||||
hideModal()
|
||||
}
|
||||
|
||||
const hideModal = () => {
|
||||
emit("hide-modal")
|
||||
}
|
||||
|
||||
@@ -119,5 +119,8 @@ watch(
|
||||
&.active {
|
||||
@apply after:bg-accentLight;
|
||||
}
|
||||
|
||||
scroll-padding: 4rem !important;
|
||||
scroll-margin: 4rem !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
:key="`result-${result.id}`"
|
||||
:entry="result"
|
||||
:active="isEqual(selectedEntry, [sectionIndex, entryIndex])"
|
||||
@mouseover="selectedEntry = [sectionIndex, entryIndex]"
|
||||
@mouseover="onMouseOver($event, sectionIndex, entryIndex)"
|
||||
@action="runAction(sectionID, result)"
|
||||
/>
|
||||
</div>
|
||||
@@ -178,6 +178,24 @@ function runAction(searcherID: string, result: SpotlightSearcherResult) {
|
||||
emit("hide-modal")
|
||||
}
|
||||
|
||||
let lastMousePosition: { x: number; y: number }
|
||||
|
||||
const onMouseOver = (
|
||||
e: MouseEvent,
|
||||
sectionIndex: number,
|
||||
entryIndex: number
|
||||
) => {
|
||||
const mousePosition = {
|
||||
x: e.clientX,
|
||||
y: e.clientY,
|
||||
}
|
||||
|
||||
// if the position is same, do nothing
|
||||
if (isEqual(lastMousePosition, mousePosition)) return
|
||||
selectedEntry.value = [sectionIndex, entryIndex]
|
||||
lastMousePosition = mousePosition
|
||||
}
|
||||
|
||||
function newUseArrowKeysForNavigation() {
|
||||
const selectedEntry = ref<[number, number]>([0, 0]) // [sectionIndex, entryIndex]
|
||||
|
||||
|
||||
@@ -21,7 +21,12 @@
|
||||
<label for="value" class="font-semibold min-w-10">{{
|
||||
t("environment.value")
|
||||
}}</label>
|
||||
<input type="text" :value="value" class="input" />
|
||||
<input
|
||||
v-model="editingValue"
|
||||
type="text"
|
||||
class="input"
|
||||
:placeholder="t('environment.value')"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex items-center space-x-8 ml-2">
|
||||
<label for="scope" class="font-semibold min-w-10">
|
||||
@@ -105,9 +110,12 @@ watch(
|
||||
scope.value = {
|
||||
type: "global",
|
||||
}
|
||||
editingName.value = ""
|
||||
replaceWithVariable.value = false
|
||||
editingName.value = ""
|
||||
editingValue.value = ""
|
||||
}
|
||||
editingName.value = props.name
|
||||
editingValue.value = props.value
|
||||
}
|
||||
)
|
||||
|
||||
@@ -132,6 +140,7 @@ const scope = ref<Scope>({
|
||||
const replaceWithVariable = ref(false)
|
||||
|
||||
const editingName = ref(props.name)
|
||||
const editingValue = ref(props.value)
|
||||
|
||||
const addEnvironment = async () => {
|
||||
if (!editingName.value) {
|
||||
@@ -141,13 +150,13 @@ const addEnvironment = async () => {
|
||||
if (scope.value.type === "global") {
|
||||
addGlobalEnvVariable({
|
||||
key: editingName.value,
|
||||
value: props.value,
|
||||
value: editingValue.value,
|
||||
})
|
||||
toast.success(`${t("environment.updated")}`)
|
||||
} else if (scope.value.type === "my-environment") {
|
||||
addEnvironmentVariable(scope.value.index, {
|
||||
key: editingName.value,
|
||||
value: props.value,
|
||||
value: editingValue.value,
|
||||
})
|
||||
toast.success(`${t("environment.updated")}`)
|
||||
} else {
|
||||
@@ -155,7 +164,7 @@ const addEnvironment = async () => {
|
||||
...scope.value.environment.environment.variables,
|
||||
{
|
||||
key: editingName.value,
|
||||
value: props.value,
|
||||
value: editingValue.value,
|
||||
},
|
||||
]
|
||||
await pipe(
|
||||
@@ -182,7 +191,7 @@ const addEnvironment = async () => {
|
||||
//replace the currenttab endpoint containing the value in the text with variablename
|
||||
currentActiveTab.value.document.request.endpoint =
|
||||
currentActiveTab.value.document.request.endpoint.replace(
|
||||
props.value,
|
||||
editingValue.value,
|
||||
variableName
|
||||
)
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
@keyup.escape="hide()"
|
||||
>
|
||||
<HoppSmartItem
|
||||
v-if="!isScopeSelector"
|
||||
:label="`${t('environment.no_environment')}`"
|
||||
:info-icon="
|
||||
selectedEnvironmentIndex.type === 'NO_ENV_SELECTED'
|
||||
@@ -48,6 +49,21 @@
|
||||
}
|
||||
"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
v-else-if="isScopeSelector && modelValue"
|
||||
:label="t('environment.global')"
|
||||
:icon="IconGlobe"
|
||||
:info-icon="modelValue.type === 'global' ? IconCheck : undefined"
|
||||
:active-info-icon="modelValue.type === 'global'"
|
||||
@click="
|
||||
() => {
|
||||
$emit('update:modelValue', {
|
||||
type: 'global',
|
||||
})
|
||||
hide()
|
||||
}
|
||||
"
|
||||
/>
|
||||
<HoppSmartTabs
|
||||
v-model="selectedEnvTab"
|
||||
:styles="`sticky overflow-x-auto my-2 border border-divider rounded flex-shrink-0 z-0 top-0 bg-primary ${
|
||||
@@ -66,14 +82,14 @@
|
||||
:key="`gen-${index}`"
|
||||
:icon="IconLayers"
|
||||
:label="gen.name"
|
||||
:info-icon="index === selectedEnv.index ? IconCheck : undefined"
|
||||
:active-info-icon="index === selectedEnv.index"
|
||||
:info-icon="isEnvActive(index) ? IconCheck : undefined"
|
||||
:active-info-icon="isEnvActive(index)"
|
||||
@click="
|
||||
() => {
|
||||
selectedEnvironmentIndex = {
|
||||
type: 'MY_ENV',
|
||||
index: index,
|
||||
}
|
||||
handleEnvironmentChange(index, {
|
||||
type: 'my-environment',
|
||||
environment: gen,
|
||||
})
|
||||
hide()
|
||||
}
|
||||
"
|
||||
@@ -113,18 +129,14 @@
|
||||
:key="`gen-team-${index}`"
|
||||
:icon="IconLayers"
|
||||
:label="gen.environment.name"
|
||||
:info-icon="
|
||||
gen.id === selectedEnv.teamEnvID ? IconCheck : undefined
|
||||
"
|
||||
:active-info-icon="gen.id === selectedEnv.teamEnvID"
|
||||
:info-icon="isEnvActive(gen.id) ? IconCheck : undefined"
|
||||
:active-info-icon="isEnvActive(gen.id)"
|
||||
@click="
|
||||
() => {
|
||||
selectedEnvironmentIndex = {
|
||||
type: 'TEAM_ENV',
|
||||
teamEnvID: gen.id,
|
||||
teamID: gen.teamID,
|
||||
environment: gen.environment,
|
||||
}
|
||||
handleEnvironmentChange(index, {
|
||||
type: 'team-environment',
|
||||
environment: gen,
|
||||
})
|
||||
hide()
|
||||
}
|
||||
"
|
||||
@@ -285,6 +297,7 @@ import IconCheck from "~icons/lucide/check"
|
||||
import IconLayers from "~icons/lucide/layers"
|
||||
import IconEye from "~icons/lucide/eye"
|
||||
import IconEdit from "~icons/lucide/edit"
|
||||
import IconGlobe from "~icons/lucide/globe"
|
||||
import { TippyComponent } from "vue-tippy"
|
||||
import { useI18n } from "~/composables/i18n"
|
||||
import { GQLError } from "~/helpers/backend/GQLClient"
|
||||
@@ -295,11 +308,39 @@ import {
|
||||
selectedEnvironmentIndex$,
|
||||
setSelectedEnvironmentIndex,
|
||||
} from "~/newstore/environments"
|
||||
import { workspaceStatus$ } from "~/newstore/workspace"
|
||||
import { changeWorkspace, workspaceStatus$ } from "~/newstore/workspace"
|
||||
import TeamEnvironmentAdapter from "~/helpers/teams/TeamEnvironmentAdapter"
|
||||
import { useColorMode } from "@composables/theming"
|
||||
import { breakpointsTailwind, useBreakpoints } from "@vueuse/core"
|
||||
import { invokeAction } from "~/helpers/actions"
|
||||
import { TeamEnvironment } from "~/helpers/teams/TeamEnvironment"
|
||||
import { Environment } from "@hoppscotch/data"
|
||||
import { onMounted } from "vue"
|
||||
import { onLoggedIn } from "~/composables/auth"
|
||||
import TeamListAdapter from "~/helpers/teams/TeamListAdapter"
|
||||
import { useLocalState } from "~/newstore/localstate"
|
||||
import { GetMyTeamsQuery } from "~/helpers/backend/graphql"
|
||||
|
||||
type Scope =
|
||||
| {
|
||||
type: "global"
|
||||
}
|
||||
| {
|
||||
type: "my-environment"
|
||||
environment: Environment
|
||||
index: number
|
||||
}
|
||||
| {
|
||||
type: "team-environment"
|
||||
environment: TeamEnvironment
|
||||
}
|
||||
const props = defineProps<{
|
||||
isScopeSelector?: boolean
|
||||
modelValue?: Scope
|
||||
}>()
|
||||
const emit = defineEmits<{
|
||||
(e: "update:modelValue", data: Scope): void
|
||||
}>()
|
||||
|
||||
const breakpoints = useBreakpoints(breakpointsTailwind)
|
||||
const mdAndLarger = breakpoints.greater("md")
|
||||
@@ -314,6 +355,38 @@ const myEnvironments = useReadonlyStream(environments$, [])
|
||||
|
||||
const workspace = useReadonlyStream(workspaceStatus$, { type: "personal" })
|
||||
|
||||
// TeamList-Adapter
|
||||
const teamListAdapter = new TeamListAdapter(true)
|
||||
const myTeams = useReadonlyStream(teamListAdapter.teamList$, null)
|
||||
const teamListFetched = ref(false)
|
||||
const REMEMBERED_TEAM_ID = useLocalState("REMEMBERED_TEAM_ID")
|
||||
|
||||
onLoggedIn(() => {
|
||||
!teamListAdapter.isInitialized && teamListAdapter.initialize()
|
||||
})
|
||||
|
||||
const switchToTeamWorkspace = (team: GetMyTeamsQuery["myTeams"][number]) => {
|
||||
REMEMBERED_TEAM_ID.value = team.id
|
||||
changeWorkspace({
|
||||
teamID: team.id,
|
||||
teamName: team.name,
|
||||
type: "team",
|
||||
})
|
||||
}
|
||||
watch(
|
||||
() => myTeams.value,
|
||||
(newTeams) => {
|
||||
if (newTeams && !teamListFetched.value) {
|
||||
teamListFetched.value = true
|
||||
if (REMEMBERED_TEAM_ID.value) {
|
||||
const team = newTeams.find((t) => t.id === REMEMBERED_TEAM_ID.value)
|
||||
if (team) switchToTeamWorkspace(team)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
// TeamEnv List Adapter
|
||||
const teamEnvListAdapter = new TeamEnvironmentAdapter(undefined)
|
||||
const teamListLoading = useReadonlyStream(teamEnvListAdapter.loading$, false)
|
||||
const teamAdapterError = useReadonlyStream(teamEnvListAdapter.error$, null)
|
||||
@@ -322,6 +395,70 @@ const teamEnvironmentList = useReadonlyStream(
|
||||
[]
|
||||
)
|
||||
|
||||
const handleEnvironmentChange = (
|
||||
index: number,
|
||||
env?:
|
||||
| {
|
||||
type: "my-environment"
|
||||
environment: Environment
|
||||
}
|
||||
| {
|
||||
type: "team-environment"
|
||||
environment: TeamEnvironment
|
||||
}
|
||||
) => {
|
||||
if (props.isScopeSelector && env) {
|
||||
if (env.type === "my-environment") {
|
||||
emit("update:modelValue", {
|
||||
type: "my-environment",
|
||||
environment: env.environment,
|
||||
index,
|
||||
})
|
||||
} else if (env.type === "team-environment") {
|
||||
emit("update:modelValue", {
|
||||
type: "team-environment",
|
||||
environment: env.environment,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
if (env && env.type === "my-environment") {
|
||||
selectedEnvironmentIndex.value = {
|
||||
type: "MY_ENV",
|
||||
index,
|
||||
}
|
||||
} else if (env && env.type === "team-environment") {
|
||||
selectedEnvironmentIndex.value = {
|
||||
type: "TEAM_ENV",
|
||||
teamEnvID: env.environment.id,
|
||||
teamID: env.environment.teamID,
|
||||
environment: env.environment.environment,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const isEnvActive = (id: string | number) => {
|
||||
if (props.isScopeSelector) {
|
||||
if (props.modelValue?.type === "my-environment") {
|
||||
return props.modelValue.index === id
|
||||
} else if (props.modelValue?.type === "team-environment") {
|
||||
return (
|
||||
props.modelValue?.type === "team-environment" &&
|
||||
props.modelValue.environment &&
|
||||
props.modelValue.environment.id === id
|
||||
)
|
||||
}
|
||||
} else {
|
||||
if (selectedEnvironmentIndex.value.type === "MY_ENV") {
|
||||
return selectedEnv.value.index === id
|
||||
} else {
|
||||
return (
|
||||
selectedEnvironmentIndex.value.type === "TEAM_ENV" &&
|
||||
selectedEnv.value.teamEnvID === id
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const selectedEnvironmentIndex = useStream(
|
||||
selectedEnvironmentIndex$,
|
||||
{ type: "NO_ENV_SELECTED" },
|
||||
@@ -349,34 +486,90 @@ watch(
|
||||
)
|
||||
|
||||
const selectedEnv = computed(() => {
|
||||
if (selectedEnvironmentIndex.value.type === "MY_ENV") {
|
||||
const environment =
|
||||
myEnvironments.value[selectedEnvironmentIndex.value.index]
|
||||
return {
|
||||
type: "MY_ENV",
|
||||
index: selectedEnvironmentIndex.value.index,
|
||||
name: environment.name,
|
||||
variables: environment.variables,
|
||||
}
|
||||
} else if (selectedEnvironmentIndex.value.type === "TEAM_ENV") {
|
||||
const teamEnv = teamEnvironmentList.value.find(
|
||||
(env) =>
|
||||
env.id ===
|
||||
(selectedEnvironmentIndex.value.type === "TEAM_ENV" &&
|
||||
selectedEnvironmentIndex.value.teamEnvID)
|
||||
)
|
||||
if (teamEnv) {
|
||||
if (props.isScopeSelector) {
|
||||
if (props.modelValue?.type === "my-environment") {
|
||||
return {
|
||||
type: "MY_ENV",
|
||||
index: props.modelValue.index,
|
||||
name: props.modelValue.environment?.name,
|
||||
}
|
||||
} else if (props.modelValue?.type === "team-environment") {
|
||||
return {
|
||||
type: "TEAM_ENV",
|
||||
name: teamEnv.environment.name,
|
||||
teamEnvID: selectedEnvironmentIndex.value.teamEnvID,
|
||||
variables: teamEnv.environment.variables,
|
||||
name: props.modelValue.environment.environment.name,
|
||||
teamEnvID: props.modelValue.environment.id,
|
||||
}
|
||||
} else {
|
||||
return { type: "global", name: "Global" }
|
||||
}
|
||||
} else {
|
||||
if (selectedEnvironmentIndex.value.type === "MY_ENV") {
|
||||
const environment =
|
||||
myEnvironments.value[selectedEnvironmentIndex.value.index]
|
||||
return {
|
||||
type: "MY_ENV",
|
||||
index: selectedEnvironmentIndex.value.index,
|
||||
name: environment.name,
|
||||
variables: environment.variables,
|
||||
}
|
||||
} else if (selectedEnvironmentIndex.value.type === "TEAM_ENV") {
|
||||
const teamEnv = teamEnvironmentList.value.find(
|
||||
(env) =>
|
||||
env.id ===
|
||||
(selectedEnvironmentIndex.value.type === "TEAM_ENV" &&
|
||||
selectedEnvironmentIndex.value.teamEnvID)
|
||||
)
|
||||
if (teamEnv) {
|
||||
return {
|
||||
type: "TEAM_ENV",
|
||||
name: teamEnv.environment.name,
|
||||
teamEnvID: selectedEnvironmentIndex.value.teamEnvID,
|
||||
variables: teamEnv.environment.variables,
|
||||
}
|
||||
} else {
|
||||
return { type: "NO_ENV_SELECTED" }
|
||||
}
|
||||
} else {
|
||||
return { type: "NO_ENV_SELECTED" }
|
||||
}
|
||||
} else {
|
||||
return { type: "NO_ENV_SELECTED" }
|
||||
}
|
||||
})
|
||||
|
||||
// Set the selected environment as initial scope value
|
||||
onMounted(() => {
|
||||
if (props.isScopeSelector) {
|
||||
if (
|
||||
selectedEnvironmentIndex.value.type === "MY_ENV" &&
|
||||
selectedEnvironmentIndex.value.index !== undefined
|
||||
) {
|
||||
emit("update:modelValue", {
|
||||
type: "my-environment",
|
||||
environment: myEnvironments.value[selectedEnvironmentIndex.value.index],
|
||||
index: selectedEnvironmentIndex.value.index,
|
||||
})
|
||||
} else if (
|
||||
selectedEnvironmentIndex.value.type === "TEAM_ENV" &&
|
||||
selectedEnvironmentIndex.value.teamEnvID &&
|
||||
teamEnvironmentList.value &&
|
||||
teamEnvironmentList.value.length > 0
|
||||
) {
|
||||
const teamEnv = teamEnvironmentList.value.find(
|
||||
(env) =>
|
||||
env.id ===
|
||||
(selectedEnvironmentIndex.value.type === "TEAM_ENV" &&
|
||||
selectedEnvironmentIndex.value.teamEnvID)
|
||||
)
|
||||
if (teamEnv) {
|
||||
emit("update:modelValue", {
|
||||
type: "team-environment",
|
||||
environment: teamEnv,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
emit("update:modelValue", {
|
||||
type: "global",
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -300,7 +300,7 @@ watch(
|
||||
|
||||
defineActionHandler("modals.environment.add", ({ envName, variableName }) => {
|
||||
editingVariableName.value = envName
|
||||
editingVariableValue.value = variableName
|
||||
if (variableName) editingVariableValue.value = variableName
|
||||
displayModalNew(true)
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -144,8 +144,6 @@ const selectedOperation = ref<gql.OperationDefinitionNode | null>(null)
|
||||
const gqlQueryString = useVModel(props, "modelValue", emit)
|
||||
|
||||
const debouncedOnUpdateQueryState = debounce((update: ViewUpdate) => {
|
||||
if (!update.selectionSet) return
|
||||
|
||||
const selectedPos = update.state.selection.main.head
|
||||
const queryString = update.state.doc.toJSON().join(update.state.lineBreak)
|
||||
|
||||
|
||||
@@ -71,6 +71,7 @@ import { connect } from "~/helpers/graphql/connection"
|
||||
import { disconnect } from "~/helpers/graphql/connection"
|
||||
import { InterceptorService } from "~/services/interceptor.service"
|
||||
import { useService } from "dioc/vue"
|
||||
import { defineActionHandler } from "~/helpers/actions"
|
||||
|
||||
const t = useI18n()
|
||||
|
||||
@@ -140,4 +141,12 @@ const cancelSwitch = () => {
|
||||
if (connected.value) disconnect()
|
||||
connectionSwitchModal.value = false
|
||||
}
|
||||
|
||||
defineActionHandler(
|
||||
"gql.connect",
|
||||
gqlConnect,
|
||||
computed(() => !connected.value)
|
||||
)
|
||||
|
||||
defineActionHandler("gql.disconnect", disconnect, connected)
|
||||
</script>
|
||||
|
||||
@@ -69,8 +69,8 @@ import { useService } from "dioc/vue"
|
||||
import { InterceptorService } from "~/services/interceptor.service"
|
||||
import { editGraphqlRequest } from "~/newstore/collections"
|
||||
|
||||
type OptionTabs = "query" | "headers" | "variables" | "authorization"
|
||||
const selectedOptionTab = ref<OptionTabs>("query")
|
||||
export type GQLOptionTabs = "query" | "headers" | "variables" | "authorization"
|
||||
const selectedOptionTab = ref<GQLOptionTabs>("query")
|
||||
const interceptorService = useService(InterceptorService)
|
||||
|
||||
const t = useI18n()
|
||||
@@ -206,4 +206,8 @@ defineActionHandler("request.save-as", () => {
|
||||
showSaveRequestModal.value = true
|
||||
})
|
||||
defineActionHandler("request.reset", clearGQLQuery)
|
||||
|
||||
defineActionHandler("request.open-tab", ({ tab }) => {
|
||||
selectedOptionTab.value = tab as GQLOptionTabs
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -128,8 +128,14 @@ const downloadResponse = (str: string) => {
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
defineActionHandler("response.file.download", () =>
|
||||
downloadResponse(responseString.value)
|
||||
defineActionHandler(
|
||||
"response.file.download",
|
||||
() => downloadResponse(responseString.value),
|
||||
computed(() => !!props.response && props.response.length > 0)
|
||||
)
|
||||
defineActionHandler(
|
||||
"response.copy",
|
||||
() => copyResponse(responseString.value),
|
||||
computed(() => !!props.response && props.response.length > 0)
|
||||
)
|
||||
defineActionHandler("response.copy", () => copyResponse(responseString.value))
|
||||
</script>
|
||||
|
||||
@@ -508,30 +508,17 @@ const changeTab = (tab: ComputedHeader["source"]) => {
|
||||
|
||||
const inspectionService = useService(InspectionService)
|
||||
|
||||
const allTabResults = inspectionService.tabs
|
||||
const headerKeyResults = inspectionService.getResultViewFor(
|
||||
currentTabID.value,
|
||||
(result) =>
|
||||
result.locations.type === "header" && result.locations.position === "key"
|
||||
)
|
||||
|
||||
const headerKeyResults = computed(() => {
|
||||
return (
|
||||
allTabResults.value
|
||||
.get(currentTabID.value)
|
||||
.filter(
|
||||
(result) =>
|
||||
result.locations.type === "header" &&
|
||||
result.locations.position === "key"
|
||||
) ?? []
|
||||
)
|
||||
})
|
||||
const headerValueResults = computed(() => {
|
||||
return (
|
||||
allTabResults.value
|
||||
.get(currentTabID.value)
|
||||
.filter(
|
||||
(result) =>
|
||||
result.locations.type === "header" &&
|
||||
result.locations.position === "value"
|
||||
) ?? []
|
||||
)
|
||||
})
|
||||
const headerValueResults = inspectionService.getResultViewFor(
|
||||
currentTabID.value,
|
||||
(result) =>
|
||||
result.locations.type === "header" && result.locations.position === "value"
|
||||
)
|
||||
|
||||
const getInspectorResult = (results: InspectorResult[], index: number) => {
|
||||
return results.filter((result) => {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<div class="flex">
|
||||
<HoppButtonSecondary
|
||||
v-tippy="{ theme: 'tooltip' }"
|
||||
to="https://docs.hoppscotch.io/documentation/getting-started/rest/using-parameters"
|
||||
to="https://docs.hoppscotch.io/documentation/features/rest-api-testing"
|
||||
blank
|
||||
:title="t('app.wiki')"
|
||||
:icon="IconHelpCircle"
|
||||
@@ -178,7 +178,7 @@ import IconCheckCircle from "~icons/lucide/check-circle"
|
||||
import IconCircle from "~icons/lucide/circle"
|
||||
import IconTrash from "~icons/lucide/trash"
|
||||
import IconWrapText from "~icons/lucide/wrap-text"
|
||||
import { computed, reactive, ref, watch } from "vue"
|
||||
import { reactive, ref, watch } from "vue"
|
||||
import { flow, pipe } from "fp-ts/function"
|
||||
import * as O from "fp-ts/Option"
|
||||
import * as A from "fp-ts/Array"
|
||||
@@ -409,30 +409,18 @@ const clearContent = () => {
|
||||
|
||||
const inspectionService = useService(InspectionService)
|
||||
|
||||
const allTabResults = inspectionService.tabs
|
||||
const parameterKeyResults = inspectionService.getResultViewFor(
|
||||
currentTabID.value,
|
||||
(result) =>
|
||||
result.locations.type === "parameter" && result.locations.position === "key"
|
||||
)
|
||||
|
||||
const parameterKeyResults = computed(() => {
|
||||
return (
|
||||
allTabResults.value
|
||||
.get(currentTabID.value)
|
||||
.filter(
|
||||
(result) =>
|
||||
result.locations.type === "parameter" &&
|
||||
result.locations.position === "key"
|
||||
) ?? []
|
||||
)
|
||||
})
|
||||
const parameterValueResults = computed(() => {
|
||||
return (
|
||||
allTabResults.value
|
||||
.get(currentTabID.value)
|
||||
.filter(
|
||||
(result) =>
|
||||
result.locations.type === "parameter" &&
|
||||
result.locations.position === "value"
|
||||
) ?? []
|
||||
)
|
||||
})
|
||||
const parameterValueResults = inspectionService.getResultViewFor(
|
||||
currentTabID.value,
|
||||
(result) =>
|
||||
result.locations.type === "parameter" &&
|
||||
result.locations.position === "value"
|
||||
)
|
||||
|
||||
const getInspectorResult = (results: InspectorResult[], index: number) => {
|
||||
return results.filter((result) => {
|
||||
|
||||
@@ -642,9 +642,5 @@ const COLUMN_LAYOUT = useSetting("COLUMN_LAYOUT")
|
||||
|
||||
const inspectionService = useService(InspectionService)
|
||||
|
||||
const allTabResults = inspectionService.tabs
|
||||
|
||||
const tabResults = computed(() => {
|
||||
return allTabResults.value.get(currentTabID.value) ?? []
|
||||
})
|
||||
const tabResults = inspectionService.getResultViewFor(currentTabID.value)
|
||||
</script>
|
||||
|
||||
@@ -101,6 +101,6 @@ const newActiveHeadersCount$ = computed(() => {
|
||||
})
|
||||
|
||||
defineActionHandler("request.open-tab", ({ tab }) => {
|
||||
selectedOptionsTab.value = tab
|
||||
selectedOptionsTab.value = tab as RequestOptionTabs
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -145,13 +145,8 @@ const statusCategory = computed(() => {
|
||||
|
||||
const inspectionService = useService(InspectionService)
|
||||
|
||||
const allTabResults = inspectionService.tabs
|
||||
|
||||
const tabResults = computed(() => {
|
||||
return (
|
||||
allTabResults.value
|
||||
.get(currentTabID.value)
|
||||
?.filter((result) => result.locations.type === "response") ?? []
|
||||
)
|
||||
})
|
||||
const tabResults = inspectionService.getResultViewFor(
|
||||
currentTabID.value,
|
||||
(result) => result.locations.type === "response"
|
||||
)
|
||||
</script>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<span
|
||||
v-tippy="{ theme: 'tooltip' }"
|
||||
:title="relativeTime"
|
||||
class="mx-auto truncate ts-font text-secondaryLight hover:text-secondary hover:text-center"
|
||||
class="mx-auto truncate text-tiny text-secondaryLight hover:text-secondary hover:text-center"
|
||||
>
|
||||
{{ shortDateTime(entry.ts) }}
|
||||
</span>
|
||||
@@ -406,8 +406,4 @@ const icon = computed(() => markRaw(ICONS[props.entry.source].icon))
|
||||
@apply transition;
|
||||
@apply hover: text-secondary;
|
||||
}
|
||||
|
||||
.ts-font {
|
||||
font-size: 0.6rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -311,35 +311,36 @@ const envVars = computed(() =>
|
||||
|
||||
const envTooltipPlugin = new HoppReactiveEnvPlugin(envVars, view)
|
||||
|
||||
const initView = (el: any) => {
|
||||
function handleTextSelection() {
|
||||
const selection = view.value?.state.selection.main
|
||||
if (selection) {
|
||||
const from = selection.from
|
||||
const to = selection.to
|
||||
const text = view.value?.state.doc.sliceString(from, to)
|
||||
const { top, left } = view.value?.coordsAtPos(from)
|
||||
if (text) {
|
||||
invokeAction("contextmenu.open", {
|
||||
position: {
|
||||
top,
|
||||
left,
|
||||
},
|
||||
text,
|
||||
})
|
||||
showSuggestionPopover.value = false
|
||||
} else {
|
||||
invokeAction("contextmenu.open", {
|
||||
position: {
|
||||
top,
|
||||
left,
|
||||
},
|
||||
text: null,
|
||||
})
|
||||
}
|
||||
function handleTextSelection() {
|
||||
const selection = view.value?.state.selection.main
|
||||
if (selection) {
|
||||
const from = selection.from
|
||||
const to = selection.to
|
||||
if (from === to) return
|
||||
const text = view.value?.state.doc.sliceString(from, to)
|
||||
const { top, left } = view.value?.coordsAtPos(from)
|
||||
if (text) {
|
||||
invokeAction("contextmenu.open", {
|
||||
position: {
|
||||
top,
|
||||
left,
|
||||
},
|
||||
text,
|
||||
})
|
||||
showSuggestionPopover.value = false
|
||||
} else {
|
||||
invokeAction("contextmenu.open", {
|
||||
position: {
|
||||
top,
|
||||
left,
|
||||
},
|
||||
text: null,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const initView = (el: any) => {
|
||||
// Debounce to prevent double click from selecting the word
|
||||
const debounceFn = useDebounceFn(() => {
|
||||
handleTextSelection()
|
||||
@@ -381,6 +382,11 @@ const initView = (el: any) => {
|
||||
drop(ev) {
|
||||
ev.preventDefault()
|
||||
},
|
||||
scroll(event) {
|
||||
if (event.target) {
|
||||
handleTextSelection()
|
||||
}
|
||||
},
|
||||
}),
|
||||
ViewPlugin.fromClass(
|
||||
class {
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
<template>
|
||||
<span class="inline-flex">
|
||||
<tippy
|
||||
interactive
|
||||
trigger="click"
|
||||
theme="popover"
|
||||
:on-shown="() => tippyActions.focus()"
|
||||
>
|
||||
<span class="select-wrapper">
|
||||
<HoppButtonSecondary
|
||||
v-tippy="{ theme: 'tooltip' }"
|
||||
:title="t('settings.change_font_size')"
|
||||
class="pr-8"
|
||||
:icon="IconType"
|
||||
outline
|
||||
:label="`${getFontSizeName(
|
||||
fontSizes.find((size) => size === active)
|
||||
)}`"
|
||||
/>
|
||||
</span>
|
||||
<template #content="{ hide }">
|
||||
<div
|
||||
ref="tippyActions"
|
||||
class="flex flex-col focus:outline-none"
|
||||
tabindex="0"
|
||||
@keyup.escape="hide()"
|
||||
>
|
||||
<HoppSmartItem
|
||||
v-for="(size, index) in fontSizes"
|
||||
:key="`size-${index}`"
|
||||
:label="`${getFontSizeName(size)}`"
|
||||
:icon="size === active ? IconCircleDot : IconCircle"
|
||||
:active="size === active"
|
||||
@click="
|
||||
() => {
|
||||
setActiveFont(size)
|
||||
hide()
|
||||
}
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</tippy>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import IconCircleDot from "~icons/lucide/circle-dot"
|
||||
import IconCircle from "~icons/lucide/circle"
|
||||
import IconType from "~icons/lucide/type"
|
||||
import { HoppFontSizes, HoppFontSize, applySetting } from "~/newstore/settings"
|
||||
import { useSetting } from "@composables/settings"
|
||||
import { useI18n } from "@composables/i18n"
|
||||
import { ref } from "vue"
|
||||
|
||||
const t = useI18n()
|
||||
|
||||
const fontSizes = HoppFontSizes
|
||||
const active = useSetting("FONT_SIZE")
|
||||
|
||||
const getFontSizeName = (size: HoppFontSize) => {
|
||||
return t(`settings.font_size_${size}`)
|
||||
}
|
||||
|
||||
const setActiveFont = (size: HoppFontSize) => {
|
||||
applySetting("FONT_SIZE", size)
|
||||
}
|
||||
|
||||
// Template refs
|
||||
const tippyActions = ref<any | null>(null)
|
||||
</script>
|
||||
@@ -216,6 +216,33 @@ export function useCodemirror(
|
||||
? new HoppEnvironmentPlugin(subscribeToStream, view)
|
||||
: null
|
||||
|
||||
function handleTextSelection() {
|
||||
const selection = view.value?.state.selection.main
|
||||
if (selection) {
|
||||
const from = selection.from
|
||||
const to = selection.to
|
||||
const text = view.value?.state.doc.sliceString(from, to)
|
||||
const { top, left } = view.value?.coordsAtPos(from)
|
||||
if (text) {
|
||||
invokeAction("contextmenu.open", {
|
||||
position: {
|
||||
top,
|
||||
left,
|
||||
},
|
||||
text,
|
||||
})
|
||||
} else {
|
||||
invokeAction("contextmenu.open", {
|
||||
position: {
|
||||
top,
|
||||
left,
|
||||
},
|
||||
text: null,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const initView = (el: any) => {
|
||||
if (el) platform.ui?.onCodemirrorInstanceMount?.(el)
|
||||
|
||||
@@ -226,33 +253,6 @@ export function useCodemirror(
|
||||
ViewPlugin.fromClass(
|
||||
class {
|
||||
update(update: ViewUpdate) {
|
||||
function handleTextSelection() {
|
||||
const selection = view.value?.state.selection.main
|
||||
if (selection) {
|
||||
const from = selection.from
|
||||
const to = selection.to
|
||||
const text = view.value?.state.doc.sliceString(from, to)
|
||||
const { top, left } = view.value?.coordsAtPos(from)
|
||||
if (text) {
|
||||
invokeAction("contextmenu.open", {
|
||||
position: {
|
||||
top,
|
||||
left,
|
||||
},
|
||||
text,
|
||||
})
|
||||
} else {
|
||||
invokeAction("contextmenu.open", {
|
||||
position: {
|
||||
top,
|
||||
left,
|
||||
},
|
||||
text: null,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Debounce to prevent double click from selecting the word
|
||||
const debounceFn = useDebounceFn(() => {
|
||||
handleTextSelection()
|
||||
@@ -296,6 +296,13 @@ export function useCodemirror(
|
||||
}
|
||||
}
|
||||
),
|
||||
EditorView.domEventHandlers({
|
||||
scroll(event) {
|
||||
if (event.target) {
|
||||
handleTextSelection()
|
||||
}
|
||||
},
|
||||
}),
|
||||
EditorView.updateListener.of((update) => {
|
||||
if (options.extendedEditorConfig.readOnly) {
|
||||
update.view.contentDOM.inputMode = "none"
|
||||
|
||||
@@ -2,12 +2,14 @@
|
||||
* For example, sending a request.
|
||||
*/
|
||||
|
||||
import { Ref, onBeforeUnmount, onMounted, watch } from "vue"
|
||||
import { Ref, onBeforeUnmount, onMounted, reactive, watch } from "vue"
|
||||
import { BehaviorSubject } from "rxjs"
|
||||
import { HoppRESTDocument } from "./rest/document"
|
||||
import { HoppGQLRequest, HoppRESTRequest } from "@hoppscotch/data"
|
||||
import { RequestOptionTabs } from "~/components/http/RequestOptions.vue"
|
||||
import { HoppGQLSaveContext } from "./graphql/document"
|
||||
import { GQLOptionTabs } from "~/components/graphql/RequestOptions.vue"
|
||||
import { computed } from "vue"
|
||||
|
||||
export type HoppAction =
|
||||
| "contextmenu.open" // Send/Cancel a Hoppscotch Request
|
||||
@@ -16,7 +18,7 @@ export type HoppAction =
|
||||
| "request.copy-link" // Copy Request Link
|
||||
| "request.save" // Save to Collections
|
||||
| "request.save-as" // Save As
|
||||
| "rest.request.rename" // Rename
|
||||
| "request.rename" // Rename request on REST or GraphQL
|
||||
| "request.method.next" // Select Next Method
|
||||
| "request.method.prev" // Select Previous Method
|
||||
| "request.method.get" // Select GET Method
|
||||
@@ -26,6 +28,11 @@ export type HoppAction =
|
||||
| "request.method.delete" // Select DELETE Method
|
||||
| "request.import-curl" // Import cURL
|
||||
| "request.show-code" // Show generated code
|
||||
| "gql.connect" // Connect to GraphQL endpoint given
|
||||
| "gql.disconnect" // Disconnect from GraphQL endpoint given
|
||||
| "tab.close-current" // Close current tab
|
||||
| "tab.close-other" // Close other tabs
|
||||
| "tab.open-new" // Open new tab
|
||||
| "collection.new" // Create root collection
|
||||
| "flyouts.chat.open" // Shows the keybinds flyout
|
||||
| "flyouts.keybinds.toggle" // Shows the keybinds flyout
|
||||
@@ -106,11 +113,11 @@ type HoppActionArgsMap = {
|
||||
request: HoppGQLRequest
|
||||
}
|
||||
"request.open-tab": {
|
||||
tab: RequestOptionTabs
|
||||
tab: RequestOptionTabs | GQLOptionTabs
|
||||
}
|
||||
|
||||
"request.duplicate-tab": {
|
||||
tabID: string
|
||||
"tab.duplicate-tab": {
|
||||
tabID?: string
|
||||
}
|
||||
|
||||
"gql.request.open": {
|
||||
@@ -150,7 +157,7 @@ type BoundActionList = {
|
||||
[A in HoppAction | HoppActionWithArgs]?: Array<ActionFunc<A>>
|
||||
}
|
||||
|
||||
const boundActions: BoundActionList = {}
|
||||
const boundActions: BoundActionList = reactive({})
|
||||
|
||||
export const activeActions$ = new BehaviorSubject<
|
||||
(HoppAction | HoppActionWithArgs)[]
|
||||
@@ -206,6 +213,15 @@ export function unbindAction<A extends HoppAction | HoppActionWithArgs>(
|
||||
activeActions$.next(Object.keys(boundActions) as HoppAction[])
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a ref that indicates whether a given action is bound at a given time
|
||||
*
|
||||
* @param action The action to check
|
||||
*/
|
||||
export function isActionBound(action: HoppAction): Ref<boolean> {
|
||||
return computed(() => !!boundActions[action])
|
||||
}
|
||||
|
||||
/**
|
||||
* A composable function that defines a component can handle a given
|
||||
* HoppAction. The handler will be bound when the component is mounted
|
||||
|
||||
@@ -56,7 +56,7 @@ export const bindings: {
|
||||
"alt-x": "request.method.delete",
|
||||
"ctrl-k": "modals.search.toggle",
|
||||
"ctrl-/": "flyouts.keybinds.toggle",
|
||||
"?": "modals.support.toggle",
|
||||
"shift-/": "modals.support.toggle",
|
||||
"ctrl-m": "modals.share.toggle",
|
||||
"alt-r": "navigation.jump.rest",
|
||||
"alt-q": "navigation.jump.graphql",
|
||||
@@ -120,7 +120,8 @@ function generateKeybindingString(ev: KeyboardEvent): ShortcutKey | null {
|
||||
}
|
||||
|
||||
function getPressedKey(ev: KeyboardEvent): Key | null {
|
||||
const val = ev.key.toLowerCase()
|
||||
const val = ev.code.toLowerCase()
|
||||
|
||||
// Check arrow keys
|
||||
if (val === "arrowup") return "up"
|
||||
else if (val === "arrowdown") return "down"
|
||||
@@ -128,21 +129,20 @@ function getPressedKey(ev: KeyboardEvent): Key | null {
|
||||
else if (val === "arrowright") return "right"
|
||||
|
||||
// Check letter keys
|
||||
const isLetter = ev.code.toLowerCase().startsWith("key")
|
||||
if (isLetter) return ev.code.toLowerCase().substring(3) as Key
|
||||
const isLetter = val.startsWith("key")
|
||||
if (isLetter) return val.substring(3) as Key
|
||||
|
||||
// Check if number keys
|
||||
if (val.length === 1 && !isNaN(val as any)) return val as Key
|
||||
const isDigit = val.startsWith("digit")
|
||||
if (isDigit) return val.substring(5) as Key
|
||||
|
||||
// Check if question mark
|
||||
if (val === "?") return "?"
|
||||
|
||||
// Check if question mark
|
||||
if (val === "/") return "/"
|
||||
// Check if slash
|
||||
if (val === "slash") return "/"
|
||||
|
||||
// Check if period
|
||||
if (val === ".") return "."
|
||||
if (val === "period") return "."
|
||||
|
||||
// Check if enter
|
||||
if (val === "enter") return "enter"
|
||||
|
||||
// If no other cases match, this is not a valid key
|
||||
|
||||
@@ -98,7 +98,11 @@ const buildHarPostData = (req: HoppRESTRequest): Har.PostData | undefined => {
|
||||
}
|
||||
}
|
||||
|
||||
export const buildHarRequest = (req: HoppRESTRequest): Har.Request => {
|
||||
export const buildHarRequest = (
|
||||
req: HoppRESTRequest
|
||||
): Har.Request & {
|
||||
postData: Har.PostData & Exclude<Har.PostData, undefined>
|
||||
} => {
|
||||
return {
|
||||
bodySize: -1, // TODO: It would be cool if we can calculate the body size
|
||||
headersSize: -1, // TODO: It would be cool if we can calculate the header size
|
||||
@@ -108,6 +112,9 @@ export const buildHarRequest = (req: HoppRESTRequest): Har.Request => {
|
||||
method: req.method,
|
||||
queryString: buildHarQueryStrings(req),
|
||||
url: req.endpoint,
|
||||
postData: buildHarPostData(req),
|
||||
postData: buildHarPostData(req) ?? {
|
||||
mimeType: "x-unknown",
|
||||
params: [],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import * as HTTPSnippet from "httpsnippet"
|
||||
import { HTTPSnippet } from "httpsnippet"
|
||||
import { HoppRESTRequest } from "@hoppscotch/data"
|
||||
import * as O from "fp-ts/Option"
|
||||
import * as E from "fp-ts/Either"
|
||||
|
||||
@@ -7,6 +7,7 @@ import { HoppRESTResponse } from "../types/HoppRESTResponse"
|
||||
import { getDefaultRESTRequest } from "./default"
|
||||
import { HoppTestResult } from "../types/HoppTestResult"
|
||||
import { platform } from "~/platform"
|
||||
import { nextTick } from "vue"
|
||||
|
||||
export type HoppRESTTab = {
|
||||
id: string
|
||||
@@ -178,7 +179,9 @@ export function closeTab(tabID: string) {
|
||||
|
||||
tabOrdering.value.splice(tabOrdering.value.indexOf(tabID), 1)
|
||||
|
||||
tabMap.delete(tabID)
|
||||
nextTick(() => {
|
||||
tabMap.delete(tabID)
|
||||
})
|
||||
}
|
||||
|
||||
export function closeOtherTabs(tabID: string) {
|
||||
|
||||
@@ -28,6 +28,7 @@ export function createHoppApp(el: string | Element, platformDef: PlatformDef) {
|
||||
performMigrations()
|
||||
|
||||
HOPP_MODULES.forEach((mod) => mod.onVueAppInit?.(app))
|
||||
platformDef.addedHoppModules?.forEach((mod) => mod.onVueAppInit?.(app))
|
||||
|
||||
app.mount(el)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="flex w-screen h-screen">
|
||||
<Splitpanes class="no-splitter" :dbl-click-splitter="false" horizontal>
|
||||
<Pane v-if="!zenMode" style="height: auto">
|
||||
<Pane style="height: auto">
|
||||
<AppHeader />
|
||||
</Pane>
|
||||
<Pane :class="spacerClass" class="flex flex-1 !overflow-auto md:mb-0">
|
||||
@@ -79,9 +79,7 @@ const router = useRouter()
|
||||
const showSearch = ref(false)
|
||||
const showSupport = ref(false)
|
||||
|
||||
const fontSize = useSetting("FONT_SIZE")
|
||||
const expandNavigation = useSetting("EXPAND_NAVIGATION")
|
||||
const zenMode = useSetting("ZEN_MODE")
|
||||
const rightSidebar = useSetting("SIDEBAR")
|
||||
const columnLayout = useSetting("COLUMN_LAYOUT")
|
||||
|
||||
@@ -133,24 +131,9 @@ watch(mdAndLarger, () => {
|
||||
columnLayout.value = true
|
||||
}
|
||||
})
|
||||
|
||||
const spacerClass = computed(() => {
|
||||
if (fontSize.value === "small" && expandNavigation.value)
|
||||
return "spacer-small"
|
||||
if (fontSize.value === "medium" && expandNavigation.value)
|
||||
return "spacer-medium"
|
||||
if (fontSize.value === "large" && expandNavigation.value)
|
||||
return "spacer-large"
|
||||
if (
|
||||
(fontSize.value === "small" ||
|
||||
fontSize.value === "medium" ||
|
||||
fontSize.value === "large") &&
|
||||
!expandNavigation.value
|
||||
)
|
||||
return "spacer-expand"
|
||||
|
||||
return ""
|
||||
})
|
||||
const spacerClass = computed(() =>
|
||||
expandNavigation.value ? "spacer-small" : "spacer-expand"
|
||||
)
|
||||
|
||||
defineActionHandler("modals.search.toggle", () => {
|
||||
showSearch.value = !showSearch.value
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
import { HoppModule } from "."
|
||||
|
||||
export const showChat = () => {
|
||||
;(window as any).$crisp.push([
|
||||
"do",
|
||||
"chat:show",
|
||||
(window as any).$crisp.push(["do", "chat:open"]),
|
||||
])
|
||||
}
|
||||
|
||||
export default <HoppModule>{
|
||||
onVueAppInit() {
|
||||
// TODO: Env variable this ?
|
||||
;(window as any).$crisp = []
|
||||
;(window as any).CRISP_WEBSITE_ID = "3ad30257-c192-4773-955d-fb05a4b41af3"
|
||||
|
||||
const d = document
|
||||
const s = d.createElement("script")
|
||||
|
||||
s.src = "https://client.crisp.chat/l.js"
|
||||
s.async = true
|
||||
d.getElementsByTagName("head")[0].appendChild(s)
|
||||
;(window as any).$crisp.push(["do", "chat:hide"])
|
||||
;(window as any).$crisp.push([
|
||||
"on",
|
||||
"chat:closed",
|
||||
() => {
|
||||
;(window as any).$crisp.push(["do", "chat:hide"])
|
||||
},
|
||||
])
|
||||
},
|
||||
}
|
||||
@@ -53,6 +53,9 @@ export default <HoppModule>{
|
||||
HOPP_MODULES.forEach((mod) => {
|
||||
mod.onBeforeRouteChange?.(to, from, router)
|
||||
})
|
||||
platform.addedHoppModules?.forEach((mod) => {
|
||||
mod.onBeforeRouteChange?.(to, from, router)
|
||||
})
|
||||
})
|
||||
|
||||
// Instead of this a better architecture is for the router
|
||||
@@ -66,10 +69,14 @@ export default <HoppModule>{
|
||||
HOPP_MODULES.forEach((mod) => {
|
||||
mod.onAfterRouteChange?.(to, router)
|
||||
})
|
||||
platform.addedHoppModules?.forEach((mod) => {
|
||||
mod.onAfterRouteChange?.(to, router)
|
||||
})
|
||||
})
|
||||
|
||||
app.use(router)
|
||||
|
||||
HOPP_MODULES.forEach((mod) => mod.onRouterInit?.(app, router))
|
||||
platform.addedHoppModules?.forEach((mod) => mod.onRouterInit?.(app, router))
|
||||
},
|
||||
}
|
||||
|
||||
@@ -68,23 +68,9 @@ const applyAccentColor = (_app: App) => {
|
||||
)
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const applyFontSize = (_app: App) => {
|
||||
const [pref] = useSettingStatic("FONT_SIZE")
|
||||
|
||||
watch(
|
||||
pref,
|
||||
(newPref) => {
|
||||
document.documentElement.setAttribute("data-font-size", newPref)
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
}
|
||||
|
||||
export default <HoppModule>{
|
||||
onVueAppInit(app) {
|
||||
applyColorMode(app)
|
||||
applyAccentColor(app)
|
||||
applyFontSize(app)
|
||||
},
|
||||
}
|
||||
|
||||
@@ -23,10 +23,6 @@ export const HoppAccentColors = [
|
||||
|
||||
export type HoppAccentColor = (typeof HoppAccentColors)[number]
|
||||
|
||||
export const HoppFontSizes = ["small", "medium", "large"] as const
|
||||
|
||||
export type HoppFontSize = (typeof HoppFontSizes)[number]
|
||||
|
||||
export type SettingsDef = {
|
||||
syncCollections: boolean
|
||||
syncHistory: boolean
|
||||
@@ -49,8 +45,6 @@ export type SettingsDef = {
|
||||
EXPAND_NAVIGATION: boolean
|
||||
SIDEBAR: boolean
|
||||
SIDEBAR_ON_LEFT: boolean
|
||||
ZEN_MODE: boolean
|
||||
FONT_SIZE: HoppFontSize
|
||||
COLUMN_LAYOUT: boolean
|
||||
}
|
||||
|
||||
@@ -76,8 +70,6 @@ export const getDefaultSettings = (): SettingsDef => ({
|
||||
EXPAND_NAVIGATION: true,
|
||||
SIDEBAR: true,
|
||||
SIDEBAR_ON_LEFT: true,
|
||||
ZEN_MODE: false,
|
||||
FONT_SIZE: "small",
|
||||
COLUMN_LAYOUT: true,
|
||||
})
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
@open-rename-modal="openReqRenameModal(tab)"
|
||||
@close-tab="removeTab(tab.id)"
|
||||
@close-other-tabs="closeOtherTabsAction(tab.id)"
|
||||
@duplicate-tab="duplicateTab(tab)"
|
||||
@duplicate-tab="duplicateTab(tab.id)"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -203,12 +203,15 @@ const renameReqName = () => {
|
||||
showRenamingReqNameModalForTabID.value = undefined
|
||||
}
|
||||
|
||||
const duplicateTab = (tab: HoppGQLTab) => {
|
||||
const newTab = createNewTab({
|
||||
request: tab.document.request,
|
||||
isDirty: true,
|
||||
})
|
||||
currentTabID.value = newTab.id
|
||||
const duplicateTab = (tabID: string) => {
|
||||
const tab = getTabRef(tabID)
|
||||
if (tab.value) {
|
||||
const newTab = createNewTab({
|
||||
request: tab.value.document.request,
|
||||
isDirty: true,
|
||||
})
|
||||
currentTabID.value = newTab.id
|
||||
}
|
||||
}
|
||||
|
||||
defineActionHandler("gql.request.open", ({ request, saveContext }) => {
|
||||
@@ -218,4 +221,19 @@ defineActionHandler("gql.request.open", ({ request, saveContext }) => {
|
||||
isDirty: false,
|
||||
})
|
||||
})
|
||||
|
||||
defineActionHandler("request.rename", () => {
|
||||
openReqRenameModal(getTabRef(currentTabID.value).value!)
|
||||
})
|
||||
|
||||
defineActionHandler("tab.duplicate-tab", ({ tabID }) => {
|
||||
duplicateTab(tabID ?? currentTabID.value)
|
||||
})
|
||||
defineActionHandler("tab.close-current", () => {
|
||||
removeTab(currentTabID.value)
|
||||
})
|
||||
defineActionHandler("tab.close-other", () => {
|
||||
closeOtherTabs(currentTabID.value)
|
||||
})
|
||||
defineActionHandler("tab.open-new", addNewTab)
|
||||
</script>
|
||||
|
||||
@@ -94,7 +94,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted, onBeforeUnmount, onBeforeMount, watch } from "vue"
|
||||
import { ref, onMounted, onBeforeUnmount, onBeforeMount } from "vue"
|
||||
import { safelyExtractRESTRequest } from "@hoppscotch/data"
|
||||
import { translateExtURLParams } from "~/helpers/RESTExtURLParams"
|
||||
import { useRoute } from "vue-router"
|
||||
@@ -140,8 +140,8 @@ import { useService } from "dioc/vue"
|
||||
import { InspectionService } from "~/services/inspection"
|
||||
import { HeaderInspectorService } from "~/services/inspection/inspectors/header.inspector"
|
||||
import { EnvironmentInspectorService } from "~/services/inspection/inspectors/environment.inspector"
|
||||
import { URLInspectorService } from "~/services/inspection/inspectors/url.inspector"
|
||||
import { ResponseInspectorService } from "~/services/inspection/inspectors/response.inspector"
|
||||
import { cloneDeep } from "lodash-es"
|
||||
|
||||
const savingRequest = ref(false)
|
||||
const confirmingCloseForTabID = ref<string | null>(null)
|
||||
@@ -215,6 +215,8 @@ const sortTabs = (e: { oldIndex: number; newIndex: number }) => {
|
||||
updateTabOrdering(e.oldIndex, e.newIndex)
|
||||
}
|
||||
|
||||
const inspectionService = useService(InspectionService)
|
||||
|
||||
const removeTab = (tabID: string) => {
|
||||
const tabState = getTabRef(tabID).value
|
||||
|
||||
@@ -227,11 +229,14 @@ const removeTab = (tabID: string) => {
|
||||
}
|
||||
|
||||
const closeOtherTabsAction = (tabID: string) => {
|
||||
const isTabDirty = getTabRef(tabID).value?.document.isDirty
|
||||
const dirtyTabCount = getDirtyTabsCount()
|
||||
// If current tab is dirty, so we need to subtract 1 from the dirty tab count
|
||||
const balanceDirtyTabCount = isTabDirty ? dirtyTabCount - 1 : dirtyTabCount
|
||||
// If there are dirty tabs, show the confirm modal
|
||||
if (dirtyTabCount > 0) {
|
||||
if (balanceDirtyTabCount > 0) {
|
||||
confirmingCloseAllTabs.value = true
|
||||
unsavedTabsCount.value = dirtyTabCount
|
||||
unsavedTabsCount.value = balanceDirtyTabCount
|
||||
exceptedTabID.value = tabID
|
||||
} else {
|
||||
closeOtherTabs(tabID)
|
||||
@@ -242,7 +247,7 @@ const duplicateTab = (tabID: string) => {
|
||||
const tab = getTabRef(tabID)
|
||||
if (tab.value) {
|
||||
const newTab = createNewTab({
|
||||
request: tab.value.document.request,
|
||||
request: cloneDeep(tab.value.document.request),
|
||||
isDirty: true,
|
||||
})
|
||||
currentTabID.value = newTab.id
|
||||
@@ -460,22 +465,22 @@ defineActionHandler("rest.request.open", ({ doc }) => {
|
||||
createNewTab(doc)
|
||||
})
|
||||
|
||||
defineActionHandler("rest.request.rename", openReqRenameModal)
|
||||
defineActionHandler("request.duplicate-tab", ({ tabID }) => {
|
||||
duplicateTab(tabID)
|
||||
defineActionHandler("request.rename", openReqRenameModal)
|
||||
defineActionHandler("tab.duplicate-tab", ({ tabID }) => {
|
||||
duplicateTab(tabID ?? currentTabID.value)
|
||||
})
|
||||
defineActionHandler("tab.close-current", () => {
|
||||
removeTab(currentTabID.value)
|
||||
})
|
||||
defineActionHandler("tab.close-other", () => {
|
||||
closeOtherTabs(currentTabID.value)
|
||||
})
|
||||
defineActionHandler("tab.open-new", addNewTab)
|
||||
|
||||
const inspectionService = useService(InspectionService)
|
||||
useService(HeaderInspectorService)
|
||||
useService(EnvironmentInspectorService)
|
||||
useService(URLInspectorService)
|
||||
useService(ResponseInspectorService)
|
||||
|
||||
watch(
|
||||
() => currentTabID.value,
|
||||
() => {
|
||||
inspectionService.initializeTabInspectors()
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
for (const inspectorDef of platform.additionalInspectors ?? []) {
|
||||
useService(inspectorDef.service)
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="container space-y-8 divide-y divide-dividerLight">
|
||||
<div class="container divide-y divide-dividerLight">
|
||||
<div class="md:grid md:gap-4 md:grid-cols-3">
|
||||
<div class="p-8 md:col-span-1">
|
||||
<h3 class="heading">
|
||||
@@ -36,14 +36,6 @@
|
||||
<SmartAccentModePicker />
|
||||
</div>
|
||||
</section>
|
||||
<section>
|
||||
<h4 class="font-semibold text-secondaryDark">
|
||||
{{ t("settings.font_size") }}
|
||||
</h4>
|
||||
<div class="mt-4">
|
||||
<SmartFontSizePicker />
|
||||
</div>
|
||||
</section>
|
||||
<section>
|
||||
<h4 class="font-semibold text-secondaryDark">
|
||||
{{ t("settings.language") }}
|
||||
@@ -90,14 +82,6 @@
|
||||
{{ t("settings.sidebar_on_left") }}
|
||||
</HoppSmartToggle>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<HoppSmartToggle
|
||||
:on="ZEN_MODE"
|
||||
@change="toggleSetting('ZEN_MODE')"
|
||||
>
|
||||
{{ t("layout.zen_mode") }}
|
||||
</HoppSmartToggle>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
@@ -178,7 +162,6 @@ const PROXY_URL = useSetting("PROXY_URL")
|
||||
const TELEMETRY_ENABLED = useSetting("TELEMETRY_ENABLED")
|
||||
const EXPAND_NAVIGATION = useSetting("EXPAND_NAVIGATION")
|
||||
const SIDEBAR_ON_LEFT = useSetting("SIDEBAR_ON_LEFT")
|
||||
const ZEN_MODE = useSetting("ZEN_MODE")
|
||||
|
||||
const confirmRemove = ref(false)
|
||||
|
||||
@@ -186,10 +169,6 @@ const proxySettings = computed(() => ({
|
||||
url: PROXY_URL.value,
|
||||
}))
|
||||
|
||||
watch(ZEN_MODE, (mode) => {
|
||||
applySetting("EXPAND_NAVIGATION", !mode)
|
||||
})
|
||||
|
||||
watch(
|
||||
proxySettings,
|
||||
({ url }) => {
|
||||
|
||||
@@ -7,9 +7,12 @@ import { HistoryPlatformDef } from "./history"
|
||||
import { TabStatePlatformDef } from "./tab"
|
||||
import { AnalyticsPlatformDef } from "./analytics"
|
||||
import { InterceptorsPlatformDef } from "./interceptors"
|
||||
import { HoppModule } from "~/modules"
|
||||
import { InspectorsPlatformDef } from "./inspectors"
|
||||
|
||||
export type PlatformDef = {
|
||||
ui?: UIPlatformDef
|
||||
addedHoppModules?: HoppModule[]
|
||||
auth: AuthPlatformDef
|
||||
analytics?: AnalyticsPlatformDef
|
||||
sync: {
|
||||
@@ -20,6 +23,7 @@ export type PlatformDef = {
|
||||
tabState: TabStatePlatformDef
|
||||
}
|
||||
interceptors: InterceptorsPlatformDef
|
||||
additionalInspectors?: InspectorsPlatformDef
|
||||
platformFeatureFlags: {
|
||||
exportAsGIST: boolean
|
||||
}
|
||||
|
||||
16
packages/hoppscotch-common/src/platform/inspectors.ts
Normal file
16
packages/hoppscotch-common/src/platform/inspectors.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { Service } from "dioc"
|
||||
import { Inspector } from "~/services/inspection"
|
||||
|
||||
/**
|
||||
* Defines an added interceptor by the platform
|
||||
*/
|
||||
export type PlatformInspectorsDef = {
|
||||
// We are keeping this as the only mode for now
|
||||
// So that if we choose to add other modes, we can do without breaking
|
||||
type: "service"
|
||||
service: typeof Service<unknown> & { ID: string } & {
|
||||
new (): Service & Inspector
|
||||
}
|
||||
}
|
||||
|
||||
export type InspectorsPlatformDef = PlatformInspectorsDef[]
|
||||
@@ -1,15 +1,17 @@
|
||||
import { TestContainer } from "dioc/testing"
|
||||
import { describe, expect, it, vi } from "vitest"
|
||||
import { URLInspectorService } from "../url.inspector"
|
||||
import { InspectionService } from "../../index"
|
||||
import { ExtensionInspectorService } from "../extension.inspector"
|
||||
import { InspectionService } from "~/services/inspection"
|
||||
import { getDefaultRESTRequest } from "~/helpers/rest/default"
|
||||
import { ref } from "vue"
|
||||
import { ExtensionInterceptorService } from "~/platform/std/interceptors/extension"
|
||||
|
||||
vi.mock("~/modules/i18n", () => ({
|
||||
__esModule: true,
|
||||
getI18n: () => (x: string) => x,
|
||||
}))
|
||||
|
||||
describe("URLInspectorService", () => {
|
||||
describe("ExtensionInspectorService", () => {
|
||||
it("registers with the inspection service upon initialization", () => {
|
||||
const container = new TestContainer()
|
||||
|
||||
@@ -19,7 +21,7 @@ describe("URLInspectorService", () => {
|
||||
registerInspector: registerInspectorFn,
|
||||
})
|
||||
|
||||
const urlInspector = container.bind(URLInspectorService)
|
||||
const urlInspector = container.bind(ExtensionInspectorService)
|
||||
|
||||
expect(registerInspectorFn).toHaveBeenCalledOnce()
|
||||
expect(registerInspectorFn).toHaveBeenCalledWith(urlInspector)
|
||||
@@ -28,55 +30,57 @@ describe("URLInspectorService", () => {
|
||||
describe("getInspectorFor", () => {
|
||||
it("should return an inspector result when localhost is in URL and extension is not available", () => {
|
||||
const container = new TestContainer()
|
||||
const urlInspector = container.bind(URLInspectorService)
|
||||
const urlInspector = container.bind(ExtensionInspectorService)
|
||||
|
||||
const req = {
|
||||
const req = ref({
|
||||
...getDefaultRESTRequest(),
|
||||
endpoint: "http://localhost:8000/api/data",
|
||||
}
|
||||
})
|
||||
|
||||
const result = urlInspector.getInspectorFor(req)
|
||||
const result = urlInspector.getInspections(req)
|
||||
|
||||
expect(result).toContainEqual(
|
||||
expect(result.value).toContainEqual(
|
||||
expect.objectContaining({ id: "url", isApplicable: true })
|
||||
)
|
||||
})
|
||||
|
||||
it("should not return an inspector result when localhost is not in URL", () => {
|
||||
const container = new TestContainer()
|
||||
const urlInspector = container.bind(URLInspectorService)
|
||||
|
||||
const req = {
|
||||
container.bindMock(ExtensionInterceptorService, {
|
||||
extensionStatus: ref("unknown-origin" as const),
|
||||
})
|
||||
|
||||
const urlInspector = container.bind(ExtensionInspectorService)
|
||||
|
||||
const req = ref({
|
||||
...getDefaultRESTRequest(),
|
||||
endpoint: "http://example.com/api/data",
|
||||
}
|
||||
})
|
||||
|
||||
const result = urlInspector.getInspectorFor(req)
|
||||
const result = urlInspector.getInspections(req)
|
||||
|
||||
expect(result).toHaveLength(0)
|
||||
expect(result.value).toHaveLength(0)
|
||||
})
|
||||
|
||||
it("should add the correct text to the results when extension is not installed", () => {
|
||||
vi.mock("~/newstore/HoppExtension", async () => {
|
||||
const { BehaviorSubject }: any = await vi.importActual("rxjs")
|
||||
|
||||
return {
|
||||
__esModule: true,
|
||||
extensionStatus$: new BehaviorSubject("waiting"),
|
||||
}
|
||||
})
|
||||
const container = new TestContainer()
|
||||
const urlInspector = container.bind(URLInspectorService)
|
||||
|
||||
const req = {
|
||||
container.bindMock(ExtensionInterceptorService, {
|
||||
extensionStatus: ref("waiting" as const),
|
||||
})
|
||||
|
||||
const urlInspector = container.bind(ExtensionInspectorService)
|
||||
|
||||
const req = ref({
|
||||
...getDefaultRESTRequest(),
|
||||
endpoint: "http://localhost:8000/api/data",
|
||||
}
|
||||
})
|
||||
|
||||
const result = urlInspector.getInspectorFor(req)
|
||||
const result = urlInspector.getInspections(req)
|
||||
|
||||
expect(result).toHaveLength(1)
|
||||
expect(result[0]).toMatchObject({
|
||||
expect(result.value).toHaveLength(1)
|
||||
expect(result.value[0]).toMatchObject({
|
||||
text: { type: "text", text: "inspections.url.extension_not_installed" },
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,107 @@
|
||||
import { Service } from "dioc"
|
||||
import {
|
||||
InspectionService,
|
||||
Inspector,
|
||||
InspectorResult,
|
||||
} from "~/services/inspection"
|
||||
import { getI18n } from "~/modules/i18n"
|
||||
import { HoppRESTRequest } from "@hoppscotch/data"
|
||||
import { computed, markRaw } from "vue"
|
||||
import IconAlertTriangle from "~icons/lucide/alert-triangle"
|
||||
import { Ref } from "vue"
|
||||
import { InterceptorService } from "~/services/interceptor.service"
|
||||
import { ExtensionInterceptorService } from "~/platform/std/interceptors/extension"
|
||||
|
||||
/**
|
||||
* This inspector is responsible for inspecting the URL of a request.
|
||||
* It checks if the URL contains localhost and if the extension is installed.
|
||||
* It also provides an action to enable the extension.
|
||||
*
|
||||
* NOTE: Initializing this service registers it as a inspector with the Inspection Service.
|
||||
*/
|
||||
export class ExtensionInspectorService extends Service implements Inspector {
|
||||
public static readonly ID = "EXTENSION_INSPECTOR_SERVICE"
|
||||
|
||||
private t = getI18n()
|
||||
|
||||
public readonly inspectorID = "extension"
|
||||
|
||||
private readonly interceptorService = this.bind(InterceptorService)
|
||||
private readonly extensionService = this.bind(ExtensionInterceptorService)
|
||||
|
||||
private readonly inspection = this.bind(InspectionService)
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
|
||||
this.inspection.registerInspector(this)
|
||||
}
|
||||
|
||||
getInspections(req: Readonly<Ref<HoppRESTRequest>>) {
|
||||
const currentExtensionStatus = this.extensionService.extensionStatus
|
||||
|
||||
const isExtensionInstalled = computed(
|
||||
() => currentExtensionStatus.value === "available"
|
||||
)
|
||||
|
||||
const EXTENSIONS_ENABLED = computed(
|
||||
() => this.interceptorService.currentInterceptorID.value === "extension"
|
||||
)
|
||||
|
||||
return computed(() => {
|
||||
const results: InspectorResult[] = []
|
||||
|
||||
const url = req.value.endpoint
|
||||
const localHostURLs = ["localhost", "127.0.0.1"]
|
||||
|
||||
const isContainLocalhost = localHostURLs.some((host) =>
|
||||
url.includes(host)
|
||||
)
|
||||
|
||||
if (
|
||||
isContainLocalhost &&
|
||||
(!EXTENSIONS_ENABLED.value || !isExtensionInstalled.value)
|
||||
) {
|
||||
let text
|
||||
|
||||
if (!isExtensionInstalled.value) {
|
||||
if (currentExtensionStatus.value === "unknown-origin") {
|
||||
text = this.t("inspections.url.extension_unknown_origin")
|
||||
} else {
|
||||
text = this.t("inspections.url.extension_not_installed")
|
||||
}
|
||||
} else if (!EXTENSIONS_ENABLED.value) {
|
||||
text = this.t("inspections.url.extention_not_enabled")
|
||||
} else {
|
||||
text = this.t("inspections.url.localhost")
|
||||
}
|
||||
|
||||
results.push({
|
||||
id: "url",
|
||||
icon: markRaw(IconAlertTriangle),
|
||||
text: {
|
||||
type: "text",
|
||||
text: text,
|
||||
},
|
||||
action: {
|
||||
text: this.t("inspections.url.extention_enable_action"),
|
||||
apply: () => {
|
||||
this.interceptorService.currentInterceptorID.value = "extension"
|
||||
},
|
||||
},
|
||||
severity: 2,
|
||||
isApplicable: true,
|
||||
locations: {
|
||||
type: "url",
|
||||
},
|
||||
doc: {
|
||||
text: this.t("action.learn_more"),
|
||||
link: "https://docs.hoppscotch.io/documentation/features/interceptor#browser-extension",
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return results
|
||||
})
|
||||
}
|
||||
}
|
||||
25
packages/hoppscotch-common/src/platform/std/ui/footerItem.ts
Normal file
25
packages/hoppscotch-common/src/platform/std/ui/footerItem.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { HoppFooterMenuItem } from "../../ui"
|
||||
import IconGift from "~icons/lucide/gift"
|
||||
import IconActivity from "~icons/lucide/activity"
|
||||
|
||||
export const whatsNew: HoppFooterMenuItem = {
|
||||
id: "whats-new",
|
||||
text: (t) => t("app.whats_new"),
|
||||
icon: IconGift,
|
||||
action: {
|
||||
type: "link",
|
||||
href: "https://docs.hoppscotch.io/documentation/changelog",
|
||||
},
|
||||
}
|
||||
|
||||
export const status: HoppFooterMenuItem = {
|
||||
id: "status",
|
||||
text: (t) => t("app.status"),
|
||||
icon: IconActivity,
|
||||
action: {
|
||||
type: "link",
|
||||
href: "https://status.hoppscotch.io",
|
||||
},
|
||||
}
|
||||
|
||||
export const stdFooterItems = [whatsNew, status]
|
||||
@@ -0,0 +1,100 @@
|
||||
import { invokeAction } from "~/helpers/actions"
|
||||
import { HoppSupportOptionsMenuItem } from "~/platform/ui"
|
||||
import IconBook from "~icons/lucide/book"
|
||||
import IconGift from "~icons/lucide/gift"
|
||||
import IconZap from "~icons/lucide/zap"
|
||||
import IconGitHub from "~icons/lucide/github"
|
||||
import IconTwitter from "~icons/brands/twitter"
|
||||
import IconDiscord from "~icons/brands/discord"
|
||||
import IconUserPlus from "~icons/lucide/user-plus"
|
||||
|
||||
export const documentation: HoppSupportOptionsMenuItem = {
|
||||
id: "documentation",
|
||||
text: (t) => t("app.documentation"),
|
||||
subtitle: (t) => t("support.documentation"),
|
||||
icon: IconBook,
|
||||
action: {
|
||||
type: "link",
|
||||
href: "https://docs.hoppscotch.io",
|
||||
},
|
||||
}
|
||||
|
||||
export const shortcuts: HoppSupportOptionsMenuItem = {
|
||||
id: "shortcuts",
|
||||
text: (t) => t("app.keyboard_shortcuts"),
|
||||
subtitle: (t) => t("support.shortcuts"),
|
||||
icon: IconZap,
|
||||
action: {
|
||||
type: "custom",
|
||||
do() {
|
||||
invokeAction("flyouts.keybinds.toggle")
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const changelog: HoppSupportOptionsMenuItem = {
|
||||
id: "changelog",
|
||||
text: (t) => t("app.whats_new"),
|
||||
subtitle: (t) => t("support.changelog"),
|
||||
icon: IconGift,
|
||||
action: {
|
||||
type: "link",
|
||||
href: "https://docs.hoppscotch.io/documentation/changelog",
|
||||
},
|
||||
}
|
||||
|
||||
export const github: HoppSupportOptionsMenuItem = {
|
||||
id: "github",
|
||||
text: (t) => t("app.github"),
|
||||
subtitle: (t) => t("support.github"),
|
||||
icon: IconGitHub,
|
||||
action: {
|
||||
type: "link",
|
||||
href: "https://hoppscotch.io/github",
|
||||
},
|
||||
}
|
||||
|
||||
export const discord: HoppSupportOptionsMenuItem = {
|
||||
id: "discord",
|
||||
text: (t) => t("app.join_discord_community"),
|
||||
subtitle: (t) => t("support.community"),
|
||||
icon: IconDiscord,
|
||||
action: {
|
||||
type: "link",
|
||||
href: "https://hoppscotch.io/discord",
|
||||
},
|
||||
}
|
||||
|
||||
export const twitter: HoppSupportOptionsMenuItem = {
|
||||
id: "discord",
|
||||
text: (t) => t("app.twitter"),
|
||||
subtitle: (t) => t("support.twitter"),
|
||||
icon: IconTwitter,
|
||||
action: {
|
||||
type: "link",
|
||||
href: "https://hoppscotch.io/twitter",
|
||||
},
|
||||
}
|
||||
|
||||
export const invite: HoppSupportOptionsMenuItem = {
|
||||
id: "invite",
|
||||
text: (t) => t("app.invite"),
|
||||
subtitle: (t) => t("shortcut.miscellaneous.invite"),
|
||||
icon: IconUserPlus,
|
||||
action: {
|
||||
type: "custom",
|
||||
do() {
|
||||
invokeAction("modals.share.toggle")
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const stdSupportOptionItems: HoppSupportOptionsMenuItem[] = [
|
||||
documentation,
|
||||
shortcuts,
|
||||
changelog,
|
||||
github,
|
||||
discord,
|
||||
twitter,
|
||||
invite,
|
||||
]
|
||||
@@ -1,4 +1,20 @@
|
||||
import { Ref } from "vue"
|
||||
import { Ref, Component } from "vue"
|
||||
import { getI18n } from "~/modules/i18n"
|
||||
|
||||
export type HoppFooterMenuItem = {
|
||||
id: string
|
||||
text: (t: ReturnType<typeof getI18n>) => string
|
||||
icon: Component
|
||||
action: { type: "link"; href: string } | { type: "custom"; do: () => void }
|
||||
}
|
||||
|
||||
export type HoppSupportOptionsMenuItem = {
|
||||
id: string
|
||||
text: (t: ReturnType<typeof getI18n>) => string
|
||||
subtitle: (t: ReturnType<typeof getI18n>) => string
|
||||
icon: Component
|
||||
action: { type: "link"; href: string } | { type: "custom"; do: () => void }
|
||||
}
|
||||
|
||||
export type UIPlatformDef = {
|
||||
appHeader?: {
|
||||
@@ -6,4 +22,15 @@ export type UIPlatformDef = {
|
||||
paddingLeft?: Ref<string>
|
||||
}
|
||||
onCodemirrorInstanceMount?: (element: HTMLElement) => void
|
||||
|
||||
/**
|
||||
* Additonal menu items shown in the "Help and Feedback" menu
|
||||
* in the app footer.
|
||||
*/
|
||||
additionalFooterMenuItems?: HoppFooterMenuItem[]
|
||||
|
||||
/**
|
||||
* Additional Support Options menu items shown in the app header
|
||||
*/
|
||||
additionalSupportOptionsMenuItems?: HoppSupportOptionsMenuItem[]
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ describe("EnvironmentMenuService", () => {
|
||||
expect(actionsMock.invokeAction).toHaveBeenCalledWith(
|
||||
"modals.environment.add",
|
||||
{
|
||||
envName: "test",
|
||||
envName: "",
|
||||
variableName: test,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -42,7 +42,7 @@ export class EnvironmentMenuService extends Service implements ContextMenu {
|
||||
icon: markRaw(IconPlusCircle),
|
||||
action: () => {
|
||||
invokeAction("modals.environment.add", {
|
||||
envName: "test",
|
||||
envName: "",
|
||||
variableName: text,
|
||||
})
|
||||
},
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { describe, it, expect } from "vitest"
|
||||
import { Inspector, InspectionService, InspectorResult } from "../"
|
||||
import { TestContainer } from "dioc/testing"
|
||||
import { ref } from "vue"
|
||||
|
||||
const inspectorResultMock: InspectorResult[] = [
|
||||
{
|
||||
@@ -21,7 +22,7 @@ const inspectorResultMock: InspectorResult[] = [
|
||||
|
||||
const testInspector: Inspector = {
|
||||
inspectorID: "inspector1",
|
||||
getInspectorFor: () => inspectorResultMock,
|
||||
getInspections: () => ref(inspectorResultMock),
|
||||
}
|
||||
|
||||
describe("InspectionService", () => {
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { HoppRESTRequest } from "@hoppscotch/data"
|
||||
import { refDebounced } from "@vueuse/core"
|
||||
import { Service } from "dioc"
|
||||
import { computed, markRaw, reactive } from "vue"
|
||||
import { Component, Ref, ref, watch } from "vue"
|
||||
import { currentActiveTab, currentTabID } from "~/helpers/rest/tab"
|
||||
import { currentActiveTab } from "~/helpers/rest/tab"
|
||||
import { HoppRESTResponse } from "~/helpers/types/HoppRESTResponse"
|
||||
|
||||
/**
|
||||
@@ -80,15 +82,16 @@ export interface Inspector {
|
||||
*/
|
||||
inspectorID: string
|
||||
/**
|
||||
* Returns the inspector results for the request
|
||||
* @param req The request to inspect
|
||||
* @param res The response to inspect
|
||||
* @returns The inspector results
|
||||
* Returns the inspector results for the request.
|
||||
* NOTE: The refs passed down are readonly and are debounced to avoid performance issues
|
||||
* @param req The ref to the request to inspect
|
||||
* @param res The ref to the response to inspect
|
||||
* @returns The ref to the inspector results
|
||||
*/
|
||||
getInspectorFor: (
|
||||
req: HoppRESTRequest,
|
||||
res?: HoppRESTResponse
|
||||
) => InspectorResult[]
|
||||
getInspections: (
|
||||
req: Readonly<Ref<HoppRESTRequest>>,
|
||||
res: Readonly<Ref<HoppRESTResponse | null | undefined>>
|
||||
) => Ref<InspectorResult[]>
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -98,38 +101,73 @@ export interface Inspector {
|
||||
export class InspectionService extends Service {
|
||||
public static readonly ID = "INSPECTION_SERVICE"
|
||||
|
||||
private inspectors: Map<string, Inspector> = new Map()
|
||||
private inspectors: Map<string, Inspector> = reactive(new Map())
|
||||
|
||||
public tabs: Ref<Map<string, InspectorResult[]>> = ref(new Map())
|
||||
private tabs: Ref<Map<string, InspectorResult[]>> = ref(new Map())
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
|
||||
this.initializeListeners()
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a inspector with the inspection service
|
||||
* @param inspector The inspector instance to register
|
||||
*/
|
||||
public registerInspector(inspector: Inspector) {
|
||||
this.inspectors.set(inspector.inspectorID, inspector)
|
||||
// markRaw is required here so that the inspector is not made reactive
|
||||
this.inspectors.set(inspector.inspectorID, markRaw(inspector))
|
||||
}
|
||||
|
||||
public initializeTabInspectors() {
|
||||
private initializeListeners() {
|
||||
watch(
|
||||
currentActiveTab.value,
|
||||
(tab) => {
|
||||
if (!tab) return
|
||||
const req = currentActiveTab.value.document.request
|
||||
const res = currentActiveTab.value.response
|
||||
const inspectors = Array.from(this.inspectors.values()).map((x) =>
|
||||
x.getInspectorFor(req, res)
|
||||
() => [this.inspectors.entries(), currentActiveTab.value.id],
|
||||
() => {
|
||||
const reqRef = computed(() => currentActiveTab.value.document.request)
|
||||
const resRef = computed(() => currentActiveTab.value.response)
|
||||
|
||||
const debouncedReq = refDebounced(reqRef, 1000, { maxWait: 2000 })
|
||||
const debouncedRes = refDebounced(resRef, 1000, { maxWait: 2000 })
|
||||
|
||||
const inspectorRefs = Array.from(this.inspectors.values()).map((x) =>
|
||||
x.getInspections(debouncedReq, debouncedRes)
|
||||
)
|
||||
this.tabs.value.set(
|
||||
currentTabID.value,
|
||||
inspectors.flatMap((x) => x)
|
||||
|
||||
const activeInspections = computed(() =>
|
||||
inspectorRefs.flatMap((x) => x!.value)
|
||||
)
|
||||
|
||||
watch(
|
||||
() => [...inspectorRefs.flatMap((x) => x!.value)],
|
||||
() => {
|
||||
this.tabs.value.set(
|
||||
currentActiveTab.value.id,
|
||||
activeInspections.value
|
||||
)
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
},
|
||||
{ immediate: true, deep: true }
|
||||
{ immediate: true, flush: "pre" }
|
||||
)
|
||||
}
|
||||
|
||||
public deleteTabInspectorResult(tabID: string) {
|
||||
// TODO: Move Tabs into a service and implement this with an event instead
|
||||
this.tabs.value.delete(tabID)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reactive view into the inspector results for a specific tab
|
||||
* @param tabID The ID of the tab to get the results for
|
||||
* @param filter The filter to apply to the results.
|
||||
* @returns The ref into the inspector results, if the tab doesn't exist, a ref into an empty array is returned
|
||||
*/
|
||||
public getResultViewFor(
|
||||
tabID: string,
|
||||
filter: (x: InspectorResult) => boolean = () => true
|
||||
) {
|
||||
return computed(() => this.tabs.value.get(tabID)?.filter(filter) ?? [])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,16 +3,23 @@ import { describe, expect, it, vi } from "vitest"
|
||||
import { EnvironmentInspectorService } from "../environment.inspector"
|
||||
import { InspectionService } from "../../index"
|
||||
import { getDefaultRESTRequest } from "~/helpers/rest/default"
|
||||
import { ref } from "vue"
|
||||
|
||||
vi.mock("~/modules/i18n", () => ({
|
||||
__esModule: true,
|
||||
getI18n: () => (x: string) => x,
|
||||
}))
|
||||
|
||||
vi.mock("~/newstore/environments", () => ({
|
||||
__esModule: true,
|
||||
getAggregateEnvs: () => [{ key: "EXISTING_ENV_VAR", value: "test_value" }],
|
||||
}))
|
||||
vi.mock("~/newstore/environments", async () => {
|
||||
const { BehaviorSubject }: any = await vi.importActual("rxjs")
|
||||
|
||||
return {
|
||||
__esModule: true,
|
||||
aggregateEnvs$: new BehaviorSubject([
|
||||
{ key: "EXISTING_ENV_VAR", value: "test_value" },
|
||||
]),
|
||||
}
|
||||
})
|
||||
|
||||
describe("EnvironmentInspectorService", () => {
|
||||
it("registers with the inspection service upon initialization", () => {
|
||||
@@ -35,14 +42,14 @@ describe("EnvironmentInspectorService", () => {
|
||||
const container = new TestContainer()
|
||||
const envInspector = container.bind(EnvironmentInspectorService)
|
||||
|
||||
const req = {
|
||||
const req = ref({
|
||||
...getDefaultRESTRequest(),
|
||||
endpoint: "<<UNDEFINED_ENV_VAR>>",
|
||||
}
|
||||
})
|
||||
|
||||
const result = envInspector.getInspectorFor(req)
|
||||
const result = envInspector.getInspections(req)
|
||||
|
||||
expect(result).toContainEqual(
|
||||
expect(result.value).toContainEqual(
|
||||
expect.objectContaining({
|
||||
id: "environment",
|
||||
isApplicable: true,
|
||||
@@ -58,31 +65,31 @@ describe("EnvironmentInspectorService", () => {
|
||||
const container = new TestContainer()
|
||||
const envInspector = container.bind(EnvironmentInspectorService)
|
||||
|
||||
const req = {
|
||||
const req = ref({
|
||||
...getDefaultRESTRequest(),
|
||||
endpoint: "<<EXISTING_ENV_VAR>>",
|
||||
}
|
||||
})
|
||||
|
||||
const result = envInspector.getInspectorFor(req)
|
||||
const result = envInspector.getInspections(req)
|
||||
|
||||
expect(result).toHaveLength(0)
|
||||
expect(result.value).toHaveLength(0)
|
||||
})
|
||||
|
||||
it("should return an inspector result when the headers contain undefined environment variables", () => {
|
||||
const container = new TestContainer()
|
||||
const envInspector = container.bind(EnvironmentInspectorService)
|
||||
|
||||
const req = {
|
||||
const req = ref({
|
||||
...getDefaultRESTRequest(),
|
||||
endpoint: "http://example.com/api/data",
|
||||
headers: [
|
||||
{ key: "<<UNDEFINED_ENV_VAR>>", value: "some-value", active: true },
|
||||
],
|
||||
}
|
||||
})
|
||||
|
||||
const result = envInspector.getInspectorFor(req)
|
||||
const result = envInspector.getInspections(req)
|
||||
|
||||
expect(result).toContainEqual(
|
||||
expect(result.value).toContainEqual(
|
||||
expect.objectContaining({
|
||||
id: "environment",
|
||||
isApplicable: true,
|
||||
@@ -98,34 +105,34 @@ describe("EnvironmentInspectorService", () => {
|
||||
const container = new TestContainer()
|
||||
const envInspector = container.bind(EnvironmentInspectorService)
|
||||
|
||||
const req = {
|
||||
const req = ref({
|
||||
...getDefaultRESTRequest(),
|
||||
endpoint: "http://example.com/api/data",
|
||||
headers: [
|
||||
{ key: "<<EXISTING_ENV_VAR>>", value: "some-value", active: true },
|
||||
],
|
||||
}
|
||||
})
|
||||
|
||||
const result = envInspector.getInspectorFor(req)
|
||||
const result = envInspector.getInspections(req)
|
||||
|
||||
expect(result).toHaveLength(0)
|
||||
expect(result.value).toHaveLength(0)
|
||||
})
|
||||
|
||||
it("should return an inspector result when the params contain undefined environment variables", () => {
|
||||
const container = new TestContainer()
|
||||
const envInspector = container.bind(EnvironmentInspectorService)
|
||||
|
||||
const req = {
|
||||
const req = ref({
|
||||
...getDefaultRESTRequest(),
|
||||
endpoint: "http://example.com/api/data",
|
||||
params: [
|
||||
{ key: "<<UNDEFINED_ENV_VAR>>", value: "some-value", active: true },
|
||||
],
|
||||
}
|
||||
})
|
||||
|
||||
const result = envInspector.getInspectorFor(req)
|
||||
const result = envInspector.getInspections(req)
|
||||
|
||||
expect(result).toContainEqual(
|
||||
expect(result.value).toContainEqual(
|
||||
expect.objectContaining({
|
||||
id: "environment",
|
||||
isApplicable: true,
|
||||
@@ -141,18 +148,18 @@ describe("EnvironmentInspectorService", () => {
|
||||
const container = new TestContainer()
|
||||
const envInspector = container.bind(EnvironmentInspectorService)
|
||||
|
||||
const req = {
|
||||
const req = ref({
|
||||
...getDefaultRESTRequest(),
|
||||
endpoint: "http://example.com/api/data",
|
||||
headers: [],
|
||||
params: [
|
||||
{ key: "<<EXISTING_ENV_VAR>>", value: "some-value", active: true },
|
||||
],
|
||||
}
|
||||
})
|
||||
|
||||
const result = envInspector.getInspectorFor(req)
|
||||
const result = envInspector.getInspections(req)
|
||||
|
||||
expect(result).toHaveLength(0)
|
||||
expect(result.value).toHaveLength(0)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -3,6 +3,7 @@ import { describe, expect, it, vi } from "vitest"
|
||||
import { HeaderInspectorService } from "../header.inspector"
|
||||
import { InspectionService } from "../../index"
|
||||
import { getDefaultRESTRequest } from "~/helpers/rest/default"
|
||||
import { ref } from "vue"
|
||||
|
||||
vi.mock("~/modules/i18n", () => ({
|
||||
__esModule: true,
|
||||
@@ -30,15 +31,15 @@ describe("HeaderInspectorService", () => {
|
||||
const container = new TestContainer()
|
||||
const headerInspector = container.bind(HeaderInspectorService)
|
||||
|
||||
const req = {
|
||||
const req = ref({
|
||||
...getDefaultRESTRequest(),
|
||||
endpoint: "http://example.com/api/data",
|
||||
headers: [{ key: "Cookie", value: "some-cookie", active: true }],
|
||||
}
|
||||
})
|
||||
|
||||
const result = headerInspector.getInspectorFor(req)
|
||||
const result = headerInspector.getInspections(req)
|
||||
|
||||
expect(result).toContainEqual(
|
||||
expect(result.value).toContainEqual(
|
||||
expect.objectContaining({ id: "header", isApplicable: true })
|
||||
)
|
||||
})
|
||||
@@ -47,15 +48,15 @@ describe("HeaderInspectorService", () => {
|
||||
const container = new TestContainer()
|
||||
const headerInspector = container.bind(HeaderInspectorService)
|
||||
|
||||
const req = {
|
||||
const req = ref({
|
||||
...getDefaultRESTRequest(),
|
||||
endpoint: "http://example.com/api/data",
|
||||
headers: [{ key: "Authorization", value: "Bearer abcd", active: true }],
|
||||
}
|
||||
})
|
||||
|
||||
const result = headerInspector.getInspectorFor(req)
|
||||
const result = headerInspector.getInspections(req)
|
||||
|
||||
expect(result).toHaveLength(0)
|
||||
expect(result.value).toHaveLength(0)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -0,0 +1,245 @@
|
||||
import { TestContainer } from "dioc/testing"
|
||||
import { describe, expect, it, beforeEach, afterEach, vi } from "vitest"
|
||||
import { ResponseInspectorService } from "../response.inspector"
|
||||
import { InspectionService } from "../../index"
|
||||
import { getDefaultRESTRequest } from "~/helpers/rest/default"
|
||||
import { ref } from "vue"
|
||||
import { HoppRESTResponse } from "~/helpers/types/HoppRESTResponse"
|
||||
|
||||
vi.mock("~/modules/i18n", () => ({
|
||||
__esModule: true,
|
||||
getI18n: () => (x: string) => x,
|
||||
}))
|
||||
|
||||
describe("ResponseInspectorService", () => {
|
||||
beforeEach(() => {
|
||||
vi.stubGlobal("navigator", {
|
||||
onLine: true,
|
||||
})
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
vi.unstubAllGlobals()
|
||||
})
|
||||
|
||||
it("registers with the inspection service upon initialization", () => {
|
||||
const container = new TestContainer()
|
||||
|
||||
const registerInspectorFn = vi.fn()
|
||||
|
||||
container.bindMock(InspectionService, {
|
||||
registerInspector: registerInspectorFn,
|
||||
})
|
||||
|
||||
const responseInspector = container.bind(ResponseInspectorService)
|
||||
|
||||
expect(registerInspectorFn).toHaveBeenCalledOnce()
|
||||
expect(registerInspectorFn).toHaveBeenCalledWith(responseInspector)
|
||||
})
|
||||
|
||||
describe("getInspectorFor", () => {
|
||||
it("should return an empty array when response is undefined", () => {
|
||||
const container = new TestContainer()
|
||||
const responseInspector = container.bind(ResponseInspectorService)
|
||||
|
||||
const req = ref({
|
||||
...getDefaultRESTRequest(),
|
||||
endpoint: "http://example.com/api/data",
|
||||
})
|
||||
|
||||
const result = responseInspector.getInspections(req, ref(undefined))
|
||||
|
||||
expect(result.value).toHaveLength(0)
|
||||
})
|
||||
|
||||
it("should return an inspector result when response type is not success or status code is not 200 and if the network is not available", () => {
|
||||
const container = new TestContainer()
|
||||
const responseInspector = container.bind(ResponseInspectorService)
|
||||
|
||||
const req = ref({
|
||||
...getDefaultRESTRequest(),
|
||||
endpoint: "http://example.com/api/data",
|
||||
})
|
||||
const res = ref<HoppRESTResponse>({
|
||||
type: "network_fail",
|
||||
error: new Error("test"),
|
||||
req: req.value,
|
||||
})
|
||||
|
||||
vi.stubGlobal("navigator", {
|
||||
onLine: false,
|
||||
})
|
||||
|
||||
const result = responseInspector.getInspections(req, res)
|
||||
|
||||
expect(result.value).toContainEqual(
|
||||
expect.objectContaining({ id: "url", isApplicable: true })
|
||||
)
|
||||
})
|
||||
|
||||
it("should return no inspector result when response type is not success or status code is not 200 and if the network is not available", () => {
|
||||
const container = new TestContainer()
|
||||
const responseInspector = container.bind(ResponseInspectorService)
|
||||
|
||||
const req = ref({
|
||||
...getDefaultRESTRequest(),
|
||||
endpoint: "http://example.com/api/data",
|
||||
})
|
||||
const res = ref<HoppRESTResponse>({
|
||||
type: "network_fail",
|
||||
error: new Error("test"),
|
||||
req: req.value,
|
||||
})
|
||||
|
||||
const result = responseInspector.getInspections(req, res)
|
||||
|
||||
expect(result.value).toHaveLength(0)
|
||||
})
|
||||
|
||||
it("should handle network_fail responses and return nothing when no network is present", () => {
|
||||
const container = new TestContainer()
|
||||
const responseInspector = container.bind(ResponseInspectorService)
|
||||
|
||||
const req = ref({
|
||||
...getDefaultRESTRequest(),
|
||||
endpoint: "http://example.com/api/data",
|
||||
})
|
||||
const res = ref<HoppRESTResponse>({
|
||||
type: "network_fail",
|
||||
error: new Error("test"),
|
||||
req: req.value,
|
||||
})
|
||||
|
||||
vi.stubGlobal("navigator", {
|
||||
onLine: false,
|
||||
})
|
||||
|
||||
const result = responseInspector.getInspections(req, res)
|
||||
|
||||
expect(result.value).toContainEqual(
|
||||
expect.objectContaining({
|
||||
text: { type: "text", text: "inspections.response.network_error" },
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it("should handle network_fail responses and return nothing when network is present", () => {
|
||||
const container = new TestContainer()
|
||||
const responseInspector = container.bind(ResponseInspectorService)
|
||||
|
||||
const req = ref({
|
||||
...getDefaultRESTRequest(),
|
||||
endpoint: "http://example.com/api/data",
|
||||
})
|
||||
const res = ref<HoppRESTResponse>({
|
||||
type: "network_fail",
|
||||
error: new Error("test"),
|
||||
req: req.value,
|
||||
})
|
||||
|
||||
const result = responseInspector.getInspections(req, res)
|
||||
|
||||
expect(result.value).toHaveLength(0)
|
||||
})
|
||||
|
||||
it("should handle fail responses", () => {
|
||||
const container = new TestContainer()
|
||||
const responseInspector = container.bind(ResponseInspectorService)
|
||||
|
||||
const req = ref({
|
||||
...getDefaultRESTRequest(),
|
||||
endpoint: "http://example.com/api/data",
|
||||
})
|
||||
const res = ref<HoppRESTResponse>({
|
||||
type: "fail",
|
||||
statusCode: 500,
|
||||
body: Uint8Array.from([]),
|
||||
headers: [],
|
||||
meta: { responseDuration: 0, responseSize: 0 },
|
||||
req: req.value,
|
||||
})
|
||||
|
||||
const result = responseInspector.getInspections(req, res)
|
||||
|
||||
expect(result.value).toContainEqual(
|
||||
expect.objectContaining({
|
||||
text: { type: "text", text: "inspections.response.default_error" },
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it("should handle 404 responses", () => {
|
||||
const container = new TestContainer()
|
||||
const responseInspector = container.bind(ResponseInspectorService)
|
||||
|
||||
const req = ref({
|
||||
...getDefaultRESTRequest(),
|
||||
endpoint: "http://example.com/api/data",
|
||||
})
|
||||
const res = ref<HoppRESTResponse>({
|
||||
type: "success",
|
||||
statusCode: 404,
|
||||
body: Uint8Array.from([]),
|
||||
headers: [],
|
||||
meta: { responseDuration: 0, responseSize: 0 },
|
||||
req: req.value,
|
||||
})
|
||||
|
||||
const result = responseInspector.getInspections(req, res)
|
||||
|
||||
expect(result.value).toContainEqual(
|
||||
expect.objectContaining({
|
||||
text: { type: "text", text: "inspections.response.404_error" },
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it("should handle 401 responses", () => {
|
||||
const container = new TestContainer()
|
||||
const responseInspector = container.bind(ResponseInspectorService)
|
||||
|
||||
const req = ref({
|
||||
...getDefaultRESTRequest(),
|
||||
endpoint: "http://example.com/api/data",
|
||||
})
|
||||
const res = ref<HoppRESTResponse>({
|
||||
type: "success",
|
||||
statusCode: 401,
|
||||
body: Uint8Array.from([]),
|
||||
headers: [],
|
||||
meta: { responseDuration: 0, responseSize: 0 },
|
||||
req: req.value,
|
||||
})
|
||||
|
||||
const result = responseInspector.getInspections(req, res)
|
||||
|
||||
expect(result.value).toContainEqual(
|
||||
expect.objectContaining({
|
||||
text: { type: "text", text: "inspections.response.401_error" },
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it("should handle successful responses", () => {
|
||||
const container = new TestContainer()
|
||||
const responseInspector = container.bind(ResponseInspectorService)
|
||||
|
||||
const req = ref({
|
||||
...getDefaultRESTRequest(),
|
||||
endpoint: "http://example.com/api/data",
|
||||
})
|
||||
const res = ref<HoppRESTResponse>({
|
||||
type: "success",
|
||||
statusCode: 200,
|
||||
body: Uint8Array.from([]),
|
||||
headers: [],
|
||||
meta: { responseDuration: 0, responseSize: 0 },
|
||||
req: req.value,
|
||||
})
|
||||
|
||||
const result = responseInspector.getInspections(req, res)
|
||||
|
||||
expect(result.value).toHaveLength(0)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,151 +0,0 @@
|
||||
import { TestContainer } from "dioc/testing"
|
||||
import { describe, expect, it, vi } from "vitest"
|
||||
import { ResponseInspectorService } from "../response.inspector"
|
||||
import { InspectionService } from "../../index"
|
||||
import { getDefaultRESTRequest } from "~/helpers/rest/default"
|
||||
|
||||
vi.mock("~/modules/i18n", () => ({
|
||||
__esModule: true,
|
||||
getI18n: () => (x: string) => x,
|
||||
}))
|
||||
|
||||
describe("ResponseInspectorService", () => {
|
||||
it("registers with the inspection service upon initialization", () => {
|
||||
const container = new TestContainer()
|
||||
|
||||
const registerInspectorFn = vi.fn()
|
||||
|
||||
container.bindMock(InspectionService, {
|
||||
registerInspector: registerInspectorFn,
|
||||
})
|
||||
|
||||
const responseInspector = container.bind(ResponseInspectorService)
|
||||
|
||||
expect(registerInspectorFn).toHaveBeenCalledOnce()
|
||||
expect(registerInspectorFn).toHaveBeenCalledWith(responseInspector)
|
||||
})
|
||||
|
||||
describe("getInspectorFor", () => {
|
||||
it("should return an empty array when response is undefined", () => {
|
||||
const container = new TestContainer()
|
||||
const responseInspector = container.bind(ResponseInspectorService)
|
||||
|
||||
const req = {
|
||||
...getDefaultRESTRequest(),
|
||||
endpoint: "http://example.com/api/data",
|
||||
}
|
||||
|
||||
const result = responseInspector.getInspectorFor(req, undefined)
|
||||
|
||||
expect(result).toHaveLength(0)
|
||||
})
|
||||
|
||||
it("should return an inspector result when response type is not success or status code is not 200", () => {
|
||||
const container = new TestContainer()
|
||||
const responseInspector = container.bind(ResponseInspectorService)
|
||||
|
||||
const req = {
|
||||
...getDefaultRESTRequest(),
|
||||
endpoint: "http://example.com/api/data",
|
||||
}
|
||||
const res = { type: "network_fail", statusCode: 400 }
|
||||
|
||||
const result = responseInspector.getInspectorFor(req, res)
|
||||
|
||||
expect(result).toContainEqual(
|
||||
expect.objectContaining({ id: "url", isApplicable: true })
|
||||
)
|
||||
})
|
||||
|
||||
it("should handle network_fail responses", () => {
|
||||
const container = new TestContainer()
|
||||
const responseInspector = container.bind(ResponseInspectorService)
|
||||
|
||||
const req = {
|
||||
...getDefaultRESTRequest(),
|
||||
endpoint: "http://example.com/api/data",
|
||||
}
|
||||
const res = { type: "network_fail", statusCode: 500 }
|
||||
|
||||
const result = responseInspector.getInspectorFor(req, res)
|
||||
|
||||
expect(result).toContainEqual(
|
||||
expect.objectContaining({
|
||||
text: { type: "text", text: "inspections.response.network_error" },
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it("should handle fail responses", () => {
|
||||
const container = new TestContainer()
|
||||
const responseInspector = container.bind(ResponseInspectorService)
|
||||
|
||||
const req = {
|
||||
...getDefaultRESTRequest(),
|
||||
endpoint: "http://example.com/api/data",
|
||||
}
|
||||
const res = { type: "fail", statusCode: 500 }
|
||||
|
||||
const result = responseInspector.getInspectorFor(req, res)
|
||||
|
||||
expect(result).toContainEqual(
|
||||
expect.objectContaining({
|
||||
text: { type: "text", text: "inspections.response.default_error" },
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it("should handle 404 responses", () => {
|
||||
const container = new TestContainer()
|
||||
const responseInspector = container.bind(ResponseInspectorService)
|
||||
|
||||
const req = {
|
||||
...getDefaultRESTRequest(),
|
||||
endpoint: "http://example.com/api/data",
|
||||
}
|
||||
const res = { type: "success", statusCode: 404 }
|
||||
|
||||
const result = responseInspector.getInspectorFor(req, res)
|
||||
|
||||
expect(result).toContainEqual(
|
||||
expect.objectContaining({
|
||||
text: { type: "text", text: "inspections.response.404_error" },
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it("should handle 401 responses", () => {
|
||||
const container = new TestContainer()
|
||||
const responseInspector = container.bind(ResponseInspectorService)
|
||||
|
||||
const req = {
|
||||
...getDefaultRESTRequest(),
|
||||
endpoint: "http://example.com/api/data",
|
||||
}
|
||||
const res = { type: "success", statusCode: 401 }
|
||||
|
||||
const result = responseInspector.getInspectorFor(req, res)
|
||||
|
||||
expect(result).toContainEqual(
|
||||
expect.objectContaining({
|
||||
text: { type: "text", text: "inspections.response.401_error" },
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it("should handle successful responses", () => {
|
||||
const container = new TestContainer()
|
||||
const responseInspector = container.bind(ResponseInspectorService)
|
||||
|
||||
const req = {
|
||||
...getDefaultRESTRequest(),
|
||||
endpoint: "http://example.com/api/data",
|
||||
}
|
||||
const res = { type: "success", statusCode: 200 }
|
||||
|
||||
const result = responseInspector.getInspectorFor(req, res)
|
||||
|
||||
expect(result).toHaveLength(0)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -6,11 +6,13 @@ import {
|
||||
InspectorResult,
|
||||
} from ".."
|
||||
import { Service } from "dioc"
|
||||
import { Ref, markRaw, ref } from "vue"
|
||||
import { Ref, markRaw } from "vue"
|
||||
import IconPlusCircle from "~icons/lucide/plus-circle"
|
||||
import { HoppRESTRequest } from "@hoppscotch/data"
|
||||
import { getAggregateEnvs } from "~/newstore/environments"
|
||||
import { aggregateEnvs$ } from "~/newstore/environments"
|
||||
import { invokeAction } from "~/helpers/actions"
|
||||
import { computed } from "vue"
|
||||
import { useStreamStatic } from "~/composables/stream"
|
||||
|
||||
const HOPP_ENVIRONMENT_REGEX = /(<<[a-zA-Z0-9-_]+>>)/g
|
||||
|
||||
@@ -34,6 +36,10 @@ export class EnvironmentInspectorService extends Service implements Inspector {
|
||||
|
||||
private readonly inspection = this.bind(InspectionService)
|
||||
|
||||
private aggregateEnvs = useStreamStatic(aggregateEnvs$, [], () => {
|
||||
/* noop */
|
||||
})[0]
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
|
||||
@@ -49,11 +55,11 @@ export class EnvironmentInspectorService extends Service implements Inspector {
|
||||
*/
|
||||
private validateEnvironmentVariables = (
|
||||
target: any[],
|
||||
results: Ref<InspectorResult[]>,
|
||||
locations: InspectorLocation
|
||||
) => {
|
||||
const env = getAggregateEnvs()
|
||||
const envKeys = env.map((e) => e.key)
|
||||
const newErrors: InspectorResult[] = []
|
||||
|
||||
const envKeys = this.aggregateEnvs.value.map((e) => e.key)
|
||||
|
||||
target.forEach((element, index) => {
|
||||
if (isENVInString(element)) {
|
||||
@@ -83,7 +89,7 @@ export class EnvironmentInspectorService extends Service implements Inspector {
|
||||
}
|
||||
}
|
||||
if (!envKeys.includes(formattedExEnv)) {
|
||||
results.value.push({
|
||||
newErrors.push({
|
||||
id: "environment",
|
||||
text: {
|
||||
type: "text",
|
||||
@@ -96,8 +102,8 @@ export class EnvironmentInspectorService extends Service implements Inspector {
|
||||
text: this.t("inspections.environment.add_environment"),
|
||||
apply: () => {
|
||||
invokeAction("modals.environment.add", {
|
||||
envName: "test",
|
||||
variableName: formattedExEnv,
|
||||
envName: formattedExEnv,
|
||||
variableName: "",
|
||||
})
|
||||
},
|
||||
},
|
||||
@@ -114,54 +120,61 @@ export class EnvironmentInspectorService extends Service implements Inspector {
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return newErrors
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the inspector results for the request
|
||||
* It checks if any env is used in the request ie, url, headers, params
|
||||
* and checks if the env is defined in the environment using the validateEnvironmentVariables function
|
||||
* @param req The request to inspect
|
||||
* @returns The inspector results
|
||||
*/
|
||||
getInspectorFor(req: HoppRESTRequest): InspectorResult[] {
|
||||
const results = ref<InspectorResult[]>([])
|
||||
getInspections(req: Readonly<Ref<HoppRESTRequest>>) {
|
||||
return computed(() => {
|
||||
const results: InspectorResult[] = []
|
||||
|
||||
const headers = req.headers
|
||||
const headers = req.value.headers
|
||||
|
||||
const params = req.params
|
||||
const params = req.value.params
|
||||
|
||||
this.validateEnvironmentVariables([req.endpoint], results, {
|
||||
type: "url",
|
||||
results.push(
|
||||
...this.validateEnvironmentVariables([req.value.endpoint], {
|
||||
type: "url",
|
||||
})
|
||||
)
|
||||
|
||||
const headerKeys = Object.values(headers).map((header) => header.key)
|
||||
|
||||
results.push(
|
||||
...this.validateEnvironmentVariables(headerKeys, {
|
||||
type: "header",
|
||||
position: "key",
|
||||
})
|
||||
)
|
||||
|
||||
const headerValues = Object.values(headers).map((header) => header.value)
|
||||
|
||||
results.push(
|
||||
...this.validateEnvironmentVariables(headerValues, {
|
||||
type: "header",
|
||||
position: "value",
|
||||
})
|
||||
)
|
||||
|
||||
const paramsKeys = Object.values(params).map((param) => param.key)
|
||||
|
||||
results.push(
|
||||
...this.validateEnvironmentVariables(paramsKeys, {
|
||||
type: "parameter",
|
||||
position: "key",
|
||||
})
|
||||
)
|
||||
|
||||
const paramsValues = Object.values(params).map((param) => param.value)
|
||||
|
||||
results.push(
|
||||
...this.validateEnvironmentVariables(paramsValues, {
|
||||
type: "parameter",
|
||||
position: "value",
|
||||
})
|
||||
)
|
||||
|
||||
return results
|
||||
})
|
||||
|
||||
const headerKeys = Object.values(headers).map((header) => header.key)
|
||||
|
||||
this.validateEnvironmentVariables(headerKeys, results, {
|
||||
type: "header",
|
||||
position: "key",
|
||||
})
|
||||
|
||||
const headerValues = Object.values(headers).map((header) => header.value)
|
||||
|
||||
this.validateEnvironmentVariables(headerValues, results, {
|
||||
type: "header",
|
||||
position: "value",
|
||||
})
|
||||
|
||||
const paramsKeys = Object.values(params).map((param) => param.key)
|
||||
|
||||
this.validateEnvironmentVariables(paramsKeys, results, {
|
||||
type: "parameter",
|
||||
position: "key",
|
||||
})
|
||||
|
||||
const paramsValues = Object.values(params).map((param) => param.value)
|
||||
|
||||
this.validateEnvironmentVariables(paramsValues, results, {
|
||||
type: "parameter",
|
||||
position: "value",
|
||||
})
|
||||
|
||||
return results.value
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Service } from "dioc"
|
||||
import { InspectionService, Inspector, InspectorResult } from ".."
|
||||
import { getI18n } from "~/modules/i18n"
|
||||
import { HoppRESTRequest } from "@hoppscotch/data"
|
||||
import { markRaw, ref } from "vue"
|
||||
import { Ref, computed, markRaw } from "vue"
|
||||
import IconAlertTriangle from "~icons/lucide/alert-triangle"
|
||||
|
||||
/**
|
||||
@@ -26,53 +26,50 @@ export class HeaderInspectorService extends Service implements Inspector {
|
||||
this.inspection.registerInspector(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the header contains cookies
|
||||
* @param req The request to inspect
|
||||
* @returns The inspector results
|
||||
*/
|
||||
getInspectorFor(req: HoppRESTRequest): InspectorResult[] {
|
||||
const results = ref<InspectorResult[]>([])
|
||||
private cookiesCheck(headerKey: string) {
|
||||
const cookieKeywords = ["Cookie", "Set-Cookie", "Cookie2", "Set-Cookie2"]
|
||||
|
||||
const cookiesCheck = (headerKey: string) => {
|
||||
const cookieKeywords = ["Cookie", "Set-Cookie", "Cookie2", "Set-Cookie2"]
|
||||
return cookieKeywords.includes(headerKey)
|
||||
}
|
||||
|
||||
return cookieKeywords.includes(headerKey)
|
||||
}
|
||||
getInspections(req: Readonly<Ref<HoppRESTRequest>>) {
|
||||
return computed(() => {
|
||||
const results: InspectorResult[] = []
|
||||
|
||||
const headers = req.headers
|
||||
const headers = req.value.headers
|
||||
|
||||
const headerKeys = Object.values(headers).map((header) => header.key)
|
||||
const headerKeys = Object.values(headers).map((header) => header.key)
|
||||
|
||||
const isContainCookies = headerKeys.includes("Cookie")
|
||||
const isContainCookies = headerKeys.includes("Cookie")
|
||||
|
||||
if (isContainCookies) {
|
||||
headerKeys.forEach((headerKey, index) => {
|
||||
if (cookiesCheck(headerKey)) {
|
||||
results.value.push({
|
||||
id: "header",
|
||||
icon: markRaw(IconAlertTriangle),
|
||||
text: {
|
||||
type: "text",
|
||||
text: this.t("inspections.header.cookie"),
|
||||
},
|
||||
severity: 2,
|
||||
isApplicable: true,
|
||||
locations: {
|
||||
type: "header",
|
||||
position: "key",
|
||||
key: headerKey,
|
||||
index: index,
|
||||
},
|
||||
doc: {
|
||||
text: this.t("action.learn_more"),
|
||||
link: "https://docs.hoppscotch.io/",
|
||||
},
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
if (isContainCookies) {
|
||||
headerKeys.forEach((headerKey, index) => {
|
||||
if (this.cookiesCheck(headerKey)) {
|
||||
results.push({
|
||||
id: "header",
|
||||
icon: markRaw(IconAlertTriangle),
|
||||
text: {
|
||||
type: "text",
|
||||
text: this.t("inspections.header.cookie"),
|
||||
},
|
||||
severity: 2,
|
||||
isApplicable: true,
|
||||
locations: {
|
||||
type: "header",
|
||||
position: "key",
|
||||
key: headerKey,
|
||||
index: index,
|
||||
},
|
||||
doc: {
|
||||
text: this.t("action.learn_more"),
|
||||
link: "https://docs.hoppscotch.io/",
|
||||
},
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return results.value
|
||||
return results
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,11 @@ import { Service } from "dioc"
|
||||
import { InspectionService, Inspector, InspectorResult } from ".."
|
||||
import { getI18n } from "~/modules/i18n"
|
||||
import { HoppRESTRequest } from "@hoppscotch/data"
|
||||
import { markRaw, ref } from "vue"
|
||||
import { markRaw } from "vue"
|
||||
import IconAlertTriangle from "~icons/lucide/alert-triangle"
|
||||
import { HoppRESTResponse } from "~/helpers/types/HoppRESTResponse"
|
||||
import { Ref } from "vue"
|
||||
import { computed } from "vue"
|
||||
|
||||
/**
|
||||
* This inspector is responsible for inspecting the response of a request.
|
||||
@@ -27,47 +29,50 @@ export class ResponseInspectorService extends Service implements Inspector {
|
||||
this.inspection.registerInspector(this)
|
||||
}
|
||||
|
||||
getInspectorFor(
|
||||
req: HoppRESTRequest,
|
||||
res: HoppRESTResponse | undefined
|
||||
): InspectorResult[] {
|
||||
const results = ref<InspectorResult[]>([])
|
||||
if (!res) return results.value
|
||||
getInspections(
|
||||
_req: Readonly<Ref<HoppRESTRequest>>,
|
||||
res: Readonly<Ref<HoppRESTResponse | null | undefined>>
|
||||
) {
|
||||
return computed(() => {
|
||||
const results: InspectorResult[] = []
|
||||
if (!res.value) return results
|
||||
|
||||
const hasErrors = res && (res.type !== "success" || res.statusCode !== 200)
|
||||
const hasErrors =
|
||||
res && (res.value.type !== "success" || res.value.statusCode !== 200)
|
||||
|
||||
let text
|
||||
let text: string | undefined = undefined
|
||||
|
||||
if (res.type === "network_fail") {
|
||||
text = this.t("inspections.response.network_error")
|
||||
} else if (res.type === "fail") {
|
||||
text = this.t("inspections.response.default_error")
|
||||
} else if (res.type === "success" && res.statusCode === 404) {
|
||||
text = this.t("inspections.response.404_error")
|
||||
} else if (res.type === "success" && res.statusCode === 401) {
|
||||
text = this.t("inspections.response.401_error")
|
||||
}
|
||||
if (res.value.type === "network_fail" && !navigator.onLine) {
|
||||
text = this.t("inspections.response.network_error")
|
||||
} else if (res.value.type === "fail") {
|
||||
text = this.t("inspections.response.default_error")
|
||||
} else if (res.value.type === "success" && res.value.statusCode === 404) {
|
||||
text = this.t("inspections.response.404_error")
|
||||
} else if (res.value.type === "success" && res.value.statusCode === 401) {
|
||||
text = this.t("inspections.response.401_error")
|
||||
}
|
||||
|
||||
if (hasErrors && text) {
|
||||
results.value.push({
|
||||
id: "url",
|
||||
icon: markRaw(IconAlertTriangle),
|
||||
text: {
|
||||
type: "text",
|
||||
text: text,
|
||||
},
|
||||
severity: 2,
|
||||
isApplicable: true,
|
||||
locations: {
|
||||
type: "response",
|
||||
},
|
||||
doc: {
|
||||
text: this.t("action.learn_more"),
|
||||
link: "https://docs.hoppscotch.io/",
|
||||
},
|
||||
})
|
||||
}
|
||||
if (hasErrors && text) {
|
||||
results.push({
|
||||
id: "url",
|
||||
icon: markRaw(IconAlertTriangle),
|
||||
text: {
|
||||
type: "text",
|
||||
text: text,
|
||||
},
|
||||
severity: 2,
|
||||
isApplicable: true,
|
||||
locations: {
|
||||
type: "response",
|
||||
},
|
||||
doc: {
|
||||
text: this.t("action.learn_more"),
|
||||
link: "https://docs.hoppscotch.io/",
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return results.value
|
||||
return results
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
import { Service } from "dioc"
|
||||
import { InspectionService, Inspector, InspectorResult } from ".."
|
||||
import { getI18n } from "~/modules/i18n"
|
||||
import { HoppRESTRequest } from "@hoppscotch/data"
|
||||
import { computed, markRaw, ref } from "vue"
|
||||
import IconAlertTriangle from "~icons/lucide/alert-triangle"
|
||||
import { useReadonlyStream } from "~/composables/stream"
|
||||
import { extensionStatus$ } from "~/newstore/HoppExtension"
|
||||
import { useSetting } from "~/composables/settings"
|
||||
import { applySetting, toggleSetting } from "~/newstore/settings"
|
||||
|
||||
/**
|
||||
* This inspector is responsible for inspecting the URL of a request.
|
||||
* It checks if the URL contains localhost and if the extension is installed.
|
||||
* It also provides an action to enable the extension.
|
||||
*
|
||||
* NOTE: Initializing this service registers it as a inspector with the Inspection Service.
|
||||
*/
|
||||
export class URLInspectorService extends Service implements Inspector {
|
||||
public static readonly ID = "URL_INSPECTOR_SERVICE"
|
||||
|
||||
private t = getI18n()
|
||||
|
||||
public readonly inspectorID = "url"
|
||||
|
||||
private readonly inspection = this.bind(InspectionService)
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
|
||||
this.inspection.registerInspector(this)
|
||||
}
|
||||
|
||||
getInspectorFor(req: HoppRESTRequest): InspectorResult[] {
|
||||
const PROXY_ENABLED = useSetting("PROXY_ENABLED")
|
||||
|
||||
const currentExtensionStatus = useReadonlyStream(extensionStatus$, null)
|
||||
|
||||
const isExtensionInstalled = computed(() => {
|
||||
return currentExtensionStatus.value === "available"
|
||||
})
|
||||
const EXTENSIONS_ENABLED = useSetting("EXTENSIONS_ENABLED")
|
||||
|
||||
const results = ref<InspectorResult[]>([])
|
||||
|
||||
const url = req.endpoint
|
||||
|
||||
const isContainLocalhost = url.includes("localhost")
|
||||
|
||||
if (
|
||||
isContainLocalhost &&
|
||||
(!EXTENSIONS_ENABLED.value || !isExtensionInstalled.value)
|
||||
) {
|
||||
let text
|
||||
|
||||
if (!isExtensionInstalled.value) {
|
||||
if (currentExtensionStatus.value === "unknown-origin") {
|
||||
text = this.t("inspections.url.extension_unknown_origin")
|
||||
} else {
|
||||
text = this.t("inspections.url.extension_not_installed")
|
||||
}
|
||||
} else if (!EXTENSIONS_ENABLED.value) {
|
||||
text = this.t("inspections.url.extention_not_enabled")
|
||||
} else {
|
||||
text = this.t("inspections.url.localhost")
|
||||
}
|
||||
|
||||
results.value.push({
|
||||
id: "url",
|
||||
icon: markRaw(IconAlertTriangle),
|
||||
text: {
|
||||
type: "text",
|
||||
text: text,
|
||||
},
|
||||
action: {
|
||||
text: this.t("inspections.url.extention_enable_action"),
|
||||
apply: () => {
|
||||
applySetting("EXTENSIONS_ENABLED", true)
|
||||
if (PROXY_ENABLED.value) toggleSetting("PROXY_ENABLED")
|
||||
},
|
||||
},
|
||||
severity: 2,
|
||||
isApplicable: true,
|
||||
locations: {
|
||||
type: "url",
|
||||
},
|
||||
doc: {
|
||||
text: this.t("action.learn_more"),
|
||||
link: "https://docs.hoppscotch.io/",
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return results.value
|
||||
}
|
||||
}
|
||||
@@ -91,8 +91,9 @@ export abstract class StaticSpotlightSearcherService<
|
||||
private async addDocsToSearchIndex() {
|
||||
this.loading.value = true
|
||||
|
||||
this.minisearch.removeAll()
|
||||
this.minisearch.vacuum()
|
||||
this.minisearch = new MiniSearch({
|
||||
fields: this.opts.searchFields as string[],
|
||||
})
|
||||
|
||||
await this.minisearch.addAllAsync(
|
||||
Object.entries(this._documents).map(([id, doc]) => ({
|
||||
|
||||
@@ -45,8 +45,11 @@ import {
|
||||
setSelectedEnvironmentIndex,
|
||||
} from "~/newstore/environments"
|
||||
|
||||
import IconCheckCircle from "~/components/app/spotlight/entry/IconSelected.vue"
|
||||
import IconCircle from "~icons/lucide/circle"
|
||||
|
||||
type Doc = {
|
||||
text: string
|
||||
text: string | string[]
|
||||
alternates: string[]
|
||||
icon: object | Component
|
||||
excludeFromSearch?: boolean
|
||||
@@ -88,40 +91,61 @@ export class EnvironmentsSpotlightSearcherService extends StaticSpotlightSearche
|
||||
|
||||
private documents: Record<string, Doc> = reactive({
|
||||
new_environment: {
|
||||
text: this.t("spotlight.environments.new"),
|
||||
text: [
|
||||
this.t("spotlight.environments.title"),
|
||||
this.t("spotlight.environments.new"),
|
||||
],
|
||||
alternates: ["new", "environment"],
|
||||
icon: markRaw(IconLayers),
|
||||
},
|
||||
new_environment_variable: {
|
||||
text: this.t("spotlight.environments.new_variable"),
|
||||
text: [
|
||||
this.t("spotlight.environments.title"),
|
||||
this.t("spotlight.environments.new_variable"),
|
||||
],
|
||||
alternates: ["new", "environment", "variable"],
|
||||
icon: markRaw(IconLayers),
|
||||
},
|
||||
edit_selected_env: {
|
||||
text: this.t("spotlight.environments.edit"),
|
||||
text: [
|
||||
this.t("spotlight.environments.title"),
|
||||
this.t("spotlight.environments.edit"),
|
||||
],
|
||||
alternates: ["edit", "environment"],
|
||||
icon: markRaw(IconEdit),
|
||||
excludeFromSearch: computed(() => !this.hasSelectedEnv.value),
|
||||
},
|
||||
delete_selected_env: {
|
||||
text: this.t("spotlight.environments.delete"),
|
||||
text: [
|
||||
this.t("spotlight.environments.title"),
|
||||
this.t("spotlight.environments.delete"),
|
||||
],
|
||||
alternates: ["delete", "environment"],
|
||||
icon: markRaw(IconTrash2),
|
||||
excludeFromSearch: computed(() => !this.hasSelectedEnv.value),
|
||||
},
|
||||
duplicate_selected_env: {
|
||||
text: this.t("spotlight.environments.duplicate"),
|
||||
text: [
|
||||
this.t("spotlight.environments.title"),
|
||||
this.t("spotlight.environments.duplicate"),
|
||||
],
|
||||
alternates: ["duplicate", "environment"],
|
||||
icon: markRaw(IconCopy),
|
||||
excludeFromSearch: computed(() => !this.hasSelectedEnv.value),
|
||||
},
|
||||
edit_global_env: {
|
||||
text: this.t("spotlight.environments.edit_global"),
|
||||
text: [
|
||||
this.t("spotlight.environments.title"),
|
||||
this.t("spotlight.environments.edit_global"),
|
||||
],
|
||||
alternates: ["edit", "global", "environment"],
|
||||
icon: markRaw(IconEdit),
|
||||
},
|
||||
duplicate_global_env: {
|
||||
text: this.t("spotlight.environments.duplicate_global"),
|
||||
text: [
|
||||
this.t("spotlight.environments.title"),
|
||||
this.t("spotlight.environments.duplicate_global"),
|
||||
],
|
||||
alternates: ["duplicate", "global", "environment"],
|
||||
icon: markRaw(IconCopy),
|
||||
},
|
||||
@@ -245,6 +269,16 @@ export class SwitchEnvSpotlightSearcherService
|
||||
this.spotlight.registerSearcher(this)
|
||||
}
|
||||
|
||||
private selectedEnvIndex = useStreamStatic(
|
||||
selectedEnvironmentIndex$,
|
||||
{
|
||||
type: "NO_ENV_SELECTED",
|
||||
},
|
||||
() => {
|
||||
/* noop */
|
||||
}
|
||||
)[0]
|
||||
|
||||
private environmentSearchable = useStreamStatic(
|
||||
activeActions$.pipe(
|
||||
map((actions) => actions.includes("modals.environment.add"))
|
||||
@@ -262,16 +296,25 @@ export class SwitchEnvSpotlightSearcherService
|
||||
const results = ref<SpotlightSearcherResult[]>([])
|
||||
|
||||
const minisearch = new MiniSearch({
|
||||
fields: ["name"],
|
||||
fields: ["name", "alternates"],
|
||||
storeFields: ["name"],
|
||||
})
|
||||
|
||||
if (this.environmentSearchable.value) {
|
||||
minisearch.addAll(
|
||||
environmentsStore.value.environments.map((entry, index) => {
|
||||
let id = `environment-${index}`
|
||||
|
||||
if (
|
||||
this.selectedEnvIndex.value?.type === "MY_ENV" &&
|
||||
this.selectedEnvIndex.value.index === index
|
||||
) {
|
||||
id += "-selected"
|
||||
}
|
||||
return {
|
||||
id: `environment-${index}`,
|
||||
id,
|
||||
name: entry.name,
|
||||
alternates: ["environment", "change", entry.name],
|
||||
}
|
||||
})
|
||||
)
|
||||
@@ -298,7 +341,9 @@ export class SwitchEnvSpotlightSearcherService
|
||||
.map((x) => {
|
||||
return {
|
||||
id: x.id,
|
||||
icon: markRaw(IconLayers),
|
||||
icon: markRaw(
|
||||
x.id.endsWith("-selected") ? IconCheckCircle : IconCircle
|
||||
),
|
||||
score: x.score,
|
||||
text: {
|
||||
type: "text",
|
||||
|
||||
@@ -9,17 +9,17 @@ import {
|
||||
|
||||
import IconLinkedIn from "~icons/brands/linkedin"
|
||||
import IconTwitter from "~icons/brands/twitter"
|
||||
import IconBook from "~icons/lucide/book"
|
||||
import IconDiscord from "~icons/lucide/link"
|
||||
import IconDiscord from "~icons/brands/discord"
|
||||
import IconGitHub from "~icons/lucide/github"
|
||||
import IconBook from "~icons/lucide/book"
|
||||
import IconLifeBuoy from "~icons/lucide/life-buoy"
|
||||
import IconMessageCircle from "~icons/lucide/message-circle"
|
||||
import IconZap from "~icons/lucide/zap"
|
||||
|
||||
type Doc = {
|
||||
text: string | string[]
|
||||
alternates: string[]
|
||||
icon: object | Component
|
||||
action: () => void
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -43,41 +43,48 @@ export class GeneralSpotlightSearcherService extends StaticSpotlightSearcherServ
|
||||
text: this.t("spotlight.general.help_menu"),
|
||||
alternates: ["help", "hoppscotch"],
|
||||
icon: markRaw(IconLifeBuoy),
|
||||
},
|
||||
chat_with_support: {
|
||||
text: this.t("spotlight.general.chat"),
|
||||
alternates: ["chat", "support", "hoppscotch"],
|
||||
icon: markRaw(IconMessageCircle),
|
||||
action() {
|
||||
invokeAction("modals.support.toggle")
|
||||
},
|
||||
},
|
||||
open_docs: {
|
||||
text: this.t("spotlight.general.open_docs"),
|
||||
alternates: ["docs", "documentation", "hoppscotch"],
|
||||
icon: markRaw(IconBook),
|
||||
action: () => this.openURL("https://docs.hoppscotch.io"),
|
||||
},
|
||||
open_keybindings: {
|
||||
text: this.t("spotlight.general.open_keybindings"),
|
||||
alternates: ["key", "shortcuts", "binding"],
|
||||
icon: markRaw(IconZap),
|
||||
action() {
|
||||
invokeAction("flyouts.keybinds.toggle")
|
||||
},
|
||||
},
|
||||
link_github: {
|
||||
text: [this.t("spotlight.general.social"), "GitHub"],
|
||||
alternates: ["social", "github", "link"],
|
||||
open_github: {
|
||||
text: this.t("spotlight.general.open_github"),
|
||||
alternates: ["repository", "github", "documentation", "hoppscotch"],
|
||||
icon: markRaw(IconGitHub),
|
||||
action: () => this.openURL("https://hoppscotch.io/github"),
|
||||
},
|
||||
link_twitter: {
|
||||
text: [this.t("spotlight.general.social"), "Twitter"],
|
||||
alternates: ["social", "twitter", "link"],
|
||||
icon: markRaw(IconTwitter),
|
||||
action: () => this.openURL("https://twitter.com/hoppscotch_io"),
|
||||
},
|
||||
link_discord: {
|
||||
text: [this.t("spotlight.general.social"), "Discord"],
|
||||
alternates: ["social", "discord", "link"],
|
||||
icon: markRaw(IconDiscord),
|
||||
action: () => this.openURL("https://hoppscotch.io/discord"),
|
||||
},
|
||||
link_linkedin: {
|
||||
text: [this.t("spotlight.general.social"), "LinkedIn"],
|
||||
alternates: ["social", "linkedin", "link"],
|
||||
icon: markRaw(IconLinkedIn),
|
||||
action: () =>
|
||||
this.openURL("https://www.linkedin.com/company/hoppscotch/"),
|
||||
},
|
||||
})
|
||||
|
||||
@@ -110,31 +117,11 @@ export class GeneralSpotlightSearcherService extends StaticSpotlightSearcherServ
|
||||
}
|
||||
|
||||
public onDocSelected(id: string): void {
|
||||
switch (id) {
|
||||
case "open_help":
|
||||
invokeAction("modals.support.toggle")
|
||||
break
|
||||
case "chat_with_support":
|
||||
invokeAction("flyouts.chat.open")
|
||||
break
|
||||
case "open_docs":
|
||||
this.openURL("https://docs.hoppscotch.io")
|
||||
break
|
||||
case "open_keybindings":
|
||||
invokeAction("flyouts.keybinds.toggle")
|
||||
break
|
||||
case "link_github":
|
||||
this.openURL("https://hoppscotch.io/github")
|
||||
break
|
||||
case "link_twitter":
|
||||
this.openURL("https://twitter.com/hoppscotch_io")
|
||||
break
|
||||
case "link_discord":
|
||||
this.openURL("https://hoppscotch.io/discord")
|
||||
break
|
||||
case "link_linkedin":
|
||||
this.openURL("https://www.linkedin.com/company/hoppscotch/")
|
||||
break
|
||||
}
|
||||
this.documents[id]?.action()
|
||||
}
|
||||
|
||||
public addCustomEntries(docs: Record<string, Doc>) {
|
||||
this.documents = { ...this.documents, ...docs }
|
||||
this.setDocuments(this.documents)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Component, computed, markRaw, reactive } from "vue"
|
||||
import { invokeAction } from "~/helpers/actions"
|
||||
import { invokeAction, isActionBound } from "~/helpers/actions"
|
||||
import { getI18n } from "~/modules/i18n"
|
||||
import { SpotlightSearcherResult, SpotlightService } from ".."
|
||||
import {
|
||||
@@ -19,6 +19,7 @@ import IconRename from "~icons/lucide/file-edit"
|
||||
import IconPlay from "~icons/lucide/play"
|
||||
import IconRotateCCW from "~icons/lucide/rotate-ccw"
|
||||
import IconSave from "~icons/lucide/save"
|
||||
import { GQLOptionTabs } from "~/components/graphql/RequestOptions.vue"
|
||||
|
||||
type Doc = {
|
||||
text: string | string[]
|
||||
@@ -46,39 +47,51 @@ export class RequestSpotlightSearcherService extends StaticSpotlightSearcherServ
|
||||
private route = useRoute()
|
||||
private isRESTPage = computed(() => this.route.name === "index")
|
||||
private isGQLPage = computed(() => this.route.name === "graphql")
|
||||
private isRESTOrGQLPage = computed(
|
||||
() => this.isRESTPage.value || this.isGQLPage.value
|
||||
)
|
||||
private isGQLConnectBound = isActionBound("gql.connect")
|
||||
private isGQLDisconnectBound = isActionBound("gql.disconnect")
|
||||
|
||||
private documents: Record<string, Doc> = reactive({
|
||||
send_request: {
|
||||
text: this.t("shortcut.request.send_request"),
|
||||
alternates: ["request", "send"],
|
||||
icon: markRaw(IconPlay),
|
||||
excludeFromSearch: computed(
|
||||
() => !this.isRESTPage.value ?? !this.isGQLPage.value
|
||||
),
|
||||
excludeFromSearch: computed(() => !this.isRESTOrGQLPage.value),
|
||||
},
|
||||
gql_connect: {
|
||||
text: [this.t("navigation.graphql"), this.t("spotlight.graphql.connect")],
|
||||
alternates: ["connect", "server", "graphql"],
|
||||
icon: markRaw(IconPlay),
|
||||
excludeFromSearch: computed(() => !this.isGQLConnectBound.value),
|
||||
},
|
||||
gql_disconnect: {
|
||||
text: [
|
||||
this.t("navigation.graphql"),
|
||||
this.t("spotlight.graphql.disconnect"),
|
||||
],
|
||||
alternates: ["disconnect", "stop", "graphql"],
|
||||
icon: markRaw(IconPlay),
|
||||
excludeFromSearch: computed(() => !this.isGQLDisconnectBound.value),
|
||||
},
|
||||
save_to_collections: {
|
||||
text: this.t("spotlight.request.save_as_new"),
|
||||
alternates: ["save", "collections"],
|
||||
icon: markRaw(IconSave),
|
||||
excludeFromSearch: computed(
|
||||
() => !this.isRESTPage.value ?? !this.isGQLPage.value
|
||||
),
|
||||
excludeFromSearch: computed(() => !this.isRESTOrGQLPage.value),
|
||||
},
|
||||
save_request: {
|
||||
text: this.t("shortcut.request.save_request"),
|
||||
alternates: ["save", "request"],
|
||||
icon: markRaw(IconSave),
|
||||
excludeFromSearch: computed(
|
||||
() => !this.isRESTPage.value ?? !this.isGQLPage.value
|
||||
),
|
||||
excludeFromSearch: computed(() => !this.isRESTOrGQLPage.value),
|
||||
},
|
||||
rename_request: {
|
||||
text: this.t("shortcut.request.rename"),
|
||||
alternates: ["rename", "request"],
|
||||
icon: markRaw(IconRename),
|
||||
excludeFromSearch: computed(
|
||||
() => !this.isRESTPage.value ?? !this.isGQLPage.value
|
||||
),
|
||||
excludeFromSearch: computed(() => !this.isRESTOrGQLPage.value),
|
||||
},
|
||||
copy_request_link: {
|
||||
text: this.t("shortcut.request.copy_request_link"),
|
||||
@@ -90,7 +103,7 @@ export class RequestSpotlightSearcherService extends StaticSpotlightSearcherServ
|
||||
text: this.t("shortcut.request.reset_request"),
|
||||
alternates: ["reset", "request"],
|
||||
icon: markRaw(IconRotateCCW),
|
||||
excludeFromSearch: computed(() => !this.isRESTPage.value),
|
||||
excludeFromSearch: computed(() => !this.isRESTOrGQLPage.value),
|
||||
},
|
||||
import_curl: {
|
||||
text: this.t("shortcut.request.import_curl"),
|
||||
@@ -143,9 +156,7 @@ export class RequestSpotlightSearcherService extends StaticSpotlightSearcherServ
|
||||
],
|
||||
alternates: ["parameters", "tab"],
|
||||
icon: markRaw(IconWindow),
|
||||
excludeFromSearch: computed(
|
||||
() => !this.isRESTPage.value ?? !this.isGQLPage.value
|
||||
),
|
||||
excludeFromSearch: computed(() => !this.isRESTOrGQLPage.value),
|
||||
},
|
||||
tab_body: {
|
||||
text: [
|
||||
@@ -154,9 +165,7 @@ export class RequestSpotlightSearcherService extends StaticSpotlightSearcherServ
|
||||
],
|
||||
alternates: ["body", "tab"],
|
||||
icon: markRaw(IconWindow),
|
||||
excludeFromSearch: computed(
|
||||
() => !this.isRESTPage.value ?? !this.isGQLPage.value
|
||||
),
|
||||
excludeFromSearch: computed(() => !this.isRESTOrGQLPage.value),
|
||||
},
|
||||
tab_headers: {
|
||||
text: [
|
||||
@@ -165,9 +174,7 @@ export class RequestSpotlightSearcherService extends StaticSpotlightSearcherServ
|
||||
],
|
||||
alternates: ["headers", "tab"],
|
||||
icon: markRaw(IconWindow),
|
||||
excludeFromSearch: computed(
|
||||
() => !this.isRESTPage.value ?? !this.isGQLPage.value
|
||||
),
|
||||
excludeFromSearch: computed(() => !this.isRESTOrGQLPage.value),
|
||||
},
|
||||
tab_authorization: {
|
||||
text: [
|
||||
@@ -176,9 +183,7 @@ export class RequestSpotlightSearcherService extends StaticSpotlightSearcherServ
|
||||
],
|
||||
alternates: ["authorization", "tab"],
|
||||
icon: markRaw(IconWindow),
|
||||
excludeFromSearch: computed(
|
||||
() => !this.isRESTPage.value ?? !this.isGQLPage.value
|
||||
),
|
||||
excludeFromSearch: computed(() => !this.isRESTOrGQLPage.value),
|
||||
},
|
||||
tab_pre_request_script: {
|
||||
text: [
|
||||
@@ -198,6 +203,24 @@ export class RequestSpotlightSearcherService extends StaticSpotlightSearcherServ
|
||||
icon: markRaw(IconWindow),
|
||||
excludeFromSearch: computed(() => !this.isRESTPage.value),
|
||||
},
|
||||
tab_query: {
|
||||
text: [
|
||||
this.t("spotlight.request.switch_to"),
|
||||
this.t("spotlight.request.tab_query"),
|
||||
],
|
||||
alternates: ["query", "tab"],
|
||||
icon: markRaw(IconWindow),
|
||||
excludeFromSearch: computed(() => !this.isGQLPage.value),
|
||||
},
|
||||
tab_variables: {
|
||||
text: [
|
||||
this.t("spotlight.request.switch_to"),
|
||||
this.t("spotlight.request.tab_variables"),
|
||||
],
|
||||
alternates: ["variables", "tab"],
|
||||
icon: markRaw(IconWindow),
|
||||
excludeFromSearch: computed(() => !this.isGQLPage.value),
|
||||
},
|
||||
})
|
||||
|
||||
constructor() {
|
||||
@@ -224,7 +247,7 @@ export class RequestSpotlightSearcherService extends StaticSpotlightSearcherServ
|
||||
}
|
||||
}
|
||||
|
||||
private openRequestTab(tab: RequestOptionTabs): void {
|
||||
private openRequestTab(tab: RequestOptionTabs | GQLOptionTabs): void {
|
||||
invokeAction("request.open-tab", {
|
||||
tab,
|
||||
})
|
||||
@@ -235,6 +258,12 @@ export class RequestSpotlightSearcherService extends StaticSpotlightSearcherServ
|
||||
case "send_request":
|
||||
invokeAction("request.send-cancel")
|
||||
break
|
||||
case "gql_connect":
|
||||
invokeAction("gql.connect")
|
||||
break
|
||||
case "gql_disconnect":
|
||||
invokeAction("gql.disconnect")
|
||||
break
|
||||
case "save_to_collections":
|
||||
invokeAction("request.save-as", {
|
||||
requestType: "rest",
|
||||
@@ -245,7 +274,7 @@ export class RequestSpotlightSearcherService extends StaticSpotlightSearcherServ
|
||||
invokeAction("request.save")
|
||||
break
|
||||
case "rename_request":
|
||||
invokeAction("rest.request.rename")
|
||||
invokeAction("request.rename")
|
||||
break
|
||||
case "copy_request_link":
|
||||
invokeAction("request.copy-link")
|
||||
@@ -292,6 +321,12 @@ export class RequestSpotlightSearcherService extends StaticSpotlightSearcherServ
|
||||
case "tab_tests":
|
||||
this.openRequestTab("tests")
|
||||
break
|
||||
case "tab_query":
|
||||
this.openRequestTab("query")
|
||||
break
|
||||
case "tab_variables":
|
||||
this.openRequestTab("variables")
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Component, computed, markRaw, reactive } from "vue"
|
||||
import { activeActions$, invokeAction } from "~/helpers/actions"
|
||||
import { invokeAction, isActionBound } from "~/helpers/actions"
|
||||
import { getI18n } from "~/modules/i18n"
|
||||
import { SpotlightSearcherResult, SpotlightService } from ".."
|
||||
import {
|
||||
@@ -9,8 +9,6 @@ import {
|
||||
|
||||
import IconDownload from "~icons/lucide/download"
|
||||
import IconCopy from "~icons/lucide/copy"
|
||||
import { map } from "rxjs"
|
||||
import { useStreamStatic } from "~/composables/stream"
|
||||
|
||||
type Doc = {
|
||||
text: string
|
||||
@@ -35,23 +33,11 @@ export class ResponseSpotlightSearcherService extends StaticSpotlightSearcherSer
|
||||
|
||||
private readonly spotlight = this.bind(SpotlightService)
|
||||
|
||||
private copyResponseActionEnabled = useStreamStatic(
|
||||
activeActions$.pipe(map((actions) => actions.includes("response.copy"))),
|
||||
activeActions$.value.includes("response.copy"),
|
||||
() => {
|
||||
/* noop */
|
||||
}
|
||||
)[0]
|
||||
private copyResponseActionEnabled = isActionBound("response.copy")
|
||||
|
||||
private downloadResponseActionEnabled = useStreamStatic(
|
||||
activeActions$.pipe(
|
||||
map((actions) => actions.includes("response.file.download"))
|
||||
),
|
||||
activeActions$.value.includes("response.file.download"),
|
||||
() => {
|
||||
/* noop */
|
||||
}
|
||||
)[0]
|
||||
private downloadResponseActionEnabled = isActionBound(
|
||||
"response.file.download"
|
||||
)
|
||||
|
||||
private documents: Record<string, Doc> = reactive({
|
||||
copy_response: {
|
||||
|
||||
@@ -14,11 +14,10 @@ import IconGlobe from "~icons/lucide/globe"
|
||||
import IconMonitor from "~icons/lucide/monitor"
|
||||
import IconMoon from "~icons/lucide/moon"
|
||||
import IconSun from "~icons/lucide/sun"
|
||||
import IconType from "~icons/lucide/type"
|
||||
import IconCheckCircle from "~icons/lucide/check-circle"
|
||||
|
||||
type Doc = {
|
||||
text: string | string[]
|
||||
excludeFromSearch?: boolean
|
||||
alternates: string[]
|
||||
icon: object | Component
|
||||
}
|
||||
@@ -34,7 +33,7 @@ export class SettingsSpotlightSearcherService extends StaticSpotlightSearcherSer
|
||||
|
||||
private t = getI18n()
|
||||
|
||||
private activeFontSize = useSetting("FONT_SIZE")
|
||||
private activeTheme = useSetting("BG_COLOR")
|
||||
|
||||
public readonly searcherID = "settings"
|
||||
public searcherSectionTitle = this.t("navigation.settings")
|
||||
@@ -48,7 +47,11 @@ export class SettingsSpotlightSearcherService extends StaticSpotlightSearcherSer
|
||||
this.t("spotlight.settings.theme.system"),
|
||||
],
|
||||
alternates: ["theme"],
|
||||
icon: markRaw(IconMonitor),
|
||||
icon: computed(() =>
|
||||
this.activeTheme.value === "system"
|
||||
? markRaw(IconCheckCircle)
|
||||
: markRaw(IconMonitor)
|
||||
),
|
||||
},
|
||||
theme_light: {
|
||||
text: [
|
||||
@@ -56,7 +59,11 @@ export class SettingsSpotlightSearcherService extends StaticSpotlightSearcherSer
|
||||
this.t("spotlight.settings.theme.light"),
|
||||
],
|
||||
alternates: ["theme"],
|
||||
icon: markRaw(IconSun),
|
||||
icon: computed(() =>
|
||||
this.activeTheme.value === "light"
|
||||
? markRaw(IconCheckCircle)
|
||||
: markRaw(IconSun)
|
||||
),
|
||||
},
|
||||
theme_dark: {
|
||||
text: [
|
||||
@@ -64,7 +71,11 @@ export class SettingsSpotlightSearcherService extends StaticSpotlightSearcherSer
|
||||
this.t("spotlight.settings.theme.dark"),
|
||||
],
|
||||
alternates: ["theme"],
|
||||
icon: markRaw(IconCloud),
|
||||
icon: computed(() =>
|
||||
this.activeTheme.value === "dark"
|
||||
? markRaw(IconCheckCircle)
|
||||
: markRaw(IconCloud)
|
||||
),
|
||||
},
|
||||
theme_black: {
|
||||
text: [
|
||||
@@ -72,53 +83,13 @@ export class SettingsSpotlightSearcherService extends StaticSpotlightSearcherSer
|
||||
this.t("spotlight.settings.theme.black"),
|
||||
],
|
||||
alternates: ["theme"],
|
||||
icon: markRaw(IconMoon),
|
||||
},
|
||||
font_size_sm: {
|
||||
text: [
|
||||
this.t("settings.font_size"),
|
||||
this.t("spotlight.settings.font.size_sm"),
|
||||
],
|
||||
onClick: () => {
|
||||
console.log("clicked")
|
||||
},
|
||||
excludeFromSearch: computed(() => this.activeFontSize.value === "small"),
|
||||
alternates: [
|
||||
"font size",
|
||||
"change font size",
|
||||
"change font",
|
||||
"increase font",
|
||||
],
|
||||
icon: markRaw(IconType),
|
||||
},
|
||||
font_size_md: {
|
||||
text: [
|
||||
this.t("settings.font_size"),
|
||||
this.t("spotlight.settings.font.size_md"),
|
||||
],
|
||||
excludeFromSearch: computed(() => this.activeFontSize.value === "medium"),
|
||||
alternates: [
|
||||
"font size",
|
||||
"change font size",
|
||||
"change font",
|
||||
"increase font",
|
||||
],
|
||||
icon: markRaw(IconType),
|
||||
},
|
||||
font_size_lg: {
|
||||
text: [
|
||||
this.t("settings.font_size"),
|
||||
this.t("spotlight.settings.font.size_lg"),
|
||||
],
|
||||
excludeFromSearch: computed(() => this.activeFontSize.value === "large"),
|
||||
alternates: [
|
||||
"font size",
|
||||
"change font size",
|
||||
"change font",
|
||||
"increase font",
|
||||
],
|
||||
icon: markRaw(IconType),
|
||||
icon: computed(() =>
|
||||
this.activeTheme.value === "black"
|
||||
? markRaw(IconCheckCircle)
|
||||
: markRaw(IconMoon)
|
||||
),
|
||||
},
|
||||
|
||||
change_lang: {
|
||||
text: [
|
||||
this.t("spotlight.section.interface"),
|
||||
@@ -176,17 +147,6 @@ export class SettingsSpotlightSearcherService extends StaticSpotlightSearcherSer
|
||||
case "theme_black":
|
||||
invokeAction("settings.theme.black")
|
||||
break
|
||||
|
||||
// font size actions
|
||||
case "font_size_sm":
|
||||
this.activeFontSize.value = "small"
|
||||
break
|
||||
case "font_size_md":
|
||||
this.activeFontSize.value = "medium"
|
||||
break
|
||||
case "font_size_lg":
|
||||
this.activeFontSize.value = "large"
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,19 +7,16 @@ import {
|
||||
} from "./base/static.searcher"
|
||||
|
||||
import { useRoute } from "vue-router"
|
||||
import { getDefaultRESTRequest } from "~/helpers/rest/default"
|
||||
import {
|
||||
closeOtherTabs,
|
||||
closeTab,
|
||||
createNewTab,
|
||||
currentTabID,
|
||||
getActiveTabs,
|
||||
} from "~/helpers/rest/tab"
|
||||
import IconWindow from "~icons/lucide/app-window"
|
||||
import IconCopy from "~icons/lucide/copy"
|
||||
import IconCopyPlus from "~icons/lucide/copy-plus"
|
||||
import IconXCircle from "~icons/lucide/x-circle"
|
||||
import IconXSquare from "~icons/lucide/x-square"
|
||||
import { invokeAction } from "~/helpers/actions"
|
||||
import { getActiveTabs as getRESTActiveTabs } from "~/helpers/rest/tab"
|
||||
import { getActiveTabs as getGQLActiveTabs } from "~/helpers/graphql/tab"
|
||||
|
||||
type Doc = {
|
||||
text: string
|
||||
text: string | string[]
|
||||
alternates: string[]
|
||||
icon: object | Component
|
||||
excludeFromSearch?: boolean
|
||||
@@ -43,36 +40,49 @@ export class TabSpotlightSearcherService extends StaticSpotlightSearcherService<
|
||||
|
||||
private route = useRoute()
|
||||
private showAction = computed(
|
||||
() => this.route.name === "index" ?? this.route.name === "graphql"
|
||||
() => this.route.name === "index" || this.route.name === "graphql"
|
||||
)
|
||||
private gqlActiveTabs = getGQLActiveTabs()
|
||||
private restActiveTabs = getRESTActiveTabs()
|
||||
private isOnlyTab = computed(() =>
|
||||
this.route.name === "graphql"
|
||||
? this.gqlActiveTabs.value.length === 1
|
||||
: this.restActiveTabs.value.length === 1
|
||||
)
|
||||
|
||||
private documents: Record<string, Doc> = reactive({
|
||||
duplicate_tab: {
|
||||
text: this.t("spotlight.tab.duplicate"),
|
||||
text: [this.t("spotlight.tab.title"), this.t("spotlight.tab.duplicate")],
|
||||
alternates: ["tab", "duplicate", "duplicate tab"],
|
||||
icon: markRaw(IconWindow),
|
||||
icon: markRaw(IconCopy),
|
||||
excludeFromSearch: computed(() => !this.showAction.value),
|
||||
},
|
||||
close_current_tab: {
|
||||
text: this.t("spotlight.tab.close_current"),
|
||||
text: [
|
||||
this.t("spotlight.tab.title"),
|
||||
this.t("spotlight.tab.close_current"),
|
||||
],
|
||||
alternates: ["tab", "close", "close tab"],
|
||||
icon: markRaw(IconWindow),
|
||||
icon: markRaw(IconXCircle),
|
||||
excludeFromSearch: computed(
|
||||
() => !this.showAction.value ?? getActiveTabs().value.length === 1
|
||||
() => !this.showAction.value || this.isOnlyTab.value
|
||||
),
|
||||
},
|
||||
close_other_tabs: {
|
||||
text: this.t("spotlight.tab.close_others"),
|
||||
text: [
|
||||
this.t("spotlight.tab.title"),
|
||||
this.t("spotlight.tab.close_others"),
|
||||
],
|
||||
alternates: ["tab", "close", "close all"],
|
||||
icon: markRaw(IconWindow),
|
||||
icon: markRaw(IconXSquare),
|
||||
excludeFromSearch: computed(
|
||||
() => !this.showAction.value ?? getActiveTabs().value.length < 2
|
||||
() => !this.showAction.value || this.isOnlyTab.value
|
||||
),
|
||||
},
|
||||
open_new_tab: {
|
||||
text: this.t("spotlight.tab.new_tab"),
|
||||
text: [this.t("spotlight.tab.title"), this.t("spotlight.tab.new_tab")],
|
||||
alternates: ["tab", "new", "open tab"],
|
||||
icon: markRaw(IconWindow),
|
||||
icon: markRaw(IconCopyPlus),
|
||||
excludeFromSearch: computed(() => !this.showAction.value),
|
||||
},
|
||||
})
|
||||
@@ -102,16 +112,9 @@ export class TabSpotlightSearcherService extends StaticSpotlightSearcherService<
|
||||
}
|
||||
|
||||
public onDocSelected(id: string): void {
|
||||
if (id === "duplicate_tab")
|
||||
invokeAction("request.duplicate-tab", {
|
||||
tabID: currentTabID.value,
|
||||
})
|
||||
if (id === "close_current_tab") closeTab(currentTabID.value)
|
||||
if (id === "close_other_tabs") closeOtherTabs(currentTabID.value)
|
||||
if (id === "open_new_tab")
|
||||
createNewTab({
|
||||
request: getDefaultRESTRequest(),
|
||||
isDirty: false,
|
||||
})
|
||||
if (id === "duplicate_tab") invokeAction("tab.duplicate-tab", {})
|
||||
if (id === "close_current_tab") invokeAction("tab.close-current")
|
||||
if (id === "close_other_tabs") invokeAction("tab.close-other")
|
||||
if (id === "open_new_tab") invokeAction("tab.open-new")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@hoppscotch/selfhost-web",
|
||||
"private": true,
|
||||
"version": "2023.4.8",
|
||||
"version": "2023.8.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev:vite": "vite",
|
||||
@@ -28,8 +28,8 @@
|
||||
"@fontsource-variable/roboto-mono": "^5.0.9",
|
||||
"@hoppscotch/common": "workspace:^",
|
||||
"@hoppscotch/data": "workspace:^",
|
||||
"axios": "^1.4.0",
|
||||
"@import-meta-env/unplugin": "^0.4.8",
|
||||
"axios": "^1.4.0",
|
||||
"buffer": "^6.0.3",
|
||||
"fp-ts": "^2.16.1",
|
||||
"process": "^0.11.10",
|
||||
@@ -65,6 +65,7 @@
|
||||
"unplugin-icons": "^0.16.5",
|
||||
"unplugin-vue-components": "^0.25.1",
|
||||
"vite": "^4.4.9",
|
||||
"vite-plugin-fonts": "^0.6.0",
|
||||
"vite-plugin-html-config": "^1.0.11",
|
||||
"vite-plugin-inspect": "^0.7.38",
|
||||
"vite-plugin-pages": "^0.31.0",
|
||||
@@ -75,7 +76,6 @@
|
||||
"vite-plugin-windicss": "^1.9.1",
|
||||
"vitest": "^0.34.2",
|
||||
"vue-tsc": "^1.8.8",
|
||||
"vite-plugin-fonts": "^0.6.0",
|
||||
"windicss": "^3.5.6"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,9 +7,16 @@ import { def as historyDef } from "./platform/history/history.platform"
|
||||
import { def as tabStateDef } from "./platform/tabState/tabState.platform"
|
||||
import { browserInterceptor } from "@hoppscotch/common/platform/std/interceptors/browser"
|
||||
import { proxyInterceptor } from "@hoppscotch/common/platform/std/interceptors/proxy"
|
||||
import { ExtensionInspectorService } from "@hoppscotch/common/platform/std/inspections/extension.inspector"
|
||||
import { ExtensionInterceptorService } from "@hoppscotch/common/platform/std/interceptors/extension"
|
||||
import { stdFooterItems } from "@hoppscotch/common/platform/std/ui/footerItem"
|
||||
import { stdSupportOptionItems } from "@hoppscotch/common/platform/std/ui/supportOptionsItem"
|
||||
|
||||
createHoppApp("#app", {
|
||||
ui: {
|
||||
additionalFooterMenuItems: stdFooterItems,
|
||||
additionalSupportOptionsMenuItems: stdSupportOptionItems,
|
||||
},
|
||||
auth: authDef,
|
||||
sync: {
|
||||
environments: environmentsDef,
|
||||
@@ -26,6 +33,9 @@ createHoppApp("#app", {
|
||||
{ type: "service", service: ExtensionInterceptorService },
|
||||
],
|
||||
},
|
||||
additionalInspectors: [
|
||||
{ type: "service", service: ExtensionInspectorService },
|
||||
],
|
||||
platformFeatureFlags: {
|
||||
exportAsGIST: false,
|
||||
},
|
||||
|
||||
@@ -1,8 +1,21 @@
|
||||
@mixin base-theme {
|
||||
--font-sans: "Inter Variable", sans-serif;
|
||||
--font-icon: "Material Symbols Rounded Variable";
|
||||
--font-mono: "Roboto Mono Variable", monospace;
|
||||
--font-size-tiny: calc(var(--font-size-body) - 0.062rem);
|
||||
--font-sans: 'Inter Variable', sans-serif;
|
||||
--font-icon: 'Material Symbols Rounded Variable';
|
||||
--font-mono: 'Roboto Mono Variable', monospace;
|
||||
--font-size-body: 0.75rem;
|
||||
--font-size-tiny: 0.688rem;
|
||||
--line-height-body: 1rem;
|
||||
--upper-primary-sticky-fold: 4.125rem;
|
||||
--upper-secondary-sticky-fold: 6.188rem;
|
||||
--upper-tertiary-sticky-fold: 8.25rem;
|
||||
--upper-mobile-primary-sticky-fold: 6.625rem;
|
||||
--upper-mobile-secondary-sticky-fold: 8.688rem;
|
||||
--upper-mobile-sticky-fold: 10.75rem;
|
||||
--upper-mobile-tertiary-sticky-fold: 8.25rem;
|
||||
--lower-primary-sticky-fold: 3rem;
|
||||
--lower-secondary-sticky-fold: 5.063rem;
|
||||
--lower-tertiary-sticky-fold: 7.125rem;
|
||||
--sidebar-primary-sticky-fold: 2rem;
|
||||
}
|
||||
|
||||
@mixin dark-theme {
|
||||
@@ -200,8 +213,8 @@
|
||||
:root {
|
||||
@include base-theme;
|
||||
@include dark-theme;
|
||||
@include green-theme;
|
||||
@include dark-editor-theme;
|
||||
@include green-theme;
|
||||
}
|
||||
|
||||
:root.light {
|
||||
@@ -257,63 +270,3 @@
|
||||
:root[data-accent='yellow'] {
|
||||
@include yellow-theme;
|
||||
}
|
||||
|
||||
@mixin font-small {
|
||||
--font-size-body: 0.75rem;
|
||||
--line-height-body: 1rem;
|
||||
--upper-primary-sticky-fold: 4.125rem;
|
||||
--upper-secondary-sticky-fold: 6.188rem;
|
||||
--upper-tertiary-sticky-fold: 8.25rem;
|
||||
--upper-mobile-primary-sticky-fold: 6.625rem;
|
||||
--upper-mobile-secondary-sticky-fold: 8.688rem;
|
||||
--upper-mobile-sticky-fold: 10.75rem;
|
||||
--upper-mobile-tertiary-sticky-fold: 8.25rem;
|
||||
--lower-primary-sticky-fold: 3rem;
|
||||
--lower-secondary-sticky-fold: 5.063rem;
|
||||
--lower-tertiary-sticky-fold: 7.125rem;
|
||||
--sidebar-primary-sticky-fold: 2rem;
|
||||
}
|
||||
|
||||
@mixin font-medium {
|
||||
--font-size-body: 0.875rem;
|
||||
--line-height-body: 1.25rem;
|
||||
--upper-primary-sticky-fold: 4.375rem;
|
||||
--upper-secondary-sticky-fold: 6.688rem;
|
||||
--upper-tertiary-sticky-fold: 9rem;
|
||||
--upper-mobile-primary-sticky-fold: 7.125rem;
|
||||
--upper-mobile-secondary-sticky-fold: 9.438rem;
|
||||
--upper-mobile-sticky-fold: 11.75rem;
|
||||
--upper-mobile-tertiary-sticky-fold: 9rem;
|
||||
--lower-primary-sticky-fold: 3.25rem;
|
||||
--lower-secondary-sticky-fold: 5.563rem;
|
||||
--lower-tertiary-sticky-fold: 7.875rem;
|
||||
--sidebar-primary-sticky-fold: 2.25rem;
|
||||
}
|
||||
|
||||
@mixin font-large {
|
||||
--font-size-body: 1rem;
|
||||
--line-height-body: 1.5rem;
|
||||
--upper-primary-sticky-fold: 4.625rem;
|
||||
--upper-secondary-sticky-fold: 7.188rem;
|
||||
--upper-tertiary-sticky-fold: 9.75rem;
|
||||
--upper-mobile-primary-sticky-fold: 7.625rem;
|
||||
--upper-mobile-secondary-sticky-fold: 10.188rem;
|
||||
--upper-mobile-sticky-fold: 12.75rem;
|
||||
--upper-mobile-tertiary-sticky-fold: 9.75rem;
|
||||
--lower-primary-sticky-fold: 3.5rem;
|
||||
--lower-secondary-sticky-fold: 6.063rem;
|
||||
--lower-tertiary-sticky-fold: 8.625rem;
|
||||
--sidebar-primary-sticky-fold: 2.5rem;
|
||||
}
|
||||
|
||||
:root[data-font-size='small'] {
|
||||
@include font-small;
|
||||
}
|
||||
|
||||
:root[data-font-size='medium'] {
|
||||
@include font-medium;
|
||||
}
|
||||
|
||||
:root[data-font-size='large'] {
|
||||
@include font-large;
|
||||
}
|
||||
|
||||
@@ -1,20 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-font-size="large">
|
||||
|
||||
<head>
|
||||
<script>
|
||||
globalThis.import_meta_env = JSON.parse('"import_meta_env_placeholder"')
|
||||
</script>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Hoppscotch Admin</title>
|
||||
<meta property="og:image" content="/cover.jpg" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
|
||||
<html lang="en">
|
||||
<head>
|
||||
<script>
|
||||
globalThis.import_meta_env = JSON.parse('"import_meta_env_placeholder"');
|
||||
</script>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Hoppscotch Admin</title>
|
||||
<meta property="og:image" content="/cover.jpg" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "hoppscotch-sh-admin",
|
||||
"private": true,
|
||||
"version": "2023.4.8",
|
||||
"version": "2023.8.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "pnpm exec npm-run-all -p -l dev:*",
|
||||
|
||||
43
packages/hoppscotch-sh-admin/src/components.d.ts
vendored
43
packages/hoppscotch-sh-admin/src/components.d.ts
vendored
@@ -1,44 +1,12 @@
|
||||
// generated by unplugin-vue-components
|
||||
// We suggest you to commit this file into source control
|
||||
// Read more: https://github.com/vuejs/core/pull/3399
|
||||
import '@vue/runtime-core';
|
||||
import '@vue/runtime-core'
|
||||
|
||||
export {};
|
||||
export {}
|
||||
|
||||
declare module '@vue/runtime-core' {
|
||||
export interface GlobalComponents {
|
||||
AppHeader: typeof import('./components/app/Header.vue')['default'];
|
||||
AppLogin: typeof import('./components/app/Login.vue')['default'];
|
||||
AppLogout: typeof import('./components/app/Logout.vue')['default'];
|
||||
AppModal: typeof import('./components/app/Modal.vue')['default'];
|
||||
AppSidebar: typeof import('./components/app/Sidebar.vue')['default'];
|
||||
AppToast: typeof import('./components/app/Toast.vue')['default'];
|
||||
DashboardMetricsCard: typeof import('./components/dashboard/MetricsCard.vue')['default'];
|
||||
HoppButtonPrimary: typeof import('@hoppscotch/ui')['HoppButtonPrimary'];
|
||||
HoppButtonSecondary: typeof import('@hoppscotch/ui')['HoppButtonSecondary'];
|
||||
HoppSmartAnchor: typeof import('@hoppscotch/ui')['HoppSmartAnchor'];
|
||||
HoppSmartAutoComplete: typeof import('@hoppscotch/ui')['HoppSmartAutoComplete'];
|
||||
HoppSmartConfirmModal: typeof import('@hoppscotch/ui')['HoppSmartConfirmModal'];
|
||||
HoppSmartInput: typeof import('@hoppscotch/ui')['HoppSmartInput'];
|
||||
HoppSmartItem: typeof import('@hoppscotch/ui')['HoppSmartItem'];
|
||||
HoppSmartModal: typeof import('@hoppscotch/ui')['HoppSmartModal'];
|
||||
HoppSmartPicture: typeof import('@hoppscotch/ui')['HoppSmartPicture'];
|
||||
HoppSmartSpinner: typeof import('@hoppscotch/ui')['HoppSmartSpinner'];
|
||||
HoppSmartTab: typeof import('@hoppscotch/ui')['HoppSmartTab'];
|
||||
IconLucideArrowLeft: typeof import('~icons/lucide/arrow-left')['default'];
|
||||
IconLucideChevronDown: typeof import('~icons/lucide/chevron-down')['default'];
|
||||
IconLucideHelpCircle: typeof import('~icons/lucide/help-circle')['default'];
|
||||
IconLucideInbox: typeof import('~icons/lucide/inbox')['default'];
|
||||
IconLucideUser: typeof import('~icons/lucide/user')['default'];
|
||||
TeamsAdd: typeof import('./components/teams/Add.vue')['default'];
|
||||
TeamsDetails: typeof import('./components/teams/Details.vue')['default'];
|
||||
TeamsInvite: typeof import('./components/teams/Invite.vue')['default'];
|
||||
TeamsMembers: typeof import('./components/teams/Members.vue')['default'];
|
||||
TeamsPendingInvites: typeof import('./components/teams/PendingInvites.vue')['default'];
|
||||
TeamsTable: typeof import('./components/teams/Table.vue')['default'];
|
||||
Tippy: typeof import('vue-tippy')['Tippy'];
|
||||
UsersInviteModal: typeof import('./components/users/InviteModal.vue')['default'];
|
||||
UsersTable: typeof import('./components/users/Table.vue')['default'];
|
||||
AppHeader: typeof import('./components/app/Header.vue')['default']
|
||||
AppLogin: typeof import('./components/app/Login.vue')['default']
|
||||
AppLogout: typeof import('./components/app/Logout.vue')['default']
|
||||
@@ -49,9 +17,15 @@ declare module '@vue/runtime-core' {
|
||||
HoppButtonPrimary: typeof import('@hoppscotch/ui')['HoppButtonPrimary']
|
||||
HoppButtonSecondary: typeof import('@hoppscotch/ui')['HoppButtonSecondary']
|
||||
HoppSmartAnchor: typeof import('@hoppscotch/ui')['HoppSmartAnchor']
|
||||
HoppSmartAutoComplete: typeof import('@hoppscotch/ui')['HoppSmartAutoComplete']
|
||||
HoppSmartConfirmModal: typeof import('@hoppscotch/ui')['HoppSmartConfirmModal']
|
||||
HoppSmartInput: typeof import('@hoppscotch/ui')['HoppSmartInput']
|
||||
HoppSmartItem: typeof import('@hoppscotch/ui')['HoppSmartItem']
|
||||
HoppSmartModal: typeof import('@hoppscotch/ui')['HoppSmartModal']
|
||||
HoppSmartPicture: typeof import('@hoppscotch/ui')['HoppSmartPicture']
|
||||
HoppSmartSpinner: typeof import('@hoppscotch/ui')['HoppSmartSpinner']
|
||||
IconLucideArrowLeft: typeof import('~icons/lucide/arrow-left')['default']
|
||||
IconLucideChevronDown: typeof import('~icons/lucide/chevron-down')['default']
|
||||
IconLucideInbox: typeof import('~icons/lucide/inbox')['default']
|
||||
TeamsAdd: typeof import('./components/teams/Add.vue')['default']
|
||||
TeamsDetails: typeof import('./components/teams/Details.vue')['default']
|
||||
@@ -63,4 +37,5 @@ declare module '@vue/runtime-core' {
|
||||
UsersInviteModal: typeof import('./components/users/InviteModal.vue')['default']
|
||||
UsersTable: typeof import('./components/users/Table.vue')['default']
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -44,8 +44,8 @@
|
||||
:key="index"
|
||||
class="text-secondaryDark hover:bg-zinc-800 hover:cursor-pointer rounded-xl"
|
||||
>
|
||||
<td class="py-2 px-3 max-w-30">
|
||||
<div>
|
||||
<td class="py-2 px-3 max-w-36">
|
||||
<div class="flex">
|
||||
<span class="truncate">
|
||||
{{ user?.adminUid }}
|
||||
</span>
|
||||
@@ -56,10 +56,12 @@
|
||||
{{ user?.adminEmail }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="py-2 px-3">
|
||||
<span>
|
||||
{{ user?.inviteeEmail }}
|
||||
</span>
|
||||
<td class="py-2 px-3 max-w-52">
|
||||
<div class="flex">
|
||||
<span class="truncate">
|
||||
{{ user?.inviteeEmail }}
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="py-2 px-3">
|
||||
<div class="flex items-center">
|
||||
|
||||
@@ -2,7 +2,20 @@
|
||||
--font-sans: "Inter Variable", sans-serif;
|
||||
--font-icon: "Material Symbols Rounded Variable";
|
||||
--font-mono: "Roboto Mono Variable", monospace;
|
||||
--font-size-tiny: calc(var(--font-size-body) - 0.062rem);
|
||||
--font-size-body: 0.75rem;
|
||||
--font-size-tiny: 0.688rem;
|
||||
--line-height-body: 1rem;
|
||||
--upper-primary-sticky-fold: 4.125rem;
|
||||
--upper-secondary-sticky-fold: 6.188rem;
|
||||
--upper-tertiary-sticky-fold: 8.25rem;
|
||||
--upper-mobile-primary-sticky-fold: 6.625rem;
|
||||
--upper-mobile-secondary-sticky-fold: 8.688rem;
|
||||
--upper-mobile-sticky-fold: 10.75rem;
|
||||
--upper-mobile-tertiary-sticky-fold: 8.25rem;
|
||||
--lower-primary-sticky-fold: 3rem;
|
||||
--lower-secondary-sticky-fold: 5.063rem;
|
||||
--lower-tertiary-sticky-fold: 7.125rem;
|
||||
--sidebar-primary-sticky-fold: 2rem;
|
||||
}
|
||||
|
||||
@mixin dark-theme {
|
||||
@@ -200,8 +213,8 @@
|
||||
:root {
|
||||
@include base-theme;
|
||||
@include dark-theme;
|
||||
@include green-theme;
|
||||
@include dark-editor-theme;
|
||||
@include green-theme;
|
||||
}
|
||||
|
||||
:root.light {
|
||||
@@ -257,63 +270,3 @@
|
||||
:root[data-accent="yellow"] {
|
||||
@include yellow-theme;
|
||||
}
|
||||
|
||||
@mixin font-small {
|
||||
--font-size-body: 0.75rem;
|
||||
--line-height-body: 1rem;
|
||||
--upper-primary-sticky-fold: 4.125rem;
|
||||
--upper-secondary-sticky-fold: 6.188rem;
|
||||
--upper-tertiary-sticky-fold: 8.25rem;
|
||||
--upper-mobile-primary-sticky-fold: 6.625rem;
|
||||
--upper-mobile-secondary-sticky-fold: 8.688rem;
|
||||
--upper-mobile-sticky-fold: 10.75rem;
|
||||
--upper-mobile-tertiary-sticky-fold: 8.25rem;
|
||||
--lower-primary-sticky-fold: 3rem;
|
||||
--lower-secondary-sticky-fold: 5.063rem;
|
||||
--lower-tertiary-sticky-fold: 7.125rem;
|
||||
--sidebar-primary-sticky-fold: 2rem;
|
||||
}
|
||||
|
||||
@mixin font-medium {
|
||||
--font-size-body: 0.875rem;
|
||||
--line-height-body: 1.25rem;
|
||||
--upper-primary-sticky-fold: 4.375rem;
|
||||
--upper-secondary-sticky-fold: 6.688rem;
|
||||
--upper-tertiary-sticky-fold: 9rem;
|
||||
--upper-mobile-primary-sticky-fold: 7.125rem;
|
||||
--upper-mobile-secondary-sticky-fold: 9.438rem;
|
||||
--upper-mobile-sticky-fold: 11.75rem;
|
||||
--upper-mobile-tertiary-sticky-fold: 9rem;
|
||||
--lower-primary-sticky-fold: 3.25rem;
|
||||
--lower-secondary-sticky-fold: 5.563rem;
|
||||
--lower-tertiary-sticky-fold: 7.875rem;
|
||||
--sidebar-primary-sticky-fold: 2.25rem;
|
||||
}
|
||||
|
||||
@mixin font-large {
|
||||
--font-size-body: 1rem;
|
||||
--line-height-body: 1.5rem;
|
||||
--upper-primary-sticky-fold: 4.625rem;
|
||||
--upper-secondary-sticky-fold: 7.188rem;
|
||||
--upper-tertiary-sticky-fold: 9.75rem;
|
||||
--upper-mobile-primary-sticky-fold: 7.625rem;
|
||||
--upper-mobile-secondary-sticky-fold: 10.188rem;
|
||||
--upper-mobile-sticky-fold: 12.75rem;
|
||||
--upper-mobile-tertiary-sticky-fold: 9.75rem;
|
||||
--lower-primary-sticky-fold: 3.5rem;
|
||||
--lower-secondary-sticky-fold: 6.063rem;
|
||||
--lower-tertiary-sticky-fold: 8.625rem;
|
||||
--sidebar-primary-sticky-fold: 2.5rem;
|
||||
}
|
||||
|
||||
:root[data-font-size="small"] {
|
||||
@include font-small;
|
||||
}
|
||||
|
||||
:root[data-font-size="medium"] {
|
||||
@include font-medium;
|
||||
}
|
||||
|
||||
:root[data-font-size="large"] {
|
||||
@include font-large;
|
||||
}
|
||||
|
||||
407
pnpm-lock.yaml
generated
407
pnpm-lock.yaml
generated
@@ -1,5 +1,11 @@
|
||||
lockfileVersion: '6.0'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
packageExtensionsChecksum: 18e898b62612ac7acc736e0323d495da
|
||||
|
||||
importers:
|
||||
|
||||
.:
|
||||
@@ -196,7 +202,7 @@ importers:
|
||||
version: 9.1.5
|
||||
'@nestjs/schematics':
|
||||
specifier: ^9.0.3
|
||||
version: 9.0.3(chokidar@3.5.3)(typescript@4.8.4)
|
||||
version: 9.0.3(typescript@4.9.3)
|
||||
'@nestjs/testing':
|
||||
specifier: ^9.2.1
|
||||
version: 9.2.1(@nestjs/common@9.2.1)(@nestjs/core@9.2.1)(@nestjs/platform-express@9.2.1)
|
||||
@@ -498,8 +504,8 @@ importers:
|
||||
specifier: ^2.12.6
|
||||
version: 2.12.6(graphql@16.8.0)
|
||||
httpsnippet:
|
||||
specifier: ^2.0.0
|
||||
version: 2.0.0(mkdirp@1.0.4)
|
||||
specifier: ^3.0.1
|
||||
version: 3.0.1(ajv@6.12.3)
|
||||
insomnia-importers:
|
||||
specifier: ^3.6.0
|
||||
version: 3.6.0(openapi-types@12.1.3)
|
||||
@@ -654,6 +660,9 @@ importers:
|
||||
'@rushstack/eslint-patch':
|
||||
specifier: ^1.3.3
|
||||
version: 1.3.3
|
||||
'@types/har-format':
|
||||
specifier: ^1.2.12
|
||||
version: 1.2.12
|
||||
'@types/js-yaml':
|
||||
specifier: ^4.0.5
|
||||
version: 4.0.5
|
||||
@@ -938,7 +947,7 @@ importers:
|
||||
version: 3.2.0(graphql@16.8.0)
|
||||
'@intlify/vite-plugin-vue-i18n':
|
||||
specifier: ^7.0.0
|
||||
version: 7.0.0(vite@3.2.4)(vue-i18n@9.2.2)
|
||||
version: 7.0.0(vite@4.4.9)
|
||||
'@rushstack/eslint-patch':
|
||||
specifier: ^1.3.3
|
||||
version: 1.3.3
|
||||
@@ -998,7 +1007,7 @@ importers:
|
||||
version: 0.7.38(rollup@2.79.1)(vite@4.4.9)
|
||||
vite-plugin-pages:
|
||||
specifier: ^0.31.0
|
||||
version: 0.31.0(@vue/compiler-sfc@3.3.4)(vite@4.4.9)
|
||||
version: 0.31.0(vite@4.4.9)
|
||||
vite-plugin-pages-sitemap:
|
||||
specifier: ^1.6.1
|
||||
version: 1.6.1
|
||||
@@ -1097,7 +1106,7 @@ importers:
|
||||
version: 0.14.9(@vue/compiler-sfc@3.2.45)(vite@3.2.4)
|
||||
unplugin-vue-components:
|
||||
specifier: ^0.21.0
|
||||
version: 0.21.0(esbuild@0.19.2)(rollup@2.79.1)(vite@3.2.4)(vue@3.2.45)
|
||||
version: 0.21.0(vite@3.2.4)(vue@3.2.45)
|
||||
vue:
|
||||
specifier: ^3.2.6
|
||||
version: 3.2.45
|
||||
@@ -1173,7 +1182,7 @@ importers:
|
||||
version: 1.0.3(vite@3.2.4)
|
||||
vite:
|
||||
specifier: ^3.1.4
|
||||
version: 3.2.4(@types/node@17.0.45)(sass@1.53.0)(terser@5.19.2)
|
||||
version: 3.2.4(@types/node@18.17.6)(sass@1.58.0)
|
||||
vite-plugin-pages:
|
||||
specifier: ^0.26.0
|
||||
version: 0.26.0(@vue/compiler-sfc@3.2.45)(vite@3.2.4)
|
||||
@@ -1276,7 +1285,7 @@ importers:
|
||||
version: 8.29.0
|
||||
eslint-plugin-prettier:
|
||||
specifier: ^4.2.1
|
||||
version: 4.2.1(eslint-config-prettier@8.6.0)(eslint@8.19.0)(prettier@2.8.4)
|
||||
version: 4.2.1(eslint-config-prettier@8.5.0)(eslint@8.29.0)(prettier@2.8.4)
|
||||
eslint-plugin-vue:
|
||||
specifier: ^9.5.1
|
||||
version: 9.5.1(eslint@8.29.0)
|
||||
@@ -3359,6 +3368,7 @@ packages:
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/android-arm@0.15.15:
|
||||
@@ -3392,6 +3402,7 @@ packages:
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/android-x64@0.16.17:
|
||||
@@ -3417,6 +3428,7 @@ packages:
|
||||
cpu: [x64]
|
||||
os: [android]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/darwin-arm64@0.16.17:
|
||||
@@ -3442,6 +3454,7 @@ packages:
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/darwin-x64@0.16.17:
|
||||
@@ -3467,6 +3480,7 @@ packages:
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/freebsd-arm64@0.16.17:
|
||||
@@ -3492,6 +3506,7 @@ packages:
|
||||
cpu: [arm64]
|
||||
os: [freebsd]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/freebsd-x64@0.16.17:
|
||||
@@ -3517,6 +3532,7 @@ packages:
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-arm64@0.16.17:
|
||||
@@ -3542,6 +3558,7 @@ packages:
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-arm@0.16.17:
|
||||
@@ -3567,6 +3584,7 @@ packages:
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-ia32@0.16.17:
|
||||
@@ -3592,6 +3610,7 @@ packages:
|
||||
cpu: [ia32]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-loong64@0.15.15:
|
||||
@@ -3625,6 +3644,7 @@ packages:
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-mips64el@0.16.17:
|
||||
@@ -3650,6 +3670,7 @@ packages:
|
||||
cpu: [mips64el]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-ppc64@0.16.17:
|
||||
@@ -3675,6 +3696,7 @@ packages:
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-riscv64@0.16.17:
|
||||
@@ -3700,6 +3722,7 @@ packages:
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-s390x@0.16.17:
|
||||
@@ -3725,6 +3748,7 @@ packages:
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-x64@0.16.17:
|
||||
@@ -3750,6 +3774,7 @@ packages:
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/netbsd-x64@0.16.17:
|
||||
@@ -3775,6 +3800,7 @@ packages:
|
||||
cpu: [x64]
|
||||
os: [netbsd]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/openbsd-x64@0.16.17:
|
||||
@@ -3800,6 +3826,7 @@ packages:
|
||||
cpu: [x64]
|
||||
os: [openbsd]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/sunos-x64@0.16.17:
|
||||
@@ -3825,6 +3852,7 @@ packages:
|
||||
cpu: [x64]
|
||||
os: [sunos]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/win32-arm64@0.16.17:
|
||||
@@ -3850,6 +3878,7 @@ packages:
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/win32-ia32@0.16.17:
|
||||
@@ -3875,6 +3904,7 @@ packages:
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/win32-x64@0.16.17:
|
||||
@@ -3900,6 +3930,7 @@ packages:
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@eslint-community/eslint-utils@4.4.0(eslint@8.29.0):
|
||||
@@ -6163,12 +6194,39 @@ packages:
|
||||
debug: 4.3.4(supports-color@9.2.2)
|
||||
fast-glob: 3.3.1
|
||||
source-map: 0.6.1
|
||||
vite: 3.2.4(@types/node@17.0.45)(sass@1.53.0)(terser@5.19.2)
|
||||
vite: 3.2.4(@types/node@18.17.6)(sass@1.58.0)
|
||||
vue-i18n: 9.2.2(vue@3.2.45)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/@intlify/vite-plugin-vue-i18n@7.0.0(vite@4.4.9):
|
||||
resolution: {integrity: sha512-2TbDOQ8XD+vkc0s5OFmr+IY/k4mYMC7pzvx0xGQn+cU/ev314+yi7Z7N7rWcBgiYk1WOUalbGSo3d4nJDxOOyw==}
|
||||
engines: {node: '>= 14.6'}
|
||||
deprecated: This plugin support until Vite 3. If you would like to use on Vite 4, please use @intlify/unplugin-vue-i18n
|
||||
peerDependencies:
|
||||
petite-vue-i18n: '*'
|
||||
vite: ^2.9.0 || ^3.0.0
|
||||
vue-i18n: '*'
|
||||
peerDependenciesMeta:
|
||||
petite-vue-i18n:
|
||||
optional: true
|
||||
vite:
|
||||
optional: true
|
||||
vue-i18n:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@intlify/bundle-utils': 3.4.0(vue-i18n@9.2.2)
|
||||
'@intlify/shared': 9.3.0-beta.26
|
||||
'@rollup/pluginutils': 4.2.1
|
||||
debug: 4.3.4(supports-color@9.2.2)
|
||||
fast-glob: 3.3.1
|
||||
source-map: 0.6.1
|
||||
vite: 4.4.9(@types/node@17.0.45)(sass@1.53.0)(terser@5.19.2)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/@intlify/vite-plugin-vue-i18n@7.0.0(vite@4.4.9)(vue-i18n@9.2.2):
|
||||
resolution: {integrity: sha512-2TbDOQ8XD+vkc0s5OFmr+IY/k4mYMC7pzvx0xGQn+cU/ev314+yi7Z7N7rWcBgiYk1WOUalbGSo3d4nJDxOOyw==}
|
||||
engines: {node: '>= 14.6'}
|
||||
@@ -7171,6 +7229,21 @@ packages:
|
||||
- chokidar
|
||||
dev: true
|
||||
|
||||
/@nestjs/schematics@9.0.3(typescript@4.9.3):
|
||||
resolution: {integrity: sha512-kZrU/lrpVd2cnK8I3ibDb3Wi1ppl3wX3U3lVWoL+DzRRoezWKkh8upEL4q0koKmuXnsmLiu3UPxFeMOrJV7TSA==}
|
||||
peerDependencies:
|
||||
typescript: ^4.3.5
|
||||
dependencies:
|
||||
'@angular-devkit/core': 14.2.1(chokidar@3.5.3)
|
||||
'@angular-devkit/schematics': 14.2.1(chokidar@3.5.3)
|
||||
fs-extra: 10.1.0
|
||||
jsonc-parser: 3.2.0
|
||||
pluralize: 8.0.0
|
||||
typescript: 4.9.3
|
||||
transitivePeerDependencies:
|
||||
- chokidar
|
||||
dev: true
|
||||
|
||||
/@nestjs/testing@9.2.1(@nestjs/common@9.2.1)(@nestjs/core@9.2.1)(@nestjs/platform-express@9.2.1):
|
||||
resolution: {integrity: sha512-lemXZdRSuqoZ87l0orCrS/c7gqwxeduIFOd21g9g2RUeQ4qlWPegbQDKASzbfC28klPyrgJLW4MNq7uv2JwV8w==}
|
||||
peerDependencies:
|
||||
@@ -8059,6 +8132,10 @@ packages:
|
||||
'@types/node': 18.17.6
|
||||
dev: true
|
||||
|
||||
/@types/har-format@1.2.12:
|
||||
resolution: {integrity: sha512-P20p/YBrqUBmzD6KhIQ8EiY4/RRzlekL4eCvfQnulFPfjmiGxKIoyCeI7qam5I7oKH3P8EU4ptEi0EfyGoLysw==}
|
||||
dev: true
|
||||
|
||||
/@types/istanbul-lib-coverage@2.0.4:
|
||||
resolution: {integrity: sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==}
|
||||
dev: true
|
||||
@@ -9199,7 +9276,7 @@ packages:
|
||||
vite: ^3.0.0
|
||||
vue: ^3.2.25
|
||||
dependencies:
|
||||
vite: 3.2.4(@types/node@17.0.45)(sass@1.53.0)(terser@5.19.2)
|
||||
vite: 3.2.4(@types/node@18.17.6)(sass@1.58.0)
|
||||
vue: 3.2.45
|
||||
dev: true
|
||||
|
||||
@@ -10232,7 +10309,7 @@ packages:
|
||||
hasBin: true
|
||||
|
||||
/after@0.8.2:
|
||||
resolution: {integrity: sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=}
|
||||
resolution: {integrity: sha512-QbJ0NTQ/I9DI3uSJA4cbexiwQeRAfjPScqIbSjUDd9TOrcg6pTkdgziesOqxBMBzit8vFCTwrP27t13vFOORRA==}
|
||||
dev: false
|
||||
|
||||
/agent-base@6.0.2:
|
||||
@@ -10289,6 +10366,15 @@ packages:
|
||||
ajv: 6.12.6
|
||||
dev: true
|
||||
|
||||
/ajv@6.12.3:
|
||||
resolution: {integrity: sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==}
|
||||
dependencies:
|
||||
fast-deep-equal: 3.1.3
|
||||
fast-json-stable-stringify: 2.1.0
|
||||
json-schema-traverse: 0.4.1
|
||||
uri-js: 4.4.1
|
||||
dev: false
|
||||
|
||||
/ajv@6.12.6:
|
||||
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
|
||||
dependencies:
|
||||
@@ -10329,11 +10415,6 @@ packages:
|
||||
dependencies:
|
||||
type-fest: 0.21.3
|
||||
|
||||
/ansi-regex@2.1.1:
|
||||
resolution: {integrity: sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: false
|
||||
|
||||
/ansi-regex@5.0.1:
|
||||
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -10342,11 +10423,6 @@ packages:
|
||||
resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
/ansi-styles@2.2.1:
|
||||
resolution: {integrity: sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: false
|
||||
|
||||
/ansi-styles@3.2.1:
|
||||
resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==}
|
||||
engines: {node: '>=4'}
|
||||
@@ -10876,7 +10952,7 @@ packages:
|
||||
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
|
||||
|
||||
/base64-arraybuffer@0.1.4:
|
||||
resolution: {integrity: sha1-mBjHngWbE1X5fgQooBfIOOkLqBI=}
|
||||
resolution: {integrity: sha512-a1eIFi4R9ySrbiMuyTGx5e92uRH5tQY6kArNcFaKBUleIoLjdjBg7Zxm3Mqm3Kmkf27HLR/1fnxX9q8GQ7Iavg==}
|
||||
engines: {node: '>= 0.6.0'}
|
||||
dev: false
|
||||
|
||||
@@ -11192,17 +11268,6 @@ packages:
|
||||
type-detect: 4.0.8
|
||||
dev: true
|
||||
|
||||
/chalk@1.1.3:
|
||||
resolution: {integrity: sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dependencies:
|
||||
ansi-styles: 2.2.1
|
||||
escape-string-regexp: 1.0.5
|
||||
has-ansi: 2.0.0
|
||||
strip-ansi: 3.0.1
|
||||
supports-color: 2.0.0
|
||||
dev: false
|
||||
|
||||
/chalk@2.4.2:
|
||||
resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
|
||||
engines: {node: '>=4'}
|
||||
@@ -11450,7 +11515,6 @@ packages:
|
||||
string-width: 4.2.3
|
||||
strip-ansi: 6.0.1
|
||||
wrap-ansi: 7.0.0
|
||||
dev: true
|
||||
|
||||
/clone@1.0.4:
|
||||
resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==}
|
||||
@@ -11569,14 +11633,14 @@ packages:
|
||||
dev: true
|
||||
|
||||
/component-bind@1.0.0:
|
||||
resolution: {integrity: sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=}
|
||||
resolution: {integrity: sha512-WZveuKPeKAG9qY+FkYDeADzdHyTYdIboXS59ixDeRJL5ZhxpqUnxSOwop4FQjMsiYm3/Or8cegVbpAHNA7pHxw==}
|
||||
dev: false
|
||||
|
||||
/component-emitter@1.3.0:
|
||||
resolution: {integrity: sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==}
|
||||
|
||||
/component-inherit@0.0.3:
|
||||
resolution: {integrity: sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=}
|
||||
resolution: {integrity: sha512-w+LhYREhatpVqTESyGFg3NlP6Iu0kEKUHETY9GoZP/pQyW4mHFZuFWRUCIqVPZ36ueVLtoOEZaAqbCF2RDndaA==}
|
||||
dev: false
|
||||
|
||||
/concat-map@0.0.1:
|
||||
@@ -13165,6 +13229,7 @@ packages:
|
||||
'@esbuild/win32-arm64': 0.19.2
|
||||
'@esbuild/win32-ia32': 0.19.2
|
||||
'@esbuild/win32-x64': 0.19.2
|
||||
dev: true
|
||||
|
||||
/escalade@3.1.1:
|
||||
resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==}
|
||||
@@ -13625,15 +13690,15 @@ packages:
|
||||
resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
||||
/event-stream@3.3.4:
|
||||
resolution: {integrity: sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==}
|
||||
/event-stream@4.0.1:
|
||||
resolution: {integrity: sha512-qACXdu/9VHPBzcyhdOWR5/IahhGMf0roTeZJfzz077GwylcDd90yOHLouhmv7GJ5XzPi6ekaQWd8AvPP2nOvpA==}
|
||||
dependencies:
|
||||
duplexer: 0.1.2
|
||||
from: 0.1.7
|
||||
map-stream: 0.1.0
|
||||
map-stream: 0.0.7
|
||||
pause-stream: 0.0.11
|
||||
split: 0.3.3
|
||||
stream-combiner: 0.0.4
|
||||
split: 1.0.1
|
||||
stream-combiner: 0.2.2
|
||||
through: 2.3.8
|
||||
dev: false
|
||||
|
||||
@@ -14115,15 +14180,6 @@ packages:
|
||||
resolution: {integrity: sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==}
|
||||
dev: false
|
||||
|
||||
/form-data@3.0.0:
|
||||
resolution: {integrity: sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==}
|
||||
engines: {node: '>= 6'}
|
||||
dependencies:
|
||||
asynckit: 0.4.0
|
||||
combined-stream: 1.0.8
|
||||
mime-types: 2.1.35
|
||||
dev: false
|
||||
|
||||
/form-data@3.0.1:
|
||||
resolution: {integrity: sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==}
|
||||
engines: {node: '>= 6'}
|
||||
@@ -14244,22 +14300,6 @@ packages:
|
||||
resolution: {integrity: sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==}
|
||||
dev: true
|
||||
|
||||
/fs-readfile-promise@2.0.1:
|
||||
resolution: {integrity: sha512-7+P9eOOMnkIOmtxrBWTzWOBQlE7Nz/cBx9EYTX5hm8DzmZ/Fj9YWeUY2O9G+Q8YblScd1hyEkcmNcZMDj5U8Ug==}
|
||||
dependencies:
|
||||
graceful-fs: 4.2.11
|
||||
dev: false
|
||||
|
||||
/fs-writefile-promise@1.0.3(mkdirp@1.0.4):
|
||||
resolution: {integrity: sha512-yI+wDwj0FsgX7tyIQJR+EP60R64evMSixtGb9AzGWjJVKlF5tCet95KomfqGBg/aIAG1Dhd6wjCOQe5HbX/qLA==}
|
||||
engines: {node: '>=0.10'}
|
||||
dependencies:
|
||||
mkdirp-promise: 1.1.0(mkdirp@1.0.4)
|
||||
pinkie-promise: 1.0.0
|
||||
transitivePeerDependencies:
|
||||
- mkdirp
|
||||
dev: false
|
||||
|
||||
/fs.realpath@1.0.0:
|
||||
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
|
||||
|
||||
@@ -14851,27 +14891,11 @@ packages:
|
||||
engines: {node: '>=4'}
|
||||
dev: false
|
||||
|
||||
/har-validator@5.1.5:
|
||||
resolution: {integrity: sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==}
|
||||
engines: {node: '>=6'}
|
||||
deprecated: this library is no longer supported
|
||||
dependencies:
|
||||
ajv: 6.12.6
|
||||
har-schema: 2.0.0
|
||||
dev: false
|
||||
|
||||
/hard-rejection@2.1.0:
|
||||
resolution: {integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==}
|
||||
engines: {node: '>=6'}
|
||||
dev: true
|
||||
|
||||
/has-ansi@2.0.0:
|
||||
resolution: {integrity: sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dependencies:
|
||||
ansi-regex: 2.1.1
|
||||
dev: false
|
||||
|
||||
/has-bigints@1.0.2:
|
||||
resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==}
|
||||
dev: true
|
||||
@@ -14883,7 +14907,7 @@ packages:
|
||||
dev: false
|
||||
|
||||
/has-cors@1.1.0:
|
||||
resolution: {integrity: sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=}
|
||||
resolution: {integrity: sha512-g5VNKdkFuUuVCP9gYfDJHjK2nqdQJ7aDLTnycnc2+RvsOQbuLdF5pm7vuE5J76SEBIQjs4kQY/BWq74JUmjbXA==}
|
||||
dev: false
|
||||
|
||||
/has-flag@3.0.0:
|
||||
@@ -15194,23 +15218,20 @@ packages:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/httpsnippet@2.0.0(mkdirp@1.0.4):
|
||||
resolution: {integrity: sha512-Hb2ttfB5OhasYxwChZ8QKpYX3v4plNvwMaMulUIC7M3RHRDf1Op6EMp47LfaU2sgQgfvo5spWK4xRAirMEisrg==}
|
||||
engines: {node: '>=10'}
|
||||
/httpsnippet@3.0.1(ajv@6.12.3):
|
||||
resolution: {integrity: sha512-RJbzVu9Gq97Ti76MPKAb9AknKbRluRbzOqswM2qgEW48QUShVEIuJjl43dZG5q0Upj2SZlKqzR6B6ah1q5znfg==}
|
||||
engines: {node: ^14.19.1 || ^16.14.2 || ^18.0.0}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
ajv: 6.12.3
|
||||
dependencies:
|
||||
chalk: 1.1.3
|
||||
commander: 2.20.3
|
||||
debug: 2.6.9
|
||||
event-stream: 3.3.4
|
||||
form-data: 3.0.0
|
||||
fs-readfile-promise: 2.0.1
|
||||
fs-writefile-promise: 1.0.3(mkdirp@1.0.4)
|
||||
har-validator: 5.1.5
|
||||
ajv: 6.12.3
|
||||
chalk: 4.1.2
|
||||
event-stream: 4.0.1
|
||||
form-data: 4.0.0
|
||||
har-schema: 2.0.0
|
||||
stringify-object: 3.3.0
|
||||
transitivePeerDependencies:
|
||||
- mkdirp
|
||||
- supports-color
|
||||
yargs: 17.7.2
|
||||
dev: false
|
||||
|
||||
/human-signals@1.1.1:
|
||||
@@ -15310,7 +15331,7 @@ packages:
|
||||
engines: {node: '>=8'}
|
||||
|
||||
/indexof@0.0.1:
|
||||
resolution: {integrity: sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=}
|
||||
resolution: {integrity: sha512-i0G7hLJ1z0DE8dsqJa2rycj9dBmNKgXBvotXtZYXakU9oivfB9Uj2ZBC27qqef2U58/ZLwalxa1X/RDCdkHtVg==}
|
||||
dev: false
|
||||
|
||||
/inflight@1.0.6:
|
||||
@@ -17722,8 +17743,8 @@ packages:
|
||||
engines: {node: '>=8'}
|
||||
dev: true
|
||||
|
||||
/map-stream@0.1.0:
|
||||
resolution: {integrity: sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==}
|
||||
/map-stream@0.0.7:
|
||||
resolution: {integrity: sha512-C0X0KQmGm3N2ftbTGBhSyuydQ+vV1LC3f3zPvT3RXHXNZrvfPZcoXp/N5DOa8vedX/rTMm2CjTtivFg2STJMRQ==}
|
||||
dev: false
|
||||
|
||||
/markdown-it-anchor@8.6.6(@types/markdown-it@12.2.3)(markdown-it@12.3.2):
|
||||
@@ -18351,16 +18372,6 @@ packages:
|
||||
- encoding
|
||||
dev: false
|
||||
|
||||
/mkdirp-promise@1.1.0(mkdirp@1.0.4):
|
||||
resolution: {integrity: sha512-xzB0UZFcW1UGS2xkXeDh39jzTP282lb3Vwp4QzCQYmkTn4ysaV5dBdbkOXmhkcE1TQlZebQlgTceaWvDr3oFgw==}
|
||||
engines: {node: '>=4'}
|
||||
deprecated: This package is broken and no longer maintained. 'mkdirp' itself supports promises now, please switch to that.
|
||||
peerDependencies:
|
||||
mkdirp: '>=0.5.0'
|
||||
dependencies:
|
||||
mkdirp: 1.0.4
|
||||
dev: false
|
||||
|
||||
/mkdirp@0.5.6:
|
||||
resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==}
|
||||
hasBin: true
|
||||
@@ -19237,18 +19248,6 @@ packages:
|
||||
engines: {node: '>=4'}
|
||||
dev: true
|
||||
|
||||
/pinkie-promise@1.0.0:
|
||||
resolution: {integrity: sha512-5mvtVNse2Ml9zpFKkWBpGsTPwm3DKhs+c95prO/F6E7d6DN0FPqxs6LONpLNpyD7Iheb7QN4BbUoKJgo+DnkQA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dependencies:
|
||||
pinkie: 1.0.0
|
||||
dev: false
|
||||
|
||||
/pinkie@1.0.0:
|
||||
resolution: {integrity: sha512-VFVaU1ysKakao68ktZm76PIdOhvEfoNNRaGkyLln9Os7r0/MCxqHjHyBM7dT3pgTiBybqiPtpqKfpENwdBp50Q==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: false
|
||||
|
||||
/pirates@4.0.5:
|
||||
resolution: {integrity: sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==}
|
||||
engines: {node: '>= 6'}
|
||||
@@ -19698,7 +19697,6 @@ packages:
|
||||
resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
|
||||
dependencies:
|
||||
safe-buffer: 5.2.1
|
||||
dev: true
|
||||
|
||||
/range-parser@1.2.1:
|
||||
resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
|
||||
@@ -20018,7 +20016,7 @@ packages:
|
||||
resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
glob: 7.2.0
|
||||
glob: 7.2.3
|
||||
dev: false
|
||||
|
||||
/rimraf@3.0.2:
|
||||
@@ -20254,7 +20252,6 @@ packages:
|
||||
chokidar: 3.5.3
|
||||
immutable: 4.3.2
|
||||
source-map-js: 1.0.2
|
||||
dev: true
|
||||
|
||||
/sass@1.66.0:
|
||||
resolution: {integrity: sha512-C3U+RgpAAlTXULZkWwzfysgbbBBo8IZudNAOJAVBLslFbIaZv4MBPkTqhuvpK4lqgdoFiWhnOGMoV4L1FyOBag==}
|
||||
@@ -20397,7 +20394,6 @@ packages:
|
||||
resolution: {integrity: sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==}
|
||||
dependencies:
|
||||
randombytes: 2.1.0
|
||||
dev: true
|
||||
|
||||
/serve-static@1.15.0:
|
||||
resolution: {integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==}
|
||||
@@ -20745,8 +20741,8 @@ packages:
|
||||
readable-stream: 3.6.0
|
||||
dev: true
|
||||
|
||||
/split@0.3.3:
|
||||
resolution: {integrity: sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==}
|
||||
/split@1.0.1:
|
||||
resolution: {integrity: sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==}
|
||||
dependencies:
|
||||
through: 2.3.8
|
||||
dev: false
|
||||
@@ -20807,10 +20803,11 @@ packages:
|
||||
readable-stream: 3.6.0
|
||||
dev: false
|
||||
|
||||
/stream-combiner@0.0.4:
|
||||
resolution: {integrity: sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==}
|
||||
/stream-combiner@0.2.2:
|
||||
resolution: {integrity: sha512-6yHMqgLYDzQDcAkL+tjJDC5nSNuNIx0vZtRZeiPh7Saef7VHX9H5Ijn9l2VIol2zaNYlYEX6KyuT/237A58qEQ==}
|
||||
dependencies:
|
||||
duplexer: 0.1.2
|
||||
through: 2.3.8
|
||||
dev: false
|
||||
|
||||
/streamsearch@1.1.0:
|
||||
@@ -20928,13 +20925,6 @@ packages:
|
||||
is-obj: 1.0.1
|
||||
is-regexp: 1.0.0
|
||||
|
||||
/strip-ansi@3.0.1:
|
||||
resolution: {integrity: sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dependencies:
|
||||
ansi-regex: 2.1.1
|
||||
dev: false
|
||||
|
||||
/strip-ansi@6.0.1:
|
||||
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -21019,7 +21009,7 @@ packages:
|
||||
graphql: 15.8.0
|
||||
iterall: 1.3.0
|
||||
symbol-observable: 1.2.0
|
||||
ws: 7.4.6
|
||||
ws: 7.5.9
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- utf-8-validate
|
||||
@@ -21113,11 +21103,6 @@ packages:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/supports-color@2.0.0:
|
||||
resolution: {integrity: sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==}
|
||||
engines: {node: '>=0.8.0'}
|
||||
dev: false
|
||||
|
||||
/supports-color@5.5.0:
|
||||
resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
|
||||
engines: {node: '>=4'}
|
||||
@@ -21287,7 +21272,7 @@ packages:
|
||||
'@jridgewell/trace-mapping': 0.3.14
|
||||
jest-worker: 27.5.1
|
||||
schema-utils: 3.1.1
|
||||
serialize-javascript: 6.0.0
|
||||
serialize-javascript: 6.0.1
|
||||
terser: 5.14.1
|
||||
webpack: 5.74.0
|
||||
dev: true
|
||||
@@ -21453,7 +21438,7 @@ packages:
|
||||
dev: true
|
||||
|
||||
/to-array@0.1.4:
|
||||
resolution: {integrity: sha1-F+bBH3PdTz10zaek/zI46a2b+JA=}
|
||||
resolution: {integrity: sha512-LhVdShQD/4Mk4zXNroIQZJC+Ap3zgLcDuwEdcmLv9CCO73NWockQDwyUnW/m8VX/EElfL6FcYx7EeutN4HJA6A==}
|
||||
dev: false
|
||||
|
||||
/to-fast-properties@2.0.0:
|
||||
@@ -22184,7 +22169,7 @@ packages:
|
||||
dependencies:
|
||||
fast-glob: 3.2.12
|
||||
unplugin: 1.4.0
|
||||
vite: 3.2.4(@types/node@17.0.45)(sass@1.53.0)(terser@5.19.2)
|
||||
vite: 3.2.4(@types/node@18.17.6)(sass@1.58.0)
|
||||
dev: true
|
||||
|
||||
/unplugin-fonts@1.0.3(vite@4.4.9):
|
||||
@@ -22322,6 +22307,36 @@ packages:
|
||||
- supports-color
|
||||
- vite
|
||||
- webpack
|
||||
dev: true
|
||||
|
||||
/unplugin-vue-components@0.21.0(vite@3.2.4)(vue@3.2.45):
|
||||
resolution: {integrity: sha512-U7uOMNmRJ2eAv9CNjP8QRvxs6nAe3FVQUEIUphC1FGguBp3BWSLgGAcSHaX2nQy0gFoDY2mLF2M52W/t/eDaKg==}
|
||||
engines: {node: '>=14'}
|
||||
peerDependencies:
|
||||
'@babel/parser': ^7.15.8
|
||||
vue: 2 || 3
|
||||
peerDependenciesMeta:
|
||||
'@babel/parser':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@antfu/utils': 0.5.2
|
||||
'@rollup/pluginutils': 4.2.1
|
||||
chokidar: 3.5.3
|
||||
debug: 4.3.4(supports-color@9.2.2)
|
||||
fast-glob: 3.3.1
|
||||
local-pkg: 0.4.3
|
||||
magic-string: 0.26.7
|
||||
minimatch: 5.1.6
|
||||
resolve: 1.22.4
|
||||
unplugin: 0.7.1(vite@3.2.4)
|
||||
vue: 3.2.45
|
||||
transitivePeerDependencies:
|
||||
- esbuild
|
||||
- rollup
|
||||
- supports-color
|
||||
- vite
|
||||
- webpack
|
||||
dev: false
|
||||
|
||||
/unplugin-vue-components@0.25.1(rollup@2.79.1)(vue@3.3.4):
|
||||
resolution: {integrity: sha512-kzS2ZHVMaGU2XEO2keYQcMjNZkanDSGDdY96uQT9EPe+wqSZwwgbFfKVJ5ti0+8rGAcKHColwKUvctBhq2LJ3A==}
|
||||
@@ -22376,6 +22391,31 @@ packages:
|
||||
vite: 3.2.4(@types/node@17.0.45)(sass@1.53.0)(terser@5.19.2)
|
||||
webpack-sources: 3.2.3
|
||||
webpack-virtual-modules: 0.4.4
|
||||
dev: true
|
||||
|
||||
/unplugin@0.7.1(vite@3.2.4):
|
||||
resolution: {integrity: sha512-Z6hNDXDNh9aimMkPU1mEjtk+2ova8gh0y7rJeJdGH1vWZOHwF2lLQiQ/R97rv9ymmzEQXsR2fyMet72T8jy6ew==}
|
||||
peerDependencies:
|
||||
esbuild: '>=0.13'
|
||||
rollup: ^2.50.0
|
||||
vite: ^2.3.0 || ^3.0.0-0
|
||||
webpack: 4 || 5
|
||||
peerDependenciesMeta:
|
||||
esbuild:
|
||||
optional: true
|
||||
rollup:
|
||||
optional: true
|
||||
vite:
|
||||
optional: true
|
||||
webpack:
|
||||
optional: true
|
||||
dependencies:
|
||||
acorn: 8.10.0
|
||||
chokidar: 3.5.3
|
||||
vite: 3.2.4(@types/node@18.17.6)(sass@1.58.0)
|
||||
webpack-sources: 3.2.3
|
||||
webpack-virtual-modules: 0.4.4
|
||||
dev: false
|
||||
|
||||
/unplugin@0.9.5(vite@3.2.4):
|
||||
resolution: {integrity: sha512-luraheyfxwtvkvHpsOvMNv7IjLdORTWKZp0gWYNHGLi2ImON3iIZOj464qEyyEwLA/EMt12fC415HW9zRpOfTg==}
|
||||
@@ -22396,7 +22436,7 @@ packages:
|
||||
dependencies:
|
||||
acorn: 8.10.0
|
||||
chokidar: 3.5.3
|
||||
vite: 3.2.4(@types/node@17.0.45)(sass@1.53.0)(terser@5.19.2)
|
||||
vite: 3.2.4(@types/node@18.17.6)(sass@1.58.0)
|
||||
webpack-sources: 3.2.3
|
||||
webpack-virtual-modules: 0.4.4
|
||||
dev: false
|
||||
@@ -22639,7 +22679,7 @@ packages:
|
||||
mlly: 1.2.0
|
||||
pathe: 1.1.0
|
||||
picocolors: 1.0.0
|
||||
vite: 4.4.9(@types/node@17.0.45)(sass@1.53.0)(terser@5.19.2)
|
||||
vite: 4.4.9(@types/node@18.17.6)(sass@1.66.0)(terser@5.19.2)
|
||||
transitivePeerDependencies:
|
||||
- '@types/node'
|
||||
- less
|
||||
@@ -22809,6 +22849,7 @@ packages:
|
||||
|
||||
/vite-plugin-fonts@0.6.0(vite@3.2.4):
|
||||
resolution: {integrity: sha512-dV6nnLEju8k5EmvlBH6egxkVZ+rgc5zWsJr9+cNRXBMEDnpRGHcZPI260UEDNg2yB99wSTNER2eduEvZFbMIGw==}
|
||||
deprecated: renamed to `unplugin-fonts`, see https://github.com/cssninjaStudio/unplugin-fonts/releases/tag/v1.0.0
|
||||
peerDependencies:
|
||||
vite: ^2.0.0 || ^3.0.0
|
||||
dependencies:
|
||||
@@ -22818,6 +22859,7 @@ packages:
|
||||
|
||||
/vite-plugin-fonts@0.6.0(vite@4.4.9):
|
||||
resolution: {integrity: sha512-dV6nnLEju8k5EmvlBH6egxkVZ+rgc5zWsJr9+cNRXBMEDnpRGHcZPI260UEDNg2yB99wSTNER2eduEvZFbMIGw==}
|
||||
deprecated: renamed to `unplugin-fonts`, see https://github.com/cssninjaStudio/unplugin-fonts/releases/tag/v1.0.0
|
||||
peerDependencies:
|
||||
vite: ^2.0.0 || ^3.0.0
|
||||
dependencies:
|
||||
@@ -22910,7 +22952,7 @@ packages:
|
||||
json5: 2.2.3
|
||||
local-pkg: 0.4.3
|
||||
picocolors: 1.0.0
|
||||
vite: 3.2.4(@types/node@17.0.45)(sass@1.53.0)(terser@5.19.2)
|
||||
vite: 3.2.4(@types/node@18.17.6)(sass@1.58.0)
|
||||
yaml: 2.3.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -22940,6 +22982,29 @@ packages:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/vite-plugin-pages@0.31.0(vite@4.4.9):
|
||||
resolution: {integrity: sha512-fw3onBfVTXQI7rOzAbSZhmfwvk50+3qNnGZpERjmD93c8nEjrGLyd53eFXYMxcJV4KA1vzi4qIHt2+6tS4dEMw==}
|
||||
peerDependencies:
|
||||
'@vue/compiler-sfc': ^2.7.0 || ^3.0.0
|
||||
vite: ^2.0.0 || ^3.0.0-0 || ^4.0.0
|
||||
peerDependenciesMeta:
|
||||
'@vue/compiler-sfc':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@types/debug': 4.1.8
|
||||
debug: 4.3.4(supports-color@9.2.2)
|
||||
deep-equal: 2.2.2
|
||||
extract-comments: 1.1.0
|
||||
fast-glob: 3.3.1
|
||||
json5: 2.2.3
|
||||
local-pkg: 0.4.3
|
||||
picocolors: 1.0.0
|
||||
vite: 4.4.9(@types/node@17.0.45)(sass@1.53.0)(terser@5.19.2)
|
||||
yaml: 2.3.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/vite-plugin-pwa@0.13.1(vite@3.2.4)(workbox-build@6.6.0)(workbox-window@6.6.0):
|
||||
resolution: {integrity: sha512-NR3dIa+o2hzlzo4lF4Gu0cYvoMjSw2DdRc6Epw1yjmCqWaGuN86WK9JqZie4arNlE1ZuWT3CLiMdiX5wcmmUmg==}
|
||||
peerDependencies:
|
||||
@@ -22999,7 +23064,7 @@ packages:
|
||||
'@vue/compiler-sfc': 3.3.4
|
||||
debug: 4.3.4(supports-color@9.2.2)
|
||||
fast-glob: 3.3.1
|
||||
vite: 3.2.4(@types/node@17.0.45)(sass@1.53.0)(terser@5.19.2)
|
||||
vite: 3.2.4(@types/node@18.17.6)(sass@1.58.0)
|
||||
vue: 3.2.45
|
||||
vue-router: 4.1.0(vue@3.2.45)
|
||||
transitivePeerDependencies:
|
||||
@@ -23031,7 +23096,7 @@ packages:
|
||||
'@windicss/plugin-utils': 1.8.8
|
||||
debug: 4.3.4(supports-color@9.2.2)
|
||||
kolorist: 1.8.0
|
||||
vite: 3.2.4(@types/node@17.0.45)(sass@1.53.0)(terser@5.19.2)
|
||||
vite: 3.2.4(@types/node@18.17.6)(sass@1.58.0)
|
||||
windicss: 3.5.6
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -23086,6 +23151,40 @@ packages:
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.2
|
||||
|
||||
/vite@3.2.4(@types/node@18.17.6)(sass@1.58.0):
|
||||
resolution: {integrity: sha512-Z2X6SRAffOUYTa+sLy3NQ7nlHFU100xwanq1WDwqaiFiCe+25zdxP1TfCS5ojPV2oDDcXudHIoPnI1Z/66B7Yw==}
|
||||
engines: {node: ^14.18.0 || >=16.0.0}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
'@types/node': '>= 14'
|
||||
less: '*'
|
||||
sass: '*'
|
||||
stylus: '*'
|
||||
sugarss: '*'
|
||||
terser: ^5.4.0
|
||||
peerDependenciesMeta:
|
||||
'@types/node':
|
||||
optional: true
|
||||
less:
|
||||
optional: true
|
||||
sass:
|
||||
optional: true
|
||||
stylus:
|
||||
optional: true
|
||||
sugarss:
|
||||
optional: true
|
||||
terser:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@types/node': 18.17.6
|
||||
esbuild: 0.15.15
|
||||
postcss: 8.4.28
|
||||
resolve: 1.22.4
|
||||
rollup: 2.79.1
|
||||
sass: 1.58.0
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.2
|
||||
|
||||
/vite@4.0.4(@types/node@17.0.45):
|
||||
resolution: {integrity: sha512-xevPU7M8FU0i/80DMR+YhgrzR5KS2ORy1B4xcX/cXLsvnUWvfHuqMmVU6N0YiJ4JWGRJJsLCgjEzKjG9/GKoSw==}
|
||||
engines: {node: ^14.18.0 || >=16.0.0}
|
||||
@@ -23285,7 +23384,7 @@ packages:
|
||||
tinybench: 2.5.0
|
||||
tinypool: 0.4.0
|
||||
tinyspy: 1.1.1
|
||||
vite: 3.2.4(@types/node@17.0.45)(sass@1.53.0)(terser@5.19.2)
|
||||
vite: 3.2.4(@types/node@18.17.6)(sass@1.58.0)
|
||||
vite-node: 0.29.8(@types/node@18.17.6)
|
||||
why-is-node-running: 2.2.2
|
||||
transitivePeerDependencies:
|
||||
@@ -24514,7 +24613,6 @@ packages:
|
||||
optional: true
|
||||
utf-8-validate:
|
||||
optional: true
|
||||
dev: true
|
||||
|
||||
/ws@8.11.0:
|
||||
resolution: {integrity: sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==}
|
||||
@@ -24761,7 +24859,6 @@ packages:
|
||||
string-width: 4.2.3
|
||||
y18n: 5.0.8
|
||||
yargs-parser: 21.1.1
|
||||
dev: true
|
||||
|
||||
/yauzl@2.10.0:
|
||||
resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==}
|
||||
@@ -24771,7 +24868,7 @@ packages:
|
||||
dev: false
|
||||
|
||||
/yeast@0.1.2:
|
||||
resolution: {integrity: sha1-AI4G2AlDIMNy28L47XagymyKxBk=}
|
||||
resolution: {integrity: sha512-8HFIh676uyGYP6wP13R/j6OJ/1HwJ46snpvzE7aHAN3Ryqh2yX6Xox2B4CUmTwwOIzlG3Bs7ocsP5dZH/R1Qbg==}
|
||||
dev: false
|
||||
|
||||
/yn@3.1.1:
|
||||
|
||||
Reference in New Issue
Block a user