chore: merge hoppscotch/patch into hoppscotch/next
This commit is contained in:
commit
cfb77f2bfe
52 changed files with 629 additions and 364 deletions
17
.github/pull_request_template.md
vendored
17
.github/pull_request_template.md
vendored
|
|
@ -7,20 +7,15 @@ Please make sure that the pull request is limited to one type (docs, feature, et
|
||||||
<!-- If this pull request closes an issue, please mention the issue number below -->
|
<!-- If this pull request closes an issue, please mention the issue number below -->
|
||||||
Closes # <!-- Issue # here -->
|
Closes # <!-- Issue # here -->
|
||||||
|
|
||||||
### Description
|
<!-- Add an introduction into what this PR tries to solve in a couple of sentences -->
|
||||||
<!-- Add a brief description of the pull request -->
|
|
||||||
|
### What's changed
|
||||||
|
<!-- Describe point by point the different things you have changed in this PR -->
|
||||||
|
|
||||||
<!-- You can also choose to add a list of changes and if they have been completed or not by using the markdown to-do list syntax
|
<!-- You can also choose to add a list of changes and if they have been completed or not by using the markdown to-do list syntax
|
||||||
- [ ] Not Completed
|
- [ ] Not Completed
|
||||||
- [x] Completed
|
- [x] Completed
|
||||||
-->
|
-->
|
||||||
|
|
||||||
### Checks
|
### Notes to reviewers
|
||||||
<!-- Make sure your pull request passes the CI checks and do check the following fields as needed - -->
|
<!-- Any information you feel the reviewer should know about when reviewing your PR -->
|
||||||
- [ ] My pull request adheres to the code style of this project
|
|
||||||
- [ ] My code requires changes to the documentation
|
|
||||||
- [ ] I have updated the documentation as required
|
|
||||||
- [ ] All the tests have passed
|
|
||||||
|
|
||||||
### Additional Information
|
|
||||||
<!-- Any additional information like breaking changes, dependencies added, screenshots, comparisons between new and old behaviour, etc. -->
|
|
||||||
|
|
|
||||||
35
CODEOWNERS
35
CODEOWNERS
|
|
@ -1,30 +1,21 @@
|
||||||
# CODEOWNERS is prioritized from bottom to top
|
# CODEOWNERS is prioritized from bottom to top
|
||||||
|
|
||||||
# If none of the below matched
|
|
||||||
* @AndrewBastin @liyasthomas
|
|
||||||
|
|
||||||
# Packages
|
# Packages
|
||||||
/packages/codemirror-lang-graphql/ @AndrewBastin
|
/packages/codemirror-lang-graphql/ @AndrewBastin
|
||||||
/packages/hoppscotch-cli/ @AndrewBastin
|
/packages/hoppscotch-cli/ @jamesgeorge007
|
||||||
/packages/hoppscotch-common/ @amk-dev @AndrewBastin
|
|
||||||
/packages/hoppscotch-data/ @AndrewBastin
|
/packages/hoppscotch-data/ @AndrewBastin
|
||||||
/packages/hoppscotch-js-sandbox/ @AndrewBastin
|
/packages/hoppscotch-js-sandbox/ @jamesgeorge007
|
||||||
/packages/hoppscotch-ui/ @anwarulislam
|
/packages/hoppscotch-selfhost-web/ @jamesgeorge007
|
||||||
/packages/hoppscotch-web/ @amk-dev
|
/packages/hoppscotch-selfhost-desktop/ @AndrewBastin
|
||||||
/packages/hoppscotch-selfhost-web/ @amk-dev
|
|
||||||
/packages/hoppscotch-sh-admin/ @JoelJacobStephen
|
/packages/hoppscotch-sh-admin/ @JoelJacobStephen
|
||||||
/packages/hoppscotch-backend/ @ankitsridhar16 @balub
|
/packages/hoppscotch-backend/ @balub
|
||||||
|
|
||||||
# Sections within Hoppscotch Common
|
# READMEs and other documentation files
|
||||||
/packages/hoppscotch-common/src/components @anwarulislam
|
*.md @liyasthomas
|
||||||
/packages/hoppscotch-common/src/components/collections @nivedin @amk-dev
|
|
||||||
/packages/hoppscotch-common/src/components/environments @nivedin @amk-dev
|
|
||||||
/packages/hoppscotch-common/src/composables @amk-dev
|
|
||||||
/packages/hoppscotch-common/src/modules @AndrewBastin @amk-dev
|
|
||||||
/packages/hoppscotch-common/src/pages @AndrewBastin @amk-dev
|
|
||||||
/packages/hoppscotch-common/src/newstore @AndrewBastin @amk-dev
|
|
||||||
|
|
||||||
README.md @liyasthomas
|
# Self Host deployment related files
|
||||||
|
*.Dockerfile @balub
|
||||||
# The lockfile has no owner
|
docker-compose.yml @balub
|
||||||
pnpm-lock.yaml
|
docker-compose.deploy.yml @balub
|
||||||
|
*.Caddyfile @balub
|
||||||
|
.dockerignore @balub
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,4 @@ Please note we have a code of conduct, please follow it in all your interactions
|
||||||
build.
|
build.
|
||||||
2. Update the README.md with details of changes to the interface, this includes new environment
|
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.
|
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
|
3. Make sure you do not expose environment variables or other sensitive information in your PR.
|
||||||
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.
|
|
||||||
|
|
|
||||||
27
SECURITY.md
27
SECURITY.md
|
|
@ -4,19 +4,36 @@ This document outlines security procedures and general policies for the Hoppscot
|
||||||
|
|
||||||
- [Security Policy](#security-policy)
|
- [Security Policy](#security-policy)
|
||||||
- [Reporting a security vulnerability](#reporting-a-security-vulnerability)
|
- [Reporting a security vulnerability](#reporting-a-security-vulnerability)
|
||||||
|
- [What is not a valid vulnerability](#what-is-not-a-valid-vulnerability)
|
||||||
- [Incident response process](#incident-response-process)
|
- [Incident response process](#incident-response-process)
|
||||||
|
|
||||||
## Reporting a security vulnerability
|
## Reporting a security vulnerability
|
||||||
|
|
||||||
Report security vulnerabilities by emailing the Hoppscotch Support team at support@hoppscotch.io.
|
We use [Github Security Advisories](https://github.com/hoppscotch/hoppscotch/security/advisories) to manage vulnerability reports and collaboration.
|
||||||
|
Someone from the Hoppscotch team shall report to you within 48 hours of the disclosure of the vulnerability in GHSA. If no response was received, please reach out to
|
||||||
|
Hoppscotch Support at support@hoppscotch.io along with the GHSA advisory link.
|
||||||
|
|
||||||
The primary security point of contact from Hoppscotch Support team will acknowledge your email within 48 hours, and will send a more detailed response within 48 hours indicating the next steps in handling your report. After the initial reply to your report, the security team will endeavor to keep you informed of the progress towards a fix and full announcement, and may ask for additional information or guidance.
|
> NOTE: Since we have multiple open source components, Advisories may move into the relevant repo (for example, an XSS in a UI component might be part of [`@hoppscotch/ui`](https://github.com/hoppscotch/ui)).
|
||||||
|
> If in doubt, open your report in `hoppscotch/hoppscotch` GHSA.
|
||||||
|
|
||||||
**Do not create a GitHub issue ticket to report a security vulnerability.**
|
**Do not create a GitHub issue ticket to report a security vulnerability!**
|
||||||
|
|
||||||
The Hoppscotch team and community take all security vulnerability reports in Hoppscotch seriously. Thank you for improving the security of Hoppscotch. We appreciate your efforts and responsible disclosure and will make every effort to acknowledge your contributions.
|
The Hoppscotch team takes all security vulnerability reports in Hoppscotch seriously. We appreciate your efforts and responsible disclosure and will make every effort to acknowledge your contributions.
|
||||||
|
|
||||||
Report security bugs in third-party modules to the person or team maintaining the module.
|
## What is not a valid vulnerability
|
||||||
|
We receive many reports about different sections of the Hoppscotch platform. Hence, we have a fine line we have drawn defining what is considered valid vulnerability.
|
||||||
|
Please refrain from opening an advisory if it describes the following:
|
||||||
|
|
||||||
|
- A vulnerability in a dependency of Hoppscotch (unless you have practical attack with it on the Hoppscotch codebase)
|
||||||
|
- Reports of vulnerabilities related to old runtimes (like NodeJS) or container images used by the codebase
|
||||||
|
- Vulnerabilities present when using Hoppscotch in anything other than the defined minimum requirements that Hoppscotch supports.
|
||||||
|
|
||||||
|
Hoppscotch Team ensures security support for:
|
||||||
|
- Modern Browsers (Chrome/Firefox/Safari/Edge) with versions up to 1 year old.
|
||||||
|
- Windows versions on or above Windows 10 on Intel and ARM.
|
||||||
|
- macOS versions dating back up to 2 years on Intel and Apple Silicon.
|
||||||
|
- Popular Linux distributions with up-to-date packages with preference to x86/64 CPUs.
|
||||||
|
- Docker/OCI Runtimes (preference to Docker and Podman) dating back up to 1 year.
|
||||||
|
|
||||||
## Incident response process
|
## Incident response process
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "hoppscotch-backend",
|
"name": "hoppscotch-backend",
|
||||||
"version": "2024.3.3",
|
"version": "2024.3.4",
|
||||||
"description": "",
|
"description": "",
|
||||||
"author": "",
|
"author": "",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
|
|
||||||
|
|
@ -112,6 +112,7 @@ describe('AdminService', () => {
|
||||||
NOT: {
|
NOT: {
|
||||||
inviteeEmail: {
|
inviteeEmail: {
|
||||||
in: [dbAdminUsers[0].email],
|
in: [dbAdminUsers[0].email],
|
||||||
|
mode: 'insensitive',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -220,7 +221,10 @@ describe('AdminService', () => {
|
||||||
|
|
||||||
expect(mockPrisma.invitedUsers.deleteMany).toHaveBeenCalledWith({
|
expect(mockPrisma.invitedUsers.deleteMany).toHaveBeenCalledWith({
|
||||||
where: {
|
where: {
|
||||||
inviteeEmail: { in: [invitedUsers[0].inviteeEmail] },
|
inviteeEmail: {
|
||||||
|
in: [invitedUsers[0].inviteeEmail],
|
||||||
|
mode: 'insensitive',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
expect(result).toEqualRight(true);
|
expect(result).toEqualRight(true);
|
||||||
|
|
|
||||||
|
|
@ -89,12 +89,17 @@ export class AdminService {
|
||||||
adminEmail: string,
|
adminEmail: string,
|
||||||
inviteeEmail: string,
|
inviteeEmail: string,
|
||||||
) {
|
) {
|
||||||
if (inviteeEmail == adminEmail) return E.left(DUPLICATE_EMAIL);
|
if (inviteeEmail.toLowerCase() == adminEmail.toLowerCase()) {
|
||||||
|
return E.left(DUPLICATE_EMAIL);
|
||||||
|
}
|
||||||
if (!validateEmail(inviteeEmail)) return E.left(INVALID_EMAIL);
|
if (!validateEmail(inviteeEmail)) return E.left(INVALID_EMAIL);
|
||||||
|
|
||||||
const alreadyInvitedUser = await this.prisma.invitedUsers.findFirst({
|
const alreadyInvitedUser = await this.prisma.invitedUsers.findFirst({
|
||||||
where: {
|
where: {
|
||||||
inviteeEmail: inviteeEmail,
|
inviteeEmail: {
|
||||||
|
equals: inviteeEmail,
|
||||||
|
mode: 'insensitive',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
if (alreadyInvitedUser != null) return E.left(USER_ALREADY_INVITED);
|
if (alreadyInvitedUser != null) return E.left(USER_ALREADY_INVITED);
|
||||||
|
|
@ -159,7 +164,7 @@ export class AdminService {
|
||||||
try {
|
try {
|
||||||
await this.prisma.invitedUsers.deleteMany({
|
await this.prisma.invitedUsers.deleteMany({
|
||||||
where: {
|
where: {
|
||||||
inviteeEmail: { in: inviteeEmails },
|
inviteeEmail: { in: inviteeEmails, mode: 'insensitive' },
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
return E.right(true);
|
return E.right(true);
|
||||||
|
|
@ -189,6 +194,7 @@ export class AdminService {
|
||||||
NOT: {
|
NOT: {
|
||||||
inviteeEmail: {
|
inviteeEmail: {
|
||||||
in: userEmailObjs.map((user) => user.email),
|
in: userEmailObjs.map((user) => user.email),
|
||||||
|
mode: 'insensitive',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -299,7 +299,10 @@ export class ShortcodeService implements UserDataHandler, OnModuleInit {
|
||||||
where: userEmail
|
where: userEmail
|
||||||
? {
|
? {
|
||||||
User: {
|
User: {
|
||||||
email: userEmail,
|
email: {
|
||||||
|
equals: userEmail,
|
||||||
|
mode: 'insensitive',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
|
|
|
||||||
|
|
@ -75,12 +75,13 @@ export class TeamInvitationService {
|
||||||
if (!isEmailValid) return E.left(INVALID_EMAIL);
|
if (!isEmailValid) return E.left(INVALID_EMAIL);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const teamInvite = await this.prisma.teamInvitation.findUniqueOrThrow({
|
const teamInvite = await this.prisma.teamInvitation.findFirstOrThrow({
|
||||||
where: {
|
where: {
|
||||||
teamID_inviteeEmail: {
|
inviteeEmail: {
|
||||||
inviteeEmail: inviteeEmail,
|
equals: inviteeEmail,
|
||||||
teamID: teamID,
|
mode: 'insensitive',
|
||||||
},
|
},
|
||||||
|
teamID,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -157,7 +157,7 @@ beforeEach(() => {
|
||||||
describe('UserService', () => {
|
describe('UserService', () => {
|
||||||
describe('findUserByEmail', () => {
|
describe('findUserByEmail', () => {
|
||||||
test('should successfully return a valid user given a valid email', async () => {
|
test('should successfully return a valid user given a valid email', async () => {
|
||||||
mockPrisma.user.findUniqueOrThrow.mockResolvedValueOnce(user);
|
mockPrisma.user.findFirst.mockResolvedValueOnce(user);
|
||||||
|
|
||||||
const result = await userService.findUserByEmail(
|
const result = await userService.findUserByEmail(
|
||||||
'dwight@dundermifflin.com',
|
'dwight@dundermifflin.com',
|
||||||
|
|
@ -166,7 +166,7 @@ describe('UserService', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should return a null user given a invalid email', async () => {
|
test('should return a null user given a invalid email', async () => {
|
||||||
mockPrisma.user.findUniqueOrThrow.mockRejectedValueOnce('NotFoundError');
|
mockPrisma.user.findFirst.mockResolvedValueOnce(null);
|
||||||
|
|
||||||
const result = await userService.findUserByEmail('jim@dundermifflin.com');
|
const result = await userService.findUserByEmail('jim@dundermifflin.com');
|
||||||
expect(result).resolves.toBeNone;
|
expect(result).resolves.toBeNone;
|
||||||
|
|
|
||||||
|
|
@ -62,16 +62,16 @@ export class UserService {
|
||||||
* @returns Option of found User
|
* @returns Option of found User
|
||||||
*/
|
*/
|
||||||
async findUserByEmail(email: string): Promise<O.None | O.Some<AuthUser>> {
|
async findUserByEmail(email: string): Promise<O.None | O.Some<AuthUser>> {
|
||||||
try {
|
const user = await this.prisma.user.findFirst({
|
||||||
const user = await this.prisma.user.findUniqueOrThrow({
|
|
||||||
where: {
|
where: {
|
||||||
email: email,
|
email: {
|
||||||
|
equals: email,
|
||||||
|
mode: 'insensitive',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
if (!user) return O.none;
|
||||||
return O.some(user);
|
return O.some(user);
|
||||||
} catch (error) {
|
|
||||||
return O.none;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -17,15 +17,17 @@
|
||||||
"dismiss": "Boşver",
|
"dismiss": "Boşver",
|
||||||
"dont_save": "Don't save",
|
"dont_save": "Don't save",
|
||||||
"download_file": "Dosyayı Indir",
|
"download_file": "Dosyayı Indir",
|
||||||
"drag_to_reorder": "Drag to reorder",
|
"drag_to_reorder": "Yeniden sıralamak için sürükleyin",
|
||||||
"duplicate": "Klonla",
|
"duplicate": "Klonla",
|
||||||
"edit": "Düzenle",
|
"edit": "Düzenle",
|
||||||
"filter": "Filter",
|
"filter": "Filtre",
|
||||||
"go_back": "Geri git",
|
"go_back": "Geri git",
|
||||||
"go_forward": "Go forward",
|
"go_forward": "İleri git",
|
||||||
"group_by": "Group by",
|
"group_by": "Group by",
|
||||||
|
"hide_secret": "Hide secret",
|
||||||
"label": "Etiket",
|
"label": "Etiket",
|
||||||
"learn_more": "Daha fazla bilgi edin",
|
"learn_more": "Daha fazla bilgi edin",
|
||||||
|
"download_here": "Download here",
|
||||||
"less": "Daha az",
|
"less": "Daha az",
|
||||||
"more": "Daha fazla",
|
"more": "Daha fazla",
|
||||||
"new": "Yeni",
|
"new": "Yeni",
|
||||||
|
|
@ -42,8 +44,9 @@
|
||||||
"scroll_to_top": "Scroll to top",
|
"scroll_to_top": "Scroll to top",
|
||||||
"search": "Arama",
|
"search": "Arama",
|
||||||
"send": "Gönder",
|
"send": "Gönder",
|
||||||
"share": "Share",
|
"share": "Paylaş",
|
||||||
"start": "Başla",
|
"start": "Başla",
|
||||||
|
"show_secret": "Show secret",
|
||||||
"starting": "Starting",
|
"starting": "Starting",
|
||||||
"stop": "Dur",
|
"stop": "Dur",
|
||||||
"to_close": "kapatmak için",
|
"to_close": "kapatmak için",
|
||||||
|
|
@ -101,16 +104,18 @@
|
||||||
"auth": {
|
"auth": {
|
||||||
"account_exists": "Farklı kimlik bilgilerine sahip hesap var - Her iki hesabı birbirine bağlamak için giriş yapın",
|
"account_exists": "Farklı kimlik bilgilerine sahip hesap var - Her iki hesabı birbirine bağlamak için giriş yapın",
|
||||||
"all_sign_in_options": "Tüm oturum açma seçenekleri",
|
"all_sign_in_options": "Tüm oturum açma seçenekleri",
|
||||||
|
"continue_with_auth_provider": "{provider} ile devam et",
|
||||||
"continue_with_email": "E-posta ile devam et",
|
"continue_with_email": "E-posta ile devam et",
|
||||||
"continue_with_github": "GitHub hesabı ile devam et",
|
"continue_with_github": "GitHub ile devam et",
|
||||||
"continue_with_google": "Google hesabı ile devam et",
|
"continue_with_github_enterprise": "GitHub Enterprise ile devam et",
|
||||||
"continue_with_microsoft": "Microsoft hesabı ile devam et",
|
"continue_with_google": "Google ile devam et",
|
||||||
|
"continue_with_microsoft": "Microsoft ile devam et",
|
||||||
"email": "E-posta",
|
"email": "E-posta",
|
||||||
"logged_out": "Çıkış yapıldı",
|
"logged_out": "Çıkış yapıldı",
|
||||||
"login": "Giriş yap",
|
"login": "Giriş",
|
||||||
"login_success": "Başarıyla giriş yapıldı",
|
"login_success": "Başarıyla giriş yapıldı",
|
||||||
"login_to_hoppscotch": "Hoppscotch'a giriş yapın",
|
"login_to_hoppscotch": "Hoppscotch'a giriş yapın",
|
||||||
"logout": "Çıkış yap",
|
"logout": "Çıkış",
|
||||||
"re_enter_email": "E-mail adresinizi yeniden girin",
|
"re_enter_email": "E-mail adresinizi yeniden girin",
|
||||||
"send_magic_link": "Sihirli bir bağlantı gönder",
|
"send_magic_link": "Sihirli bir bağlantı gönder",
|
||||||
"sync": "Senkronizasyon",
|
"sync": "Senkronizasyon",
|
||||||
|
|
@ -135,20 +140,42 @@
|
||||||
"redirect_no_token_endpoint": "No Token Endpoint Defined",
|
"redirect_no_token_endpoint": "No Token Endpoint Defined",
|
||||||
"something_went_wrong_on_oauth_redirect": "Something went wrong during OAuth Redirect",
|
"something_went_wrong_on_oauth_redirect": "Something went wrong during OAuth Redirect",
|
||||||
"something_went_wrong_on_token_generation": "Something went wrong on token generation",
|
"something_went_wrong_on_token_generation": "Something went wrong on token generation",
|
||||||
"token_generation_oidc_discovery_failed": "Failure on token generation: OpenID Connect Discovery Failed"
|
"token_generation_oidc_discovery_failed": "Failure on token generation: OpenID Connect Discovery Failed",
|
||||||
|
"grant_type": "Grant Type",
|
||||||
|
"grant_type_auth_code": "Authorization Code",
|
||||||
|
"token_fetched_successfully": "Token fetched successfully",
|
||||||
|
"token_fetch_failed": "Failed to fetch token",
|
||||||
|
"validation_failed": "Validation Failed, please check the form fields",
|
||||||
|
"label_authorization_endpoint": "Authorization Endpoint",
|
||||||
|
"label_client_id": "Client ID",
|
||||||
|
"label_client_secret": "Client Secret",
|
||||||
|
"label_code_challenge": "Code Challenge",
|
||||||
|
"label_code_challenge_method": "Code Challenge Method",
|
||||||
|
"label_code_verifier": "Code Verifier",
|
||||||
|
"label_scopes": "Scopes",
|
||||||
|
"label_token_endpoint": "Token Endpoint",
|
||||||
|
"label_use_pkce": "Use PKCE",
|
||||||
|
"label_implicit": "Implicit",
|
||||||
|
"label_password": "Password",
|
||||||
|
"label_username": "Username",
|
||||||
|
"label_auth_code": "Authorization Code",
|
||||||
|
"label_client_credentials": "Client Credentials"
|
||||||
},
|
},
|
||||||
"pass_key_by": "Şunla anahtar ekleyin",
|
"pass_key_by": "Şunla anahtar ekleyin",
|
||||||
|
"pass_by_query_params_label": "Query Parameters",
|
||||||
|
"pass_by_headers_label": "Headers",
|
||||||
"password": "Parola",
|
"password": "Parola",
|
||||||
"save_to_inherit": "Please save this request in any collection to inherit the authorization",
|
"save_to_inherit": "Please save this request in any collection to inherit the authorization",
|
||||||
"token": "Jeton",
|
"token": "Jeton",
|
||||||
"type": "Yetki türü",
|
"type": "Yetki Türü",
|
||||||
"username": "Kullanıcı adı"
|
"username": "Kullanıcı adı"
|
||||||
},
|
},
|
||||||
"collection": {
|
"collection": {
|
||||||
"created": "Koleksiyon oluşturuldu",
|
"created": "Koleksiyon oluşturuldu",
|
||||||
"different_parent": "Cannot reorder collection with different parent",
|
"different_parent": "Cannot reorder collection with different parent",
|
||||||
"edit": "Koleksiyonu düzenle",
|
"edit": "Koleksiyonu düzenle",
|
||||||
"import_or_create": "Import or create a collection",
|
"import_or_create": "Koleksiyon oluşturun veya içe aktarın",
|
||||||
|
"import_collection":"Koleksiyonu İçe Aktar",
|
||||||
"invalid_name": "Lütfen koleksiyon için geçerli bir ad girin",
|
"invalid_name": "Lütfen koleksiyon için geçerli bir ad girin",
|
||||||
"invalid_root_move": "Collection already in the root",
|
"invalid_root_move": "Collection already in the root",
|
||||||
"moved": "Başarıyla taşındı",
|
"moved": "Başarıyla taşındı",
|
||||||
|
|
@ -158,15 +185,13 @@
|
||||||
"new": "Yeni koleksiyon",
|
"new": "Yeni koleksiyon",
|
||||||
"order_changed": "Collection Order Updated",
|
"order_changed": "Collection Order Updated",
|
||||||
"properties": "Collection Properties",
|
"properties": "Collection Properties",
|
||||||
"properties_updated": "Collection Properties Updated",
|
"properties_updated": "Koleksiyon Özellikleri Güncellendi",
|
||||||
"renamed": "Koleksiyon yeniden adlandırıldı",
|
"renamed": "Koleksiyon yeniden adlandırıldı",
|
||||||
"request_in_use": "Kullanımda istek",
|
"request_in_use": "Kullanımda istek",
|
||||||
"save_as": "Farklı kaydet",
|
"save_as": "Farklı kaydet",
|
||||||
"save_to_collection": "Save to Collection",
|
"save_to_collection": "Save to Collection",
|
||||||
"select": "Bir koleksiyon Seçin",
|
"select": "Bir koleksiyon Seçin",
|
||||||
"select_location": "Konum seçin",
|
"select_location": "Konum seçin"
|
||||||
"select_team": "Bir takım seçin",
|
|
||||||
"team_collections": "Takım koleksiyonları"
|
|
||||||
},
|
},
|
||||||
"confirm": {
|
"confirm": {
|
||||||
"close_unsaved_tab": "Are you sure you want to close this tab?",
|
"close_unsaved_tab": "Are you sure you want to close this tab?",
|
||||||
|
|
@ -237,14 +262,15 @@
|
||||||
"pending_invites": "Bu takım için bekleyen bir istek yok",
|
"pending_invites": "Bu takım için bekleyen bir istek yok",
|
||||||
"profile": "Bu profili görüntülemek için giriş yapın",
|
"profile": "Bu profili görüntülemek için giriş yapın",
|
||||||
"protocols": "Protokoller boş",
|
"protocols": "Protokoller boş",
|
||||||
|
"request_variables": "This request does not have any request variables",
|
||||||
"schema": "Bir GraphQL uç noktasına bağlanma",
|
"schema": "Bir GraphQL uç noktasına bağlanma",
|
||||||
|
"secret_environments": "Secrets are not synced to Hoppscotch",
|
||||||
"shared_requests": "Shared requests are empty",
|
"shared_requests": "Shared requests are empty",
|
||||||
"shared_requests_logout": "Login to view your shared requests or create a new one",
|
"shared_requests_logout": "Login to view your shared requests or create a new one",
|
||||||
"subscription": "Subscriptions are empty",
|
"subscription": "Subscriptions are empty",
|
||||||
"team_name": "Takım adı boş",
|
"team_name": "Takım adı boş",
|
||||||
"teams": "Takımlar boş",
|
"teams": "Takımlar boş",
|
||||||
"tests": "Bu istek için test yok",
|
"tests": "Bu istek için test yok"
|
||||||
"shortcodes": "Shortcodes are empty"
|
|
||||||
},
|
},
|
||||||
"environment": {
|
"environment": {
|
||||||
"add_to_global": "Globale ekle",
|
"add_to_global": "Globale ekle",
|
||||||
|
|
@ -260,24 +286,27 @@
|
||||||
"import_or_create": "Import or create a environment",
|
"import_or_create": "Import or create a environment",
|
||||||
"invalid_name": "Lütfen ortam için geçerli bir ad girin",
|
"invalid_name": "Lütfen ortam için geçerli bir ad girin",
|
||||||
"list": "Environment variables",
|
"list": "Environment variables",
|
||||||
"my_environments": "My Environments",
|
"my_environments": "Ortamlarım",
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
"nested_overflow": "İç içe ortam değişkenleri 10 düzeyle sınırlıdır",
|
"nested_overflow": "İç içe ortam değişkenleri 10 düzeyle sınırlıdır",
|
||||||
"new": "Yeni ortam",
|
"new": "Yeni ortam",
|
||||||
"no_active_environment": "No active environment",
|
"no_active_environment": "Aktif ortam yok",
|
||||||
"no_environment": "Ortam yok",
|
"no_environment": "Ortam yok",
|
||||||
"no_environment_description": "Hiçbir ortam seçilmedi. Aşağıdaki değişkenlerle ne yapacağınızı seçin.",
|
"no_environment_description": "Hiçbir ortam seçilmedi. Aşağıdaki değişkenlerle ne yapacağınızı seçin.",
|
||||||
"quick_peek": "Environment Quick Peek",
|
"quick_peek": "Environment Quick Peek",
|
||||||
"replace_with_variable": "Replace with variable",
|
"replace_with_variable": "Replace with variable",
|
||||||
"scope": "Scope",
|
"scope": "Scope",
|
||||||
|
"secrets": "Secrets",
|
||||||
|
"secret_value": "Secret value",
|
||||||
"select": "Ortam seçin",
|
"select": "Ortam seçin",
|
||||||
"set": "Set environment",
|
"set": "Set environment",
|
||||||
"set_as_environment": "Set as environment",
|
"set_as_environment": "Set as environment",
|
||||||
"team_environments": "Team Environments",
|
"team_environments": "Team Environments",
|
||||||
"title": "Ortamlar",
|
"title": "Ortamlar",
|
||||||
"updated": "Ortam güncellendi",
|
"updated": "Ortam güncellendi",
|
||||||
"value": "Value",
|
"value": "Değer",
|
||||||
"variable": "Variable",
|
"variable": "Değişken",
|
||||||
|
"variables": "Değişkenler",
|
||||||
"variable_list": "Değişken listesi"
|
"variable_list": "Değişken listesi"
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
|
|
@ -289,6 +318,7 @@
|
||||||
"danger_zone": "Danger zone",
|
"danger_zone": "Danger zone",
|
||||||
"delete_account": "Your account is currently an owner in these teams:",
|
"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_description": "You must either remove yourself, transfer ownership, or delete these teams before you can delete your account.",
|
||||||
|
"empty_profile_name": "Profile name cannot be empty",
|
||||||
"empty_req_name": "Boş İstek Adı",
|
"empty_req_name": "Boş İstek Adı",
|
||||||
"f12_details": "(Ayrıntılar için F12)",
|
"f12_details": "(Ayrıntılar için F12)",
|
||||||
"gql_prettify_invalid_query": "Geçersiz bir sorgu güzelleştirilemedi, sorgu sözdizimi hatalarını çözüp tekrar deneyin",
|
"gql_prettify_invalid_query": "Geçersiz bir sorgu güzelleştirilemedi, sorgu sözdizimi hatalarını çözüp tekrar deneyin",
|
||||||
|
|
@ -296,7 +326,8 @@
|
||||||
"incorrect_email": "Geçersiz e-posta",
|
"incorrect_email": "Geçersiz e-posta",
|
||||||
"invalid_link": "Geçersiz bağlantı",
|
"invalid_link": "Geçersiz bağlantı",
|
||||||
"invalid_link_description": "Tıkladığınız linkin süresi geçmiş veya geçersiz",
|
"invalid_link_description": "Tıkladığınız linkin süresi geçmiş veya geçersiz",
|
||||||
"json_parsing_failed": "Invalid JSON",
|
"invalid_embed_link": "The embed does not exist or is invalid.",
|
||||||
|
"json_parsing_failed": "Geçersiz JSON",
|
||||||
"json_prettify_invalid_body": "Geçersiz bir gövde güzelleştirilemedi, JSON sözdizimi hatalarını çözüp tekrar deneyin",
|
"json_prettify_invalid_body": "Geçersiz bir gövde güzelleştirilemedi, JSON sözdizimi hatalarını çözüp tekrar deneyin",
|
||||||
"network_error": "Görünene göre bir ağ hatası var. Lütfen tekrar deneyin.",
|
"network_error": "Görünene göre bir ağ hatası var. Lütfen tekrar deneyin.",
|
||||||
"network_fail": "İstek gönderilemedi",
|
"network_fail": "İstek gönderilemedi",
|
||||||
|
|
@ -307,22 +338,26 @@
|
||||||
"page_not_found": "This page could not be found",
|
"page_not_found": "This page could not be found",
|
||||||
"please_install_extension": "Please install the extension and add origin to the extension.",
|
"please_install_extension": "Please install the extension and add origin to the extension.",
|
||||||
"proxy_error": "Proxy error",
|
"proxy_error": "Proxy error",
|
||||||
|
"same_profile_name": "Updated profile name is same as the current profile name",
|
||||||
"script_fail": "Ön istek komut dosyası çalıştırılamadı",
|
"script_fail": "Ön istek komut dosyası çalıştırılamadı",
|
||||||
"something_went_wrong": "Bir şeyler yanlış gitti",
|
"something_went_wrong": "Bir şeyler yanlış gitti",
|
||||||
"test_script_fail": "Could not execute post-request script"
|
"test_script_fail": "Could not execute post-request script",
|
||||||
|
"reading_files": "Error while reading one or more files."
|
||||||
},
|
},
|
||||||
"export": {
|
"export": {
|
||||||
"as_json": "JSON olarak dışa aktar",
|
"as_json": "JSON olarak dışa aktar",
|
||||||
"create_secret_gist": "Gizli Gist oluştur",
|
"create_secret_gist": "Gizli Gist oluştur",
|
||||||
|
"create_secret_gist_tooltip_text": "Export as secret Gist",
|
||||||
"failed": "Something went wrong while exporting",
|
"failed": "Something went wrong while exporting",
|
||||||
"gist_created": "Gist oluşturuldu",
|
|
||||||
"require_github": "Gizli Gist oluşturmak için GitHub ile giriş yapın",
|
"require_github": "Gizli Gist oluşturmak için GitHub ile giriş yapın",
|
||||||
|
"secret_gist_success": "Successfully exported as secret Gist",
|
||||||
|
"success": "Successfully exported",
|
||||||
"title": "Dışarı Aktar"
|
"title": "Dışarı Aktar"
|
||||||
},
|
},
|
||||||
"filter": {
|
"filter": {
|
||||||
"all": "All",
|
"all": "Tümü",
|
||||||
"none": "None",
|
"none": "Hiçbiri",
|
||||||
"starred": "Starred"
|
"starred": "Yıldızlı"
|
||||||
},
|
},
|
||||||
"folder": {
|
"folder": {
|
||||||
"created": "Klasör oluşturuldu",
|
"created": "Klasör oluşturuldu",
|
||||||
|
|
@ -339,7 +374,8 @@
|
||||||
"mutations": "Mutasyonlar",
|
"mutations": "Mutasyonlar",
|
||||||
"schema": "Şema",
|
"schema": "Şema",
|
||||||
"subscriptions": "Abonelikler",
|
"subscriptions": "Abonelikler",
|
||||||
"switch_connection": "Switch connection"
|
"switch_connection": "Switch connection",
|
||||||
|
"url_placeholder": "Enter a GraphQL endpoint URL"
|
||||||
},
|
},
|
||||||
"graphql_collections": {
|
"graphql_collections": {
|
||||||
"title": "GraphQL Collections"
|
"title": "GraphQL Collections"
|
||||||
|
|
@ -379,6 +415,8 @@
|
||||||
"environments_from_gist": "Import From Gist",
|
"environments_from_gist": "Import From Gist",
|
||||||
"environments_from_gist_description": "Import Hoppscotch Environments From Gist",
|
"environments_from_gist_description": "Import Hoppscotch Environments From Gist",
|
||||||
"failed": "İçe aktarılamadı",
|
"failed": "İçe aktarılamadı",
|
||||||
|
"file_size_limit_exceeded_warning_multiple_files": "Chosen files exceed the recommended limit of 10MB. Only the first {files} selected will be imported",
|
||||||
|
"file_size_limit_exceeded_warning_single_file": "The currently chosen file exceeds the recommended limit of 10MB. Please select another file.",
|
||||||
"from_file": "Import from File",
|
"from_file": "Import from File",
|
||||||
"from_gist": "Gist'ten içe aktar",
|
"from_gist": "Gist'ten içe aktar",
|
||||||
"from_gist_description": "Gist ile içe aktar",
|
"from_gist_description": "Gist ile içe aktar",
|
||||||
|
|
@ -405,12 +443,15 @@
|
||||||
"json_description": "Import collections from a Hoppscotch Collections JSON file",
|
"json_description": "Import collections from a Hoppscotch Collections JSON file",
|
||||||
"postman_environment": "Postman Environment",
|
"postman_environment": "Postman Environment",
|
||||||
"postman_environment_description": "Import Postman Environment from a JSON file",
|
"postman_environment_description": "Import Postman Environment from a JSON file",
|
||||||
|
"success": "Successfully imported",
|
||||||
"title": "İçe aktar"
|
"title": "İçe aktar"
|
||||||
},
|
},
|
||||||
"inspections": {
|
"inspections": {
|
||||||
"description": "Inspect possible errors",
|
"description": "Inspect possible errors",
|
||||||
"environment": {
|
"environment": {
|
||||||
"add_environment": "Add to Environment",
|
"add_environment": "Add to Environment",
|
||||||
|
"add_environment_value": "Add value",
|
||||||
|
"empty_value": "Environment value is empty for the variable '{variable}' ",
|
||||||
"not_found": "Environment variable “{environment}” not found."
|
"not_found": "Environment variable “{environment}” not found."
|
||||||
},
|
},
|
||||||
"header": {
|
"header": {
|
||||||
|
|
@ -546,6 +587,7 @@
|
||||||
"raw_body": "Ham istek gövdesi",
|
"raw_body": "Ham istek gövdesi",
|
||||||
"rename": "Rename Request",
|
"rename": "Rename Request",
|
||||||
"renamed": "Yeniden adlandırılmış istek",
|
"renamed": "Yeniden adlandırılmış istek",
|
||||||
|
"request_variables": "Request variables",
|
||||||
"run": "Çalıştır",
|
"run": "Çalıştır",
|
||||||
"save": "Kaydet",
|
"save": "Kaydet",
|
||||||
"save_as": "Farklı kaydet",
|
"save_as": "Farklı kaydet",
|
||||||
|
|
@ -557,9 +599,9 @@
|
||||||
"title": "İstek",
|
"title": "İstek",
|
||||||
"type": "İstek türü",
|
"type": "İstek türü",
|
||||||
"url": "URL",
|
"url": "URL",
|
||||||
|
"url_placeholder": "Enter a URL or paste a cURL command",
|
||||||
"variables": "Değişkenler",
|
"variables": "Değişkenler",
|
||||||
"view_my_links": "View my links",
|
"view_my_links": "View my links"
|
||||||
"copy_link": "Bağlantıyı kopyala"
|
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"audio": "Audio",
|
"audio": "Audio",
|
||||||
|
|
@ -611,7 +653,7 @@
|
||||||
"profile_description": "Profil detaylarını güncelle",
|
"profile_description": "Profil detaylarını güncelle",
|
||||||
"profile_email": "E-posta adresi",
|
"profile_email": "E-posta adresi",
|
||||||
"profile_name": "Profil ismi",
|
"profile_name": "Profil ismi",
|
||||||
"proxy": "vekil",
|
"proxy": "Proxy",
|
||||||
"proxy_url": "Proxy URL'si",
|
"proxy_url": "Proxy URL'si",
|
||||||
"proxy_use_toggle": "İstek göndermek için proxy ara yazılımını kullanın",
|
"proxy_use_toggle": "İstek göndermek için proxy ara yazılımını kullanın",
|
||||||
"read_the": "Oku",
|
"read_the": "Oku",
|
||||||
|
|
@ -704,8 +746,7 @@
|
||||||
"send_request": "İstek gönder",
|
"send_request": "İstek gönder",
|
||||||
"share_request": "Share Request",
|
"share_request": "Share Request",
|
||||||
"show_code": "Generate code snippet",
|
"show_code": "Generate code snippet",
|
||||||
"title": "İstek",
|
"title": "İstek"
|
||||||
"copy_request_link": "İstek bağlantısını kopyala"
|
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"copy": "Copy response to clipboard",
|
"copy": "Copy response to clipboard",
|
||||||
|
|
@ -726,6 +767,11 @@
|
||||||
"more": "Daha fazla göster",
|
"more": "Daha fazla göster",
|
||||||
"sidebar": "Kenar çubuğunu göster"
|
"sidebar": "Kenar çubuğunu göster"
|
||||||
},
|
},
|
||||||
|
"site_protection": {
|
||||||
|
"error_fetching_site_protection_status": "Something Went Wrong While Fetching Site Protection Status",
|
||||||
|
"login_to_continue": "Login to continue",
|
||||||
|
"login_to_continue_description": "You need to be logged in to access this Hoppscotch Enterprise Instance."
|
||||||
|
},
|
||||||
"socketio": {
|
"socketio": {
|
||||||
"communication": "İletişim",
|
"communication": "İletişim",
|
||||||
"connection_not_authorized": "This SocketIO connection does not use any authentication.",
|
"connection_not_authorized": "This SocketIO connection does not use any authentication.",
|
||||||
|
|
@ -763,6 +809,13 @@
|
||||||
"invite": "Invite your friends to Hoppscotch",
|
"invite": "Invite your friends to Hoppscotch",
|
||||||
"title": "Miscellaneous"
|
"title": "Miscellaneous"
|
||||||
},
|
},
|
||||||
|
"phrases": {
|
||||||
|
"create_environment": "Create environment",
|
||||||
|
"create_workspace": "Create workspace",
|
||||||
|
"import_collections": "Import collections",
|
||||||
|
"share_request": "Share request",
|
||||||
|
"try": "Try"
|
||||||
|
},
|
||||||
"request": {
|
"request": {
|
||||||
"save_as_new": "Save as new request",
|
"save_as_new": "Save as new request",
|
||||||
"select_method": "Select method",
|
"select_method": "Select method",
|
||||||
|
|
@ -867,7 +920,6 @@
|
||||||
"forum": "Sorular sorun ve cevaplar alın",
|
"forum": "Sorular sorun ve cevaplar alın",
|
||||||
"github": "Bizi Github'da takip edin",
|
"github": "Bizi Github'da takip edin",
|
||||||
"shortcuts": "Uygulamaya daha hızlı göz atın",
|
"shortcuts": "Uygulamaya daha hızlı göz atın",
|
||||||
"team": "Takımla iletişim kurun",
|
|
||||||
"title": "Destek",
|
"title": "Destek",
|
||||||
"twitter": "Bizi Twitter'da takip edin"
|
"twitter": "Bizi Twitter'da takip edin"
|
||||||
},
|
},
|
||||||
|
|
@ -888,6 +940,7 @@
|
||||||
"queries": "Sorgular",
|
"queries": "Sorgular",
|
||||||
"query": "Sorgu",
|
"query": "Sorgu",
|
||||||
"schema": "Schema",
|
"schema": "Schema",
|
||||||
|
"share_tab_request": "Share tab request",
|
||||||
"shared_requests": "Shared Requests",
|
"shared_requests": "Shared Requests",
|
||||||
"socketio": "Socket.IO",
|
"socketio": "Socket.IO",
|
||||||
"sse": "SSE",
|
"sse": "SSE",
|
||||||
|
|
@ -917,7 +970,6 @@
|
||||||
"invite_tooltip": "İnsanları bu çalışma alanına davet edin",
|
"invite_tooltip": "İnsanları bu çalışma alanına davet edin",
|
||||||
"invited_to_team": "{owner} seni {team} takımına davet etti.",
|
"invited_to_team": "{owner} seni {team} takımına davet etti.",
|
||||||
"join": "Davet kabul edildi",
|
"join": "Davet kabul edildi",
|
||||||
"join_beta": "Takımlara erişmek için beta programına katılın.",
|
|
||||||
"join_team": "{team}'e katıl",
|
"join_team": "{team}'e katıl",
|
||||||
"joined_team": "{team} takımına katıldın",
|
"joined_team": "{team} takımına katıldın",
|
||||||
"joined_team_description": "Artık bu takımın bir üyesisin",
|
"joined_team_description": "Artık bu takımın bir üyesisin",
|
||||||
|
|
@ -946,6 +998,7 @@
|
||||||
"permissions": "İzinler",
|
"permissions": "İzinler",
|
||||||
"same_target_destination": "Same target and destination",
|
"same_target_destination": "Same target and destination",
|
||||||
"saved": "Takım kaydedildi",
|
"saved": "Takım kaydedildi",
|
||||||
|
"search_title": "Team Requests",
|
||||||
"select_a_team": "Takım seç",
|
"select_a_team": "Takım seç",
|
||||||
"success_invites": "Success invites",
|
"success_invites": "Success invites",
|
||||||
"title": "Başlık",
|
"title": "Başlık",
|
||||||
|
|
@ -976,6 +1029,7 @@
|
||||||
},
|
},
|
||||||
"workspace": {
|
"workspace": {
|
||||||
"change": "Change workspace",
|
"change": "Change workspace",
|
||||||
|
"other_workspaces": "My Workspaces",
|
||||||
"personal": "My Workspace",
|
"personal": "My Workspace",
|
||||||
"team": "Team Workspace",
|
"team": "Team Workspace",
|
||||||
"title": "Workspaces"
|
"title": "Workspaces"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "@hoppscotch/common",
|
"name": "@hoppscotch/common",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "2024.3.3",
|
"version": "2024.3.4",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "pnpm exec npm-run-all -p -l dev:*",
|
"dev": "pnpm exec npm-run-all -p -l dev:*",
|
||||||
"test": "vitest --run",
|
"test": "vitest --run",
|
||||||
|
|
|
||||||
13
packages/hoppscotch-common/src/components.d.ts
vendored
13
packages/hoppscotch-common/src/components.d.ts
vendored
|
|
@ -1,11 +1,11 @@
|
||||||
/* eslint-disable */
|
// generated by unplugin-vue-components
|
||||||
/* prettier-ignore */
|
// We suggest you to commit this file into source control
|
||||||
// @ts-nocheck
|
|
||||||
// Generated by unplugin-vue-components
|
|
||||||
// Read more: https://github.com/vuejs/core/pull/3399
|
// Read more: https://github.com/vuejs/core/pull/3399
|
||||||
|
import '@vue/runtime-core'
|
||||||
|
|
||||||
export {}
|
export {}
|
||||||
|
|
||||||
declare module 'vue' {
|
declare module '@vue/runtime-core' {
|
||||||
export interface GlobalComponents {
|
export interface GlobalComponents {
|
||||||
AppActionHandler: typeof import('./components/app/ActionHandler.vue')['default']
|
AppActionHandler: typeof import('./components/app/ActionHandler.vue')['default']
|
||||||
AppBanner: typeof import('./components/app/Banner.vue')['default']
|
AppBanner: typeof import('./components/app/Banner.vue')['default']
|
||||||
|
|
@ -148,7 +148,6 @@ declare module 'vue' {
|
||||||
IconLucideAlertTriangle: typeof import('~icons/lucide/alert-triangle')['default']
|
IconLucideAlertTriangle: typeof import('~icons/lucide/alert-triangle')['default']
|
||||||
IconLucideArrowLeft: typeof import('~icons/lucide/arrow-left')['default']
|
IconLucideArrowLeft: typeof import('~icons/lucide/arrow-left')['default']
|
||||||
IconLucideArrowUpRight: typeof import('~icons/lucide/arrow-up-right')['default']
|
IconLucideArrowUpRight: typeof import('~icons/lucide/arrow-up-right')['default']
|
||||||
IconLucideBrush: (typeof import("~icons/lucide/brush"))["default"]
|
|
||||||
IconLucideCheckCircle: typeof import('~icons/lucide/check-circle')['default']
|
IconLucideCheckCircle: typeof import('~icons/lucide/check-circle')['default']
|
||||||
IconLucideChevronRight: typeof import('~icons/lucide/chevron-right')['default']
|
IconLucideChevronRight: typeof import('~icons/lucide/chevron-right')['default']
|
||||||
IconLucideGlobe: typeof import('~icons/lucide/globe')['default']
|
IconLucideGlobe: typeof import('~icons/lucide/globe')['default']
|
||||||
|
|
@ -158,7 +157,6 @@ declare module 'vue' {
|
||||||
IconLucideLayers: typeof import('~icons/lucide/layers')['default']
|
IconLucideLayers: typeof import('~icons/lucide/layers')['default']
|
||||||
IconLucideListEnd: typeof import('~icons/lucide/list-end')['default']
|
IconLucideListEnd: typeof import('~icons/lucide/list-end')['default']
|
||||||
IconLucideMinus: typeof import('~icons/lucide/minus')['default']
|
IconLucideMinus: typeof import('~icons/lucide/minus')['default']
|
||||||
IconLucideRss: (typeof import("~icons/lucide/rss"))["default"]
|
|
||||||
IconLucideSearch: typeof import('~icons/lucide/search')['default']
|
IconLucideSearch: typeof import('~icons/lucide/search')['default']
|
||||||
IconLucideUsers: typeof import('~icons/lucide/users')['default']
|
IconLucideUsers: typeof import('~icons/lucide/users')['default']
|
||||||
IconLucideX: typeof import('~icons/lucide/x')['default']
|
IconLucideX: typeof import('~icons/lucide/x')['default']
|
||||||
|
|
@ -214,4 +212,5 @@ declare module 'vue' {
|
||||||
WorkspaceCurrent: typeof import('./components/workspace/Current.vue')['default']
|
WorkspaceCurrent: typeof import('./components/workspace/Current.vue')['default']
|
||||||
WorkspaceSelector: typeof import('./components/workspace/Selector.vue')['default']
|
WorkspaceSelector: typeof import('./components/workspace/Selector.vue')['default']
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col space-y-2">
|
<div class="flex flex-col space-y-2">
|
||||||
<div class="flex flex-col px-4 pt-2">
|
<div v-if="isTooltipComponent" class="flex flex-col px-4 pt-2">
|
||||||
<h2 class="inline-flex pb-1 font-semibold text-secondaryDark">
|
<h2 class="inline-flex pb-1 font-semibold text-secondaryDark">
|
||||||
{{ t("settings.interceptor") }}
|
{{ t("settings.interceptor") }}
|
||||||
</h2>
|
</h2>
|
||||||
|
|
@ -19,6 +19,9 @@
|
||||||
:value="interceptor.interceptorID"
|
:value="interceptor.interceptorID"
|
||||||
:label="unref(interceptor.name(t))"
|
:label="unref(interceptor.name(t))"
|
||||||
:selected="interceptorSelection === interceptor.interceptorID"
|
:selected="interceptorSelection === interceptor.interceptorID"
|
||||||
|
:class="{
|
||||||
|
'!px-0 hover:bg-transparent': !isTooltipComponent,
|
||||||
|
}"
|
||||||
@change="interceptorSelection = interceptor.interceptorID"
|
@change="interceptorSelection = interceptor.interceptorID"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
@ -39,6 +42,15 @@ import { InterceptorService } from "~/services/interceptor.service"
|
||||||
|
|
||||||
const t = useI18n()
|
const t = useI18n()
|
||||||
|
|
||||||
|
withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
isTooltipComponent?: boolean
|
||||||
|
}>(),
|
||||||
|
{
|
||||||
|
isTooltipComponent: true,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
const interceptorService = useService(InterceptorService)
|
const interceptorService = useService(InterceptorService)
|
||||||
|
|
||||||
const interceptorSelection =
|
const interceptorSelection =
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,11 @@
|
||||||
@close="hideModal"
|
@close="hideModal"
|
||||||
>
|
>
|
||||||
<template #body>
|
<template #body>
|
||||||
<template v-if="isLoadingAllowedAuthProviders">
|
<template v-if="platform.auth.customLoginSelectorUI">
|
||||||
|
<component :is="platform.auth.customLoginSelectorUI" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-else-if="isLoadingAllowedAuthProviders">
|
||||||
<div class="flex justify-center">
|
<div class="flex justify-center">
|
||||||
<HoppSmartSpinner />
|
<HoppSmartSpinner />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -302,7 +302,7 @@ const supportedGrantTypes = [
|
||||||
|
|
||||||
auth.value.grantTypeInfo = {
|
auth.value.grantTypeInfo = {
|
||||||
...auth.value.grantTypeInfo,
|
...auth.value.grantTypeInfo,
|
||||||
clientSecret: value,
|
clientSecret: value ?? "",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,7 @@ import { readFileAsText } from "~/helpers/functional/files"
|
||||||
import xmlFormat from "xml-formatter"
|
import xmlFormat from "xml-formatter"
|
||||||
import { useNestedSetting } from "~/composables/settings"
|
import { useNestedSetting } from "~/composables/settings"
|
||||||
import { toggleNestedSetting } from "~/newstore/settings"
|
import { toggleNestedSetting } from "~/newstore/settings"
|
||||||
|
import * as LJSON from "lossless-json"
|
||||||
|
|
||||||
type PossibleContentTypes = Exclude<
|
type PossibleContentTypes = Exclude<
|
||||||
ValidContentTypes,
|
ValidContentTypes,
|
||||||
|
|
@ -187,8 +188,8 @@ const prettifyRequestBody = () => {
|
||||||
let prettifyBody = ""
|
let prettifyBody = ""
|
||||||
try {
|
try {
|
||||||
if (body.value.contentType.endsWith("json")) {
|
if (body.value.contentType.endsWith("json")) {
|
||||||
const jsonObj = JSON.parse(rawParamsBody.value as string)
|
const jsonObj = LJSON.parse(rawParamsBody.value as string)
|
||||||
prettifyBody = JSON.stringify(jsonObj, null, 2)
|
prettifyBody = LJSON.stringify(jsonObj, undefined, 2) as string
|
||||||
} else if (body.value.contentType === "application/xml") {
|
} else if (body.value.contentType === "application/xml") {
|
||||||
prettifyBody = prettifyXML(rawParamsBody.value as string)
|
prettifyBody = prettifyXML(rawParamsBody.value as string)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,16 +36,6 @@
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="space-y-4 py-4">
|
|
||||||
<div class="flex items-center">
|
|
||||||
<HoppSmartToggle
|
|
||||||
:on="extensionEnabled"
|
|
||||||
@change="extensionEnabled = !extensionEnabled"
|
|
||||||
>
|
|
||||||
{{ t("settings.extensions_use_toggle") }}
|
|
||||||
</HoppSmartToggle>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
|
@ -55,34 +45,12 @@ import IconCheckCircle from "~icons/lucide/check-circle"
|
||||||
import { useI18n } from "@composables/i18n"
|
import { useI18n } from "@composables/i18n"
|
||||||
import { ExtensionInterceptorService } from "~/platform/std/interceptors/extension"
|
import { ExtensionInterceptorService } from "~/platform/std/interceptors/extension"
|
||||||
import { useService } from "dioc/vue"
|
import { useService } from "dioc/vue"
|
||||||
import { computed } from "vue"
|
|
||||||
import { InterceptorService } from "~/services/interceptor.service"
|
|
||||||
import { platform } from "~/platform"
|
|
||||||
|
|
||||||
const t = useI18n()
|
const t = useI18n()
|
||||||
|
|
||||||
const interceptorService = useService(InterceptorService)
|
|
||||||
const extensionService = useService(ExtensionInterceptorService)
|
const extensionService = useService(ExtensionInterceptorService)
|
||||||
|
|
||||||
const extensionVersion = extensionService.extensionVersion
|
const extensionVersion = extensionService.extensionVersion
|
||||||
const hasChromeExtInstalled = extensionService.chromeExtensionInstalled
|
const hasChromeExtInstalled = extensionService.chromeExtensionInstalled
|
||||||
const hasFirefoxExtInstalled = extensionService.firefoxExtensionInstalled
|
const hasFirefoxExtInstalled = extensionService.firefoxExtensionInstalled
|
||||||
|
|
||||||
const extensionEnabled = computed({
|
|
||||||
get() {
|
|
||||||
return (
|
|
||||||
interceptorService.currentInterceptorID.value ===
|
|
||||||
extensionService.interceptorID
|
|
||||||
)
|
|
||||||
},
|
|
||||||
set(active) {
|
|
||||||
if (active) {
|
|
||||||
interceptorService.currentInterceptorID.value =
|
|
||||||
extensionService.interceptorID
|
|
||||||
} else {
|
|
||||||
interceptorService.currentInterceptorID.value =
|
|
||||||
platform.interceptors.default
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -8,16 +8,6 @@
|
||||||
:label="t('app.proxy_privacy_policy')"
|
:label="t('app.proxy_privacy_policy')"
|
||||||
/>.
|
/>.
|
||||||
</div>
|
</div>
|
||||||
<div class="space-y-4 py-4">
|
|
||||||
<div class="flex items-center">
|
|
||||||
<HoppSmartToggle
|
|
||||||
:on="proxyEnabled"
|
|
||||||
@change="proxyEnabled = !proxyEnabled"
|
|
||||||
>
|
|
||||||
{{ t("settings.proxy_use_toggle") }}
|
|
||||||
</HoppSmartToggle>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center space-x-2 py-4">
|
<div class="flex items-center space-x-2 py-4">
|
||||||
<HoppSmartInput
|
<HoppSmartInput
|
||||||
v-model="PROXY_URL"
|
v-model="PROXY_URL"
|
||||||
|
|
@ -50,7 +40,6 @@ import { computed } from "vue"
|
||||||
import { useService } from "dioc/vue"
|
import { useService } from "dioc/vue"
|
||||||
import { InterceptorService } from "~/services/interceptor.service"
|
import { InterceptorService } from "~/services/interceptor.service"
|
||||||
import { proxyInterceptor } from "~/platform/std/interceptors/proxy"
|
import { proxyInterceptor } from "~/platform/std/interceptors/proxy"
|
||||||
import { platform } from "~/platform"
|
|
||||||
|
|
||||||
const t = useI18n()
|
const t = useI18n()
|
||||||
const toast = useToast()
|
const toast = useToast()
|
||||||
|
|
@ -59,23 +48,11 @@ const interceptorService = useService(InterceptorService)
|
||||||
|
|
||||||
const PROXY_URL = useSetting("PROXY_URL")
|
const PROXY_URL = useSetting("PROXY_URL")
|
||||||
|
|
||||||
const proxyEnabled = computed({
|
const proxyEnabled = computed(
|
||||||
get() {
|
() =>
|
||||||
return (
|
|
||||||
interceptorService.currentInterceptorID.value ===
|
interceptorService.currentInterceptorID.value ===
|
||||||
proxyInterceptor.interceptorID
|
proxyInterceptor.interceptorID
|
||||||
)
|
)
|
||||||
},
|
|
||||||
set(active) {
|
|
||||||
if (active) {
|
|
||||||
interceptorService.currentInterceptorID.value =
|
|
||||||
proxyInterceptor.interceptorID
|
|
||||||
} else {
|
|
||||||
interceptorService.currentInterceptorID.value =
|
|
||||||
platform.interceptors.default
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const clearIcon = refAutoReset<typeof IconRotateCCW | typeof IconCheck>(
|
const clearIcon = refAutoReset<typeof IconRotateCCW | typeof IconCheck>(
|
||||||
IconRotateCCW,
|
IconRotateCCW,
|
||||||
|
|
|
||||||
|
|
@ -15,10 +15,6 @@ export type NetworkStrategy = (
|
||||||
req: AxiosRequestConfig
|
req: AxiosRequestConfig
|
||||||
) => TE.TaskEither<any, NetworkResponse>
|
) => TE.TaskEither<any, NetworkResponse>
|
||||||
|
|
||||||
export const cancelRunningRequest = () => {
|
|
||||||
// TODO: Implement
|
|
||||||
}
|
|
||||||
|
|
||||||
function processResponse(
|
function processResponse(
|
||||||
res: NetworkResponse,
|
res: NetworkResponse,
|
||||||
req: EffectiveHoppRESTRequest,
|
req: EffectiveHoppRESTRequest,
|
||||||
|
|
@ -34,7 +30,10 @@ function processResponse(
|
||||||
statusCode: res.status,
|
statusCode: res.status,
|
||||||
statusText: res.statusText,
|
statusText: res.statusText,
|
||||||
body: res.data,
|
body: res.data,
|
||||||
headers: Object.keys(res.headers).map((x) => ({
|
// If multi headers are present, then we can just use that, else fallback to Axios type
|
||||||
|
headers:
|
||||||
|
res.additional?.multiHeaders ??
|
||||||
|
Object.keys(res.headers).map((x) => ({
|
||||||
key: x,
|
key: x,
|
||||||
value: res.headers[x],
|
value: res.headers[x],
|
||||||
})),
|
})),
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
import { cloneDeep, defaultsDeep, has } from "lodash-es"
|
import { cloneDeep, defaultsDeep, has } from "lodash-es"
|
||||||
import { Observable } from "rxjs"
|
import { Observable } from "rxjs"
|
||||||
import { distinctUntilChanged, pluck } from "rxjs/operators"
|
import { distinctUntilChanged, pluck } from "rxjs/operators"
|
||||||
import { nextTick } from "vue"
|
|
||||||
import { platform } from "~/platform"
|
|
||||||
import type { KeysMatching } from "~/types/ts-utils"
|
import type { KeysMatching } from "~/types/ts-utils"
|
||||||
import DispatchingStore, { defineDispatchers } from "./DispatchingStore"
|
import DispatchingStore, { defineDispatchers } from "./DispatchingStore"
|
||||||
|
|
||||||
|
|
@ -70,8 +68,7 @@ export type SettingsDef = {
|
||||||
HAS_OPENED_SPOTLIGHT: boolean
|
HAS_OPENED_SPOTLIGHT: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getDefaultSettings = (): SettingsDef => {
|
export const getDefaultSettings = (): SettingsDef => ({
|
||||||
const defaultSettings: SettingsDef = {
|
|
||||||
syncCollections: true,
|
syncCollections: true,
|
||||||
syncHistory: true,
|
syncHistory: true,
|
||||||
syncEnvironments: true,
|
syncEnvironments: true,
|
||||||
|
|
@ -95,6 +92,7 @@ export const getDefaultSettings = (): SettingsDef => {
|
||||||
cookie: true,
|
cookie: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Set empty because interceptor module will set the default value
|
||||||
CURRENT_INTERCEPTOR_ID: "",
|
CURRENT_INTERCEPTOR_ID: "",
|
||||||
|
|
||||||
// TODO: Interceptor related settings should move under the interceptor systems
|
// TODO: Interceptor related settings should move under the interceptor systems
|
||||||
|
|
@ -115,19 +113,8 @@ export const getDefaultSettings = (): SettingsDef => {
|
||||||
COLUMN_LAYOUT: true,
|
COLUMN_LAYOUT: true,
|
||||||
|
|
||||||
HAS_OPENED_SPOTLIGHT: false,
|
HAS_OPENED_SPOTLIGHT: false,
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for platform to initialize before setting CURRENT_INTERCEPTOR_ID
|
|
||||||
nextTick(() => {
|
|
||||||
applySetting(
|
|
||||||
"CURRENT_INTERCEPTOR_ID",
|
|
||||||
platform?.interceptors.default || "browser"
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return defaultSettings
|
|
||||||
}
|
|
||||||
|
|
||||||
type ApplySettingPayload = {
|
type ApplySettingPayload = {
|
||||||
[K in keyof SettingsDef]: {
|
[K in keyof SettingsDef]: {
|
||||||
settingKey: K
|
settingKey: K
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,12 @@
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="space-y-8 p-8 md:col-span-2">
|
<div class="space-y-8 p-8 md:col-span-2">
|
||||||
|
<section class="flex flex-col space-y-2">
|
||||||
|
<h4 class="font-semibold text-secondaryDark">
|
||||||
|
{{ t("settings.interceptor") }}
|
||||||
|
</h4>
|
||||||
|
<AppInterceptor :is-tooltip-component="false" />
|
||||||
|
</section>
|
||||||
<section v-for="[id, settings] in interceptorsWithSettings" :key="id">
|
<section v-for="[id, settings] in interceptorsWithSettings" :key="id">
|
||||||
<h4 class="font-semibold text-secondaryDark">
|
<h4 class="font-semibold text-secondaryDark">
|
||||||
{{ settings.entryTitle(t) }}
|
{{ settings.entryTitle(t) }}
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,13 @@ export type LoginItemDef = {
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AuthPlatformDef = {
|
export type AuthPlatformDef = {
|
||||||
|
/**
|
||||||
|
* Whether this platform shows a custom login selector UI. Used for situations
|
||||||
|
* where we don't want to render the traditional UI and want to replace it
|
||||||
|
* with something else
|
||||||
|
*/
|
||||||
|
customLoginSelectorUI?: Component
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an observable that emits the current user as per the auth implementation.
|
* Returns an observable that emits the current user as per the auth implementation.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,22 @@ export type NetworkResponse = AxiosResponse<unknown> & {
|
||||||
endTime: number
|
endTime: number
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Optional additional fields with special optional metadata that can be used
|
||||||
|
*/
|
||||||
|
additional?: {
|
||||||
|
/**
|
||||||
|
* By the HTTP spec, we can have multiple headers with the same name, but
|
||||||
|
* this is not accessible in the AxiosResponse type as the headers there are Record<string, string>
|
||||||
|
* (and hence cannot have secondary values).
|
||||||
|
*
|
||||||
|
* If this value is present, headers can be read from here which will have the data.
|
||||||
|
*/
|
||||||
|
multiHeaders?: Array<{
|
||||||
|
key: string
|
||||||
|
value: string
|
||||||
|
}>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,6 @@ const AuthCodeOauthFlowParamsSchema = AuthCodeGrantTypeParams.pick({
|
||||||
params.authEndpoint.length >= 1 &&
|
params.authEndpoint.length >= 1 &&
|
||||||
params.tokenEndpoint.length >= 1 &&
|
params.tokenEndpoint.length >= 1 &&
|
||||||
params.clientID.length >= 1 &&
|
params.clientID.length >= 1 &&
|
||||||
params.clientSecret.length >= 1 &&
|
|
||||||
(!params.scopes || params.scopes.trim().length >= 1)
|
(!params.scopes || params.scopes.trim().length >= 1)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
@ -85,7 +84,7 @@ const initAuthCodeOauthFlow = async ({
|
||||||
grant_type: "AUTHORIZATION_CODE"
|
grant_type: "AUTHORIZATION_CODE"
|
||||||
authEndpoint: string
|
authEndpoint: string
|
||||||
tokenEndpoint: string
|
tokenEndpoint: string
|
||||||
clientSecret: string
|
clientSecret?: string
|
||||||
clientID: string
|
clientID: string
|
||||||
isPKCE: boolean
|
isPKCE: boolean
|
||||||
codeVerifier?: string
|
codeVerifier?: string
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ export const REST_COLLECTIONS_MOCK: HoppCollection[] = [
|
||||||
folders: [],
|
folders: [],
|
||||||
requests: [
|
requests: [
|
||||||
{
|
{
|
||||||
v: "4",
|
v: "5",
|
||||||
endpoint: "https://echo.hoppscotch.io",
|
endpoint: "https://echo.hoppscotch.io",
|
||||||
name: "Echo test",
|
name: "Echo test",
|
||||||
params: [],
|
params: [],
|
||||||
|
|
@ -50,7 +50,7 @@ export const GQL_COLLECTIONS_MOCK: HoppCollection[] = [
|
||||||
folders: [],
|
folders: [],
|
||||||
requests: [
|
requests: [
|
||||||
{
|
{
|
||||||
v: 4,
|
v: 5,
|
||||||
name: "Echo test",
|
name: "Echo test",
|
||||||
url: "https://echo.hoppscotch.io/graphql",
|
url: "https://echo.hoppscotch.io/graphql",
|
||||||
headers: [],
|
headers: [],
|
||||||
|
|
@ -138,7 +138,7 @@ export const REST_HISTORY_MOCK: RESTHistoryEntry[] = [
|
||||||
preRequestScript: "",
|
preRequestScript: "",
|
||||||
testScript: "",
|
testScript: "",
|
||||||
requestVariables: [],
|
requestVariables: [],
|
||||||
v: "4",
|
v: "5",
|
||||||
},
|
},
|
||||||
responseMeta: { duration: 807, statusCode: 200 },
|
responseMeta: { duration: 807, statusCode: 200 },
|
||||||
star: false,
|
star: false,
|
||||||
|
|
@ -150,7 +150,7 @@ export const GQL_HISTORY_MOCK: GQLHistoryEntry[] = [
|
||||||
{
|
{
|
||||||
v: 1,
|
v: 1,
|
||||||
request: {
|
request: {
|
||||||
v: 4,
|
v: 5,
|
||||||
name: "Untitled",
|
name: "Untitled",
|
||||||
url: "https://echo.hoppscotch.io/graphql",
|
url: "https://echo.hoppscotch.io/graphql",
|
||||||
query: "query Request { url }",
|
query: "query Request { url }",
|
||||||
|
|
@ -171,7 +171,7 @@ export const GQL_TAB_STATE_MOCK: PersistableTabState<HoppGQLDocument> = {
|
||||||
tabID: "5edbe8d4-65c9-4381-9354-5f1bf05d8ccc",
|
tabID: "5edbe8d4-65c9-4381-9354-5f1bf05d8ccc",
|
||||||
doc: {
|
doc: {
|
||||||
request: {
|
request: {
|
||||||
v: 4,
|
v: 5,
|
||||||
name: "Untitled",
|
name: "Untitled",
|
||||||
url: "https://echo.hoppscotch.io/graphql",
|
url: "https://echo.hoppscotch.io/graphql",
|
||||||
headers: [],
|
headers: [],
|
||||||
|
|
@ -194,7 +194,7 @@ export const REST_TAB_STATE_MOCK: PersistableTabState<HoppRESTDocument> = {
|
||||||
tabID: "e6e8d800-caa8-44a2-a6a6-b4765a3167aa",
|
tabID: "e6e8d800-caa8-44a2-a6a6-b4765a3167aa",
|
||||||
doc: {
|
doc: {
|
||||||
request: {
|
request: {
|
||||||
v: "4",
|
v: "5",
|
||||||
endpoint: "https://echo.hoppscotch.io",
|
endpoint: "https://echo.hoppscotch.io",
|
||||||
name: "Echo test",
|
name: "Echo test",
|
||||||
params: [],
|
params: [],
|
||||||
|
|
|
||||||
|
|
@ -400,7 +400,7 @@ const HoppTestResultSchema = z
|
||||||
(x) => "secret" in x && !x.secret
|
(x) => "secret" in x && !x.secret
|
||||||
).and(
|
).and(
|
||||||
z.object({
|
z.object({
|
||||||
previousValue: z.string(),
|
previousValue: z.optional(z.string()),
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
|
@ -415,7 +415,7 @@ const HoppTestResultSchema = z
|
||||||
(x) => "secret" in x && !x.secret
|
(x) => "secret" in x && !x.secret
|
||||||
).and(
|
).and(
|
||||||
z.object({
|
z.object({
|
||||||
previousValue: z.string(),
|
previousValue: z.optional(z.string()),
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import V1_VERSION from "./v/1"
|
||||||
import V2_VERSION from "./v/2"
|
import V2_VERSION from "./v/2"
|
||||||
import V3_VERSION from "./v/3"
|
import V3_VERSION from "./v/3"
|
||||||
import V4_VERSION from "./v/4"
|
import V4_VERSION from "./v/4"
|
||||||
|
import V5_VERSION from "./v/5"
|
||||||
|
|
||||||
export { GQLHeader } from "./v/1"
|
export { GQLHeader } from "./v/1"
|
||||||
export {
|
export {
|
||||||
|
|
@ -13,23 +14,24 @@ export {
|
||||||
HoppGQLAuthInherit,
|
HoppGQLAuthInherit,
|
||||||
} from "./v/2"
|
} from "./v/2"
|
||||||
|
|
||||||
export { HoppGQLAuth } from "./v/4"
|
export { HoppGQLAuthOAuth2, HoppGQLAuth } from "./v/5"
|
||||||
export { HoppGQLAuthOAuth2 } from "./v/3"
|
|
||||||
export { HoppGQLAuthAPIKey } from "./v/4"
|
export { HoppGQLAuthAPIKey } from "./v/4"
|
||||||
|
|
||||||
export const GQL_REQ_SCHEMA_VERSION = 4
|
export const GQL_REQ_SCHEMA_VERSION = 5
|
||||||
|
|
||||||
const versionedObject = z.object({
|
const versionedObject = z.object({
|
||||||
v: z.number(),
|
v: z.number(),
|
||||||
})
|
})
|
||||||
|
|
||||||
export const HoppGQLRequest = createVersionedEntity({
|
export const HoppGQLRequest = createVersionedEntity({
|
||||||
latestVersion: 4,
|
latestVersion: 5,
|
||||||
versionMap: {
|
versionMap: {
|
||||||
1: V1_VERSION,
|
1: V1_VERSION,
|
||||||
2: V2_VERSION,
|
2: V2_VERSION,
|
||||||
3: V3_VERSION,
|
3: V3_VERSION,
|
||||||
4: V4_VERSION,
|
4: V4_VERSION,
|
||||||
|
5: V5_VERSION,
|
||||||
},
|
},
|
||||||
getVersion(x) {
|
getVersion(x) {
|
||||||
const result = versionedObject.safeParse(x)
|
const result = versionedObject.safeParse(x)
|
||||||
|
|
|
||||||
47
packages/hoppscotch-data/src/graphql/v/5.ts
Normal file
47
packages/hoppscotch-data/src/graphql/v/5.ts
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
import { z } from "zod"
|
||||||
|
|
||||||
|
import { defineVersion } from "verzod"
|
||||||
|
|
||||||
|
import { HoppRESTAuthOAuth2 } from "../../rest/v/5"
|
||||||
|
import {
|
||||||
|
HoppGQLAuthBasic,
|
||||||
|
HoppGQLAuthBearer,
|
||||||
|
HoppGQLAuthInherit,
|
||||||
|
HoppGQLAuthNone,
|
||||||
|
} from "./2"
|
||||||
|
import { HoppGQLAuthAPIKey, V4_SCHEMA } from "./4"
|
||||||
|
|
||||||
|
export { HoppRESTAuthOAuth2 as HoppGQLAuthOAuth2 } from "../../rest/v/5"
|
||||||
|
|
||||||
|
export const HoppGQLAuth = z
|
||||||
|
.discriminatedUnion("authType", [
|
||||||
|
HoppGQLAuthNone,
|
||||||
|
HoppGQLAuthInherit,
|
||||||
|
HoppGQLAuthBasic,
|
||||||
|
HoppGQLAuthBearer,
|
||||||
|
HoppGQLAuthAPIKey,
|
||||||
|
HoppRESTAuthOAuth2, // both rest and gql have the same auth type for oauth2
|
||||||
|
])
|
||||||
|
.and(
|
||||||
|
z.object({
|
||||||
|
authActive: z.boolean(),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
export type HoppGQLAuth = z.infer<typeof HoppGQLAuth>
|
||||||
|
|
||||||
|
export const V5_SCHEMA = V4_SCHEMA.extend({
|
||||||
|
v: z.literal(5),
|
||||||
|
auth: HoppGQLAuth,
|
||||||
|
})
|
||||||
|
|
||||||
|
export default defineVersion({
|
||||||
|
initial: false,
|
||||||
|
schema: V5_SCHEMA,
|
||||||
|
up(old: z.infer<typeof V4_SCHEMA>) {
|
||||||
|
return {
|
||||||
|
...old,
|
||||||
|
v: 5 as const,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
@ -6,12 +6,13 @@ import V1_VERSION from "./v/1"
|
||||||
import V2_VERSION from "./v/2"
|
import V2_VERSION from "./v/2"
|
||||||
import V3_VERSION from "./v/3"
|
import V3_VERSION from "./v/3"
|
||||||
import V4_VERSION from "./v/4"
|
import V4_VERSION from "./v/4"
|
||||||
|
import V5_VERSION from "./v/5"
|
||||||
import { createVersionedEntity, InferredEntity } from "verzod"
|
import { createVersionedEntity, InferredEntity } from "verzod"
|
||||||
import { lodashIsEqualEq, mapThenEq, undefinedEq } from "../utils/eq"
|
import { lodashIsEqualEq, mapThenEq, undefinedEq } from "../utils/eq"
|
||||||
|
|
||||||
import { HoppRESTReqBody, HoppRESTHeaders, HoppRESTParams } from "./v/1"
|
import { HoppRESTReqBody, HoppRESTHeaders, HoppRESTParams } from "./v/1"
|
||||||
|
|
||||||
import { HoppRESTAuth } from "./v/4"
|
import { HoppRESTAuth } from "./v/5"
|
||||||
import { HoppRESTRequestVariables } from "./v/2"
|
import { HoppRESTRequestVariables } from "./v/2"
|
||||||
import { z } from "zod"
|
import { z } from "zod"
|
||||||
|
|
||||||
|
|
@ -29,14 +30,18 @@ export {
|
||||||
} from "./v/1"
|
} from "./v/1"
|
||||||
|
|
||||||
export {
|
export {
|
||||||
HoppRESTAuthOAuth2,
|
|
||||||
AuthCodeGrantTypeParams,
|
|
||||||
ClientCredentialsGrantTypeParams,
|
ClientCredentialsGrantTypeParams,
|
||||||
ImplicitOauthFlowParams,
|
ImplicitOauthFlowParams,
|
||||||
PasswordGrantTypeParams,
|
PasswordGrantTypeParams,
|
||||||
} from "./v/3"
|
} from "./v/3"
|
||||||
|
|
||||||
export { HoppRESTAuth, HoppRESTAuthAPIKey } from "./v/4"
|
export {
|
||||||
|
AuthCodeGrantTypeParams,
|
||||||
|
HoppRESTAuthOAuth2,
|
||||||
|
HoppRESTAuth,
|
||||||
|
} from "./v/5"
|
||||||
|
|
||||||
|
export { HoppRESTAuthAPIKey } from "./v/4"
|
||||||
|
|
||||||
export { HoppRESTRequestVariables } from "./v/2"
|
export { HoppRESTRequestVariables } from "./v/2"
|
||||||
|
|
||||||
|
|
@ -46,13 +51,14 @@ const versionedObject = z.object({
|
||||||
})
|
})
|
||||||
|
|
||||||
export const HoppRESTRequest = createVersionedEntity({
|
export const HoppRESTRequest = createVersionedEntity({
|
||||||
latestVersion: 4,
|
latestVersion: 5,
|
||||||
versionMap: {
|
versionMap: {
|
||||||
0: V0_VERSION,
|
0: V0_VERSION,
|
||||||
1: V1_VERSION,
|
1: V1_VERSION,
|
||||||
2: V2_VERSION,
|
2: V2_VERSION,
|
||||||
3: V3_VERSION,
|
3: V3_VERSION,
|
||||||
4: V4_VERSION,
|
4: V4_VERSION,
|
||||||
|
5: V5_VERSION,
|
||||||
},
|
},
|
||||||
getVersion(data) {
|
getVersion(data) {
|
||||||
// For V1 onwards we have the v string storing the number
|
// For V1 onwards we have the v string storing the number
|
||||||
|
|
@ -94,7 +100,7 @@ const HoppRESTRequestEq = Eq.struct<HoppRESTRequest>({
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
|
||||||
export const RESTReqSchemaVersion = "4"
|
export const RESTReqSchemaVersion = "5"
|
||||||
|
|
||||||
export type HoppRESTParam = HoppRESTRequest["params"][number]
|
export type HoppRESTParam = HoppRESTRequest["params"][number]
|
||||||
export type HoppRESTHeader = HoppRESTRequest["headers"][number]
|
export type HoppRESTHeader = HoppRESTRequest["headers"][number]
|
||||||
|
|
@ -189,7 +195,7 @@ export function makeRESTRequest(
|
||||||
|
|
||||||
export function getDefaultRESTRequest(): HoppRESTRequest {
|
export function getDefaultRESTRequest(): HoppRESTRequest {
|
||||||
return {
|
return {
|
||||||
v: "4",
|
v: "5",
|
||||||
endpoint: "https://echo.hoppscotch.io",
|
endpoint: "https://echo.hoppscotch.io",
|
||||||
name: "Untitled",
|
name: "Untitled",
|
||||||
params: [],
|
params: [],
|
||||||
|
|
|
||||||
66
packages/hoppscotch-data/src/rest/v/5.ts
Normal file
66
packages/hoppscotch-data/src/rest/v/5.ts
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
import { z } from "zod"
|
||||||
|
import { defineVersion } from "verzod"
|
||||||
|
import {
|
||||||
|
HoppRESTAuthBasic,
|
||||||
|
HoppRESTAuthBearer,
|
||||||
|
HoppRESTAuthInherit,
|
||||||
|
HoppRESTAuthNone,
|
||||||
|
} from "./1"
|
||||||
|
import { HoppRESTAuthAPIKey, V4_SCHEMA } from "./4"
|
||||||
|
import {
|
||||||
|
AuthCodeGrantTypeParams as AuthCodeGrantTypeParamsOld,
|
||||||
|
ClientCredentialsGrantTypeParams,
|
||||||
|
HoppRESTAuthOAuth2 as HoppRESTAuthOAuth2Old,
|
||||||
|
ImplicitOauthFlowParams,
|
||||||
|
PasswordGrantTypeParams,
|
||||||
|
} from "./3"
|
||||||
|
|
||||||
|
export const AuthCodeGrantTypeParams = AuthCodeGrantTypeParamsOld.extend({
|
||||||
|
clientSecret: z.string().optional(),
|
||||||
|
})
|
||||||
|
|
||||||
|
export const HoppRESTAuthOAuth2 = HoppRESTAuthOAuth2Old.extend({
|
||||||
|
grantTypeInfo: z.discriminatedUnion("grantType", [
|
||||||
|
AuthCodeGrantTypeParams,
|
||||||
|
ClientCredentialsGrantTypeParams,
|
||||||
|
PasswordGrantTypeParams,
|
||||||
|
ImplicitOauthFlowParams,
|
||||||
|
]),
|
||||||
|
})
|
||||||
|
|
||||||
|
export type HoppRESTAuthOAuth2 = z.infer<typeof HoppRESTAuthOAuth2>
|
||||||
|
|
||||||
|
export const HoppRESTAuth = z
|
||||||
|
.discriminatedUnion("authType", [
|
||||||
|
HoppRESTAuthNone,
|
||||||
|
HoppRESTAuthInherit,
|
||||||
|
HoppRESTAuthBasic,
|
||||||
|
HoppRESTAuthBearer,
|
||||||
|
HoppRESTAuthOAuth2,
|
||||||
|
HoppRESTAuthAPIKey,
|
||||||
|
])
|
||||||
|
.and(
|
||||||
|
z.object({
|
||||||
|
authActive: z.boolean(),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
export type HoppRESTAuth = z.infer<typeof HoppRESTAuth>
|
||||||
|
|
||||||
|
export const V5_SCHEMA = V4_SCHEMA.extend({
|
||||||
|
v: z.literal("5"),
|
||||||
|
auth: HoppRESTAuth,
|
||||||
|
})
|
||||||
|
|
||||||
|
export default defineVersion({
|
||||||
|
schema: V5_SCHEMA,
|
||||||
|
initial: false,
|
||||||
|
up(old: z.infer<typeof V4_SCHEMA>) {
|
||||||
|
// v5 is not a breaking change in terms of migrations
|
||||||
|
// we're just making clientSecret in authcode + pkce flow optional
|
||||||
|
return {
|
||||||
|
...old,
|
||||||
|
v: "5" as const,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "@hoppscotch/selfhost-desktop",
|
"name": "@hoppscotch/selfhost-desktop",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "2024.3.3",
|
"version": "2024.3.4",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev:vite": "vite",
|
"dev:vite": "vite",
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
"@fontsource-variable/material-symbols-rounded": "5.0.16",
|
"@fontsource-variable/material-symbols-rounded": "5.0.16",
|
||||||
"@fontsource-variable/roboto-mono": "5.0.16",
|
"@fontsource-variable/roboto-mono": "5.0.16",
|
||||||
"@hoppscotch/common": "workspace:^",
|
"@hoppscotch/common": "workspace:^",
|
||||||
|
"@hoppscotch/data": "workspace:^",
|
||||||
"@platform/auth": "0.1.106",
|
"@platform/auth": "0.1.106",
|
||||||
"@tauri-apps/api": "1.5.1",
|
"@tauri-apps/api": "1.5.1",
|
||||||
"@tauri-apps/cli": "1.5.6",
|
"@tauri-apps/cli": "1.5.6",
|
||||||
|
|
|
||||||
|
|
@ -1260,7 +1260,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hoppscotch-desktop"
|
name = "hoppscotch-desktop"
|
||||||
version = "24.3.3"
|
version = "24.3.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cocoa 0.25.0",
|
"cocoa 0.25.0",
|
||||||
"hex_color",
|
"hex_color",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "hoppscotch-desktop"
|
name = "hoppscotch-desktop"
|
||||||
version = "24.3.3"
|
version = "24.3.4"
|
||||||
description = "A Tauri App"
|
description = "A Tauri App"
|
||||||
authors = ["you"]
|
authors = ["you"]
|
||||||
license = ""
|
license = ""
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
},
|
},
|
||||||
"package": {
|
"package": {
|
||||||
"productName": "Hoppscotch",
|
"productName": "Hoppscotch",
|
||||||
"version": "24.3.3"
|
"version": "24.3.4"
|
||||||
},
|
},
|
||||||
"tauri": {
|
"tauri": {
|
||||||
"allowlist": {
|
"allowlist": {
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ import { def as collectionsDef } from "./platform/collections/collections.platfo
|
||||||
import { def as settingsDef } from "./platform/settings/settings.platform"
|
import { def as settingsDef } from "./platform/settings/settings.platform"
|
||||||
import { def as historyDef } from "./platform/history/history.platform"
|
import { def as historyDef } from "./platform/history/history.platform"
|
||||||
import { proxyInterceptor } from "@hoppscotch/common/platform/std/interceptors/proxy"
|
import { proxyInterceptor } from "@hoppscotch/common/platform/std/interceptors/proxy"
|
||||||
import { ExtensionInspectorService } from "@hoppscotch/common/platform/std/inspections/extension.inspector"
|
|
||||||
import { NativeInterceptorService } from "./platform/interceptors/native"
|
import { NativeInterceptorService } from "./platform/interceptors/native"
|
||||||
import { nextTick, ref, watch } from "vue"
|
import { nextTick, ref, watch } from "vue"
|
||||||
import { emit, listen } from "@tauri-apps/api/event"
|
import { emit, listen } from "@tauri-apps/api/event"
|
||||||
|
|
@ -53,9 +52,6 @@ const headerPaddingTop = ref("0px")
|
||||||
{ type: "standalone", interceptor: proxyInterceptor },
|
{ type: "standalone", interceptor: proxyInterceptor },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
additionalInspectors: [
|
|
||||||
{ type: "service", service: ExtensionInspectorService },
|
|
||||||
],
|
|
||||||
platformFeatureFlags: {
|
platformFeatureFlags: {
|
||||||
exportAsGIST: false,
|
exportAsGIST: false,
|
||||||
hasTelemetry: false,
|
hasTelemetry: false,
|
||||||
|
|
|
||||||
|
|
@ -97,6 +97,11 @@ async function runRequest(
|
||||||
endTime: timeEnd,
|
endTime: timeEnd,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
additional: {
|
||||||
|
multiHeaders: Object.entries(res.rawHeaders).flatMap(
|
||||||
|
([header, values]) => values.map((value) => ({ key: header, value }))
|
||||||
|
),
|
||||||
|
},
|
||||||
})
|
})
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const timeEnd = Date.now()
|
const timeEnd = Date.now()
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "@hoppscotch/selfhost-web",
|
"name": "@hoppscotch/selfhost-web",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "2024.3.3",
|
"version": "2024.3.4",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev:vite": "vite",
|
"dev:vite": "vite",
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@
|
||||||
"client_id": "CLIENT ID",
|
"client_id": "CLIENT ID",
|
||||||
"client_secret": "CLIENT SECRET",
|
"client_secret": "CLIENT SECRET",
|
||||||
"description": "Configure authentication providers for your server",
|
"description": "Configure authentication providers for your server",
|
||||||
|
"provider_not_specified": "Please enable at least one authentication provider",
|
||||||
"scope": "SCOPE",
|
"scope": "SCOPE",
|
||||||
"tenant": "TENANT",
|
"tenant": "TENANT",
|
||||||
"title": "Authentication Providers",
|
"title": "Authentication Providers",
|
||||||
|
|
@ -146,6 +147,7 @@
|
||||||
"email_failure": "Failed to send invitation",
|
"email_failure": "Failed to send invitation",
|
||||||
"email_signin_failure": "Failed to login with Email",
|
"email_signin_failure": "Failed to login with Email",
|
||||||
"email_success": "Email invitation sent successfully",
|
"email_success": "Email invitation sent successfully",
|
||||||
|
"emails_cannot_be_same": "You cannot invite yourself, please choose a different email address!!",
|
||||||
"enter_team_email": "Please enter email of workspace owner!!",
|
"enter_team_email": "Please enter email of workspace owner!!",
|
||||||
"error": "Something went wrong",
|
"error": "Something went wrong",
|
||||||
"error_auth_providers": "Unable to load auth providers",
|
"error_auth_providers": "Unable to load auth providers",
|
||||||
|
|
@ -171,6 +173,7 @@
|
||||||
"remove_admin_from_users_success": "Admin status removed from selected users!!",
|
"remove_admin_from_users_success": "Admin status removed from selected users!!",
|
||||||
"remove_admin_to_delete_user": "Remove admin privilege to delete the user!!",
|
"remove_admin_to_delete_user": "Remove admin privilege to delete the user!!",
|
||||||
"remove_owner_to_delete_user": "Remove team ownership status to delete the user!!",
|
"remove_owner_to_delete_user": "Remove team ownership status to delete the user!!",
|
||||||
|
"remove_owner_failure_only_one_owner": "Failed to remove member. There should be atleast one owner in a team!!",
|
||||||
"remove_admin_for_deletion": "Remove admin status before attempting deletion!!",
|
"remove_admin_for_deletion": "Remove admin status before attempting deletion!!",
|
||||||
"remove_owner_for_deletion": "One or more users are team owners. Update ownership before deletion!!",
|
"remove_owner_for_deletion": "One or more users are team owners. Update ownership before deletion!!",
|
||||||
"remove_invitee_failure": "Removal of invitee failed!!",
|
"remove_invitee_failure": "Removal of invitee failed!!",
|
||||||
|
|
@ -193,7 +196,6 @@
|
||||||
"sign_in_options": "All sign in option",
|
"sign_in_options": "All sign in option",
|
||||||
"sign_out": "Sign out",
|
"sign_out": "Sign out",
|
||||||
"team_name_too_short": "Workspace name should be atleast 6 characters long!!",
|
"team_name_too_short": "Workspace name should be atleast 6 characters long!!",
|
||||||
"team_name_long": "Workspace name should be atleast 6 characters long!!",
|
|
||||||
"user_already_invited": "Failed to send invite. User is already invited!!",
|
"user_already_invited": "Failed to send invite. User is already invited!!",
|
||||||
"user_not_found": "User not found in the infra!!",
|
"user_not_found": "User not found in the infra!!",
|
||||||
"users_to_admin_success": "Selected users are elevated to admin status!!",
|
"users_to_admin_success": "Selected users are elevated to admin status!!",
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "hoppscotch-sh-admin",
|
"name": "hoppscotch-sh-admin",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "2024.3.3",
|
"version": "2024.3.4",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "pnpm exec npm-run-all -p -l dev:*",
|
"dev": "pnpm exec npm-run-all -p -l dev:*",
|
||||||
|
|
|
||||||
89
packages/hoppscotch-sh-admin/src/components.d.ts
vendored
89
packages/hoppscotch-sh-admin/src/components.d.ts
vendored
|
|
@ -1,56 +1,51 @@
|
||||||
// generated by unplugin-vue-components
|
// generated by unplugin-vue-components
|
||||||
// We suggest you to commit this file into source control
|
// We suggest you to commit this file into source control
|
||||||
// Read more: https://github.com/vuejs/core/pull/3399
|
// Read more: https://github.com/vuejs/core/pull/3399
|
||||||
import '@vue/runtime-core'
|
import '@vue/runtime-core';
|
||||||
|
|
||||||
export {}
|
export {};
|
||||||
|
|
||||||
declare module '@vue/runtime-core' {
|
declare module '@vue/runtime-core' {
|
||||||
export interface GlobalComponents {
|
export interface GlobalComponents {
|
||||||
AppHeader: typeof import('./components/app/Header.vue')['default']
|
AppHeader: typeof import('./components/app/Header.vue')['default'];
|
||||||
AppLogin: typeof import('./components/app/Login.vue')['default']
|
AppLogin: typeof import('./components/app/Login.vue')['default'];
|
||||||
AppLogout: typeof import('./components/app/Logout.vue')['default']
|
AppLogout: typeof import('./components/app/Logout.vue')['default'];
|
||||||
AppModal: typeof import('./components/app/Modal.vue')['default']
|
AppModal: typeof import('./components/app/Modal.vue')['default'];
|
||||||
AppSidebar: typeof import('./components/app/Sidebar.vue')['default']
|
AppSidebar: typeof import('./components/app/Sidebar.vue')['default'];
|
||||||
AppToast: typeof import('./components/app/Toast.vue')['default']
|
AppToast: typeof import('./components/app/Toast.vue')['default'];
|
||||||
DashboardMetricsCard: typeof import('./components/dashboard/MetricsCard.vue')['default']
|
DashboardMetricsCard: typeof import('./components/dashboard/MetricsCard.vue')['default'];
|
||||||
HoppButtonPrimary: typeof import('@hoppscotch/ui')['HoppButtonPrimary']
|
HoppButtonPrimary: typeof import('@hoppscotch/ui')['HoppButtonPrimary'];
|
||||||
HoppButtonSecondary: typeof import('@hoppscotch/ui')['HoppButtonSecondary']
|
HoppButtonSecondary: typeof import('@hoppscotch/ui')['HoppButtonSecondary'];
|
||||||
HoppSmartAnchor: typeof import('@hoppscotch/ui')['HoppSmartAnchor']
|
HoppSmartAnchor: typeof import('@hoppscotch/ui')['HoppSmartAnchor'];
|
||||||
HoppSmartAutoComplete: typeof import('@hoppscotch/ui')['HoppSmartAutoComplete']
|
HoppSmartConfirmModal: typeof import('@hoppscotch/ui')['HoppSmartConfirmModal'];
|
||||||
HoppSmartConfirmModal: typeof import('@hoppscotch/ui')['HoppSmartConfirmModal']
|
HoppSmartInput: typeof import('@hoppscotch/ui')['HoppSmartInput'];
|
||||||
HoppSmartInput: typeof import('@hoppscotch/ui')['HoppSmartInput']
|
HoppSmartItem: typeof import('@hoppscotch/ui')['HoppSmartItem'];
|
||||||
HoppSmartItem: typeof import('@hoppscotch/ui')['HoppSmartItem']
|
HoppSmartLink: typeof import('@hoppscotch/ui')['HoppSmartLink'];
|
||||||
HoppSmartLink: typeof import('@hoppscotch/ui')['HoppSmartLink']
|
HoppSmartModal: typeof import('@hoppscotch/ui')['HoppSmartModal'];
|
||||||
HoppSmartModal: typeof import('@hoppscotch/ui')['HoppSmartModal']
|
HoppSmartPicture: typeof import('@hoppscotch/ui')['HoppSmartPicture'];
|
||||||
HoppSmartPicture: typeof import('@hoppscotch/ui')['HoppSmartPicture']
|
HoppSmartPlaceholder: typeof import('@hoppscotch/ui')['HoppSmartPlaceholder'];
|
||||||
HoppSmartSpinner: typeof import('@hoppscotch/ui')['HoppSmartSpinner']
|
HoppSmartSelectWrapper: typeof import('@hoppscotch/ui')['HoppSmartSelectWrapper'];
|
||||||
HoppSmartTab: typeof import('@hoppscotch/ui')['HoppSmartTab']
|
HoppSmartSpinner: typeof import('@hoppscotch/ui')['HoppSmartSpinner'];
|
||||||
HoppSmartTable: typeof import('@hoppscotch/ui')['HoppSmartTable']
|
HoppSmartTab: typeof import('@hoppscotch/ui')['HoppSmartTab'];
|
||||||
HoppSmartTabs: typeof import('@hoppscotch/ui')['HoppSmartTabs']
|
HoppSmartTabs: typeof import('@hoppscotch/ui')['HoppSmartTabs'];
|
||||||
HoppSmartToggle: typeof import('@hoppscotch/ui')['HoppSmartToggle']
|
HoppSmartToggle: typeof import('@hoppscotch/ui')['HoppSmartToggle'];
|
||||||
IconLucideArrowLeft: typeof import('~icons/lucide/arrow-left')['default']
|
IconLucideInbox: typeof import('~icons/lucide/inbox')['default'];
|
||||||
IconLucideChevronDown: typeof import('~icons/lucide/chevron-down')['default']
|
SettingsAuthProvider: typeof import('./components/settings/AuthProvider.vue')['default'];
|
||||||
IconLucideInbox: typeof import('~icons/lucide/inbox')['default']
|
SettingsConfigurations: typeof import('./components/settings/Configurations.vue')['default'];
|
||||||
IconLucideSearch: typeof import('~icons/lucide/search')['default']
|
SettingsDataSharing: typeof import('./components/settings/DataSharing.vue')['default'];
|
||||||
IconLucideUser: typeof import('~icons/lucide/user')['default']
|
SettingsReset: typeof import('./components/settings/Reset.vue')['default'];
|
||||||
SettingsAuthProvider: typeof import('./components/settings/AuthProvider.vue')['default']
|
SettingsServerRestart: typeof import('./components/settings/ServerRestart.vue')['default'];
|
||||||
SettingsConfigurations: typeof import('./components/settings/Configurations.vue')['default']
|
SettingsSmtpConfiguration: typeof import('./components/settings/SmtpConfiguration.vue')['default'];
|
||||||
SettingsDataSharing: typeof import('./components/settings/DataSharing.vue')['default']
|
SetupDataSharingAndNewsletter: typeof import('./components/setup/DataSharingAndNewsletter.vue')['default'];
|
||||||
SettingsReset: typeof import('./components/settings/Reset.vue')['default']
|
TeamsAdd: typeof import('./components/teams/Add.vue')['default'];
|
||||||
SettingsServerRestart: typeof import('./components/settings/ServerRestart.vue')['default']
|
TeamsDetails: typeof import('./components/teams/Details.vue')['default'];
|
||||||
SettingsSmtpConfiguration: typeof import('./components/settings/SmtpConfiguration.vue')['default']
|
TeamsInvite: typeof import('./components/teams/Invite.vue')['default'];
|
||||||
SetupDataSharingAndNewsletter: typeof import('./components/setup/DataSharingAndNewsletter.vue')['default']
|
TeamsMembers: typeof import('./components/teams/Members.vue')['default'];
|
||||||
TeamsAdd: typeof import('./components/teams/Add.vue')['default']
|
TeamsPendingInvites: typeof import('./components/teams/PendingInvites.vue')['default'];
|
||||||
TeamsDetails: typeof import('./components/teams/Details.vue')['default']
|
Tippy: typeof import('vue-tippy')['Tippy'];
|
||||||
TeamsInvite: typeof import('./components/teams/Invite.vue')['default']
|
UiAutoResetIcon: typeof import('./components/ui/AutoResetIcon.vue')['default'];
|
||||||
TeamsMembers: typeof import('./components/teams/Members.vue')['default']
|
UsersDetails: typeof import('./components/users/Details.vue')['default'];
|
||||||
TeamsPendingInvites: typeof import('./components/teams/PendingInvites.vue')['default']
|
UsersInviteModal: typeof import('./components/users/InviteModal.vue')['default'];
|
||||||
Tippy: typeof import('vue-tippy')['Tippy']
|
UsersSharedRequests: typeof import('./components/users/SharedRequests.vue')['default'];
|
||||||
UiAutoResetIcon: typeof import('./components/ui/AutoResetIcon.vue')['default']
|
|
||||||
UsersDetails: typeof import('./components/users/Details.vue')['default']
|
|
||||||
UsersInviteModal: typeof import('./components/users/InviteModal.vue')['default']
|
|
||||||
UsersSharedRequests: typeof import('./components/users/SharedRequests.vue')['default']
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,11 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<SettingsServerRestart v-if="resetInfraConfigs" :reset="resetInfraConfigs" />
|
<SettingsServerRestart
|
||||||
|
v-if="resetInfraConfigs"
|
||||||
|
:reset="resetInfraConfigs"
|
||||||
|
@mutation-failure="resetInfraConfigs = false"
|
||||||
|
/>
|
||||||
|
|
||||||
<HoppSmartConfirmModal
|
<HoppSmartConfirmModal
|
||||||
:show="resetModal"
|
:show="resetModal"
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,10 @@ const props = withDefaults(
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'mutationFailure'): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
// Mutations to update or reset server configurations and audit logs
|
// Mutations to update or reset server configurations and audit logs
|
||||||
const resetInfraConfigsMutation = useMutation(ResetInfraConfigsDocument);
|
const resetInfraConfigsMutation = useMutation(ResetInfraConfigsDocument);
|
||||||
const updateInfraConfigsMutation = useMutation(UpdateInfraConfigsDocument);
|
const updateInfraConfigsMutation = useMutation(UpdateInfraConfigsDocument);
|
||||||
|
|
@ -73,28 +77,40 @@ const startCountdown = () => {
|
||||||
}, 1000);
|
}, 1000);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const triggerComponentUnMount = () => emit('mutationFailure');
|
||||||
|
|
||||||
// Call relevant mutations on component mount and initiate server restart
|
// Call relevant mutations on component mount and initiate server restart
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
let success = true;
|
|
||||||
|
|
||||||
if (props.reset) {
|
if (props.reset) {
|
||||||
success = await resetInfraConfigs(resetInfraConfigsMutation);
|
const resetInfraConfigsResult = await resetInfraConfigs(
|
||||||
if (!success) return;
|
resetInfraConfigsMutation
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!resetInfraConfigsResult) {
|
||||||
|
return triggerComponentUnMount();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
const infraResult = await updateInfraConfigs(updateInfraConfigsMutation);
|
const infraResult = await updateInfraConfigs(updateInfraConfigsMutation);
|
||||||
|
|
||||||
if (!infraResult) return;
|
if (!infraResult) {
|
||||||
|
return triggerComponentUnMount();
|
||||||
|
}
|
||||||
|
|
||||||
const authResult = await updateAuthProvider(
|
const authResult = await updateAuthProvider(
|
||||||
updateAllowedAuthProviderMutation
|
updateAllowedAuthProviderMutation
|
||||||
);
|
);
|
||||||
if (!authResult) return;
|
|
||||||
|
if (!authResult) {
|
||||||
|
return triggerComponentUnMount();
|
||||||
|
}
|
||||||
|
|
||||||
const dataSharingResult = await updateDataSharingConfigs(
|
const dataSharingResult = await updateDataSharingConfigs(
|
||||||
toggleDataSharingMutation
|
toggleDataSharingMutation
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!dataSharingResult) return;
|
if (!dataSharingResult) {
|
||||||
|
return triggerComponentUnMount();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
restart.value = true;
|
restart.value = true;
|
||||||
|
|
|
||||||
|
|
@ -168,6 +168,7 @@ import { useRoute } from 'vue-router';
|
||||||
import { useI18n } from '~/composables/i18n';
|
import { useI18n } from '~/composables/i18n';
|
||||||
import { useToast } from '~/composables/toast';
|
import { useToast } from '~/composables/toast';
|
||||||
import { useClientHandler } from '~/composables/useClientHandler';
|
import { useClientHandler } from '~/composables/useClientHandler';
|
||||||
|
import { getCompiledErrorMessage } from '~/helpers/errors';
|
||||||
import IconChevronDown from '~icons/lucide/chevron-down';
|
import IconChevronDown from '~icons/lucide/chevron-down';
|
||||||
import IconCircle from '~icons/lucide/circle';
|
import IconCircle from '~icons/lucide/circle';
|
||||||
import IconCircleDot from '~icons/lucide/circle-dot';
|
import IconCircleDot from '~icons/lucide/circle-dot';
|
||||||
|
|
@ -353,7 +354,13 @@ const removeExistingTeamMember = async (userID: string, index: number) => {
|
||||||
team.value.id
|
team.value.id
|
||||||
)();
|
)();
|
||||||
if (removeTeamMemberResult.error) {
|
if (removeTeamMemberResult.error) {
|
||||||
toast.error(t('state.remove_member_failure'));
|
const compiledErrorMessage = getCompiledErrorMessage(
|
||||||
|
removeTeamMemberResult.error.message
|
||||||
|
);
|
||||||
|
|
||||||
|
compiledErrorMessage
|
||||||
|
? toast.error(compiledErrorMessage)
|
||||||
|
: toast.error(t('state.remove_member_failure'));
|
||||||
} else {
|
} else {
|
||||||
team.value.teamMembers = team.value.teamMembers?.filter(
|
team.value.teamMembers = team.value.teamMembers?.filter(
|
||||||
(member: any) => member.user.uid !== userID
|
(member: any) => member.user.uid !== userID
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<HoppSmartModal
|
<HoppSmartModal
|
||||||
v-if="show"
|
|
||||||
dialog
|
dialog
|
||||||
:title="t('users.invite_user')"
|
:title="t('users.invite_user')"
|
||||||
@close="emit('hide-modal')"
|
@close="emit('hide-modal')"
|
||||||
|
|
@ -38,15 +37,6 @@ import { useToast } from '~/composables/toast';
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
|
|
||||||
withDefaults(
|
|
||||||
defineProps<{
|
|
||||||
show: boolean;
|
|
||||||
}>(),
|
|
||||||
{
|
|
||||||
show: false,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(event: 'hide-modal'): void;
|
(event: 'hide-modal'): void;
|
||||||
(event: 'send-invite', email: string): void;
|
(event: 'send-invite', email: string): void;
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import {
|
||||||
ServerConfigs,
|
ServerConfigs,
|
||||||
UpdatedConfigs,
|
UpdatedConfigs,
|
||||||
} from '~/helpers/configs';
|
} from '~/helpers/configs';
|
||||||
|
import { getCompiledErrorMessage } from '~/helpers/errors';
|
||||||
import { useToast } from './toast';
|
import { useToast } from './toast';
|
||||||
import { useClientHandler } from './useClientHandler';
|
import { useClientHandler } from './useClientHandler';
|
||||||
|
|
||||||
|
|
@ -201,7 +202,12 @@ export function useConfigHandler(updatedConfigs?: ServerConfigs) {
|
||||||
const result = await mutation.executeMutation(variables);
|
const result = await mutation.executeMutation(variables);
|
||||||
|
|
||||||
if (result.error) {
|
if (result.error) {
|
||||||
toast.error(t(errorMessage));
|
const { message } = result.error;
|
||||||
|
const compiledErrorMessage = getCompiledErrorMessage(message);
|
||||||
|
|
||||||
|
compiledErrorMessage
|
||||||
|
? toast.error(t(compiledErrorMessage))
|
||||||
|
: toast.error(t(errorMessage));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,14 @@ export const UNAUTHORIZED = 'Unauthorized' as const;
|
||||||
// Sometimes the backend returns Unauthorized error message as follows:
|
// Sometimes the backend returns Unauthorized error message as follows:
|
||||||
export const GRAPHQL_UNAUTHORIZED = '[GraphQL] Unauthorized' as const;
|
export const GRAPHQL_UNAUTHORIZED = '[GraphQL] Unauthorized' as const;
|
||||||
|
|
||||||
|
// When the email is invalid
|
||||||
|
export const INVALID_EMAIL = '[GraphQL] invalid/email' as const;
|
||||||
|
|
||||||
|
// When trying to remove the only admin account
|
||||||
export const ONLY_ONE_ADMIN_ACCOUNT_FOUND =
|
export const ONLY_ONE_ADMIN_ACCOUNT_FOUND =
|
||||||
'[GraphQL] admin/only_one_admin_account_found' as const;
|
'[GraphQL] admin/only_one_admin_account_found' as const;
|
||||||
|
|
||||||
|
// When trying to delete an admin account
|
||||||
export const ADMIN_CANNOT_BE_DELETED =
|
export const ADMIN_CANNOT_BE_DELETED =
|
||||||
'admin/admin_can_not_be_deleted' as const;
|
'admin/admin_can_not_be_deleted' as const;
|
||||||
|
|
||||||
|
|
@ -19,4 +24,53 @@ export const USER_ALREADY_INVITED =
|
||||||
'[GraphQL] admin/user_already_invited' as const;
|
'[GraphQL] admin/user_already_invited' as const;
|
||||||
|
|
||||||
// When attempting to delete a user who is an owner of a team
|
// When attempting to delete a user who is an owner of a team
|
||||||
export const USER_IS_OWNER = 'user/is_owner' as const;
|
export const USER_IS_OWNER = 'user/is_owner';
|
||||||
|
|
||||||
|
// When attempting to delete a user who is the only owner of a team
|
||||||
|
export const TEAM_ONLY_ONE_OWNER = '[GraphQL] team/only_one_owner';
|
||||||
|
|
||||||
|
// Even one auth provider is not specified
|
||||||
|
export const AUTH_PROVIDER_NOT_SPECIFIED =
|
||||||
|
'[GraphQL] auth/provider_not_specified' as const;
|
||||||
|
|
||||||
|
export const BOTH_EMAILS_CANNOT_BE_SAME =
|
||||||
|
'[GraphQL] email/both_emails_cannot_be_same' as const;
|
||||||
|
|
||||||
|
type ErrorMessages = {
|
||||||
|
message: string;
|
||||||
|
alternateMessage?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const ERROR_MESSAGES: Record<string, ErrorMessages> = {
|
||||||
|
[INVALID_EMAIL]: {
|
||||||
|
message: 'state.invalid_email',
|
||||||
|
},
|
||||||
|
[ONLY_ONE_ADMIN_ACCOUNT_FOUND]: {
|
||||||
|
message: 'state.remove_admin_failure_only_one_admin',
|
||||||
|
},
|
||||||
|
[ADMIN_CANNOT_BE_DELETED]: {
|
||||||
|
message: 'state.remove_admin_to_delete_user',
|
||||||
|
alternateMessage: 'state.remove_admin_for_deletion',
|
||||||
|
},
|
||||||
|
[USER_ALREADY_INVITED]: {
|
||||||
|
message: 'state.user_already_invited',
|
||||||
|
},
|
||||||
|
[USER_IS_OWNER]: {
|
||||||
|
message: 'state.remove_owner_to_delete_user',
|
||||||
|
alternateMessage: 'state.remove_owner_for_deletion',
|
||||||
|
},
|
||||||
|
[TEAM_ONLY_ONE_OWNER]: {
|
||||||
|
message: 'state.remove_owner_failure_only_one_owner',
|
||||||
|
},
|
||||||
|
[AUTH_PROVIDER_NOT_SPECIFIED]: {
|
||||||
|
message: 'configs.auth_providers.provider_not_specified',
|
||||||
|
},
|
||||||
|
[BOTH_EMAILS_CANNOT_BE_SAME]: {
|
||||||
|
message: 'state.emails_cannot_be_same',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getCompiledErrorMessage = (name: string, altMessage = false) => {
|
||||||
|
const error = ERROR_MESSAGES[name];
|
||||||
|
return altMessage ? error?.alternateMessage ?? '' : error?.message ?? '';
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,11 @@
|
||||||
import { useToast } from '~/composables/toast';
|
import { useToast } from '~/composables/toast';
|
||||||
import { getI18n } from '~/modules/i18n';
|
import { getI18n } from '~/modules/i18n';
|
||||||
import { UserDeletionResult } from './backend/graphql';
|
import { UserDeletionResult } from './backend/graphql';
|
||||||
import { ADMIN_CANNOT_BE_DELETED, USER_IS_OWNER } from './errors';
|
import {
|
||||||
|
ADMIN_CANNOT_BE_DELETED,
|
||||||
|
USER_IS_OWNER,
|
||||||
|
getCompiledErrorMessage,
|
||||||
|
} from './errors';
|
||||||
|
|
||||||
type ToastMessage = {
|
type ToastMessage = {
|
||||||
message: string;
|
message: string;
|
||||||
|
|
@ -49,14 +53,12 @@ export const handleUserDeletion = (deletedUsersList: UserDeletionResult[]) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const errMsgMap = {
|
const errMsgMap = {
|
||||||
[ADMIN_CANNOT_BE_DELETED]: isBulkAction
|
[ADMIN_CANNOT_BE_DELETED]: t(
|
||||||
? t('state.remove_admin_for_deletion')
|
getCompiledErrorMessage(ADMIN_CANNOT_BE_DELETED, isBulkAction)
|
||||||
: t('state.remove_admin_to_delete_user'),
|
),
|
||||||
|
[USER_IS_OWNER]: t(getCompiledErrorMessage(USER_IS_OWNER, isBulkAction)),
|
||||||
[USER_IS_OWNER]: isBulkAction
|
|
||||||
? t('state.remove_owner_for_deletion')
|
|
||||||
: t('state.remove_owner_to_delete_user'),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const errMsgMapKeys = Object.keys(errMsgMap);
|
const errMsgMapKeys = Object.keys(errMsgMap);
|
||||||
|
|
||||||
const toastMessages: ToastMessage[] = [];
|
const toastMessages: ToastMessage[] = [];
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@
|
||||||
<SettingsServerRestart
|
<SettingsServerRestart
|
||||||
v-if="initiateServerRestart"
|
v-if="initiateServerRestart"
|
||||||
:workingConfigs="workingConfigs"
|
:workingConfigs="workingConfigs"
|
||||||
|
@mutation-failure="initiateServerRestart = false"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<HoppSmartConfirmModal
|
<HoppSmartConfirmModal
|
||||||
|
|
|
||||||
|
|
@ -174,18 +174,21 @@
|
||||||
class="py-4 border-divider rounded-r-none bg-emerald-800 text-secondaryDark"
|
class="py-4 border-divider rounded-r-none bg-emerald-800 text-secondaryDark"
|
||||||
/>
|
/>
|
||||||
<HoppButtonSecondary
|
<HoppButtonSecondary
|
||||||
|
v-if="areNonAdminsSelected"
|
||||||
:icon="IconUserCheck"
|
:icon="IconUserCheck"
|
||||||
:label="t('users.make_admin')"
|
:label="t('users.make_admin')"
|
||||||
class="py-4 border-divider border-r-1 rounded-none hover:bg-emerald-600"
|
class="py-4 border-divider border-r-1 rounded-none hover:bg-emerald-600"
|
||||||
@click="confirmUsersToAdmin = true"
|
@click="confirmUsersToAdmin = true"
|
||||||
/>
|
/>
|
||||||
<HoppButtonSecondary
|
<HoppButtonSecondary
|
||||||
|
v-if="areAdminsSelected"
|
||||||
:icon="IconUserMinus"
|
:icon="IconUserMinus"
|
||||||
:label="t('users.remove_admin_status')"
|
:label="t('users.remove_admin_status')"
|
||||||
class="py-4 border-divider border-r-1 rounded-none hover:bg-orange-500"
|
class="py-4 border-divider border-r-1 rounded-none hover:bg-orange-500"
|
||||||
@click="confirmAdminsToUsers = true"
|
@click="confirmAdminsToUsers = true"
|
||||||
/>
|
/>
|
||||||
<HoppButtonSecondary
|
<HoppButtonSecondary
|
||||||
|
v-if="areNonAdminsSelected"
|
||||||
:icon="IconTrash"
|
:icon="IconTrash"
|
||||||
:label="t('users.delete_users')"
|
:label="t('users.delete_users')"
|
||||||
class="py-4 border-divider rounded-none hover:bg-red-500"
|
class="py-4 border-divider rounded-none hover:bg-red-500"
|
||||||
|
|
@ -203,7 +206,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<UsersInviteModal
|
<UsersInviteModal
|
||||||
:show="showInviteUserModal"
|
v-if="showInviteUserModal"
|
||||||
@hide-modal="showInviteUserModal = false"
|
@hide-modal="showInviteUserModal = false"
|
||||||
@send-invite="sendInvite"
|
@send-invite="sendInvite"
|
||||||
/>
|
/>
|
||||||
|
|
@ -258,10 +261,7 @@ import {
|
||||||
UsersListQuery,
|
UsersListQuery,
|
||||||
UsersListV2Document,
|
UsersListV2Document,
|
||||||
} from '~/helpers/backend/graphql';
|
} from '~/helpers/backend/graphql';
|
||||||
import {
|
import { getCompiledErrorMessage } from '~/helpers/errors';
|
||||||
ONLY_ONE_ADMIN_ACCOUNT_FOUND,
|
|
||||||
USER_ALREADY_INVITED,
|
|
||||||
} from '~/helpers/errors';
|
|
||||||
import { handleUserDeletion } from '~/helpers/userManagement';
|
import { handleUserDeletion } from '~/helpers/userManagement';
|
||||||
import IconCheck from '~icons/lucide/check';
|
import IconCheck from '~icons/lucide/check';
|
||||||
import IconLeft from '~icons/lucide/chevron-left';
|
import IconLeft from '~icons/lucide/chevron-left';
|
||||||
|
|
@ -291,6 +291,7 @@ const headings = [
|
||||||
|
|
||||||
// Get Paginated Results of all the users in the infra
|
// Get Paginated Results of all the users in the infra
|
||||||
const usersPerPage = 20;
|
const usersPerPage = 20;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
fetching,
|
fetching,
|
||||||
error,
|
error,
|
||||||
|
|
@ -306,6 +307,19 @@ const {
|
||||||
// Selected Rows
|
// Selected Rows
|
||||||
const selectedRows = ref<UsersListQuery['infra']['allUsers']>([]);
|
const selectedRows = ref<UsersListQuery['infra']['allUsers']>([]);
|
||||||
|
|
||||||
|
const areAdminsSelected = computed(() =>
|
||||||
|
selectedRows.value.some((user) => user.isAdmin)
|
||||||
|
);
|
||||||
|
|
||||||
|
const areNonAdminsSelected = computed(() => {
|
||||||
|
// No Admins selected implicitly conveys that all the selected users are non-Admins assuming `selectedRows.length` > 0 (markup render condition)
|
||||||
|
if (!areAdminsSelected.value) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return selectedRows.value.some((user) => !user.isAdmin);
|
||||||
|
});
|
||||||
|
|
||||||
// Ensure this variable is declared outside the debounce function
|
// Ensure this variable is declared outside the debounce function
|
||||||
let debounceTimeout: ReturnType<typeof setTimeout> | null = null;
|
let debounceTimeout: ReturnType<typeof setTimeout> | null = null;
|
||||||
|
|
||||||
|
|
@ -442,9 +456,12 @@ const sendInvite = async (email: string) => {
|
||||||
const variables = { inviteeEmail: email.trim() };
|
const variables = { inviteeEmail: email.trim() };
|
||||||
const result = await sendInvitation.executeMutation(variables);
|
const result = await sendInvitation.executeMutation(variables);
|
||||||
if (result.error) {
|
if (result.error) {
|
||||||
if (result.error.message === USER_ALREADY_INVITED)
|
const { message } = result.error;
|
||||||
toast.error(t('state.user_already_invited'));
|
const compiledErrorMessage = getCompiledErrorMessage(message);
|
||||||
else toast.error(t('state.email_failure'));
|
|
||||||
|
compiledErrorMessage
|
||||||
|
? toast.error(t(compiledErrorMessage))
|
||||||
|
: toast.error(t('state.email_failure'));
|
||||||
} else {
|
} else {
|
||||||
toast.success(t('state.email_success'));
|
toast.success(t('state.email_success'));
|
||||||
showInviteUserModal.value = false;
|
showInviteUserModal.value = false;
|
||||||
|
|
@ -522,8 +539,10 @@ const makeAdminsToUsers = async (id: string | null) => {
|
||||||
const variables = { userUIDs };
|
const variables = { userUIDs };
|
||||||
const result = await adminsToUser.executeMutation(variables);
|
const result = await adminsToUser.executeMutation(variables);
|
||||||
if (result.error) {
|
if (result.error) {
|
||||||
if (result.error.message === ONLY_ONE_ADMIN_ACCOUNT_FOUND) {
|
const compiledErrorMessage = getCompiledErrorMessage(result.error.message);
|
||||||
return toast.error(t('state.remove_admin_failure_only_one_admin'));
|
|
||||||
|
if (compiledErrorMessage) {
|
||||||
|
return toast.error(t(getCompiledErrorMessage(result.error.message)));
|
||||||
}
|
}
|
||||||
|
|
||||||
toast.error(
|
toast.error(
|
||||||
|
|
|
||||||
|
|
@ -907,6 +907,9 @@ importers:
|
||||||
'@hoppscotch/common':
|
'@hoppscotch/common':
|
||||||
specifier: workspace:^
|
specifier: workspace:^
|
||||||
version: link:../hoppscotch-common
|
version: link:../hoppscotch-common
|
||||||
|
'@hoppscotch/data':
|
||||||
|
specifier: workspace:^
|
||||||
|
version: link:../hoppscotch-data
|
||||||
'@platform/auth':
|
'@platform/auth':
|
||||||
specifier: 0.1.106
|
specifier: 0.1.106
|
||||||
version: 0.1.106
|
version: 0.1.106
|
||||||
|
|
@ -3514,8 +3517,8 @@ packages:
|
||||||
resolution: {integrity: sha512-4ttr/FNO29w+kBbU7HZ/U0Lzuh2cRDhP8UlWOtV9ERcjHzuyXVZmjyleESK6eVP60tGC9QtQW9yZE+JeRhDHkg==}
|
resolution: {integrity: sha512-4ttr/FNO29w+kBbU7HZ/U0Lzuh2cRDhP8UlWOtV9ERcjHzuyXVZmjyleESK6eVP60tGC9QtQW9yZE+JeRhDHkg==}
|
||||||
engines: {node: '>= 14'}
|
engines: {node: '>= 14'}
|
||||||
|
|
||||||
'@intlify/message-compiler@10.0.0-alpha.3':
|
'@intlify/message-compiler@10.0.0-beta.1':
|
||||||
resolution: {integrity: sha512-WjM1KAl5enpOfprfVAJ3FzwACmizZFPgyV0sn+QXoWH8BG2ahVkf7uVEqQH0mvUr2rKKaScwpzhH3wZ5F7ZdPw==}
|
resolution: {integrity: sha512-rBmXBZzDgq3yPkL/3/r9uK0nrsJOYHSpaW0mtGBxxjt9pY9vaPL0UAKbVAjFPRnfEY41ixgpkpTjai6IKZ+hvg==}
|
||||||
engines: {node: '>= 16'}
|
engines: {node: '>= 16'}
|
||||||
|
|
||||||
'@intlify/message-compiler@9.2.2':
|
'@intlify/message-compiler@9.2.2':
|
||||||
|
|
@ -3530,8 +3533,8 @@ packages:
|
||||||
resolution: {integrity: sha512-McnYWhcoYmDJvssVu6QGR0shqlkJuL1HHdi5lK7fNqvQqRYaQ4lSLjYmZxwc8tRNMdIe9/KUKfyPxU9M6yCtNQ==}
|
resolution: {integrity: sha512-McnYWhcoYmDJvssVu6QGR0shqlkJuL1HHdi5lK7fNqvQqRYaQ4lSLjYmZxwc8tRNMdIe9/KUKfyPxU9M6yCtNQ==}
|
||||||
engines: {node: '>= 16'}
|
engines: {node: '>= 16'}
|
||||||
|
|
||||||
'@intlify/shared@10.0.0-alpha.3':
|
'@intlify/shared@10.0.0-beta.1':
|
||||||
resolution: {integrity: sha512-fi2q48i+C6sSCAt3vOj/9LD3tkr1wcvLt+ifZEHrpPiwHCyKLDYGp5qBNUHUBBA/iqFTeWdtHUbHE9z9OeTXkw==}
|
resolution: {integrity: sha512-61MnYhgqS/TyAto9CXOltHlhK2WflLBcKpIkRhZCUL2IkiVvh7qKevsqZ3RYZylyC3q19ajLW6mB+iJtnbAOpg==}
|
||||||
engines: {node: '>= 16'}
|
engines: {node: '>= 16'}
|
||||||
|
|
||||||
'@intlify/shared@9.2.2':
|
'@intlify/shared@9.2.2':
|
||||||
|
|
@ -15519,8 +15522,8 @@ snapshots:
|
||||||
|
|
||||||
'@intlify/bundle-utils@3.4.0(vue-i18n@9.8.0(vue@3.3.9(typescript@5.3.2)))':
|
'@intlify/bundle-utils@3.4.0(vue-i18n@9.8.0(vue@3.3.9(typescript@5.3.2)))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@intlify/message-compiler': 10.0.0-alpha.3
|
'@intlify/message-compiler': 10.0.0-beta.1
|
||||||
'@intlify/shared': 10.0.0-alpha.3
|
'@intlify/shared': 10.0.0-beta.1
|
||||||
jsonc-eslint-parser: 1.4.1
|
jsonc-eslint-parser: 1.4.1
|
||||||
source-map: 0.6.1
|
source-map: 0.6.1
|
||||||
yaml-eslint-parser: 0.3.2
|
yaml-eslint-parser: 0.3.2
|
||||||
|
|
@ -15573,9 +15576,9 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@intlify/shared': 9.2.2
|
'@intlify/shared': 9.2.2
|
||||||
|
|
||||||
'@intlify/message-compiler@10.0.0-alpha.3':
|
'@intlify/message-compiler@10.0.0-beta.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@intlify/shared': 10.0.0-alpha.3
|
'@intlify/shared': 10.0.0-beta.1
|
||||||
source-map-js: 1.0.2
|
source-map-js: 1.0.2
|
||||||
|
|
||||||
'@intlify/message-compiler@9.2.2':
|
'@intlify/message-compiler@9.2.2':
|
||||||
|
|
@ -15593,7 +15596,7 @@ snapshots:
|
||||||
'@intlify/shared': 9.8.0
|
'@intlify/shared': 9.8.0
|
||||||
source-map-js: 1.0.2
|
source-map-js: 1.0.2
|
||||||
|
|
||||||
'@intlify/shared@10.0.0-alpha.3': {}
|
'@intlify/shared@10.0.0-beta.1': {}
|
||||||
|
|
||||||
'@intlify/shared@9.2.2': {}
|
'@intlify/shared@9.2.2': {}
|
||||||
|
|
||||||
|
|
@ -15624,7 +15627,7 @@ snapshots:
|
||||||
'@intlify/vite-plugin-vue-i18n@6.0.1(vite@4.5.0(@types/node@18.18.8)(sass@1.69.5)(terser@5.27.0))(vue-i18n@9.8.0(vue@3.3.9(typescript@4.9.5)))':
|
'@intlify/vite-plugin-vue-i18n@6.0.1(vite@4.5.0(@types/node@18.18.8)(sass@1.69.5)(terser@5.27.0))(vue-i18n@9.8.0(vue@3.3.9(typescript@4.9.5)))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@intlify/bundle-utils': 7.0.0(vue-i18n@9.8.0(vue@3.3.9(typescript@4.9.5)))
|
'@intlify/bundle-utils': 7.0.0(vue-i18n@9.8.0(vue@3.3.9(typescript@4.9.5)))
|
||||||
'@intlify/shared': 10.0.0-alpha.3
|
'@intlify/shared': 10.0.0-beta.1
|
||||||
'@rollup/pluginutils': 4.2.1
|
'@rollup/pluginutils': 4.2.1
|
||||||
debug: 4.3.4(supports-color@9.2.2)
|
debug: 4.3.4(supports-color@9.2.2)
|
||||||
fast-glob: 3.3.2
|
fast-glob: 3.3.2
|
||||||
|
|
@ -15638,7 +15641,7 @@ snapshots:
|
||||||
'@intlify/vite-plugin-vue-i18n@7.0.0(vite@4.5.0(@types/node@18.18.8)(sass@1.69.5)(terser@5.27.0))(vue-i18n@9.8.0(vue@3.3.9(typescript@5.3.2)))':
|
'@intlify/vite-plugin-vue-i18n@7.0.0(vite@4.5.0(@types/node@18.18.8)(sass@1.69.5)(terser@5.27.0))(vue-i18n@9.8.0(vue@3.3.9(typescript@5.3.2)))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@intlify/bundle-utils': 3.4.0(vue-i18n@9.8.0(vue@3.3.9(typescript@5.3.2)))
|
'@intlify/bundle-utils': 3.4.0(vue-i18n@9.8.0(vue@3.3.9(typescript@5.3.2)))
|
||||||
'@intlify/shared': 10.0.0-alpha.3
|
'@intlify/shared': 10.0.0-beta.1
|
||||||
'@rollup/pluginutils': 4.2.1
|
'@rollup/pluginutils': 4.2.1
|
||||||
debug: 4.3.4(supports-color@9.2.2)
|
debug: 4.3.4(supports-color@9.2.2)
|
||||||
fast-glob: 3.3.2
|
fast-glob: 3.3.2
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue