Compare commits
10 Commits
2024.3.2
...
fix/safari
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a870725abf | ||
|
|
cd7429dd24 | ||
|
|
e6cc235532 | ||
|
|
6a65eb03e7 | ||
|
|
c66ea66689 | ||
|
|
8b0f337280 | ||
|
|
2e8a04fbd6 | ||
|
|
7e1ebd5b43 | ||
|
|
1eb5e02100 | ||
|
|
6198a25bc6 |
15
.github/workflows/tests.yml
vendored
15
.github/workflows/tests.yml
vendored
@@ -17,21 +17,22 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Setup environment
|
- name: Setup environment
|
||||||
run: mv .env.example .env
|
run: mv .env.example .env
|
||||||
|
|
||||||
- name: Setup node
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: ${{ matrix.node-version }}
|
|
||||||
|
|
||||||
- name: Setup pnpm
|
- name: Setup pnpm
|
||||||
uses: pnpm/action-setup@v3
|
uses: pnpm/action-setup@v2.2.4
|
||||||
with:
|
with:
|
||||||
version: 8
|
version: 8
|
||||||
run_install: true
|
run_install: true
|
||||||
|
|
||||||
|
- name: Setup node
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: ${{ matrix.node }}
|
||||||
|
cache: pnpm
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: pnpm test
|
run: pnpm test
|
||||||
|
|||||||
@@ -1,48 +0,0 @@
|
|||||||
# THIS IS NOT TO BE USED FOR PERSONAL DEPLOYMENTS!
|
|
||||||
# Internal Docker Compose Image used for internal testing deployments
|
|
||||||
|
|
||||||
version: "3.7"
|
|
||||||
|
|
||||||
services:
|
|
||||||
hoppscotch-db:
|
|
||||||
image: postgres:15
|
|
||||||
user: postgres
|
|
||||||
environment:
|
|
||||||
POSTGRES_USER: postgres
|
|
||||||
POSTGRES_PASSWORD: testpass
|
|
||||||
POSTGRES_DB: hoppscotch
|
|
||||||
healthcheck:
|
|
||||||
test:
|
|
||||||
[
|
|
||||||
"CMD-SHELL",
|
|
||||||
"sh -c 'pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}'"
|
|
||||||
]
|
|
||||||
interval: 5s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 10
|
|
||||||
|
|
||||||
hoppscotch-aio:
|
|
||||||
container_name: hoppscotch-aio
|
|
||||||
build:
|
|
||||||
dockerfile: prod.Dockerfile
|
|
||||||
context: .
|
|
||||||
target: aio
|
|
||||||
environment:
|
|
||||||
- DATABASE_URL=postgresql://postgres:testpass@hoppscotch-db:5432/hoppscotch
|
|
||||||
- ENABLE_SUBPATH_BASED_ACCESS=true
|
|
||||||
env_file:
|
|
||||||
- ./.env
|
|
||||||
depends_on:
|
|
||||||
hoppscotch-db:
|
|
||||||
condition: service_healthy
|
|
||||||
command: ["sh", "-c", "pnpm exec prisma migrate deploy && node /usr/src/app/aio_run.mjs"]
|
|
||||||
healthcheck:
|
|
||||||
test:
|
|
||||||
- CMD
|
|
||||||
- curl
|
|
||||||
- '-f'
|
|
||||||
- 'http://localhost:80'
|
|
||||||
interval: 2s
|
|
||||||
timeout: 10s
|
|
||||||
retries: 30
|
|
||||||
|
|
||||||
@@ -9,10 +9,6 @@ curlCheck() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
if [ "$ENABLE_SUBPATH_BASED_ACCESS" = "true" ]; then
|
curlCheck "http://localhost:3000"
|
||||||
curlCheck "http://localhost:80/backend/ping"
|
curlCheck "http://localhost:3100"
|
||||||
else
|
curlCheck "http://localhost:3170/ping"
|
||||||
curlCheck "http://localhost:3000"
|
|
||||||
curlCheck "http://localhost:3100"
|
|
||||||
curlCheck "http://localhost:3170/ping"
|
|
||||||
fi
|
|
||||||
|
|||||||
14
package.json
14
package.json
@@ -23,13 +23,13 @@
|
|||||||
"./packages/*"
|
"./packages/*"
|
||||||
],
|
],
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "16.3.0",
|
"@commitlint/cli": "^16.2.3",
|
||||||
"@commitlint/config-conventional": "16.2.4",
|
"@commitlint/config-conventional": "^16.2.1",
|
||||||
"@hoppscotch/ui": "0.1.0",
|
"@hoppscotch/ui": "^0.1.0",
|
||||||
"@types/node": "17.0.27",
|
"@types/node": "17.0.27",
|
||||||
"cross-env": "7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"http-server": "14.1.1",
|
"http-server": "^14.1.1",
|
||||||
"husky": "7.0.4",
|
"husky": "^7.0.4",
|
||||||
"lint-staged": "12.4.0"
|
"lint-staged": "12.4.0"
|
||||||
},
|
},
|
||||||
"pnpm": {
|
"pnpm": {
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
"vue": "3.3.9"
|
"vue": "3.3.9"
|
||||||
},
|
},
|
||||||
"packageExtensions": {
|
"packageExtensions": {
|
||||||
"httpsnippet@3.0.1": {
|
"httpsnippet@^3.0.1": {
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"ajv": "6.12.3"
|
"ajv": "6.12.3"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,16 +17,16 @@
|
|||||||
"types": "dist/index.d.ts",
|
"types": "dist/index.d.ts",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/language": "6.10.1",
|
"@codemirror/language": "6.9.3",
|
||||||
"@lezer/highlight": "1.2.0",
|
"@lezer/highlight": "1.2.0",
|
||||||
"@lezer/lr": "1.3.14"
|
"@lezer/lr": "^1.3.14"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@lezer/generator": "1.5.1",
|
"@lezer/generator": "^1.5.1",
|
||||||
"mocha": "9.2.2",
|
"mocha": "^9.2.2",
|
||||||
"rollup": "3.29.4",
|
"rollup": "^3.29.3",
|
||||||
"rollup-plugin-dts": "6.0.2",
|
"rollup-plugin-dts": "^6.0.2",
|
||||||
"rollup-plugin-ts": "3.4.5",
|
"rollup-plugin-ts": "^3.4.5",
|
||||||
"typescript": "5.2.2"
|
"typescript": "^5.2.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,9 @@
|
|||||||
"collection": "@nestjs/schematics",
|
"collection": "@nestjs/schematics",
|
||||||
"sourceRoot": "src",
|
"sourceRoot": "src",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"assets": [{ "include": "mailer/templates/**/*", "outDir": "dist" }],
|
"assets": [
|
||||||
|
"**/*.hbs"
|
||||||
|
],
|
||||||
"watchAssets": true
|
"watchAssets": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "hoppscotch-backend",
|
"name": "hoppscotch-backend",
|
||||||
"version": "2024.3.2",
|
"version": "2023.12.5",
|
||||||
"description": "",
|
"description": "",
|
||||||
"author": "",
|
"author": "",
|
||||||
"private": true,
|
"private": true,
|
||||||
@@ -24,83 +24,80 @@
|
|||||||
"do-test": "pnpm run test"
|
"do-test": "pnpm run test"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@apollo/server": "4.9.5",
|
"@apollo/server": "^4.9.4",
|
||||||
"@nestjs-modules/mailer": "1.9.1",
|
"@nestjs-modules/mailer": "^1.9.1",
|
||||||
"@nestjs/apollo": "12.0.9",
|
"@nestjs/apollo": "^12.0.9",
|
||||||
"@nestjs/common": "10.2.7",
|
"@nestjs/common": "^10.2.6",
|
||||||
"@nestjs/config": "3.1.1",
|
"@nestjs/config": "^3.1.1",
|
||||||
"@nestjs/core": "10.2.7",
|
"@nestjs/core": "^10.2.6",
|
||||||
"@nestjs/graphql": "12.0.9",
|
"@nestjs/graphql": "^12.0.9",
|
||||||
"@nestjs/jwt": "10.1.1",
|
"@nestjs/jwt": "^10.1.1",
|
||||||
"@nestjs/passport": "10.0.2",
|
"@nestjs/passport": "^10.0.2",
|
||||||
"@nestjs/platform-express": "10.2.7",
|
"@nestjs/platform-express": "^10.2.6",
|
||||||
"@nestjs/schedule": "4.0.1",
|
"@nestjs/throttler": "^5.0.0",
|
||||||
"@nestjs/throttler": "5.0.1",
|
"@prisma/client": "^5.8.0",
|
||||||
"@prisma/client": "5.8.1",
|
"argon2": "^0.30.3",
|
||||||
"argon2": "0.30.3",
|
"bcrypt": "^5.1.0",
|
||||||
"bcrypt": "5.1.0",
|
"cookie": "^0.5.0",
|
||||||
"cookie": "0.5.0",
|
"cookie-parser": "^1.4.6",
|
||||||
"cookie-parser": "1.4.6",
|
"express": "^4.17.1",
|
||||||
"cron": "3.1.6",
|
"express-session": "^1.17.3",
|
||||||
"express": "4.18.2",
|
"fp-ts": "^2.13.1",
|
||||||
"express-session": "1.17.3",
|
"graphql": "^16.8.1",
|
||||||
"fp-ts": "2.13.1",
|
"graphql-query-complexity": "^0.12.0",
|
||||||
"graphql": "16.8.1",
|
"graphql-redis-subscriptions": "^2.6.0",
|
||||||
"graphql-query-complexity": "0.12.0",
|
"graphql-subscriptions": "^2.0.0",
|
||||||
"graphql-redis-subscriptions": "2.6.0",
|
"handlebars": "^4.7.7",
|
||||||
"graphql-subscriptions": "2.0.0",
|
"io-ts": "^2.2.16",
|
||||||
"handlebars": "4.7.7",
|
"luxon": "^3.2.1",
|
||||||
"io-ts": "2.2.16",
|
"nodemailer": "^6.9.1",
|
||||||
"luxon": "3.2.1",
|
"passport": "^0.6.0",
|
||||||
"nodemailer": "6.9.1",
|
"passport-github2": "^0.1.12",
|
||||||
"passport": "0.6.0",
|
"passport-google-oauth20": "^2.0.0",
|
||||||
"passport-github2": "0.1.12",
|
"passport-jwt": "^4.0.1",
|
||||||
"passport-google-oauth20": "2.0.0",
|
"passport-local": "^1.0.0",
|
||||||
"passport-jwt": "4.0.1",
|
"passport-microsoft": "^1.0.0",
|
||||||
"passport-local": "1.0.0",
|
"prisma": "^5.8.0",
|
||||||
"passport-microsoft": "1.0.0",
|
"reflect-metadata": "^0.1.13",
|
||||||
"posthog-node": "3.6.3",
|
"rimraf": "^3.0.2",
|
||||||
"prisma": "5.8.1",
|
"rxjs": "^7.6.0"
|
||||||
"reflect-metadata": "0.1.13",
|
|
||||||
"rimraf": "3.0.2",
|
|
||||||
"rxjs": "7.6.0"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@nestjs/cli": "10.2.1",
|
"@nestjs/cli": "^10.1.18",
|
||||||
"@nestjs/schematics": "10.0.3",
|
"@nestjs/schematics": "^10.0.2",
|
||||||
"@nestjs/testing": "10.2.7",
|
"@nestjs/testing": "^10.2.6",
|
||||||
"@relmify/jest-fp-ts": "2.0.2",
|
"@relmify/jest-fp-ts": "^2.0.2",
|
||||||
"@types/argon2": "0.15.0",
|
"@types/argon2": "^0.15.0",
|
||||||
"@types/bcrypt": "5.0.0",
|
"@types/bcrypt": "^5.0.0",
|
||||||
"@types/cookie": "0.5.1",
|
"@types/cookie": "^0.5.1",
|
||||||
"@types/cookie-parser": "1.4.3",
|
"@types/cookie-parser": "^1.4.3",
|
||||||
"@types/express": "4.17.14",
|
"@types/express": "^4.17.14",
|
||||||
"@types/jest": "29.4.0",
|
"@types/jest": "^29.4.0",
|
||||||
"@types/luxon": "3.2.0",
|
"@types/luxon": "^3.2.0",
|
||||||
"@types/node": "18.11.10",
|
"@types/node": "^18.11.10",
|
||||||
"@types/nodemailer": "6.4.7",
|
"@types/nodemailer": "^6.4.7",
|
||||||
"@types/passport-github2": "1.2.5",
|
"@types/passport-github2": "^1.2.5",
|
||||||
"@types/passport-google-oauth20": "2.0.11",
|
"@types/passport-google-oauth20": "^2.0.11",
|
||||||
"@types/passport-jwt": "3.0.8",
|
"@types/passport-jwt": "^3.0.8",
|
||||||
"@types/passport-microsoft": "0.0.0",
|
"@types/passport-microsoft": "^0.0.0",
|
||||||
"@types/supertest": "2.0.12",
|
"@types/supertest": "^2.0.12",
|
||||||
"@typescript-eslint/eslint-plugin": "5.45.0",
|
"@typescript-eslint/eslint-plugin": "^5.45.0",
|
||||||
"@typescript-eslint/parser": "5.45.0",
|
"@typescript-eslint/parser": "^5.45.0",
|
||||||
"cross-env": "7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"eslint": "8.29.0",
|
"eslint": "^8.29.0",
|
||||||
"eslint-config-prettier": "8.5.0",
|
"eslint-config-prettier": "^8.5.0",
|
||||||
"eslint-plugin-prettier": "4.2.1",
|
"eslint-plugin-prettier": "^4.2.1",
|
||||||
"jest": "29.4.1",
|
"jest": "^29.4.1",
|
||||||
"jest-mock-extended": "3.0.1",
|
"jest-mock-extended": "^3.0.1",
|
||||||
"jwt": "link:@types/nestjs/jwt",
|
"jwt": "link:@types/nestjs/jwt",
|
||||||
"prettier": "2.8.4",
|
"prettier": "^2.8.4",
|
||||||
"source-map-support": "0.5.21",
|
"source-map-support": "^0.5.21",
|
||||||
"supertest": "6.3.2",
|
"supertest": "^6.3.2",
|
||||||
"ts-jest": "29.0.5",
|
"ts-jest": "29.0.5",
|
||||||
"ts-loader": "9.4.2",
|
"ts-loader": "^9.4.2",
|
||||||
"ts-node": "10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
"tsconfig-paths": "4.1.1",
|
"tsconfig-paths": "4.1.1",
|
||||||
"typescript": "4.9.3"
|
"typescript": "^4.9.3"
|
||||||
},
|
},
|
||||||
"jest": {
|
"jest": {
|
||||||
"moduleFileExtensions": [
|
"moduleFileExtensions": [
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
-- This is a custom migration file which is not generated by Prisma.
|
|
||||||
-- The aim of this migration is to add text search indices to the TeamCollection and TeamRequest tables.
|
|
||||||
|
|
||||||
-- Create Extension
|
|
||||||
CREATE EXTENSION IF NOT EXISTS pg_trgm;
|
|
||||||
|
|
||||||
-- Create GIN Trigram Index for Team Collection title
|
|
||||||
CREATE INDEX
|
|
||||||
"TeamCollection_title_trgm_idx"
|
|
||||||
ON
|
|
||||||
"TeamCollection"
|
|
||||||
USING
|
|
||||||
GIN (title gin_trgm_ops);
|
|
||||||
|
|
||||||
-- Create GIN Trigram Index for Team Collection title
|
|
||||||
CREATE INDEX
|
|
||||||
"TeamRequest_title_trgm_idx"
|
|
||||||
ON
|
|
||||||
"TeamRequest"
|
|
||||||
USING
|
|
||||||
GIN (title gin_trgm_ops);
|
|
||||||
|
|
||||||
@@ -41,31 +41,31 @@ model TeamInvitation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
model TeamCollection {
|
model TeamCollection {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
parentID String?
|
parentID String?
|
||||||
data Json?
|
data Json?
|
||||||
parent TeamCollection? @relation("TeamCollectionChildParent", fields: [parentID], references: [id])
|
parent TeamCollection? @relation("TeamCollectionChildParent", fields: [parentID], references: [id])
|
||||||
children TeamCollection[] @relation("TeamCollectionChildParent")
|
children TeamCollection[] @relation("TeamCollectionChildParent")
|
||||||
requests TeamRequest[]
|
requests TeamRequest[]
|
||||||
teamID String
|
teamID String
|
||||||
team Team @relation(fields: [teamID], references: [id], onDelete: Cascade)
|
team Team @relation(fields: [teamID], references: [id], onDelete: Cascade)
|
||||||
title String
|
title String
|
||||||
orderIndex Int
|
orderIndex Int
|
||||||
createdOn DateTime @default(now()) @db.Timestamp(3)
|
createdOn DateTime @default(now()) @db.Timestamp(3)
|
||||||
updatedOn DateTime @updatedAt @db.Timestamp(3)
|
updatedOn DateTime @updatedAt @db.Timestamp(3)
|
||||||
}
|
}
|
||||||
|
|
||||||
model TeamRequest {
|
model TeamRequest {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
collectionID String
|
collectionID String
|
||||||
collection TeamCollection @relation(fields: [collectionID], references: [id], onDelete: Cascade)
|
collection TeamCollection @relation(fields: [collectionID], references: [id], onDelete: Cascade)
|
||||||
teamID String
|
teamID String
|
||||||
team Team @relation(fields: [teamID], references: [id], onDelete: Cascade)
|
team Team @relation(fields: [teamID], references: [id], onDelete: Cascade)
|
||||||
title String
|
title String
|
||||||
request Json
|
request Json
|
||||||
orderIndex Int
|
orderIndex Int
|
||||||
createdOn DateTime @default(now()) @db.Timestamp(3)
|
createdOn DateTime @default(now()) @db.Timestamp(3)
|
||||||
updatedOn DateTime @updatedAt @db.Timestamp(3)
|
updatedOn DateTime @updatedAt @db.Timestamp(3)
|
||||||
}
|
}
|
||||||
|
|
||||||
model Shortcode {
|
model Shortcode {
|
||||||
|
|||||||
@@ -27,7 +27,9 @@ import {
|
|||||||
} from './input-types.args';
|
} from './input-types.args';
|
||||||
import { GqlThrottlerGuard } from 'src/guards/gql-throttler.guard';
|
import { GqlThrottlerGuard } from 'src/guards/gql-throttler.guard';
|
||||||
import { SkipThrottle } from '@nestjs/throttler';
|
import { SkipThrottle } from '@nestjs/throttler';
|
||||||
import { UserDeletionResult } from 'src/user/user.model';
|
import { User } from 'src/user/user.model';
|
||||||
|
import { PaginationArgs } from 'src/types/input-types.args';
|
||||||
|
import { TeamInvitation } from 'src/team-invitation/team-invitation.model';
|
||||||
|
|
||||||
@UseGuards(GqlThrottlerGuard)
|
@UseGuards(GqlThrottlerGuard)
|
||||||
@Resolver(() => Admin)
|
@Resolver(() => Admin)
|
||||||
@@ -47,6 +49,203 @@ export class AdminResolver {
|
|||||||
return admin;
|
return admin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ResolveField(() => [User], {
|
||||||
|
description: 'Returns a list of all admin users in infra',
|
||||||
|
deprecationReason: 'Use `infra` query instead',
|
||||||
|
})
|
||||||
|
@UseGuards(GqlAuthGuard, GqlAdminGuard)
|
||||||
|
async admins() {
|
||||||
|
const admins = await this.adminService.fetchAdmins();
|
||||||
|
return admins;
|
||||||
|
}
|
||||||
|
@ResolveField(() => User, {
|
||||||
|
description: 'Returns a user info by UID',
|
||||||
|
deprecationReason: 'Use `infra` query instead',
|
||||||
|
})
|
||||||
|
@UseGuards(GqlAuthGuard, GqlAdminGuard)
|
||||||
|
async userInfo(
|
||||||
|
@Args({
|
||||||
|
name: 'userUid',
|
||||||
|
type: () => ID,
|
||||||
|
description: 'The user UID',
|
||||||
|
})
|
||||||
|
userUid: string,
|
||||||
|
): Promise<AuthUser> {
|
||||||
|
const user = await this.adminService.fetchUserInfo(userUid);
|
||||||
|
if (E.isLeft(user)) throwErr(user.left);
|
||||||
|
return user.right;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ResolveField(() => [User], {
|
||||||
|
description: 'Returns a list of all the users in infra',
|
||||||
|
deprecationReason: 'Use `infra` query instead',
|
||||||
|
})
|
||||||
|
@UseGuards(GqlAuthGuard, GqlAdminGuard)
|
||||||
|
async allUsers(
|
||||||
|
@Parent() admin: Admin,
|
||||||
|
@Args() args: PaginationArgs,
|
||||||
|
): Promise<AuthUser[]> {
|
||||||
|
const users = await this.adminService.fetchUsers(args.cursor, args.take);
|
||||||
|
return users;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ResolveField(() => [InvitedUser], {
|
||||||
|
description: 'Returns a list of all the invited users',
|
||||||
|
deprecationReason: 'Use `infra` query instead',
|
||||||
|
})
|
||||||
|
async invitedUsers(@Parent() admin: Admin): Promise<InvitedUser[]> {
|
||||||
|
const users = await this.adminService.fetchInvitedUsers();
|
||||||
|
return users;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ResolveField(() => [Team], {
|
||||||
|
description: 'Returns a list of all the teams in the infra',
|
||||||
|
deprecationReason: 'Use `infra` query instead',
|
||||||
|
})
|
||||||
|
async allTeams(
|
||||||
|
@Parent() admin: Admin,
|
||||||
|
@Args() args: PaginationArgs,
|
||||||
|
): Promise<Team[]> {
|
||||||
|
const teams = await this.adminService.fetchAllTeams(args.cursor, args.take);
|
||||||
|
return teams;
|
||||||
|
}
|
||||||
|
@ResolveField(() => Team, {
|
||||||
|
description: 'Returns a team info by ID when requested by Admin',
|
||||||
|
deprecationReason: 'Use `infra` query instead',
|
||||||
|
})
|
||||||
|
async teamInfo(
|
||||||
|
@Parent() admin: Admin,
|
||||||
|
@Args({
|
||||||
|
name: 'teamID',
|
||||||
|
type: () => ID,
|
||||||
|
description: 'Team ID for which info to fetch',
|
||||||
|
})
|
||||||
|
teamID: string,
|
||||||
|
): Promise<Team> {
|
||||||
|
const team = await this.adminService.getTeamInfo(teamID);
|
||||||
|
if (E.isLeft(team)) throwErr(team.left);
|
||||||
|
return team.right;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ResolveField(() => Number, {
|
||||||
|
description: 'Return count of all the members in a team',
|
||||||
|
deprecationReason: 'Use `infra` query instead',
|
||||||
|
})
|
||||||
|
async membersCountInTeam(
|
||||||
|
@Parent() admin: Admin,
|
||||||
|
@Args({
|
||||||
|
name: 'teamID',
|
||||||
|
type: () => ID,
|
||||||
|
description: 'Team ID for which team members to fetch',
|
||||||
|
nullable: false,
|
||||||
|
})
|
||||||
|
teamID: string,
|
||||||
|
): Promise<number> {
|
||||||
|
const teamMembersCount = await this.adminService.membersCountInTeam(teamID);
|
||||||
|
return teamMembersCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ResolveField(() => Number, {
|
||||||
|
description: 'Return count of all the stored collections in a team',
|
||||||
|
deprecationReason: 'Use `infra` query instead',
|
||||||
|
})
|
||||||
|
async collectionCountInTeam(
|
||||||
|
@Parent() admin: Admin,
|
||||||
|
@Args({
|
||||||
|
name: 'teamID',
|
||||||
|
type: () => ID,
|
||||||
|
description: 'Team ID for which team members to fetch',
|
||||||
|
})
|
||||||
|
teamID: string,
|
||||||
|
): Promise<number> {
|
||||||
|
const teamCollCount = await this.adminService.collectionCountInTeam(teamID);
|
||||||
|
return teamCollCount;
|
||||||
|
}
|
||||||
|
@ResolveField(() => Number, {
|
||||||
|
description: 'Return count of all the stored requests in a team',
|
||||||
|
deprecationReason: 'Use `infra` query instead',
|
||||||
|
})
|
||||||
|
async requestCountInTeam(
|
||||||
|
@Parent() admin: Admin,
|
||||||
|
@Args({
|
||||||
|
name: 'teamID',
|
||||||
|
type: () => ID,
|
||||||
|
description: 'Team ID for which team members to fetch',
|
||||||
|
})
|
||||||
|
teamID: string,
|
||||||
|
): Promise<number> {
|
||||||
|
const teamReqCount = await this.adminService.requestCountInTeam(teamID);
|
||||||
|
return teamReqCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ResolveField(() => Number, {
|
||||||
|
description: 'Return count of all the stored environments in a team',
|
||||||
|
deprecationReason: 'Use `infra` query instead',
|
||||||
|
})
|
||||||
|
async environmentCountInTeam(
|
||||||
|
@Parent() admin: Admin,
|
||||||
|
@Args({
|
||||||
|
name: 'teamID',
|
||||||
|
type: () => ID,
|
||||||
|
description: 'Team ID for which team members to fetch',
|
||||||
|
})
|
||||||
|
teamID: string,
|
||||||
|
): Promise<number> {
|
||||||
|
const envsCount = await this.adminService.environmentCountInTeam(teamID);
|
||||||
|
return envsCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ResolveField(() => [TeamInvitation], {
|
||||||
|
description: 'Return all the pending invitations in a team',
|
||||||
|
deprecationReason: 'Use `infra` query instead',
|
||||||
|
})
|
||||||
|
async pendingInvitationCountInTeam(
|
||||||
|
@Parent() admin: Admin,
|
||||||
|
@Args({
|
||||||
|
name: 'teamID',
|
||||||
|
type: () => ID,
|
||||||
|
description: 'Team ID for which team members to fetch',
|
||||||
|
})
|
||||||
|
teamID: string,
|
||||||
|
) {
|
||||||
|
const invitations = await this.adminService.pendingInvitationCountInTeam(
|
||||||
|
teamID,
|
||||||
|
);
|
||||||
|
return invitations;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ResolveField(() => Number, {
|
||||||
|
description: 'Return total number of Users in organization',
|
||||||
|
deprecationReason: 'Use `infra` query instead',
|
||||||
|
})
|
||||||
|
async usersCount() {
|
||||||
|
return this.adminService.getUsersCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ResolveField(() => Number, {
|
||||||
|
description: 'Return total number of Teams in organization',
|
||||||
|
deprecationReason: 'Use `infra` query instead',
|
||||||
|
})
|
||||||
|
async teamsCount() {
|
||||||
|
return this.adminService.getTeamsCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ResolveField(() => Number, {
|
||||||
|
description: 'Return total number of Team Collections in organization',
|
||||||
|
deprecationReason: 'Use `infra` query instead',
|
||||||
|
})
|
||||||
|
async teamCollectionsCount() {
|
||||||
|
return this.adminService.getTeamCollectionsCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ResolveField(() => Number, {
|
||||||
|
description: 'Return total number of Team Requests in organization',
|
||||||
|
deprecationReason: 'Use `infra` query instead',
|
||||||
|
})
|
||||||
|
async teamRequestsCount() {
|
||||||
|
return this.adminService.getTeamRequestsCount();
|
||||||
|
}
|
||||||
|
|
||||||
/* Mutations */
|
/* Mutations */
|
||||||
|
|
||||||
@Mutation(() => InvitedUser, {
|
@Mutation(() => InvitedUser, {
|
||||||
@@ -70,26 +269,8 @@ export class AdminResolver {
|
|||||||
return invitedUser.right;
|
return invitedUser.right;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Mutation(() => Boolean, {
|
|
||||||
description: 'Revoke a user invites by invitee emails',
|
|
||||||
})
|
|
||||||
@UseGuards(GqlAuthGuard, GqlAdminGuard)
|
|
||||||
async revokeUserInvitationsByAdmin(
|
|
||||||
@Args({
|
|
||||||
name: 'inviteeEmails',
|
|
||||||
description: 'Invitee Emails',
|
|
||||||
type: () => [String],
|
|
||||||
})
|
|
||||||
inviteeEmails: string[],
|
|
||||||
): Promise<boolean> {
|
|
||||||
const invite = await this.adminService.revokeUserInvitations(inviteeEmails);
|
|
||||||
if (E.isLeft(invite)) throwErr(invite.left);
|
|
||||||
return invite.right;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Mutation(() => Boolean, {
|
@Mutation(() => Boolean, {
|
||||||
description: 'Delete an user account from infra',
|
description: 'Delete an user account from infra',
|
||||||
deprecationReason: 'Use removeUsersByAdmin instead',
|
|
||||||
})
|
})
|
||||||
@UseGuards(GqlAuthGuard, GqlAdminGuard)
|
@UseGuards(GqlAuthGuard, GqlAdminGuard)
|
||||||
async removeUserByAdmin(
|
async removeUserByAdmin(
|
||||||
@@ -100,33 +281,12 @@ export class AdminResolver {
|
|||||||
})
|
})
|
||||||
userUID: string,
|
userUID: string,
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
const removedUser = await this.adminService.removeUserAccount(userUID);
|
const invitedUser = await this.adminService.removeUserAccount(userUID);
|
||||||
if (E.isLeft(removedUser)) throwErr(removedUser.left);
|
if (E.isLeft(invitedUser)) throwErr(invitedUser.left);
|
||||||
return removedUser.right;
|
return invitedUser.right;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Mutation(() => [UserDeletionResult], {
|
|
||||||
description: 'Delete user accounts from infra',
|
|
||||||
})
|
|
||||||
@UseGuards(GqlAuthGuard, GqlAdminGuard)
|
|
||||||
async removeUsersByAdmin(
|
|
||||||
@Args({
|
|
||||||
name: 'userUIDs',
|
|
||||||
description: 'users UID',
|
|
||||||
type: () => [ID],
|
|
||||||
})
|
|
||||||
userUIDs: string[],
|
|
||||||
): Promise<UserDeletionResult[]> {
|
|
||||||
const deletionResults = await this.adminService.removeUserAccounts(
|
|
||||||
userUIDs,
|
|
||||||
);
|
|
||||||
if (E.isLeft(deletionResults)) throwErr(deletionResults.left);
|
|
||||||
return deletionResults.right;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Mutation(() => Boolean, {
|
@Mutation(() => Boolean, {
|
||||||
description: 'Make user an admin',
|
description: 'Make user an admin',
|
||||||
deprecationReason: 'Use makeUsersAdmin instead',
|
|
||||||
})
|
})
|
||||||
@UseGuards(GqlAuthGuard, GqlAdminGuard)
|
@UseGuards(GqlAuthGuard, GqlAdminGuard)
|
||||||
async makeUserAdmin(
|
async makeUserAdmin(
|
||||||
@@ -142,51 +302,8 @@ export class AdminResolver {
|
|||||||
return admin.right;
|
return admin.right;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Mutation(() => Boolean, {
|
|
||||||
description: 'Make users an admin',
|
|
||||||
})
|
|
||||||
@UseGuards(GqlAuthGuard, GqlAdminGuard)
|
|
||||||
async makeUsersAdmin(
|
|
||||||
@Args({
|
|
||||||
name: 'userUIDs',
|
|
||||||
description: 'users UID',
|
|
||||||
type: () => [ID],
|
|
||||||
})
|
|
||||||
userUIDs: string[],
|
|
||||||
): Promise<boolean> {
|
|
||||||
const isUpdated = await this.adminService.makeUsersAdmin(userUIDs);
|
|
||||||
if (E.isLeft(isUpdated)) throwErr(isUpdated.left);
|
|
||||||
return isUpdated.right;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Mutation(() => Boolean, {
|
|
||||||
description: 'Update user display name',
|
|
||||||
})
|
|
||||||
@UseGuards(GqlAuthGuard, GqlAdminGuard)
|
|
||||||
async updateUserDisplayNameByAdmin(
|
|
||||||
@Args({
|
|
||||||
name: 'userUID',
|
|
||||||
description: 'users UID',
|
|
||||||
type: () => ID,
|
|
||||||
})
|
|
||||||
userUID: string,
|
|
||||||
@Args({
|
|
||||||
name: 'displayName',
|
|
||||||
description: 'users display name',
|
|
||||||
})
|
|
||||||
displayName: string,
|
|
||||||
): Promise<boolean> {
|
|
||||||
const isUpdated = await this.adminService.updateUserDisplayName(
|
|
||||||
userUID,
|
|
||||||
displayName,
|
|
||||||
);
|
|
||||||
if (E.isLeft(isUpdated)) throwErr(isUpdated.left);
|
|
||||||
return isUpdated.right;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Mutation(() => Boolean, {
|
@Mutation(() => Boolean, {
|
||||||
description: 'Remove user as admin',
|
description: 'Remove user as admin',
|
||||||
deprecationReason: 'Use demoteUsersByAdmin instead',
|
|
||||||
})
|
})
|
||||||
@UseGuards(GqlAuthGuard, GqlAdminGuard)
|
@UseGuards(GqlAuthGuard, GqlAdminGuard)
|
||||||
async removeUserAsAdmin(
|
async removeUserAsAdmin(
|
||||||
@@ -202,23 +319,6 @@ export class AdminResolver {
|
|||||||
return admin.right;
|
return admin.right;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Mutation(() => Boolean, {
|
|
||||||
description: 'Remove users as admin',
|
|
||||||
})
|
|
||||||
@UseGuards(GqlAuthGuard, GqlAdminGuard)
|
|
||||||
async demoteUsersByAdmin(
|
|
||||||
@Args({
|
|
||||||
name: 'userUIDs',
|
|
||||||
description: 'users UID',
|
|
||||||
type: () => [ID],
|
|
||||||
})
|
|
||||||
userUIDs: string[],
|
|
||||||
): Promise<boolean> {
|
|
||||||
const isUpdated = await this.adminService.demoteUsersByAdmin(userUIDs);
|
|
||||||
if (E.isLeft(isUpdated)) throwErr(isUpdated.left);
|
|
||||||
return isUpdated.right;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Mutation(() => Team, {
|
@Mutation(() => Team, {
|
||||||
description:
|
description:
|
||||||
'Create a new team by providing the user uid to nominate as Team owner',
|
'Create a new team by providing the user uid to nominate as Team owner',
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { AdminService } from './admin.service';
|
import { AdminService } from './admin.service';
|
||||||
import { PubSubService } from '../pubsub/pubsub.service';
|
import { PubSubService } from '../pubsub/pubsub.service';
|
||||||
import { mockDeep } from 'jest-mock-extended';
|
import { mockDeep } from 'jest-mock-extended';
|
||||||
import { InvitedUsers, User as DbUser } from '@prisma/client';
|
import { InvitedUsers } from '@prisma/client';
|
||||||
import { UserService } from '../user/user.service';
|
import { UserService } from '../user/user.service';
|
||||||
import { TeamService } from '../team/team.service';
|
import { TeamService } from '../team/team.service';
|
||||||
import { TeamEnvironmentsService } from '../team-environments/team-environments.service';
|
import { TeamEnvironmentsService } from '../team-environments/team-environments.service';
|
||||||
@@ -13,15 +13,10 @@ import { PrismaService } from 'src/prisma/prisma.service';
|
|||||||
import {
|
import {
|
||||||
DUPLICATE_EMAIL,
|
DUPLICATE_EMAIL,
|
||||||
INVALID_EMAIL,
|
INVALID_EMAIL,
|
||||||
ONLY_ONE_ADMIN_ACCOUNT,
|
|
||||||
USER_ALREADY_INVITED,
|
USER_ALREADY_INVITED,
|
||||||
USER_INVITATION_DELETION_FAILED,
|
|
||||||
USER_NOT_FOUND,
|
|
||||||
} from '../errors';
|
} from '../errors';
|
||||||
import { ShortcodeService } from 'src/shortcode/shortcode.service';
|
import { ShortcodeService } from 'src/shortcode/shortcode.service';
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
import { OffsetPaginationArgs } from 'src/types/input-types.args';
|
|
||||||
import * as E from 'fp-ts/Either';
|
|
||||||
|
|
||||||
const mockPrisma = mockDeep<PrismaService>();
|
const mockPrisma = mockDeep<PrismaService>();
|
||||||
const mockPubSub = mockDeep<PubSubService>();
|
const mockPubSub = mockDeep<PubSubService>();
|
||||||
@@ -63,87 +58,20 @@ const invitedUsers: InvitedUsers[] = [
|
|||||||
invitedOn: new Date(),
|
invitedOn: new Date(),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const dbAdminUsers: DbUser[] = [
|
|
||||||
{
|
|
||||||
uid: 'uid 1',
|
|
||||||
displayName: 'displayName',
|
|
||||||
email: 'email@email.com',
|
|
||||||
photoURL: 'photoURL',
|
|
||||||
isAdmin: true,
|
|
||||||
refreshToken: 'refreshToken',
|
|
||||||
currentRESTSession: '',
|
|
||||||
currentGQLSession: '',
|
|
||||||
createdOn: new Date(),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
uid: 'uid 2',
|
|
||||||
displayName: 'displayName',
|
|
||||||
email: 'email@email.com',
|
|
||||||
photoURL: 'photoURL',
|
|
||||||
isAdmin: true,
|
|
||||||
refreshToken: 'refreshToken',
|
|
||||||
currentRESTSession: '',
|
|
||||||
currentGQLSession: '',
|
|
||||||
createdOn: new Date(),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
const dbNonAminUser: DbUser = {
|
|
||||||
uid: 'uid 3',
|
|
||||||
displayName: 'displayName',
|
|
||||||
email: 'email@email.com',
|
|
||||||
photoURL: 'photoURL',
|
|
||||||
isAdmin: false,
|
|
||||||
refreshToken: 'refreshToken',
|
|
||||||
currentRESTSession: '',
|
|
||||||
currentGQLSession: '',
|
|
||||||
createdOn: new Date(),
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('AdminService', () => {
|
describe('AdminService', () => {
|
||||||
describe('fetchInvitedUsers', () => {
|
describe('fetchInvitedUsers', () => {
|
||||||
test('should resolve right and apply pagination correctly', async () => {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-ignore
|
|
||||||
mockPrisma.user.findMany.mockResolvedValue([dbAdminUsers[0]]);
|
|
||||||
// @ts-ignore
|
|
||||||
mockPrisma.invitedUsers.findMany.mockResolvedValue(invitedUsers);
|
|
||||||
|
|
||||||
const paginationArgs: OffsetPaginationArgs = { take: 5, skip: 2 };
|
|
||||||
const results = await adminService.fetchInvitedUsers(paginationArgs);
|
|
||||||
|
|
||||||
expect(mockPrisma.invitedUsers.findMany).toHaveBeenCalledWith({
|
|
||||||
...paginationArgs,
|
|
||||||
orderBy: {
|
|
||||||
invitedOn: 'desc',
|
|
||||||
},
|
|
||||||
where: {
|
|
||||||
NOT: {
|
|
||||||
inviteeEmail: {
|
|
||||||
in: [dbAdminUsers[0].email],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
test('should resolve right and return an array of invited users', async () => {
|
test('should resolve right and return an array of invited users', async () => {
|
||||||
const paginationArgs: OffsetPaginationArgs = { take: 10, skip: 0 };
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
mockPrisma.user.findMany.mockResolvedValue([dbAdminUsers[0]]);
|
|
||||||
// @ts-ignore
|
|
||||||
mockPrisma.invitedUsers.findMany.mockResolvedValue(invitedUsers);
|
mockPrisma.invitedUsers.findMany.mockResolvedValue(invitedUsers);
|
||||||
|
|
||||||
const results = await adminService.fetchInvitedUsers(paginationArgs);
|
const results = await adminService.fetchInvitedUsers();
|
||||||
expect(results).toEqual(invitedUsers);
|
expect(results).toEqual(invitedUsers);
|
||||||
});
|
});
|
||||||
test('should resolve left and return an empty array if invited users not found', async () => {
|
test('should resolve left and return an empty array if invited users not found', async () => {
|
||||||
const paginationArgs: OffsetPaginationArgs = { take: 10, skip: 0 };
|
|
||||||
|
|
||||||
mockPrisma.invitedUsers.findMany.mockResolvedValue([]);
|
mockPrisma.invitedUsers.findMany.mockResolvedValue([]);
|
||||||
|
|
||||||
const results = await adminService.fetchInvitedUsers(paginationArgs);
|
const results = await adminService.fetchInvitedUsers();
|
||||||
expect(results).toEqual([]);
|
expect(results).toEqual([]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -206,58 +134,6 @@ describe('AdminService', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('revokeUserInvitations', () => {
|
|
||||||
test('should resolve left and return error if email not invited', async () => {
|
|
||||||
mockPrisma.invitedUsers.deleteMany.mockRejectedValueOnce(
|
|
||||||
'RecordNotFound',
|
|
||||||
);
|
|
||||||
|
|
||||||
const result = await adminService.revokeUserInvitations([
|
|
||||||
'test@gmail.com',
|
|
||||||
]);
|
|
||||||
|
|
||||||
expect(result).toEqualLeft(USER_INVITATION_DELETION_FAILED);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should resolve right and return deleted invitee email', async () => {
|
|
||||||
const adminUid = 'adminUid';
|
|
||||||
mockPrisma.invitedUsers.deleteMany.mockResolvedValueOnce({ count: 1 });
|
|
||||||
|
|
||||||
const result = await adminService.revokeUserInvitations([
|
|
||||||
invitedUsers[0].inviteeEmail,
|
|
||||||
]);
|
|
||||||
|
|
||||||
expect(mockPrisma.invitedUsers.deleteMany).toHaveBeenCalledWith({
|
|
||||||
where: {
|
|
||||||
inviteeEmail: { in: [invitedUsers[0].inviteeEmail] },
|
|
||||||
},
|
|
||||||
});
|
|
||||||
expect(result).toEqualRight(true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('removeUsersAsAdmin', () => {
|
|
||||||
test('should resolve right and make admins to users', async () => {
|
|
||||||
mockUserService.fetchAdminUsers.mockResolvedValueOnce(dbAdminUsers);
|
|
||||||
mockUserService.removeUsersAsAdmin.mockResolvedValueOnce(E.right(true));
|
|
||||||
|
|
||||||
return expect(
|
|
||||||
await adminService.demoteUsersByAdmin([dbAdminUsers[0].uid]),
|
|
||||||
).toEqualRight(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should resolve left and return error if only one admin in the infra', async () => {
|
|
||||||
mockUserService.fetchAdminUsers.mockResolvedValueOnce(dbAdminUsers);
|
|
||||||
mockUserService.removeUsersAsAdmin.mockResolvedValueOnce(E.right(true));
|
|
||||||
|
|
||||||
return expect(
|
|
||||||
await adminService.demoteUsersByAdmin(
|
|
||||||
dbAdminUsers.map((user) => user.uid),
|
|
||||||
),
|
|
||||||
).toEqualLeft(ONLY_ONE_ADMIN_ACCOUNT);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('getUsersCount', () => {
|
describe('getUsersCount', () => {
|
||||||
test('should return count of all users in the organization', async () => {
|
test('should return count of all users in the organization', async () => {
|
||||||
mockUserService.getUsersCount.mockResolvedValueOnce(10);
|
mockUserService.getUsersCount.mockResolvedValueOnce(10);
|
||||||
|
|||||||
@@ -6,16 +6,13 @@ import * as E from 'fp-ts/Either';
|
|||||||
import * as O from 'fp-ts/Option';
|
import * as O from 'fp-ts/Option';
|
||||||
import { validateEmail } from '../utils';
|
import { validateEmail } from '../utils';
|
||||||
import {
|
import {
|
||||||
ADMIN_CAN_NOT_BE_DELETED,
|
|
||||||
DUPLICATE_EMAIL,
|
DUPLICATE_EMAIL,
|
||||||
EMAIL_FAILED,
|
EMAIL_FAILED,
|
||||||
INVALID_EMAIL,
|
INVALID_EMAIL,
|
||||||
ONLY_ONE_ADMIN_ACCOUNT,
|
ONLY_ONE_ADMIN_ACCOUNT,
|
||||||
TEAM_INVITE_ALREADY_MEMBER,
|
TEAM_INVITE_ALREADY_MEMBER,
|
||||||
TEAM_INVITE_NO_INVITE_FOUND,
|
TEAM_INVITE_NO_INVITE_FOUND,
|
||||||
USERS_NOT_FOUND,
|
|
||||||
USER_ALREADY_INVITED,
|
USER_ALREADY_INVITED,
|
||||||
USER_INVITATION_DELETION_FAILED,
|
|
||||||
USER_IS_ADMIN,
|
USER_IS_ADMIN,
|
||||||
USER_NOT_FOUND,
|
USER_NOT_FOUND,
|
||||||
} from '../errors';
|
} from '../errors';
|
||||||
@@ -29,8 +26,6 @@ import { TeamInvitationService } from '../team-invitation/team-invitation.servic
|
|||||||
import { TeamMemberRole } from '../team/team.model';
|
import { TeamMemberRole } from '../team/team.model';
|
||||||
import { ShortcodeService } from 'src/shortcode/shortcode.service';
|
import { ShortcodeService } from 'src/shortcode/shortcode.service';
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
import { OffsetPaginationArgs } from 'src/types/input-types.args';
|
|
||||||
import { UserDeletionResult } from 'src/user/user.model';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AdminService {
|
export class AdminService {
|
||||||
@@ -53,30 +48,12 @@ export class AdminService {
|
|||||||
* @param cursorID Users uid
|
* @param cursorID Users uid
|
||||||
* @param take number of users to fetch
|
* @param take number of users to fetch
|
||||||
* @returns an Either of array of user or error
|
* @returns an Either of array of user or error
|
||||||
* @deprecated use fetchUsersV2 instead
|
|
||||||
*/
|
*/
|
||||||
async fetchUsers(cursorID: string, take: number) {
|
async fetchUsers(cursorID: string, take: number) {
|
||||||
const allUsers = await this.userService.fetchAllUsers(cursorID, take);
|
const allUsers = await this.userService.fetchAllUsers(cursorID, take);
|
||||||
return allUsers;
|
return allUsers;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetch all the users in the infra.
|
|
||||||
* @param searchString search on users displayName or email
|
|
||||||
* @param paginationOption pagination options
|
|
||||||
* @returns an Either of array of user or error
|
|
||||||
*/
|
|
||||||
async fetchUsersV2(
|
|
||||||
searchString: string,
|
|
||||||
paginationOption: OffsetPaginationArgs,
|
|
||||||
) {
|
|
||||||
const allUsers = await this.userService.fetchAllUsersV2(
|
|
||||||
searchString,
|
|
||||||
paginationOption,
|
|
||||||
);
|
|
||||||
return allUsers;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invite a user to join the infra.
|
* Invite a user to join the infra.
|
||||||
* @param adminUID Admin's UID
|
* @param adminUID Admin's UID
|
||||||
@@ -133,68 +110,14 @@ export class AdminService {
|
|||||||
return E.right(invitedUser);
|
return E.right(invitedUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the display name of a user
|
|
||||||
* @param userUid Who's display name is being updated
|
|
||||||
* @param displayName New display name of the user
|
|
||||||
* @returns an Either of boolean or error
|
|
||||||
*/
|
|
||||||
async updateUserDisplayName(userUid: string, displayName: string) {
|
|
||||||
const updatedUser = await this.userService.updateUserDisplayName(
|
|
||||||
userUid,
|
|
||||||
displayName,
|
|
||||||
);
|
|
||||||
if (E.isLeft(updatedUser)) return E.left(updatedUser.left);
|
|
||||||
|
|
||||||
return E.right(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Revoke infra level user invitations
|
|
||||||
* @param inviteeEmails Invitee's emails
|
|
||||||
* @param adminUid Admin Uid
|
|
||||||
* @returns an Either of boolean or error string
|
|
||||||
*/
|
|
||||||
async revokeUserInvitations(inviteeEmails: string[]) {
|
|
||||||
try {
|
|
||||||
await this.prisma.invitedUsers.deleteMany({
|
|
||||||
where: {
|
|
||||||
inviteeEmail: { in: inviteeEmails },
|
|
||||||
},
|
|
||||||
});
|
|
||||||
return E.right(true);
|
|
||||||
} catch (error) {
|
|
||||||
return E.left(USER_INVITATION_DELETION_FAILED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch the list of invited users by the admin.
|
* Fetch the list of invited users by the admin.
|
||||||
* @returns an Either of array of `InvitedUser` object or error
|
* @returns an Either of array of `InvitedUser` object or error
|
||||||
*/
|
*/
|
||||||
async fetchInvitedUsers(paginationOption: OffsetPaginationArgs) {
|
async fetchInvitedUsers() {
|
||||||
const userEmailObjs = await this.prisma.user.findMany({
|
const invitedUsers = await this.prisma.invitedUsers.findMany();
|
||||||
select: {
|
|
||||||
email: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const pendingInvitedUsers = await this.prisma.invitedUsers.findMany({
|
const users: InvitedUser[] = invitedUsers.map(
|
||||||
take: paginationOption.take,
|
|
||||||
skip: paginationOption.skip,
|
|
||||||
orderBy: {
|
|
||||||
invitedOn: 'desc',
|
|
||||||
},
|
|
||||||
where: {
|
|
||||||
NOT: {
|
|
||||||
inviteeEmail: {
|
|
||||||
in: userEmailObjs.map((user) => user.email),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const users: InvitedUser[] = pendingInvitedUsers.map(
|
|
||||||
(user) => <InvitedUser>{ ...user },
|
(user) => <InvitedUser>{ ...user },
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -414,7 +337,6 @@ export class AdminService {
|
|||||||
* Remove a user account by UID
|
* Remove a user account by UID
|
||||||
* @param userUid User UID
|
* @param userUid User UID
|
||||||
* @returns an Either of boolean or error
|
* @returns an Either of boolean or error
|
||||||
* @deprecated use removeUserAccounts instead
|
|
||||||
*/
|
*/
|
||||||
async removeUserAccount(userUid: string) {
|
async removeUserAccount(userUid: string) {
|
||||||
const user = await this.userService.findUserById(userUid);
|
const user = await this.userService.findUserById(userUid);
|
||||||
@@ -427,73 +349,10 @@ export class AdminService {
|
|||||||
return E.right(delUser.right);
|
return E.right(delUser.right);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove user (not Admin) accounts by UIDs
|
|
||||||
* @param userUIDs User UIDs
|
|
||||||
* @returns an Either of boolean or error
|
|
||||||
*/
|
|
||||||
async removeUserAccounts(userUIDs: string[]) {
|
|
||||||
const userDeleteResult: UserDeletionResult[] = [];
|
|
||||||
|
|
||||||
// step 1: fetch all users
|
|
||||||
const allUsersList = await this.userService.findUsersByIds(userUIDs);
|
|
||||||
if (allUsersList.length === 0) return E.left(USERS_NOT_FOUND);
|
|
||||||
|
|
||||||
// step 2: admin user can not be deleted without removing admin status/role
|
|
||||||
allUsersList.forEach((user) => {
|
|
||||||
if (user.isAdmin) {
|
|
||||||
userDeleteResult.push({
|
|
||||||
userUID: user.uid,
|
|
||||||
isDeleted: false,
|
|
||||||
errorMessage: ADMIN_CAN_NOT_BE_DELETED,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const nonAdminUsers = allUsersList.filter((user) => !user.isAdmin);
|
|
||||||
let deletedUserEmails: string[] = [];
|
|
||||||
|
|
||||||
// step 3: delete non-admin users
|
|
||||||
const deletionPromises = nonAdminUsers.map((user) => {
|
|
||||||
return this.userService
|
|
||||||
.deleteUserByUID(user)()
|
|
||||||
.then((res) => {
|
|
||||||
if (E.isLeft(res)) {
|
|
||||||
return {
|
|
||||||
userUID: user.uid,
|
|
||||||
isDeleted: false,
|
|
||||||
errorMessage: res.left,
|
|
||||||
} as UserDeletionResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
deletedUserEmails.push(user.email);
|
|
||||||
return {
|
|
||||||
userUID: user.uid,
|
|
||||||
isDeleted: true,
|
|
||||||
errorMessage: null,
|
|
||||||
} as UserDeletionResult;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
const promiseResult = await Promise.allSettled(deletionPromises);
|
|
||||||
|
|
||||||
// step 4: revoke all the invites sent to the deleted users
|
|
||||||
await this.revokeUserInvitations(deletedUserEmails);
|
|
||||||
|
|
||||||
// step 5: return the result
|
|
||||||
promiseResult.forEach((result) => {
|
|
||||||
if (result.status === 'fulfilled') {
|
|
||||||
userDeleteResult.push(result.value);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return E.right(userDeleteResult);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make a user an admin
|
* Make a user an admin
|
||||||
* @param userUid User UID
|
* @param userUid User UID
|
||||||
* @returns an Either of boolean or error
|
* @returns an Either of boolean or error
|
||||||
* @deprecated use makeUsersAdmin instead
|
|
||||||
*/
|
*/
|
||||||
async makeUserAdmin(userUID: string) {
|
async makeUserAdmin(userUID: string) {
|
||||||
const admin = await this.userService.makeAdmin(userUID);
|
const admin = await this.userService.makeAdmin(userUID);
|
||||||
@@ -501,22 +360,10 @@ export class AdminService {
|
|||||||
return E.right(true);
|
return E.right(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Make users to admin
|
|
||||||
* @param userUid User UIDs
|
|
||||||
* @returns an Either of boolean or error
|
|
||||||
*/
|
|
||||||
async makeUsersAdmin(userUIDs: string[]) {
|
|
||||||
const isUpdated = await this.userService.makeAdmins(userUIDs);
|
|
||||||
if (E.isLeft(isUpdated)) return E.left(isUpdated.left);
|
|
||||||
return E.right(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove user as admin
|
* Remove user as admin
|
||||||
* @param userUid User UID
|
* @param userUid User UID
|
||||||
* @returns an Either of boolean or error
|
* @returns an Either of boolean or error
|
||||||
* @deprecated use demoteUsersByAdmin instead
|
|
||||||
*/
|
*/
|
||||||
async removeUserAsAdmin(userUID: string) {
|
async removeUserAsAdmin(userUID: string) {
|
||||||
const adminUsers = await this.userService.fetchAdminUsers();
|
const adminUsers = await this.userService.fetchAdminUsers();
|
||||||
@@ -527,26 +374,6 @@ export class AdminService {
|
|||||||
return E.right(true);
|
return E.right(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove users as admin
|
|
||||||
* @param userUIDs User UIDs
|
|
||||||
* @returns an Either of boolean or error
|
|
||||||
*/
|
|
||||||
async demoteUsersByAdmin(userUIDs: string[]) {
|
|
||||||
const adminUsers = await this.userService.fetchAdminUsers();
|
|
||||||
|
|
||||||
const remainingAdmins = adminUsers.filter(
|
|
||||||
(adminUser) => !userUIDs.includes(adminUser.uid),
|
|
||||||
);
|
|
||||||
if (remainingAdmins.length < 1) {
|
|
||||||
return E.left(ONLY_ONE_ADMIN_ACCOUNT);
|
|
||||||
}
|
|
||||||
|
|
||||||
const isUpdated = await this.userService.removeUsersAsAdmin(userUIDs);
|
|
||||||
if (E.isLeft(isUpdated)) return E.left(isUpdated.left);
|
|
||||||
return E.right(isUpdated.right);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch list of all the Users in org
|
* Fetch list of all the Users in org
|
||||||
* @returns number of users in the org
|
* @returns number of users in the org
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
import { Injectable, ExecutionContext, CanActivate } from '@nestjs/common';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class RESTAdminGuard implements CanActivate {
|
|
||||||
canActivate(context: ExecutionContext): boolean {
|
|
||||||
const request = context.switchToHttp().getRequest();
|
|
||||||
const user = request.user;
|
|
||||||
|
|
||||||
return user.isAdmin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -17,10 +17,7 @@ import { AuthUser } from 'src/types/AuthUser';
|
|||||||
import { throwErr } from 'src/utils';
|
import { throwErr } from 'src/utils';
|
||||||
import * as E from 'fp-ts/Either';
|
import * as E from 'fp-ts/Either';
|
||||||
import { Admin } from './admin.model';
|
import { Admin } from './admin.model';
|
||||||
import {
|
import { PaginationArgs } from 'src/types/input-types.args';
|
||||||
OffsetPaginationArgs,
|
|
||||||
PaginationArgs,
|
|
||||||
} from 'src/types/input-types.args';
|
|
||||||
import { InvitedUser } from './invited-user.model';
|
import { InvitedUser } from './invited-user.model';
|
||||||
import { Team } from 'src/team/team.model';
|
import { Team } from 'src/team/team.model';
|
||||||
import { TeamInvitation } from 'src/team-invitation/team-invitation.model';
|
import { TeamInvitation } from 'src/team-invitation/team-invitation.model';
|
||||||
@@ -32,8 +29,7 @@ import {
|
|||||||
EnableAndDisableSSOArgs,
|
EnableAndDisableSSOArgs,
|
||||||
InfraConfigArgs,
|
InfraConfigArgs,
|
||||||
} from 'src/infra-config/input-args';
|
} from 'src/infra-config/input-args';
|
||||||
import { InfraConfigEnum } from 'src/types/InfraConfig';
|
import { InfraConfigEnumForClient } from 'src/types/InfraConfig';
|
||||||
import { ServiceStatus } from 'src/infra-config/helper';
|
|
||||||
|
|
||||||
@UseGuards(GqlThrottlerGuard)
|
@UseGuards(GqlThrottlerGuard)
|
||||||
@Resolver(() => Infra)
|
@Resolver(() => Infra)
|
||||||
@@ -80,7 +76,6 @@ export class InfraResolver {
|
|||||||
|
|
||||||
@ResolveField(() => [User], {
|
@ResolveField(() => [User], {
|
||||||
description: 'Returns a list of all the users in infra',
|
description: 'Returns a list of all the users in infra',
|
||||||
deprecationReason: 'Use allUsersV2 instead',
|
|
||||||
})
|
})
|
||||||
@UseGuards(GqlAuthGuard, GqlAdminGuard)
|
@UseGuards(GqlAuthGuard, GqlAdminGuard)
|
||||||
async allUsers(@Args() args: PaginationArgs): Promise<AuthUser[]> {
|
async allUsers(@Args() args: PaginationArgs): Promise<AuthUser[]> {
|
||||||
@@ -88,33 +83,11 @@ export class InfraResolver {
|
|||||||
return users;
|
return users;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ResolveField(() => [User], {
|
|
||||||
description: 'Returns a list of all the users in infra',
|
|
||||||
})
|
|
||||||
@UseGuards(GqlAuthGuard, GqlAdminGuard)
|
|
||||||
async allUsersV2(
|
|
||||||
@Args({
|
|
||||||
name: 'searchString',
|
|
||||||
nullable: true,
|
|
||||||
description: 'Search on users displayName or email',
|
|
||||||
})
|
|
||||||
searchString: string,
|
|
||||||
@Args() paginationOption: OffsetPaginationArgs,
|
|
||||||
): Promise<AuthUser[]> {
|
|
||||||
const users = await this.adminService.fetchUsersV2(
|
|
||||||
searchString,
|
|
||||||
paginationOption,
|
|
||||||
);
|
|
||||||
return users;
|
|
||||||
}
|
|
||||||
|
|
||||||
@ResolveField(() => [InvitedUser], {
|
@ResolveField(() => [InvitedUser], {
|
||||||
description: 'Returns a list of all the invited users',
|
description: 'Returns a list of all the invited users',
|
||||||
})
|
})
|
||||||
async invitedUsers(
|
async invitedUsers(): Promise<InvitedUser[]> {
|
||||||
@Args() args: OffsetPaginationArgs,
|
const users = await this.adminService.fetchInvitedUsers();
|
||||||
): Promise<InvitedUser[]> {
|
|
||||||
const users = await this.adminService.fetchInvitedUsers(args);
|
|
||||||
return users;
|
return users;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -274,10 +247,10 @@ export class InfraResolver {
|
|||||||
async infraConfigs(
|
async infraConfigs(
|
||||||
@Args({
|
@Args({
|
||||||
name: 'configNames',
|
name: 'configNames',
|
||||||
type: () => [InfraConfigEnum],
|
type: () => [InfraConfigEnumForClient],
|
||||||
description: 'Configs to fetch',
|
description: 'Configs to fetch',
|
||||||
})
|
})
|
||||||
names: InfraConfigEnum[],
|
names: InfraConfigEnumForClient[],
|
||||||
) {
|
) {
|
||||||
const infraConfigs = await this.infraConfigService.getMany(names);
|
const infraConfigs = await this.infraConfigService.getMany(names);
|
||||||
if (E.isLeft(infraConfigs)) throwErr(infraConfigs.left);
|
if (E.isLeft(infraConfigs)) throwErr(infraConfigs.left);
|
||||||
@@ -311,25 +284,6 @@ export class InfraResolver {
|
|||||||
return updatedRes.right;
|
return updatedRes.right;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Mutation(() => Boolean, {
|
|
||||||
description: 'Enable or disable analytics collection',
|
|
||||||
})
|
|
||||||
@UseGuards(GqlAuthGuard, GqlAdminGuard)
|
|
||||||
async toggleAnalyticsCollection(
|
|
||||||
@Args({
|
|
||||||
name: 'status',
|
|
||||||
type: () => ServiceStatus,
|
|
||||||
description: 'Toggle analytics collection',
|
|
||||||
})
|
|
||||||
analyticsCollectionStatus: ServiceStatus,
|
|
||||||
) {
|
|
||||||
const res = await this.infraConfigService.toggleAnalyticsCollection(
|
|
||||||
analyticsCollectionStatus,
|
|
||||||
);
|
|
||||||
if (E.isLeft(res)) throwErr(res.left);
|
|
||||||
return res.right;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Mutation(() => Boolean, {
|
@Mutation(() => Boolean, {
|
||||||
description: 'Reset Infra Configs with default values (.env)',
|
description: 'Reset Infra Configs with default values (.env)',
|
||||||
})
|
})
|
||||||
@@ -352,9 +306,7 @@ export class InfraResolver {
|
|||||||
})
|
})
|
||||||
providerInfo: EnableAndDisableSSOArgs[],
|
providerInfo: EnableAndDisableSSOArgs[],
|
||||||
) {
|
) {
|
||||||
const isUpdated = await this.infraConfigService.enableAndDisableSSO(
|
const isUpdated = await this.infraConfigService.enableAndDisableSSO(providerInfo);
|
||||||
providerInfo,
|
|
||||||
);
|
|
||||||
if (E.isLeft(isUpdated)) throwErr(isUpdated.left);
|
if (E.isLeft(isUpdated)) throwErr(isUpdated.left);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -24,8 +24,6 @@ import { ConfigModule, ConfigService } from '@nestjs/config';
|
|||||||
import { InfraConfigModule } from './infra-config/infra-config.module';
|
import { InfraConfigModule } from './infra-config/infra-config.module';
|
||||||
import { loadInfraConfiguration } from './infra-config/helper';
|
import { loadInfraConfiguration } from './infra-config/helper';
|
||||||
import { MailerModule } from './mailer/mailer.module';
|
import { MailerModule } from './mailer/mailer.module';
|
||||||
import { PosthogModule } from './posthog/posthog.module';
|
|
||||||
import { ScheduleModule } from '@nestjs/schedule';
|
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -98,8 +96,6 @@ import { ScheduleModule } from '@nestjs/schedule';
|
|||||||
UserCollectionModule,
|
UserCollectionModule,
|
||||||
ShortcodeModule,
|
ShortcodeModule,
|
||||||
InfraConfigModule,
|
InfraConfigModule,
|
||||||
PosthogModule,
|
|
||||||
ScheduleModule.forRoot(),
|
|
||||||
],
|
],
|
||||||
providers: [GQLComplexityPlugin],
|
providers: [GQLComplexityPlugin],
|
||||||
controllers: [AppController],
|
controllers: [AppController],
|
||||||
|
|||||||
@@ -18,7 +18,12 @@ import { JwtAuthGuard } from './guards/jwt-auth.guard';
|
|||||||
import { GqlUser } from 'src/decorators/gql-user.decorator';
|
import { GqlUser } from 'src/decorators/gql-user.decorator';
|
||||||
import { AuthUser } from 'src/types/AuthUser';
|
import { AuthUser } from 'src/types/AuthUser';
|
||||||
import { RTCookie } from 'src/decorators/rt-cookie.decorator';
|
import { RTCookie } from 'src/decorators/rt-cookie.decorator';
|
||||||
import { AuthProvider, authCookieHandler, authProviderCheck } from './helper';
|
import {
|
||||||
|
AuthProvider,
|
||||||
|
authCookieHandler,
|
||||||
|
authProviderCheck,
|
||||||
|
throwHTTPErr,
|
||||||
|
} from './helper';
|
||||||
import { GoogleSSOGuard } from './guards/google-sso.guard';
|
import { GoogleSSOGuard } from './guards/google-sso.guard';
|
||||||
import { GithubSSOGuard } from './guards/github-sso.guard';
|
import { GithubSSOGuard } from './guards/github-sso.guard';
|
||||||
import { MicrosoftSSOGuard } from './guards/microsoft-sso-.guard';
|
import { MicrosoftSSOGuard } from './guards/microsoft-sso-.guard';
|
||||||
@@ -26,7 +31,6 @@ import { ThrottlerBehindProxyGuard } from 'src/guards/throttler-behind-proxy.gua
|
|||||||
import { SkipThrottle } from '@nestjs/throttler';
|
import { SkipThrottle } from '@nestjs/throttler';
|
||||||
import { AUTH_PROVIDER_NOT_SPECIFIED } from 'src/errors';
|
import { AUTH_PROVIDER_NOT_SPECIFIED } from 'src/errors';
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
import { throwHTTPErr } from 'src/utils';
|
|
||||||
|
|
||||||
@UseGuards(ThrottlerBehindProxyGuard)
|
@UseGuards(ThrottlerBehindProxyGuard)
|
||||||
@Controller({ path: 'auth', version: '1' })
|
@Controller({ path: 'auth', version: '1' })
|
||||||
|
|||||||
@@ -12,10 +12,7 @@ import { GithubStrategy } from './strategies/github.strategy';
|
|||||||
import { MicrosoftStrategy } from './strategies/microsoft.strategy';
|
import { MicrosoftStrategy } from './strategies/microsoft.strategy';
|
||||||
import { AuthProvider, authProviderCheck } from './helper';
|
import { AuthProvider, authProviderCheck } from './helper';
|
||||||
import { ConfigModule, ConfigService } from '@nestjs/config';
|
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||||
import {
|
import { loadInfraConfiguration } from 'src/infra-config/helper';
|
||||||
isInfraConfigTablePopulated,
|
|
||||||
loadInfraConfiguration,
|
|
||||||
} from 'src/infra-config/helper';
|
|
||||||
import { InfraConfigModule } from 'src/infra-config/infra-config.module';
|
import { InfraConfigModule } from 'src/infra-config/infra-config.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
@@ -37,11 +34,6 @@ import { InfraConfigModule } from 'src/infra-config/infra-config.module';
|
|||||||
})
|
})
|
||||||
export class AuthModule {
|
export class AuthModule {
|
||||||
static async register() {
|
static async register() {
|
||||||
const isInfraConfigPopulated = await isInfraConfigTablePopulated();
|
|
||||||
if (!isInfraConfigPopulated) {
|
|
||||||
return { module: AuthModule };
|
|
||||||
}
|
|
||||||
|
|
||||||
const env = await loadInfraConfiguration();
|
const env = await loadInfraConfiguration();
|
||||||
const allowedAuthProviders = env.INFRA.VITE_ALLOWED_AUTH_PROVIDERS;
|
const allowedAuthProviders = env.INFRA.VITE_ALLOWED_AUTH_PROVIDERS;
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import {
|
|||||||
RefreshTokenPayload,
|
RefreshTokenPayload,
|
||||||
} from 'src/types/AuthTokens';
|
} from 'src/types/AuthTokens';
|
||||||
import { JwtService } from '@nestjs/jwt';
|
import { JwtService } from '@nestjs/jwt';
|
||||||
import { RESTError } from 'src/types/RESTError';
|
import { AuthError } from 'src/types/AuthError';
|
||||||
import { AuthUser, IsAdmin } from 'src/types/AuthUser';
|
import { AuthUser, IsAdmin } from 'src/types/AuthUser';
|
||||||
import { VerificationToken } from '@prisma/client';
|
import { VerificationToken } from '@prisma/client';
|
||||||
import { Origin } from './helper';
|
import { Origin } from './helper';
|
||||||
@@ -117,7 +117,7 @@ export class AuthService {
|
|||||||
userUid,
|
userUid,
|
||||||
);
|
);
|
||||||
if (E.isLeft(updatedUser))
|
if (E.isLeft(updatedUser))
|
||||||
return E.left(<RESTError>{
|
return E.left(<AuthError>{
|
||||||
message: updatedUser.left,
|
message: updatedUser.left,
|
||||||
statusCode: HttpStatus.NOT_FOUND,
|
statusCode: HttpStatus.NOT_FOUND,
|
||||||
});
|
});
|
||||||
@@ -255,7 +255,7 @@ export class AuthService {
|
|||||||
*/
|
*/
|
||||||
async verifyMagicLinkTokens(
|
async verifyMagicLinkTokens(
|
||||||
magicLinkIDTokens: VerifyMagicDto,
|
magicLinkIDTokens: VerifyMagicDto,
|
||||||
): Promise<E.Right<AuthTokens> | E.Left<RESTError>> {
|
): Promise<E.Right<AuthTokens> | E.Left<AuthError>> {
|
||||||
const passwordlessTokens = await this.validatePasswordlessTokens(
|
const passwordlessTokens = await this.validatePasswordlessTokens(
|
||||||
magicLinkIDTokens,
|
magicLinkIDTokens,
|
||||||
);
|
);
|
||||||
@@ -373,7 +373,7 @@ export class AuthService {
|
|||||||
if (usersCount === 1) {
|
if (usersCount === 1) {
|
||||||
const elevatedUser = await this.usersService.makeAdmin(user.uid);
|
const elevatedUser = await this.usersService.makeAdmin(user.uid);
|
||||||
if (E.isLeft(elevatedUser))
|
if (E.isLeft(elevatedUser))
|
||||||
return E.left(<RESTError>{
|
return E.left(<AuthError>{
|
||||||
message: elevatedUser.left,
|
message: elevatedUser.left,
|
||||||
statusCode: HttpStatus.NOT_FOUND,
|
statusCode: HttpStatus.NOT_FOUND,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
|
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
|
||||||
import { AuthGuard } from '@nestjs/passport';
|
import { AuthGuard } from '@nestjs/passport';
|
||||||
import { AuthProvider, authProviderCheck } from '../helper';
|
import { AuthProvider, authProviderCheck, throwHTTPErr } from '../helper';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { AUTH_PROVIDER_NOT_SPECIFIED } from 'src/errors';
|
import { AUTH_PROVIDER_NOT_SPECIFIED } from 'src/errors';
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
import { throwHTTPErr } from 'src/utils';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class GithubSSOGuard extends AuthGuard('github') implements CanActivate {
|
export class GithubSSOGuard extends AuthGuard('github') implements CanActivate {
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
|
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
|
||||||
import { AuthGuard } from '@nestjs/passport';
|
import { AuthGuard } from '@nestjs/passport';
|
||||||
import { AuthProvider, authProviderCheck } from '../helper';
|
import { AuthProvider, authProviderCheck, throwHTTPErr } from '../helper';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { AUTH_PROVIDER_NOT_SPECIFIED } from 'src/errors';
|
import { AUTH_PROVIDER_NOT_SPECIFIED } from 'src/errors';
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
import { throwHTTPErr } from 'src/utils';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class GoogleSSOGuard extends AuthGuard('google') implements CanActivate {
|
export class GoogleSSOGuard extends AuthGuard('google') implements CanActivate {
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
|
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
|
||||||
import { AuthGuard } from '@nestjs/passport';
|
import { AuthGuard } from '@nestjs/passport';
|
||||||
import { AuthProvider, authProviderCheck } from '../helper';
|
import { AuthProvider, authProviderCheck, throwHTTPErr } from '../helper';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { AUTH_PROVIDER_NOT_SPECIFIED } from 'src/errors';
|
import { AUTH_PROVIDER_NOT_SPECIFIED } from 'src/errors';
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
import { throwHTTPErr } from 'src/utils';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class MicrosoftSSOGuard
|
export class MicrosoftSSOGuard
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { HttpException, HttpStatus } from '@nestjs/common';
|
import { HttpException, HttpStatus } from '@nestjs/common';
|
||||||
import { DateTime } from 'luxon';
|
import { DateTime } from 'luxon';
|
||||||
|
import { AuthError } from 'src/types/AuthError';
|
||||||
import { AuthTokens } from 'src/types/AuthTokens';
|
import { AuthTokens } from 'src/types/AuthTokens';
|
||||||
import { Response } from 'express';
|
import { Response } from 'express';
|
||||||
import * as cookie from 'cookie';
|
import * as cookie from 'cookie';
|
||||||
@@ -24,6 +25,15 @@ export enum AuthProvider {
|
|||||||
EMAIL = 'EMAIL',
|
EMAIL = 'EMAIL',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function allows throw to be used as an expression
|
||||||
|
* @param errMessage Message present in the error message
|
||||||
|
*/
|
||||||
|
export function throwHTTPErr(errorData: AuthError): never {
|
||||||
|
const { message, statusCode } = errorData;
|
||||||
|
throw new HttpException(message, statusCode);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets and returns the cookies in the response object on successful authentication
|
* Sets and returns the cookies in the response object on successful authentication
|
||||||
* @param res Express Response Object
|
* @param res Express Response Object
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ export class GithubStrategy extends PassportStrategy(Strategy) {
|
|||||||
super({
|
super({
|
||||||
clientID: configService.get('INFRA.GITHUB_CLIENT_ID'),
|
clientID: configService.get('INFRA.GITHUB_CLIENT_ID'),
|
||||||
clientSecret: configService.get('INFRA.GITHUB_CLIENT_SECRET'),
|
clientSecret: configService.get('INFRA.GITHUB_CLIENT_SECRET'),
|
||||||
callbackURL: configService.get('INFRA.GITHUB_CALLBACK_URL'),
|
callbackURL: configService.get('GITHUB_CALLBACK_URL'),
|
||||||
scope: [configService.get('INFRA.GITHUB_SCOPE')],
|
scope: [configService.get('GITHUB_SCOPE')],
|
||||||
store: true,
|
store: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ export class GoogleStrategy extends PassportStrategy(Strategy) {
|
|||||||
super({
|
super({
|
||||||
clientID: configService.get('INFRA.GOOGLE_CLIENT_ID'),
|
clientID: configService.get('INFRA.GOOGLE_CLIENT_ID'),
|
||||||
clientSecret: configService.get('INFRA.GOOGLE_CLIENT_SECRET'),
|
clientSecret: configService.get('INFRA.GOOGLE_CLIENT_SECRET'),
|
||||||
callbackURL: configService.get('INFRA.GOOGLE_CALLBACK_URL'),
|
callbackURL: configService.get('GOOGLE_CALLBACK_URL'),
|
||||||
scope: configService.get('INFRA.GOOGLE_SCOPE').split(','),
|
scope: configService.get('GOOGLE_SCOPE').split(','),
|
||||||
passReqToCallback: true,
|
passReqToCallback: true,
|
||||||
store: true,
|
store: true,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ export class MicrosoftStrategy extends PassportStrategy(Strategy) {
|
|||||||
super({
|
super({
|
||||||
clientID: configService.get('INFRA.MICROSOFT_CLIENT_ID'),
|
clientID: configService.get('INFRA.MICROSOFT_CLIENT_ID'),
|
||||||
clientSecret: configService.get('INFRA.MICROSOFT_CLIENT_SECRET'),
|
clientSecret: configService.get('INFRA.MICROSOFT_CLIENT_SECRET'),
|
||||||
callbackURL: configService.get('INFRA.MICROSOFT_CALLBACK_URL'),
|
callbackURL: configService.get('MICROSOFT_CALLBACK_URL'),
|
||||||
scope: [configService.get('INFRA.MICROSOFT_SCOPE')],
|
scope: [configService.get('MICROSOFT_SCOPE')],
|
||||||
tenant: configService.get('INFRA.MICROSOFT_TENANT'),
|
tenant: configService.get('MICROSOFT_TENANT'),
|
||||||
store: true,
|
store: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,14 +10,6 @@ export const DUPLICATE_EMAIL = 'email/both_emails_cannot_be_same' as const;
|
|||||||
export const ONLY_ONE_ADMIN_ACCOUNT =
|
export const ONLY_ONE_ADMIN_ACCOUNT =
|
||||||
'admin/only_one_admin_account_found' as const;
|
'admin/only_one_admin_account_found' as const;
|
||||||
|
|
||||||
/**
|
|
||||||
* Admin user can not be deleted
|
|
||||||
* To delete the admin user, first make the Admin user a normal user
|
|
||||||
* (AdminService)
|
|
||||||
*/
|
|
||||||
export const ADMIN_CAN_NOT_BE_DELETED =
|
|
||||||
'admin/admin_can_not_be_deleted' as const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Token Authorization failed (Check 'Authorization' Header)
|
* Token Authorization failed (Check 'Authorization' Header)
|
||||||
* (GqlAuthGuard)
|
* (GqlAuthGuard)
|
||||||
@@ -84,12 +76,6 @@ export const USER_ALREADY_INVITED = 'admin/user_already_invited' as const;
|
|||||||
*/
|
*/
|
||||||
export const USER_UPDATE_FAILED = 'user/update_failed' as const;
|
export const USER_UPDATE_FAILED = 'user/update_failed' as const;
|
||||||
|
|
||||||
/**
|
|
||||||
* User display name validation failure
|
|
||||||
* (UserService)
|
|
||||||
*/
|
|
||||||
export const USER_SHORT_DISPLAY_NAME = 'user/short_display_name' as const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User deletion failure
|
* User deletion failure
|
||||||
* (UserService)
|
* (UserService)
|
||||||
@@ -113,13 +99,6 @@ export const USER_IS_OWNER = 'user/is_owner' as const;
|
|||||||
*/
|
*/
|
||||||
export const USER_IS_ADMIN = 'user/is_admin' as const;
|
export const USER_IS_ADMIN = 'user/is_admin' as const;
|
||||||
|
|
||||||
/**
|
|
||||||
* User invite deletion failure error due to invitation not found
|
|
||||||
* (AdminService)
|
|
||||||
*/
|
|
||||||
export const USER_INVITATION_DELETION_FAILED =
|
|
||||||
'user/invitation_deletion_failed' as const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Teams not found
|
* Teams not found
|
||||||
* (TeamsService)
|
* (TeamsService)
|
||||||
@@ -234,12 +213,6 @@ export const TEAM_COL_NOT_SAME_PARENT =
|
|||||||
export const TEAM_COL_SAME_NEXT_COLL =
|
export const TEAM_COL_SAME_NEXT_COLL =
|
||||||
'team_coll/collection_and_next_collection_are_same';
|
'team_coll/collection_and_next_collection_are_same';
|
||||||
|
|
||||||
/**
|
|
||||||
* Team Collection search failed
|
|
||||||
* (TeamCollectionService)
|
|
||||||
*/
|
|
||||||
export const TEAM_COL_SEARCH_FAILED = 'team_coll/team_collection_search_failed';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Team Collection Re-Ordering Failed
|
* Team Collection Re-Ordering Failed
|
||||||
* (TeamCollectionService)
|
* (TeamCollectionService)
|
||||||
@@ -295,13 +268,6 @@ export const TEAM_NOT_OWNER = 'team_coll/team_not_owner' as const;
|
|||||||
export const TEAM_COLL_DATA_INVALID =
|
export const TEAM_COLL_DATA_INVALID =
|
||||||
'team_coll/team_coll_data_invalid' as const;
|
'team_coll/team_coll_data_invalid' as const;
|
||||||
|
|
||||||
/**
|
|
||||||
* Team Collection parent tree generation failed
|
|
||||||
* (TeamCollectionService)
|
|
||||||
*/
|
|
||||||
export const TEAM_COLL_PARENT_TREE_GEN_FAILED =
|
|
||||||
'team_coll/team_coll_parent_tree_generation_failed';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tried to perform an action on a request that doesn't accept their member role level
|
* Tried to perform an action on a request that doesn't accept their member role level
|
||||||
* (GqlRequestTeamMemberGuard)
|
* (GqlRequestTeamMemberGuard)
|
||||||
@@ -327,19 +293,6 @@ export const TEAM_REQ_INVALID_TARGET_COLL_ID =
|
|||||||
*/
|
*/
|
||||||
export const TEAM_REQ_REORDERING_FAILED = 'team_req/reordering_failed' as const;
|
export const TEAM_REQ_REORDERING_FAILED = 'team_req/reordering_failed' as const;
|
||||||
|
|
||||||
/**
|
|
||||||
* Team Request search failed
|
|
||||||
* (TeamRequestService)
|
|
||||||
*/
|
|
||||||
export const TEAM_REQ_SEARCH_FAILED = 'team_req/team_request_search_failed';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Team Request parent tree generation failed
|
|
||||||
* (TeamRequestService)
|
|
||||||
*/
|
|
||||||
export const TEAM_REQ_PARENT_TREE_GEN_FAILED =
|
|
||||||
'team_req/team_req_parent_tree_generation_failed';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* No Postmark Sender Email defined
|
* No Postmark Sender Email defined
|
||||||
* (AuthService)
|
* (AuthService)
|
||||||
@@ -737,27 +690,9 @@ export const INFRA_CONFIG_INVALID_INPUT = 'infra_config/invalid_input' as const;
|
|||||||
export const INFRA_CONFIG_SERVICE_NOT_CONFIGURED =
|
export const INFRA_CONFIG_SERVICE_NOT_CONFIGURED =
|
||||||
'infra_config/service_not_configured' as const;
|
'infra_config/service_not_configured' as const;
|
||||||
|
|
||||||
/**
|
|
||||||
* Infra Config update/fetch operation not allowed
|
|
||||||
* (InfraConfigService)
|
|
||||||
*/
|
|
||||||
export const INFRA_CONFIG_OPERATION_NOT_ALLOWED =
|
|
||||||
'infra_config/operation_not_allowed';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Error message for when the database table does not exist
|
* Error message for when the database table does not exist
|
||||||
* (InfraConfigService)
|
* (InfraConfigService)
|
||||||
*/
|
*/
|
||||||
export const DATABASE_TABLE_NOT_EXIST =
|
export const DATABASE_TABLE_NOT_EXIST =
|
||||||
'Database migration not found. Please check the documentation for assistance: https://docs.hoppscotch.io/documentation/self-host/community-edition/install-and-build#running-migrations';
|
'Database migration not found. Please check the documentation for assistance: https://docs.hoppscotch.io/documentation/self-host/community-edition/install-and-build#running-migrations';
|
||||||
|
|
||||||
/**
|
|
||||||
* PostHog client is not initialized
|
|
||||||
* (InfraConfigService)
|
|
||||||
*/
|
|
||||||
export const POSTHOG_CLIENT_NOT_INITIALIZED = 'posthog/client_not_initialized';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inputs supplied are invalid
|
|
||||||
*/
|
|
||||||
export const INVALID_PARAMS = 'invalid_parameters' as const;
|
|
||||||
|
|||||||
@@ -1,12 +1,8 @@
|
|||||||
import { AuthProvider } from 'src/auth/helper';
|
import { AuthProvider } from 'src/auth/helper';
|
||||||
import {
|
import { AUTH_PROVIDER_NOT_CONFIGURED } from 'src/errors';
|
||||||
AUTH_PROVIDER_NOT_CONFIGURED,
|
|
||||||
DATABASE_TABLE_NOT_EXIST,
|
|
||||||
} from 'src/errors';
|
|
||||||
import { PrismaService } from 'src/prisma/prisma.service';
|
import { PrismaService } from 'src/prisma/prisma.service';
|
||||||
import { InfraConfigEnum } from 'src/types/InfraConfig';
|
import { InfraConfigEnum } from 'src/types/InfraConfig';
|
||||||
import { throwErr } from 'src/utils';
|
import { throwErr } from 'src/utils';
|
||||||
import { randomBytes } from 'crypto';
|
|
||||||
|
|
||||||
export enum ServiceStatus {
|
export enum ServiceStatus {
|
||||||
ENABLE = 'ENABLE',
|
ENABLE = 'ENABLE',
|
||||||
@@ -17,21 +13,14 @@ const AuthProviderConfigurations = {
|
|||||||
[AuthProvider.GOOGLE]: [
|
[AuthProvider.GOOGLE]: [
|
||||||
InfraConfigEnum.GOOGLE_CLIENT_ID,
|
InfraConfigEnum.GOOGLE_CLIENT_ID,
|
||||||
InfraConfigEnum.GOOGLE_CLIENT_SECRET,
|
InfraConfigEnum.GOOGLE_CLIENT_SECRET,
|
||||||
InfraConfigEnum.GOOGLE_CALLBACK_URL,
|
|
||||||
InfraConfigEnum.GOOGLE_SCOPE,
|
|
||||||
],
|
],
|
||||||
[AuthProvider.GITHUB]: [
|
[AuthProvider.GITHUB]: [
|
||||||
InfraConfigEnum.GITHUB_CLIENT_ID,
|
InfraConfigEnum.GITHUB_CLIENT_ID,
|
||||||
InfraConfigEnum.GITHUB_CLIENT_SECRET,
|
InfraConfigEnum.GITHUB_CLIENT_SECRET,
|
||||||
InfraConfigEnum.GITHUB_CALLBACK_URL,
|
|
||||||
InfraConfigEnum.GITHUB_SCOPE,
|
|
||||||
],
|
],
|
||||||
[AuthProvider.MICROSOFT]: [
|
[AuthProvider.MICROSOFT]: [
|
||||||
InfraConfigEnum.MICROSOFT_CLIENT_ID,
|
InfraConfigEnum.MICROSOFT_CLIENT_ID,
|
||||||
InfraConfigEnum.MICROSOFT_CLIENT_SECRET,
|
InfraConfigEnum.MICROSOFT_CLIENT_SECRET,
|
||||||
InfraConfigEnum.MICROSOFT_CALLBACK_URL,
|
|
||||||
InfraConfigEnum.MICROSOFT_SCOPE,
|
|
||||||
InfraConfigEnum.MICROSOFT_TENANT,
|
|
||||||
],
|
],
|
||||||
[AuthProvider.EMAIL]: [
|
[AuthProvider.EMAIL]: [
|
||||||
InfraConfigEnum.MAILER_SMTP_URL,
|
InfraConfigEnum.MAILER_SMTP_URL,
|
||||||
@@ -64,139 +53,6 @@ export async function loadInfraConfiguration() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Read the default values from .env file and return them as an array
|
|
||||||
* @returns Array of default infra configs
|
|
||||||
*/
|
|
||||||
export async function getDefaultInfraConfigs(): Promise<
|
|
||||||
{ name: InfraConfigEnum; value: string }[]
|
|
||||||
> {
|
|
||||||
const prisma = new PrismaService();
|
|
||||||
|
|
||||||
// Prepare rows for 'infra_config' table with default values (from .env) for each 'name'
|
|
||||||
const infraConfigDefaultObjs: { name: InfraConfigEnum; value: string }[] = [
|
|
||||||
{
|
|
||||||
name: InfraConfigEnum.MAILER_SMTP_URL,
|
|
||||||
value: process.env.MAILER_SMTP_URL,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: InfraConfigEnum.MAILER_ADDRESS_FROM,
|
|
||||||
value: process.env.MAILER_ADDRESS_FROM,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: InfraConfigEnum.GOOGLE_CLIENT_ID,
|
|
||||||
value: process.env.GOOGLE_CLIENT_ID,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: InfraConfigEnum.GOOGLE_CLIENT_SECRET,
|
|
||||||
value: process.env.GOOGLE_CLIENT_SECRET,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: InfraConfigEnum.GOOGLE_CALLBACK_URL,
|
|
||||||
value: process.env.GOOGLE_CALLBACK_URL,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: InfraConfigEnum.GOOGLE_SCOPE,
|
|
||||||
value: process.env.GOOGLE_SCOPE,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: InfraConfigEnum.GITHUB_CLIENT_ID,
|
|
||||||
value: process.env.GITHUB_CLIENT_ID,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: InfraConfigEnum.GITHUB_CLIENT_SECRET,
|
|
||||||
value: process.env.GITHUB_CLIENT_SECRET,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: InfraConfigEnum.GITHUB_CALLBACK_URL,
|
|
||||||
value: process.env.GITHUB_CALLBACK_URL,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: InfraConfigEnum.GITHUB_SCOPE,
|
|
||||||
value: process.env.GITHUB_SCOPE,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: InfraConfigEnum.MICROSOFT_CLIENT_ID,
|
|
||||||
value: process.env.MICROSOFT_CLIENT_ID,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: InfraConfigEnum.MICROSOFT_CLIENT_SECRET,
|
|
||||||
value: process.env.MICROSOFT_CLIENT_SECRET,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: InfraConfigEnum.MICROSOFT_CALLBACK_URL,
|
|
||||||
value: process.env.MICROSOFT_CALLBACK_URL,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: InfraConfigEnum.MICROSOFT_SCOPE,
|
|
||||||
value: process.env.MICROSOFT_SCOPE,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: InfraConfigEnum.MICROSOFT_TENANT,
|
|
||||||
value: process.env.MICROSOFT_TENANT,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: InfraConfigEnum.VITE_ALLOWED_AUTH_PROVIDERS,
|
|
||||||
value: getConfiguredSSOProviders(),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: InfraConfigEnum.ALLOW_ANALYTICS_COLLECTION,
|
|
||||||
value: false.toString(),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: InfraConfigEnum.ANALYTICS_USER_ID,
|
|
||||||
value: generateAnalyticsUserId(),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: InfraConfigEnum.IS_FIRST_TIME_INFRA_SETUP,
|
|
||||||
value: (await prisma.infraConfig.count()) === 0 ? 'true' : 'false',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
return infraConfigDefaultObjs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the missing entries in the 'infra_config' table
|
|
||||||
* @returns Array of InfraConfig
|
|
||||||
*/
|
|
||||||
export async function getMissingInfraConfigEntries() {
|
|
||||||
const prisma = new PrismaService();
|
|
||||||
const [dbInfraConfigs, infraConfigDefaultObjs] = await Promise.all([
|
|
||||||
prisma.infraConfig.findMany(),
|
|
||||||
getDefaultInfraConfigs(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
const missingEntries = infraConfigDefaultObjs.filter(
|
|
||||||
(config) =>
|
|
||||||
!dbInfraConfigs.some((dbConfig) => dbConfig.name === config.name),
|
|
||||||
);
|
|
||||||
|
|
||||||
return missingEntries;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Verify if 'infra_config' table is loaded with all entries
|
|
||||||
* @returns boolean
|
|
||||||
*/
|
|
||||||
export async function isInfraConfigTablePopulated(): Promise<boolean> {
|
|
||||||
const prisma = new PrismaService();
|
|
||||||
try {
|
|
||||||
const propsRemainingToInsert = await getMissingInfraConfigEntries();
|
|
||||||
|
|
||||||
if (propsRemainingToInsert.length > 0) {
|
|
||||||
console.log(
|
|
||||||
'Infra Config table is not populated with all entries. Populating now...',
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} catch (error) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stop the app after 5 seconds
|
* Stop the app after 5 seconds
|
||||||
* (Docker will re-start the app)
|
* (Docker will re-start the app)
|
||||||
@@ -248,12 +104,3 @@ export function getConfiguredSSOProviders() {
|
|||||||
|
|
||||||
return configuredAuthProviders.join(',');
|
return configuredAuthProviders.join(',');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate a hashed valued for analytics
|
|
||||||
* @returns Generated hashed value
|
|
||||||
*/
|
|
||||||
export function generateAnalyticsUserId() {
|
|
||||||
const hashedUserID = randomBytes(20).toString('hex');
|
|
||||||
return hashedUserID;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,47 +0,0 @@
|
|||||||
import { Controller, Get, HttpStatus, Put, UseGuards } from '@nestjs/common';
|
|
||||||
import { ThrottlerBehindProxyGuard } from 'src/guards/throttler-behind-proxy.guard';
|
|
||||||
import { InfraConfigService } from './infra-config.service';
|
|
||||||
import * as E from 'fp-ts/Either';
|
|
||||||
import { JwtAuthGuard } from 'src/auth/guards/jwt-auth.guard';
|
|
||||||
import { RESTAdminGuard } from 'src/admin/guards/rest-admin.guard';
|
|
||||||
import { RESTError } from 'src/types/RESTError';
|
|
||||||
import { InfraConfigEnum } from 'src/types/InfraConfig';
|
|
||||||
import { throwHTTPErr } from 'src/utils';
|
|
||||||
|
|
||||||
@UseGuards(ThrottlerBehindProxyGuard)
|
|
||||||
@Controller({ path: 'site', version: '1' })
|
|
||||||
export class SiteController {
|
|
||||||
constructor(private infraConfigService: InfraConfigService) {}
|
|
||||||
|
|
||||||
@Get('setup')
|
|
||||||
@UseGuards(JwtAuthGuard, RESTAdminGuard)
|
|
||||||
async fetchSetupInfo() {
|
|
||||||
const status = await this.infraConfigService.get(
|
|
||||||
InfraConfigEnum.IS_FIRST_TIME_INFRA_SETUP,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (E.isLeft(status))
|
|
||||||
throwHTTPErr(<RESTError>{
|
|
||||||
message: status.left,
|
|
||||||
statusCode: HttpStatus.NOT_FOUND,
|
|
||||||
});
|
|
||||||
return status.right;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Put('setup')
|
|
||||||
@UseGuards(JwtAuthGuard, RESTAdminGuard)
|
|
||||||
async setSetupAsComplete() {
|
|
||||||
const res = await this.infraConfigService.update(
|
|
||||||
InfraConfigEnum.IS_FIRST_TIME_INFRA_SETUP,
|
|
||||||
false.toString(),
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (E.isLeft(res))
|
|
||||||
throwHTTPErr(<RESTError>{
|
|
||||||
message: res.left,
|
|
||||||
statusCode: HttpStatus.FORBIDDEN,
|
|
||||||
});
|
|
||||||
return res.right;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Field, ObjectType, registerEnumType } from '@nestjs/graphql';
|
import { Field, ObjectType, registerEnumType } from '@nestjs/graphql';
|
||||||
import { AuthProvider } from 'src/auth/helper';
|
import { AuthProvider } from 'src/auth/helper';
|
||||||
import { InfraConfigEnum } from 'src/types/InfraConfig';
|
import { InfraConfigEnumForClient } from 'src/types/InfraConfig';
|
||||||
import { ServiceStatus } from './helper';
|
import { ServiceStatus } from './helper';
|
||||||
|
|
||||||
@ObjectType()
|
@ObjectType()
|
||||||
@@ -8,7 +8,7 @@ export class InfraConfig {
|
|||||||
@Field({
|
@Field({
|
||||||
description: 'Infra Config Name',
|
description: 'Infra Config Name',
|
||||||
})
|
})
|
||||||
name: InfraConfigEnum;
|
name: InfraConfigEnumForClient;
|
||||||
|
|
||||||
@Field({
|
@Field({
|
||||||
description: 'Infra Config Value',
|
description: 'Infra Config Value',
|
||||||
@@ -16,7 +16,7 @@ export class InfraConfig {
|
|||||||
value: string;
|
value: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
registerEnumType(InfraConfigEnum, {
|
registerEnumType(InfraConfigEnumForClient, {
|
||||||
name: 'InfraConfigEnum',
|
name: 'InfraConfigEnum',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
import { InfraConfigService } from './infra-config.service';
|
import { InfraConfigService } from './infra-config.service';
|
||||||
import { PrismaModule } from 'src/prisma/prisma.module';
|
import { PrismaModule } from 'src/prisma/prisma.module';
|
||||||
import { SiteController } from './infra-config.controller';
|
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [PrismaModule],
|
imports: [PrismaModule],
|
||||||
providers: [InfraConfigService],
|
providers: [InfraConfigService],
|
||||||
exports: [InfraConfigService],
|
exports: [InfraConfigService],
|
||||||
controllers: [SiteController],
|
|
||||||
})
|
})
|
||||||
export class InfraConfigModule {}
|
export class InfraConfigModule {}
|
||||||
|
|||||||
@@ -1,16 +1,13 @@
|
|||||||
import { mockDeep, mockReset } from 'jest-mock-extended';
|
import { mockDeep, mockReset } from 'jest-mock-extended';
|
||||||
import { PrismaService } from 'src/prisma/prisma.service';
|
import { PrismaService } from 'src/prisma/prisma.service';
|
||||||
import { InfraConfigService } from './infra-config.service';
|
import { InfraConfigService } from './infra-config.service';
|
||||||
import { InfraConfigEnum } from 'src/types/InfraConfig';
|
|
||||||
import {
|
import {
|
||||||
INFRA_CONFIG_NOT_FOUND,
|
InfraConfigEnum,
|
||||||
INFRA_CONFIG_OPERATION_NOT_ALLOWED,
|
InfraConfigEnumForClient,
|
||||||
INFRA_CONFIG_UPDATE_FAILED,
|
} from 'src/types/InfraConfig';
|
||||||
} from 'src/errors';
|
import { INFRA_CONFIG_NOT_FOUND, INFRA_CONFIG_UPDATE_FAILED } from 'src/errors';
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
import * as helper from './helper';
|
import * as helper from './helper';
|
||||||
import { InfraConfig as dbInfraConfig } from '@prisma/client';
|
|
||||||
import { InfraConfig } from './infra-config.model';
|
|
||||||
|
|
||||||
const mockPrisma = mockDeep<PrismaService>();
|
const mockPrisma = mockDeep<PrismaService>();
|
||||||
const mockConfigService = mockDeep<ConfigService>();
|
const mockConfigService = mockDeep<ConfigService>();
|
||||||
@@ -22,82 +19,12 @@ const infraConfigService = new InfraConfigService(
|
|||||||
mockConfigService,
|
mockConfigService,
|
||||||
);
|
);
|
||||||
|
|
||||||
const INITIALIZED_DATE_CONST = new Date();
|
|
||||||
const dbInfraConfigs: dbInfraConfig[] = [
|
|
||||||
{
|
|
||||||
id: '3',
|
|
||||||
name: InfraConfigEnum.GOOGLE_CLIENT_ID,
|
|
||||||
value: 'abcdefghijkl',
|
|
||||||
active: true,
|
|
||||||
createdOn: INITIALIZED_DATE_CONST,
|
|
||||||
updatedOn: INITIALIZED_DATE_CONST,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '4',
|
|
||||||
name: InfraConfigEnum.VITE_ALLOWED_AUTH_PROVIDERS,
|
|
||||||
value: 'google',
|
|
||||||
active: true,
|
|
||||||
createdOn: INITIALIZED_DATE_CONST,
|
|
||||||
updatedOn: INITIALIZED_DATE_CONST,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
const infraConfigs: InfraConfig[] = [
|
|
||||||
{
|
|
||||||
name: dbInfraConfigs[0].name as InfraConfigEnum,
|
|
||||||
value: dbInfraConfigs[0].value,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: dbInfraConfigs[1].name as InfraConfigEnum,
|
|
||||||
value: dbInfraConfigs[1].value,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mockReset(mockPrisma);
|
mockReset(mockPrisma);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('InfraConfigService', () => {
|
describe('InfraConfigService', () => {
|
||||||
describe('update', () => {
|
describe('update', () => {
|
||||||
it('should update the infra config without backend server restart', async () => {
|
|
||||||
const name = InfraConfigEnum.GOOGLE_CLIENT_ID;
|
|
||||||
const value = 'true';
|
|
||||||
|
|
||||||
mockPrisma.infraConfig.update.mockResolvedValueOnce({
|
|
||||||
id: '',
|
|
||||||
name,
|
|
||||||
value,
|
|
||||||
active: true,
|
|
||||||
createdOn: new Date(),
|
|
||||||
updatedOn: new Date(),
|
|
||||||
});
|
|
||||||
|
|
||||||
jest.spyOn(helper, 'stopApp').mockReturnValueOnce();
|
|
||||||
const result = await infraConfigService.update(name, value);
|
|
||||||
|
|
||||||
expect(helper.stopApp).not.toHaveBeenCalled();
|
|
||||||
expect(result).toEqualRight({ name, value });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should update the infra config with backend server restart', async () => {
|
|
||||||
const name = InfraConfigEnum.GOOGLE_CLIENT_ID;
|
|
||||||
const value = 'true';
|
|
||||||
|
|
||||||
mockPrisma.infraConfig.update.mockResolvedValueOnce({
|
|
||||||
id: '',
|
|
||||||
name,
|
|
||||||
value,
|
|
||||||
active: true,
|
|
||||||
createdOn: new Date(),
|
|
||||||
updatedOn: new Date(),
|
|
||||||
});
|
|
||||||
jest.spyOn(helper, 'stopApp').mockReturnValueOnce();
|
|
||||||
|
|
||||||
const result = await infraConfigService.update(name, value, true);
|
|
||||||
|
|
||||||
expect(helper.stopApp).toHaveBeenCalledTimes(1);
|
|
||||||
expect(result).toEqualRight({ name, value });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should update the infra config', async () => {
|
it('should update the infra config', async () => {
|
||||||
const name = InfraConfigEnum.GOOGLE_CLIENT_ID;
|
const name = InfraConfigEnum.GOOGLE_CLIENT_ID;
|
||||||
const value = 'true';
|
const value = 'true';
|
||||||
@@ -144,7 +71,7 @@ describe('InfraConfigService', () => {
|
|||||||
|
|
||||||
describe('get', () => {
|
describe('get', () => {
|
||||||
it('should get the infra config', async () => {
|
it('should get the infra config', async () => {
|
||||||
const name = InfraConfigEnum.GOOGLE_CLIENT_ID;
|
const name = InfraConfigEnumForClient.GOOGLE_CLIENT_ID;
|
||||||
const value = 'true';
|
const value = 'true';
|
||||||
|
|
||||||
mockPrisma.infraConfig.findUniqueOrThrow.mockResolvedValueOnce({
|
mockPrisma.infraConfig.findUniqueOrThrow.mockResolvedValueOnce({
|
||||||
@@ -160,7 +87,7 @@ describe('InfraConfigService', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should pass correct params to prisma findUnique', async () => {
|
it('should pass correct params to prisma findUnique', async () => {
|
||||||
const name = InfraConfigEnum.GOOGLE_CLIENT_ID;
|
const name = InfraConfigEnumForClient.GOOGLE_CLIENT_ID;
|
||||||
|
|
||||||
await infraConfigService.get(name);
|
await infraConfigService.get(name);
|
||||||
|
|
||||||
@@ -171,7 +98,7 @@ describe('InfraConfigService', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should throw an error if the infra config does not exist', async () => {
|
it('should throw an error if the infra config does not exist', async () => {
|
||||||
const name = InfraConfigEnum.GOOGLE_CLIENT_ID;
|
const name = InfraConfigEnumForClient.GOOGLE_CLIENT_ID;
|
||||||
|
|
||||||
mockPrisma.infraConfig.findUniqueOrThrow.mockRejectedValueOnce('null');
|
mockPrisma.infraConfig.findUniqueOrThrow.mockRejectedValueOnce('null');
|
||||||
|
|
||||||
@@ -179,45 +106,4 @@ describe('InfraConfigService', () => {
|
|||||||
expect(result).toEqualLeft(INFRA_CONFIG_NOT_FOUND);
|
expect(result).toEqualLeft(INFRA_CONFIG_NOT_FOUND);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getMany', () => {
|
|
||||||
it('should throw error if any disallowed names are provided', async () => {
|
|
||||||
const disallowedNames = [InfraConfigEnum.VITE_ALLOWED_AUTH_PROVIDERS];
|
|
||||||
const result = await infraConfigService.getMany(disallowedNames);
|
|
||||||
|
|
||||||
expect(result).toEqualLeft(INFRA_CONFIG_OPERATION_NOT_ALLOWED);
|
|
||||||
});
|
|
||||||
it('should resolve right with disallowed names if `checkDisallowed` parameter passed', async () => {
|
|
||||||
const disallowedNames = [InfraConfigEnum.VITE_ALLOWED_AUTH_PROVIDERS];
|
|
||||||
|
|
||||||
const dbInfraConfigResponses = dbInfraConfigs.filter((dbConfig) =>
|
|
||||||
disallowedNames.includes(dbConfig.name as InfraConfigEnum),
|
|
||||||
);
|
|
||||||
mockPrisma.infraConfig.findMany.mockResolvedValueOnce(
|
|
||||||
dbInfraConfigResponses,
|
|
||||||
);
|
|
||||||
|
|
||||||
const result = await infraConfigService.getMany(disallowedNames, false);
|
|
||||||
|
|
||||||
expect(result).toEqualRight(
|
|
||||||
infraConfigs.filter((i) => disallowedNames.includes(i.name)),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return right with infraConfigs if Prisma query succeeds', async () => {
|
|
||||||
const allowedNames = [InfraConfigEnum.GOOGLE_CLIENT_ID];
|
|
||||||
|
|
||||||
const dbInfraConfigResponses = dbInfraConfigs.filter((dbConfig) =>
|
|
||||||
allowedNames.includes(dbConfig.name as InfraConfigEnum),
|
|
||||||
);
|
|
||||||
mockPrisma.infraConfig.findMany.mockResolvedValueOnce(
|
|
||||||
dbInfraConfigResponses,
|
|
||||||
);
|
|
||||||
|
|
||||||
const result = await infraConfigService.getMany(allowedNames);
|
|
||||||
expect(result).toEqualRight(
|
|
||||||
infraConfigs.filter((i) => allowedNames.includes(i.name)),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,30 +3,23 @@ import { InfraConfig } from './infra-config.model';
|
|||||||
import { PrismaService } from 'src/prisma/prisma.service';
|
import { PrismaService } from 'src/prisma/prisma.service';
|
||||||
import { InfraConfig as DBInfraConfig } from '@prisma/client';
|
import { InfraConfig as DBInfraConfig } from '@prisma/client';
|
||||||
import * as E from 'fp-ts/Either';
|
import * as E from 'fp-ts/Either';
|
||||||
import { InfraConfigEnum } from 'src/types/InfraConfig';
|
import {
|
||||||
|
InfraConfigEnum,
|
||||||
|
InfraConfigEnumForClient,
|
||||||
|
} from 'src/types/InfraConfig';
|
||||||
import {
|
import {
|
||||||
AUTH_PROVIDER_NOT_SPECIFIED,
|
AUTH_PROVIDER_NOT_SPECIFIED,
|
||||||
DATABASE_TABLE_NOT_EXIST,
|
DATABASE_TABLE_NOT_EXIST,
|
||||||
INFRA_CONFIG_INVALID_INPUT,
|
INFRA_CONFIG_INVALID_INPUT,
|
||||||
INFRA_CONFIG_NOT_FOUND,
|
INFRA_CONFIG_NOT_FOUND,
|
||||||
|
INFRA_CONFIG_NOT_LISTED,
|
||||||
INFRA_CONFIG_RESET_FAILED,
|
INFRA_CONFIG_RESET_FAILED,
|
||||||
INFRA_CONFIG_UPDATE_FAILED,
|
INFRA_CONFIG_UPDATE_FAILED,
|
||||||
INFRA_CONFIG_SERVICE_NOT_CONFIGURED,
|
INFRA_CONFIG_SERVICE_NOT_CONFIGURED,
|
||||||
INFRA_CONFIG_OPERATION_NOT_ALLOWED,
|
|
||||||
} from 'src/errors';
|
} from 'src/errors';
|
||||||
import {
|
import { throwErr, validateSMTPEmail, validateSMTPUrl } from 'src/utils';
|
||||||
throwErr,
|
|
||||||
validateSMTPEmail,
|
|
||||||
validateSMTPUrl,
|
|
||||||
validateUrl,
|
|
||||||
} from 'src/utils';
|
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
import {
|
import { ServiceStatus, getConfiguredSSOProviders, stopApp } from './helper';
|
||||||
ServiceStatus,
|
|
||||||
getDefaultInfraConfigs,
|
|
||||||
getMissingInfraConfigEntries,
|
|
||||||
stopApp,
|
|
||||||
} from './helper';
|
|
||||||
import { EnableAndDisableSSOArgs, InfraConfigArgs } from './input-args';
|
import { EnableAndDisableSSOArgs, InfraConfigArgs } from './input-args';
|
||||||
import { AuthProvider } from 'src/auth/helper';
|
import { AuthProvider } from 'src/auth/helper';
|
||||||
|
|
||||||
@@ -37,31 +30,76 @@ export class InfraConfigService implements OnModuleInit {
|
|||||||
private readonly configService: ConfigService,
|
private readonly configService: ConfigService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
// Following fields are not updatable by `infraConfigs` Mutation. Use dedicated mutations for these fields instead.
|
|
||||||
EXCLUDE_FROM_UPDATE_CONFIGS = [
|
|
||||||
InfraConfigEnum.VITE_ALLOWED_AUTH_PROVIDERS,
|
|
||||||
InfraConfigEnum.ALLOW_ANALYTICS_COLLECTION,
|
|
||||||
InfraConfigEnum.ANALYTICS_USER_ID,
|
|
||||||
InfraConfigEnum.IS_FIRST_TIME_INFRA_SETUP,
|
|
||||||
];
|
|
||||||
// Following fields can not be fetched by `infraConfigs` Query. Use dedicated queries for these fields instead.
|
|
||||||
EXCLUDE_FROM_FETCH_CONFIGS = [
|
|
||||||
InfraConfigEnum.VITE_ALLOWED_AUTH_PROVIDERS,
|
|
||||||
InfraConfigEnum.ANALYTICS_USER_ID,
|
|
||||||
InfraConfigEnum.IS_FIRST_TIME_INFRA_SETUP,
|
|
||||||
];
|
|
||||||
|
|
||||||
async onModuleInit() {
|
async onModuleInit() {
|
||||||
await this.initializeInfraConfigTable();
|
await this.initializeInfraConfigTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getDefaultInfraConfigs(): { name: InfraConfigEnum; value: string }[] {
|
||||||
|
// Prepare rows for 'infra_config' table with default values (from .env) for each 'name'
|
||||||
|
const infraConfigDefaultObjs: { name: InfraConfigEnum; value: string }[] = [
|
||||||
|
{
|
||||||
|
name: InfraConfigEnum.MAILER_SMTP_URL,
|
||||||
|
value: process.env.MAILER_SMTP_URL,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: InfraConfigEnum.MAILER_ADDRESS_FROM,
|
||||||
|
value: process.env.MAILER_ADDRESS_FROM,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: InfraConfigEnum.GOOGLE_CLIENT_ID,
|
||||||
|
value: process.env.GOOGLE_CLIENT_ID,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: InfraConfigEnum.GOOGLE_CLIENT_SECRET,
|
||||||
|
value: process.env.GOOGLE_CLIENT_SECRET,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: InfraConfigEnum.GITHUB_CLIENT_ID,
|
||||||
|
value: process.env.GITHUB_CLIENT_ID,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: InfraConfigEnum.GITHUB_CLIENT_SECRET,
|
||||||
|
value: process.env.GITHUB_CLIENT_SECRET,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: InfraConfigEnum.MICROSOFT_CLIENT_ID,
|
||||||
|
value: process.env.MICROSOFT_CLIENT_ID,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: InfraConfigEnum.MICROSOFT_CLIENT_SECRET,
|
||||||
|
value: process.env.MICROSOFT_CLIENT_SECRET,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: InfraConfigEnum.VITE_ALLOWED_AUTH_PROVIDERS,
|
||||||
|
value: getConfiguredSSOProviders(),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return infraConfigDefaultObjs;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the 'infra_config' table with values from .env
|
* Initialize the 'infra_config' table with values from .env
|
||||||
* @description This function create rows 'infra_config' in very first time (only once)
|
* @description This function create rows 'infra_config' in very first time (only once)
|
||||||
*/
|
*/
|
||||||
async initializeInfraConfigTable() {
|
async initializeInfraConfigTable() {
|
||||||
try {
|
try {
|
||||||
const propsToInsert = await getMissingInfraConfigEntries();
|
// Get all the 'names' of the properties to be saved in the 'infra_config' table
|
||||||
|
const enumValues = Object.values(InfraConfigEnum);
|
||||||
|
|
||||||
|
// Fetch the default values (value in .env) for configs to be saved in 'infra_config' table
|
||||||
|
const infraConfigDefaultObjs = this.getDefaultInfraConfigs();
|
||||||
|
|
||||||
|
// Check if all the 'names' are listed in the default values
|
||||||
|
if (enumValues.length !== infraConfigDefaultObjs.length) {
|
||||||
|
throw new Error(INFRA_CONFIG_NOT_LISTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Eliminate the rows (from 'infraConfigDefaultObjs') that are already present in the database table
|
||||||
|
const dbInfraConfigs = await this.prisma.infraConfig.findMany();
|
||||||
|
const propsToInsert = infraConfigDefaultObjs.filter(
|
||||||
|
(p) => !dbInfraConfigs.find((e) => e.name === p.name),
|
||||||
|
);
|
||||||
|
|
||||||
if (propsToInsert.length > 0) {
|
if (propsToInsert.length > 0) {
|
||||||
await this.prisma.infraConfig.createMany({ data: propsToInsert });
|
await this.prisma.infraConfig.createMany({ data: propsToInsert });
|
||||||
@@ -109,10 +147,12 @@ export class InfraConfigService implements OnModuleInit {
|
|||||||
* Update InfraConfig by name
|
* Update InfraConfig by name
|
||||||
* @param name Name of the InfraConfig
|
* @param name Name of the InfraConfig
|
||||||
* @param value Value of the InfraConfig
|
* @param value Value of the InfraConfig
|
||||||
* @param restartEnabled If true, restart the app after updating the InfraConfig
|
|
||||||
* @returns InfraConfig model
|
* @returns InfraConfig model
|
||||||
*/
|
*/
|
||||||
async update(name: InfraConfigEnum, value: string, restartEnabled = false) {
|
async update(
|
||||||
|
name: InfraConfigEnumForClient | InfraConfigEnum,
|
||||||
|
value: string,
|
||||||
|
) {
|
||||||
const isValidate = this.validateEnvValues([{ name, value }]);
|
const isValidate = this.validateEnvValues([{ name, value }]);
|
||||||
if (E.isLeft(isValidate)) return E.left(isValidate.left);
|
if (E.isLeft(isValidate)) return E.left(isValidate.left);
|
||||||
|
|
||||||
@@ -122,7 +162,7 @@ export class InfraConfigService implements OnModuleInit {
|
|||||||
data: { value },
|
data: { value },
|
||||||
});
|
});
|
||||||
|
|
||||||
if (restartEnabled) stopApp();
|
stopApp();
|
||||||
|
|
||||||
return E.right(this.cast(infraConfig));
|
return E.right(this.cast(infraConfig));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -136,11 +176,6 @@ export class InfraConfigService implements OnModuleInit {
|
|||||||
* @returns InfraConfig model
|
* @returns InfraConfig model
|
||||||
*/
|
*/
|
||||||
async updateMany(infraConfigs: InfraConfigArgs[]) {
|
async updateMany(infraConfigs: InfraConfigArgs[]) {
|
||||||
for (let i = 0; i < infraConfigs.length; i++) {
|
|
||||||
if (this.EXCLUDE_FROM_UPDATE_CONFIGS.includes(infraConfigs[i].name))
|
|
||||||
return E.left(INFRA_CONFIG_OPERATION_NOT_ALLOWED);
|
|
||||||
}
|
|
||||||
|
|
||||||
const isValidate = this.validateEnvValues(infraConfigs);
|
const isValidate = this.validateEnvValues(infraConfigs);
|
||||||
if (E.isLeft(isValidate)) return E.left(isValidate.left);
|
if (E.isLeft(isValidate)) return E.left(isValidate.left);
|
||||||
|
|
||||||
@@ -174,26 +209,12 @@ export class InfraConfigService implements OnModuleInit {
|
|||||||
) {
|
) {
|
||||||
switch (service) {
|
switch (service) {
|
||||||
case AuthProvider.GOOGLE:
|
case AuthProvider.GOOGLE:
|
||||||
return (
|
return configMap.GOOGLE_CLIENT_ID && configMap.GOOGLE_CLIENT_SECRET;
|
||||||
configMap.GOOGLE_CLIENT_ID &&
|
|
||||||
configMap.GOOGLE_CLIENT_SECRET &&
|
|
||||||
configMap.GOOGLE_CALLBACK_URL &&
|
|
||||||
configMap.GOOGLE_SCOPE
|
|
||||||
);
|
|
||||||
case AuthProvider.GITHUB:
|
case AuthProvider.GITHUB:
|
||||||
return (
|
return configMap.GITHUB_CLIENT_ID && configMap.GITHUB_CLIENT_SECRET;
|
||||||
configMap.GITHUB_CLIENT_ID &&
|
|
||||||
configMap.GITHUB_CLIENT_SECRET &&
|
|
||||||
configMap.GITHUB_CALLBACK_URL &&
|
|
||||||
configMap.GITHUB_SCOPE
|
|
||||||
);
|
|
||||||
case AuthProvider.MICROSOFT:
|
case AuthProvider.MICROSOFT:
|
||||||
return (
|
return (
|
||||||
configMap.MICROSOFT_CLIENT_ID &&
|
configMap.MICROSOFT_CLIENT_ID && configMap.MICROSOFT_CLIENT_SECRET
|
||||||
configMap.MICROSOFT_CLIENT_SECRET &&
|
|
||||||
configMap.MICROSOFT_CALLBACK_URL &&
|
|
||||||
configMap.MICROSOFT_SCOPE &&
|
|
||||||
configMap.MICROSOFT_TENANT
|
|
||||||
);
|
);
|
||||||
case AuthProvider.EMAIL:
|
case AuthProvider.EMAIL:
|
||||||
return configMap.MAILER_SMTP_URL && configMap.MAILER_ADDRESS_FROM;
|
return configMap.MAILER_SMTP_URL && configMap.MAILER_ADDRESS_FROM;
|
||||||
@@ -202,22 +223,6 @@ export class InfraConfigService implements OnModuleInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Enable or Disable Analytics Collection
|
|
||||||
*
|
|
||||||
* @param status Status to enable or disable
|
|
||||||
* @returns Boolean of status of analytics collection
|
|
||||||
*/
|
|
||||||
async toggleAnalyticsCollection(status: ServiceStatus) {
|
|
||||||
const isUpdated = await this.update(
|
|
||||||
InfraConfigEnum.ALLOW_ANALYTICS_COLLECTION,
|
|
||||||
status === ServiceStatus.ENABLE ? 'true' : 'false',
|
|
||||||
);
|
|
||||||
|
|
||||||
if (E.isLeft(isUpdated)) return E.left(isUpdated.left);
|
|
||||||
return E.right(isUpdated.right.value === 'true');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enable or Disable SSO for login/signup
|
* Enable or Disable SSO for login/signup
|
||||||
* @param provider Auth Provider to enable or disable
|
* @param provider Auth Provider to enable or disable
|
||||||
@@ -256,7 +261,6 @@ export class InfraConfigService implements OnModuleInit {
|
|||||||
const isUpdated = await this.update(
|
const isUpdated = await this.update(
|
||||||
InfraConfigEnum.VITE_ALLOWED_AUTH_PROVIDERS,
|
InfraConfigEnum.VITE_ALLOWED_AUTH_PROVIDERS,
|
||||||
updatedAuthProviders.join(','),
|
updatedAuthProviders.join(','),
|
||||||
true,
|
|
||||||
);
|
);
|
||||||
if (E.isLeft(isUpdated)) return E.left(isUpdated.left);
|
if (E.isLeft(isUpdated)) return E.left(isUpdated.left);
|
||||||
|
|
||||||
@@ -268,7 +272,7 @@ export class InfraConfigService implements OnModuleInit {
|
|||||||
* @param name Name of the InfraConfig
|
* @param name Name of the InfraConfig
|
||||||
* @returns InfraConfig model
|
* @returns InfraConfig model
|
||||||
*/
|
*/
|
||||||
async get(name: InfraConfigEnum) {
|
async get(name: InfraConfigEnumForClient) {
|
||||||
try {
|
try {
|
||||||
const infraConfig = await this.prisma.infraConfig.findUniqueOrThrow({
|
const infraConfig = await this.prisma.infraConfig.findUniqueOrThrow({
|
||||||
where: { name },
|
where: { name },
|
||||||
@@ -283,18 +287,9 @@ export class InfraConfigService implements OnModuleInit {
|
|||||||
/**
|
/**
|
||||||
* Get InfraConfigs by names
|
* Get InfraConfigs by names
|
||||||
* @param names Names of the InfraConfigs
|
* @param names Names of the InfraConfigs
|
||||||
* @param checkDisallowedKeys If true, check if the names are allowed to fetch by client
|
|
||||||
* @returns InfraConfig model
|
* @returns InfraConfig model
|
||||||
*/
|
*/
|
||||||
async getMany(names: InfraConfigEnum[], checkDisallowedKeys: boolean = true) {
|
async getMany(names: InfraConfigEnumForClient[]) {
|
||||||
if (checkDisallowedKeys) {
|
|
||||||
// Check if the names are allowed to fetch by client
|
|
||||||
for (let i = 0; i < names.length; i++) {
|
|
||||||
if (this.EXCLUDE_FROM_FETCH_CONFIGS.includes(names[i]))
|
|
||||||
return E.left(INFRA_CONFIG_OPERATION_NOT_ALLOWED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const infraConfigs = await this.prisma.infraConfig.findMany({
|
const infraConfigs = await this.prisma.infraConfig.findMany({
|
||||||
where: { name: { in: names } },
|
where: { name: { in: names } },
|
||||||
@@ -320,28 +315,14 @@ export class InfraConfigService implements OnModuleInit {
|
|||||||
* Reset all the InfraConfigs to their default values (from .env)
|
* Reset all the InfraConfigs to their default values (from .env)
|
||||||
*/
|
*/
|
||||||
async reset() {
|
async reset() {
|
||||||
// These are all the infra-configs that should not be reset
|
|
||||||
const RESET_EXCLUSION_LIST = [
|
|
||||||
InfraConfigEnum.IS_FIRST_TIME_INFRA_SETUP,
|
|
||||||
InfraConfigEnum.ANALYTICS_USER_ID,
|
|
||||||
InfraConfigEnum.ALLOW_ANALYTICS_COLLECTION,
|
|
||||||
];
|
|
||||||
try {
|
try {
|
||||||
const infraConfigDefaultObjs = await getDefaultInfraConfigs();
|
const infraConfigDefaultObjs = this.getDefaultInfraConfigs();
|
||||||
const updatedInfraConfigDefaultObjs = infraConfigDefaultObjs.filter(
|
|
||||||
(p) => RESET_EXCLUSION_LIST.includes(p.name) === false,
|
|
||||||
);
|
|
||||||
|
|
||||||
await this.prisma.infraConfig.deleteMany({
|
await this.prisma.infraConfig.deleteMany({
|
||||||
where: {
|
where: { name: { in: infraConfigDefaultObjs.map((p) => p.name) } },
|
||||||
name: {
|
|
||||||
in: updatedInfraConfigDefaultObjs.map((p) => p.name),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
await this.prisma.infraConfig.createMany({
|
await this.prisma.infraConfig.createMany({
|
||||||
data: updatedInfraConfigDefaultObjs,
|
data: infraConfigDefaultObjs,
|
||||||
});
|
});
|
||||||
|
|
||||||
stopApp();
|
stopApp();
|
||||||
@@ -357,60 +338,36 @@ export class InfraConfigService implements OnModuleInit {
|
|||||||
*/
|
*/
|
||||||
validateEnvValues(
|
validateEnvValues(
|
||||||
infraConfigs: {
|
infraConfigs: {
|
||||||
name: InfraConfigEnum;
|
name: InfraConfigEnumForClient | InfraConfigEnum;
|
||||||
value: string;
|
value: string;
|
||||||
}[],
|
}[],
|
||||||
) {
|
) {
|
||||||
for (let i = 0; i < infraConfigs.length; i++) {
|
for (let i = 0; i < infraConfigs.length; i++) {
|
||||||
switch (infraConfigs[i].name) {
|
switch (infraConfigs[i].name) {
|
||||||
case InfraConfigEnum.MAILER_SMTP_URL:
|
case InfraConfigEnumForClient.MAILER_SMTP_URL:
|
||||||
const isValidUrl = validateSMTPUrl(infraConfigs[i].value);
|
const isValidUrl = validateSMTPUrl(infraConfigs[i].value);
|
||||||
if (!isValidUrl) return E.left(INFRA_CONFIG_INVALID_INPUT);
|
if (!isValidUrl) return E.left(INFRA_CONFIG_INVALID_INPUT);
|
||||||
break;
|
break;
|
||||||
case InfraConfigEnum.MAILER_ADDRESS_FROM:
|
case InfraConfigEnumForClient.MAILER_ADDRESS_FROM:
|
||||||
const isValidEmail = validateSMTPEmail(infraConfigs[i].value);
|
const isValidEmail = validateSMTPEmail(infraConfigs[i].value);
|
||||||
if (!isValidEmail) return E.left(INFRA_CONFIG_INVALID_INPUT);
|
if (!isValidEmail) return E.left(INFRA_CONFIG_INVALID_INPUT);
|
||||||
break;
|
break;
|
||||||
case InfraConfigEnum.GOOGLE_CLIENT_ID:
|
case InfraConfigEnumForClient.GOOGLE_CLIENT_ID:
|
||||||
if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT);
|
if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT);
|
||||||
break;
|
break;
|
||||||
case InfraConfigEnum.GOOGLE_CLIENT_SECRET:
|
case InfraConfigEnumForClient.GOOGLE_CLIENT_SECRET:
|
||||||
if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT);
|
if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT);
|
||||||
break;
|
break;
|
||||||
case InfraConfigEnum.GOOGLE_CALLBACK_URL:
|
case InfraConfigEnumForClient.GITHUB_CLIENT_ID:
|
||||||
if (!validateUrl(infraConfigs[i].value))
|
|
||||||
return E.left(INFRA_CONFIG_INVALID_INPUT);
|
|
||||||
break;
|
|
||||||
case InfraConfigEnum.GOOGLE_SCOPE:
|
|
||||||
if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT);
|
if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT);
|
||||||
break;
|
break;
|
||||||
case InfraConfigEnum.GITHUB_CLIENT_ID:
|
case InfraConfigEnumForClient.GITHUB_CLIENT_SECRET:
|
||||||
if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT);
|
if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT);
|
||||||
break;
|
break;
|
||||||
case InfraConfigEnum.GITHUB_CLIENT_SECRET:
|
case InfraConfigEnumForClient.MICROSOFT_CLIENT_ID:
|
||||||
if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT);
|
if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT);
|
||||||
break;
|
break;
|
||||||
case InfraConfigEnum.GITHUB_CALLBACK_URL:
|
case InfraConfigEnumForClient.MICROSOFT_CLIENT_SECRET:
|
||||||
if (!validateUrl(infraConfigs[i].value))
|
|
||||||
return E.left(INFRA_CONFIG_INVALID_INPUT);
|
|
||||||
break;
|
|
||||||
case InfraConfigEnum.GITHUB_SCOPE:
|
|
||||||
if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT);
|
|
||||||
break;
|
|
||||||
case InfraConfigEnum.MICROSOFT_CLIENT_ID:
|
|
||||||
if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT);
|
|
||||||
break;
|
|
||||||
case InfraConfigEnum.MICROSOFT_CLIENT_SECRET:
|
|
||||||
if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT);
|
|
||||||
break;
|
|
||||||
case InfraConfigEnum.MICROSOFT_CALLBACK_URL:
|
|
||||||
if (!validateUrl(infraConfigs[i].value))
|
|
||||||
return E.left(INFRA_CONFIG_INVALID_INPUT);
|
|
||||||
break;
|
|
||||||
case InfraConfigEnum.MICROSOFT_SCOPE:
|
|
||||||
if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT);
|
|
||||||
break;
|
|
||||||
case InfraConfigEnum.MICROSOFT_TENANT:
|
|
||||||
if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT);
|
if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import { Field, InputType } from '@nestjs/graphql';
|
import { Field, InputType } from '@nestjs/graphql';
|
||||||
import { InfraConfigEnum } from 'src/types/InfraConfig';
|
import { InfraConfigEnumForClient } from 'src/types/InfraConfig';
|
||||||
import { ServiceStatus } from './helper';
|
import { ServiceStatus } from './helper';
|
||||||
import { AuthProvider } from 'src/auth/helper';
|
import { AuthProvider } from 'src/auth/helper';
|
||||||
|
|
||||||
@InputType()
|
@InputType()
|
||||||
export class InfraConfigArgs {
|
export class InfraConfigArgs {
|
||||||
@Field(() => InfraConfigEnum, {
|
@Field(() => InfraConfigEnumForClient, {
|
||||||
description: 'Infra Config Name',
|
description: 'Infra Config Name',
|
||||||
})
|
})
|
||||||
name: InfraConfigEnum;
|
name: InfraConfigEnumForClient;
|
||||||
|
|
||||||
@Field({
|
@Field({
|
||||||
description: 'Infra Config Value',
|
description: 'Infra Config Value',
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ export class MailerService {
|
|||||||
): string {
|
): string {
|
||||||
switch (mailDesc.template) {
|
switch (mailDesc.template) {
|
||||||
case 'team-invitation':
|
case 'team-invitation':
|
||||||
return `A user has invited you to join a team workspace in Hoppscotch`;
|
return `${mailDesc.variables.invitee} invited you to join ${mailDesc.variables.invite_team_name} in Hoppscotch`;
|
||||||
|
|
||||||
case 'user-invitation':
|
case 'user-invitation':
|
||||||
return 'Sign in to Hoppscotch';
|
return 'Sign in to Hoppscotch';
|
||||||
|
|||||||
@@ -27,12 +27,6 @@
|
|||||||
color: #3869D4;
|
color: #3869D4;
|
||||||
}
|
}
|
||||||
|
|
||||||
a.nohighlight {
|
|
||||||
color: inherit !important;
|
|
||||||
text-decoration: none !important;
|
|
||||||
cursor: default !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
a img {
|
a img {
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
@@ -464,7 +458,7 @@
|
|||||||
<td class="content-cell">
|
<td class="content-cell">
|
||||||
<div class="f-fallback">
|
<div class="f-fallback">
|
||||||
<h1>Hi there,</h1>
|
<h1>Hi there,</h1>
|
||||||
<p><a class="nohighlight" name="invitee" href="#">{{invitee}}</a> with <a class="nohighlight" name="invite_team_name" href="#">{{invite_team_name}}</a> has invited you to use Hoppscotch to collaborate with them. Click the button below to set up your account and get started:</p>
|
<p>{{invitee}} with {{invite_team_name}} has invited you to use Hoppscotch to collaborate with them. Click the button below to set up your account and get started:</p>
|
||||||
<!-- Action -->
|
<!-- Action -->
|
||||||
<table class="body-action" align="center" width="100%" cellpadding="0" cellspacing="0">
|
<table class="body-action" align="center" width="100%" cellpadding="0" cellspacing="0">
|
||||||
<tr>
|
<tr>
|
||||||
@@ -490,7 +484,7 @@
|
|||||||
Welcome aboard, <br />
|
Welcome aboard, <br />
|
||||||
Your friends at Hoppscotch
|
Your friends at Hoppscotch
|
||||||
</p>
|
</p>
|
||||||
<p><strong>P.S.</strong> If you don't associate with <a class="nohighlight" name="invitee" href="#">{{invitee}}</a> or <a class="nohighlight" name="invite_team_name" href="#">{{invite_team_name}}</a>, just ignore this email.</p>
|
<p><strong>P.S.</strong> If you don't associate with {{invitee}} or {{invite_team_name}}, just ignore this email.</p>
|
||||||
<!-- Sub copy -->
|
<!-- Sub copy -->
|
||||||
<table class="body-sub">
|
<table class="body-sub">
|
||||||
<tr>
|
<tr>
|
||||||
|
|||||||
@@ -27,12 +27,6 @@
|
|||||||
color: #3869D4;
|
color: #3869D4;
|
||||||
}
|
}
|
||||||
|
|
||||||
a.nohighlight {
|
|
||||||
color: inherit !important;
|
|
||||||
text-decoration: none !important;
|
|
||||||
cursor: default !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
a img {
|
a img {
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
import { Module } from '@nestjs/common';
|
|
||||||
import { PosthogService } from './posthog.service';
|
|
||||||
import { PrismaModule } from 'src/prisma/prisma.module';
|
|
||||||
|
|
||||||
@Module({
|
|
||||||
imports: [PrismaModule],
|
|
||||||
providers: [PosthogService],
|
|
||||||
})
|
|
||||||
export class PosthogModule {}
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
|
||||||
import { PostHog } from 'posthog-node';
|
|
||||||
import { Cron, CronExpression, SchedulerRegistry } from '@nestjs/schedule';
|
|
||||||
import { ConfigService } from '@nestjs/config';
|
|
||||||
import { PrismaService } from 'src/prisma/prisma.service';
|
|
||||||
import { CronJob } from 'cron';
|
|
||||||
import { POSTHOG_CLIENT_NOT_INITIALIZED } from 'src/errors';
|
|
||||||
import { throwErr } from 'src/utils';
|
|
||||||
@Injectable()
|
|
||||||
export class PosthogService {
|
|
||||||
private postHogClient: PostHog;
|
|
||||||
private POSTHOG_API_KEY = 'phc_9CipPajQC22mSkk2wxe2TXsUA0Ysyupe8dt5KQQELqx';
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private readonly configService: ConfigService,
|
|
||||||
private readonly prismaService: PrismaService,
|
|
||||||
private schedulerRegistry: SchedulerRegistry,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
async onModuleInit() {
|
|
||||||
if (this.configService.get('INFRA.ALLOW_ANALYTICS_COLLECTION') === 'true') {
|
|
||||||
console.log('Initializing PostHog');
|
|
||||||
this.postHogClient = new PostHog(this.POSTHOG_API_KEY, {
|
|
||||||
host: 'https://eu.posthog.com',
|
|
||||||
});
|
|
||||||
|
|
||||||
// Schedule the cron job only if analytics collection is allowed
|
|
||||||
this.scheduleCronJob();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private scheduleCronJob() {
|
|
||||||
const job = new CronJob(CronExpression.EVERY_WEEK, async () => {
|
|
||||||
await this.capture();
|
|
||||||
});
|
|
||||||
|
|
||||||
this.schedulerRegistry.addCronJob('captureAnalytics', job);
|
|
||||||
job.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
async capture() {
|
|
||||||
if (!this.postHogClient) {
|
|
||||||
throwErr(POSTHOG_CLIENT_NOT_INITIALIZED);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.postHogClient.capture({
|
|
||||||
distinctId: this.configService.get('INFRA.ANALYTICS_USER_ID'),
|
|
||||||
event: 'sh_instance',
|
|
||||||
properties: {
|
|
||||||
type: 'COMMUNITY',
|
|
||||||
total_user_count: await this.prismaService.user.count(),
|
|
||||||
total_workspace_count: await this.prismaService.team.count(),
|
|
||||||
version: this.configService.get('npm_package_version'),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
console.log('Sent event to PostHog');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
// Type of data returned from the query to obtain all search results
|
|
||||||
export type SearchQueryReturnType = {
|
|
||||||
id: string;
|
|
||||||
title: string;
|
|
||||||
type: 'collection' | 'request';
|
|
||||||
method?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Type of data returned from the query to obtain all parents
|
|
||||||
export type ParentTreeQueryReturnType = {
|
|
||||||
id: string;
|
|
||||||
parentID: string;
|
|
||||||
title: string;
|
|
||||||
};
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
import {
|
|
||||||
Controller,
|
|
||||||
Get,
|
|
||||||
HttpStatus,
|
|
||||||
Param,
|
|
||||||
Query,
|
|
||||||
UseGuards,
|
|
||||||
} from '@nestjs/common';
|
|
||||||
import { TeamCollectionService } from './team-collection.service';
|
|
||||||
import * as E from 'fp-ts/Either';
|
|
||||||
import { ThrottlerBehindProxyGuard } from 'src/guards/throttler-behind-proxy.guard';
|
|
||||||
import { JwtAuthGuard } from 'src/auth/guards/jwt-auth.guard';
|
|
||||||
import { RequiresTeamRole } from 'src/team/decorators/requires-team-role.decorator';
|
|
||||||
import { TeamMemberRole } from '@prisma/client';
|
|
||||||
import { RESTTeamMemberGuard } from 'src/team/guards/rest-team-member.guard';
|
|
||||||
import { throwHTTPErr } from 'src/utils';
|
|
||||||
import { RESTError } from 'src/types/RESTError';
|
|
||||||
import { INVALID_PARAMS } from 'src/errors';
|
|
||||||
|
|
||||||
@UseGuards(ThrottlerBehindProxyGuard)
|
|
||||||
@Controller({ path: 'team-collection', version: '1' })
|
|
||||||
export class TeamCollectionController {
|
|
||||||
constructor(private readonly teamCollectionService: TeamCollectionService) {}
|
|
||||||
|
|
||||||
@Get('search/:teamID')
|
|
||||||
@RequiresTeamRole(
|
|
||||||
TeamMemberRole.VIEWER,
|
|
||||||
TeamMemberRole.EDITOR,
|
|
||||||
TeamMemberRole.OWNER,
|
|
||||||
)
|
|
||||||
@UseGuards(JwtAuthGuard, RESTTeamMemberGuard)
|
|
||||||
async searchByTitle(
|
|
||||||
@Query('searchQuery') searchQuery: string,
|
|
||||||
@Param('teamID') teamID: string,
|
|
||||||
@Query('take') take: string,
|
|
||||||
@Query('skip') skip: string,
|
|
||||||
) {
|
|
||||||
if (!teamID || !searchQuery) {
|
|
||||||
return <RESTError>{
|
|
||||||
message: INVALID_PARAMS,
|
|
||||||
statusCode: HttpStatus.BAD_REQUEST,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const res = await this.teamCollectionService.searchByTitle(
|
|
||||||
searchQuery.trim(),
|
|
||||||
teamID,
|
|
||||||
parseInt(take),
|
|
||||||
parseInt(skip),
|
|
||||||
);
|
|
||||||
if (E.isLeft(res)) throwHTTPErr(res.left);
|
|
||||||
return res.right;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,7 +6,6 @@ import { GqlCollectionTeamMemberGuard } from './guards/gql-collection-team-membe
|
|||||||
import { TeamModule } from '../team/team.module';
|
import { TeamModule } from '../team/team.module';
|
||||||
import { UserModule } from '../user/user.module';
|
import { UserModule } from '../user/user.module';
|
||||||
import { PubSubModule } from '../pubsub/pubsub.module';
|
import { PubSubModule } from '../pubsub/pubsub.module';
|
||||||
import { TeamCollectionController } from './team-collection.controller';
|
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [PrismaModule, TeamModule, UserModule, PubSubModule],
|
imports: [PrismaModule, TeamModule, UserModule, PubSubModule],
|
||||||
@@ -16,6 +15,5 @@ import { TeamCollectionController } from './team-collection.controller';
|
|||||||
GqlCollectionTeamMemberGuard,
|
GqlCollectionTeamMemberGuard,
|
||||||
],
|
],
|
||||||
exports: [TeamCollectionService, GqlCollectionTeamMemberGuard],
|
exports: [TeamCollectionService, GqlCollectionTeamMemberGuard],
|
||||||
controllers: [TeamCollectionController],
|
|
||||||
})
|
})
|
||||||
export class TeamCollectionModule {}
|
export class TeamCollectionModule {}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { HttpStatus, Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { PrismaService } from '../prisma/prisma.service';
|
import { PrismaService } from '../prisma/prisma.service';
|
||||||
import { TeamCollection } from './team-collection.model';
|
import { TeamCollection } from './team-collection.model';
|
||||||
import {
|
import {
|
||||||
@@ -14,21 +14,14 @@ import {
|
|||||||
TEAM_COL_SAME_NEXT_COLL,
|
TEAM_COL_SAME_NEXT_COLL,
|
||||||
TEAM_COL_REORDERING_FAILED,
|
TEAM_COL_REORDERING_FAILED,
|
||||||
TEAM_COLL_DATA_INVALID,
|
TEAM_COLL_DATA_INVALID,
|
||||||
TEAM_REQ_SEARCH_FAILED,
|
|
||||||
TEAM_COL_SEARCH_FAILED,
|
|
||||||
TEAM_REQ_PARENT_TREE_GEN_FAILED,
|
|
||||||
TEAM_COLL_PARENT_TREE_GEN_FAILED,
|
|
||||||
} from '../errors';
|
} from '../errors';
|
||||||
import { PubSubService } from '../pubsub/pubsub.service';
|
import { PubSubService } from '../pubsub/pubsub.service';
|
||||||
import { escapeSqlLikeString, isValidLength } from 'src/utils';
|
import { isValidLength } from 'src/utils';
|
||||||
import * as E from 'fp-ts/Either';
|
import * as E from 'fp-ts/Either';
|
||||||
import * as O from 'fp-ts/Option';
|
import * as O from 'fp-ts/Option';
|
||||||
import { Prisma, TeamCollection as DBTeamCollection } from '@prisma/client';
|
import { Prisma, TeamCollection as DBTeamCollection } from '@prisma/client';
|
||||||
import { CollectionFolder } from 'src/types/CollectionFolder';
|
import { CollectionFolder } from 'src/types/CollectionFolder';
|
||||||
import { stringToJson } from 'src/utils';
|
import { stringToJson } from 'src/utils';
|
||||||
import { CollectionSearchNode } from 'src/types/CollectionSearchNode';
|
|
||||||
import { ParentTreeQueryReturnType, SearchQueryReturnType } from './helper';
|
|
||||||
import { RESTError } from 'src/types/RESTError';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class TeamCollectionService {
|
export class TeamCollectionService {
|
||||||
@@ -1063,285 +1056,4 @@ export class TeamCollectionService {
|
|||||||
return E.left(TEAM_COLL_NOT_FOUND);
|
return E.left(TEAM_COLL_NOT_FOUND);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Search for TeamCollections and TeamRequests by title
|
|
||||||
*
|
|
||||||
* @param searchQuery The search query
|
|
||||||
* @param teamID The Team ID
|
|
||||||
* @param take Number of items we want returned
|
|
||||||
* @param skip Number of items we want to skip
|
|
||||||
* @returns An Either of the search results
|
|
||||||
*/
|
|
||||||
async searchByTitle(
|
|
||||||
searchQuery: string,
|
|
||||||
teamID: string,
|
|
||||||
take = 10,
|
|
||||||
skip = 0,
|
|
||||||
) {
|
|
||||||
// Fetch all collections and requests that match the search query
|
|
||||||
const searchResults: SearchQueryReturnType[] = [];
|
|
||||||
|
|
||||||
const matchedCollections = await this.searchCollections(
|
|
||||||
searchQuery,
|
|
||||||
teamID,
|
|
||||||
take,
|
|
||||||
skip,
|
|
||||||
);
|
|
||||||
if (E.isLeft(matchedCollections))
|
|
||||||
return E.left(<RESTError>{
|
|
||||||
message: matchedCollections.left,
|
|
||||||
statusCode: HttpStatus.NOT_FOUND,
|
|
||||||
});
|
|
||||||
searchResults.push(...matchedCollections.right);
|
|
||||||
|
|
||||||
const matchedRequests = await this.searchRequests(
|
|
||||||
searchQuery,
|
|
||||||
teamID,
|
|
||||||
take,
|
|
||||||
skip,
|
|
||||||
);
|
|
||||||
if (E.isLeft(matchedRequests))
|
|
||||||
return E.left(<RESTError>{
|
|
||||||
message: matchedRequests.left,
|
|
||||||
statusCode: HttpStatus.NOT_FOUND,
|
|
||||||
});
|
|
||||||
searchResults.push(...matchedRequests.right);
|
|
||||||
|
|
||||||
// Generate the parent tree for searchResults
|
|
||||||
const searchResultsWithTree: CollectionSearchNode[] = [];
|
|
||||||
|
|
||||||
for (let i = 0; i < searchResults.length; i++) {
|
|
||||||
const fetchedParentTree = await this.fetchParentTree(searchResults[i]);
|
|
||||||
if (E.isLeft(fetchedParentTree))
|
|
||||||
return E.left(<RESTError>{
|
|
||||||
message: fetchedParentTree.left,
|
|
||||||
statusCode: HttpStatus.NOT_FOUND,
|
|
||||||
});
|
|
||||||
searchResultsWithTree.push({
|
|
||||||
type: searchResults[i].type,
|
|
||||||
title: searchResults[i].title,
|
|
||||||
method: searchResults[i].method,
|
|
||||||
id: searchResults[i].id,
|
|
||||||
path: !fetchedParentTree
|
|
||||||
? []
|
|
||||||
: (fetchedParentTree.right as CollectionSearchNode[]),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return E.right({ data: searchResultsWithTree });
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Search for TeamCollections by title
|
|
||||||
*
|
|
||||||
* @param searchQuery The search query
|
|
||||||
* @param teamID The Team ID
|
|
||||||
* @param take Number of items we want returned
|
|
||||||
* @param skip Number of items we want to skip
|
|
||||||
* @returns An Either of the search results
|
|
||||||
*/
|
|
||||||
private async searchCollections(
|
|
||||||
searchQuery: string,
|
|
||||||
teamID: string,
|
|
||||||
take: number,
|
|
||||||
skip: number,
|
|
||||||
) {
|
|
||||||
const query = Prisma.sql`
|
|
||||||
SELECT
|
|
||||||
id,title,'collection' AS type
|
|
||||||
FROM
|
|
||||||
"TeamCollection"
|
|
||||||
WHERE
|
|
||||||
"TeamCollection"."teamID"=${teamID}
|
|
||||||
AND
|
|
||||||
title ILIKE ${`%${escapeSqlLikeString(searchQuery)}%`}
|
|
||||||
ORDER BY
|
|
||||||
similarity(title, ${searchQuery})
|
|
||||||
LIMIT ${take}
|
|
||||||
OFFSET ${skip === 0 ? 0 : (skip - 1) * take};
|
|
||||||
`;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const res = await this.prisma.$queryRaw<SearchQueryReturnType[]>(query);
|
|
||||||
return E.right(res);
|
|
||||||
} catch (error) {
|
|
||||||
return E.left(TEAM_COL_SEARCH_FAILED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Search for TeamRequests by title
|
|
||||||
*
|
|
||||||
* @param searchQuery The search query
|
|
||||||
* @param teamID The Team ID
|
|
||||||
* @param take Number of items we want returned
|
|
||||||
* @param skip Number of items we want to skip
|
|
||||||
* @returns An Either of the search results
|
|
||||||
*/
|
|
||||||
private async searchRequests(
|
|
||||||
searchQuery: string,
|
|
||||||
teamID: string,
|
|
||||||
take: number,
|
|
||||||
skip: number,
|
|
||||||
) {
|
|
||||||
const query = Prisma.sql`
|
|
||||||
SELECT
|
|
||||||
id,title,request->>'method' as method,'request' AS type
|
|
||||||
FROM
|
|
||||||
"TeamRequest"
|
|
||||||
WHERE
|
|
||||||
"TeamRequest"."teamID"=${teamID}
|
|
||||||
AND
|
|
||||||
title ILIKE ${`%${escapeSqlLikeString(searchQuery)}%`}
|
|
||||||
ORDER BY
|
|
||||||
similarity(title, ${searchQuery})
|
|
||||||
LIMIT ${take}
|
|
||||||
OFFSET ${skip === 0 ? 0 : (skip - 1) * take};
|
|
||||||
`;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const res = await this.prisma.$queryRaw<SearchQueryReturnType[]>(query);
|
|
||||||
return E.right(res);
|
|
||||||
} catch (error) {
|
|
||||||
return E.left(TEAM_REQ_SEARCH_FAILED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate the parent tree of a search result
|
|
||||||
*
|
|
||||||
* @param searchResult The search result for which we want to generate the parent tree
|
|
||||||
* @returns The parent tree of the search result
|
|
||||||
*/
|
|
||||||
private async fetchParentTree(searchResult: SearchQueryReturnType) {
|
|
||||||
return searchResult.type === 'collection'
|
|
||||||
? await this.fetchCollectionParentTree(searchResult.id)
|
|
||||||
: await this.fetchRequestParentTree(searchResult.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate the parent tree of a collection
|
|
||||||
*
|
|
||||||
* @param id The ID of the collection
|
|
||||||
* @returns The parent tree of the collection
|
|
||||||
*/
|
|
||||||
private async fetchCollectionParentTree(id: string) {
|
|
||||||
try {
|
|
||||||
const query = Prisma.sql`
|
|
||||||
WITH RECURSIVE collection_tree AS (
|
|
||||||
SELECT tc.id, tc."parentID", tc.title
|
|
||||||
FROM "TeamCollection" AS tc
|
|
||||||
JOIN "TeamCollection" AS tr ON tc.id = tr."parentID"
|
|
||||||
WHERE tr.id = ${id}
|
|
||||||
|
|
||||||
UNION ALL
|
|
||||||
|
|
||||||
SELECT parent.id, parent."parentID", parent.title
|
|
||||||
FROM "TeamCollection" AS parent
|
|
||||||
JOIN collection_tree AS ct ON parent.id = ct."parentID"
|
|
||||||
)
|
|
||||||
SELECT * FROM collection_tree;
|
|
||||||
`;
|
|
||||||
const res = await this.prisma.$queryRaw<ParentTreeQueryReturnType[]>(
|
|
||||||
query,
|
|
||||||
);
|
|
||||||
|
|
||||||
const collectionParentTree = this.generateParentTree(res);
|
|
||||||
return E.right(collectionParentTree);
|
|
||||||
} catch (error) {
|
|
||||||
E.left(TEAM_COLL_PARENT_TREE_GEN_FAILED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate the parent tree from the collections
|
|
||||||
*
|
|
||||||
* @param parentCollections The parent collections
|
|
||||||
* @returns The parent tree of the parent collections
|
|
||||||
*/
|
|
||||||
private generateParentTree(parentCollections: ParentTreeQueryReturnType[]) {
|
|
||||||
function findChildren(id: string): CollectionSearchNode[] {
|
|
||||||
const collection = parentCollections.filter((item) => item.id === id)[0];
|
|
||||||
if (collection.parentID == null) {
|
|
||||||
return <CollectionSearchNode[]>[
|
|
||||||
{
|
|
||||||
id: collection.id,
|
|
||||||
title: collection.title,
|
|
||||||
type: 'collection' as const,
|
|
||||||
path: [],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
const res = <CollectionSearchNode[]>[
|
|
||||||
{
|
|
||||||
id: collection.id,
|
|
||||||
title: collection.title,
|
|
||||||
type: 'collection' as const,
|
|
||||||
path: findChildren(collection.parentID),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parentCollections.length > 0) {
|
|
||||||
if (parentCollections[0].parentID == null) {
|
|
||||||
return <CollectionSearchNode[]>[
|
|
||||||
{
|
|
||||||
id: parentCollections[0].id,
|
|
||||||
title: parentCollections[0].title,
|
|
||||||
type: 'collection',
|
|
||||||
path: [],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return <CollectionSearchNode[]>[
|
|
||||||
{
|
|
||||||
id: parentCollections[0].id,
|
|
||||||
title: parentCollections[0].title,
|
|
||||||
type: 'collection',
|
|
||||||
path: findChildren(parentCollections[0].parentID),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return <CollectionSearchNode[]>[];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate the parent tree of a request
|
|
||||||
*
|
|
||||||
* @param id The ID of the request
|
|
||||||
* @returns The parent tree of the request
|
|
||||||
*/
|
|
||||||
private async fetchRequestParentTree(id: string) {
|
|
||||||
try {
|
|
||||||
const query = Prisma.sql`
|
|
||||||
WITH RECURSIVE request_collection_tree AS (
|
|
||||||
SELECT tc.id, tc."parentID", tc.title
|
|
||||||
FROM "TeamCollection" AS tc
|
|
||||||
JOIN "TeamRequest" AS tr ON tc.id = tr."collectionID"
|
|
||||||
WHERE tr.id = ${id}
|
|
||||||
|
|
||||||
UNION ALL
|
|
||||||
|
|
||||||
SELECT parent.id, parent."parentID", parent.title
|
|
||||||
FROM "TeamCollection" AS parent
|
|
||||||
JOIN request_collection_tree AS ct ON parent.id = ct."parentID"
|
|
||||||
)
|
|
||||||
SELECT * FROM request_collection_tree;
|
|
||||||
|
|
||||||
`;
|
|
||||||
const res = await this.prisma.$queryRaw<ParentTreeQueryReturnType[]>(
|
|
||||||
query,
|
|
||||||
);
|
|
||||||
|
|
||||||
const requestParentTree = this.generateParentTree(res);
|
|
||||||
return E.right(requestParentTree);
|
|
||||||
} catch (error) {
|
|
||||||
return E.left(TEAM_REQ_PARENT_TREE_GEN_FAILED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,47 +0,0 @@
|
|||||||
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
|
|
||||||
import { Reflector } from '@nestjs/core';
|
|
||||||
import { TeamService } from '../../team/team.service';
|
|
||||||
import { TeamMemberRole } from '../../team/team.model';
|
|
||||||
import {
|
|
||||||
BUG_TEAM_NO_REQUIRE_TEAM_ROLE,
|
|
||||||
BUG_AUTH_NO_USER_CTX,
|
|
||||||
BUG_TEAM_NO_TEAM_ID,
|
|
||||||
TEAM_MEMBER_NOT_FOUND,
|
|
||||||
TEAM_NOT_REQUIRED_ROLE,
|
|
||||||
} from 'src/errors';
|
|
||||||
import { throwHTTPErr } from 'src/utils';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class RESTTeamMemberGuard implements CanActivate {
|
|
||||||
constructor(
|
|
||||||
private readonly reflector: Reflector,
|
|
||||||
private readonly teamService: TeamService,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
|
||||||
const requireRoles = this.reflector.get<TeamMemberRole[]>(
|
|
||||||
'requiresTeamRole',
|
|
||||||
context.getHandler(),
|
|
||||||
);
|
|
||||||
if (!requireRoles)
|
|
||||||
throwHTTPErr({ message: BUG_TEAM_NO_REQUIRE_TEAM_ROLE, statusCode: 400 });
|
|
||||||
|
|
||||||
const request = context.switchToHttp().getRequest();
|
|
||||||
|
|
||||||
const { user } = request;
|
|
||||||
if (user == undefined)
|
|
||||||
throwHTTPErr({ message: BUG_AUTH_NO_USER_CTX, statusCode: 400 });
|
|
||||||
|
|
||||||
const teamID = request.params.teamID;
|
|
||||||
if (!teamID)
|
|
||||||
throwHTTPErr({ message: BUG_TEAM_NO_TEAM_ID, statusCode: 400 });
|
|
||||||
|
|
||||||
const teamMember = await this.teamService.getTeamMember(teamID, user.uid);
|
|
||||||
if (!teamMember)
|
|
||||||
throwHTTPErr({ message: TEAM_MEMBER_NOT_FOUND, statusCode: 404 });
|
|
||||||
|
|
||||||
if (requireRoles.includes(teamMember.role)) return true;
|
|
||||||
|
|
||||||
throwHTTPErr({ message: TEAM_NOT_REQUIRED_ROLE, statusCode: 403 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
import { HttpStatus } from '@nestjs/common';
|
import { HttpStatus } from '@nestjs/common';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Custom interface to handle errors for REST modules such as Auth, Admin modules
|
** Custom interface to handle errors specific to Auth module
|
||||||
** Since its REST we need to return the HTTP status code along with the error message
|
** Since its REST we need to return the HTTP status code along with the error message
|
||||||
*/
|
*/
|
||||||
export type RESTError = {
|
export type AuthError = {
|
||||||
message: string;
|
message: string;
|
||||||
statusCode: HttpStatus;
|
statusCode: HttpStatus;
|
||||||
};
|
};
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
// Response type of results from the search query
|
|
||||||
export type CollectionSearchNode = {
|
|
||||||
/** Encodes the hierarchy of where the node is **/
|
|
||||||
path: CollectionSearchNode[];
|
|
||||||
} & (
|
|
||||||
| {
|
|
||||||
type: 'request';
|
|
||||||
title: string;
|
|
||||||
method: string;
|
|
||||||
id: string;
|
|
||||||
}
|
|
||||||
| {
|
|
||||||
type: 'collection';
|
|
||||||
title: string;
|
|
||||||
id: string;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
@@ -4,23 +4,26 @@ export enum InfraConfigEnum {
|
|||||||
|
|
||||||
GOOGLE_CLIENT_ID = 'GOOGLE_CLIENT_ID',
|
GOOGLE_CLIENT_ID = 'GOOGLE_CLIENT_ID',
|
||||||
GOOGLE_CLIENT_SECRET = 'GOOGLE_CLIENT_SECRET',
|
GOOGLE_CLIENT_SECRET = 'GOOGLE_CLIENT_SECRET',
|
||||||
GOOGLE_CALLBACK_URL = 'GOOGLE_CALLBACK_URL',
|
|
||||||
GOOGLE_SCOPE = 'GOOGLE_SCOPE',
|
|
||||||
|
|
||||||
GITHUB_CLIENT_ID = 'GITHUB_CLIENT_ID',
|
GITHUB_CLIENT_ID = 'GITHUB_CLIENT_ID',
|
||||||
GITHUB_CLIENT_SECRET = 'GITHUB_CLIENT_SECRET',
|
GITHUB_CLIENT_SECRET = 'GITHUB_CLIENT_SECRET',
|
||||||
GITHUB_CALLBACK_URL = 'GITHUB_CALLBACK_URL',
|
|
||||||
GITHUB_SCOPE = 'GITHUB_SCOPE',
|
|
||||||
|
|
||||||
MICROSOFT_CLIENT_ID = 'MICROSOFT_CLIENT_ID',
|
MICROSOFT_CLIENT_ID = 'MICROSOFT_CLIENT_ID',
|
||||||
MICROSOFT_CLIENT_SECRET = 'MICROSOFT_CLIENT_SECRET',
|
MICROSOFT_CLIENT_SECRET = 'MICROSOFT_CLIENT_SECRET',
|
||||||
MICROSOFT_CALLBACK_URL = 'MICROSOFT_CALLBACK_URL',
|
|
||||||
MICROSOFT_SCOPE = 'MICROSOFT_SCOPE',
|
|
||||||
MICROSOFT_TENANT = 'MICROSOFT_TENANT',
|
|
||||||
|
|
||||||
VITE_ALLOWED_AUTH_PROVIDERS = 'VITE_ALLOWED_AUTH_PROVIDERS',
|
VITE_ALLOWED_AUTH_PROVIDERS = 'VITE_ALLOWED_AUTH_PROVIDERS',
|
||||||
|
}
|
||||||
ALLOW_ANALYTICS_COLLECTION = 'ALLOW_ANALYTICS_COLLECTION',
|
|
||||||
ANALYTICS_USER_ID = 'ANALYTICS_USER_ID',
|
export enum InfraConfigEnumForClient {
|
||||||
IS_FIRST_TIME_INFRA_SETUP = 'IS_FIRST_TIME_INFRA_SETUP',
|
MAILER_SMTP_URL = 'MAILER_SMTP_URL',
|
||||||
|
MAILER_ADDRESS_FROM = 'MAILER_ADDRESS_FROM',
|
||||||
|
|
||||||
|
GOOGLE_CLIENT_ID = 'GOOGLE_CLIENT_ID',
|
||||||
|
GOOGLE_CLIENT_SECRET = 'GOOGLE_CLIENT_SECRET',
|
||||||
|
|
||||||
|
GITHUB_CLIENT_ID = 'GITHUB_CLIENT_ID',
|
||||||
|
GITHUB_CLIENT_SECRET = 'GITHUB_CLIENT_SECRET',
|
||||||
|
|
||||||
|
MICROSOFT_CLIENT_ID = 'MICROSOFT_CLIENT_ID',
|
||||||
|
MICROSOFT_CLIENT_SECRET = 'MICROSOFT_CLIENT_SECRET',
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,21 +17,3 @@ export class PaginationArgs {
|
|||||||
})
|
})
|
||||||
take: number;
|
take: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ArgsType()
|
|
||||||
@InputType()
|
|
||||||
export class OffsetPaginationArgs {
|
|
||||||
@Field({
|
|
||||||
nullable: true,
|
|
||||||
defaultValue: 0,
|
|
||||||
description: 'Number of items to skip',
|
|
||||||
})
|
|
||||||
skip: number;
|
|
||||||
|
|
||||||
@Field({
|
|
||||||
nullable: true,
|
|
||||||
defaultValue: 10,
|
|
||||||
description: 'Number of items to fetch',
|
|
||||||
})
|
|
||||||
take: number;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -56,22 +56,3 @@ export enum SessionType {
|
|||||||
registerEnumType(SessionType, {
|
registerEnumType(SessionType, {
|
||||||
name: 'SessionType',
|
name: 'SessionType',
|
||||||
});
|
});
|
||||||
|
|
||||||
@ObjectType()
|
|
||||||
export class UserDeletionResult {
|
|
||||||
@Field(() => ID, {
|
|
||||||
description: 'UID of the user',
|
|
||||||
})
|
|
||||||
userUID: string;
|
|
||||||
|
|
||||||
@Field(() => Boolean, {
|
|
||||||
description: 'Flag to determine if user deletion was successful or not',
|
|
||||||
})
|
|
||||||
isDeleted: Boolean;
|
|
||||||
|
|
||||||
@Field({
|
|
||||||
nullable: true,
|
|
||||||
description: 'Error message if user deletion was not successful',
|
|
||||||
})
|
|
||||||
errorMessage: String;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -58,29 +58,6 @@ export class UserResolver {
|
|||||||
if (E.isLeft(updatedUser)) throwErr(updatedUser.left);
|
if (E.isLeft(updatedUser)) throwErr(updatedUser.left);
|
||||||
return updatedUser.right;
|
return updatedUser.right;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Mutation(() => User, {
|
|
||||||
description: 'Update a users display name',
|
|
||||||
})
|
|
||||||
@UseGuards(GqlAuthGuard)
|
|
||||||
async updateDisplayName(
|
|
||||||
@GqlUser() user: AuthUser,
|
|
||||||
@Args({
|
|
||||||
name: 'updatedDisplayName',
|
|
||||||
description: 'New name of user',
|
|
||||||
type: () => String,
|
|
||||||
})
|
|
||||||
updatedDisplayName: string,
|
|
||||||
) {
|
|
||||||
const updatedUser = await this.userService.updateUserDisplayName(
|
|
||||||
user.uid,
|
|
||||||
updatedDisplayName,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (E.isLeft(updatedUser)) throwErr(updatedUser.left);
|
|
||||||
return updatedUser.right;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Mutation(() => Boolean, {
|
@Mutation(() => Boolean, {
|
||||||
description: 'Delete an user account',
|
description: 'Delete an user account',
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,9 +1,4 @@
|
|||||||
import {
|
import { JSON_INVALID, USER_NOT_FOUND } from 'src/errors';
|
||||||
JSON_INVALID,
|
|
||||||
USERS_NOT_FOUND,
|
|
||||||
USER_NOT_FOUND,
|
|
||||||
USER_SHORT_DISPLAY_NAME,
|
|
||||||
} from 'src/errors';
|
|
||||||
import { mockDeep, mockReset } from 'jest-mock-extended';
|
import { mockDeep, mockReset } from 'jest-mock-extended';
|
||||||
import { PrismaService } from 'src/prisma/prisma.service';
|
import { PrismaService } from 'src/prisma/prisma.service';
|
||||||
import { AuthUser } from 'src/types/AuthUser';
|
import { AuthUser } from 'src/types/AuthUser';
|
||||||
@@ -181,26 +176,6 @@ describe('UserService', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('findUsersByIds', () => {
|
|
||||||
test('should successfully return users given valid user UIDs', async () => {
|
|
||||||
mockPrisma.user.findMany.mockResolvedValueOnce(users);
|
|
||||||
|
|
||||||
const result = await userService.findUsersByIds([
|
|
||||||
'123344',
|
|
||||||
'5555',
|
|
||||||
'6666',
|
|
||||||
]);
|
|
||||||
expect(result).toEqual(users);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should return empty array of users given a invalid user UIDs', async () => {
|
|
||||||
mockPrisma.user.findMany.mockResolvedValueOnce([]);
|
|
||||||
|
|
||||||
const result = await userService.findUsersByIds(['sdcvbdbr']);
|
|
||||||
expect(result).toEqual([]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('createUserViaMagicLink', () => {
|
describe('createUserViaMagicLink', () => {
|
||||||
test('should successfully create user and account for magic-link given valid inputs', async () => {
|
test('should successfully create user and account for magic-link given valid inputs', async () => {
|
||||||
mockPrisma.user.create.mockResolvedValueOnce(user);
|
mockPrisma.user.create.mockResolvedValueOnce(user);
|
||||||
@@ -439,62 +414,6 @@ describe('UserService', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('updateUserDisplayName', () => {
|
|
||||||
test('should resolve right and update user display name', async () => {
|
|
||||||
const newDisplayName = 'New Name';
|
|
||||||
mockPrisma.user.update.mockResolvedValueOnce({
|
|
||||||
...user,
|
|
||||||
displayName: newDisplayName,
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = await userService.updateUserDisplayName(
|
|
||||||
user.uid,
|
|
||||||
newDisplayName,
|
|
||||||
);
|
|
||||||
expect(result).toEqualRight({
|
|
||||||
...user,
|
|
||||||
displayName: newDisplayName,
|
|
||||||
currentGQLSession: JSON.stringify(user.currentGQLSession),
|
|
||||||
currentRESTSession: JSON.stringify(user.currentRESTSession),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
test('should resolve right and publish user updated subscription', async () => {
|
|
||||||
const newDisplayName = 'New Name';
|
|
||||||
mockPrisma.user.update.mockResolvedValueOnce({
|
|
||||||
...user,
|
|
||||||
displayName: newDisplayName,
|
|
||||||
});
|
|
||||||
|
|
||||||
await userService.updateUserDisplayName(user.uid, user.displayName);
|
|
||||||
expect(mockPubSub.publish).toHaveBeenCalledWith(
|
|
||||||
`user/${user.uid}/updated`,
|
|
||||||
{
|
|
||||||
...user,
|
|
||||||
displayName: newDisplayName,
|
|
||||||
currentGQLSession: JSON.stringify(user.currentGQLSession),
|
|
||||||
currentRESTSession: JSON.stringify(user.currentRESTSession),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
});
|
|
||||||
test('should resolve left and error when invalid user uid is passed', async () => {
|
|
||||||
mockPrisma.user.update.mockRejectedValueOnce('NotFoundError');
|
|
||||||
|
|
||||||
const result = await userService.updateUserDisplayName(
|
|
||||||
'invalidUserUid',
|
|
||||||
user.displayName,
|
|
||||||
);
|
|
||||||
expect(result).toEqualLeft(USER_NOT_FOUND);
|
|
||||||
});
|
|
||||||
test('should resolve left and error when short display name is passed', async () => {
|
|
||||||
const newDisplayName = '';
|
|
||||||
const result = await userService.updateUserDisplayName(
|
|
||||||
user.uid,
|
|
||||||
newDisplayName,
|
|
||||||
);
|
|
||||||
expect(result).toEqualLeft(USER_SHORT_DISPLAY_NAME);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('fetchAllUsers', () => {
|
describe('fetchAllUsers', () => {
|
||||||
test('should resolve right and return 20 users when cursor is null', async () => {
|
test('should resolve right and return 20 users when cursor is null', async () => {
|
||||||
mockPrisma.user.findMany.mockResolvedValueOnce(users);
|
mockPrisma.user.findMany.mockResolvedValueOnce(users);
|
||||||
@@ -516,36 +435,6 @@ describe('UserService', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('fetchAllUsersV2', () => {
|
|
||||||
test('should resolve right and return first 20 users when searchString is null', async () => {
|
|
||||||
mockPrisma.user.findMany.mockResolvedValueOnce(users);
|
|
||||||
|
|
||||||
const result = await userService.fetchAllUsersV2(null, {
|
|
||||||
take: 20,
|
|
||||||
skip: 0,
|
|
||||||
});
|
|
||||||
expect(result).toEqual(users);
|
|
||||||
});
|
|
||||||
test('should resolve right and return next 20 users when searchString is provided', async () => {
|
|
||||||
mockPrisma.user.findMany.mockResolvedValueOnce(users);
|
|
||||||
|
|
||||||
const result = await userService.fetchAllUsersV2('.com', {
|
|
||||||
take: 20,
|
|
||||||
skip: 0,
|
|
||||||
});
|
|
||||||
expect(result).toEqual(users);
|
|
||||||
});
|
|
||||||
test('should resolve left and return an empty array when users not found', async () => {
|
|
||||||
mockPrisma.user.findMany.mockResolvedValueOnce([]);
|
|
||||||
|
|
||||||
const result = await userService.fetchAllUsersV2('Unknown entry', {
|
|
||||||
take: 20,
|
|
||||||
skip: 0,
|
|
||||||
});
|
|
||||||
expect(result).toEqual([]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('fetchAdminUsers', () => {
|
describe('fetchAdminUsers', () => {
|
||||||
test('should return a list of admin users', async () => {
|
test('should return a list of admin users', async () => {
|
||||||
mockPrisma.user.findMany.mockResolvedValueOnce(adminUsers);
|
mockPrisma.user.findMany.mockResolvedValueOnce(adminUsers);
|
||||||
@@ -667,17 +556,4 @@ describe('UserService', () => {
|
|||||||
expect(result).toEqual(10);
|
expect(result).toEqual(10);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('removeUsersAsAdmin', () => {
|
|
||||||
test('should resolve right and return true for valid user UIDs', async () => {
|
|
||||||
mockPrisma.user.updateMany.mockResolvedValueOnce({ count: 1 });
|
|
||||||
const result = await userService.removeUsersAsAdmin(['123344']);
|
|
||||||
expect(result).toEqualRight(true);
|
|
||||||
});
|
|
||||||
test('should resolve right and return false for invalid user UIDs', async () => {
|
|
||||||
mockPrisma.user.updateMany.mockResolvedValueOnce({ count: 0 });
|
|
||||||
const result = await userService.removeUsersAsAdmin(['123344']);
|
|
||||||
expect(result).toEqualLeft(USERS_NOT_FOUND);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -8,18 +8,13 @@ import * as T from 'fp-ts/Task';
|
|||||||
import * as A from 'fp-ts/Array';
|
import * as A from 'fp-ts/Array';
|
||||||
import { pipe, constVoid } from 'fp-ts/function';
|
import { pipe, constVoid } from 'fp-ts/function';
|
||||||
import { AuthUser } from 'src/types/AuthUser';
|
import { AuthUser } from 'src/types/AuthUser';
|
||||||
import {
|
import { USER_NOT_FOUND } from 'src/errors';
|
||||||
USERS_NOT_FOUND,
|
|
||||||
USER_NOT_FOUND,
|
|
||||||
USER_SHORT_DISPLAY_NAME,
|
|
||||||
} from 'src/errors';
|
|
||||||
import { SessionType, User } from './user.model';
|
import { SessionType, User } from './user.model';
|
||||||
import { USER_UPDATE_FAILED } from 'src/errors';
|
import { USER_UPDATE_FAILED } from 'src/errors';
|
||||||
import { PubSubService } from 'src/pubsub/pubsub.service';
|
import { PubSubService } from 'src/pubsub/pubsub.service';
|
||||||
import { stringToJson, taskEitherValidateArraySeq } from 'src/utils';
|
import { stringToJson, taskEitherValidateArraySeq } from 'src/utils';
|
||||||
import { UserDataHandler } from './user.data.handler';
|
import { UserDataHandler } from './user.data.handler';
|
||||||
import { User as DbUser } from '@prisma/client';
|
import { User as DbUser } from '@prisma/client';
|
||||||
import { OffsetPaginationArgs } from 'src/types/input-types.args';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class UserService {
|
export class UserService {
|
||||||
@@ -93,20 +88,6 @@ export class UserService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Find users with given IDs
|
|
||||||
* @param userUIDs User IDs
|
|
||||||
* @returns Array of found Users
|
|
||||||
*/
|
|
||||||
async findUsersByIds(userUIDs: string[]): Promise<AuthUser[]> {
|
|
||||||
const users = await this.prisma.user.findMany({
|
|
||||||
where: {
|
|
||||||
uid: { in: userUIDs },
|
|
||||||
},
|
|
||||||
});
|
|
||||||
return users;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update User with new generated hashed refresh token
|
* Update User with new generated hashed refresh token
|
||||||
*
|
*
|
||||||
@@ -288,34 +269,6 @@ export class UserService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Update a user's data
|
|
||||||
* @param userUID User UID
|
|
||||||
* @param displayName User's displayName
|
|
||||||
* @returns a Either of User or error
|
|
||||||
*/
|
|
||||||
async updateUserDisplayName(userUID: string, displayName: string) {
|
|
||||||
if (!displayName || displayName.length === 0) {
|
|
||||||
return E.left(USER_SHORT_DISPLAY_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const dbUpdatedUser = await this.prisma.user.update({
|
|
||||||
where: { uid: userUID },
|
|
||||||
data: { displayName },
|
|
||||||
});
|
|
||||||
|
|
||||||
const updatedUser = this.convertDbUserToUser(dbUpdatedUser);
|
|
||||||
|
|
||||||
// Publish subscription for user updates
|
|
||||||
await this.pubsub.publish(`user/${updatedUser.uid}/updated`, updatedUser);
|
|
||||||
|
|
||||||
return E.right(updatedUser);
|
|
||||||
} catch (error) {
|
|
||||||
return E.left(USER_NOT_FOUND);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate and parse currentRESTSession and currentGQLSession
|
* Validate and parse currentRESTSession and currentGQLSession
|
||||||
* @param sessionData string of the session
|
* @param sessionData string of the session
|
||||||
@@ -333,7 +286,6 @@ export class UserService {
|
|||||||
* @param cursorID string of userUID or null
|
* @param cursorID string of userUID or null
|
||||||
* @param take number of users to query
|
* @param take number of users to query
|
||||||
* @returns an array of `User` object
|
* @returns an array of `User` object
|
||||||
* @deprecated use fetchAllUsersV2 instead
|
|
||||||
*/
|
*/
|
||||||
async fetchAllUsers(cursorID: string, take: number) {
|
async fetchAllUsers(cursorID: string, take: number) {
|
||||||
const fetchedUsers = await this.prisma.user.findMany({
|
const fetchedUsers = await this.prisma.user.findMany({
|
||||||
@@ -344,43 +296,6 @@ export class UserService {
|
|||||||
return fetchedUsers;
|
return fetchedUsers;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetch all the users in the `User` table based on cursor
|
|
||||||
* @param searchString search on user's displayName or email
|
|
||||||
* @param paginationOption pagination options
|
|
||||||
* @returns an array of `User` object
|
|
||||||
*/
|
|
||||||
async fetchAllUsersV2(
|
|
||||||
searchString: string,
|
|
||||||
paginationOption: OffsetPaginationArgs,
|
|
||||||
) {
|
|
||||||
const fetchedUsers = await this.prisma.user.findMany({
|
|
||||||
skip: paginationOption.skip,
|
|
||||||
take: paginationOption.take,
|
|
||||||
where: searchString
|
|
||||||
? {
|
|
||||||
OR: [
|
|
||||||
{
|
|
||||||
displayName: {
|
|
||||||
contains: searchString,
|
|
||||||
mode: 'insensitive',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
email: {
|
|
||||||
contains: searchString,
|
|
||||||
mode: 'insensitive',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
: undefined,
|
|
||||||
orderBy: [{ isAdmin: 'desc' }, { displayName: 'asc' }],
|
|
||||||
});
|
|
||||||
|
|
||||||
return fetchedUsers;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch the number of users in db
|
* Fetch the number of users in db
|
||||||
* @returns a count (Int) of user records in DB
|
* @returns a count (Int) of user records in DB
|
||||||
@@ -411,23 +326,6 @@ export class UserService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Change users to admins by toggling isAdmin param to true
|
|
||||||
* @param userUID user UIDs
|
|
||||||
* @returns a Either of true or error
|
|
||||||
*/
|
|
||||||
async makeAdmins(userUIDs: string[]) {
|
|
||||||
try {
|
|
||||||
await this.prisma.user.updateMany({
|
|
||||||
where: { uid: { in: userUIDs } },
|
|
||||||
data: { isAdmin: true },
|
|
||||||
});
|
|
||||||
return E.right(true);
|
|
||||||
} catch (error) {
|
|
||||||
return E.left(USER_UPDATE_FAILED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch all the admin users
|
* Fetch all the admin users
|
||||||
* @returns an array of admin users
|
* @returns an array of admin users
|
||||||
@@ -546,22 +444,4 @@ export class UserService {
|
|||||||
return E.left(USER_NOT_FOUND);
|
return E.left(USER_NOT_FOUND);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Change users from an admin by toggling isAdmin param to false
|
|
||||||
* @param userUIDs user UIDs
|
|
||||||
* @returns a Either of true or error
|
|
||||||
*/
|
|
||||||
async removeUsersAsAdmin(userUIDs: string[]) {
|
|
||||||
const data = await this.prisma.user.updateMany({
|
|
||||||
where: { uid: { in: userUIDs } },
|
|
||||||
data: { isAdmin: false },
|
|
||||||
});
|
|
||||||
|
|
||||||
if (data.count === 0) {
|
|
||||||
return E.left(USERS_NOT_FOUND);
|
|
||||||
}
|
|
||||||
|
|
||||||
return E.right(true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { ExecutionContext, HttpException } from '@nestjs/common';
|
import { ExecutionContext } from '@nestjs/common';
|
||||||
import { Reflector } from '@nestjs/core';
|
import { Reflector } from '@nestjs/core';
|
||||||
import { GqlExecutionContext } from '@nestjs/graphql';
|
import { GqlExecutionContext } from '@nestjs/graphql';
|
||||||
import { pipe } from 'fp-ts/lib/function';
|
import { pipe } from 'fp-ts/lib/function';
|
||||||
@@ -16,7 +16,6 @@ import {
|
|||||||
JSON_INVALID,
|
JSON_INVALID,
|
||||||
} from './errors';
|
} from './errors';
|
||||||
import { AuthProvider } from './auth/helper';
|
import { AuthProvider } from './auth/helper';
|
||||||
import { RESTError } from './types/RESTError';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A workaround to throw an exception in an expression.
|
* A workaround to throw an exception in an expression.
|
||||||
@@ -28,15 +27,6 @@ export function throwErr(errMessage: string): never {
|
|||||||
throw new Error(errMessage);
|
throw new Error(errMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* This function allows throw to be used as an expression
|
|
||||||
* @param errMessage Message present in the error message
|
|
||||||
*/
|
|
||||||
export function throwHTTPErr(errorData: RESTError): never {
|
|
||||||
const { message, statusCode } = errorData;
|
|
||||||
throw new HttpException(message, statusCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prints the given value to log and returns the same value.
|
* Prints the given value to log and returns the same value.
|
||||||
* Used for debugging functional pipelines.
|
* Used for debugging functional pipelines.
|
||||||
@@ -183,16 +173,6 @@ export const validateSMTPUrl = (url: string) => {
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks to see if the URL is valid or not
|
|
||||||
* @param url The URL to validate
|
|
||||||
* @returns boolean
|
|
||||||
*/
|
|
||||||
export const validateUrl = (url: string) => {
|
|
||||||
const urlRegex = /^(http|https):\/\/[^ "]+$/;
|
|
||||||
return urlRegex.test(url);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* String to JSON parser
|
* String to JSON parser
|
||||||
* @param {str} str The string to parse
|
* @param {str} str The string to parse
|
||||||
@@ -250,39 +230,3 @@ export function checkEnvironmentAuthProvider(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds escape backslashes to the input so that it can be used inside
|
|
||||||
* SQL LIKE/ILIKE queries. Inspired by PHP's `mysql_real_escape_string`
|
|
||||||
* function.
|
|
||||||
*
|
|
||||||
* Eg. "100%" -> "100\\%"
|
|
||||||
*
|
|
||||||
* Source: https://stackoverflow.com/a/32648526
|
|
||||||
*/
|
|
||||||
export function escapeSqlLikeString(str: string) {
|
|
||||||
if (typeof str != 'string') return str;
|
|
||||||
|
|
||||||
return str.replace(/[\0\x08\x09\x1a\n\r"'\\\%]/g, function (char) {
|
|
||||||
switch (char) {
|
|
||||||
case '\0':
|
|
||||||
return '\\0';
|
|
||||||
case '\x08':
|
|
||||||
return '\\b';
|
|
||||||
case '\x09':
|
|
||||||
return '\\t';
|
|
||||||
case '\x1a':
|
|
||||||
return '\\z';
|
|
||||||
case '\n':
|
|
||||||
return '\\n';
|
|
||||||
case '\r':
|
|
||||||
return '\\r';
|
|
||||||
case '"':
|
|
||||||
case "'":
|
|
||||||
case '\\':
|
|
||||||
case '%':
|
|
||||||
return '\\' + char; // prepends a backslash to backslash, percent,
|
|
||||||
// and double/single quotes
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -52,34 +52,11 @@ hopp [options or commands] arguments
|
|||||||
Taking the above example, `pw.env.get("ENV1")` will return `"value1"`
|
Taking the above example, `pw.env.get("ENV1")` will return `"value1"`
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
- Before you install Hoppscotch CLI you need to make sure you have the dependencies it requires to run.
|
|
||||||
- **Windows & macOS**: You will need `node-gyp` installed. Find instructions here: https://github.com/nodejs/node-gyp
|
|
||||||
- **Debian/Ubuntu derivatives**:
|
|
||||||
```sh
|
|
||||||
sudo apt-get install python g++ build-essential
|
|
||||||
```
|
|
||||||
- **Alpine Linux**:
|
|
||||||
```sh
|
|
||||||
sudo apk add python3 make g++
|
|
||||||
```
|
|
||||||
- **Amazon Linux (AMI)**
|
|
||||||
```sh
|
|
||||||
sudo yum install gcc72 gcc72-c++
|
|
||||||
```
|
|
||||||
- **Arch Linux**
|
|
||||||
```sh
|
|
||||||
sudo pacman -S make gcc python
|
|
||||||
```
|
|
||||||
- **RHEL/Fedora derivatives**:
|
|
||||||
```sh
|
|
||||||
sudo dnf install python3 make gcc gcc-c++ zlib-devel brotli-devel openssl-devel libuv-devel
|
|
||||||
```
|
|
||||||
|
|
||||||
|
Install [@hoppscotch/cli](https://www.npmjs.com/package/@hoppscotch/cli) from npm by running:
|
||||||
- Once the dependencies are installed, install [@hoppscotch/cli](https://www.npmjs.com/package/@hoppscotch/cli) from npm by running:
|
```
|
||||||
```
|
npm i -g @hoppscotch/cli
|
||||||
npm i -g @hoppscotch/cli
|
```
|
||||||
```
|
|
||||||
|
|
||||||
## **Developing:**
|
## **Developing:**
|
||||||
|
|
||||||
|
|||||||
3
packages/hoppscotch-cli/bin/hopp
Executable file
3
packages/hoppscotch-cli/bin/hopp
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
// * The entry point of the CLI
|
||||||
|
require("../dist").cli(process.argv);
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
// * The entry point of the CLI
|
|
||||||
// @ts-check
|
|
||||||
|
|
||||||
import { cli } from "../dist/index.js";
|
|
||||||
|
|
||||||
import { spawnSync } from "child_process";
|
|
||||||
import { cloneDeep } from "lodash-es";
|
|
||||||
|
|
||||||
const nodeVersion = parseInt(process.versions.node.split(".")[0]);
|
|
||||||
|
|
||||||
// As per isolated-vm documentation, we need to supply `--no-node-snapshot` for node >= 20
|
|
||||||
// src: https://github.com/laverdet/isolated-vm?tab=readme-ov-file#requirements
|
|
||||||
if (nodeVersion >= 20 && !process.execArgv.includes("--no-node-snapshot")) {
|
|
||||||
const argCopy = cloneDeep(process.argv);
|
|
||||||
|
|
||||||
// Replace first argument with --no-node-snapshot
|
|
||||||
// We can get argv[0] from process.argv0
|
|
||||||
argCopy[0] = "--no-node-snapshot";
|
|
||||||
|
|
||||||
const result = spawnSync(
|
|
||||||
process.argv0,
|
|
||||||
argCopy,
|
|
||||||
{ stdio: "inherit" }
|
|
||||||
);
|
|
||||||
|
|
||||||
// Exit with the same status code as the spawned process
|
|
||||||
process.exit(result.status ?? 0);
|
|
||||||
} else {
|
|
||||||
cli(process.argv);
|
|
||||||
}
|
|
||||||
@@ -1,12 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "@hoppscotch/cli",
|
"name": "@hoppscotch/cli",
|
||||||
"version": "0.8.0",
|
"version": "0.6.0",
|
||||||
"description": "A CLI to run Hoppscotch test scripts in CI environments.",
|
"description": "A CLI to run Hoppscotch test scripts in CI environments.",
|
||||||
"homepage": "https://hoppscotch.io",
|
"homepage": "https://hoppscotch.io",
|
||||||
"type": "module",
|
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"bin": {
|
"bin": {
|
||||||
"hopp": "bin/hopp.js"
|
"hopp": "bin/hopp"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
@@ -40,30 +39,28 @@
|
|||||||
},
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"private": false,
|
"private": false,
|
||||||
"dependencies": {
|
|
||||||
"axios": "1.6.7",
|
|
||||||
"chalk": "5.3.0",
|
|
||||||
"commander": "11.1.0",
|
|
||||||
"isolated-vm": "4.7.2",
|
|
||||||
"lodash-es": "4.17.21",
|
|
||||||
"qs": "6.11.2",
|
|
||||||
"verzod": "0.2.2",
|
|
||||||
"zod": "3.22.4"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@hoppscotch/data": "workspace:^",
|
"@hoppscotch/data": "workspace:^",
|
||||||
"@hoppscotch/js-sandbox": "workspace:^",
|
"@hoppscotch/js-sandbox": "workspace:^",
|
||||||
"@relmify/jest-fp-ts": "2.1.1",
|
"@relmify/jest-fp-ts": "^2.1.1",
|
||||||
"@swc/core": "1.4.2",
|
"@swc/core": "^1.3.92",
|
||||||
"@types/jest": "29.5.12",
|
"@types/jest": "^29.5.5",
|
||||||
"@types/lodash-es": "4.17.12",
|
"@types/lodash": "^4.14.199",
|
||||||
"@types/qs": "6.9.12",
|
"@types/qs": "^6.9.8",
|
||||||
"fp-ts": "2.16.2",
|
"axios": "^0.21.4",
|
||||||
"jest": "29.7.0",
|
"chalk": "^4.1.2",
|
||||||
"prettier": "3.2.5",
|
"commander": "^11.0.0",
|
||||||
"qs": "6.11.2",
|
"esm": "^3.2.25",
|
||||||
"ts-jest": "29.1.2",
|
"fp-ts": "^2.16.1",
|
||||||
"tsup": "8.0.2",
|
"io-ts": "^2.2.20",
|
||||||
"typescript": "5.3.3"
|
"jest": "^29.7.0",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
|
"prettier": "^3.0.3",
|
||||||
|
"qs": "^6.11.2",
|
||||||
|
"ts-jest": "^29.1.1",
|
||||||
|
"tsup": "^7.2.0",
|
||||||
|
"typescript": "^5.2.2",
|
||||||
|
"verzod": "^0.2.2",
|
||||||
|
"zod": "^3.22.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ describe("Test `hopp test <file>` command:", () => {
|
|||||||
const out = getErrorCode(stderr);
|
const out = getErrorCode(stderr);
|
||||||
expect(out).toBe<HoppErrorCode>("INVALID_ARGUMENT");
|
expect(out).toBe<HoppErrorCode>("INVALID_ARGUMENT");
|
||||||
});
|
});
|
||||||
});
|
})
|
||||||
|
|
||||||
describe("Supplied collection export file validations", () => {
|
describe("Supplied collection export file validations", () => {
|
||||||
test("Errors with the code `FILE_NOT_FOUND` if the supplied collection export file doesn't exist", async () => {
|
test("Errors with the code `FILE_NOT_FOUND` if the supplied collection export file doesn't exist", async () => {
|
||||||
@@ -66,43 +66,6 @@ describe("Test `hopp test <file>` command:", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Versioned entities", () => {
|
|
||||||
describe("Collections & Requests", () => {
|
|
||||||
const testFixtures = [
|
|
||||||
{ fileName: "coll-v1-req-v0.json", collVersion: 1, reqVersion: 0 },
|
|
||||||
{ fileName: "coll-v1-req-v1.json", collVersion: 1, reqVersion: 1 },
|
|
||||||
{ fileName: "coll-v2-req-v2.json", collVersion: 2, reqVersion: 2 },
|
|
||||||
{ fileName: "coll-v2-req-v3.json", collVersion: 2, reqVersion: 3 },
|
|
||||||
];
|
|
||||||
|
|
||||||
testFixtures.forEach(({ collVersion, fileName, reqVersion }) => {
|
|
||||||
test(`Successfully processes a supplied collection export file where the collection is based on the "v${collVersion}" schema and the request following the "v${reqVersion}" schema`, async () => {
|
|
||||||
const args = `test ${getTestJsonFilePath(fileName, "collection")}`;
|
|
||||||
const { error } = await runCLI(args);
|
|
||||||
|
|
||||||
expect(error).toBeNull();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("Environments", () => {
|
|
||||||
const testFixtures = [
|
|
||||||
{ fileName: "env-v0.json", version: 0 },
|
|
||||||
{ fileName: "env-v1.json", version: 1 },
|
|
||||||
];
|
|
||||||
|
|
||||||
testFixtures.forEach(({ fileName, version }) => {
|
|
||||||
test(`Successfully processes the supplied collection and environment export files where the environment is based on the "v${version}" schema`, async () => {
|
|
||||||
const ENV_PATH = getTestJsonFilePath(fileName, "environment");
|
|
||||||
const args = `test ${getTestJsonFilePath("sample-coll.json", "collection")} --env ${ENV_PATH}`;
|
|
||||||
const { error } = await runCLI(args);
|
|
||||||
|
|
||||||
expect(error).toBeNull();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test("Successfully processes a supplied collection export file of the expected format", async () => {
|
test("Successfully processes a supplied collection export file of the expected format", async () => {
|
||||||
const args = `test ${getTestJsonFilePath("passes-coll.json", "collection")}`;
|
const args = `test ${getTestJsonFilePath("passes-coll.json", "collection")}`;
|
||||||
const { error } = await runCLI(args);
|
const { error } = await runCLI(args);
|
||||||
@@ -112,8 +75,7 @@ describe("Test `hopp test <file>` command:", () => {
|
|||||||
|
|
||||||
test("Successfully inherits headers and authorization set at the root collection", async () => {
|
test("Successfully inherits headers and authorization set at the root collection", async () => {
|
||||||
const args = `test ${getTestJsonFilePath(
|
const args = `test ${getTestJsonFilePath(
|
||||||
"collection-level-headers-auth-coll.json",
|
"collection-level-headers-auth-coll.json", "collection"
|
||||||
"collection"
|
|
||||||
)}`;
|
)}`;
|
||||||
const { error } = await runCLI(args);
|
const { error } = await runCLI(args);
|
||||||
|
|
||||||
@@ -122,8 +84,7 @@ describe("Test `hopp test <file>` command:", () => {
|
|||||||
|
|
||||||
test("Persists environment variables set in the pre-request script for consumption in the test script", async () => {
|
test("Persists environment variables set in the pre-request script for consumption in the test script", async () => {
|
||||||
const args = `test ${getTestJsonFilePath(
|
const args = `test ${getTestJsonFilePath(
|
||||||
"pre-req-script-env-var-persistence-coll.json",
|
"pre-req-script-env-var-persistence-coll.json", "collection"
|
||||||
"collection"
|
|
||||||
)}`;
|
)}`;
|
||||||
const { error } = await runCLI(args);
|
const { error } = await runCLI(args);
|
||||||
|
|
||||||
@@ -145,8 +106,7 @@ describe("Test `hopp test <file> --env <file>` command:", () => {
|
|||||||
|
|
||||||
test("Errors with the code `INVALID_FILE_TYPE` if the supplied environment export file doesn't end with the `.json` extension", async () => {
|
test("Errors with the code `INVALID_FILE_TYPE` if the supplied environment export file doesn't end with the `.json` extension", async () => {
|
||||||
const args = `${VALID_TEST_ARGS} --env ${getTestJsonFilePath(
|
const args = `${VALID_TEST_ARGS} --env ${getTestJsonFilePath(
|
||||||
"notjson-coll.txt",
|
"notjson-coll.txt", "collection"
|
||||||
"collection"
|
|
||||||
)}`;
|
)}`;
|
||||||
const { stderr } = await runCLI(args);
|
const { stderr } = await runCLI(args);
|
||||||
|
|
||||||
@@ -163,10 +123,7 @@ describe("Test `hopp test <file> --env <file>` command:", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("Errors with the code `MALFORMED_ENV_FILE` on supplying a malformed environment export file", async () => {
|
test("Errors with the code `MALFORMED_ENV_FILE` on supplying a malformed environment export file", async () => {
|
||||||
const ENV_PATH = getTestJsonFilePath(
|
const ENV_PATH = getTestJsonFilePath("malformed-envs.json", "environment");
|
||||||
"malformed-envs.json",
|
|
||||||
"environment"
|
|
||||||
);
|
|
||||||
const args = `${VALID_TEST_ARGS} --env ${ENV_PATH}`;
|
const args = `${VALID_TEST_ARGS} --env ${ENV_PATH}`;
|
||||||
const { stderr } = await runCLI(args);
|
const { stderr } = await runCLI(args);
|
||||||
|
|
||||||
@@ -185,10 +142,7 @@ describe("Test `hopp test <file> --env <file>` command:", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("Successfully resolves values from the supplied environment export file", async () => {
|
test("Successfully resolves values from the supplied environment export file", async () => {
|
||||||
const TESTS_PATH = getTestJsonFilePath(
|
const TESTS_PATH = getTestJsonFilePath("env-flag-tests-coll.json", "collection");
|
||||||
"env-flag-tests-coll.json",
|
|
||||||
"collection"
|
|
||||||
);
|
|
||||||
const ENV_PATH = getTestJsonFilePath("env-flag-envs.json", "environment");
|
const ENV_PATH = getTestJsonFilePath("env-flag-envs.json", "environment");
|
||||||
const args = `test ${TESTS_PATH} --env ${ENV_PATH}`;
|
const args = `test ${TESTS_PATH} --env ${ENV_PATH}`;
|
||||||
|
|
||||||
@@ -197,14 +151,8 @@ describe("Test `hopp test <file> --env <file>` command:", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("Successfully resolves environment variables referenced in the request body", async () => {
|
test("Successfully resolves environment variables referenced in the request body", async () => {
|
||||||
const COLL_PATH = getTestJsonFilePath(
|
const COLL_PATH = getTestJsonFilePath("req-body-env-vars-coll.json", "collection");
|
||||||
"req-body-env-vars-coll.json",
|
const ENVS_PATH = getTestJsonFilePath("req-body-env-vars-envs.json", "environment");
|
||||||
"collection"
|
|
||||||
);
|
|
||||||
const ENVS_PATH = getTestJsonFilePath(
|
|
||||||
"req-body-env-vars-envs.json",
|
|
||||||
"environment"
|
|
||||||
);
|
|
||||||
const args = `test ${COLL_PATH} --env ${ENVS_PATH}`;
|
const args = `test ${COLL_PATH} --env ${ENVS_PATH}`;
|
||||||
|
|
||||||
const { error } = await runCLI(args);
|
const { error } = await runCLI(args);
|
||||||
@@ -212,10 +160,7 @@ describe("Test `hopp test <file> --env <file>` command:", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("Works with shorth `-e` flag", async () => {
|
test("Works with shorth `-e` flag", async () => {
|
||||||
const TESTS_PATH = getTestJsonFilePath(
|
const TESTS_PATH = getTestJsonFilePath("env-flag-tests-coll.json", "collection");
|
||||||
"env-flag-tests-coll.json",
|
|
||||||
"collection"
|
|
||||||
);
|
|
||||||
const ENV_PATH = getTestJsonFilePath("env-flag-envs.json", "environment");
|
const ENV_PATH = getTestJsonFilePath("env-flag-envs.json", "environment");
|
||||||
const args = `test ${TESTS_PATH} -e ${ENV_PATH}`;
|
const args = `test ${TESTS_PATH} -e ${ENV_PATH}`;
|
||||||
|
|
||||||
@@ -224,7 +169,7 @@ describe("Test `hopp test <file> --env <file>` command:", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("Secret environment variables", () => {
|
describe("Secret environment variables", () => {
|
||||||
jest.setTimeout(100000);
|
jest.setTimeout(10000);
|
||||||
|
|
||||||
// Reads secret environment values from system environment
|
// Reads secret environment values from system environment
|
||||||
test("Successfully picks the values for secret environment variables from `process.env` and persists the variables set from the pre-request script", async () => {
|
test("Successfully picks the values for secret environment variables from `process.env` and persists the variables set from the pre-request script", async () => {
|
||||||
@@ -238,10 +183,7 @@ describe("Test `hopp test <file> --env <file>` command:", () => {
|
|||||||
secretHeaderValue: "secret-header-value",
|
secretHeaderValue: "secret-header-value",
|
||||||
};
|
};
|
||||||
|
|
||||||
const COLL_PATH = getTestJsonFilePath(
|
const COLL_PATH = getTestJsonFilePath("secret-envs-coll.json", "collection");
|
||||||
"secret-envs-coll.json",
|
|
||||||
"collection"
|
|
||||||
);
|
|
||||||
const ENVS_PATH = getTestJsonFilePath("secret-envs.json", "environment");
|
const ENVS_PATH = getTestJsonFilePath("secret-envs.json", "environment");
|
||||||
const args = `test ${COLL_PATH} --env ${ENVS_PATH}`;
|
const args = `test ${COLL_PATH} --env ${ENVS_PATH}`;
|
||||||
|
|
||||||
@@ -255,14 +197,8 @@ describe("Test `hopp test <file> --env <file>` command:", () => {
|
|||||||
|
|
||||||
// Prefers values specified in the environment export file over values set in the system environment
|
// Prefers values specified in the environment export file over values set in the system environment
|
||||||
test("Successfully picks the values for secret environment variables set directly in the environment export file and persists the environment variables set from the pre-request script", async () => {
|
test("Successfully picks the values for secret environment variables set directly in the environment export file and persists the environment variables set from the pre-request script", async () => {
|
||||||
const COLL_PATH = getTestJsonFilePath(
|
const COLL_PATH = getTestJsonFilePath("secret-envs-coll.json", "collection");
|
||||||
"secret-envs-coll.json",
|
const ENVS_PATH = getTestJsonFilePath("secret-supplied-values-envs.json", "environment");
|
||||||
"collection"
|
|
||||||
);
|
|
||||||
const ENVS_PATH = getTestJsonFilePath(
|
|
||||||
"secret-supplied-values-envs.json",
|
|
||||||
"environment"
|
|
||||||
);
|
|
||||||
const args = `test ${COLL_PATH} --env ${ENVS_PATH}`;
|
const args = `test ${COLL_PATH} --env ${ENVS_PATH}`;
|
||||||
|
|
||||||
const { error, stdout } = await runCLI(args);
|
const { error, stdout } = await runCLI(args);
|
||||||
@@ -276,13 +212,9 @@ describe("Test `hopp test <file> --env <file>` command:", () => {
|
|||||||
// Values set from the scripting context takes the highest precedence
|
// Values set from the scripting context takes the highest precedence
|
||||||
test("Setting values for secret environment variables from the pre-request script overrides values set at the supplied environment export file", async () => {
|
test("Setting values for secret environment variables from the pre-request script overrides values set at the supplied environment export file", async () => {
|
||||||
const COLL_PATH = getTestJsonFilePath(
|
const COLL_PATH = getTestJsonFilePath(
|
||||||
"secret-envs-persistence-coll.json",
|
"secret-envs-persistence-coll.json", "collection"
|
||||||
"collection"
|
|
||||||
);
|
|
||||||
const ENVS_PATH = getTestJsonFilePath(
|
|
||||||
"secret-supplied-values-envs.json",
|
|
||||||
"environment"
|
|
||||||
);
|
);
|
||||||
|
const ENVS_PATH = getTestJsonFilePath("secret-supplied-values-envs.json", "environment");
|
||||||
const args = `test ${COLL_PATH} --env ${ENVS_PATH}`;
|
const args = `test ${COLL_PATH} --env ${ENVS_PATH}`;
|
||||||
|
|
||||||
const { error, stdout } = await runCLI(args);
|
const { error, stdout } = await runCLI(args);
|
||||||
@@ -295,12 +227,10 @@ describe("Test `hopp test <file> --env <file>` command:", () => {
|
|||||||
|
|
||||||
test("Persists secret environment variable values set from the pre-request script for consumption in the request and post-request script context", async () => {
|
test("Persists secret environment variable values set from the pre-request script for consumption in the request and post-request script context", async () => {
|
||||||
const COLL_PATH = getTestJsonFilePath(
|
const COLL_PATH = getTestJsonFilePath(
|
||||||
"secret-envs-persistence-scripting-coll.json",
|
"secret-envs-persistence-scripting-coll.json", "collection"
|
||||||
"collection"
|
|
||||||
);
|
);
|
||||||
const ENVS_PATH = getTestJsonFilePath(
|
const ENVS_PATH = getTestJsonFilePath(
|
||||||
"secret-envs-persistence-scripting-envs.json",
|
"secret-envs-persistence-scripting-envs.json", "environment"
|
||||||
"environment"
|
|
||||||
);
|
);
|
||||||
const args = `test ${COLL_PATH} --env ${ENVS_PATH}`;
|
const args = `test ${COLL_PATH} --env ${ENVS_PATH}`;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,84 @@
|
|||||||
|
import { isRESTCollection } from "../../../utils/checks";
|
||||||
|
|
||||||
|
describe("isRESTCollection", () => {
|
||||||
|
test("Undefined collection value.", () => {
|
||||||
|
expect(isRESTCollection(undefined)).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Invalid id value.", () => {
|
||||||
|
expect(
|
||||||
|
isRESTCollection({
|
||||||
|
v: 1,
|
||||||
|
name: "test",
|
||||||
|
id: 1,
|
||||||
|
})
|
||||||
|
).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Invalid requests value.", () => {
|
||||||
|
expect(
|
||||||
|
isRESTCollection({
|
||||||
|
v: 1,
|
||||||
|
name: "test",
|
||||||
|
id: "1",
|
||||||
|
requests: null,
|
||||||
|
})
|
||||||
|
).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Invalid folders value.", () => {
|
||||||
|
expect(
|
||||||
|
isRESTCollection({
|
||||||
|
v: 1,
|
||||||
|
name: "test",
|
||||||
|
id: "1",
|
||||||
|
requests: [],
|
||||||
|
folders: undefined,
|
||||||
|
})
|
||||||
|
).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Invalid RESTCollection(s) in folders.", () => {
|
||||||
|
expect(
|
||||||
|
isRESTCollection({
|
||||||
|
v: 1,
|
||||||
|
name: "test",
|
||||||
|
id: "1",
|
||||||
|
requests: [],
|
||||||
|
folders: [
|
||||||
|
{
|
||||||
|
v: 1,
|
||||||
|
name: "test1",
|
||||||
|
id: "2",
|
||||||
|
requests: undefined,
|
||||||
|
folders: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Invalid HoppRESTRequest(s) in requests.", () => {
|
||||||
|
expect(
|
||||||
|
isRESTCollection({
|
||||||
|
v: 1,
|
||||||
|
name: "test",
|
||||||
|
id: "1",
|
||||||
|
requests: [{}],
|
||||||
|
folders: [],
|
||||||
|
})
|
||||||
|
).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Valid RESTCollection.", () => {
|
||||||
|
expect(
|
||||||
|
isRESTCollection({
|
||||||
|
v: 1,
|
||||||
|
name: "test",
|
||||||
|
id: "1",
|
||||||
|
requests: [],
|
||||||
|
folders: [],
|
||||||
|
})
|
||||||
|
).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
{
|
|
||||||
"v": 1,
|
|
||||||
"name": "coll-v1",
|
|
||||||
"folders": [
|
|
||||||
{
|
|
||||||
"v": 1,
|
|
||||||
"name": "coll-v1-child",
|
|
||||||
"folders": [],
|
|
||||||
"requests": [
|
|
||||||
{
|
|
||||||
"url": "https://echo.hoppscotch.io",
|
|
||||||
"path": "/get",
|
|
||||||
"headers": [
|
|
||||||
{ "key": "Inactive-Header", "value": "Inactive Header", "active": false },
|
|
||||||
{ "key": "Authorization", "value": "Bearer token123", "active": true }
|
|
||||||
],
|
|
||||||
"params": [
|
|
||||||
{ "key": "key", "value": "value", "active": true },
|
|
||||||
{ "key": "inactive-key", "value": "inactive-param", "active": false }
|
|
||||||
],
|
|
||||||
"name": "req-v0-II",
|
|
||||||
"method": "GET",
|
|
||||||
"preRequestScript": "",
|
|
||||||
"testScript": "pw.test(\"Asserts request params\", () => {\n pw.expect(pw.response.body.args.key).toBe(\"value\")\n pw.expect(pw.response.body.args[\"inactive-key\"]).toBe(undefined)\n})\n\npw.test(\"Asserts request headers\", () => {\n pw.expect(pw.response.body.headers[\"authorization\"]).toBe(\"Bearer token123\")\n pw.expect(pw.response.body.headers[\"inactive-header\"]).toBe(undefined)\n})",
|
|
||||||
"contentType": "application/json",
|
|
||||||
"body": "",
|
|
||||||
"auth": "Bearer Token",
|
|
||||||
"bearerToken": "token123"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"requests": [
|
|
||||||
{
|
|
||||||
"url": "https://echo.hoppscotch.io",
|
|
||||||
"path": "/get",
|
|
||||||
"headers": [
|
|
||||||
{ "key": "Inactive-Header", "value": "Inactive Header", "active": false },
|
|
||||||
{ "key": "Authorization", "value": "Bearer token123", "active": true }
|
|
||||||
],
|
|
||||||
"params": [
|
|
||||||
{ "key": "key", "value": "value", "active": true },
|
|
||||||
{ "key": "inactive-key", "value": "inactive-param", "active": false }
|
|
||||||
],
|
|
||||||
"name": "req-v0",
|
|
||||||
"method": "GET",
|
|
||||||
"preRequestScript": "",
|
|
||||||
"testScript": "pw.test(\"Asserts request params\", () => {\n pw.expect(pw.response.body.args.key).toBe(\"value\")\n pw.expect(pw.response.body.args[\"inactive-key\"]).toBe(undefined)\n})\n\npw.test(\"Asserts request headers\", () => {\n pw.expect(pw.response.body.headers[\"authorization\"]).toBe(\"Bearer token123\")\n pw.expect(pw.response.body.headers[\"inactive-header\"]).toBe(undefined)\n})",
|
|
||||||
"contentType": "application/json",
|
|
||||||
"body": "",
|
|
||||||
"auth": "Bearer Token",
|
|
||||||
"bearerToken": "token123"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,97 +0,0 @@
|
|||||||
{
|
|
||||||
"v": 1,
|
|
||||||
"name": "coll-v1",
|
|
||||||
"folders": [
|
|
||||||
{
|
|
||||||
"v": 1,
|
|
||||||
"name": "coll-v1-child",
|
|
||||||
"folders": [],
|
|
||||||
"requests": [
|
|
||||||
{
|
|
||||||
"v": "1",
|
|
||||||
"endpoint": "https://echo.hoppscotch.io",
|
|
||||||
"headers": [
|
|
||||||
{
|
|
||||||
"key": "Inactive-Header",
|
|
||||||
"value": "Inactive Header",
|
|
||||||
"active": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "Authorization",
|
|
||||||
"value": "Bearer token123",
|
|
||||||
"active": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"params": [
|
|
||||||
{
|
|
||||||
"key": "key",
|
|
||||||
"value": "value",
|
|
||||||
"active": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "inactive-key",
|
|
||||||
"value": "inactive-param",
|
|
||||||
"active": false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "req-v1-II",
|
|
||||||
"method": "GET",
|
|
||||||
"preRequestScript": "",
|
|
||||||
"testScript": "pw.test(\"Asserts request params\", () => {\n pw.expect(pw.response.body.args.key).toBe(\"value\")\n pw.expect(pw.response.body.args[\"inactive-key\"]).toBe(undefined)\n})\n\npw.test(\"Asserts request headers\", () => {\n pw.expect(pw.response.body.headers[\"authorization\"]).toBe(\"Bearer token123\")\n pw.expect(pw.response.body.headers[\"inactive-header\"]).toBe(undefined)\n})",
|
|
||||||
"body": {
|
|
||||||
"contentType": null,
|
|
||||||
"body": null
|
|
||||||
},
|
|
||||||
"auth": {
|
|
||||||
"authType": "bearer",
|
|
||||||
"authActive": true,
|
|
||||||
"token": "token123"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"requests": [
|
|
||||||
{
|
|
||||||
"v": "1",
|
|
||||||
"endpoint": "https://echo.hoppscotch.io",
|
|
||||||
"headers": [
|
|
||||||
{
|
|
||||||
"key": "Inactive-Header",
|
|
||||||
"value": "Inactive Header",
|
|
||||||
"active": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "Authorization",
|
|
||||||
"value": "Bearer token123",
|
|
||||||
"active": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"params": [
|
|
||||||
{
|
|
||||||
"key": "key",
|
|
||||||
"value": "value",
|
|
||||||
"active": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "inactive-key",
|
|
||||||
"value": "inactive-param",
|
|
||||||
"active": false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "req-v1",
|
|
||||||
"method": "GET",
|
|
||||||
"preRequestScript": "",
|
|
||||||
"testScript": "pw.test(\"Asserts request params\", () => {\n pw.expect(pw.response.body.args.key).toBe(\"value\")\n pw.expect(pw.response.body.args[\"inactive-key\"]).toBe(undefined)\n})\n\npw.test(\"Asserts request headers\", () => {\n pw.expect(pw.response.body.headers[\"authorization\"]).toBe(\"Bearer token123\")\n pw.expect(pw.response.body.headers[\"inactive-header\"]).toBe(undefined)\n})",
|
|
||||||
"body": {
|
|
||||||
"contentType": null,
|
|
||||||
"body": null
|
|
||||||
},
|
|
||||||
"auth": {
|
|
||||||
"authType": "bearer",
|
|
||||||
"authActive": true,
|
|
||||||
"token": "token123"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,109 +0,0 @@
|
|||||||
{
|
|
||||||
"v": 2,
|
|
||||||
"name": "coll-v2",
|
|
||||||
"folders": [
|
|
||||||
{
|
|
||||||
"v": 2,
|
|
||||||
"name": "coll-v2-child",
|
|
||||||
"folders": [],
|
|
||||||
"requests": [
|
|
||||||
{
|
|
||||||
"v": "2",
|
|
||||||
"endpoint": "https://echo.hoppscotch.io",
|
|
||||||
"headers": [
|
|
||||||
{
|
|
||||||
"key": "Inactive-Header",
|
|
||||||
"value": "Inactive Header",
|
|
||||||
"active": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "Authorization",
|
|
||||||
"value": "Bearer token123",
|
|
||||||
"active": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"params": [
|
|
||||||
{
|
|
||||||
"key": "key",
|
|
||||||
"value": "value",
|
|
||||||
"active": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "inactive-key",
|
|
||||||
"value": "inactive-param",
|
|
||||||
"active": false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "req-v2-II",
|
|
||||||
"method": "GET",
|
|
||||||
"preRequestScript": "",
|
|
||||||
"testScript": "pw.test(\"Asserts request params\", () => {\n pw.expect(pw.response.body.args.key).toBe(\"value\")\n pw.expect(pw.response.body.args[\"inactive-key\"]).toBe(undefined)\n})\n\npw.test(\"Asserts request headers\", () => {\n pw.expect(pw.response.body.headers[\"authorization\"]).toBe(\"Bearer token123\")\n pw.expect(pw.response.body.headers[\"inactive-header\"]).toBe(undefined)\n})",
|
|
||||||
"body": {
|
|
||||||
"contentType": null,
|
|
||||||
"body": null
|
|
||||||
},
|
|
||||||
"auth": {
|
|
||||||
"authType": "bearer",
|
|
||||||
"authActive": true,
|
|
||||||
"token": "token123"
|
|
||||||
},
|
|
||||||
"requestVariables": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"auth": {
|
|
||||||
"authType": "inherit",
|
|
||||||
"authActive": true
|
|
||||||
},
|
|
||||||
"headers": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"requests": [
|
|
||||||
{
|
|
||||||
"v": "2",
|
|
||||||
"endpoint": "https://echo.hoppscotch.io",
|
|
||||||
"headers": [
|
|
||||||
{
|
|
||||||
"key": "Inactive-Header",
|
|
||||||
"value": "Inactive Header",
|
|
||||||
"active": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "Authorization",
|
|
||||||
"value": "Bearer token123",
|
|
||||||
"active": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"params": [
|
|
||||||
{
|
|
||||||
"key": "key",
|
|
||||||
"value": "value",
|
|
||||||
"active": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "inactive-key",
|
|
||||||
"value": "inactive-param",
|
|
||||||
"active": false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "req-v2",
|
|
||||||
"method": "GET",
|
|
||||||
"preRequestScript": "",
|
|
||||||
"testScript": "pw.test(\"Asserts request params\", () => {\n pw.expect(pw.response.body.args.key).toBe(\"value\")\n pw.expect(pw.response.body.args[\"inactive-key\"]).toBe(undefined)\n})\n\npw.test(\"Asserts request headers\", () => {\n pw.expect(pw.response.body.headers[\"authorization\"]).toBe(\"Bearer token123\")\n pw.expect(pw.response.body.headers[\"inactive-header\"]).toBe(undefined)\n})",
|
|
||||||
"body": {
|
|
||||||
"contentType": null,
|
|
||||||
"body": null
|
|
||||||
},
|
|
||||||
"auth": {
|
|
||||||
"authType": "bearer",
|
|
||||||
"authActive": true,
|
|
||||||
"token": "token123"
|
|
||||||
},
|
|
||||||
"requestVariables": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"auth": {
|
|
||||||
"authType": "inherit",
|
|
||||||
"authActive": true
|
|
||||||
},
|
|
||||||
"headers": []
|
|
||||||
}
|
|
||||||
@@ -1,109 +0,0 @@
|
|||||||
{
|
|
||||||
"v": 2,
|
|
||||||
"name": "coll-v2",
|
|
||||||
"folders": [
|
|
||||||
{
|
|
||||||
"v": 2,
|
|
||||||
"name": "coll-v2-child",
|
|
||||||
"folders": [],
|
|
||||||
"requests": [
|
|
||||||
{
|
|
||||||
"v": "3",
|
|
||||||
"endpoint": "https://echo.hoppscotch.io",
|
|
||||||
"headers": [
|
|
||||||
{
|
|
||||||
"key": "Inactive-Header",
|
|
||||||
"value": "Inactive Header",
|
|
||||||
"active": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "Authorization",
|
|
||||||
"value": "Bearer token123",
|
|
||||||
"active": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"params": [
|
|
||||||
{
|
|
||||||
"key": "key",
|
|
||||||
"value": "value",
|
|
||||||
"active": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "inactive-key",
|
|
||||||
"value": "inactive-param",
|
|
||||||
"active": false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "req-v3-II",
|
|
||||||
"method": "GET",
|
|
||||||
"preRequestScript": "",
|
|
||||||
"testScript": "pw.test(\"Asserts request params\", () => {\n pw.expect(pw.response.body.args.key).toBe(\"value\")\n pw.expect(pw.response.body.args[\"inactive-key\"]).toBe(undefined)\n})\n\npw.test(\"Asserts request headers\", () => {\n pw.expect(pw.response.body.headers[\"authorization\"]).toBe(\"Bearer token123\")\n pw.expect(pw.response.body.headers[\"inactive-header\"]).toBe(undefined)\n})",
|
|
||||||
"body": {
|
|
||||||
"contentType": null,
|
|
||||||
"body": null
|
|
||||||
},
|
|
||||||
"auth": {
|
|
||||||
"authType": "bearer",
|
|
||||||
"authActive": true,
|
|
||||||
"token": "token123"
|
|
||||||
},
|
|
||||||
"requestVariables": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"auth": {
|
|
||||||
"authType": "inherit",
|
|
||||||
"authActive": true
|
|
||||||
},
|
|
||||||
"headers": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"requests": [
|
|
||||||
{
|
|
||||||
"v": "3",
|
|
||||||
"endpoint": "https://echo.hoppscotch.io",
|
|
||||||
"headers": [
|
|
||||||
{
|
|
||||||
"key": "Inactive-Header",
|
|
||||||
"value": "Inactive Header",
|
|
||||||
"active": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "Authorization",
|
|
||||||
"value": "Bearer token123",
|
|
||||||
"active": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"params": [
|
|
||||||
{
|
|
||||||
"key": "key",
|
|
||||||
"value": "value",
|
|
||||||
"active": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "inactive-key",
|
|
||||||
"value": "inactive-param",
|
|
||||||
"active": false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "req-v3",
|
|
||||||
"method": "GET",
|
|
||||||
"preRequestScript": "",
|
|
||||||
"testScript": "pw.test(\"Asserts request params\", () => {\n pw.expect(pw.response.body.args.key).toBe(\"value\")\n pw.expect(pw.response.body.args[\"inactive-key\"]).toBe(undefined)\n})\n\npw.test(\"Asserts request headers\", () => {\n pw.expect(pw.response.body.headers[\"authorization\"]).toBe(\"Bearer token123\")\n pw.expect(pw.response.body.headers[\"inactive-header\"]).toBe(undefined)\n})",
|
|
||||||
"body": {
|
|
||||||
"contentType": null,
|
|
||||||
"body": null
|
|
||||||
},
|
|
||||||
"auth": {
|
|
||||||
"authType": "bearer",
|
|
||||||
"authActive": true,
|
|
||||||
"token": "token123"
|
|
||||||
},
|
|
||||||
"requestVariables": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"auth": {
|
|
||||||
"authType": "inherit",
|
|
||||||
"authActive": true
|
|
||||||
},
|
|
||||||
"headers": []
|
|
||||||
}
|
|
||||||
@@ -1,23 +1,23 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"v": 2,
|
"v": 1,
|
||||||
"name": "CollectionA",
|
"name": "CollectionA",
|
||||||
"folders": [
|
"folders": [
|
||||||
{
|
{
|
||||||
"v": 2,
|
"v": 1,
|
||||||
"name": "FolderA",
|
"name": "FolderA",
|
||||||
"folders": [
|
"folders": [
|
||||||
{
|
{
|
||||||
"v": 2,
|
"v": 1,
|
||||||
"name": "FolderB",
|
"name": "FolderB",
|
||||||
"folders": [
|
"folders": [
|
||||||
{
|
{
|
||||||
"v": 2,
|
"v": 1,
|
||||||
"name": "FolderC",
|
"name": "FolderC",
|
||||||
"folders": [],
|
"folders": [],
|
||||||
"requests": [
|
"requests": [
|
||||||
{
|
{
|
||||||
"v": "3",
|
"v": "1",
|
||||||
"endpoint": "https://echo.hoppscotch.io",
|
"endpoint": "https://echo.hoppscotch.io",
|
||||||
"name": "RequestD",
|
"name": "RequestD",
|
||||||
"params": [],
|
"params": [],
|
||||||
@@ -40,8 +40,7 @@
|
|||||||
"body": {
|
"body": {
|
||||||
"contentType": null,
|
"contentType": null,
|
||||||
"body": null
|
"body": null
|
||||||
},
|
}
|
||||||
"requestVariables": []
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"auth": {
|
"auth": {
|
||||||
@@ -53,7 +52,7 @@
|
|||||||
],
|
],
|
||||||
"requests": [
|
"requests": [
|
||||||
{
|
{
|
||||||
"v": "3",
|
"v": "1",
|
||||||
"endpoint": "https://echo.hoppscotch.io",
|
"endpoint": "https://echo.hoppscotch.io",
|
||||||
"name": "RequestC",
|
"name": "RequestC",
|
||||||
"params": [],
|
"params": [],
|
||||||
@@ -68,14 +67,13 @@
|
|||||||
"body": {
|
"body": {
|
||||||
"contentType": null,
|
"contentType": null,
|
||||||
"body": null
|
"body": null
|
||||||
},
|
}
|
||||||
"requestVariables": []
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"auth": {
|
"auth": {
|
||||||
"authType": "api-key",
|
"authType": "api-key",
|
||||||
"authActive": true,
|
"authActive": true,
|
||||||
"addTo": "HEADERS",
|
"addTo": "Headers",
|
||||||
"key": "key",
|
"key": "key",
|
||||||
"value": "test-key"
|
"value": "test-key"
|
||||||
},
|
},
|
||||||
@@ -90,7 +88,7 @@
|
|||||||
],
|
],
|
||||||
"requests": [
|
"requests": [
|
||||||
{
|
{
|
||||||
"v": "3",
|
"v": "1",
|
||||||
"endpoint": "https://echo.hoppscotch.io",
|
"endpoint": "https://echo.hoppscotch.io",
|
||||||
"name": "RequestB",
|
"name": "RequestB",
|
||||||
"params": [],
|
"params": [],
|
||||||
@@ -106,7 +104,6 @@
|
|||||||
"contentType": null,
|
"contentType": null,
|
||||||
"body": null
|
"body": null
|
||||||
},
|
},
|
||||||
"requestVariables": [],
|
|
||||||
"id": "clpttpdq00003qp16kut6doqv"
|
"id": "clpttpdq00003qp16kut6doqv"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -119,7 +116,7 @@
|
|||||||
],
|
],
|
||||||
"requests": [
|
"requests": [
|
||||||
{
|
{
|
||||||
"v": "3",
|
"v": "1",
|
||||||
"endpoint": "https://echo.hoppscotch.io",
|
"endpoint": "https://echo.hoppscotch.io",
|
||||||
"name": "RequestA",
|
"name": "RequestA",
|
||||||
"params": [],
|
"params": [],
|
||||||
@@ -135,7 +132,6 @@
|
|||||||
"contentType": null,
|
"contentType": null,
|
||||||
"body": null
|
"body": null
|
||||||
},
|
},
|
||||||
"requestVariables": [],
|
|
||||||
"id": "clpttpdq00003qp16kut6doqv"
|
"id": "clpttpdq00003qp16kut6doqv"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -153,16 +149,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"v": 2,
|
"v": 1,
|
||||||
"name": "CollectionB",
|
"name": "CollectionB",
|
||||||
"folders": [
|
"folders": [
|
||||||
{
|
{
|
||||||
"v": 2,
|
"v": 1,
|
||||||
"name": "FolderA",
|
"name": "FolderA",
|
||||||
"folders": [],
|
"folders": [],
|
||||||
"requests": [
|
"requests": [
|
||||||
{
|
{
|
||||||
"v": "3",
|
"v": "1",
|
||||||
"endpoint": "https://echo.hoppscotch.io",
|
"endpoint": "https://echo.hoppscotch.io",
|
||||||
"name": "RequestB",
|
"name": "RequestB",
|
||||||
"params": [],
|
"params": [],
|
||||||
@@ -178,7 +174,6 @@
|
|||||||
"contentType": null,
|
"contentType": null,
|
||||||
"body": null
|
"body": null
|
||||||
},
|
},
|
||||||
"requestVariables": [],
|
|
||||||
"id": "clpttpdq00003qp16kut6doqv"
|
"id": "clpttpdq00003qp16kut6doqv"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -191,7 +186,7 @@
|
|||||||
],
|
],
|
||||||
"requests": [
|
"requests": [
|
||||||
{
|
{
|
||||||
"v": "3",
|
"v": "1",
|
||||||
"endpoint": "https://echo.hoppscotch.io",
|
"endpoint": "https://echo.hoppscotch.io",
|
||||||
"name": "RequestA",
|
"name": "RequestA",
|
||||||
"params": [],
|
"params": [],
|
||||||
@@ -207,7 +202,6 @@
|
|||||||
"contentType": null,
|
"contentType": null,
|
||||||
"body": null
|
"body": null
|
||||||
},
|
},
|
||||||
"requestVariables": [],
|
|
||||||
"id": "clpttpdq00003qp16kut6doqv"
|
"id": "clpttpdq00003qp16kut6doqv"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"folders": [],
|
"folders": [],
|
||||||
"requests": [
|
"requests": [
|
||||||
{
|
{
|
||||||
"v": "3",
|
"v": "1",
|
||||||
"endpoint": "<<URL>>",
|
"endpoint": "<<URL>>",
|
||||||
"name": "test1",
|
"name": "test1",
|
||||||
"params": [],
|
"params": [],
|
||||||
@@ -16,8 +16,7 @@
|
|||||||
"body": {
|
"body": {
|
||||||
"contentType": "application/json",
|
"contentType": "application/json",
|
||||||
"body": "{\n \"<<BODY_KEY>>\":\"<<BODY_VALUE>>\"\n}"
|
"body": "{\n \"<<BODY_KEY>>\":\"<<BODY_VALUE>>\"\n}"
|
||||||
},
|
}
|
||||||
"requestVariables": []
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
"folders": [],
|
"folders": [],
|
||||||
"requests": [
|
"requests": [
|
||||||
{
|
{
|
||||||
"v": "3",
|
"v": "1",
|
||||||
"endpoint": "https://echo.hoppscotch.io/<<HEADERS_TYPE1>>",
|
"endpoint": "https://echo.hoppscotch.io/<<HEADERS_TYPE1>>",
|
||||||
"name": "",
|
"name": "",
|
||||||
"params": [],
|
"params": [],
|
||||||
@@ -13,18 +13,20 @@
|
|||||||
"method": "GET",
|
"method": "GET",
|
||||||
"auth": {
|
"auth": {
|
||||||
"authType": "none",
|
"authType": "none",
|
||||||
"authActive": true
|
"authActive": true,
|
||||||
|
"addTo": "Headers",
|
||||||
|
"key": "",
|
||||||
|
"value": ""
|
||||||
},
|
},
|
||||||
"preRequestScript": "pw.env.set(\"HEADERS_TYPE1\", \"devblin_local1\");",
|
"preRequestScript": "pw.env.set(\"HEADERS_TYPE1\", \"devblin_local1\");",
|
||||||
"testScript": "// Check status code is 200\npwd.test(\"Status code is 200\", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\n// Check JSON response property\npw.test(\"Check JSON response property\", ()=> {\n pw.expect(pw.response.body.method).toBe(\"GET\");\n pw.expect(pw.response.body.headers).toBeType(\"string\");\n});",
|
"testScript": "// Check status code is 200\npwd.test(\"Status code is 200\", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\n// Check JSON response property\npw.test(\"Check JSON response property\", ()=> {\n pw.expect(pw.response.body.method).toBe(\"GET\");\n pw.expect(pw.response.body.headers).toBeType(\"string\");\n});",
|
||||||
"body": {
|
"body": {
|
||||||
"contentType": "application/json",
|
"contentType": "application/json",
|
||||||
"body": "{\n\"test\": \"<<HEADERS_TYPE1>>\"\n}"
|
"body": "{\n\"test\": \"<<HEADERS_TYPE1>>\"\n}"
|
||||||
},
|
}
|
||||||
"requestVariables": []
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"v": "3",
|
"v": "1",
|
||||||
"endpoint": "https://echo.hoppscotch.dio/<<HEADERS_TYPE2>>",
|
"endpoint": "https://echo.hoppscotch.dio/<<HEADERS_TYPE2>>",
|
||||||
"name": "success",
|
"name": "success",
|
||||||
"params": [],
|
"params": [],
|
||||||
@@ -32,15 +34,17 @@
|
|||||||
"method": "GET",
|
"method": "GET",
|
||||||
"auth": {
|
"auth": {
|
||||||
"authType": "none",
|
"authType": "none",
|
||||||
"authActive": true
|
"authActive": true,
|
||||||
|
"addTo": "Headers",
|
||||||
|
"key": "",
|
||||||
|
"value": ""
|
||||||
},
|
},
|
||||||
"preRequestScript": "pw.env.setd(\"HEADERS_TYPE2\", \"devblin_local2\");",
|
"preRequestScript": "pw.env.setd(\"HEADERS_TYPE2\", \"devblin_local2\");",
|
||||||
"testScript": "// Check status code is 200\npw.test(\"Status code is 200\", ()=> {\n pw.expect(pw.response.status).toBe(300);\n});\n\n// Check JSON response property\npw.test(\"Check JSON response property\", ()=> {\n pw.expect(pw.response.body.method).toBe(\"GET\");\n pw.expect(pw.response.body.headers).toBeType(\"object\");\n});",
|
"testScript": "// Check status code is 200\npw.test(\"Status code is 200\", ()=> {\n pw.expect(pw.response.status).toBe(300);\n});\n\n// Check JSON response property\npw.test(\"Check JSON response property\", ()=> {\n pw.expect(pw.response.body.method).toBe(\"GET\");\n pw.expect(pw.response.body.headers).toBeType(\"object\");\n});",
|
||||||
"body": {
|
"body": {
|
||||||
"contentType": "application/json",
|
"contentType": "application/json",
|
||||||
"body": "{\n\"test\": \"<<HEADERS_TYPE2>>\"\n}"
|
"body": "{\n\"test\": \"<<HEADERS_TYPE2>>\"\n}"
|
||||||
},
|
}
|
||||||
"requestVariables": []
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"folders": [],
|
"folders": [],
|
||||||
"requests":
|
"requests":
|
||||||
{
|
{
|
||||||
"v": "3",
|
"v": "1",
|
||||||
"endpoint": "https://echo.hoppscotch.io/<<HEADERS_TYPE1>>",
|
"endpoint": "https://echo.hoppscotch.io/<<HEADERS_TYPE1>>",
|
||||||
"name": "fail",
|
"name": "fail",
|
||||||
"params": [],
|
"params": [],
|
||||||
@@ -12,18 +12,20 @@
|
|||||||
"method": "GET",
|
"method": "GET",
|
||||||
"auth": {
|
"auth": {
|
||||||
"authType": "none",
|
"authType": "none",
|
||||||
"authActive": true
|
"authActive": true,
|
||||||
|
"addTo": "Headers",
|
||||||
|
"key": "",
|
||||||
|
"value": ""
|
||||||
},
|
},
|
||||||
"preRequestScript": "pw.env.set(\"HEADERS_TYPE1\", \"devblin_local1\");",
|
"preRequestScript": "pw.env.set(\"HEADERS_TYPE1\", \"devblin_local1\");",
|
||||||
"testScript": "// Check status code is 200\npw.test(\"Status code is 200\", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\n// Check JSON response property\npw.test(\"Check JSON response property\", ()=> {\n pw.expect(pw.response.body.method).toBe(\"GET\");\n pw.expect(pw.response.body.headers).toBeType(\"string\");\n});",
|
"testScript": "// Check status code is 200\npw.test(\"Status code is 200\", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\n// Check JSON response property\npw.test(\"Check JSON response property\", ()=> {\n pw.expect(pw.response.body.method).toBe(\"GET\");\n pw.expect(pw.response.body.headers).toBeType(\"string\");\n});",
|
||||||
"body": {
|
"body": {
|
||||||
"contentType": "application/json",
|
"contentType": "application/json",
|
||||||
"body": "{\n\"test\": \"<<HEADERS_TYPE1>>\"\n}"
|
"body": "{\n\"test\": \"<<HEADERS_TYPE1>>\"\n}"
|
||||||
},
|
}
|
||||||
"requestVariables": [],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"v": "3",
|
"v": "1",
|
||||||
"endpoint": "https://echo.hoppscotch.io/<<HEADERS_TYPE2>>",
|
"endpoint": "https://echo.hoppscotch.io/<<HEADERS_TYPE2>>",
|
||||||
"name": "success",
|
"name": "success",
|
||||||
"params": [],
|
"params": [],
|
||||||
@@ -31,15 +33,17 @@
|
|||||||
"method": "GET",
|
"method": "GET",
|
||||||
"auth": {
|
"auth": {
|
||||||
"authType": "none",
|
"authType": "none",
|
||||||
"authActive": true
|
"authActive": true,
|
||||||
|
"addTo": "Headers",
|
||||||
|
"key": "",
|
||||||
|
"value": ""
|
||||||
},
|
},
|
||||||
"preRequestScript": "pw.env.set(\"HEADERS_TYPE2\", \"devblin_local2\");",
|
"preRequestScript": "pw.env.set(\"HEADERS_TYPE2\", \"devblin_local2\");",
|
||||||
"testScript": "// Check status code is 200\npw.test(\"Status code is 200\", ()=> {\n pw.expect(pw.response.status).toBe(300);\n});\n\n// Check JSON response property\npw.test(\"Check JSON response property\", ()=> {\n pw.expect(pw.response.body.method).toBe(\"GET\");\n pw.expect(pw.response.body.headers).toBeType(\"object\");\n});",
|
"testScript": "// Check status code is 200\npw.test(\"Status code is 200\", ()=> {\n pw.expect(pw.response.status).toBe(300);\n});\n\n// Check JSON response property\npw.test(\"Check JSON response property\", ()=> {\n pw.expect(pw.response.body.method).toBe(\"GET\");\n pw.expect(pw.response.body.headers).toBeType(\"object\");\n});",
|
||||||
"body": {
|
"body": {
|
||||||
"contentType": "application/json",
|
"contentType": "application/json",
|
||||||
"body": "{\n\"test\": \"<<HEADERS_TYPE2>>\"\n}"
|
"body": "{\n\"test\": \"<<HEADERS_TYPE2>>\"\n}"
|
||||||
},
|
}
|
||||||
"requestVariables": []
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"folders": [],
|
"folders": [],
|
||||||
"requests":
|
"requests":
|
||||||
{
|
{
|
||||||
"v": "2",
|
"v": "1",
|
||||||
"endpoint": "https://echo.hoppscotch.io/<<HEADERS_TYPE1>>",
|
"endpoint": "https://echo.hoppscotch.io/<<HEADERS_TYPE1>>",
|
||||||
"name": "fail",
|
"name": "fail",
|
||||||
"params": [],
|
"params": [],
|
||||||
@@ -22,8 +22,7 @@
|
|||||||
"body": {
|
"body": {
|
||||||
"contentType": "application/json",
|
"contentType": "application/json",
|
||||||
"body": "{\n\"test\": \"<<HEADERS_TYPE1>>\"\n}"
|
"body": "{\n\"test\": \"<<HEADERS_TYPE1>>\"\n}"
|
||||||
},
|
}
|
||||||
"requestVariables": []
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
"folders": [],
|
"folders": [],
|
||||||
"requests": [
|
"requests": [
|
||||||
{
|
{
|
||||||
"v": "3",
|
"v": "1",
|
||||||
"endpoint": "https://echo.hoppscotch.io/<<HEADERS_TYPE1>>",
|
"endpoint": "https://echo.hoppscotch.io/<<HEADERS_TYPE1>>",
|
||||||
"name": "",
|
"name": "",
|
||||||
"params": [],
|
"params": [],
|
||||||
@@ -13,18 +13,20 @@
|
|||||||
"method": "GET",
|
"method": "GET",
|
||||||
"auth": {
|
"auth": {
|
||||||
"authType": "none",
|
"authType": "none",
|
||||||
"authActive": true
|
"authActive": true,
|
||||||
|
"addTo": "Headers",
|
||||||
|
"key": "",
|
||||||
|
"value": ""
|
||||||
},
|
},
|
||||||
"preRequestScript": "pw.env.set(\"HEADERS_TYPE1\", \"devblin_local1\");",
|
"preRequestScript": "pw.env.set(\"HEADERS_TYPE1\", \"devblin_local1\");",
|
||||||
"testScript": "// Check status code is 200\npw.test(\"Status code is 200\", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\n// Check JSON response property\npw.test(\"Check JSON response property\", ()=> {\n pw.expect(pw.response.body.method).toBe(\"GET\");\n pw.expect(pw.response.body.headers).toBeType(\"object\");\n});",
|
"testScript": "// Check status code is 200\npw.test(\"Status code is 200\", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\n// Check JSON response property\npw.test(\"Check JSON response property\", ()=> {\n pw.expect(pw.response.body.method).toBe(\"GET\");\n pw.expect(pw.response.body.headers).toBeType(\"object\");\n});",
|
||||||
"body": {
|
"body": {
|
||||||
"contentType": "application/json",
|
"contentType": "application/json",
|
||||||
"body": "{\n\"test\": \"<<HEADERS_TYPE1>>\"\n}"
|
"body": "{\n\"test\": \"<<HEADERS_TYPE1>>\"\n}"
|
||||||
},
|
}
|
||||||
"requestVariables": []
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"v": "3",
|
"v": "1",
|
||||||
"endpoint": "https://echo.hoppscotch.io/<<HEADERS_TYPE2>>",
|
"endpoint": "https://echo.hoppscotch.io/<<HEADERS_TYPE2>>",
|
||||||
"name": "success",
|
"name": "success",
|
||||||
"params": [],
|
"params": [],
|
||||||
@@ -32,15 +34,17 @@
|
|||||||
"method": "GET",
|
"method": "GET",
|
||||||
"auth": {
|
"auth": {
|
||||||
"authType": "none",
|
"authType": "none",
|
||||||
"authActive": true
|
"authActive": true,
|
||||||
|
"addTo": "Headers",
|
||||||
|
"key": "",
|
||||||
|
"value": ""
|
||||||
},
|
},
|
||||||
"preRequestScript": "pw.env.set(\"HEADERS_TYPE2\", \"devblin_local2\");",
|
"preRequestScript": "pw.env.set(\"HEADERS_TYPE2\", \"devblin_local2\");",
|
||||||
"testScript": "// Check status code is 200\npw.test(\"Status code is 200\", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\n// Check JSON response property\npw.test(\"Check JSON response property\", ()=> {\n pw.expect(pw.response.body.method).toBe(\"GET\");\n pw.expect(pw.response.body.headers).toBeType(\"object\");\n});",
|
"testScript": "// Check status code is 200\npw.test(\"Status code is 200\", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\n// Check JSON response property\npw.test(\"Check JSON response property\", ()=> {\n pw.expect(pw.response.body.method).toBe(\"GET\");\n pw.expect(pw.response.body.headers).toBeType(\"object\");\n});",
|
||||||
"body": {
|
"body": {
|
||||||
"contentType": "application/json",
|
"contentType": "application/json",
|
||||||
"body": "{\n\"test\": \"<<HEADERS_TYPE2>>\"\n}"
|
"body": "{\n\"test\": \"<<HEADERS_TYPE2>>\"\n}"
|
||||||
},
|
}
|
||||||
"requestVariables": []
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"folders": [],
|
"folders": [],
|
||||||
"requests": [
|
"requests": [
|
||||||
{
|
{
|
||||||
"v": "3",
|
"v": "1",
|
||||||
"auth": { "authType": "none", "authActive": true },
|
"auth": { "authType": "none", "authActive": true },
|
||||||
"body": { "body": null, "contentType": null },
|
"body": { "body": null, "contentType": null },
|
||||||
"name": "sample-req",
|
"name": "sample-req",
|
||||||
@@ -13,8 +13,7 @@
|
|||||||
"headers": [],
|
"headers": [],
|
||||||
"endpoint": "https://echo.hoppscotch.io",
|
"endpoint": "https://echo.hoppscotch.io",
|
||||||
"testScript": "pw.expect(pw.env.get(\"variable\")).toBe(\"value\")",
|
"testScript": "pw.expect(pw.env.get(\"variable\")).toBe(\"value\")",
|
||||||
"preRequestScript": "pw.env.set(\"variable\", \"value\");",
|
"preRequestScript": "pw.env.set(\"variable\", \"value\");"
|
||||||
"requestVariables": []
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"auth": { "authType": "inherit", "authActive": true },
|
"auth": { "authType": "inherit", "authActive": true },
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"folders": [],
|
"folders": [],
|
||||||
"requests": [
|
"requests": [
|
||||||
{
|
{
|
||||||
"v": "3",
|
"v": "1",
|
||||||
"name": "test-request",
|
"name": "test-request",
|
||||||
"endpoint": "https://echo.hoppscotch.io",
|
"endpoint": "https://echo.hoppscotch.io",
|
||||||
"method": "POST",
|
"method": "POST",
|
||||||
@@ -19,8 +19,7 @@
|
|||||||
"body": "{\n \"firstName\": \"<<firstName>>\",\n \"lastName\": \"<<lastName>>\",\n \"greetText\": \"<<salutation>>, <<fullName>>\",\n \"fullName\": \"<<fullName>>\",\n \"id\": \"<<id>>\"\n}"
|
"body": "{\n \"firstName\": \"<<firstName>>\",\n \"lastName\": \"<<lastName>>\",\n \"greetText\": \"<<salutation>>, <<fullName>>\",\n \"fullName\": \"<<fullName>>\",\n \"id\": \"<<id>>\"\n}"
|
||||||
},
|
},
|
||||||
"preRequestScript": "",
|
"preRequestScript": "",
|
||||||
"testScript": "pw.test(\"Status code is 200\", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\npw.test(\"Successfully resolves environments recursively\", ()=> {\n pw.expect(pw.env.getResolve(\"recursiveVarX\")).toBe(\"Hello\")\n pw.expect(pw.env.getResolve(\"recursiveVarY\")).toBe(\"Hello\")\n pw.expect(pw.env.getResolve(\"salutation\")).toBe(\"Hello\")\n});\n\npw.test(\"Successfully resolves environments referenced in the request body\", () => {\n const expectedId = \"7\"\n const expectedFirstName = \"John\"\n const expectedLastName = \"Doe\"\n const expectedFullName = `${expectedFirstName} ${expectedLastName}`\n const expectedGreetText = `Hello, ${expectedFullName}`\n\n pw.expect(pw.env.getResolve(\"recursiveVarX\")).toBe(\"Hello\")\n pw.expect(pw.env.getResolve(\"recursiveVarY\")).toBe(\"Hello\")\n pw.expect(pw.env.getResolve(\"salutation\")).toBe(\"Hello\")\n\n const { id, firstName, lastName, fullName, greetText } = JSON.parse(pw.response.body.data)\n\n pw.expect(id).toBe(expectedId)\n pw.expect(expectedFirstName).toBe(firstName)\n pw.expect(expectedLastName).toBe(lastName)\n pw.expect(fullName).toBe(expectedFullName)\n pw.expect(greetText).toBe(expectedGreetText)\n});",
|
"testScript": "pw.test(\"Status code is 200\", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\npw.test(\"Successfully resolves environments recursively\", ()=> {\n pw.expect(pw.env.getResolve(\"recursiveVarX\")).toBe(\"Hello\")\n pw.expect(pw.env.getResolve(\"recursiveVarY\")).toBe(\"Hello\")\n pw.expect(pw.env.getResolve(\"salutation\")).toBe(\"Hello\")\n});\n\npw.test(\"Successfully resolves environments referenced in the request body\", () => {\n const expectedId = \"7\"\n const expectedFirstName = \"John\"\n const expectedLastName = \"Doe\"\n const expectedFullName = `${expectedFirstName} ${expectedLastName}`\n const expectedGreetText = `Hello, ${expectedFullName}`\n\n pw.expect(pw.env.getResolve(\"recursiveVarX\")).toBe(\"Hello\")\n pw.expect(pw.env.getResolve(\"recursiveVarY\")).toBe(\"Hello\")\n pw.expect(pw.env.getResolve(\"salutation\")).toBe(\"Hello\")\n\n const { id, firstName, lastName, fullName, greetText } = JSON.parse(pw.response.body.data)\n\n pw.expect(id).toBe(expectedId)\n pw.expect(expectedFirstName).toBe(firstName)\n pw.expect(expectedLastName).toBe(lastName)\n pw.expect(fullName).toBe(expectedFullName)\n pw.expect(greetText).toBe(expectedGreetText)\n});"
|
||||||
"requestVariables": []
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"auth": {
|
"auth": {
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
{
|
|
||||||
"v": 1,
|
|
||||||
"name": "tests",
|
|
||||||
"folders": [],
|
|
||||||
"requests": [
|
|
||||||
{
|
|
||||||
"v": "2",
|
|
||||||
"endpoint": "<<baseURL>>",
|
|
||||||
"name": "",
|
|
||||||
"params": [],
|
|
||||||
"headers": [],
|
|
||||||
"method": "GET",
|
|
||||||
"auth": {
|
|
||||||
"authType": "none",
|
|
||||||
"authActive": true
|
|
||||||
},
|
|
||||||
"preRequestScript": "",
|
|
||||||
"testScript": "// Check status code is 200\npw.test(\"Status code is 200\", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\n// Check JSON response property\npw.test(\"Check JSON response property\", ()=> {\n pw.expect(pw.response.body.method).toBe(\"GET\");\n pw.expect(pw.response.body.headers).toBeType(\"object\");\n});",
|
|
||||||
"body": {
|
|
||||||
"contentType": null,
|
|
||||||
"body": null
|
|
||||||
},
|
|
||||||
"requestVariables": []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -4,15 +4,9 @@
|
|||||||
"folders": [],
|
"folders": [],
|
||||||
"requests": [
|
"requests": [
|
||||||
{
|
{
|
||||||
"v": "3",
|
"v": "1",
|
||||||
"auth": {
|
"auth": { "authType": "none", "authActive": true },
|
||||||
"authType": "none",
|
"body": { "body": null, "contentType": null },
|
||||||
"authActive": true
|
|
||||||
},
|
|
||||||
"body": {
|
|
||||||
"body": null,
|
|
||||||
"contentType": null
|
|
||||||
},
|
|
||||||
"name": "test-secret-headers",
|
"name": "test-secret-headers",
|
||||||
"method": "GET",
|
"method": "GET",
|
||||||
"params": [],
|
"params": [],
|
||||||
@@ -23,17 +17,13 @@
|
|||||||
"active": true
|
"active": true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"requestVariables": [],
|
"endpoint": "<<baseURL>>/headers",
|
||||||
"endpoint": "<<echoHoppBaseURL>>/headers",
|
"testScript": "pw.test(\"Successfully parses secret variable holding the header value\", () => {\n const secretHeaderValue = pw.env.get(\"secretHeaderValue\")\n pw.expect(secretHeaderValue).toBe(\"secret-header-value\")\n \n if (secretHeaderValue) {\n pw.expect(pw.response.body.headers[\"Secret-Header-Key\"]).toBe(secretHeaderValue)\n }\n\n pw.expect(pw.env.get(\"secretHeaderValueFromPreReqScript\")).toBe(\"secret-header-value\")\n})",
|
||||||
"testScript": "pw.test(\"Successfully parses secret variable holding the header value\", () => {\n const secretHeaderValue = pw.env.get(\"secretHeaderValue\")\n pw.expect(secretHeaderValue).toBe(\"secret-header-value\")\n \n if (secretHeaderValue) {\n pw.expect(pw.response.body.headers[\"secret-header-key\"]).toBe(secretHeaderValue)\n }\n\n pw.expect(pw.env.get(\"secretHeaderValueFromPreReqScript\")).toBe(\"secret-header-value\")\n})",
|
|
||||||
"preRequestScript": "const secretHeaderValueFromPreReqScript = pw.env.get(\"secretHeaderValue\")\npw.env.set(\"secretHeaderValueFromPreReqScript\", secretHeaderValueFromPreReqScript)"
|
"preRequestScript": "const secretHeaderValueFromPreReqScript = pw.env.get(\"secretHeaderValue\")\npw.env.set(\"secretHeaderValueFromPreReqScript\", secretHeaderValueFromPreReqScript)"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"v": "3",
|
"v": "1",
|
||||||
"auth": {
|
"auth": { "authType": "none", "authActive": true },
|
||||||
"authType": "none",
|
|
||||||
"authActive": true
|
|
||||||
},
|
|
||||||
"body": {
|
"body": {
|
||||||
"body": "{\n \"secretBodyKey\": \"<<secretBodyValue>>\"\n}",
|
"body": "{\n \"secretBodyKey\": \"<<secretBodyValue>>\"\n}",
|
||||||
"contentType": "application/json"
|
"contentType": "application/json"
|
||||||
@@ -42,21 +32,14 @@
|
|||||||
"method": "POST",
|
"method": "POST",
|
||||||
"params": [],
|
"params": [],
|
||||||
"headers": [],
|
"headers": [],
|
||||||
"requestVariables": [],
|
"endpoint": "<<baseURL>>/post",
|
||||||
"endpoint": "<<echoHoppBaseURL>>/post",
|
"testScript": "pw.test(\"Successfully parses secret variable holding the request body value\", () => {\n const secretBodyValue = pw.env.get(\"secretBodyValue\")\n pw.expect(secretBodyValue).toBe(\"secret-body-value\")\n \n if (secretBodyValue) {\n pw.expect(pw.response.body.json.secretBodyKey).toBe(secretBodyValue)\n }\n\n pw.expect(pw.env.get(\"secretBodyValueFromPreReqScript\")).toBe(\"secret-body-value\")\n})",
|
||||||
"testScript": "pw.test(\"Successfully parses secret variable holding the request body value\", () => {\n const secretBodyValue = pw.env.get(\"secretBodyValue\")\n pw.expect(secretBodyValue).toBe(\"secret-body-value\")\n \n if (secretBodyValue) {\n pw.expect(JSON.parse(pw.response.body.data).secretBodyKey).toBe(secretBodyValue)\n }\n\n pw.expect(pw.env.get(\"secretBodyValueFromPreReqScript\")).toBe(\"secret-body-value\")\n})",
|
|
||||||
"preRequestScript": "const secretBodyValueFromPreReqScript = pw.env.get(\"secretBodyValue\")\npw.env.set(\"secretBodyValueFromPreReqScript\", secretBodyValueFromPreReqScript)"
|
"preRequestScript": "const secretBodyValueFromPreReqScript = pw.env.get(\"secretBodyValue\")\npw.env.set(\"secretBodyValueFromPreReqScript\", secretBodyValueFromPreReqScript)"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"v": "3",
|
"v": "1",
|
||||||
"auth": {
|
"auth": { "authType": "none", "authActive": true },
|
||||||
"authType": "none",
|
"body": { "body": null, "contentType": null },
|
||||||
"authActive": true
|
|
||||||
},
|
|
||||||
"body": {
|
|
||||||
"body": null,
|
|
||||||
"contentType": null
|
|
||||||
},
|
|
||||||
"name": "test-secret-query-params",
|
"name": "test-secret-query-params",
|
||||||
"method": "GET",
|
"method": "GET",
|
||||||
"params": [
|
"params": [
|
||||||
@@ -67,34 +50,29 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"headers": [],
|
"headers": [],
|
||||||
"requestVariables": [],
|
"endpoint": "<<baseURL>>/get",
|
||||||
"endpoint": "<<echoHoppBaseURL>>",
|
|
||||||
"testScript": "pw.test(\"Successfully parses secret variable holding the query param value\", () => {\n const secretQueryParamValue = pw.env.get(\"secretQueryParamValue\")\n pw.expect(secretQueryParamValue).toBe(\"secret-query-param-value\")\n \n if (secretQueryParamValue) {\n pw.expect(pw.response.body.args.secretQueryParamKey).toBe(secretQueryParamValue)\n }\n\n pw.expect(pw.env.get(\"secretQueryParamValueFromPreReqScript\")).toBe(\"secret-query-param-value\")\n})",
|
"testScript": "pw.test(\"Successfully parses secret variable holding the query param value\", () => {\n const secretQueryParamValue = pw.env.get(\"secretQueryParamValue\")\n pw.expect(secretQueryParamValue).toBe(\"secret-query-param-value\")\n \n if (secretQueryParamValue) {\n pw.expect(pw.response.body.args.secretQueryParamKey).toBe(secretQueryParamValue)\n }\n\n pw.expect(pw.env.get(\"secretQueryParamValueFromPreReqScript\")).toBe(\"secret-query-param-value\")\n})",
|
||||||
"preRequestScript": "const secretQueryParamValueFromPreReqScript = pw.env.get(\"secretQueryParamValue\")\npw.env.set(\"secretQueryParamValueFromPreReqScript\", secretQueryParamValueFromPreReqScript)"
|
"preRequestScript": "const secretQueryParamValueFromPreReqScript = pw.env.get(\"secretQueryParamValue\")\npw.env.set(\"secretQueryParamValueFromPreReqScript\", secretQueryParamValueFromPreReqScript)"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"v": "3",
|
"v": "1",
|
||||||
"auth": {
|
"auth": {
|
||||||
"authType": "basic",
|
"authType": "basic",
|
||||||
"password": "<<secretBasicAuthPassword>>",
|
"password": "<<secretBasicAuthPassword>>",
|
||||||
"username": "<<secretBasicAuthUsername>>",
|
"username": "<<secretBasicAuthUsername>>",
|
||||||
"authActive": true
|
"authActive": true
|
||||||
},
|
},
|
||||||
"body": {
|
"body": { "body": null, "contentType": null },
|
||||||
"body": null,
|
|
||||||
"contentType": null
|
|
||||||
},
|
|
||||||
"name": "test-secret-basic-auth",
|
"name": "test-secret-basic-auth",
|
||||||
"method": "GET",
|
"method": "GET",
|
||||||
"params": [],
|
"params": [],
|
||||||
"headers": [],
|
"headers": [],
|
||||||
"requestVariables": [],
|
"endpoint": "<<baseURL>>/basic-auth/<<secretBasicAuthUsername>>/<<secretBasicAuthPassword>>",
|
||||||
"endpoint": "<<httpbinBaseURL>>/basic-auth/<<secretBasicAuthUsername>>/<<secretBasicAuthPassword>>",
|
"testScript": "pw.test(\"Successfully parses secret variables holding basic auth credentials\", () => {\n\tconst secretBasicAuthUsername = pw.env.get(\"secretBasicAuthUsername\")\n \tconst secretBasicAuthPassword = pw.env.get(\"secretBasicAuthPassword\")\n\n pw.expect(secretBasicAuthUsername).toBe(\"test-user\")\n pw.expect(secretBasicAuthPassword).toBe(\"test-pass\")\n\n if (secretBasicAuthUsername && secretBasicAuthPassword) {\n const { authenticated, user } = pw.response.body\n pw.expect(authenticated).toBe(true)\n pw.expect(user).toBe(secretBasicAuthUsername)\n }\n});",
|
||||||
"testScript": "pw.test(\"Successfully parses secret variables holding basic auth credentials\", () => {\n\tconst secretBasicAuthUsername = pw.env.get(\"secretBasicAuthUsername\")\n \tconst secretBasicAuthPassword = pw.env.get(\"secretBasicAuthPassword\")\n\n pw.expect(secretBasicAuthUsername).toBe(\"test-user\")\n pw.expect(secretBasicAuthPassword).toBe(\"test-pass\")\n\n // The endpoint at times results in a `502` bad gateway\n if (pw.response.status !== 200) {\n return\n }\n\n if (secretBasicAuthUsername && secretBasicAuthPassword) {\n const { authenticated, user } = pw.response.body\n pw.expect(authenticated).toBe(true)\n pw.expect(user).toBe(secretBasicAuthUsername)\n }\n});",
|
|
||||||
"preRequestScript": ""
|
"preRequestScript": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"v": "3",
|
"v": "1",
|
||||||
"auth": {
|
"auth": {
|
||||||
"token": "<<secretBearerToken>>",
|
"token": "<<secretBearerToken>>",
|
||||||
"authType": "bearer",
|
"authType": "bearer",
|
||||||
@@ -102,42 +80,28 @@
|
|||||||
"username": "testuser",
|
"username": "testuser",
|
||||||
"authActive": true
|
"authActive": true
|
||||||
},
|
},
|
||||||
"body": {
|
"body": { "body": null, "contentType": null },
|
||||||
"body": null,
|
|
||||||
"contentType": null
|
|
||||||
},
|
|
||||||
"name": "test-secret-bearer-auth",
|
"name": "test-secret-bearer-auth",
|
||||||
"method": "GET",
|
"method": "GET",
|
||||||
"params": [],
|
"params": [],
|
||||||
"headers": [],
|
"headers": [],
|
||||||
"requestVariables": [],
|
"endpoint": "<<baseURL>>/bearer",
|
||||||
"endpoint": "<<httpbinBaseURL>>/bearer",
|
"testScript": "pw.test(\"Successfully parses secret variable holding the bearer token\", () => {\n const secretBearerToken = pw.env.get(\"secretBearerToken\")\n const preReqSecretBearerToken = pw.env.get(\"preReqSecretBearerToken\")\n\n pw.expect(secretBearerToken).toBe(\"test-token\")\n\n if (secretBearerToken) { \n pw.expect(pw.response.body.token).toBe(secretBearerToken)\n pw.expect(preReqSecretBearerToken).toBe(\"test-token\")\n }\n});",
|
||||||
"testScript": "pw.test(\"Successfully parses secret variable holding the bearer token\", () => {\n const secretBearerToken = pw.env.get(\"secretBearerToken\")\n const preReqSecretBearerToken = pw.env.get(\"preReqSecretBearerToken\")\n\n pw.expect(secretBearerToken).toBe(\"test-token\")\n\n // Safeguard to prevent test failures due to the endpoint\n if (pw.response.status !== 200) {\n return\n }\n\n if (secretBearerToken) { \n pw.expect(pw.response.body.token).toBe(secretBearerToken)\n pw.expect(preReqSecretBearerToken).toBe(\"test-token\")\n }\n});",
|
|
||||||
"preRequestScript": "const secretBearerToken = pw.env.get(\"secretBearerToken\")\npw.env.set(\"preReqSecretBearerToken\", secretBearerToken)"
|
"preRequestScript": "const secretBearerToken = pw.env.get(\"secretBearerToken\")\npw.env.set(\"preReqSecretBearerToken\", secretBearerToken)"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"v": "3",
|
"v": "1",
|
||||||
"auth": {
|
"auth": { "authType": "none", "authActive": true },
|
||||||
"authType": "none",
|
"body": { "body": null, "contentType": null },
|
||||||
"authActive": true
|
|
||||||
},
|
|
||||||
"body": {
|
|
||||||
"body": null,
|
|
||||||
"contentType": null
|
|
||||||
},
|
|
||||||
"name": "test-secret-fallback",
|
"name": "test-secret-fallback",
|
||||||
"method": "GET",
|
"method": "GET",
|
||||||
"params": [],
|
"params": [],
|
||||||
"headers": [],
|
"headers": [],
|
||||||
"requestVariables": [],
|
"endpoint": "<<baseURL>>",
|
||||||
"endpoint": "<<echoHoppBaseURL>>",
|
|
||||||
"testScript": "pw.test(\"Returns an empty string if the value for a secret environment variable is not found in the system environment\", () => {\n pw.expect(pw.env.get(\"nonExistentValueInSystemEnv\")).toBe(\"\")\n})",
|
"testScript": "pw.test(\"Returns an empty string if the value for a secret environment variable is not found in the system environment\", () => {\n pw.expect(pw.env.get(\"nonExistentValueInSystemEnv\")).toBe(\"\")\n})",
|
||||||
"preRequestScript": ""
|
"preRequestScript": ""
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"auth": {
|
"auth": { "authType": "inherit", "authActive": false },
|
||||||
"authType": "inherit",
|
|
||||||
"authActive": false
|
|
||||||
},
|
|
||||||
"headers": []
|
"headers": []
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"v": 2,
|
"v": 2,
|
||||||
"name": "secret-envs-persistence-coll",
|
"name": "secret-envs-setters-coll",
|
||||||
"folders": [],
|
"folders": [],
|
||||||
"requests": [
|
"requests": [
|
||||||
{
|
{
|
||||||
"v": "3",
|
"v": "1",
|
||||||
"auth": {
|
"auth": {
|
||||||
"authType": "none",
|
"authType": "none",
|
||||||
"authActive": true
|
"authActive": true
|
||||||
@@ -16,7 +16,6 @@
|
|||||||
"name": "test-secret-headers",
|
"name": "test-secret-headers",
|
||||||
"method": "GET",
|
"method": "GET",
|
||||||
"params": [],
|
"params": [],
|
||||||
"requestVariables": [],
|
|
||||||
"headers": [
|
"headers": [
|
||||||
{
|
{
|
||||||
"key": "Secret-Header-Key",
|
"key": "Secret-Header-Key",
|
||||||
@@ -24,12 +23,12 @@
|
|||||||
"active": true
|
"active": true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"endpoint": "<<echoHoppBaseURL>>",
|
"endpoint": "<<baseURL>>/headers",
|
||||||
"testScript": "pw.test(\"Successfully parses secret variable holding the header value\", () => {\n const secretHeaderValue = pw.env.getResolve(\"secretHeaderValue\")\n pw.expect(secretHeaderValue).toBe(\"secret-header-value\")\n \n if (secretHeaderValue) {\n pw.expect(pw.response.body.headers[\"secret-header-key\"]).toBe(secretHeaderValue)\n }\n\n pw.expect(pw.env.getResolve(\"secretHeaderValueFromPreReqScript\")).toBe(\"secret-header-value\")\n})",
|
"testScript": "pw.test(\"Successfully parses secret variable holding the header value\", () => {\n const secretHeaderValue = pw.env.getResolve(\"secretHeaderValue\")\n pw.expect(secretHeaderValue).toBe(\"secret-header-value\")\n \n if (secretHeaderValue) {\n pw.expect(pw.response.body.headers[\"Secret-Header-Key\"]).toBe(secretHeaderValue)\n }\n\n pw.expect(pw.env.getResolve(\"secretHeaderValueFromPreReqScript\")).toBe(\"secret-header-value\")\n})",
|
||||||
"preRequestScript": "pw.env.set(\"secretHeaderValue\", \"secret-header-value\")\n\nconst secretHeaderValueFromPreReqScript = pw.env.getResolve(\"secretHeaderValue\")\npw.env.set(\"secretHeaderValueFromPreReqScript\", secretHeaderValueFromPreReqScript)"
|
"preRequestScript": "pw.env.set(\"secretHeaderValue\", \"secret-header-value\")\n\nconst secretHeaderValueFromPreReqScript = pw.env.getResolve(\"secretHeaderValue\")\npw.env.set(\"secretHeaderValueFromPreReqScript\", secretHeaderValueFromPreReqScript)"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"v": "3",
|
"v": "1",
|
||||||
"auth": {
|
"auth": {
|
||||||
"authType": "none",
|
"authType": "none",
|
||||||
"authActive": true
|
"authActive": true
|
||||||
@@ -41,7 +40,6 @@
|
|||||||
"name": "test-secret-headers-overrides",
|
"name": "test-secret-headers-overrides",
|
||||||
"method": "GET",
|
"method": "GET",
|
||||||
"params": [],
|
"params": [],
|
||||||
"requestVariables": [],
|
|
||||||
"headers": [
|
"headers": [
|
||||||
{
|
{
|
||||||
"key": "Secret-Header-Key",
|
"key": "Secret-Header-Key",
|
||||||
@@ -49,12 +47,12 @@
|
|||||||
"active": true
|
"active": true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"endpoint": "<<echoHoppBaseURL>>",
|
"endpoint": "<<baseURL>>/headers",
|
||||||
"testScript": "pw.test(\"Value set at the pre-request script takes precedence\", () => {\n const secretHeaderValue = pw.env.getResolve(\"secretHeaderValue\")\n pw.expect(secretHeaderValue).toBe(\"secret-header-value-overriden\")\n \n if (secretHeaderValue) {\n pw.expect(pw.response.body.headers[\"secret-header-key\"]).toBe(secretHeaderValue)\n }\n\n pw.expect(pw.env.getResolve(\"secretHeaderValueFromPreReqScript\")).toBe(\"secret-header-value-overriden\")\n})",
|
"testScript": "pw.test(\"Value set at the pre-request script takes precedence\", () => {\n const secretHeaderValue = pw.env.getResolve(\"secretHeaderValue\")\n pw.expect(secretHeaderValue).toBe(\"secret-header-value-overriden\")\n \n if (secretHeaderValue) {\n pw.expect(pw.response.body.headers[\"Secret-Header-Key\"]).toBe(secretHeaderValue)\n }\n\n pw.expect(pw.env.getResolve(\"secretHeaderValueFromPreReqScript\")).toBe(\"secret-header-value-overriden\")\n})",
|
||||||
"preRequestScript": "pw.env.set(\"secretHeaderValue\", \"secret-header-value-overriden\")\n\nconst secretHeaderValueFromPreReqScript = pw.env.getResolve(\"secretHeaderValue\")\npw.env.set(\"secretHeaderValueFromPreReqScript\", secretHeaderValueFromPreReqScript)"
|
"preRequestScript": "pw.env.set(\"secretHeaderValue\", \"secret-header-value-overriden\")\n\nconst secretHeaderValueFromPreReqScript = pw.env.getResolve(\"secretHeaderValue\")\npw.env.set(\"secretHeaderValueFromPreReqScript\", secretHeaderValueFromPreReqScript)"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"v": "3",
|
"v": "1",
|
||||||
"auth": {
|
"auth": {
|
||||||
"authType": "none",
|
"authType": "none",
|
||||||
"authActive": true
|
"authActive": true
|
||||||
@@ -66,14 +64,13 @@
|
|||||||
"name": "test-secret-body",
|
"name": "test-secret-body",
|
||||||
"method": "POST",
|
"method": "POST",
|
||||||
"params": [],
|
"params": [],
|
||||||
"requestVariables": [],
|
|
||||||
"headers": [],
|
"headers": [],
|
||||||
"endpoint": "<<echoHoppBaseURL>>/post",
|
"endpoint": "<<baseURL>>/post",
|
||||||
"testScript": "pw.test(\"Successfully parses secret variable holding the request body value\", () => {\n const secretBodyValue = pw.env.get(\"secretBodyValue\")\n pw.expect(secretBodyValue).toBe(\"secret-body-value\")\n \n if (secretBodyValue) {\n pw.expect(JSON.parse(pw.response.body.data).secretBodyKey).toBe(secretBodyValue)\n }\n\n pw.expect(pw.env.get(\"secretBodyValueFromPreReqScript\")).toBe(\"secret-body-value\")\n})",
|
"testScript": "pw.test(\"Successfully parses secret variable holding the request body value\", () => {\n const secretBodyValue = pw.env.get(\"secretBodyValue\")\n pw.expect(secretBodyValue).toBe(\"secret-body-value\")\n \n if (secretBodyValue) {\n pw.expect(pw.response.body.json.secretBodyKey).toBe(secretBodyValue)\n }\n\n pw.expect(pw.env.get(\"secretBodyValueFromPreReqScript\")).toBe(\"secret-body-value\")\n})",
|
||||||
"preRequestScript": "const secretBodyValue = pw.env.get(\"secretBodyValue\")\n\nif (!secretBodyValue) { \n pw.env.set(\"secretBodyValue\", \"secret-body-value\")\n}\n\nconst secretBodyValueFromPreReqScript = pw.env.get(\"secretBodyValue\")\npw.env.set(\"secretBodyValueFromPreReqScript\", secretBodyValueFromPreReqScript)"
|
"preRequestScript": "const secretBodyValue = pw.env.get(\"secretBodyValue\")\n\nif (!secretBodyValue) { \n pw.env.set(\"secretBodyValue\", \"secret-body-value\")\n}\n\nconst secretBodyValueFromPreReqScript = pw.env.get(\"secretBodyValue\")\npw.env.set(\"secretBodyValueFromPreReqScript\", secretBodyValueFromPreReqScript)"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"v": "3",
|
"v": "1",
|
||||||
"auth": {
|
"auth": {
|
||||||
"authType": "none",
|
"authType": "none",
|
||||||
"authActive": true
|
"authActive": true
|
||||||
@@ -91,14 +88,13 @@
|
|||||||
"active": true
|
"active": true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"requestVariables": [],
|
|
||||||
"headers": [],
|
"headers": [],
|
||||||
"endpoint": "<<echoHoppBaseURL>>",
|
"endpoint": "<<baseURL>>/get",
|
||||||
"testScript": "pw.test(\"Successfully parses secret variable holding the query param value\", () => {\n const secretQueryParamValue = pw.env.get(\"secretQueryParamValue\")\n pw.expect(secretQueryParamValue).toBe(\"secret-query-param-value\")\n \n if (secretQueryParamValue) {\n pw.expect(pw.response.body.args.secretQueryParamKey).toBe(secretQueryParamValue)\n }\n\n pw.expect(pw.env.get(\"secretQueryParamValueFromPreReqScript\")).toBe(\"secret-query-param-value\")\n})",
|
"testScript": "pw.test(\"Successfully parses secret variable holding the query param value\", () => {\n const secretQueryParamValue = pw.env.get(\"secretQueryParamValue\")\n pw.expect(secretQueryParamValue).toBe(\"secret-query-param-value\")\n \n if (secretQueryParamValue) {\n pw.expect(pw.response.body.args.secretQueryParamKey).toBe(secretQueryParamValue)\n }\n\n pw.expect(pw.env.get(\"secretQueryParamValueFromPreReqScript\")).toBe(\"secret-query-param-value\")\n})",
|
||||||
"preRequestScript": "const secretQueryParamValue = pw.env.get(\"secretQueryParamValue\")\n\nif (!secretQueryParamValue) {\n pw.env.set(\"secretQueryParamValue\", \"secret-query-param-value\")\n}\n\nconst secretQueryParamValueFromPreReqScript = pw.env.get(\"secretQueryParamValue\")\npw.env.set(\"secretQueryParamValueFromPreReqScript\", secretQueryParamValueFromPreReqScript)"
|
"preRequestScript": "const secretQueryParamValue = pw.env.get(\"secretQueryParamValue\")\n\nif (!secretQueryParamValue) {\n pw.env.set(\"secretQueryParamValue\", \"secret-query-param-value\")\n}\n\nconst secretQueryParamValueFromPreReqScript = pw.env.get(\"secretQueryParamValue\")\npw.env.set(\"secretQueryParamValueFromPreReqScript\", secretQueryParamValueFromPreReqScript)"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"v": "3",
|
"v": "1",
|
||||||
"auth": {
|
"auth": {
|
||||||
"authType": "basic",
|
"authType": "basic",
|
||||||
"password": "<<secretBasicAuthPassword>>",
|
"password": "<<secretBasicAuthPassword>>",
|
||||||
@@ -112,14 +108,13 @@
|
|||||||
"name": "test-secret-basic-auth",
|
"name": "test-secret-basic-auth",
|
||||||
"method": "GET",
|
"method": "GET",
|
||||||
"params": [],
|
"params": [],
|
||||||
"requestVariables": [],
|
|
||||||
"headers": [],
|
"headers": [],
|
||||||
"endpoint": "<<httpbinBaseURL>>/basic-auth/<<secretBasicAuthUsername>>/<<secretBasicAuthPassword>>",
|
"endpoint": "<<baseURL>>/basic-auth/<<secretBasicAuthUsername>>/<<secretBasicAuthPassword>>",
|
||||||
"testScript": "pw.test(\"Successfully parses secret variables holding basic auth credentials\", () => {\n\tconst secretBasicAuthUsername = pw.env.get(\"secretBasicAuthUsername\")\n \tconst secretBasicAuthPassword = pw.env.get(\"secretBasicAuthPassword\")\n\n pw.expect(secretBasicAuthUsername).toBe(\"test-user\")\n pw.expect(secretBasicAuthPassword).toBe(\"test-pass\")\n\n // The endpoint at times results in a `502` bad gateway\n if (pw.response.status !== 200) {\n return\n }\n\n if (secretBasicAuthUsername && secretBasicAuthPassword) {\n const { authenticated, user } = pw.response.body\n pw.expect(authenticated).toBe(true)\n pw.expect(user).toBe(secretBasicAuthUsername)\n }\n});",
|
"testScript": "pw.test(\"Successfully parses secret variables holding basic auth credentials\", () => {\n\tconst secretBasicAuthUsername = pw.env.get(\"secretBasicAuthUsername\")\n \tconst secretBasicAuthPassword = pw.env.get(\"secretBasicAuthPassword\")\n\n pw.expect(secretBasicAuthUsername).toBe(\"test-user\")\n pw.expect(secretBasicAuthPassword).toBe(\"test-pass\")\n\n if (secretBasicAuthUsername && secretBasicAuthPassword) {\n const { authenticated, user } = pw.response.body\n pw.expect(authenticated).toBe(true)\n pw.expect(user).toBe(secretBasicAuthUsername)\n }\n});",
|
||||||
"preRequestScript": "let secretBasicAuthUsername = pw.env.get(\"secretBasicAuthUsername\")\n\nlet secretBasicAuthPassword = pw.env.get(\"secretBasicAuthPassword\")\n\nif (!secretBasicAuthUsername) {\n pw.env.set(\"secretBasicAuthUsername\", \"test-user\")\n}\n\nif (!secretBasicAuthPassword) {\n pw.env.set(\"secretBasicAuthPassword\", \"test-pass\")\n}"
|
"preRequestScript": "let secretBasicAuthUsername = pw.env.get(\"secretBasicAuthUsername\")\n\nlet secretBasicAuthPassword = pw.env.get(\"secretBasicAuthPassword\")\n\nif (!secretBasicAuthUsername) {\n pw.env.set(\"secretBasicAuthUsername\", \"test-user\")\n}\n\nif (!secretBasicAuthPassword) {\n pw.env.set(\"secretBasicAuthPassword\", \"test-pass\")\n}"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"v": "3",
|
"v": "1",
|
||||||
"auth": {
|
"auth": {
|
||||||
"token": "<<secretBearerToken>>",
|
"token": "<<secretBearerToken>>",
|
||||||
"authType": "bearer",
|
"authType": "bearer",
|
||||||
@@ -134,10 +129,9 @@
|
|||||||
"name": "test-secret-bearer-auth",
|
"name": "test-secret-bearer-auth",
|
||||||
"method": "GET",
|
"method": "GET",
|
||||||
"params": [],
|
"params": [],
|
||||||
"requestVariables": [],
|
|
||||||
"headers": [],
|
"headers": [],
|
||||||
"endpoint": "<<httpbinBaseURL>>/bearer",
|
"endpoint": "<<baseURL>>/bearer",
|
||||||
"testScript": "pw.test(\"Successfully parses secret variable holding the bearer token\", () => {\n const secretBearerToken = pw.env.resolve(\"<<secretBearerToken>>\")\n const preReqSecretBearerToken = pw.env.resolve(\"<<preReqSecretBearerToken>>\")\n\n pw.expect(secretBearerToken).toBe(\"test-token\")\n\n // Safeguard to prevent test failures due to the endpoint\n if (pw.response.status !== 200) {\n return\n }\n\n if (secretBearerToken) { \n pw.expect(pw.response.body.token).toBe(secretBearerToken)\n pw.expect(preReqSecretBearerToken).toBe(\"test-token\")\n }\n});",
|
"testScript": "pw.test(\"Successfully parses secret variable holding the bearer token\", () => {\n const secretBearerToken = pw.env.resolve(\"<<secretBearerToken>>\")\n const preReqSecretBearerToken = pw.env.resolve(\"<<preReqSecretBearerToken>>\")\n\n pw.expect(secretBearerToken).toBe(\"test-token\")\n\n if (secretBearerToken) { \n pw.expect(pw.response.body.token).toBe(secretBearerToken)\n pw.expect(preReqSecretBearerToken).toBe(\"test-token\")\n }\n});",
|
||||||
"preRequestScript": "let secretBearerToken = pw.env.resolve(\"<<secretBearerToken>>\")\n\nif (!secretBearerToken) {\n pw.env.set(\"secretBearerToken\", \"test-token\")\n secretBearerToken = pw.env.resolve(\"<<secretBearerToken>>\")\n}\n\npw.env.set(\"preReqSecretBearerToken\", secretBearerToken)"
|
"preRequestScript": "let secretBearerToken = pw.env.resolve(\"<<secretBearerToken>>\")\n\nif (!secretBearerToken) {\n pw.env.set(\"secretBearerToken\", \"test-token\")\n secretBearerToken = pw.env.resolve(\"<<secretBearerToken>>\")\n}\n\npw.env.set(\"preReqSecretBearerToken\", secretBearerToken)"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
"folders": [],
|
"folders": [],
|
||||||
"requests": [
|
"requests": [
|
||||||
{
|
{
|
||||||
"v": "3",
|
"v": "1",
|
||||||
"endpoint": "https://echo.hoppscotch.io/post",
|
"endpoint": "https://httpbin.org/post",
|
||||||
"name": "req",
|
"name": "req",
|
||||||
"params": [],
|
"params": [],
|
||||||
"headers": [
|
"headers": [
|
||||||
@@ -18,12 +18,11 @@
|
|||||||
"method": "POST",
|
"method": "POST",
|
||||||
"auth": { "authType": "none", "authActive": true },
|
"auth": { "authType": "none", "authActive": true },
|
||||||
"preRequestScript": "pw.env.set(\"preReqVarOne\", \"pre-req-value-one\")\n\npw.env.set(\"preReqVarTwo\", \"pre-req-value-two\")\n\npw.env.set(\"customHeaderValueFromSecretVar\", \"custom-header-secret-value\")\n\npw.env.set(\"customBodyValue\", \"custom-body-value\")",
|
"preRequestScript": "pw.env.set(\"preReqVarOne\", \"pre-req-value-one\")\n\npw.env.set(\"preReqVarTwo\", \"pre-req-value-two\")\n\npw.env.set(\"customHeaderValueFromSecretVar\", \"custom-header-secret-value\")\n\npw.env.set(\"customBodyValue\", \"custom-body-value\")",
|
||||||
"testScript": "pw.test(\"Secret environment value set from the pre-request script takes precedence\", () => {\n pw.expect(pw.env.get(\"preReqVarOne\")).toBe(\"pre-req-value-one\")\n})\n\npw.test(\"Successfully sets initial value for the secret variable from the pre-request script\", () => {\n pw.env.set(\"postReqVarTwo\", \"post-req-value-two\")\n pw.expect(pw.env.get(\"postReqVarTwo\")).toBe(\"post-req-value-two\")\n})\n\npw.test(\"Successfully resolves secret variable values referred in request headers that are set in pre-request script\", () => {\n pw.expect(pw.response.body.headers[\"custom-header\"]).toBe(\"custom-header-secret-value\")\n})\n\npw.test(\"Successfully resolves secret variable values referred in request body that are set in pre-request script\", () => {\n pw.expect(JSON.parse(pw.response.body.data).key).toBe(\"custom-body-value\")\n})\n\npw.test(\"Secret environment variable set from the post-request script takes precedence\", () => {\n pw.env.set(\"postReqVarOne\", \"post-req-value-one\")\n pw.expect(pw.env.get(\"postReqVarOne\")).toBe(\"post-req-value-one\")\n})\n\npw.test(\"Successfully sets initial value for the secret variable from the post-request script\", () => {\n pw.env.set(\"postReqVarTwo\", \"post-req-value-two\")\n pw.expect(pw.env.get(\"postReqVarTwo\")).toBe(\"post-req-value-two\")\n})\n\npw.test(\"Successfully removes environment variables via the pw.env.unset method\", () => {\n pw.env.unset(\"preReqVarOne\")\n pw.env.unset(\"postReqVarTwo\")\n\n pw.expect(pw.env.get(\"preReqVarOne\")).toBe(undefined)\n pw.expect(pw.env.get(\"postReqVarTwo\")).toBe(undefined)\n})",
|
"testScript": "pw.test(\"Secret environment value set from the pre-request script takes precedence\", () => {\n pw.expect(pw.env.get(\"preReqVarOne\")).toBe(\"pre-req-value-one\")\n})\n\npw.test(\"Successfully sets initial value for the secret variable from the pre-request script\", () => {\n pw.env.set(\"postReqVarTwo\", \"post-req-value-two\")\n pw.expect(pw.env.get(\"postReqVarTwo\")).toBe(\"post-req-value-two\")\n})\n\npw.test(\"Successfully resolves secret variable values referred in request headers that are set in pre-request sccript\", () => {\n pw.expect(pw.response.body.headers[\"Custom-Header\"]).toBe(\"custom-header-secret-value\")\n})\n\npw.test(\"Successfully resolves secret variable values referred in request body that are set in pre-request sccript\", () => {\n pw.expect(pw.response.body.json.key).toBe(\"custom-body-value\")\n})\n\npw.test(\"Secret environment variable set from the post-request script takes precedence\", () => {\n pw.env.set(\"postReqVarOne\", \"post-req-value-one\")\n pw.expect(pw.env.get(\"postReqVarOne\")).toBe(\"post-req-value-one\")\n})\n\npw.test(\"Successfully sets initial value for the secret variable from the post-request script\", () => {\n pw.env.set(\"postReqVarTwo\", \"post-req-value-two\")\n pw.expect(pw.env.get(\"postReqVarTwo\")).toBe(\"post-req-value-two\")\n})\n\npw.test(\"Successfully removes environment variables via the pw.env.unset method\", () => {\n pw.env.unset(\"preReqVarOne\")\n pw.env.unset(\"postReqVarTwo\")\n\n pw.expect(pw.env.get(\"preReqVarOne\")).toBe(undefined)\n pw.expect(pw.env.get(\"postReqVarTwo\")).toBe(undefined)\n})",
|
||||||
"body": {
|
"body": {
|
||||||
"contentType": "application/json",
|
"contentType": "application/json",
|
||||||
"body": "{\n \"key\": \"<<customBodyValue>>\"\n}"
|
"body": "{\n \"key\": \"<<customBodyValue>>\"\n}"
|
||||||
},
|
}
|
||||||
"requestVariables": []
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"auth": { "authType": "inherit", "authActive": false },
|
"auth": { "authType": "inherit", "authActive": false },
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "env-v0",
|
|
||||||
"variables": [
|
|
||||||
{
|
|
||||||
"key": "baseURL",
|
|
||||||
"value": "https://echo.hoppscotch.io"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "env-v0",
|
|
||||||
"variables": [
|
|
||||||
{
|
|
||||||
"key": "baseURL",
|
|
||||||
"value": "https://echo.hoppscotch.io",
|
|
||||||
"secret": false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -32,12 +32,7 @@
|
|||||||
"secret": true
|
"secret": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "echoHoppBaseURL",
|
"key": "baseURL",
|
||||||
"value": "https://echo.hoppscotch.io",
|
|
||||||
"secret": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "httpbinBaseURL",
|
|
||||||
"value": "https://httpbin.org",
|
"value": "https://httpbin.org",
|
||||||
"secret": false
|
"secret": false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,12 +38,7 @@
|
|||||||
"secret": true
|
"secret": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "echoHoppBaseURL",
|
"key": "baseURL",
|
||||||
"value": "https://echo.hoppscotch.io",
|
|
||||||
"secret": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "httpbinBaseURL",
|
|
||||||
"value": "https://httpbin.org",
|
"value": "https://httpbin.org",
|
||||||
"secret": false
|
"secret": false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,16 +3,15 @@ import { resolve } from "path";
|
|||||||
|
|
||||||
import { ExecResponse } from "./types";
|
import { ExecResponse } from "./types";
|
||||||
|
|
||||||
export const runCLI = (args: string, options = {}): Promise<ExecResponse> => {
|
export const runCLI = (args: string, options = {}): Promise<ExecResponse> =>
|
||||||
const CLI_PATH = resolve(__dirname, "../../bin/hopp.js");
|
{
|
||||||
const command = `node ${CLI_PATH} ${args}`;
|
const CLI_PATH = resolve(__dirname, "../../bin/hopp");
|
||||||
|
const command = `node ${CLI_PATH} ${args}`
|
||||||
|
|
||||||
return new Promise((resolve) =>
|
return new Promise((resolve) =>
|
||||||
exec(command, options, (error, stdout, stderr) =>
|
exec(command, options, (error, stdout, stderr) => resolve({ error, stdout, stderr }))
|
||||||
resolve({ error, stdout, stderr })
|
);
|
||||||
)
|
}
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const trimAnsi = (target: string) => {
|
export const trimAnsi = (target: string) => {
|
||||||
const ansiRegex =
|
const ansiRegex =
|
||||||
@@ -26,18 +25,12 @@ export const getErrorCode = (out: string) => {
|
|||||||
return ansiTrimmedStr.split(" ")[0];
|
return ansiTrimmedStr.split(" ")[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getTestJsonFilePath = (
|
export const getTestJsonFilePath = (file: string, kind: "collection" | "environment") => {
|
||||||
file: string,
|
|
||||||
kind: "collection" | "environment"
|
|
||||||
) => {
|
|
||||||
const kindDir = {
|
const kindDir = {
|
||||||
collection: "collections",
|
collection: "collections",
|
||||||
environment: "environments",
|
environment: "environments",
|
||||||
}[kind];
|
}[kind];
|
||||||
|
|
||||||
const filePath = resolve(
|
const filePath = resolve(__dirname, `../../src/__tests__/samples/${kindDir}/${file}`);
|
||||||
__dirname,
|
|
||||||
`../../src/__tests__/samples/${kindDir}/${file}`
|
|
||||||
);
|
|
||||||
return filePath;
|
return filePath;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import chalk from "chalk";
|
import chalk from "chalk";
|
||||||
import { Command } from "commander";
|
import { program } from "commander";
|
||||||
import * as E from "fp-ts/Either";
|
import * as E from "fp-ts/Either";
|
||||||
|
|
||||||
import { version } from "../package.json";
|
import { version } from "../package.json";
|
||||||
import { test } from "./commands/test";
|
import { test } from "./commands/test";
|
||||||
import { handleError } from "./handlers/error";
|
import { handleError } from "./handlers/error";
|
||||||
@@ -21,8 +20,6 @@ const CLI_AFTER_ALL_TXT = `\nFor more help, head on to ${accent(
|
|||||||
"https://docs.hoppscotch.io/documentation/clients/cli"
|
"https://docs.hoppscotch.io/documentation/clients/cli"
|
||||||
)}`;
|
)}`;
|
||||||
|
|
||||||
const program = new Command();
|
|
||||||
|
|
||||||
program
|
program
|
||||||
.name("hopp")
|
.name("hopp")
|
||||||
.version(version, "-v, --ver", "see the current version of hopp-cli")
|
.version(version, "-v, --ver", "see the current version of hopp-cli")
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { error } from "../../types/errors";
|
|||||||
import {
|
import {
|
||||||
HoppEnvKeyPairObject,
|
HoppEnvKeyPairObject,
|
||||||
HoppEnvPair,
|
HoppEnvPair,
|
||||||
HoppEnvs,
|
HoppEnvs
|
||||||
} from "../../types/request";
|
} from "../../types/request";
|
||||||
import { readJsonFile } from "../../utils/mutators";
|
import { readJsonFile } from "../../utils/mutators";
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ import { readJsonFile } from "../../utils/mutators";
|
|||||||
*/
|
*/
|
||||||
export async function parseEnvsData(path: string) {
|
export async function parseEnvsData(path: string) {
|
||||||
const contents = await readJsonFile(path);
|
const contents = await readJsonFile(path);
|
||||||
const envPairs: Array<HoppEnvPair | Record<string, string>> = [];
|
const envPairs: Array<Environment["variables"][number] | HoppEnvPair> = [];
|
||||||
|
|
||||||
// The legacy key-value pair format that is still supported
|
// The legacy key-value pair format that is still supported
|
||||||
const HoppEnvKeyPairResult = HoppEnvKeyPairObject.safeParse(contents);
|
const HoppEnvKeyPairResult = HoppEnvKeyPairObject.safeParse(contents);
|
||||||
@@ -26,9 +26,7 @@ export async function parseEnvsData(path: string) {
|
|||||||
const HoppEnvExportObjectResult = Environment.safeParse(contents);
|
const HoppEnvExportObjectResult = Environment.safeParse(contents);
|
||||||
|
|
||||||
// Shape of the bulk environment export object that is exported from the app
|
// Shape of the bulk environment export object that is exported from the app
|
||||||
const HoppBulkEnvExportObjectResult = z
|
const HoppBulkEnvExportObjectResult = z.array(entityReference(Environment)).safeParse(contents)
|
||||||
.array(entityReference(Environment))
|
|
||||||
.safeParse(contents);
|
|
||||||
|
|
||||||
// CLI doesnt support bulk environments export
|
// CLI doesnt support bulk environments export
|
||||||
// Hence we check for this case and throw an error if it matches the format
|
// Hence we check for this case and throw an error if it matches the format
|
||||||
@@ -38,16 +36,13 @@ export async function parseEnvsData(path: string) {
|
|||||||
|
|
||||||
// Checks if the environment file is of the correct format
|
// Checks if the environment file is of the correct format
|
||||||
// If it doesnt match either of them, we throw an error
|
// If it doesnt match either of them, we throw an error
|
||||||
if (
|
if (!HoppEnvKeyPairResult.success && HoppEnvExportObjectResult.type === "err") {
|
||||||
!HoppEnvKeyPairResult.success &&
|
|
||||||
HoppEnvExportObjectResult.type === "err"
|
|
||||||
) {
|
|
||||||
throw error({ code: "MALFORMED_ENV_FILE", path, data: error });
|
throw error({ code: "MALFORMED_ENV_FILE", path, data: error });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HoppEnvKeyPairResult.success) {
|
if (HoppEnvKeyPairResult.success) {
|
||||||
for (const [key, value] of Object.entries(HoppEnvKeyPairResult.data)) {
|
for (const [key, value] of Object.entries(HoppEnvKeyPairResult.data)) {
|
||||||
envPairs.push({ key, value, secret: false });
|
envPairs.push({ key, value });
|
||||||
}
|
}
|
||||||
} else if (HoppEnvExportObjectResult.type === "ok") {
|
} else if (HoppEnvExportObjectResult.type === "ok") {
|
||||||
envPairs.push(...HoppEnvExportObjectResult.value.variables);
|
envPairs.push(...HoppEnvExportObjectResult.value.variables);
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { HoppCollection, isHoppRESTRequest } from "@hoppscotch/data";
|
||||||
|
import * as A from "fp-ts/Array";
|
||||||
import { CommanderError } from "commander";
|
import { CommanderError } from "commander";
|
||||||
import { HoppCLIError, HoppErrnoException } from "../types/errors";
|
import { HoppCLIError, HoppErrnoException } from "../types/errors";
|
||||||
|
|
||||||
@@ -12,6 +14,48 @@ export const hasProperty = <P extends PropertyKey>(
|
|||||||
prop: P
|
prop: P
|
||||||
): target is Record<P, unknown> => prop in target;
|
): target is Record<P, unknown> => prop in target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Typeguard to check valid Hoppscotch REST Collection.
|
||||||
|
* @param param The object to be checked.
|
||||||
|
* @returns True, if unknown parameter is valid Hoppscotch REST Collection;
|
||||||
|
* False, otherwise.
|
||||||
|
*/
|
||||||
|
export const isRESTCollection = (param: unknown): param is HoppCollection => {
|
||||||
|
if (!!param && typeof param === "object") {
|
||||||
|
if (!hasProperty(param, "v") || typeof param.v !== "number") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!hasProperty(param, "name") || typeof param.name !== "string") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (hasProperty(param, "id") && typeof param.id !== "string") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!hasProperty(param, "requests") || !Array.isArray(param.requests)) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
// Checks each requests array to be valid HoppRESTRequest.
|
||||||
|
const checkRequests = A.every(isHoppRESTRequest)(param.requests);
|
||||||
|
if (!checkRequests) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!hasProperty(param, "folders") || !Array.isArray(param.folders)) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
// Checks each folder to be valid REST collection.
|
||||||
|
const checkFolders = A.every(isRESTCollection)(param.folders);
|
||||||
|
if (!checkFolders) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if given error data is of type HoppCLIError, based on existence
|
* Checks if given error data is of type HoppCLIError, based on existence
|
||||||
* of code property.
|
* of code property.
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { HoppCollection, HoppRESTRequest } from "@hoppscotch/data";
|
import { HoppCollection, HoppRESTRequest } from "@hoppscotch/data";
|
||||||
import chalk from "chalk";
|
import { bold } from "chalk";
|
||||||
import { log } from "console";
|
import { log } from "console";
|
||||||
import * as A from "fp-ts/Array";
|
import * as A from "fp-ts/Array";
|
||||||
import { pipe } from "fp-ts/function";
|
import { pipe } from "fp-ts/function";
|
||||||
import { round } from "lodash-es";
|
import round from "lodash/round";
|
||||||
|
|
||||||
import { CollectionRunnerParam } from "../types/collections";
|
import { CollectionRunnerParam } from "../types/collections";
|
||||||
import {
|
import {
|
||||||
@@ -68,7 +68,7 @@ export const collectionsRunner = async (
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Request processing initiated message.
|
// Request processing initiated message.
|
||||||
log(WARN(`\nRunning: ${chalk.bold(requestPath)}`));
|
log(WARN(`\nRunning: ${bold(requestPath)}`));
|
||||||
|
|
||||||
// Processing current request.
|
// Processing current request.
|
||||||
const result = await processRequest(processRequestParams)();
|
const result = await processRequest(processRequestParams)();
|
||||||
@@ -131,7 +131,7 @@ const getCollectionStack = (collections: HoppCollection[]): CollectionStack[] =>
|
|||||||
* path of each request within collection-json file, failed-tests-report, errors,
|
* path of each request within collection-json file, failed-tests-report, errors,
|
||||||
* total execution duration for requests, pre-request-scripts, test-scripts.
|
* total execution duration for requests, pre-request-scripts, test-scripts.
|
||||||
* @returns True, if collection runner executed without any errors or failed test-cases.
|
* @returns True, if collection runner executed without any errors or failed test-cases.
|
||||||
* False, if errors occurred or test-cases failed.
|
* False, if errors occured or test-cases failed.
|
||||||
*/
|
*/
|
||||||
export const collectionsRunnerResult = (
|
export const collectionsRunnerResult = (
|
||||||
requestsReport: RequestReport[]
|
requestsReport: RequestReport[]
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import chalk from "chalk";
|
import { bold } from "chalk";
|
||||||
import { groupEnd, group, log } from "console";
|
import { groupEnd, group, log } from "console";
|
||||||
import { handleError } from "../handlers/error";
|
import { handleError } from "../handlers/error";
|
||||||
import { RequestConfig } from "../interfaces/request";
|
import { RequestConfig } from "../interfaces/request";
|
||||||
@@ -112,7 +112,7 @@ export const printTestsMetrics = (testsMetrics: TestMetrics) => {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Prints details of each reported error for a request with error code.
|
* Prints details of each reported error for a request with error code.
|
||||||
* @param path Request's path in collection for which errors occurred.
|
* @param path Request's path in collection for which errors occured.
|
||||||
* @param errorsReport List of errors reported.
|
* @param errorsReport List of errors reported.
|
||||||
*/
|
*/
|
||||||
export const printErrorsReport = (
|
export const printErrorsReport = (
|
||||||
@@ -120,7 +120,7 @@ export const printErrorsReport = (
|
|||||||
errorsReport: HoppCLIError[]
|
errorsReport: HoppCLIError[]
|
||||||
) => {
|
) => {
|
||||||
if (errorsReport.length > 0) {
|
if (errorsReport.length > 0) {
|
||||||
const REPORTED_ERRORS_TITLE = FAIL(`\n${chalk.bold(path)} reported errors:`);
|
const REPORTED_ERRORS_TITLE = FAIL(`\n${bold(path)} reported errors:`);
|
||||||
|
|
||||||
group(REPORTED_ERRORS_TITLE);
|
group(REPORTED_ERRORS_TITLE);
|
||||||
for (const errorReport of errorsReport) {
|
for (const errorReport of errorsReport) {
|
||||||
@@ -143,7 +143,7 @@ export const printFailedTestsReport = (
|
|||||||
|
|
||||||
// Only printing test-reports with failed test-cases.
|
// Only printing test-reports with failed test-cases.
|
||||||
if (failedTestsReport.length > 0) {
|
if (failedTestsReport.length > 0) {
|
||||||
const FAILED_TESTS_PATH = FAIL(`\n${chalk.bold(path)} failed tests:`);
|
const FAILED_TESTS_PATH = FAIL(`\n${bold(path)} failed tests:`);
|
||||||
group(FAILED_TESTS_PATH);
|
group(FAILED_TESTS_PATH);
|
||||||
|
|
||||||
for (const failedTestReport of failedTestsReport) {
|
for (const failedTestReport of failedTestsReport) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { clone } from "lodash-es";
|
import { clone } from "lodash";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sorts the array based on the sort func.
|
* Sorts the array based on the sort func.
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import * as E from "fp-ts/Either";
|
|||||||
import * as S from "fp-ts/string";
|
import * as S from "fp-ts/string";
|
||||||
import * as O from "fp-ts/Option";
|
import * as O from "fp-ts/Option";
|
||||||
import { error } from "../types/errors";
|
import { error } from "../types/errors";
|
||||||
import { round } from "lodash-es";
|
import round from "lodash/round";
|
||||||
import { DEFAULT_DURATION_PRECISION } from "./constants";
|
import { DEFAULT_DURATION_PRECISION } from "./constants";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,46 +1,8 @@
|
|||||||
import { HoppCollection, HoppRESTRequest } from "@hoppscotch/data";
|
|
||||||
import fs from "fs/promises";
|
import fs from "fs/promises";
|
||||||
import { entityReference } from "verzod";
|
|
||||||
import { z } from "zod";
|
|
||||||
|
|
||||||
import { error } from "../types/errors";
|
|
||||||
import { FormDataEntry } from "../types/request";
|
import { FormDataEntry } from "../types/request";
|
||||||
import { isHoppErrnoException } from "./checks";
|
import { error } from "../types/errors";
|
||||||
|
import { isRESTCollection, isHoppErrnoException } from "./checks";
|
||||||
const getValidRequests = (
|
import { HoppCollection } from "@hoppscotch/data";
|
||||||
collections: HoppCollection[],
|
|
||||||
collectionFilePath: string
|
|
||||||
) => {
|
|
||||||
return collections.map((collection) => {
|
|
||||||
// Validate requests using zod schema
|
|
||||||
const requestSchemaParsedResult = z
|
|
||||||
.array(entityReference(HoppRESTRequest))
|
|
||||||
.safeParse(collection.requests);
|
|
||||||
|
|
||||||
// Handle validation errors
|
|
||||||
if (!requestSchemaParsedResult.success) {
|
|
||||||
throw error({
|
|
||||||
code: "MALFORMED_COLLECTION",
|
|
||||||
path: collectionFilePath,
|
|
||||||
data: "Please check the collection data.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Recursively validate requests in nested folders
|
|
||||||
if (collection.folders.length > 0) {
|
|
||||||
collection.folders = getValidRequests(
|
|
||||||
collection.folders,
|
|
||||||
collectionFilePath
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return validated collection
|
|
||||||
return {
|
|
||||||
...collection,
|
|
||||||
requests: requestSchemaParsedResult.data,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses array of FormDataEntry to FormData.
|
* Parses array of FormDataEntry to FormData.
|
||||||
@@ -105,11 +67,7 @@ export async function parseCollectionData(
|
|||||||
? contents
|
? contents
|
||||||
: [contents];
|
: [contents];
|
||||||
|
|
||||||
const collectionSchemaParsedResult = z
|
if (maybeArrayOfCollections.some((x) => !isRESTCollection(x))) {
|
||||||
.array(entityReference(HoppCollection))
|
|
||||||
.safeParse(maybeArrayOfCollections);
|
|
||||||
|
|
||||||
if (!collectionSchemaParsedResult.success) {
|
|
||||||
throw error({
|
throw error({
|
||||||
code: "MALFORMED_COLLECTION",
|
code: "MALFORMED_COLLECTION",
|
||||||
path,
|
path,
|
||||||
@@ -117,5 +75,5 @@ export async function parseCollectionData(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return getValidRequests(collectionSchemaParsedResult.data, path);
|
return maybeArrayOfCollections as HoppCollection[];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,40 +109,27 @@ export function getEffectiveRESTRequest(
|
|||||||
key: "Authorization",
|
key: "Authorization",
|
||||||
value: `Basic ${btoa(`${username}:${password}`)}`,
|
value: `Basic ${btoa(`${username}:${password}`)}`,
|
||||||
});
|
});
|
||||||
} else if (request.auth.authType === "bearer") {
|
} else if (
|
||||||
|
request.auth.authType === "bearer" ||
|
||||||
|
request.auth.authType === "oauth-2"
|
||||||
|
) {
|
||||||
effectiveFinalHeaders.push({
|
effectiveFinalHeaders.push({
|
||||||
active: true,
|
active: true,
|
||||||
key: "Authorization",
|
key: "Authorization",
|
||||||
value: `Bearer ${parseTemplateString(request.auth.token, envVariables)}`,
|
value: `Bearer ${parseTemplateString(
|
||||||
|
request.auth.token,
|
||||||
|
envVariables
|
||||||
|
)}`,
|
||||||
});
|
});
|
||||||
} else if (request.auth.authType === "oauth-2") {
|
|
||||||
const { addTo } = request.auth;
|
|
||||||
|
|
||||||
if (addTo === "HEADERS") {
|
|
||||||
effectiveFinalHeaders.push({
|
|
||||||
active: true,
|
|
||||||
key: "Authorization",
|
|
||||||
value: `Bearer ${parseTemplateString(request.auth.grantTypeInfo.token, envVariables)}`,
|
|
||||||
});
|
|
||||||
} else if (addTo === "QUERY_PARAMS") {
|
|
||||||
effectiveFinalParams.push({
|
|
||||||
active: true,
|
|
||||||
key: "access_token",
|
|
||||||
value: parseTemplateString(
|
|
||||||
request.auth.grantTypeInfo.token,
|
|
||||||
envVariables
|
|
||||||
),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else if (request.auth.authType === "api-key") {
|
} else if (request.auth.authType === "api-key") {
|
||||||
const { key, value, addTo } = request.auth;
|
const { key, value, addTo } = request.auth;
|
||||||
if (addTo === "HEADERS") {
|
if (addTo === "Headers") {
|
||||||
effectiveFinalHeaders.push({
|
effectiveFinalHeaders.push({
|
||||||
active: true,
|
active: true,
|
||||||
key: parseTemplateString(key, envVariables),
|
key: parseTemplateString(key, envVariables),
|
||||||
value: parseTemplateString(value, envVariables),
|
value: parseTemplateString(value, envVariables),
|
||||||
});
|
});
|
||||||
} else if (addTo === "QUERY_PARAMS") {
|
} else if (addTo === "Query params") {
|
||||||
effectiveFinalParams.push({
|
effectiveFinalParams.push({
|
||||||
active: true,
|
active: true,
|
||||||
key: parseTemplateString(key, envVariables),
|
key: parseTemplateString(key, envVariables),
|
||||||
|
|||||||
@@ -41,10 +41,10 @@ const processVariables = (variable: Environment["variables"][number]) => {
|
|||||||
...variable,
|
...variable,
|
||||||
value:
|
value:
|
||||||
"value" in variable ? variable.value : process.env[variable.key] || "",
|
"value" in variable ? variable.value : process.env[variable.key] || "",
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
return variable;
|
return variable
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Processes given envs, which includes processing each variable in global
|
* Processes given envs, which includes processing each variable in global
|
||||||
@@ -56,10 +56,10 @@ const processEnvs = (envs: HoppEnvs) => {
|
|||||||
const processedEnvs = {
|
const processedEnvs = {
|
||||||
global: envs.global.map(processVariables),
|
global: envs.global.map(processVariables),
|
||||||
selected: envs.selected.map(processVariables),
|
selected: envs.selected.map(processVariables),
|
||||||
};
|
}
|
||||||
|
|
||||||
return processedEnvs;
|
return processedEnvs
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transforms given request data to request-config used by request-runner to
|
* Transforms given request data to request-config used by request-runner to
|
||||||
@@ -70,7 +70,7 @@ const processEnvs = (envs: HoppEnvs) => {
|
|||||||
export const createRequest = (req: EffectiveHoppRESTRequest): RequestConfig => {
|
export const createRequest = (req: EffectiveHoppRESTRequest): RequestConfig => {
|
||||||
const config: RequestConfig = {
|
const config: RequestConfig = {
|
||||||
supported: true,
|
supported: true,
|
||||||
displayUrl: req.effectiveFinalDisplayURL,
|
displayUrl: req.effectiveFinalDisplayURL
|
||||||
};
|
};
|
||||||
const { finalBody, finalEndpoint, finalHeaders, finalParams } = getRequest;
|
const { finalBody, finalEndpoint, finalHeaders, finalParams } = getRequest;
|
||||||
const reqParams = finalParams(req);
|
const reqParams = finalParams(req);
|
||||||
@@ -131,7 +131,6 @@ export const requestRunner =
|
|||||||
let status: number;
|
let status: number;
|
||||||
const baseResponse = await axios(requestConfig);
|
const baseResponse = await axios(requestConfig);
|
||||||
const { config } = baseResponse;
|
const { config } = baseResponse;
|
||||||
// PR-COMMENT: type error
|
|
||||||
const runnerResponse: RequestRunnerResponse = {
|
const runnerResponse: RequestRunnerResponse = {
|
||||||
...baseResponse,
|
...baseResponse,
|
||||||
endpoint: getRequest.endpoint(config.url),
|
endpoint: getRequest.endpoint(config.url),
|
||||||
@@ -258,13 +257,10 @@ export const processRequest =
|
|||||||
let updatedEnvs = <HoppEnvs>{};
|
let updatedEnvs = <HoppEnvs>{};
|
||||||
|
|
||||||
// Fetch values for secret environment variables from system environment
|
// Fetch values for secret environment variables from system environment
|
||||||
const processedEnvs = processEnvs(envs);
|
const processedEnvs = processEnvs(envs)
|
||||||
|
|
||||||
// Executing pre-request-script
|
// Executing pre-request-script
|
||||||
const preRequestRes = await preRequestScriptRunner(
|
const preRequestRes = await preRequestScriptRunner(request, processedEnvs)();
|
||||||
request,
|
|
||||||
processedEnvs
|
|
||||||
)();
|
|
||||||
if (E.isLeft(preRequestRes)) {
|
if (E.isLeft(preRequestRes)) {
|
||||||
printPreRequestRunner.fail();
|
printPreRequestRunner.fail();
|
||||||
|
|
||||||
@@ -351,7 +347,7 @@ export const processRequest =
|
|||||||
*/
|
*/
|
||||||
export const preProcessRequest = (
|
export const preProcessRequest = (
|
||||||
request: HoppRESTRequest,
|
request: HoppRESTRequest,
|
||||||
collection: HoppCollection
|
collection: HoppCollection,
|
||||||
): HoppRESTRequest => {
|
): HoppRESTRequest => {
|
||||||
const tempRequest = Object.assign({}, request);
|
const tempRequest = Object.assign({}, request);
|
||||||
const { headers: parentHeaders, auth: parentAuth } = collection;
|
const { headers: parentHeaders, auth: parentAuth } = collection;
|
||||||
@@ -376,10 +372,8 @@ export const preProcessRequest = (
|
|||||||
// Filter out header entries present in the parent (folder/collection) under the same name
|
// Filter out header entries present in the parent (folder/collection) under the same name
|
||||||
// This ensures the child headers take precedence over the parent headers
|
// This ensures the child headers take precedence over the parent headers
|
||||||
const filteredEntries = parentHeaders.filter((parentHeaderEntries) => {
|
const filteredEntries = parentHeaders.filter((parentHeaderEntries) => {
|
||||||
return !tempRequest.headers.some(
|
return !tempRequest.headers.some((reqHeaderEntries) => reqHeaderEntries.key === parentHeaderEntries.key)
|
||||||
(reqHeaderEntries) => reqHeaderEntries.key === parentHeaderEntries.key
|
})
|
||||||
);
|
|
||||||
});
|
|
||||||
tempRequest.headers.push(...filteredEntries);
|
tempRequest.headers.push(...filteredEntries);
|
||||||
} else if (!tempRequest.headers) {
|
} else if (!tempRequest.headers) {
|
||||||
tempRequest.headers = [];
|
tempRequest.headers = [];
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "ESNext",
|
"target": "ES6",
|
||||||
"module": "ESNext",
|
"module": "commonjs",
|
||||||
"outDir": ".",
|
"outDir": ".",
|
||||||
"rootDir": ".",
|
"rootDir": ".",
|
||||||
"strict": true,
|
"strict": true,
|
||||||
|
|||||||
@@ -3,14 +3,17 @@ import { defineConfig } from "tsup";
|
|||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
entry: [ "./src/index.ts" ],
|
entry: [ "./src/index.ts" ],
|
||||||
outDir: "./dist/",
|
outDir: "./dist/",
|
||||||
format: ["esm"],
|
format: ["cjs"],
|
||||||
platform: "node",
|
platform: "node",
|
||||||
sourcemap: true,
|
sourcemap: true,
|
||||||
bundle: true,
|
bundle: true,
|
||||||
target: "esnext",
|
target: "node12",
|
||||||
skipNodeModulesBundle: false,
|
skipNodeModulesBundle: false,
|
||||||
esbuildOptions(options) {
|
esbuildOptions(options) {
|
||||||
options.bundle = true
|
options.bundle = true
|
||||||
},
|
},
|
||||||
|
noExternal: [
|
||||||
|
/\w+/
|
||||||
|
],
|
||||||
clean: true,
|
clean: true,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -10,9 +10,6 @@ module.exports = {
|
|||||||
parserOptions: {
|
parserOptions: {
|
||||||
sourceType: "module",
|
sourceType: "module",
|
||||||
requireConfigFile: false,
|
requireConfigFile: false,
|
||||||
ecmaFeatures: {
|
|
||||||
jsx: false,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
extends: [
|
extends: [
|
||||||
"@vue/typescript/recommended",
|
"@vue/typescript/recommended",
|
||||||
|
|||||||
@@ -563,22 +563,12 @@ details[open] summary .indicator {
|
|||||||
.env-highlight {
|
.env-highlight {
|
||||||
@apply text-accentContrast;
|
@apply text-accentContrast;
|
||||||
|
|
||||||
&.request-variable-highlight {
|
&.env-found {
|
||||||
@apply bg-amber-500;
|
@apply bg-accentDark;
|
||||||
@apply hover:bg-amber-600;
|
@apply hover:bg-accent;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.environment-variable-highlight {
|
&.env-not-found {
|
||||||
@apply bg-green-500;
|
|
||||||
@apply hover:bg-green-600;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.global-variable-highlight {
|
|
||||||
@apply bg-blue-500;
|
|
||||||
@apply hover:bg-blue-600;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.environment-not-found-highlight {
|
|
||||||
@apply bg-red-500;
|
@apply bg-red-500;
|
||||||
@apply hover:bg-red-600;
|
@apply hover:bg-red-600;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,6 @@
|
|||||||
"hide_secret": "Hide secret",
|
"hide_secret": "Hide secret",
|
||||||
"label": "Label",
|
"label": "Label",
|
||||||
"learn_more": "Learn more",
|
"learn_more": "Learn more",
|
||||||
"download_here": "Download here",
|
|
||||||
"less": "Less",
|
"less": "Less",
|
||||||
"more": "More",
|
"more": "More",
|
||||||
"new": "New",
|
"new": "New",
|
||||||
@@ -104,10 +103,8 @@
|
|||||||
"auth": {
|
"auth": {
|
||||||
"account_exists": "Account exists with different credential - Login to link both accounts",
|
"account_exists": "Account exists with different credential - Login to link both accounts",
|
||||||
"all_sign_in_options": "All sign in options",
|
"all_sign_in_options": "All sign in options",
|
||||||
"continue_with_auth_provider": "Continue with {provider}",
|
|
||||||
"continue_with_email": "Continue with Email",
|
"continue_with_email": "Continue with Email",
|
||||||
"continue_with_github": "Continue with GitHub",
|
"continue_with_github": "Continue with GitHub",
|
||||||
"continue_with_github_enterprise": "Continue with GitHub Enterprise",
|
|
||||||
"continue_with_google": "Continue with Google",
|
"continue_with_google": "Continue with Google",
|
||||||
"continue_with_microsoft": "Continue with Microsoft",
|
"continue_with_microsoft": "Continue with Microsoft",
|
||||||
"email": "Email",
|
"email": "Email",
|
||||||
@@ -140,30 +137,9 @@
|
|||||||
"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": "Pass by",
|
"pass_key_by": "Pass by",
|
||||||
"pass_by_query_params_label": "Query Parameters",
|
|
||||||
"pass_by_headers_label": "Headers",
|
|
||||||
"password": "Password",
|
"password": "Password",
|
||||||
"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": "Token",
|
"token": "Token",
|
||||||
@@ -175,11 +151,10 @@
|
|||||||
"different_parent": "Cannot reorder collection with different parent",
|
"different_parent": "Cannot reorder collection with different parent",
|
||||||
"edit": "Edit Collection",
|
"edit": "Edit Collection",
|
||||||
"import_or_create": "Import or create a collection",
|
"import_or_create": "Import or create a collection",
|
||||||
"import_collection":"Import Collection",
|
|
||||||
"invalid_name": "Please provide a name for the collection",
|
"invalid_name": "Please provide a name for the collection",
|
||||||
"invalid_root_move": "Collection already in the root",
|
"invalid_root_move": "Collection already in the root",
|
||||||
"moved": "Moved Successfully",
|
"moved": "Moved Successfully",
|
||||||
"my_collections": "Personal Collections",
|
"my_collections": "My Collections",
|
||||||
"name": "My New Collection",
|
"name": "My New Collection",
|
||||||
"name_length_insufficient": "Collection name should be at least 3 characters long",
|
"name_length_insufficient": "Collection name should be at least 3 characters long",
|
||||||
"new": "New Collection",
|
"new": "New Collection",
|
||||||
@@ -191,12 +166,14 @@
|
|||||||
"save_as": "Save as",
|
"save_as": "Save as",
|
||||||
"save_to_collection": "Save to Collection",
|
"save_to_collection": "Save to Collection",
|
||||||
"select": "Select a Collection",
|
"select": "Select a Collection",
|
||||||
"select_location": "Select location"
|
"select_location": "Select location",
|
||||||
|
"select_team": "Select a team",
|
||||||
|
"team_collections": "Team Collections"
|
||||||
},
|
},
|
||||||
"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?",
|
||||||
"close_unsaved_tabs": "Are you sure you want to close all tabs? {count} unsaved tabs will be lost.",
|
"close_unsaved_tabs": "Are you sure you want to close all tabs? {count} unsaved tabs will be lost.",
|
||||||
"exit_team": "Are you sure you want to leave this workspace?",
|
"exit_team": "Are you sure you want to leave this team?",
|
||||||
"logout": "Are you sure you want to logout?",
|
"logout": "Are you sure you want to logout?",
|
||||||
"remove_collection": "Are you sure you want to permanently delete this collection?",
|
"remove_collection": "Are you sure you want to permanently delete this collection?",
|
||||||
"remove_environment": "Are you sure you want to permanently delete this environment?",
|
"remove_environment": "Are you sure you want to permanently delete this environment?",
|
||||||
@@ -204,7 +181,7 @@
|
|||||||
"remove_history": "Are you sure you want to permanently delete all history?",
|
"remove_history": "Are you sure you want to permanently delete all history?",
|
||||||
"remove_request": "Are you sure you want to permanently delete this request?",
|
"remove_request": "Are you sure you want to permanently delete this request?",
|
||||||
"remove_shared_request": "Are you sure you want to permanently delete this shared request?",
|
"remove_shared_request": "Are you sure you want to permanently delete this shared request?",
|
||||||
"remove_team": "Are you sure you want to delete this workspace?",
|
"remove_team": "Are you sure you want to delete this team?",
|
||||||
"remove_telemetry": "Are you sure you want to opt-out of Telemetry?",
|
"remove_telemetry": "Are you sure you want to opt-out of Telemetry?",
|
||||||
"request_change": "Are you sure you want to discard current request, unsaved changes will be lost.",
|
"request_change": "Are you sure you want to discard current request, unsaved changes will be lost.",
|
||||||
"save_unsaved_tab": "Do you want to save changes made in this tab?",
|
"save_unsaved_tab": "Do you want to save changes made in this tab?",
|
||||||
@@ -257,19 +234,18 @@
|
|||||||
"headers": "This request does not have any headers",
|
"headers": "This request does not have any headers",
|
||||||
"history": "History is empty",
|
"history": "History is empty",
|
||||||
"invites": "Invite list is empty",
|
"invites": "Invite list is empty",
|
||||||
"members": "Workspace is empty",
|
"members": "Team is empty",
|
||||||
"parameters": "This request does not have any parameters",
|
"parameters": "This request does not have any parameters",
|
||||||
"pending_invites": "There are no pending invites for this workspace",
|
"pending_invites": "There are no pending invites for this team",
|
||||||
"profile": "Login to view your profile",
|
"profile": "Login to view your profile",
|
||||||
"protocols": "Protocols are empty",
|
"protocols": "Protocols are empty",
|
||||||
"request_variables": "This request does not have any request variables",
|
|
||||||
"schema": "Connect to a GraphQL endpoint to view schema",
|
"schema": "Connect to a GraphQL endpoint to view schema",
|
||||||
"secret_environments": "Secrets are not synced to Hoppscotch",
|
"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": "Workspace name empty",
|
"team_name": "Team name empty",
|
||||||
"teams": "You don't belong to any workspaces",
|
"teams": "You don't belong to any teams",
|
||||||
"tests": "There are no tests for this request"
|
"tests": "There are no tests for this request"
|
||||||
},
|
},
|
||||||
"environment": {
|
"environment": {
|
||||||
@@ -286,7 +262,7 @@
|
|||||||
"import_or_create": "Import or create a environment",
|
"import_or_create": "Import or create a environment",
|
||||||
"invalid_name": "Please provide a name for the environment",
|
"invalid_name": "Please provide a name for the environment",
|
||||||
"list": "Environment variables",
|
"list": "Environment variables",
|
||||||
"my_environments": "Personal Environments",
|
"my_environments": "My Environments",
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
"nested_overflow": "nested environment variables are limited to 10 levels",
|
"nested_overflow": "nested environment variables are limited to 10 levels",
|
||||||
"new": "New Environment",
|
"new": "New Environment",
|
||||||
@@ -301,12 +277,12 @@
|
|||||||
"select": "Select environment",
|
"select": "Select environment",
|
||||||
"set": "Set environment",
|
"set": "Set environment",
|
||||||
"set_as_environment": "Set as environment",
|
"set_as_environment": "Set as environment",
|
||||||
"team_environments": "Workspace Environments",
|
"team_environments": "Team Environments",
|
||||||
"title": "Environments",
|
"title": "Environments",
|
||||||
"updated": "Environment updated",
|
"updated": "Environment updated",
|
||||||
"value": "Value",
|
"value": "Value",
|
||||||
"variable": "Variable",
|
"variable": "Variable",
|
||||||
"variables": "Variables",
|
"variables":"Variables",
|
||||||
"variable_list": "Variable List"
|
"variable_list": "Variable List"
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
@@ -316,9 +292,8 @@
|
|||||||
"check_how_to_add_origin": "Check how you can add an origin",
|
"check_how_to_add_origin": "Check how you can add an origin",
|
||||||
"curl_invalid_format": "cURL is not formatted properly",
|
"curl_invalid_format": "cURL is not formatted properly",
|
||||||
"danger_zone": "Danger zone",
|
"danger_zone": "Danger zone",
|
||||||
"delete_account": "Your account is currently an owner in these workspaces:",
|
"delete_account": "Your account is currently an owner in these teams:",
|
||||||
"delete_account_description": "You must either remove yourself, transfer ownership, or delete these workspaces 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": "Empty Request Name",
|
"empty_req_name": "Empty Request Name",
|
||||||
"f12_details": "(F12 for details)",
|
"f12_details": "(F12 for details)",
|
||||||
"gql_prettify_invalid_query": "Couldn't prettify an invalid query, solve query syntax errors and try again",
|
"gql_prettify_invalid_query": "Couldn't prettify an invalid query, solve query syntax errors and try again",
|
||||||
@@ -338,11 +313,9 @@
|
|||||||
"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": "Could not execute pre-request script",
|
"script_fail": "Could not execute pre-request script",
|
||||||
"something_went_wrong": "Something went wrong",
|
"something_went_wrong": "Something went wrong",
|
||||||
"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": "Export as JSON",
|
"as_json": "Export as JSON",
|
||||||
@@ -374,8 +347,7 @@
|
|||||||
"mutations": "Mutations",
|
"mutations": "Mutations",
|
||||||
"schema": "Schema",
|
"schema": "Schema",
|
||||||
"subscriptions": "Subscriptions",
|
"subscriptions": "Subscriptions",
|
||||||
"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"
|
||||||
@@ -422,8 +394,8 @@
|
|||||||
"from_insomnia_description": "Import from Insomnia collection",
|
"from_insomnia_description": "Import from Insomnia collection",
|
||||||
"from_json": "Import from Hoppscotch",
|
"from_json": "Import from Hoppscotch",
|
||||||
"from_json_description": "Import from Hoppscotch collection file",
|
"from_json_description": "Import from Hoppscotch collection file",
|
||||||
"from_my_collections": "Import from Personal Collections",
|
"from_my_collections": "Import from My Collections",
|
||||||
"from_my_collections_description": "Import from Personal Collections file",
|
"from_my_collections_description": "Import from My Collections file",
|
||||||
"from_openapi": "Import from OpenAPI",
|
"from_openapi": "Import from OpenAPI",
|
||||||
"from_openapi_description": "Import from OpenAPI specification file (YML/JSON)",
|
"from_openapi_description": "Import from OpenAPI specification file (YML/JSON)",
|
||||||
"from_postman": "Import from Postman",
|
"from_postman": "Import from Postman",
|
||||||
@@ -441,10 +413,7 @@
|
|||||||
"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",
|
||||||
"title": "Import",
|
"title": "Import"
|
||||||
"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.",
|
|
||||||
"success": "Successfully imported"
|
|
||||||
},
|
},
|
||||||
"inspections": {
|
"inspections": {
|
||||||
"description": "Inspect possible errors",
|
"description": "Inspect possible errors",
|
||||||
@@ -455,7 +424,7 @@
|
|||||||
"not_found": "Environment variable “{environment}” not found."
|
"not_found": "Environment variable “{environment}” not found."
|
||||||
},
|
},
|
||||||
"header": {
|
"header": {
|
||||||
"cookie": "The browser doesn't allow Hoppscotch to set Cookie Headers. Please use Authorization Headers instead. However, our Hoppscotch Desktop App is live now and supports Cookies."
|
"cookie": "The browser doesn't allow Hoppscotch to set the Cookie Header. While we're working on the Hoppscotch Desktop App (coming soon), please use the Authorization Header instead."
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"401_error": "Please check your authentication credentials.",
|
"401_error": "Please check your authentication credentials.",
|
||||||
@@ -540,7 +509,7 @@
|
|||||||
"email_verification_mail": "A verification email has been sent to your email address. Please click on the link to verify your email address.",
|
"email_verification_mail": "A verification email has been sent to your email address. Please click on the link to verify your email address.",
|
||||||
"no_permission": "You do not have permission to perform this action.",
|
"no_permission": "You do not have permission to perform this action.",
|
||||||
"owner": "Owner",
|
"owner": "Owner",
|
||||||
"owner_description": "Owners can add, edit, and delete requests, collections and workspace members.",
|
"owner_description": "Owners can add, edit, and delete requests, collections and team members.",
|
||||||
"roles": "Roles",
|
"roles": "Roles",
|
||||||
"roles_description": "Roles are used to control access to the shared collections.",
|
"roles_description": "Roles are used to control access to the shared collections.",
|
||||||
"updated": "Profile updated",
|
"updated": "Profile updated",
|
||||||
@@ -587,7 +556,6 @@
|
|||||||
"raw_body": "Raw Request Body",
|
"raw_body": "Raw Request Body",
|
||||||
"rename": "Rename Request",
|
"rename": "Rename Request",
|
||||||
"renamed": "Request renamed",
|
"renamed": "Request renamed",
|
||||||
"request_variables": "Request variables",
|
|
||||||
"run": "Run",
|
"run": "Run",
|
||||||
"save": "Save",
|
"save": "Save",
|
||||||
"save_as": "Save as",
|
"save_as": "Save as",
|
||||||
@@ -599,7 +567,6 @@
|
|||||||
"title": "Request",
|
"title": "Request",
|
||||||
"type": "Request type",
|
"type": "Request type",
|
||||||
"url": "URL",
|
"url": "URL",
|
||||||
"url_placeholder": "Enter a URL or paste a cURL command",
|
|
||||||
"variables": "Variables",
|
"variables": "Variables",
|
||||||
"view_my_links": "View my links"
|
"view_my_links": "View my links"
|
||||||
},
|
},
|
||||||
@@ -846,19 +813,12 @@
|
|||||||
"title": "Tabs"
|
"title": "Tabs"
|
||||||
},
|
},
|
||||||
"workspace": {
|
"workspace": {
|
||||||
"delete": "Delete current workspace",
|
"delete": "Delete current team",
|
||||||
"edit": "Edit current workspace",
|
"edit": "Edit current team",
|
||||||
"invite": "Invite people to workspace",
|
"invite": "Invite people to team",
|
||||||
"new": "Create new workspace",
|
"new": "Create new team",
|
||||||
"switch_to_personal": "Switch to your personal workspace",
|
"switch_to_personal": "Switch to your personal workspace",
|
||||||
"title": "Workspaces"
|
"title": "Teams"
|
||||||
},
|
|
||||||
"phrases":{
|
|
||||||
"try": "Try",
|
|
||||||
"import_collections": "Import collections",
|
|
||||||
"create_environment": "Create environment",
|
|
||||||
"create_workspace": "Create workspace",
|
|
||||||
"share_request": "Share request"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sse": {
|
"sse": {
|
||||||
@@ -915,6 +875,7 @@
|
|||||||
"forum": "Ask questions and get answers",
|
"forum": "Ask questions and get answers",
|
||||||
"github": "Follow us on Github",
|
"github": "Follow us on Github",
|
||||||
"shortcuts": "Browse app faster",
|
"shortcuts": "Browse app faster",
|
||||||
|
"team": "Get in touch with the team",
|
||||||
"title": "Support",
|
"title": "Support",
|
||||||
"twitter": "Follow us on Twitter"
|
"twitter": "Follow us on Twitter"
|
||||||
},
|
},
|
||||||
@@ -945,60 +906,60 @@
|
|||||||
"websocket": "WebSocket"
|
"websocket": "WebSocket"
|
||||||
},
|
},
|
||||||
"team": {
|
"team": {
|
||||||
"already_member": "You are already a member of this workspace. Contact your workspace owner.",
|
"already_member": "You are already a member of this team. Contact your team owner.",
|
||||||
"create_new": "Create new workspace",
|
"create_new": "Create new team",
|
||||||
"deleted": "Workspace deleted",
|
"deleted": "Team deleted",
|
||||||
"edit": "Edit Workspace",
|
"edit": "Edit Team",
|
||||||
"email": "E-mail",
|
"email": "E-mail",
|
||||||
"email_do_not_match": "Email doesn't match with your account details. Contact your workspace owner.",
|
"email_do_not_match": "Email doesn't match with your account details. Contact your team owner.",
|
||||||
"exit": "Exit Workspace",
|
"exit": "Exit Team",
|
||||||
"exit_disabled": "Only owner cannot exit the workspace",
|
"exit_disabled": "Only owner cannot exit the team",
|
||||||
"failed_invites": "Failed invites",
|
"failed_invites": "Failed invites",
|
||||||
"invalid_coll_id": "Invalid collection ID",
|
"invalid_coll_id": "Invalid collection ID",
|
||||||
"invalid_email_format": "Email format is invalid",
|
"invalid_email_format": "Email format is invalid",
|
||||||
"invalid_id": "Invalid workspace ID. Contact your workspace owner.",
|
"invalid_id": "Invalid team ID. Contact your team owner.",
|
||||||
"invalid_invite_link": "Invalid invite link",
|
"invalid_invite_link": "Invalid invite link",
|
||||||
"invalid_invite_link_description": "The link you followed is invalid. Contact your workspace owner.",
|
"invalid_invite_link_description": "The link you followed is invalid. Contact your team owner.",
|
||||||
"invalid_member_permission": "Please provide a valid permission to the workspace member",
|
"invalid_member_permission": "Please provide a valid permission to the team member",
|
||||||
"invite": "Invite",
|
"invite": "Invite",
|
||||||
"invite_more": "Invite more",
|
"invite_more": "Invite more",
|
||||||
"invite_tooltip": "Invite people to this workspace",
|
"invite_tooltip": "Invite people to this workspace",
|
||||||
"invited_to_team": "{owner} invited you to join {workspace}",
|
"invited_to_team": "{owner} invited you to join {team}",
|
||||||
"join": "Invitation accepted",
|
"join": "Invitation accepted",
|
||||||
"join_team": "Join {workspace}",
|
"join_beta": "Join the beta program to access teams.",
|
||||||
"joined_team": "You have joined {workspace}",
|
"join_team": "Join {team}",
|
||||||
"joined_team_description": "You are now a member of this workspace",
|
"joined_team": "You have joined {team}",
|
||||||
"left": "You left the workspace",
|
"joined_team_description": "You are now a member of this team",
|
||||||
|
"left": "You left the team",
|
||||||
"login_to_continue": "Login to continue",
|
"login_to_continue": "Login to continue",
|
||||||
"login_to_continue_description": "You need to be logged in to join a workspace.",
|
"login_to_continue_description": "You need to be logged in to join a team.",
|
||||||
"logout_and_try_again": "Logout and sign in with another account",
|
"logout_and_try_again": "Logout and sign in with another account",
|
||||||
"member_has_invite": "This email ID already has an invite. Contact your workspace owner.",
|
"member_has_invite": "This email ID already has an invite. Contact your team owner.",
|
||||||
"member_not_found": "Member not found. Contact your workspace owner.",
|
"member_not_found": "Member not found. Contact your team owner.",
|
||||||
"member_removed": "User removed",
|
"member_removed": "User removed",
|
||||||
"member_role_updated": "User roles updated",
|
"member_role_updated": "User roles updated",
|
||||||
"members": "Members",
|
"members": "Members",
|
||||||
"more_members": "+{count} more",
|
"more_members": "+{count} more",
|
||||||
"name_length_insufficient": "Workspace name should be at least 6 characters long",
|
"name_length_insufficient": "Team name should be at least 6 characters long",
|
||||||
"name_updated": "Workspace name updated",
|
"name_updated": "Team name updated",
|
||||||
"new": "New Workspace",
|
"new": "New Team",
|
||||||
"new_created": "New workspace created",
|
"new_created": "New team created",
|
||||||
"new_name": "My New Workspace",
|
"new_name": "My New Team",
|
||||||
"no_access": "You do not have edit access to this workspace",
|
"no_access": "You do not have edit access to this team",
|
||||||
"no_invite_found": "Invitation not found. Contact your workspace owner.",
|
"no_invite_found": "Invitation not found. Contact your team owner.",
|
||||||
"no_request_found": "Request not found.",
|
"no_request_found": "Request not found.",
|
||||||
"not_found": "Workspace not found. Contact your workspace owner.",
|
"not_found": "Team not found. Contact your team owner.",
|
||||||
"not_valid_viewer": "You are not a valid viewer. Contact your workspace owner.",
|
"not_valid_viewer": "You are not a valid viewer. Contact your team owner.",
|
||||||
"parent_coll_move": "Cannot move collection to a child collection",
|
"parent_coll_move": "Cannot move collection to a child collection",
|
||||||
"pending_invites": "Pending invites",
|
"pending_invites": "Pending invites",
|
||||||
"permissions": "Permissions",
|
"permissions": "Permissions",
|
||||||
"same_target_destination": "Same target and destination",
|
"same_target_destination": "Same target and destination",
|
||||||
"saved": "Workspace saved",
|
"saved": "Team saved",
|
||||||
"select_a_team": "Select a workspace",
|
"select_a_team": "Select a team",
|
||||||
"success_invites": "Success invites",
|
"success_invites": "Success invites",
|
||||||
"title": "Workspaces",
|
"title": "Teams",
|
||||||
"we_sent_invite_link": "We sent an invite link to all invitees!",
|
"we_sent_invite_link": "We sent an invite link to all invitees!",
|
||||||
"we_sent_invite_link_description": "Ask all invitees to check their inbox. Click on the link to join the workspace.",
|
"we_sent_invite_link_description": "Ask all invitees to check their inbox. Click on the link to join the team."
|
||||||
"search_title": "Team Requests"
|
|
||||||
},
|
},
|
||||||
"team_environment": {
|
"team_environment": {
|
||||||
"deleted": "Environment Deleted",
|
"deleted": "Environment Deleted",
|
||||||
@@ -1024,14 +985,8 @@
|
|||||||
},
|
},
|
||||||
"workspace": {
|
"workspace": {
|
||||||
"change": "Change workspace",
|
"change": "Change workspace",
|
||||||
"personal": "Personal Workspace",
|
"personal": "My Workspace",
|
||||||
"other_workspaces": "My Workspaces",
|
"team": "Team Workspace",
|
||||||
"team": "Workspace",
|
|
||||||
"title": "Workspaces"
|
"title": "Workspaces"
|
||||||
},
|
|
||||||
"site_protection": {
|
|
||||||
"login_to_continue": "Login to continue",
|
|
||||||
"login_to_continue_description": "You need to be logged in to access this Hoppscotch Enterprise Instance.",
|
|
||||||
"error_fetching_site_protection_status": "Something Went Wrong While Fetching Site Protection Status"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,8 +32,8 @@
|
|||||||
"no": "No",
|
"no": "No",
|
||||||
"open_workspace": "Abrir espacio de trabajo",
|
"open_workspace": "Abrir espacio de trabajo",
|
||||||
"paste": "Pegar",
|
"paste": "Pegar",
|
||||||
"prettify": "Formatear",
|
"prettify": "Embellecer",
|
||||||
"properties": "Propiedades",
|
"properties": "Properties",
|
||||||
"remove": "Eliminar",
|
"remove": "Eliminar",
|
||||||
"rename": "Rename",
|
"rename": "Rename",
|
||||||
"restore": "Restaurar",
|
"restore": "Restaurar",
|
||||||
@@ -63,7 +63,7 @@
|
|||||||
"contact_us": "Contáctanos",
|
"contact_us": "Contáctanos",
|
||||||
"cookies": "Cookies",
|
"cookies": "Cookies",
|
||||||
"copy": "Copiar",
|
"copy": "Copiar",
|
||||||
"copy_interface_type": "Copiar tipo de interfaz",
|
"copy_interface_type": "Copy interface type",
|
||||||
"copy_user_id": "Copiar token de autenticación de usuario",
|
"copy_user_id": "Copiar token de autenticación de usuario",
|
||||||
"developer_option": "Opciones para desarrolladores",
|
"developer_option": "Opciones para desarrolladores",
|
||||||
"developer_option_description": "Herramientas para desarrolladores que ayudan en el desarrollo y mantenimiento de Hoppscotch.",
|
"developer_option_description": "Herramientas para desarrolladores que ayudan en el desarrollo y mantenimiento de Hoppscotch.",
|
||||||
@@ -80,14 +80,14 @@
|
|||||||
"name": "Hoppscotch",
|
"name": "Hoppscotch",
|
||||||
"new_version_found": "Se ha encontrado una nueva versión. Recarga la página para usarla.",
|
"new_version_found": "Se ha encontrado una nueva versión. Recarga la página para usarla.",
|
||||||
"open_in_hoppscotch": "Open in Hoppscotch",
|
"open_in_hoppscotch": "Open in Hoppscotch",
|
||||||
"options": "Opciones",
|
"options": "Options",
|
||||||
"proxy_privacy_policy": "Política de privacidad de proxy",
|
"proxy_privacy_policy": "Política de privacidad de proxy",
|
||||||
"reload": "Recargar",
|
"reload": "Recargar",
|
||||||
"search": "Buscar",
|
"search": "Buscar",
|
||||||
"share": "Compartir",
|
"share": "Compartir",
|
||||||
"shortcuts": "Atajos",
|
"shortcuts": "Atajos",
|
||||||
"social_description": "Síguenos en redes sociales para estar al día de las últimas noticias, actualizaciones y lanzamientos.",
|
"social_description": "Follow us on social media to stay updated with the latest news, updates and releases.",
|
||||||
"social_links": "Redes sociales",
|
"social_links": "Social links",
|
||||||
"spotlight": "Destacar",
|
"spotlight": "Destacar",
|
||||||
"status": "Estado",
|
"status": "Estado",
|
||||||
"status_description": "Comprobar el estado del sitio web",
|
"status_description": "Comprobar el estado del sitio web",
|
||||||
@@ -119,27 +119,27 @@
|
|||||||
},
|
},
|
||||||
"authorization": {
|
"authorization": {
|
||||||
"generate_token": "Generar token",
|
"generate_token": "Generar token",
|
||||||
"graphql_headers": "Las cabeceras de autorización se envían como parte de la carga útil de connection_init",
|
"graphql_headers": "Authorization Headers are sent as part of the payload to connection_init",
|
||||||
"include_in_url": "Incluir en la URL",
|
"include_in_url": "Incluir en la URL",
|
||||||
"inherited_from": "Heredado {auth} de colección padre {collection} ",
|
"inherited_from": "Inherited from {auth} from Parent Collection {collection} ",
|
||||||
"learn": "Aprender",
|
"learn": "Aprender",
|
||||||
"oauth": {
|
"oauth": {
|
||||||
"redirect_auth_server_returned_error": "El servidor de autenticación ha devuelto un estado de error",
|
"redirect_auth_server_returned_error": "Auth Server returned an error state",
|
||||||
"redirect_auth_token_request_failed": "Fallo en la solicitud de token de autentificación",
|
"redirect_auth_token_request_failed": "Request to get the auth token failed",
|
||||||
"redirect_auth_token_request_invalid_response": "Respuesta no válida del punto final de Token al solicitar un token de autentificación",
|
"redirect_auth_token_request_invalid_response": "Invalid Response from the Token Endpoint when requesting for an auth token",
|
||||||
"redirect_invalid_state": "Valor de estado no válido presente en la redirección",
|
"redirect_invalid_state": "Invalid State value present in the redirect",
|
||||||
"redirect_no_auth_code": "No hay código de autorización en la redirección",
|
"redirect_no_auth_code": "No Authorization Code present in the redirect",
|
||||||
"redirect_no_client_id": "No se ha definido el ID de cliente",
|
"redirect_no_client_id": "No Client ID defined",
|
||||||
"redirect_no_client_secret": "No se ha definido ningún ID secreto de cliente",
|
"redirect_no_client_secret": "No Client Secret Defined",
|
||||||
"redirect_no_code_verifier": "No se ha definido ningún verificador de códigos",
|
"redirect_no_code_verifier": "No Code Verifier Defined",
|
||||||
"redirect_no_token_endpoint": "No se ha definido ningún punto final de token",
|
"redirect_no_token_endpoint": "No Token Endpoint Defined",
|
||||||
"something_went_wrong_on_oauth_redirect": "Algo ha ido mal durante la redirección OAuth",
|
"something_went_wrong_on_oauth_redirect": "Something went wrong during OAuth Redirect",
|
||||||
"something_went_wrong_on_token_generation": "Algo salió mal en la generación del token",
|
"something_went_wrong_on_token_generation": "Something went wrong on token generation",
|
||||||
"token_generation_oidc_discovery_failed": "Fallo en la generación del token: OpenID Connect Discovery Failed"
|
"token_generation_oidc_discovery_failed": "Failure on token generation: OpenID Connect Discovery Failed"
|
||||||
},
|
},
|
||||||
"pass_key_by": "Pasar por",
|
"pass_key_by": "Pasar por",
|
||||||
"password": "Contraseña",
|
"password": "Contraseña",
|
||||||
"save_to_inherit": "Por favor, guarda esta solicitud en cualquier colección para heredar la autorización",
|
"save_to_inherit": "Please save this request in any collection to inherit the authorization",
|
||||||
"token": "Token",
|
"token": "Token",
|
||||||
"type": "Tipo de autorización",
|
"type": "Tipo de autorización",
|
||||||
"username": "Nombre de usuario"
|
"username": "Nombre de usuario"
|
||||||
@@ -148,7 +148,7 @@
|
|||||||
"created": "Colección creada",
|
"created": "Colección creada",
|
||||||
"different_parent": "No se puede reordenar la colección con un padre diferente",
|
"different_parent": "No se puede reordenar la colección con un padre diferente",
|
||||||
"edit": "Editar colección",
|
"edit": "Editar colección",
|
||||||
"import_or_create": "Importar o crear una colección",
|
"import_or_create": "Import or create a collection",
|
||||||
"invalid_name": "Proporciona un nombre válido para la colección.",
|
"invalid_name": "Proporciona un nombre válido para la colección.",
|
||||||
"invalid_root_move": "La colección ya está en la raíz",
|
"invalid_root_move": "La colección ya está en la raíz",
|
||||||
"moved": "Movido con éxito",
|
"moved": "Movido con éxito",
|
||||||
@@ -157,20 +157,20 @@
|
|||||||
"name_length_insufficient": "El nombre de la colección debe tener al menos 3 caracteres",
|
"name_length_insufficient": "El nombre de la colección debe tener al menos 3 caracteres",
|
||||||
"new": "Nueva colección",
|
"new": "Nueva colección",
|
||||||
"order_changed": "Orden de colección actualizada",
|
"order_changed": "Orden de colección actualizada",
|
||||||
"properties": "Propiedades de la colección",
|
"properties": "Collection Properties",
|
||||||
"properties_updated": "Propiedades de la colección actualizadas",
|
"properties_updated": "Collection Properties Updated",
|
||||||
"renamed": "Colección renombrada",
|
"renamed": "Colección renombrada",
|
||||||
"request_in_use": "Solicitud en uso",
|
"request_in_use": "Solicitud en uso",
|
||||||
"save_as": "Guardar como",
|
"save_as": "Guardar como",
|
||||||
"save_to_collection": "Guardar en la colección",
|
"save_to_collection": "Save to Collection",
|
||||||
"select": "Seleccionar colección",
|
"select": "Seleccionar colección",
|
||||||
"select_location": "Seleccionar ubicación",
|
"select_location": "Seleccionar ubicación",
|
||||||
"select_team": "Seleccionar equipo",
|
"select_team": "Seleccionar equipo",
|
||||||
"team_collections": "Colecciones de equipos"
|
"team_collections": "Colecciones de equipos"
|
||||||
},
|
},
|
||||||
"confirm": {
|
"confirm": {
|
||||||
"close_unsaved_tab": "¿Seguro que quieres cerrar esta pestaña?",
|
"close_unsaved_tab": "Are you sure you want to close this tab?",
|
||||||
"close_unsaved_tabs": "¿Estás seguro de que quieres cerrar todas las pestañas? {count} pestañas no guardadas se perderán.",
|
"close_unsaved_tabs": "Are you sure you want to close all tabs? {count} unsaved tabs will be lost.",
|
||||||
"exit_team": "¿Estás seguro de que quieres dejar este equipo?",
|
"exit_team": "¿Estás seguro de que quieres dejar este equipo?",
|
||||||
"logout": "¿Estás seguro de que deseas cerrar la sesión?",
|
"logout": "¿Estás seguro de que deseas cerrar la sesión?",
|
||||||
"remove_collection": "¿Estás seguro de que deseas eliminar esta colección de forma permanente?",
|
"remove_collection": "¿Estás seguro de que deseas eliminar esta colección de forma permanente?",
|
||||||
@@ -178,7 +178,7 @@
|
|||||||
"remove_folder": "¿Estás seguro de que deseas eliminar esta carpeta de forma permanente?",
|
"remove_folder": "¿Estás seguro de que deseas eliminar esta carpeta de forma permanente?",
|
||||||
"remove_history": "¿Estás seguro de que deseas eliminar todo el historial de forma permanente?",
|
"remove_history": "¿Estás seguro de que deseas eliminar todo el historial de forma permanente?",
|
||||||
"remove_request": "¿Estás seguro de que deseas eliminar esta solicitud de forma permanente?",
|
"remove_request": "¿Estás seguro de que deseas eliminar esta solicitud de forma permanente?",
|
||||||
"remove_shared_request": "¿Estás seguro de que quieres eliminar definitivamente esta solicitud compartida?",
|
"remove_shared_request": "Are you sure you want to permanently delete this shared request?",
|
||||||
"remove_team": "¿Estás seguro de que deseas eliminar este equipo?",
|
"remove_team": "¿Estás seguro de que deseas eliminar este equipo?",
|
||||||
"remove_telemetry": "¿Estás seguro de que deseas darse de baja de la telemetría?",
|
"remove_telemetry": "¿Estás seguro de que deseas darse de baja de la telemetría?",
|
||||||
"request_change": "¿Estás seguro de que deseas descartar la solicitud actual, los cambios no guardados se perderán.",
|
"request_change": "¿Estás seguro de que deseas descartar la solicitud actual, los cambios no guardados se perderán.",
|
||||||
@@ -186,35 +186,35 @@
|
|||||||
"sync": "¿Estás seguro de que deseas sincronizar este espacio de trabajo?"
|
"sync": "¿Estás seguro de que deseas sincronizar este espacio de trabajo?"
|
||||||
},
|
},
|
||||||
"context_menu": {
|
"context_menu": {
|
||||||
"add_parameters": "Añadir a parámetros",
|
"add_parameters": "Add to parameters",
|
||||||
"open_request_in_new_tab": "Abrir solicitud en una nueva pestaña",
|
"open_request_in_new_tab": "Open request in new tab",
|
||||||
"set_environment_variable": "Establecer como variable"
|
"set_environment_variable": "Set as variable"
|
||||||
},
|
},
|
||||||
"cookies": {
|
"cookies": {
|
||||||
"modal": {
|
"modal": {
|
||||||
"cookie_expires": "Expira en",
|
"cookie_expires": "Expires",
|
||||||
"cookie_name": "Nombre",
|
"cookie_name": "Name",
|
||||||
"cookie_path": "Ruta",
|
"cookie_path": "Path",
|
||||||
"cookie_string": "Cookies",
|
"cookie_string": "Cookie string",
|
||||||
"cookie_value": "Valor",
|
"cookie_value": "Value",
|
||||||
"empty_domain": "Dominio vacio",
|
"empty_domain": "Domain is empty",
|
||||||
"empty_domains": "No hay dominios",
|
"empty_domains": "Domain list is empty",
|
||||||
"enter_cookie_string": "Introducir cookies",
|
"enter_cookie_string": "Enter cookie string",
|
||||||
"interceptor_no_support": "El interceptor seleccionado actualmente no admite cookies. Seleccione otro interceptor e inténtelo de nuevo.",
|
"interceptor_no_support": "Your currently selected interceptor does not support cookies. Select a different Interceptor and try again.",
|
||||||
"managed_tab": "Gestionado",
|
"managed_tab": "Managed",
|
||||||
"new_domain_name": "Nuevo nombre de dominio",
|
"new_domain_name": "New domain name",
|
||||||
"no_cookies_in_domain": "No hay cookies para este dominio",
|
"no_cookies_in_domain": "No cookies set for this domain",
|
||||||
"raw_tab": "Sin procesar",
|
"raw_tab": "Raw",
|
||||||
"set": "Establecer una cookie"
|
"set": "Set a cookie"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"count": {
|
"count": {
|
||||||
"header": "{count} encabezado(s)",
|
"header": "Encabezado {count}",
|
||||||
"message": "{count} mensaje(s)",
|
"message": "Mensaje {count}",
|
||||||
"parameter": "{count} parámetro(s)",
|
"parameter": "Parámetro {count}",
|
||||||
"protocol": "{count} protocolo(s)",
|
"protocol": "Protocolo {count}",
|
||||||
"value": "{cuenta} valor(es)",
|
"value": "Valor {cuenta}",
|
||||||
"variable": "{count} variable(es)"
|
"variable": "Variable {count}"
|
||||||
},
|
},
|
||||||
"documentation": {
|
"documentation": {
|
||||||
"generate": "Generar documentación",
|
"generate": "Generar documentación",
|
||||||
@@ -223,26 +223,26 @@
|
|||||||
"empty": {
|
"empty": {
|
||||||
"authorization": "Esta solicitud no utiliza ninguna autorización.",
|
"authorization": "Esta solicitud no utiliza ninguna autorización.",
|
||||||
"body": "Esta solicitud no tiene cuerpo",
|
"body": "Esta solicitud no tiene cuerpo",
|
||||||
"collection": "Colección vacía",
|
"collection": "La colección está vacía",
|
||||||
"collections": "No hay colecciones",
|
"collections": "Las colecciones están vacías",
|
||||||
"documentation": "Conectarse a un punto final de GraphQL para ver la documentación",
|
"documentation": "Conectarse a un punto final de GraphQL para ver la documentación",
|
||||||
"endpoint": "El punto final no puede estar vacío",
|
"endpoint": "El punto final no puede estar vacío",
|
||||||
"environments": "No hay entornos",
|
"environments": "Los entornos están vacíos",
|
||||||
"folder": "Carpeta vacía",
|
"folder": "La carpeta está vacía",
|
||||||
"headers": "Esta solicitud no tiene encabezados",
|
"headers": "Esta solicitud no tiene encabezados",
|
||||||
"history": "No hay historial",
|
"history": "El historial está vacío",
|
||||||
"invites": "Lista de invitados vacía",
|
"invites": "La lista de invitados está vacía",
|
||||||
"members": "No hay miembros en el equipo",
|
"members": "El equipo está vacío",
|
||||||
"parameters": "Esta solicitud no tiene ningún parámetro",
|
"parameters": "Esta solicitud no tiene ningún parámetro",
|
||||||
"pending_invites": "No hay invitaciones pendientes para este equipo",
|
"pending_invites": "No hay invitaciones pendientes para este equipo",
|
||||||
"profile": "Iniciar sesión para ver tu perfil",
|
"profile": "Iniciar sesión para ver tu perfil",
|
||||||
"protocols": "No hay protocolos",
|
"protocols": "Los protocolos están vacíos",
|
||||||
"schema": "Conectarse a un punto final de GraphQL",
|
"schema": "Conectarse a un punto final de GraphQL",
|
||||||
"shared_requests": "No hay solicitudes compartidas",
|
"shared_requests": "Shared requests are empty",
|
||||||
"shared_requests_logout": "Iniciar sesión para ver sus solicitudes compartidas o crear una nueva",
|
"shared_requests_logout": "Login to view your shared requests or create a new one",
|
||||||
"subscription": "No hay suscripciones",
|
"subscription": "Subscriptions are empty",
|
||||||
"team_name": "Nombre del equipo vacío",
|
"team_name": "Nombre del equipo vacío",
|
||||||
"teams": "No hay equipos",
|
"teams": "Los equipos están vacíos",
|
||||||
"tests": "No hay pruebas para esta solicitud",
|
"tests": "No hay pruebas para esta solicitud",
|
||||||
"shortcodes": "Aún no se han creado Shortcodes"
|
"shortcodes": "Aún no se han creado Shortcodes"
|
||||||
},
|
},
|
||||||
@@ -250,41 +250,41 @@
|
|||||||
"add_to_global": "Añadir a Global",
|
"add_to_global": "Añadir a Global",
|
||||||
"added": "Adición al entorno",
|
"added": "Adición al entorno",
|
||||||
"create_new": "Crear un nuevo entorno",
|
"create_new": "Crear un nuevo entorno",
|
||||||
"created": "Entorno creado",
|
"created": "Environment created",
|
||||||
"deleted": "Eliminar el entorno",
|
"deleted": "Eliminar el entorno",
|
||||||
"duplicated": "Entorno duplicado",
|
"duplicated": "Environment duplicated",
|
||||||
"edit": "Editar entorno",
|
"edit": "Editar entorno",
|
||||||
"empty_variables": "No hay variables",
|
"empty_variables": "No variables",
|
||||||
"global": "Global",
|
"global": "Global",
|
||||||
"global_variables": "Variables globales",
|
"global_variables": "Global variables",
|
||||||
"import_or_create": "Importar o crear un entorno",
|
"import_or_create": "Import or create a environment",
|
||||||
"invalid_name": "Proporciona un nombre válido para el entorno.",
|
"invalid_name": "Proporciona un nombre válido para el entorno.",
|
||||||
"list": "Variables de entorno",
|
"list": "Environment variables",
|
||||||
"my_environments": "Mis entornos",
|
"my_environments": "Mis entornos",
|
||||||
"name": "Nombre",
|
"name": "Name",
|
||||||
"nested_overflow": "las variables de entorno anidadas están limitadas a 10 niveles",
|
"nested_overflow": "las variables de entorno anidadas están limitadas a 10 niveles",
|
||||||
"new": "Nuevo entorno",
|
"new": "Nuevo entorno",
|
||||||
"no_active_environment": "Ningún entorno activo",
|
"no_active_environment": "No active environment",
|
||||||
"no_environment": "Sin entorno",
|
"no_environment": "Sin entorno",
|
||||||
"no_environment_description": "No se ha seleccionado ningún entorno. Elije qué hacer con las siguientes variables.",
|
"no_environment_description": "No se ha seleccionado ningún entorno. Elije qué hacer con las siguientes variables.",
|
||||||
"quick_peek": "Vistazo rápido al entorno",
|
"quick_peek": "Environment Quick Peek",
|
||||||
"replace_with_variable": "Sustituir por variable",
|
"replace_with_variable": "Replace with variable",
|
||||||
"scope": "Ámbito",
|
"scope": "Scope",
|
||||||
"select": "Seleccionar entorno",
|
"select": "Seleccionar entorno",
|
||||||
"set": "Establecer entorno",
|
"set": "Set environment",
|
||||||
"set_as_environment": "Establecer como entorno",
|
"set_as_environment": "Set as environment",
|
||||||
"team_environments": "Entornos de trabajo en equipo",
|
"team_environments": "Entornos de trabajo en equipo",
|
||||||
"title": "Entornos",
|
"title": "Entornos",
|
||||||
"updated": "Entorno actualizado",
|
"updated": "Entorno actualizado",
|
||||||
"value": "Valor",
|
"value": "Value",
|
||||||
"variable": "Variable",
|
"variable": "Variable",
|
||||||
"variable_list": "Lista de variables"
|
"variable_list": "Lista de variables"
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
"authproviders_load_error": "No se han podido cargar los proveedores de autenticación",
|
"authproviders_load_error": "Unable to load auth providers",
|
||||||
"browser_support_sse": "Este navegador no parece ser compatible con los eventos enviados por el servidor.",
|
"browser_support_sse": "Este navegador no parece ser compatible con los eventos enviados por el servidor.",
|
||||||
"check_console_details": "Consulta el registro de la consola para obtener más detalles.",
|
"check_console_details": "Consulta el registro de la consola para obtener más detalles.",
|
||||||
"check_how_to_add_origin": "Comprueba cómo puede añadir un origen",
|
"check_how_to_add_origin": "Check how you can add an origin",
|
||||||
"curl_invalid_format": "cURL no está formateado correctamente",
|
"curl_invalid_format": "cURL no está formateado correctamente",
|
||||||
"danger_zone": "Zona de peligro",
|
"danger_zone": "Zona de peligro",
|
||||||
"delete_account": "Tu cuenta es actualmente propietaria en estos equipos:",
|
"delete_account": "Tu cuenta es actualmente propietaria en estos equipos:",
|
||||||
@@ -300,13 +300,13 @@
|
|||||||
"json_prettify_invalid_body": "No se puede aplicar embellecedor a un cuerpo inválido, resuelve errores de sintaxis json y vuelve a intentarlo",
|
"json_prettify_invalid_body": "No se puede aplicar embellecedor a un cuerpo inválido, resuelve errores de sintaxis json y vuelve a intentarlo",
|
||||||
"network_error": "Parece que hay un error de red. Por favor, inténtalo de nuevo.",
|
"network_error": "Parece que hay un error de red. Por favor, inténtalo de nuevo.",
|
||||||
"network_fail": "No se pudo enviar la solicitud",
|
"network_fail": "No se pudo enviar la solicitud",
|
||||||
"no_collections_to_export": "No hay colecciones para exportar. Crea una colección para empezar.",
|
"no_collections_to_export": "No collections to export. Please create a collection to get started.",
|
||||||
"no_duration": "Sin duración",
|
"no_duration": "Sin duración",
|
||||||
"no_environments_to_export": "No hay entornos para exportar. Por favor, crea un entorno para empezar.",
|
"no_environments_to_export": "No environments to export. Please create an environment to get started.",
|
||||||
"no_results_found": "No se han encontrado coincidencias",
|
"no_results_found": "No se han encontrado coincidencias",
|
||||||
"page_not_found": "No se ha podido encontrar esta página",
|
"page_not_found": "No se ha podido encontrar esta página",
|
||||||
"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": "Error de proxy",
|
"proxy_error": "Proxy error",
|
||||||
"script_fail": "No se pudo ejecutar el script de solicitud previa",
|
"script_fail": "No se pudo ejecutar el script de solicitud previa",
|
||||||
"something_went_wrong": "Algo salió mal",
|
"something_went_wrong": "Algo salió mal",
|
||||||
"test_script_fail": "No se ha podido ejecutar la secuencia de comandos posterior a la solicitud"
|
"test_script_fail": "No se ha podido ejecutar la secuencia de comandos posterior a la solicitud"
|
||||||
@@ -314,15 +314,15 @@
|
|||||||
"export": {
|
"export": {
|
||||||
"as_json": "Exportar como JSON",
|
"as_json": "Exportar como JSON",
|
||||||
"create_secret_gist": "Crear un Gist secreto",
|
"create_secret_gist": "Crear un Gist secreto",
|
||||||
"failed": "Algo ha ido mal al exportar",
|
"failed": "Something went wrong while exporting",
|
||||||
"gist_created": "Gist creado",
|
"gist_created": "Gist creado",
|
||||||
"require_github": "Iniciar sesión con GitHub para crear un Gist secreto",
|
"require_github": "Iniciar sesión con GitHub para crear un Gist secreto",
|
||||||
"title": "Exportar"
|
"title": "Exportar"
|
||||||
},
|
},
|
||||||
"filter": {
|
"filter": {
|
||||||
"all": "Todos",
|
"all": "All",
|
||||||
"none": "Ninguno",
|
"none": "None",
|
||||||
"starred": "Destacado"
|
"starred": "Starred"
|
||||||
},
|
},
|
||||||
"folder": {
|
"folder": {
|
||||||
"created": "Carpeta creada",
|
"created": "Carpeta creada",
|
||||||
@@ -333,16 +333,16 @@
|
|||||||
"renamed": "Carpeta renombrada"
|
"renamed": "Carpeta renombrada"
|
||||||
},
|
},
|
||||||
"graphql": {
|
"graphql": {
|
||||||
"connection_switch_confirm": "¿Deseas conectarte con el endpoint GraphQL más reciente?",
|
"connection_switch_confirm": "Do you want to connect with the latest GraphQL endpoint?",
|
||||||
"connection_switch_new_url": "Al cambiar a una pestaña se desconectará de la conexión GraphQL activa. La nueva URL de conexión es",
|
"connection_switch_new_url": "Switching to a tab will disconnected you from the active GraphQL connection. New connection URL is",
|
||||||
"connection_switch_url": "Estás conectado a un endpoint GraphQL cuya URL de conexión es",
|
"connection_switch_url": "You're connected to a GraphQL endpoint the connection URL is",
|
||||||
"mutations": "Mutaciones",
|
"mutations": "Mutaciones",
|
||||||
"schema": "Esquema",
|
"schema": "Esquema",
|
||||||
"subscriptions": "Suscripciones",
|
"subscriptions": "Suscripciones",
|
||||||
"switch_connection": "Cambiar conexión"
|
"switch_connection": "Switch connection"
|
||||||
},
|
},
|
||||||
"graphql_collections": {
|
"graphql_collections": {
|
||||||
"title": "Colecciones de GraphQL"
|
"title": "GraphQL Collections"
|
||||||
},
|
},
|
||||||
"group": {
|
"group": {
|
||||||
"time": "Tiempo",
|
"time": "Tiempo",
|
||||||
@@ -355,8 +355,8 @@
|
|||||||
},
|
},
|
||||||
"helpers": {
|
"helpers": {
|
||||||
"authorization": "El encabezado de autorización se generará automáticamente cuando se envía la solicitud.",
|
"authorization": "El encabezado de autorización se generará automáticamente cuando se envía la solicitud.",
|
||||||
"collection_properties_authorization": " Esta autorización se establecerá para cada solicitud de esta colección.",
|
"collection_properties_authorization": " This authorization will be set for every request in this collection.",
|
||||||
"collection_properties_header": "Este encabezado se establecerá para cada solicitud de esta colección.",
|
"collection_properties_header": "This header will be set for every request in this collection.",
|
||||||
"generate_documentation_first": "Generar la documentación primero",
|
"generate_documentation_first": "Generar la documentación primero",
|
||||||
"network_fail": "No se puede acceder a la API. Comprueba tu conexión de red y vuelve a intentarlo.",
|
"network_fail": "No se puede acceder a la API. Comprueba tu conexión de red y vuelve a intentarlo.",
|
||||||
"offline": "Parece estar desconectado. Es posible que los datos de este espacio de trabajo no estén actualizados.",
|
"offline": "Parece estar desconectado. Es posible que los datos de este espacio de trabajo no estén actualizados.",
|
||||||
@@ -376,10 +376,10 @@
|
|||||||
"import": {
|
"import": {
|
||||||
"collections": "Importar colecciones",
|
"collections": "Importar colecciones",
|
||||||
"curl": "Importar cURL",
|
"curl": "Importar cURL",
|
||||||
"environments_from_gist": "Importar desde Gist",
|
"environments_from_gist": "Import From Gist",
|
||||||
"environments_from_gist_description": "Importar entornos Hoppscotch desde Gist",
|
"environments_from_gist_description": "Import Hoppscotch Environments From Gist",
|
||||||
"failed": "Importación fallida",
|
"failed": "Importación fallida",
|
||||||
"from_file": "Importar desde archivo",
|
"from_file": "Import from File",
|
||||||
"from_gist": "Importar desde Gist",
|
"from_gist": "Importar desde Gist",
|
||||||
"from_gist_description": "Importar desde URL de Gist",
|
"from_gist_description": "Importar desde URL de Gist",
|
||||||
"from_insomnia": "Importar desde Insomnia",
|
"from_insomnia": "Importar desde Insomnia",
|
||||||
@@ -394,41 +394,41 @@
|
|||||||
"from_postman_description": "Importar desde una colección de Postman",
|
"from_postman_description": "Importar desde una colección de Postman",
|
||||||
"from_url": "Importar desde una URL",
|
"from_url": "Importar desde una URL",
|
||||||
"gist_url": "Introduce la URL de Gist",
|
"gist_url": "Introduce la URL de Gist",
|
||||||
"gql_collections_from_gist_description": "Importar colecciones GraphQL desde Gist",
|
"gql_collections_from_gist_description": "Import GraphQL Collections From Gist",
|
||||||
"hoppscotch_environment": "Entorno de Hoppscotch",
|
"hoppscotch_environment": "Hoppscotch Environment",
|
||||||
"hoppscotch_environment_description": "Importar archivo JSON del entorno de Hoppscotch",
|
"hoppscotch_environment_description": "Import Hoppscotch Environment JSON file",
|
||||||
"import_from_url_invalid_fetch": "No se han podido obtener datos de la url",
|
"import_from_url_invalid_fetch": "Couldn't get data from the url",
|
||||||
"import_from_url_invalid_file_format": "Error al importar colecciones",
|
"import_from_url_invalid_file_format": "Error while importing collections",
|
||||||
"import_from_url_invalid_type": "Tipo no admitido. Los valores aceptados son \"hoppscotch\", \"openapi\", \"postman\", \"insomnia\".",
|
"import_from_url_invalid_type": "Unsupported type. accepted values are 'hoppscotch', 'openapi', 'postman', 'insomnia'",
|
||||||
"import_from_url_success": "Colecciones Importadas",
|
"import_from_url_success": "Collections Imported",
|
||||||
"insomnia_environment_description": "Importar el entorno de Insomnia desde un archivo JSON/YAML",
|
"insomnia_environment_description": "Import Insomnia Environment from a JSON/YAML file",
|
||||||
"json_description": "Importar colecciones desde un archivo JSON de colecciones de Hoppscotch",
|
"json_description": "Importar colecciones desde un archivo JSON de colecciones de Hoppscotch",
|
||||||
"postman_environment": "Entorno de Postman",
|
"postman_environment": "Postman Environment",
|
||||||
"postman_environment_description": "Importar entorno de Postman desde un archivo JSON",
|
"postman_environment_description": "Import Postman Environment from a JSON file",
|
||||||
"title": "Importar"
|
"title": "Importar"
|
||||||
},
|
},
|
||||||
"inspections": {
|
"inspections": {
|
||||||
"description": "Inspeccionar posibles errores",
|
"description": "Inspect possible errors",
|
||||||
"environment": {
|
"environment": {
|
||||||
"add_environment": "Añadir al Entorno",
|
"add_environment": "Add to Environment",
|
||||||
"not_found": "No se ha encontrado la variable de entorno \"{environment}\"."
|
"not_found": "Environment variable “{environment}” not found."
|
||||||
},
|
},
|
||||||
"header": {
|
"header": {
|
||||||
"cookie": "El navegador no permite que Hoppscotch establezca el encabezado Cookie. Mientras trabajamos en la aplicación de escritorio de Hoppscotch (próximamente), por favor utilice el encabezado de autorización en su lugar."
|
"cookie": "The browser doesn't allow Hoppscotch to set the Cookie Header. While we're working on the Hoppscotch Desktop App (coming soon), please use the Authorization Header instead."
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"401_error": "Compruebe tus credenciales de autenticación.",
|
"401_error": "Please check your authentication credentials.",
|
||||||
"404_error": "Compruebe la URL de su solicitud y el tipo de método.",
|
"404_error": "Please check your request URL and method type.",
|
||||||
"cors_error": "Por favor, comprueba tu configuración de Compartición de Recursos \"Cross-Origin\".",
|
"cors_error": "Please check your Cross-Origin Resource Sharing configuration.",
|
||||||
"default_error": "Por favor, comprueba tu solicitud.",
|
"default_error": "Please check your request.",
|
||||||
"network_error": "Comprueba tu conexión de red."
|
"network_error": "Please check your network connection."
|
||||||
},
|
},
|
||||||
"title": "Inspeccionador",
|
"title": "Inspector",
|
||||||
"url": {
|
"url": {
|
||||||
"extension_not_installed": "Extensión no instalada.",
|
"extension_not_installed": "Extension not installed.",
|
||||||
"extension_unknown_origin": "Asegúrate de haber agregado el origen del punto final de la API a la lista de Extensiones del Navegador Hoppscotch.",
|
"extension_unknown_origin": "Make sure you've added the API endpoint's origin to the Hoppscotch Browser Extension list.",
|
||||||
"extention_enable_action": "Activar la extensión del navegador",
|
"extention_enable_action": "Enable Browser Extension",
|
||||||
"extention_not_enabled": "Extensión no habilitada."
|
"extention_not_enabled": "Extension not enabled."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"layout": {
|
"layout": {
|
||||||
@@ -442,10 +442,10 @@
|
|||||||
"close_unsaved_tab": "Tienes cambios sin guardar",
|
"close_unsaved_tab": "Tienes cambios sin guardar",
|
||||||
"collections": "Colecciones",
|
"collections": "Colecciones",
|
||||||
"confirm": "Confirmar",
|
"confirm": "Confirmar",
|
||||||
"customize_request": "Personalizar solicitud",
|
"customize_request": "Customize Request",
|
||||||
"edit_request": "Editar solicitud",
|
"edit_request": "Editar solicitud",
|
||||||
"import_export": "Importación y exportación",
|
"import_export": "Importación y exportación",
|
||||||
"share_request": "Compartir solicitud"
|
"share_request": "Share Request"
|
||||||
},
|
},
|
||||||
"mqtt": {
|
"mqtt": {
|
||||||
"already_subscribed": "Ya estás suscrito a este tema.",
|
"already_subscribed": "Ya estás suscrito a este tema.",
|
||||||
@@ -493,7 +493,7 @@
|
|||||||
},
|
},
|
||||||
"profile": {
|
"profile": {
|
||||||
"app_settings": "Ajustes de la aplicación",
|
"app_settings": "Ajustes de la aplicación",
|
||||||
"default_hopp_displayname": "Usuario anónimo",
|
"default_hopp_displayname": "Unnamed User",
|
||||||
"editor": "Editor",
|
"editor": "Editor",
|
||||||
"editor_description": "Los editores pueden añadir, editar y eliminar solicitudes.",
|
"editor_description": "Los editores pueden añadir, editar y eliminar solicitudes.",
|
||||||
"email_verification_mail": "Se ha enviado un correo electrónico de verificación a tu dirección de correo electrónico. Haz clic en el enlace para verificar tu dirección de correo electrónico.",
|
"email_verification_mail": "Se ha enviado un correo electrónico de verificación a tu dirección de correo electrónico. Haz clic en el enlace para verificar tu dirección de correo electrónico.",
|
||||||
@@ -526,12 +526,12 @@
|
|||||||
"enter_curl": "Ingrese cURL",
|
"enter_curl": "Ingrese cURL",
|
||||||
"generate_code": "Generar código",
|
"generate_code": "Generar código",
|
||||||
"generated_code": "Código generado",
|
"generated_code": "Código generado",
|
||||||
"go_to_authorization_tab": "Ir a la pestaña Autorización",
|
"go_to_authorization_tab": "Go to Authorization tab",
|
||||||
"go_to_body_tab": "Ir a la pestaña de cuerpo",
|
"go_to_body_tab": "Go to Body tab",
|
||||||
"header_list": "Lista de encabezados",
|
"header_list": "Lista de encabezados",
|
||||||
"invalid_name": "Proporciona un nombre para la solicitud.",
|
"invalid_name": "Proporciona un nombre para la solicitud.",
|
||||||
"method": "Método",
|
"method": "Método",
|
||||||
"moved": "Solicitud movida",
|
"moved": "Request moved",
|
||||||
"name": "Nombre de solicitud",
|
"name": "Nombre de solicitud",
|
||||||
"new": "Nueva solicitud",
|
"new": "Nueva solicitud",
|
||||||
"order_changed": "Orden de solicitudes actualizadas",
|
"order_changed": "Orden de solicitudes actualizadas",
|
||||||
@@ -543,8 +543,8 @@
|
|||||||
"path": "Ruta",
|
"path": "Ruta",
|
||||||
"payload": "Carga útil",
|
"payload": "Carga útil",
|
||||||
"query": "Consulta",
|
"query": "Consulta",
|
||||||
"raw_body": "cuerpo sin procesar",
|
"raw_body": "Cuerpo de solicitud sin procesar",
|
||||||
"rename": "Renombrar solicitud",
|
"rename": "Rename Request",
|
||||||
"renamed": "Solicitud renombrada",
|
"renamed": "Solicitud renombrada",
|
||||||
"run": "Ejecutar",
|
"run": "Ejecutar",
|
||||||
"save": "Guardar",
|
"save": "Guardar",
|
||||||
@@ -552,8 +552,8 @@
|
|||||||
"saved": "Solicitud guardada",
|
"saved": "Solicitud guardada",
|
||||||
"share": "Compartir",
|
"share": "Compartir",
|
||||||
"share_description": "Comparte Hoppscotch con tus amigos",
|
"share_description": "Comparte Hoppscotch con tus amigos",
|
||||||
"share_request": "Compartir solicitud",
|
"share_request": "Share Request",
|
||||||
"stop": "Detener",
|
"stop": "Stop",
|
||||||
"title": "Solicitud",
|
"title": "Solicitud",
|
||||||
"type": "Tipo de solicitud",
|
"type": "Tipo de solicitud",
|
||||||
"url": "URL",
|
"url": "URL",
|
||||||
@@ -571,7 +571,7 @@
|
|||||||
"json": "JSON",
|
"json": "JSON",
|
||||||
"pdf": "PDF",
|
"pdf": "PDF",
|
||||||
"preview_html": "Vista previa de HTML",
|
"preview_html": "Vista previa de HTML",
|
||||||
"raw": "Sin procesar",
|
"raw": "Crudo",
|
||||||
"size": "Tamaño",
|
"size": "Tamaño",
|
||||||
"status": "Estado",
|
"status": "Estado",
|
||||||
"time": "Tiempo",
|
"time": "Tiempo",
|
||||||
@@ -635,29 +635,29 @@
|
|||||||
"verify_email": "Verificar correo electrónico"
|
"verify_email": "Verificar correo electrónico"
|
||||||
},
|
},
|
||||||
"shared_requests": {
|
"shared_requests": {
|
||||||
"button": "Botón",
|
"button": "Button",
|
||||||
"button_info": "Crea un botón \"Ejecutar en Hoppscotch\" para tu página web, blog o un README.",
|
"button_info": "Create a 'Run in Hoppscotch' button for your website, blog or a README.",
|
||||||
"copy_html": "Copiar HTML",
|
"copy_html": "Copy HTML",
|
||||||
"copy_link": "Copiar enlace",
|
"copy_link": "Copy Link",
|
||||||
"copy_markdown": "Copiar Markdown",
|
"copy_markdown": "Copy Markdown",
|
||||||
"creating_widget": "Crear widget",
|
"creating_widget": "Creating widget",
|
||||||
"customize": "Personalizar",
|
"customize": "Customize",
|
||||||
"deleted": "Solicitud compartida eliminada",
|
"deleted": "Shared request deleted",
|
||||||
"description": "Selecciona un widget, puedes cambiarlo y personalizarlo más tarde",
|
"description": "Select a widget, you can change and customize this later",
|
||||||
"embed": "Incrustar",
|
"embed": "Embed",
|
||||||
"embed_info": "Añada un mini \"Hoppscotch API Playground\" a tu sitio web, blog o documentación.",
|
"embed_info": "Add a mini 'Hoppscotch API Playground' to your website, blog or documentation.",
|
||||||
"link": "Enlace",
|
"link": "Link",
|
||||||
"link_info": "Crea un enlace compartible para compartirlo con cualquier persona en Internet con acceso de visualización.",
|
"link_info": "Create a shareable link to share with anyone on the internet with view access.",
|
||||||
"modified": "Solicitud compartida modificada",
|
"modified": "Shared request modified",
|
||||||
"not_found": "Solicitud compartida no encontrada",
|
"not_found": "Shared request not found",
|
||||||
"open_new_tab": "Abrir en una nueva pestaña",
|
"open_new_tab": "Open in new tab",
|
||||||
"preview": "Vista previa",
|
"preview": "Preview",
|
||||||
"run_in_hoppscotch": "Correr en Hoppscotch",
|
"run_in_hoppscotch": "Run in Hoppscotch",
|
||||||
"theme": {
|
"theme": {
|
||||||
"dark": "Oscuro",
|
"dark": "Dark",
|
||||||
"light": "Claro",
|
"light": "Light",
|
||||||
"system": "Sistema",
|
"system": "System",
|
||||||
"title": "Tema"
|
"title": "Theme"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"shortcut": {
|
"shortcut": {
|
||||||
@@ -684,8 +684,8 @@
|
|||||||
"title": "Navegación"
|
"title": "Navegación"
|
||||||
},
|
},
|
||||||
"others": {
|
"others": {
|
||||||
"prettify": "Formatear el contenido del editor",
|
"prettify": "Prettify Editor's Content",
|
||||||
"title": "Otros"
|
"title": "Others"
|
||||||
},
|
},
|
||||||
"request": {
|
"request": {
|
||||||
"delete_method": "Seleccionar método DELETE",
|
"delete_method": "Seleccionar método DELETE",
|
||||||
@@ -697,13 +697,13 @@
|
|||||||
"post_method": "Seleccionar método POST",
|
"post_method": "Seleccionar método POST",
|
||||||
"previous_method": "Seleccionar método anterior",
|
"previous_method": "Seleccionar método anterior",
|
||||||
"put_method": "Seleccionar método PUT",
|
"put_method": "Seleccionar método PUT",
|
||||||
"rename": "Renombrar solicitud",
|
"rename": "Rename Request",
|
||||||
"reset_request": "Solicitud de reinicio",
|
"reset_request": "Solicitud de reinicio",
|
||||||
"save_request": "Guardar solicitud",
|
"save_request": "Save Request",
|
||||||
"save_to_collections": "Guardar en colecciones",
|
"save_to_collections": "Guardar en colecciones",
|
||||||
"send_request": "Enviar solicitud",
|
"send_request": "Enviar solicitud",
|
||||||
"share_request": "Compartir solicitud",
|
"share_request": "Share Request",
|
||||||
"show_code": "Generar fragmento de código",
|
"show_code": "Generate code snippet",
|
||||||
"title": "Solicitud",
|
"title": "Solicitud",
|
||||||
"copy_request_link": "Copiar enlace de solicitud"
|
"copy_request_link": "Copiar enlace de solicitud"
|
||||||
},
|
},
|
||||||
@@ -722,95 +722,95 @@
|
|||||||
},
|
},
|
||||||
"show": {
|
"show": {
|
||||||
"code": "Mostrar código",
|
"code": "Mostrar código",
|
||||||
"collection": "Ampliar el panel de colecciones",
|
"collection": "Expand Collection Panel",
|
||||||
"more": "Mostrar más",
|
"more": "Mostrar más",
|
||||||
"sidebar": "Mostrar barra lateral"
|
"sidebar": "Mostrar barra lateral"
|
||||||
},
|
},
|
||||||
"socketio": {
|
"socketio": {
|
||||||
"communication": "Comunicación",
|
"communication": "Comunicación",
|
||||||
"connection_not_authorized": "Esta conexión SocketIO no utiliza ningún tipo de autenticación.",
|
"connection_not_authorized": "This SocketIO connection does not use any authentication.",
|
||||||
"event_name": "Nombre del evento",
|
"event_name": "Nombre del evento",
|
||||||
"events": "Eventos",
|
"events": "Eventos",
|
||||||
"log": "Registro",
|
"log": "Registro",
|
||||||
"url": "URL"
|
"url": "URL"
|
||||||
},
|
},
|
||||||
"spotlight": {
|
"spotlight": {
|
||||||
"change_language": "Cambiar idioma",
|
"change_language": "Change Language",
|
||||||
"environments": {
|
"environments": {
|
||||||
"delete": "Borrar el entorno actual",
|
"delete": "Delete current environment",
|
||||||
"duplicate": "Duplicar el entorno actual",
|
"duplicate": "Duplicate current environment",
|
||||||
"duplicate_global": "Entorno global duplicado",
|
"duplicate_global": "Duplicate global environment",
|
||||||
"edit": "Editar el entorno actual",
|
"edit": "Edit current environment",
|
||||||
"edit_global": "Editar el entorno global",
|
"edit_global": "Edit global environment",
|
||||||
"new": "Crear un nuevo entorno",
|
"new": "Create new environment",
|
||||||
"new_variable": "Crear una nueva variable de entorno",
|
"new_variable": "Create a new environment variable",
|
||||||
"title": "Entornos"
|
"title": "Environments"
|
||||||
},
|
},
|
||||||
"general": {
|
"general": {
|
||||||
"chat": "Chatear con el servicio de asistencia",
|
"chat": "Chat with support",
|
||||||
"help_menu": "Ayuda y asistencia",
|
"help_menu": "Help and support",
|
||||||
"open_docs": "Leer la documentación",
|
"open_docs": "Read Documentation",
|
||||||
"open_github": "Abrir repositorio de GitHub",
|
"open_github": "Open GitHub repository",
|
||||||
"open_keybindings": "Atajos de teclado",
|
"open_keybindings": "Keyboard shortcuts",
|
||||||
"social": "Social",
|
"social": "Social",
|
||||||
"title": "General"
|
"title": "General"
|
||||||
},
|
},
|
||||||
"graphql": {
|
"graphql": {
|
||||||
"connect": "Conectarse al servidor",
|
"connect": "Connect to server",
|
||||||
"disconnect": "Desconectarse del servidor"
|
"disconnect": "Disconnect from server"
|
||||||
},
|
},
|
||||||
"miscellaneous": {
|
"miscellaneous": {
|
||||||
"invite": "Invita a tus amigos a Hoppscotch",
|
"invite": "Invite your friends to Hoppscotch",
|
||||||
"title": "Varios"
|
"title": "Miscellaneous"
|
||||||
},
|
},
|
||||||
"request": {
|
"request": {
|
||||||
"save_as_new": "Guardar como nueva solicitud",
|
"save_as_new": "Save as new request",
|
||||||
"select_method": "Seleccionar método",
|
"select_method": "Select method",
|
||||||
"switch_to": "Cambiar a",
|
"switch_to": "Switch to",
|
||||||
"tab_authorization": "Pestaña de autorización",
|
"tab_authorization": "Authorization tab",
|
||||||
"tab_body": "Pestaña de cuerpo",
|
"tab_body": "Body tab",
|
||||||
"tab_headers": "Pestaña de encabezados",
|
"tab_headers": "Headers tab",
|
||||||
"tab_parameters": "Pestaña de parámetros",
|
"tab_parameters": "Parameters tab",
|
||||||
"tab_pre_request_script": "Pestaña del script de pre-solicitud",
|
"tab_pre_request_script": "Pre-request script tab",
|
||||||
"tab_query": "Pestaña de consulta",
|
"tab_query": "Query tab",
|
||||||
"tab_tests": "Pestaña de pruebas",
|
"tab_tests": "Tests tab",
|
||||||
"tab_variables": "Pestaña de variables"
|
"tab_variables": "Variables tab"
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"copy": "Copiar respuesta",
|
"copy": "Copy response",
|
||||||
"download": "Descargar la respuesta como archivo",
|
"download": "Download response as file",
|
||||||
"title": "Respuesta"
|
"title": "Response"
|
||||||
},
|
},
|
||||||
"section": {
|
"section": {
|
||||||
"interceptor": "Interceptor",
|
"interceptor": "Interceptor",
|
||||||
"interface": "Interfaz",
|
"interface": "Interface",
|
||||||
"theme": "Tema",
|
"theme": "Theme",
|
||||||
"user": "Usuario"
|
"user": "User"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"change_interceptor": "Cambiar Interceptor",
|
"change_interceptor": "Change Interceptor",
|
||||||
"change_language": "Cambiar idioma",
|
"change_language": "Change Language",
|
||||||
"theme": {
|
"theme": {
|
||||||
"black": "Negro",
|
"black": "Black",
|
||||||
"dark": "Oscuro",
|
"dark": "Dark",
|
||||||
"light": "Claro",
|
"light": "Light",
|
||||||
"system": "Preferencia del sistema"
|
"system": "System preference"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tab": {
|
"tab": {
|
||||||
"close_current": "Cerrar la pestaña actual",
|
"close_current": "Close current tab",
|
||||||
"close_others": "Cerrar todas las demás pestañas",
|
"close_others": "Close all other tabs",
|
||||||
"duplicate": "Duplicar pestaña actual",
|
"duplicate": "Duplicate current tab",
|
||||||
"new_tab": "Abrir una nueva pestaña",
|
"new_tab": "Open a new tab",
|
||||||
"title": "Pestañas"
|
"title": "Tabs"
|
||||||
},
|
},
|
||||||
"workspace": {
|
"workspace": {
|
||||||
"delete": "Borrar el equipo actual",
|
"delete": "Delete current team",
|
||||||
"edit": "Editar el equipo actual",
|
"edit": "Edit current team",
|
||||||
"invite": "Invitar al equipo",
|
"invite": "Invite people to team",
|
||||||
"new": "Crear un nuevo equipo",
|
"new": "Create new team",
|
||||||
"switch_to_personal": "Cambia a tu espacio de trabajo personal",
|
"switch_to_personal": "Switch to your personal workspace",
|
||||||
"title": "Equipos"
|
"title": "Teams"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sse": {
|
"sse": {
|
||||||
@@ -825,10 +825,10 @@
|
|||||||
"connected": "Conectado",
|
"connected": "Conectado",
|
||||||
"connected_to": "Conectado a {name}",
|
"connected_to": "Conectado a {name}",
|
||||||
"connecting_to": "Conectando con {name}...",
|
"connecting_to": "Conectando con {name}...",
|
||||||
"connection_error": "Error de conexión",
|
"connection_error": "Failed to connect",
|
||||||
"connection_failed": "Conexión fallida",
|
"connection_failed": "Error de conexión",
|
||||||
"connection_lost": "Conexión perdida",
|
"connection_lost": "Conexión perdida",
|
||||||
"copied_interface_to_clipboard": "Copiado tipo de interfaz {language} al portapapeles",
|
"copied_interface_to_clipboard": "Copied {language} interface type to clipboard",
|
||||||
"copied_to_clipboard": "Copiado al portapapeles",
|
"copied_to_clipboard": "Copiado al portapapeles",
|
||||||
"deleted": "Eliminado",
|
"deleted": "Eliminado",
|
||||||
"deprecated": "OBSOLETO",
|
"deprecated": "OBSOLETO",
|
||||||
@@ -836,21 +836,21 @@
|
|||||||
"disconnected": "Desconectado",
|
"disconnected": "Desconectado",
|
||||||
"disconnected_from": "Desconectado de {name}",
|
"disconnected_from": "Desconectado de {name}",
|
||||||
"docs_generated": "Documentación generada",
|
"docs_generated": "Documentación generada",
|
||||||
"download_failed": "Descarga fallida",
|
"download_failed": "Download failed",
|
||||||
"download_started": "Descarga iniciada",
|
"download_started": "Descarga iniciada",
|
||||||
"enabled": "Activado",
|
"enabled": "Activado",
|
||||||
"file_imported": "Archivo importado",
|
"file_imported": "Archivo importado",
|
||||||
"finished_in": "Terminado en {duration}ms",
|
"finished_in": "Terminado en {duration} ms",
|
||||||
"hide": "Ocultar",
|
"hide": "Hide",
|
||||||
"history_deleted": "Historial eliminado",
|
"history_deleted": "Historial eliminado",
|
||||||
"linewrap": "Envolver líneas",
|
"linewrap": "Envolver líneas",
|
||||||
"loading": "Cargando...",
|
"loading": "Cargando...",
|
||||||
"message_received": "Mensaje: llegó {message} al: {topic}",
|
"message_received": "Mensaje: {mensaje} llegó sobre el tema: {topic}",
|
||||||
"mqtt_subscription_failed": "Algo ha ido mal al suscribirse al tema: {topic}",
|
"mqtt_subscription_failed": "Algo ha ido mal al suscribirse al tema: {topic}",
|
||||||
"none": "Ninguno",
|
"none": "Ninguno",
|
||||||
"nothing_found": "Nada encontrado para",
|
"nothing_found": "Nada encontrado para",
|
||||||
"published_error": "Algo ha ido mal al publicar el mensaje: {message} al tema: {topic}",
|
"published_error": "Algo ha ido mal al publicar el mensaje: {topic} al tema: {message}",
|
||||||
"published_message": "Mensaje publicado: {message} al tema: {topic}",
|
"published_message": "Mensaje publicado: {mensaje} al tema: {topic}",
|
||||||
"reconnection_error": "Fallo en la reconexión",
|
"reconnection_error": "Fallo en la reconexión",
|
||||||
"show": "Show",
|
"show": "Show",
|
||||||
"subscribed_failed": "Error al suscribirse al tema: {topic}",
|
"subscribed_failed": "Error al suscribirse al tema: {topic}",
|
||||||
@@ -874,12 +874,12 @@
|
|||||||
"tab": {
|
"tab": {
|
||||||
"authorization": "Autorización",
|
"authorization": "Autorización",
|
||||||
"body": "Cuerpo",
|
"body": "Cuerpo",
|
||||||
"close": "Cerrar pestaña",
|
"close": "Close Tab",
|
||||||
"close_others": "Cerrar otras pestañas",
|
"close_others": "Close other Tabs",
|
||||||
"collections": "Colecciones",
|
"collections": "Colecciones",
|
||||||
"documentation": "Documentación",
|
"documentation": "Documentación",
|
||||||
"duplicate": "Duplicar pestaña",
|
"duplicate": "Duplicate Tab",
|
||||||
"environments": "Entornos",
|
"environments": "Environments",
|
||||||
"headers": "Encabezados",
|
"headers": "Encabezados",
|
||||||
"history": "Historial",
|
"history": "Historial",
|
||||||
"mqtt": "MQTT",
|
"mqtt": "MQTT",
|
||||||
@@ -888,7 +888,7 @@
|
|||||||
"queries": "Consultas",
|
"queries": "Consultas",
|
||||||
"query": "Consulta",
|
"query": "Consulta",
|
||||||
"schema": "Esquema",
|
"schema": "Esquema",
|
||||||
"shared_requests": "Solicitudes compartidas",
|
"shared_requests": "Shared Requests",
|
||||||
"socketio": "Socket.IO",
|
"socketio": "Socket.IO",
|
||||||
"sse": "SSE",
|
"sse": "SSE",
|
||||||
"tests": "Pruebas",
|
"tests": "Pruebas",
|
||||||
@@ -905,7 +905,7 @@
|
|||||||
"email_do_not_match": "El correo electrónico no coincide con los datos de tu cuenta. Ponte en contacto con el propietario de tu equipo.",
|
"email_do_not_match": "El correo electrónico no coincide con los datos de tu cuenta. Ponte en contacto con el propietario de tu equipo.",
|
||||||
"exit": "Salir del equipo",
|
"exit": "Salir del equipo",
|
||||||
"exit_disabled": "Solo el propietario puede salir del equipo",
|
"exit_disabled": "Solo el propietario puede salir del equipo",
|
||||||
"failed_invites": "Invitaciones fallidas",
|
"failed_invites": "Failed invites",
|
||||||
"invalid_coll_id": "Identificador de colección no válido",
|
"invalid_coll_id": "Identificador de colección no válido",
|
||||||
"invalid_email_format": "El formato de correo electrónico no es válido",
|
"invalid_email_format": "El formato de correo electrónico no es válido",
|
||||||
"invalid_id": "Identificador de equipo inválido. Ponte en contacto con el propietario de tu equipo.",
|
"invalid_id": "Identificador de equipo inválido. Ponte en contacto con el propietario de tu equipo.",
|
||||||
@@ -915,7 +915,7 @@
|
|||||||
"invite": "Invitar",
|
"invite": "Invitar",
|
||||||
"invite_more": "Invitar a más",
|
"invite_more": "Invitar a más",
|
||||||
"invite_tooltip": "Invite a personas a este espacio de trabajo",
|
"invite_tooltip": "Invite a personas a este espacio de trabajo",
|
||||||
"invited_to_team": "{owner} te ha invitado al equipo {team}",
|
"invited_to_team": "{owner} te ha invitado a unirte al {tema}",
|
||||||
"join": "Invitación aceptada",
|
"join": "Invitación aceptada",
|
||||||
"join_beta": "Únete al programa beta para acceder a los equipos.",
|
"join_beta": "Únete al programa beta para acceder a los equipos.",
|
||||||
"join_team": "Entrar a {team}",
|
"join_team": "Entrar a {team}",
|
||||||
@@ -930,7 +930,7 @@
|
|||||||
"member_removed": "Usuario eliminado",
|
"member_removed": "Usuario eliminado",
|
||||||
"member_role_updated": "Funciones de usuario actualizadas",
|
"member_role_updated": "Funciones de usuario actualizadas",
|
||||||
"members": "Miembros",
|
"members": "Miembros",
|
||||||
"more_members": "+{count} más",
|
"more_members": "+{count} more",
|
||||||
"name_length_insufficient": "El nombre del equipo debe tener al menos 6 caracteres",
|
"name_length_insufficient": "El nombre del equipo debe tener al menos 6 caracteres",
|
||||||
"name_updated": "Nombre de equipo actualizado",
|
"name_updated": "Nombre de equipo actualizado",
|
||||||
"new": "Nuevo equipo",
|
"new": "Nuevo equipo",
|
||||||
@@ -944,13 +944,13 @@
|
|||||||
"parent_coll_move": "No se puede mover la colección a una colección hija",
|
"parent_coll_move": "No se puede mover la colección a una colección hija",
|
||||||
"pending_invites": "Invitaciones pendientes",
|
"pending_invites": "Invitaciones pendientes",
|
||||||
"permissions": "Permisos",
|
"permissions": "Permisos",
|
||||||
"same_target_destination": "Mismo objetivo y destino",
|
"same_target_destination": "Same target and destination",
|
||||||
"saved": "Equipo guardado",
|
"saved": "Equipo guardado",
|
||||||
"select_a_team": "Seleccionar un equipo",
|
"select_a_team": "Seleccionar un equipo",
|
||||||
"success_invites": "Invitaciones con éxito",
|
"success_invites": "Success invites",
|
||||||
"title": "Equipos",
|
"title": "Equipos",
|
||||||
"we_sent_invite_link": "¡Hemos enviado un enlace de invitación a todos los invitados!",
|
"we_sent_invite_link": "¡Hemos enviado un enlace de invitación a todos los invitados!",
|
||||||
"we_sent_invite_link_description": "Pide a todos los invitados que revisen su bandeja de entrada. Tienen que hacer clic en el enlace para unirse al equipo."
|
"we_sent_invite_link_description": "Pide a todos los invitados que revisen tu bandeja de entrada. Haz clic en el enlace para unirse al equipo."
|
||||||
},
|
},
|
||||||
"team_environment": {
|
"team_environment": {
|
||||||
"deleted": "Entorno eliminado",
|
"deleted": "Entorno eliminado",
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
{
|
{
|
||||||
"action": {
|
"action": {
|
||||||
"add": "Ajouter",
|
"add": "Add",
|
||||||
"autoscroll": "Auto-scroll",
|
"autoscroll": "Autoscroll",
|
||||||
"cancel": "Annuler",
|
"cancel": "Annuler",
|
||||||
"choose_file": "Choisir un fichier",
|
"choose_file": "Choisir un fichier",
|
||||||
"clear": "Effacer",
|
"clear": "Effacer",
|
||||||
"clear_all": "Tout effacer",
|
"clear_all": "Tout effacer",
|
||||||
"clear_history": "Effacer tout l'historique",
|
"clear_history": "Clear all History",
|
||||||
"close": "Fermer",
|
"close": "Close",
|
||||||
"connect": "Connecter",
|
"connect": "Connecter",
|
||||||
"connecting": "Connexion",
|
"connecting": "Connecting",
|
||||||
"copy": "Copier",
|
"copy": "Copier",
|
||||||
"create": "Create",
|
"create": "Create",
|
||||||
"delete": "Supprimer",
|
"delete": "Supprimer",
|
||||||
@@ -22,8 +22,8 @@
|
|||||||
"edit": "Éditer",
|
"edit": "Éditer",
|
||||||
"filter": "Filter",
|
"filter": "Filter",
|
||||||
"go_back": "Retour",
|
"go_back": "Retour",
|
||||||
"go_forward": "Avancer",
|
"go_forward": "Go forward",
|
||||||
"group_by": "Grouper par",
|
"group_by": "Group by",
|
||||||
"label": "Étiqueter",
|
"label": "Étiqueter",
|
||||||
"learn_more": "En savoir plus",
|
"learn_more": "En savoir plus",
|
||||||
"less": "Moins",
|
"less": "Moins",
|
||||||
@@ -35,16 +35,16 @@
|
|||||||
"prettify": "Formater",
|
"prettify": "Formater",
|
||||||
"properties": "Properties",
|
"properties": "Properties",
|
||||||
"remove": "Supprimer",
|
"remove": "Supprimer",
|
||||||
"rename": "Renommer",
|
"rename": "Rename",
|
||||||
"restore": "Restaurer",
|
"restore": "Restaurer",
|
||||||
"save": "Sauvegarder",
|
"save": "Sauvegarder",
|
||||||
"scroll_to_bottom": "Défiler vers le bas",
|
"scroll_to_bottom": "Scroll to bottom",
|
||||||
"scroll_to_top": "Défiler vers le haut",
|
"scroll_to_top": "Scroll to top",
|
||||||
"search": "Chercher",
|
"search": "Chercher",
|
||||||
"send": "Envoyer",
|
"send": "Envoyer",
|
||||||
"share": "Share",
|
"share": "Share",
|
||||||
"start": "Démarrer",
|
"start": "Démarrer",
|
||||||
"starting": "Démarrage",
|
"starting": "Starting",
|
||||||
"stop": "Arrêter",
|
"stop": "Arrêter",
|
||||||
"to_close": "pour fermer",
|
"to_close": "pour fermer",
|
||||||
"to_navigate": "pour naviguer",
|
"to_navigate": "pour naviguer",
|
||||||
@@ -86,8 +86,8 @@
|
|||||||
"search": "Chercher",
|
"search": "Chercher",
|
||||||
"share": "Partager",
|
"share": "Partager",
|
||||||
"shortcuts": "Raccourcis",
|
"shortcuts": "Raccourcis",
|
||||||
"social_description": "Suivez-nous sur les médias sociaux pour rester informé des dernières nouvelles, mises à jour et communiqués.",
|
"social_description": "Follow us on social media to stay updated with the latest news, updates and releases.",
|
||||||
"social_links": "Liens sociaux",
|
"social_links": "Social links",
|
||||||
"spotlight": "Projecteur",
|
"spotlight": "Projecteur",
|
||||||
"status": "Statut",
|
"status": "Statut",
|
||||||
"status_description": "Vérifier l'état du site web",
|
"status_description": "Vérifier l'état du site web",
|
||||||
@@ -95,7 +95,7 @@
|
|||||||
"twitter": "Twitter",
|
"twitter": "Twitter",
|
||||||
"type_a_command_search": "Tapez une commande ou recherchez…",
|
"type_a_command_search": "Tapez une commande ou recherchez…",
|
||||||
"we_use_cookies": "Nous utilisons des cookies",
|
"we_use_cookies": "Nous utilisons des cookies",
|
||||||
"whats_new": "Quoi de neuf ?",
|
"whats_new": "Quoi de neuf?",
|
||||||
"wiki": "Wiki"
|
"wiki": "Wiki"
|
||||||
},
|
},
|
||||||
"auth": {
|
"auth": {
|
||||||
@@ -119,38 +119,39 @@
|
|||||||
},
|
},
|
||||||
"authorization": {
|
"authorization": {
|
||||||
"generate_token": "Générer un jeton",
|
"generate_token": "Générer un jeton",
|
||||||
"graphql_headers": "Les en-têtes d'autorisation sont envoyés en tant que partie de la charge utile de connection_init.",
|
"graphql_headers": "Authorization Headers are sent as part of the payload to connection_init",
|
||||||
"include_in_url": "Inclure dans l'URL",
|
"include_in_url": "Inclure dans l'URL",
|
||||||
"inherited_from": "Inherited from {auth} from Parent Collection {collection} ",
|
"inherited_from": "Inherited from {auth} from Parent Collection {collection} ",
|
||||||
"learn": "Apprendre comment",
|
"learn": "Apprendre comment",
|
||||||
|
"oauth": {
|
||||||
|
"redirect_auth_server_returned_error": "Auth Server returned an error state",
|
||||||
|
"redirect_auth_token_request_failed": "Request to get the auth token failed",
|
||||||
|
"redirect_auth_token_request_invalid_response": "Invalid Response from the Token Endpoint when requesting for an auth token",
|
||||||
|
"redirect_invalid_state": "Invalid State value present in the redirect",
|
||||||
|
"redirect_no_auth_code": "No Authorization Code present in the redirect",
|
||||||
|
"redirect_no_client_id": "No Client ID defined",
|
||||||
|
"redirect_no_client_secret": "No Client Secret Defined",
|
||||||
|
"redirect_no_code_verifier": "No Code Verifier 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_token_generation": "Something went wrong on token generation",
|
||||||
|
"token_generation_oidc_discovery_failed": "Failure on token generation: OpenID Connect Discovery Failed"
|
||||||
|
},
|
||||||
"pass_key_by": "Pass by",
|
"pass_key_by": "Pass by",
|
||||||
"password": "Mot de passe",
|
"password": "Mot de passe",
|
||||||
"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": "Type d'autorisation",
|
"type": "Type d'autorisation",
|
||||||
"username": "Nom d'utilisateur",
|
"username": "Nom d'utilisateur"
|
||||||
"oauth": {
|
|
||||||
"something_went_wrong_on_token_generation": "Un problème s'est produit lors de la génération des jetons",
|
|
||||||
"redirect_auth_server_returned_error": "Le serveur d'authentification a renvoyé un état d'erreur",
|
|
||||||
"redirect_no_auth_code": "Pas de code d'autorisation dans la redirection",
|
|
||||||
"redirect_invalid_state": "Valeur d'état non valide présente dans la redirection",
|
|
||||||
"redirect_no_token_endpoint": "Aucun point de terminaison de jeton n'est défini",
|
|
||||||
"redirect_no_client_id": "Pas d'ID client défini",
|
|
||||||
"redirect_no_client_secret": "Pas de secret client défini",
|
|
||||||
"redirect_no_code_verifier": "Pas de vérificateur de code défini",
|
|
||||||
"redirect_auth_token_request_failed": "La demande d'obtention du jeton d'authentification a échoué",
|
|
||||||
"redirect_auth_token_request_invalid_response": "Réponse invalide du point de terminaison Token lors de la demande d'un jeton d'authentification",
|
|
||||||
"something_went_wrong_on_oauth_redirect": "Quelque chose s'est mal passé lors de la redirection OAuth"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"collection": {
|
"collection": {
|
||||||
"created": "Collection créée",
|
"created": "Collection créée",
|
||||||
"different_parent": "Impossible de réorganiser une collection dont le parent est différent",
|
"different_parent": "Cannot reorder collection with different parent",
|
||||||
"edit": "Modifier la collection",
|
"edit": "Modifier la collection",
|
||||||
"import_or_create": "Importer ou créer une collection",
|
"import_or_create": "Import or create a collection",
|
||||||
"invalid_name": "Veuillez fournir un nom valide pour la collection",
|
"invalid_name": "Veuillez fournir un nom valide pour la collection",
|
||||||
"invalid_root_move": "Collection déjà présente dans la racine",
|
"invalid_root_move": "Collection already in the root",
|
||||||
"moved": "Déplacement réussi",
|
"moved": "Moved Successfully",
|
||||||
"my_collections": "Mes collections",
|
"my_collections": "Mes collections",
|
||||||
"name": "Ma nouvelle collection",
|
"name": "Ma nouvelle collection",
|
||||||
"name_length_insufficient": "Le nom de la collection doit comporter au moins 3 caractères",
|
"name_length_insufficient": "Le nom de la collection doit comporter au moins 3 caractères",
|
||||||
@@ -161,16 +162,16 @@
|
|||||||
"renamed": "Collection renommée",
|
"renamed": "Collection renommée",
|
||||||
"request_in_use": "Demande en cours d'utilisation",
|
"request_in_use": "Demande en cours d'utilisation",
|
||||||
"save_as": "Enregistrer sous",
|
"save_as": "Enregistrer sous",
|
||||||
"save_to_collection": "Enregistrer dans la collection",
|
"save_to_collection": "Save to Collection",
|
||||||
"select": "Sélectionnez une collection",
|
"select": "Sélectionnez une collection",
|
||||||
"select_location": "Sélectionnez l'emplacement",
|
"select_location": "Sélectionnez l'emplacement",
|
||||||
"select_team": "Sélectionnez une équipe",
|
"select_team": "Sélectionnez une équipe",
|
||||||
"team_collections": "Collections de l'équipe"
|
"team_collections": "Collections de l'équipe"
|
||||||
},
|
},
|
||||||
"confirm": {
|
"confirm": {
|
||||||
"close_unsaved_tab": "Êtes-vous sûr de vouloir fermer cet onglet ?",
|
"close_unsaved_tab": "Are you sure you want to close this tab?",
|
||||||
"close_unsaved_tabs": "Êtes-vous sûr de vouloir fermer tous les onglets ? {count} onglets non enregistrés seront perdus",
|
"close_unsaved_tabs": "Are you sure you want to close all tabs? {count} unsaved tabs will be lost.",
|
||||||
"exit_team": "Êtes-vous sûr de vouloir quitter cette équipe ?",
|
"exit_team": "Are you sure you want to leave this team?",
|
||||||
"logout": "Êtes-vous sûr de vouloir vous déconnecter?",
|
"logout": "Êtes-vous sûr de vouloir vous déconnecter?",
|
||||||
"remove_collection": "Voulez-vous vraiment supprimer définitivement cette collection ?",
|
"remove_collection": "Voulez-vous vraiment supprimer définitivement cette collection ?",
|
||||||
"remove_environment": "Voulez-vous vraiment supprimer définitivement cet environnement ?",
|
"remove_environment": "Voulez-vous vraiment supprimer définitivement cet environnement ?",
|
||||||
@@ -180,31 +181,31 @@
|
|||||||
"remove_shared_request": "Are you sure you want to permanently delete this shared request?",
|
"remove_shared_request": "Are you sure you want to permanently delete this shared request?",
|
||||||
"remove_team": "Voulez-vous vraiment supprimer cette équipe ?",
|
"remove_team": "Voulez-vous vraiment supprimer cette équipe ?",
|
||||||
"remove_telemetry": "Êtes-vous sûr de vouloir désactiver la télémétrie ?",
|
"remove_telemetry": "Êtes-vous sûr de vouloir désactiver la télémétrie ?",
|
||||||
"request_change": "Êtes-vous sûr de vouloir rejeter la demande en cours ? Les modifications non enregistrées seront perdues.",
|
"request_change": "Are you sure you want to discard current request, unsaved changes will be lost.",
|
||||||
"save_unsaved_tab": "Souhaitez-vous enregistrer les modifications apportées dans cet onglet ?",
|
"save_unsaved_tab": "Do you want to save changes made in this tab?",
|
||||||
"sync": "Voulez-vous vraiment synchroniser cet espace de travail ?"
|
"sync": "Voulez-vous vraiment synchroniser cet espace de travail ?"
|
||||||
},
|
},
|
||||||
"context_menu": {
|
"context_menu": {
|
||||||
"add_parameters": "Ajouter aux paramètres",
|
"add_parameters": "Add to parameters",
|
||||||
"open_request_in_new_tab": "Ouvrir la demande dans un nouvel onglet",
|
"open_request_in_new_tab": "Open request in new tab",
|
||||||
"set_environment_variable": "Définir comme variable"
|
"set_environment_variable": "Set as variable"
|
||||||
},
|
},
|
||||||
"cookies": {
|
"cookies": {
|
||||||
"modal": {
|
"modal": {
|
||||||
"new_domain_name": "Nouveau nom de domaine",
|
"cookie_expires": "Expires",
|
||||||
"set": "Définir un cookie",
|
"cookie_name": "Name",
|
||||||
"cookie_string": "Chaîne de caractères de cookie",
|
"cookie_path": "Path",
|
||||||
"enter_cookie_string": "Saisir la chaîne de caractères du cookie",
|
"cookie_string": "Cookie string",
|
||||||
"cookie_name": "Nom",
|
"cookie_value": "Value",
|
||||||
"cookie_value": "Valeur",
|
"empty_domain": "Domain is empty",
|
||||||
"cookie_path": "Chemin d'accès",
|
"empty_domains": "Domain list is empty",
|
||||||
"cookie_expires": "Expiration",
|
"enter_cookie_string": "Enter cookie string",
|
||||||
"managed_tab": "Gestion",
|
"interceptor_no_support": "Your currently selected interceptor does not support cookies. Select a different Interceptor and try again.",
|
||||||
"raw_tab": "Brut",
|
"managed_tab": "Managed",
|
||||||
"interceptor_no_support": "L'intercepteur que vous avez sélectionné ne prend pas en charge les cookies. Sélectionnez un autre intercepteur et réessayez.",
|
"new_domain_name": "New domain name",
|
||||||
"empty_domains": "La liste des domaines est vide",
|
"no_cookies_in_domain": "No cookies set for this domain",
|
||||||
"empty_domain": "Le domaine est vide",
|
"raw_tab": "Raw",
|
||||||
"no_cookies_in_domain": "Aucun cookie n'est défini pour ce domaine"
|
"set": "Set a cookie"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"count": {
|
"count": {
|
||||||
@@ -237,7 +238,7 @@
|
|||||||
"profile": "Connectez-vous pour voir votre profil",
|
"profile": "Connectez-vous pour voir votre profil",
|
||||||
"protocols": "Les protocoles sont vides",
|
"protocols": "Les protocoles sont vides",
|
||||||
"schema": "Se connecter à un point de terminaison GraphQL",
|
"schema": "Se connecter à un point de terminaison GraphQL",
|
||||||
"shared_requests": "Il n'y a pas de requêtes partagées",
|
"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": "Nom de l'équipe vide",
|
"team_name": "Nom de l'équipe vide",
|
||||||
@@ -251,15 +252,15 @@
|
|||||||
"create_new": "Créer un nouvel environnement",
|
"create_new": "Créer un nouvel environnement",
|
||||||
"created": "Environnement créé",
|
"created": "Environnement créé",
|
||||||
"deleted": "Environnement supprimé",
|
"deleted": "Environnement supprimé",
|
||||||
"duplicated": "Environnement dupliqué",
|
"duplicated": "Environment duplicated",
|
||||||
"edit": "Modifier l'environnement",
|
"edit": "Modifier l'environnement",
|
||||||
"empty_variables": "No variables",
|
"empty_variables": "No variables",
|
||||||
"global": "Global",
|
"global": "Global",
|
||||||
"global_variables": "Variables globales",
|
"global_variables": "Global variables",
|
||||||
"import_or_create": "Importer ou créer un environnement",
|
"import_or_create": "Import or create a environment",
|
||||||
"invalid_name": "Veuillez fournir un nom valide pour l'environnement",
|
"invalid_name": "Veuillez fournir un nom valide pour l'environnement",
|
||||||
"list": "Variables d'environnement",
|
"list": "Environment variables",
|
||||||
"my_environments": "Mes environnements",
|
"my_environments": "My Environments",
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
"nested_overflow": "les variables d'environnement imbriquées sont limitées à 10 niveaux",
|
"nested_overflow": "les variables d'environnement imbriquées sont limitées à 10 niveaux",
|
||||||
"new": "Nouvel environnement",
|
"new": "Nouvel environnement",
|
||||||
@@ -283,11 +284,11 @@
|
|||||||
"authproviders_load_error": "Unable to load auth providers",
|
"authproviders_load_error": "Unable to load auth providers",
|
||||||
"browser_support_sse": "Ce navigateur ne semble pas prendre en charge les événements envoyés par le serveur.",
|
"browser_support_sse": "Ce navigateur ne semble pas prendre en charge les événements envoyés par le serveur.",
|
||||||
"check_console_details": "Consultez le journal de la console pour plus de détails.",
|
"check_console_details": "Consultez le journal de la console pour plus de détails.",
|
||||||
"check_how_to_add_origin": "Vérifiez comment vous pouvez ajouter une origine",
|
"check_how_to_add_origin": "Check how you can add an origin",
|
||||||
"curl_invalid_format": "cURL n'est pas formaté correctement",
|
"curl_invalid_format": "cURL n'est pas formaté correctement",
|
||||||
"danger_zone": "Zone de danger",
|
"danger_zone": "Danger zone",
|
||||||
"delete_account": "Votre compte est actuellement propriétaire de ces équipes :",
|
"delete_account": "Your account is currently an owner in these teams:",
|
||||||
"delete_account_description": "Vous devez vous retirer, transférer la propriété ou supprimer ces équipes avant de pouvoir supprimer votre compte.",
|
"delete_account_description": "You must either remove yourself, transfer ownership, or delete these teams before you can delete your account.",
|
||||||
"empty_req_name": "Nom de la requête vide",
|
"empty_req_name": "Nom de la requête vide",
|
||||||
"f12_details": "(F12 pour les détails)",
|
"f12_details": "(F12 pour les détails)",
|
||||||
"gql_prettify_invalid_query": "Impossible de formater une requête non valide, résolvez les erreurs de syntaxe de la requête et réessayer",
|
"gql_prettify_invalid_query": "Impossible de formater une requête non valide, résolvez les erreurs de syntaxe de la requête et réessayer",
|
||||||
@@ -299,13 +300,13 @@
|
|||||||
"json_prettify_invalid_body": "Impossible de formater un corps non valide, résolvez les erreurs de syntaxe json et réessayez",
|
"json_prettify_invalid_body": "Impossible de formater un corps non valide, résolvez les erreurs de syntaxe json et réessayez",
|
||||||
"network_error": "Il semble y avoir une erreur de réseau. Veuillez réessayer.",
|
"network_error": "Il semble y avoir une erreur de réseau. Veuillez réessayer.",
|
||||||
"network_fail": "Impossible d'envoyer la requête",
|
"network_fail": "Impossible d'envoyer la requête",
|
||||||
"no_collections_to_export": "Aucune collection à exporter. Veuillez créer une collection pour commencer.",
|
"no_collections_to_export": "No collections to export. Please create a collection to get started.",
|
||||||
"no_duration": "Pas de durée",
|
"no_duration": "Pas de durée",
|
||||||
"no_environments_to_export": "Aucun environnement à exporter. Veuillez créer un environnement pour commencer.",
|
"no_environments_to_export": "No environments to export. Please create an environment to get started.",
|
||||||
"no_results_found": "Aucune correspondance trouvée",
|
"no_results_found": "Aucune correspondance trouvée",
|
||||||
"page_not_found": "Cette page n'a pas pu être trouvée",
|
"page_not_found": "Cette page n'a pas pu être trouvée",
|
||||||
"please_install_extension": "Veuillez installer l'extension et ajouter l'origine à l'extension.",
|
"please_install_extension": "Please install the extension and add origin to the extension.",
|
||||||
"proxy_error": "Erreur de proxy",
|
"proxy_error": "Proxy error",
|
||||||
"script_fail": "Impossible d'exécuter le script de pré-requête",
|
"script_fail": "Impossible d'exécuter le script de pré-requête",
|
||||||
"something_went_wrong": "Quelque chose s'est mal passé",
|
"something_went_wrong": "Quelque chose s'est mal passé",
|
||||||
"test_script_fail": "Impossible d'exécuter le script post-requête"
|
"test_script_fail": "Impossible d'exécuter le script post-requête"
|
||||||
@@ -319,9 +320,9 @@
|
|||||||
"title": "Exportation"
|
"title": "Exportation"
|
||||||
},
|
},
|
||||||
"filter": {
|
"filter": {
|
||||||
"all": "Tout",
|
"all": "All",
|
||||||
"none": "Aucun",
|
"none": "None",
|
||||||
"starred": "Étoilé"
|
"starred": "Starred"
|
||||||
},
|
},
|
||||||
"folder": {
|
"folder": {
|
||||||
"created": "Dossier créé",
|
"created": "Dossier créé",
|
||||||
@@ -332,19 +333,19 @@
|
|||||||
"renamed": "Dossier renommé"
|
"renamed": "Dossier renommé"
|
||||||
},
|
},
|
||||||
"graphql": {
|
"graphql": {
|
||||||
"connection_switch_confirm": "Voulez-vous vous connecter avec le dernier point de terminaison GraphQL ?",
|
"connection_switch_confirm": "Do you want to connect with the latest GraphQL endpoint?",
|
||||||
"connection_switch_new_url": "Le passage à un autre onglet vous déconnectera de la connexion GraphQL active. La nouvelle URL de connexion est",
|
"connection_switch_new_url": "Switching to a tab will disconnected you from the active GraphQL connection. New connection URL is",
|
||||||
"connection_switch_url": "Vous êtes connecté à un point de terminaison GraphQL dont l'URL de connexion est",
|
"connection_switch_url": "You're connected to a GraphQL endpoint the connection URL is",
|
||||||
"mutations": "Mutations",
|
"mutations": "Mutations",
|
||||||
"schema": "Schéma",
|
"schema": "Schéma",
|
||||||
"subscriptions": "Abonnements",
|
"subscriptions": "Abonnements",
|
||||||
"switch_connection": "Changer de connexion"
|
"switch_connection": "Switch connection"
|
||||||
},
|
},
|
||||||
"graphql_collections": {
|
"graphql_collections": {
|
||||||
"title": "GraphQL Collections"
|
"title": "GraphQL Collections"
|
||||||
},
|
},
|
||||||
"group": {
|
"group": {
|
||||||
"time": "Temps",
|
"time": "Time",
|
||||||
"url": "URL"
|
"url": "URL"
|
||||||
},
|
},
|
||||||
"header": {
|
"header": {
|
||||||
@@ -375,7 +376,7 @@
|
|||||||
"import": {
|
"import": {
|
||||||
"collections": "Importer des collections",
|
"collections": "Importer des collections",
|
||||||
"curl": "Importer en cURL",
|
"curl": "Importer en cURL",
|
||||||
"environments_from_gist": "Importer depuis 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": "Échec de l'importation",
|
"failed": "Échec de l'importation",
|
||||||
"from_file": "Import from File",
|
"from_file": "Import from File",
|
||||||
@@ -407,27 +408,27 @@
|
|||||||
"title": "Importer"
|
"title": "Importer"
|
||||||
},
|
},
|
||||||
"inspections": {
|
"inspections": {
|
||||||
"description": "Inspecter les erreurs possibles",
|
"description": "Inspect possible errors",
|
||||||
"environment": {
|
"environment": {
|
||||||
"add_environment": "Ajouter à l'environnement",
|
"add_environment": "Add to Environment",
|
||||||
"not_found": "La variable d'environnement “{environment}“ n'a pas été trouvée."
|
"not_found": "Environment variable “{environment}” not found."
|
||||||
},
|
},
|
||||||
"header": {
|
"header": {
|
||||||
"cookie": "Le navigateur ne permet pas à Hoppscotch de définir l'en-tête Cookie. Pendant que nous travaillons sur l'application de bureau Hoppscotch (bientôt disponible), veuillez utiliser l'en-tête d'autorisation à la place."
|
"cookie": "The browser doesn't allow Hoppscotch to set the Cookie Header. While we're working on the Hoppscotch Desktop App (coming soon), please use the Authorization Header instead."
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"401_error": "Veuillez vérifier vos informations d'authentification.",
|
"401_error": "Please check your authentication credentials.",
|
||||||
"404_error": "Veuillez vérifier l'URL de votre demande et le type de méthode.",
|
"404_error": "Please check your request URL and method type.",
|
||||||
"cors_error": "Veuillez vérifier la configuration du partage des ressources entre les origines.",
|
"cors_error": "Please check your Cross-Origin Resource Sharing configuration.",
|
||||||
"default_error": "Veuillez vérifier votre demande.",
|
"default_error": "Please check your request.",
|
||||||
"network_error": "Veuillez vérifier votre connexion réseau."
|
"network_error": "Please check your network connection."
|
||||||
},
|
},
|
||||||
"title": "Inspecteur",
|
"title": "Inspector",
|
||||||
"url": {
|
"url": {
|
||||||
"extension_not_installed": "L'extension n'est pas installée.",
|
"extension_not_installed": "Extension not installed.",
|
||||||
"extension_unknown_origin": "Assurez-vous d'avoir ajouté l'origine du point de terminaison de l'API à la liste des extensions du navigateur Hoppscotch.",
|
"extension_unknown_origin": "Make sure you've added the API endpoint's origin to the Hoppscotch Browser Extension list.",
|
||||||
"extention_enable_action": "Activer l'extension du navigateur",
|
"extention_enable_action": "Enable Browser Extension",
|
||||||
"extention_not_enabled": "L'extension n'est pas activée."
|
"extention_not_enabled": "Extension not enabled."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"layout": {
|
"layout": {
|
||||||
@@ -438,25 +439,25 @@
|
|||||||
"row": "Disposition horizontale"
|
"row": "Disposition horizontale"
|
||||||
},
|
},
|
||||||
"modal": {
|
"modal": {
|
||||||
"close_unsaved_tab": "Vous avez des modifications non enregistrées",
|
"close_unsaved_tab": "You have unsaved changes",
|
||||||
"collections": "Collections",
|
"collections": "Collections",
|
||||||
"confirm": "Confirmer",
|
"confirm": "Confirmer",
|
||||||
"customize_request": "Customize Request",
|
"customize_request": "Customize Request",
|
||||||
"edit_request": "Modifier la requête",
|
"edit_request": "Modifier la requête",
|
||||||
"import_export": "Importer / Exporter",
|
"import_export": "Importer / Exporter",
|
||||||
"share_request": "Partager une requête"
|
"share_request": "Share Request"
|
||||||
},
|
},
|
||||||
"mqtt": {
|
"mqtt": {
|
||||||
"already_subscribed": "Vous êtes déjà abonné à ce sujet.",
|
"already_subscribed": "You are already subscribed to this topic.",
|
||||||
"clean_session": "Effacer la Session",
|
"clean_session": "Clean Session",
|
||||||
"clear_input": "Effacer la saisie",
|
"clear_input": "Clear input",
|
||||||
"clear_input_on_send": "Effacer la saisie lors de l'envoi",
|
"clear_input_on_send": "Clear input on send",
|
||||||
"client_id": "Client ID",
|
"client_id": "Client ID",
|
||||||
"color": "Choisir la couleur",
|
"color": "Pick a color",
|
||||||
"communication": "Communication",
|
"communication": "Communication",
|
||||||
"connection_config": "Connection Config",
|
"connection_config": "Connection Config",
|
||||||
"connection_not_authorized": "Cette connexion MQTT n'utilise pas d'authentification.",
|
"connection_not_authorized": "This MQTT connection does not use any authentication.",
|
||||||
"invalid_topic": "Veuillez fournir un sujet pour l'abonnement",
|
"invalid_topic": "Please provide a topic for the subscription",
|
||||||
"keep_alive": "Keep Alive",
|
"keep_alive": "Keep Alive",
|
||||||
"log": "Infos",
|
"log": "Infos",
|
||||||
"lw_message": "Last-Will Message",
|
"lw_message": "Last-Will Message",
|
||||||
@@ -465,7 +466,7 @@
|
|||||||
"lw_topic": "Last-Will Topic",
|
"lw_topic": "Last-Will Topic",
|
||||||
"message": "Message",
|
"message": "Message",
|
||||||
"new": "New Subscription",
|
"new": "New Subscription",
|
||||||
"not_connected": "Veuillez d'abord établir une connexion MQTT.",
|
"not_connected": "Please start a MQTT connection first.",
|
||||||
"publish": "Publier",
|
"publish": "Publier",
|
||||||
"qos": "QoS",
|
"qos": "QoS",
|
||||||
"ssl": "SSL",
|
"ssl": "SSL",
|
||||||
@@ -479,7 +480,7 @@
|
|||||||
"navigation": {
|
"navigation": {
|
||||||
"doc": "Documents",
|
"doc": "Documents",
|
||||||
"graphql": "GraphQL",
|
"graphql": "GraphQL",
|
||||||
"profile": "Profil",
|
"profile": "Profile",
|
||||||
"realtime": "Temps réel",
|
"realtime": "Temps réel",
|
||||||
"rest": "REST",
|
"rest": "REST",
|
||||||
"settings": "Paramètres"
|
"settings": "Paramètres"
|
||||||
@@ -492,7 +493,7 @@
|
|||||||
},
|
},
|
||||||
"profile": {
|
"profile": {
|
||||||
"app_settings": "Réglages de l'application",
|
"app_settings": "Réglages de l'application",
|
||||||
"default_hopp_displayname": "Utilisateur anonyme",
|
"default_hopp_displayname": "Unnamed User",
|
||||||
"editor": "Éditeur",
|
"editor": "Éditeur",
|
||||||
"editor_description": "Les éditeurs peuvent ajouter, modifier et supprimer des demandes.",
|
"editor_description": "Les éditeurs peuvent ajouter, modifier et supprimer des demandes.",
|
||||||
"email_verification_mail": "Un e-mail de vérification a été envoyé à votre adresse e-mail. Veuillez cliquer sur le lien pour vérifier votre adresse électronique.",
|
"email_verification_mail": "Un e-mail de vérification a été envoyé à votre adresse e-mail. Veuillez cliquer sur le lien pour vérifier votre adresse électronique.",
|
||||||
@@ -525,17 +526,17 @@
|
|||||||
"enter_curl": "Entrer cURL",
|
"enter_curl": "Entrer cURL",
|
||||||
"generate_code": "Générer le code",
|
"generate_code": "Générer le code",
|
||||||
"generated_code": "Code généré",
|
"generated_code": "Code généré",
|
||||||
|
"go_to_authorization_tab": "Go to Authorization tab",
|
||||||
"go_to_body_tab": "Go to Body tab",
|
"go_to_body_tab": "Go to Body tab",
|
||||||
"go_to_authorization_tab": "Aller à l'autorisation",
|
|
||||||
"header_list": "Liste des en-têtes",
|
"header_list": "Liste des en-têtes",
|
||||||
"invalid_name": "Veuillez fournir un nom pour la requête",
|
"invalid_name": "Veuillez fournir un nom pour la requête",
|
||||||
"method": "Méthode",
|
"method": "Méthode",
|
||||||
"moved": "Request moved",
|
"moved": "Request moved",
|
||||||
"name": "Nom de la requête",
|
"name": "Nom de la requête",
|
||||||
"new": "Nouvelle requête",
|
"new": "Nouvelle requête",
|
||||||
"order_changed": "Demande de commande Mise à jour",
|
"order_changed": "Request Order Updated",
|
||||||
"override": "Remplacer",
|
"override": "Remplacer",
|
||||||
"override_help": "Définir <xmp>Content-Type</xmp> dans les en-têtes",
|
"override_help": "Set <xmp>Content-Type</xmp> in Headers",
|
||||||
"overriden": "Remplacé",
|
"overriden": "Remplacé",
|
||||||
"parameter_list": "Paramètres de requête",
|
"parameter_list": "Paramètres de requête",
|
||||||
"parameters": "Paramètres",
|
"parameters": "Paramètres",
|
||||||
@@ -543,7 +544,7 @@
|
|||||||
"payload": "Charge utile",
|
"payload": "Charge utile",
|
||||||
"query": "Requête",
|
"query": "Requête",
|
||||||
"raw_body": "Corps de requête brut",
|
"raw_body": "Corps de requête brut",
|
||||||
"rename": "Demande de renommage",
|
"rename": "Rename Request",
|
||||||
"renamed": "Requête renommée",
|
"renamed": "Requête renommée",
|
||||||
"run": "Lancer",
|
"run": "Lancer",
|
||||||
"save": "Sauvegarder",
|
"save": "Sauvegarder",
|
||||||
@@ -563,7 +564,7 @@
|
|||||||
"response": {
|
"response": {
|
||||||
"audio": "Audio",
|
"audio": "Audio",
|
||||||
"body": "Corps de réponse",
|
"body": "Corps de réponse",
|
||||||
"filter_response_body": "Filtrer le corps de la réponse JSON (utilise la syntaxe JSONPath)",
|
"filter_response_body": "Filter JSON response body (uses JSONPath syntax)",
|
||||||
"headers": "En-têtes",
|
"headers": "En-têtes",
|
||||||
"html": "HTML",
|
"html": "HTML",
|
||||||
"image": "Image",
|
"image": "Image",
|
||||||
@@ -575,14 +576,14 @@
|
|||||||
"status": "Statut",
|
"status": "Statut",
|
||||||
"time": "Temps",
|
"time": "Temps",
|
||||||
"title": "Réponse",
|
"title": "Réponse",
|
||||||
"video": "Vidéo",
|
"video": "Video",
|
||||||
"waiting_for_connection": "En attente de connexion",
|
"waiting_for_connection": "En attente de connexion",
|
||||||
"xml": "XML"
|
"xml": "XML"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"accent_color": "Couleur d'accent",
|
"accent_color": "Couleur d'accent",
|
||||||
"account": "Compte",
|
"account": "Compte",
|
||||||
"account_deleted": "Votre compte a été supprimé",
|
"account_deleted": "Your account has been deleted",
|
||||||
"account_description": "Personnalisez les paramètres de votre compte.",
|
"account_description": "Personnalisez les paramètres de votre compte.",
|
||||||
"account_email_description": "Votre adresse e-mail principale.",
|
"account_email_description": "Votre adresse e-mail principale.",
|
||||||
"account_name_description": "Ceci est votre nom d'affichage.",
|
"account_name_description": "Ceci est votre nom d'affichage.",
|
||||||
@@ -591,8 +592,8 @@
|
|||||||
"black_mode": "Noir",
|
"black_mode": "Noir",
|
||||||
"choose_language": "Choisissez la langue",
|
"choose_language": "Choisissez la langue",
|
||||||
"dark_mode": "Sombre",
|
"dark_mode": "Sombre",
|
||||||
"delete_account": "Supprimer le compte",
|
"delete_account": "Delete account",
|
||||||
"delete_account_description": "Lorsque vous supprimez votre compte, toutes vos données sont définitivement effacées. Cette action ne peut être annulée.",
|
"delete_account_description": "Once you delete your account, all your data will be permanently deleted. This action cannot be undone.",
|
||||||
"expand_navigation": "Expand navigation",
|
"expand_navigation": "Expand navigation",
|
||||||
"experiments": "Expériences",
|
"experiments": "Expériences",
|
||||||
"experiments_notice": "Il s'agit d'une collection d'expériences sur lesquelles nous travaillons et qui pourraient s'avérer utiles, amusantes, les deux ou aucune. Ils ne sont pas définitifs et peuvent ne pas être stables, donc si quelque chose de trop étrange se produit, ne paniquez pas. Il suffit d'éteindre le truc. Blague à part,",
|
"experiments_notice": "Il s'agit d'une collection d'expériences sur lesquelles nous travaillons et qui pourraient s'avérer utiles, amusantes, les deux ou aucune. Ils ne sont pas définitifs et peuvent ne pas être stables, donc si quelque chose de trop étrange se produit, ne paniquez pas. Il suffit d'éteindre le truc. Blague à part,",
|
||||||
@@ -600,7 +601,7 @@
|
|||||||
"extension_version": "Version d'extension",
|
"extension_version": "Version d'extension",
|
||||||
"extensions": "Extensions",
|
"extensions": "Extensions",
|
||||||
"extensions_use_toggle": "Utilisez l'extension de navigateur pour envoyer des requêtes (le cas échéant)",
|
"extensions_use_toggle": "Utilisez l'extension de navigateur pour envoyer des requêtes (le cas échéant)",
|
||||||
"follow": "Suivez-nous",
|
"follow": "Follow Us",
|
||||||
"interceptor": "Intercepteur",
|
"interceptor": "Intercepteur",
|
||||||
"interceptor_description": "Middleware entre l'application et les API.",
|
"interceptor_description": "Middleware entre l'application et les API.",
|
||||||
"language": "Langue",
|
"language": "Langue",
|
||||||
@@ -630,7 +631,7 @@
|
|||||||
"theme_description": "Personnalisez le thème de votre application.",
|
"theme_description": "Personnalisez le thème de votre application.",
|
||||||
"use_experimental_url_bar": "Utiliser la barre d'URL expérimentale avec mise en évidence de l'environnement",
|
"use_experimental_url_bar": "Utiliser la barre d'URL expérimentale avec mise en évidence de l'environnement",
|
||||||
"user": "Utilisateur",
|
"user": "Utilisateur",
|
||||||
"verified_email": "E-mail vérifié",
|
"verified_email": "Verified email",
|
||||||
"verify_email": "Vérifier l'email"
|
"verify_email": "Vérifier l'email"
|
||||||
},
|
},
|
||||||
"shared_requests": {
|
"shared_requests": {
|
||||||
@@ -683,20 +684,20 @@
|
|||||||
"title": "Navigation"
|
"title": "Navigation"
|
||||||
},
|
},
|
||||||
"others": {
|
"others": {
|
||||||
"prettify": "Améliorer le contenu de l'éditeur",
|
"prettify": "Prettify Editor's Content",
|
||||||
"title": "Autres"
|
"title": "Others"
|
||||||
},
|
},
|
||||||
"request": {
|
"request": {
|
||||||
"delete_method": "Sélectionnez la méthode DELETE",
|
"delete_method": "Sélectionnez la méthode DELETE",
|
||||||
"get_method": "Sélectionnez la méthode GET",
|
"get_method": "Sélectionnez la méthode GET",
|
||||||
"head_method": "Sélectionnez la méthode HEAD",
|
"head_method": "Sélectionnez la méthode HEAD",
|
||||||
"import_curl": "Importer cURL",
|
"import_curl": "Import cURL",
|
||||||
"method": "Méthode",
|
"method": "Méthode",
|
||||||
"next_method": "Sélectionnez la méthode suivante",
|
"next_method": "Sélectionnez la méthode suivante",
|
||||||
"post_method": "Sélectionnez la méthode POST",
|
"post_method": "Sélectionnez la méthode POST",
|
||||||
"previous_method": "Sélectionnez la méthode précédente",
|
"previous_method": "Sélectionnez la méthode précédente",
|
||||||
"put_method": "Sélectionnez la méthode PUT",
|
"put_method": "Sélectionnez la méthode PUT",
|
||||||
"rename": "Demande de renommage",
|
"rename": "Rename Request",
|
||||||
"reset_request": "Réinitialiser la requête",
|
"reset_request": "Réinitialiser la requête",
|
||||||
"save_request": "Save Request",
|
"save_request": "Save Request",
|
||||||
"save_to_collections": "Enregistrer dans les collections",
|
"save_to_collections": "Enregistrer dans les collections",
|
||||||
@@ -727,89 +728,89 @@
|
|||||||
},
|
},
|
||||||
"socketio": {
|
"socketio": {
|
||||||
"communication": "Communication",
|
"communication": "Communication",
|
||||||
"connection_not_authorized": "Cette connexion SocketIO n'utilise pas d'authentification.",
|
"connection_not_authorized": "This SocketIO connection does not use any authentication.",
|
||||||
"event_name": "Nom de l'événement",
|
"event_name": "Nom de l'événement",
|
||||||
"events": "Événements",
|
"events": "Événements",
|
||||||
"log": "Infos",
|
"log": "Infos",
|
||||||
"url": "URL"
|
"url": "URL"
|
||||||
},
|
},
|
||||||
"spotlight": {
|
"spotlight": {
|
||||||
"change_language": "Changer de langue",
|
"change_language": "Change Language",
|
||||||
"environments": {
|
"environments": {
|
||||||
"delete": "Supprimer l'environnement actuel",
|
"delete": "Delete current environment",
|
||||||
"duplicate": "Dupliquer l'environnement actuel",
|
"duplicate": "Duplicate current environment",
|
||||||
"duplicate_global": "Duplication de l'environnement global",
|
"duplicate_global": "Duplicate global environment",
|
||||||
"edit": "Modifier l'environnement actuel",
|
"edit": "Edit current environment",
|
||||||
"edit_global": "Modifier l'environnement mondial",
|
"edit_global": "Edit global environment",
|
||||||
"new": "Créer un nouvel environnement",
|
"new": "Create new environment",
|
||||||
"new_variable": "Créer une nouvelle variable d'environnement",
|
"new_variable": "Create a new environment variable",
|
||||||
"title": "Environments"
|
"title": "Environments"
|
||||||
},
|
},
|
||||||
"general": {
|
"general": {
|
||||||
"chat": "Chat avec le support",
|
"chat": "Chat with support",
|
||||||
"help_menu": "Aide et assistance",
|
"help_menu": "Help and support",
|
||||||
"open_docs": "Lire la documentation",
|
"open_docs": "Read Documentation",
|
||||||
"open_github": "Ouvrir le dépôt GitHub",
|
"open_github": "Open GitHub repository",
|
||||||
"open_keybindings": "Raccourcis clavier",
|
"open_keybindings": "Keyboard shortcuts",
|
||||||
"social": "Social",
|
"social": "Social",
|
||||||
"title": "Général"
|
"title": "General"
|
||||||
},
|
},
|
||||||
"graphql": {
|
"graphql": {
|
||||||
"connect": "Connexion au serveur",
|
"connect": "Connect to server",
|
||||||
"disconnect": "Déconnexion du serveur"
|
"disconnect": "Disconnect from server"
|
||||||
},
|
},
|
||||||
"miscellaneous": {
|
"miscellaneous": {
|
||||||
"invite": "Invitez vos amis à Hoppscotch",
|
"invite": "Invite your friends to Hoppscotch",
|
||||||
"title": "Divers"
|
"title": "Miscellaneous"
|
||||||
},
|
},
|
||||||
"request": {
|
"request": {
|
||||||
"save_as_new": "Sauvegarder comme nouvelle demande",
|
"save_as_new": "Save as new request",
|
||||||
"select_method": "Sélectionner la méthode",
|
"select_method": "Select method",
|
||||||
"switch_to": "Basculer vers",
|
"switch_to": "Switch to",
|
||||||
"tab_authorization": "Onglet Autorisation",
|
"tab_authorization": "Authorization tab",
|
||||||
"tab_body": "Onglet du corps",
|
"tab_body": "Body tab",
|
||||||
"tab_headers": "Onglet En-têtes",
|
"tab_headers": "Headers tab",
|
||||||
"tab_parameters": "Onglet Paramètres",
|
"tab_parameters": "Parameters tab",
|
||||||
"tab_pre_request_script": "Onglet script de pré-demande",
|
"tab_pre_request_script": "Pre-request script tab",
|
||||||
"tab_query": "Onglet Requête",
|
"tab_query": "Query tab",
|
||||||
"tab_tests": "Onglet Tests",
|
"tab_tests": "Tests tab",
|
||||||
"tab_variables": "Onglet Variables"
|
"tab_variables": "Variables tab"
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"copy": "Copier la réponse",
|
"copy": "Copy response",
|
||||||
"download": "Télécharger la réponse sous forme de fichier",
|
"download": "Download response as file",
|
||||||
"title": "Réponse"
|
"title": "Response"
|
||||||
},
|
},
|
||||||
"section": {
|
"section": {
|
||||||
"interceptor": "Intercepteur",
|
"interceptor": "Interceptor",
|
||||||
"interface": "Interface",
|
"interface": "Interface",
|
||||||
"theme": "Thème",
|
"theme": "Theme",
|
||||||
"user": "Utilisateur"
|
"user": "User"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"change_interceptor": "Changer d'intercepteur",
|
"change_interceptor": "Change Interceptor",
|
||||||
"change_language": "Changer de langue",
|
"change_language": "Change Language",
|
||||||
"theme": {
|
"theme": {
|
||||||
"black": "Noir",
|
"black": "Black",
|
||||||
"dark": "Sombre",
|
"dark": "Dark",
|
||||||
"light": "Clair",
|
"light": "Light",
|
||||||
"system": "Préférence du système"
|
"system": "System preference"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tab": {
|
"tab": {
|
||||||
"close_current": "Fermer l'onglet actuel",
|
"close_current": "Close current tab",
|
||||||
"close_others": "Fermer tous les autres onglets",
|
"close_others": "Close all other tabs",
|
||||||
"duplicate": "Dupliquer l'onglet actuel",
|
"duplicate": "Duplicate current tab",
|
||||||
"new_tab": "Ouvrir un nouvel onglet",
|
"new_tab": "Open a new tab",
|
||||||
"title": "Onglets"
|
"title": "Tabs"
|
||||||
},
|
},
|
||||||
"workspace": {
|
"workspace": {
|
||||||
"delete": "Supprimer l'équipe actuelle",
|
"delete": "Delete current team",
|
||||||
"edit": "Modifier l'équipe actuelle",
|
"edit": "Edit current team",
|
||||||
"invite": "Inviter les gens à rejoindre l'équipe",
|
"invite": "Invite people to team",
|
||||||
"new": "Créer une nouvelle équipe",
|
"new": "Create new team",
|
||||||
"switch_to_personal": "Passez à votre espace de travail personnel",
|
"switch_to_personal": "Switch to your personal workspace",
|
||||||
"title": "Les équipes"
|
"title": "Teams"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sse": {
|
"sse": {
|
||||||
@@ -835,12 +836,12 @@
|
|||||||
"disconnected": "Déconnecté",
|
"disconnected": "Déconnecté",
|
||||||
"disconnected_from": "Déconnecté de {name}",
|
"disconnected_from": "Déconnecté de {name}",
|
||||||
"docs_generated": "Documentation générée",
|
"docs_generated": "Documentation générée",
|
||||||
|
"download_failed": "Download failed",
|
||||||
"download_started": "Téléchargement commencé",
|
"download_started": "Téléchargement commencé",
|
||||||
"download_failed": "Téléchargement échoué",
|
|
||||||
"enabled": "Active",
|
"enabled": "Active",
|
||||||
"file_imported": "Fichier importé",
|
"file_imported": "Fichier importé",
|
||||||
"finished_in": "Terminé en {duration} ms",
|
"finished_in": "Terminé en {duration} ms",
|
||||||
"hide": "Cacher",
|
"hide": "Hide",
|
||||||
"history_deleted": "Historique supprimé",
|
"history_deleted": "Historique supprimé",
|
||||||
"linewrap": "Retour à la ligne",
|
"linewrap": "Retour à la ligne",
|
||||||
"loading": "Chargement...",
|
"loading": "Chargement...",
|
||||||
@@ -851,7 +852,7 @@
|
|||||||
"published_error": "Quelque chose s'est mal passé lors de la publication du message : {topic} dans le sujet : {message}",
|
"published_error": "Quelque chose s'est mal passé lors de la publication du message : {topic} dans le sujet : {message}",
|
||||||
"published_message": "Message publié : {message} au sujet : {topic}",
|
"published_message": "Message publié : {message} au sujet : {topic}",
|
||||||
"reconnection_error": "Échec de la reconnexion",
|
"reconnection_error": "Échec de la reconnexion",
|
||||||
"show": "Afficher",
|
"show": "Show",
|
||||||
"subscribed_failed": "Échec de l'inscription au sujet : {topic}",
|
"subscribed_failed": "Échec de l'inscription au sujet : {topic}",
|
||||||
"subscribed_success": "Inscription réussie au sujet : {topic}",
|
"subscribed_success": "Inscription réussie au sujet : {topic}",
|
||||||
"unsubscribed_failed": "Échec de la désinscription du sujet : {topic}",
|
"unsubscribed_failed": "Échec de la désinscription du sujet : {topic}",
|
||||||
@@ -860,7 +861,7 @@
|
|||||||
},
|
},
|
||||||
"support": {
|
"support": {
|
||||||
"changelog": "En savoir plus sur les dernières versions",
|
"changelog": "En savoir plus sur les dernières versions",
|
||||||
"chat": "Des questions ? Discutez avec nous!",
|
"chat": "Des questions? Discutez avec nous!",
|
||||||
"community": "Posez des questions et aidez les autres",
|
"community": "Posez des questions et aidez les autres",
|
||||||
"documentation": "En savoir plus sur Hoppscotch",
|
"documentation": "En savoir plus sur Hoppscotch",
|
||||||
"forum": "Posez des questions et obtenez des réponses",
|
"forum": "Posez des questions et obtenez des réponses",
|
||||||
@@ -873,21 +874,21 @@
|
|||||||
"tab": {
|
"tab": {
|
||||||
"authorization": "Autorisation",
|
"authorization": "Autorisation",
|
||||||
"body": "Corps",
|
"body": "Corps",
|
||||||
"close": "Fermer l'onglet",
|
"close": "Close Tab",
|
||||||
"close_others": "Fermer les autres onglets",
|
"close_others": "Close other Tabs",
|
||||||
"collections": "Collections",
|
"collections": "Collections",
|
||||||
"documentation": "Documentation",
|
"documentation": "Documentation",
|
||||||
"duplicate": "Dupliquer l'onglet",
|
"duplicate": "Duplicate Tab",
|
||||||
"environments": "Environments",
|
"environments": "Environments",
|
||||||
"headers": "En-têtes",
|
"headers": "En-têtes",
|
||||||
"history": "Historique",
|
"history": "Histoire",
|
||||||
"mqtt": "MQTT",
|
"mqtt": "MQTT",
|
||||||
"parameters": "Paramètres",
|
"parameters": "Paramètres",
|
||||||
"pre_request_script": "Script de pré-requête",
|
"pre_request_script": "Script de pré-requête",
|
||||||
"queries": "Requêtes",
|
"queries": "Requêtes",
|
||||||
"query": "Requête",
|
"query": "Requête",
|
||||||
"schema": "Schema",
|
"schema": "Schema",
|
||||||
"shared_requests": "Requêtes partagées",
|
"shared_requests": "Shared Requests",
|
||||||
"socketio": "Socket.IO",
|
"socketio": "Socket.IO",
|
||||||
"sse": "ESS",
|
"sse": "ESS",
|
||||||
"tests": "Tests",
|
"tests": "Tests",
|
||||||
@@ -904,6 +905,7 @@
|
|||||||
"email_do_not_match": "L'email ne correspond pas aux détails de votre compte. Contactez le propriétaire de votre équipe.",
|
"email_do_not_match": "L'email ne correspond pas aux détails de votre compte. Contactez le propriétaire de votre équipe.",
|
||||||
"exit": "Quitter l'équipe",
|
"exit": "Quitter l'équipe",
|
||||||
"exit_disabled": "Seul le propriétaire ne peut pas quitter l'équipe",
|
"exit_disabled": "Seul le propriétaire ne peut pas quitter l'équipe",
|
||||||
|
"failed_invites": "Failed invites",
|
||||||
"invalid_coll_id": "Invalid collection ID",
|
"invalid_coll_id": "Invalid collection ID",
|
||||||
"invalid_email_format": "Le format de l'e-mail n'est pas valide",
|
"invalid_email_format": "Le format de l'e-mail n'est pas valide",
|
||||||
"invalid_id": "L'email ne correspond pas aux détails de votre compte. Contactez le propriétaire de votre équipe.",
|
"invalid_id": "L'email ne correspond pas aux détails de votre compte. Contactez le propriétaire de votre équipe.",
|
||||||
@@ -939,22 +941,21 @@
|
|||||||
"no_request_found": "Request not found.",
|
"no_request_found": "Request not found.",
|
||||||
"not_found": "Équipe non trouvée. Contactez le propriétaire de votre équipe.",
|
"not_found": "Équipe non trouvée. Contactez le propriétaire de votre équipe.",
|
||||||
"not_valid_viewer": "Vous n'êtes pas un visionneur valide. Contactez le propriétaire de votre équipe.",
|
"not_valid_viewer": "Vous n'êtes pas un visionneur valide. Contactez le propriétaire de votre équipe.",
|
||||||
"parent_coll_move": "Impossible de déplacer une collection vers une collection enfant",
|
"parent_coll_move": "Cannot move collection to a child collection",
|
||||||
"success_invites": "Les invitations réussites",
|
|
||||||
"pending_invites": "Invitations en attente",
|
"pending_invites": "Invitations en attente",
|
||||||
"failed_invites": "Échec des invitations",
|
|
||||||
"permissions": "Autorisations",
|
"permissions": "Autorisations",
|
||||||
"same_target_destination": "Même destinataire et même cible",
|
"same_target_destination": "Same target and destination",
|
||||||
"saved": "Équipe enregistrée",
|
"saved": "Équipe enregistrée",
|
||||||
"select_a_team": "Choisir une équipe",
|
"select_a_team": "Choisir une équipe",
|
||||||
|
"success_invites": "Success invites",
|
||||||
"title": "Équipes",
|
"title": "Équipes",
|
||||||
"we_sent_invite_link": "Nous avons envoyé un lien d'invitation à tous les invités !",
|
"we_sent_invite_link": "Nous avons envoyé un lien d'invitation à tous les invités !",
|
||||||
"we_sent_invite_link_description": "Demandez à tous les invités de vérifier leur boîte de réception. Cliquez sur le lien pour rejoindre l'équipe."
|
"we_sent_invite_link_description": "Demandez à tous les invités de vérifier leur boîte de réception. Cliquez sur le lien pour rejoindre l'équipe."
|
||||||
},
|
},
|
||||||
"team_environment": {
|
"team_environment": {
|
||||||
"deleted": "Environment supprimé",
|
"deleted": "Environment Deleted",
|
||||||
"duplicate": "Environment dupliqué",
|
"duplicate": "Environment Duplicated",
|
||||||
"not_found": "Environment non trouvé"
|
"not_found": "Environment not found."
|
||||||
},
|
},
|
||||||
"test": {
|
"test": {
|
||||||
"failed": "Test échoué",
|
"failed": "Test échoué",
|
||||||
@@ -974,10 +975,10 @@
|
|||||||
"url": "URL"
|
"url": "URL"
|
||||||
},
|
},
|
||||||
"workspace": {
|
"workspace": {
|
||||||
"change": "Changer d'espace de travail",
|
"change": "Change workspace",
|
||||||
"personal": "Mon espace de travail",
|
"personal": "My Workspace",
|
||||||
"team": "Espace de travail de l'équipe",
|
"team": "Team Workspace",
|
||||||
"title": "Espaces de travail"
|
"title": "Workspaces"
|
||||||
},
|
},
|
||||||
"shortcodes": {
|
"shortcodes": {
|
||||||
"actions": "Actions",
|
"actions": "Actions",
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
{
|
{
|
||||||
"action": {
|
"action": {
|
||||||
"add": "Hozzáadás",
|
"add": "Add",
|
||||||
"autoscroll": "Automatikus görgetés",
|
"autoscroll": "Automatikus görgetés",
|
||||||
"cancel": "Mégse",
|
"cancel": "Mégse",
|
||||||
"choose_file": "Válasszon egy fájlt",
|
"choose_file": "Válasszon egy fájlt",
|
||||||
"clear": "Törlés",
|
"clear": "Törlés",
|
||||||
"clear_all": "Összes törlése",
|
"clear_all": "Összes törlése",
|
||||||
"clear_history": "Összes előzmény törlése",
|
"clear_history": "Clear all History",
|
||||||
"close": "Bezárás",
|
"close": "Bezárás",
|
||||||
"connect": "Kapcsolódás",
|
"connect": "Kapcsolódás",
|
||||||
"connecting": "Kapcsolódás",
|
"connecting": "Kapcsolódás",
|
||||||
"copy": "Másolás",
|
"copy": "Másolás",
|
||||||
"create": "Létrehozás",
|
"create": "Create",
|
||||||
"delete": "Törlés",
|
"delete": "Törlés",
|
||||||
"disconnect": "Leválasztás",
|
"disconnect": "Leválasztás",
|
||||||
"dismiss": "Eltüntetés",
|
"dismiss": "Eltüntetés",
|
||||||
@@ -33,16 +33,16 @@
|
|||||||
"open_workspace": "Munkaterület megnyitása",
|
"open_workspace": "Munkaterület megnyitása",
|
||||||
"paste": "Beillesztés",
|
"paste": "Beillesztés",
|
||||||
"prettify": "Csinosítás",
|
"prettify": "Csinosítás",
|
||||||
"properties": "Tulajdonságok",
|
"properties": "Properties",
|
||||||
"remove": "Eltávolítás",
|
"remove": "Eltávolítás",
|
||||||
"rename": "Átnevezés",
|
"rename": "Rename",
|
||||||
"restore": "Visszaállítás",
|
"restore": "Visszaállítás",
|
||||||
"save": "Mentés",
|
"save": "Mentés",
|
||||||
"scroll_to_bottom": "Görgetés az aljára",
|
"scroll_to_bottom": "Görgetés az aljára",
|
||||||
"scroll_to_top": "Görgetés a tetejére",
|
"scroll_to_top": "Görgetés a tetejére",
|
||||||
"search": "Keresés",
|
"search": "Keresés",
|
||||||
"send": "Küldés",
|
"send": "Küldés",
|
||||||
"share": "Megosztás",
|
"share": "Share",
|
||||||
"start": "Indítás",
|
"start": "Indítás",
|
||||||
"starting": "Indítás",
|
"starting": "Indítás",
|
||||||
"stop": "Leállítás",
|
"stop": "Leállítás",
|
||||||
@@ -61,9 +61,9 @@
|
|||||||
"app": {
|
"app": {
|
||||||
"chat_with_us": "Csevegjen velünk",
|
"chat_with_us": "Csevegjen velünk",
|
||||||
"contact_us": "Lépjen kapcsolatba velünk",
|
"contact_us": "Lépjen kapcsolatba velünk",
|
||||||
"cookies": "Sütik",
|
"cookies": "Cookies",
|
||||||
"copy": "Másolás",
|
"copy": "Másolás",
|
||||||
"copy_interface_type": "Interface típusának másolása",
|
"copy_interface_type": "Copy interface type",
|
||||||
"copy_user_id": "Felhasználó-hitelesítési token másolása",
|
"copy_user_id": "Felhasználó-hitelesítési token másolása",
|
||||||
"developer_option": "Fejlesztői beállítások",
|
"developer_option": "Fejlesztői beállítások",
|
||||||
"developer_option_description": "Fejlesztői eszközök, amelyek segítenek a Hoppscotch fejlesztésében és karbantartásában.",
|
"developer_option_description": "Fejlesztői eszközök, amelyek segítenek a Hoppscotch fejlesztésében és karbantartásában.",
|
||||||
@@ -79,15 +79,15 @@
|
|||||||
"keyboard_shortcuts": "Gyorsbillentyűk",
|
"keyboard_shortcuts": "Gyorsbillentyűk",
|
||||||
"name": "Hoppscotch",
|
"name": "Hoppscotch",
|
||||||
"new_version_found": "Új verzió található. Töltse újra az oldalt a frissítéshez.",
|
"new_version_found": "Új verzió található. Töltse újra az oldalt a frissítéshez.",
|
||||||
"open_in_hoppscotch": "Megnyitás Hoppscotch-ban.",
|
"open_in_hoppscotch": "Open in Hoppscotch",
|
||||||
"options": "Beállítások",
|
"options": "Beállítások",
|
||||||
"proxy_privacy_policy": "Proxy adatvédelmi irányelvei",
|
"proxy_privacy_policy": "Proxy adatvédelmi irányelvei",
|
||||||
"reload": "Újratöltés",
|
"reload": "Újratöltés",
|
||||||
"search": "Keresés",
|
"search": "Keresés",
|
||||||
"share": "Megosztás",
|
"share": "Megosztás",
|
||||||
"shortcuts": "Gyorsbillentyűk",
|
"shortcuts": "Gyorsbillentyűk",
|
||||||
"social_description": "Kövess minket a közösségi médiában, hogy ne maradj le a hírekről, frissítésekről és új kiadásokról.",
|
"social_description": "Follow us on social media to stay updated with the latest news, updates and releases.",
|
||||||
"social_links": "Közösségi média linkek",
|
"social_links": "Social links",
|
||||||
"spotlight": "Reflektorfény",
|
"spotlight": "Reflektorfény",
|
||||||
"status": "Állapot",
|
"status": "Állapot",
|
||||||
"status_description": "A weboldal állapotának ellenőrzése",
|
"status_description": "A weboldal állapotának ellenőrzése",
|
||||||
@@ -119,27 +119,27 @@
|
|||||||
},
|
},
|
||||||
"authorization": {
|
"authorization": {
|
||||||
"generate_token": "Token előállítása",
|
"generate_token": "Token előállítása",
|
||||||
"graphql_headers": "Azonosító fejléc connection_init tartalmaként elküldve",
|
"graphql_headers": "Authorization Headers are sent as part of the payload to connection_init",
|
||||||
"include_in_url": "Felvétel az URL-be",
|
"include_in_url": "Felvétel az URL-be",
|
||||||
"inherited_from": "Örökölt a(z) {auth}-tól, a(z) {collection} gyűjteményből ",
|
"inherited_from": "Inherited from {auth} from Parent Collection {collection} ",
|
||||||
"learn": "Tudja meg, hogyan",
|
"learn": "Tudja meg, hogyan",
|
||||||
"oauth": {
|
"oauth": {
|
||||||
"redirect_auth_server_returned_error": "Az Auth szerver hibás állapottal tért vissza",
|
"redirect_auth_server_returned_error": "Auth Server returned an error state",
|
||||||
"redirect_auth_token_request_failed": "Kérés az auth token lekéréséhez sikertelen",
|
"redirect_auth_token_request_failed": "Request to get the auth token failed",
|
||||||
"redirect_auth_token_request_invalid_response": "Érvénytelen válasz a Token Endpoint-tól, az auth token lekérésekpr",
|
"redirect_auth_token_request_invalid_response": "Invalid Response from the Token Endpoint when requesting for an auth token",
|
||||||
"redirect_invalid_state": "Érvénytelen állapotérték az átirányításban",
|
"redirect_invalid_state": "Invalid State value present in the redirect",
|
||||||
"redirect_no_auth_code": "Nincs azonosítás az átirányításban",
|
"redirect_no_auth_code": "No Authorization Code present in the redirect",
|
||||||
"redirect_no_client_id": "Nincs felhasználó azonosító",
|
"redirect_no_client_id": "No Client ID defined",
|
||||||
"redirect_no_client_secret": "Nincs felhasználó jelszó",
|
"redirect_no_client_secret": "No Client Secret Defined",
|
||||||
"redirect_no_code_verifier": "Nincs kódellenőrző",
|
"redirect_no_code_verifier": "No Code Verifier Defined",
|
||||||
"redirect_no_token_endpoint": "Nincs \"Token Endpoint\"",
|
"redirect_no_token_endpoint": "No Token Endpoint Defined",
|
||||||
"something_went_wrong_on_oauth_redirect": "Valami rosszul sikerült az OAuth átirányításakor",
|
"something_went_wrong_on_oauth_redirect": "Something went wrong during OAuth Redirect",
|
||||||
"something_went_wrong_on_token_generation": "Valami rosszul sikerült a token generálásakor",
|
"something_went_wrong_on_token_generation": "Something went wrong on token generation",
|
||||||
"token_generation_oidc_discovery_failed": "Hiba a token generálásakor: OpenID Connect Discovery hiba"
|
"token_generation_oidc_discovery_failed": "Failure on token generation: OpenID Connect Discovery Failed"
|
||||||
},
|
},
|
||||||
"pass_key_by": "Átadta",
|
"pass_key_by": "Átadta",
|
||||||
"password": "Jelszó",
|
"password": "Jelszó",
|
||||||
"save_to_inherit": "Kérjük, mentse el ezt kérést bármelyik gyűjteménybe, hogy az azonosítás örökölhető lehessen",
|
"save_to_inherit": "Please save this request in any collection to inherit the authorization",
|
||||||
"token": "Token",
|
"token": "Token",
|
||||||
"type": "Felhatalmazás típusa",
|
"type": "Felhatalmazás típusa",
|
||||||
"username": "Felhasználónév"
|
"username": "Felhasználónév"
|
||||||
@@ -148,7 +148,7 @@
|
|||||||
"created": "Gyűjtemény létrehozva",
|
"created": "Gyűjtemény létrehozva",
|
||||||
"different_parent": "Nem lehet átrendezni a különböző szülővel rendelkező gyűjteményt",
|
"different_parent": "Nem lehet átrendezni a különböző szülővel rendelkező gyűjteményt",
|
||||||
"edit": "Gyűjtemény szerkesztése",
|
"edit": "Gyűjtemény szerkesztése",
|
||||||
"import_or_create": "Gyűjtemény importálása vagy létrehozása",
|
"import_or_create": "Import or create a collection",
|
||||||
"invalid_name": "Adjon nevet a gyűjteménynek",
|
"invalid_name": "Adjon nevet a gyűjteménynek",
|
||||||
"invalid_root_move": "A gyűjtemény már a gyökérben van",
|
"invalid_root_move": "A gyűjtemény már a gyökérben van",
|
||||||
"moved": "Sikeresen áthelyezve",
|
"moved": "Sikeresen áthelyezve",
|
||||||
@@ -157,20 +157,20 @@
|
|||||||
"name_length_insufficient": "A gyűjtemény nevének legalább 3 karakter hosszúságúnak kell lennie",
|
"name_length_insufficient": "A gyűjtemény nevének legalább 3 karakter hosszúságúnak kell lennie",
|
||||||
"new": "Új gyűjtemény",
|
"new": "Új gyűjtemény",
|
||||||
"order_changed": "Gyűjtemény sorrendje frissítve",
|
"order_changed": "Gyűjtemény sorrendje frissítve",
|
||||||
"properties": "Gyűjtemény tulajdonságok",
|
"properties": "Collection Properties",
|
||||||
"properties_updated": "Gyűjtemény tulajdonságai frissítve",
|
"properties_updated": "Collection Properties Updated",
|
||||||
"renamed": "Gyűjtemény átnevezve",
|
"renamed": "Gyűjtemény átnevezve",
|
||||||
"request_in_use": "A kérés használatban",
|
"request_in_use": "A kérés használatban",
|
||||||
"save_as": "Mentés másként",
|
"save_as": "Mentés másként",
|
||||||
"save_to_collection": "Mentés egy gyűjteménybe",
|
"save_to_collection": "Save to Collection",
|
||||||
"select": "Gyűjtemény kiválasztása",
|
"select": "Gyűjtemény kiválasztása",
|
||||||
"select_location": "Hely kiválasztása",
|
"select_location": "Hely kiválasztása",
|
||||||
"select_team": "Csapat kiválasztása",
|
"select_team": "Csapat kiválasztása",
|
||||||
"team_collections": "Csapat gyűjteményei"
|
"team_collections": "Csapat gyűjteményei"
|
||||||
},
|
},
|
||||||
"confirm": {
|
"confirm": {
|
||||||
"close_unsaved_tab": "Biztos, hogy bezárja ezt a lapot?",
|
"close_unsaved_tab": "Are you sure you want to close this tab?",
|
||||||
"close_unsaved_tabs": "Biztos, hogy bezárja az összes lapot? {count} elmentetlen lap el fog veszni.",
|
"close_unsaved_tabs": "Are you sure you want to close all tabs? {count} unsaved tabs will be lost.",
|
||||||
"exit_team": "Biztosan el szeretné hagyni ezt a csapatot?",
|
"exit_team": "Biztosan el szeretné hagyni ezt a csapatot?",
|
||||||
"logout": "Biztosan ki szeretne jelentkezni?",
|
"logout": "Biztosan ki szeretne jelentkezni?",
|
||||||
"remove_collection": "Biztosan véglegesen törölni szeretné ezt a gyűjteményt?",
|
"remove_collection": "Biztosan véglegesen törölni szeretné ezt a gyűjteményt?",
|
||||||
@@ -178,7 +178,7 @@
|
|||||||
"remove_folder": "Biztosan véglegesen törölni szeretné ezt a mappát?",
|
"remove_folder": "Biztosan véglegesen törölni szeretné ezt a mappát?",
|
||||||
"remove_history": "Biztosan véglegesen törölni szeretné az összes előzményt?",
|
"remove_history": "Biztosan véglegesen törölni szeretné az összes előzményt?",
|
||||||
"remove_request": "Biztosan véglegesen törölni szeretné ezt a kérést?",
|
"remove_request": "Biztosan véglegesen törölni szeretné ezt a kérést?",
|
||||||
"remove_shared_request": "Biztos, hogy véglegesen törölni szeretné ezt a megosztott kérést?",
|
"remove_shared_request": "Are you sure you want to permanently delete this shared request?",
|
||||||
"remove_team": "Biztosan törölni szeretné ezt a csapatot?",
|
"remove_team": "Biztosan törölni szeretné ezt a csapatot?",
|
||||||
"remove_telemetry": "Biztosan ki szeretné kapcsolni a telemetriát?",
|
"remove_telemetry": "Biztosan ki szeretné kapcsolni a telemetriát?",
|
||||||
"request_change": "Biztosan el szeretné vetni a jelenlegi kérést? Minden mentetlen változtatás el fog veszni.",
|
"request_change": "Biztosan el szeretné vetni a jelenlegi kérést? Minden mentetlen változtatás el fog veszni.",
|
||||||
@@ -186,26 +186,26 @@
|
|||||||
"sync": "Szeretné visszaállítani a munkaterületét a felhőből? Ez el fogja vetni a helyi folyamatát."
|
"sync": "Szeretné visszaállítani a munkaterületét a felhőből? Ez el fogja vetni a helyi folyamatát."
|
||||||
},
|
},
|
||||||
"context_menu": {
|
"context_menu": {
|
||||||
"add_parameters": "Paraméterek hozzáadása",
|
"add_parameters": "Add to parameters",
|
||||||
"open_request_in_new_tab": "Kérés megnyitása új lapot",
|
"open_request_in_new_tab": "Open request in new tab",
|
||||||
"set_environment_variable": "Változóként való beállítás"
|
"set_environment_variable": "Set as variable"
|
||||||
},
|
},
|
||||||
"cookies": {
|
"cookies": {
|
||||||
"modal": {
|
"modal": {
|
||||||
"cookie_expires": "Lejárat",
|
"cookie_expires": "Expires",
|
||||||
"cookie_name": "Név",
|
"cookie_name": "Name",
|
||||||
"cookie_path": "Útvonal",
|
"cookie_path": "Path",
|
||||||
"cookie_string": "Süti szöveg",
|
"cookie_string": "Cookie string",
|
||||||
"cookie_value": "Érték",
|
"cookie_value": "Value",
|
||||||
"empty_domain": "Üres domain",
|
"empty_domain": "Domain is empty",
|
||||||
"empty_domains": "Domain lista üres",
|
"empty_domains": "Domain list is empty",
|
||||||
"enter_cookie_string": "Süti szövegének megadása",
|
"enter_cookie_string": "Enter cookie string",
|
||||||
"interceptor_no_support": "A kiválasztott interceptor nem támogatja a sütiket. Válasszon ki egy másik interceptor-t és próbálja újra.",
|
"interceptor_no_support": "Your currently selected interceptor does not support cookies. Select a different Interceptor and try again.",
|
||||||
"managed_tab": "Menedzselt",
|
"managed_tab": "Managed",
|
||||||
"new_domain_name": "Új domain neve",
|
"new_domain_name": "New domain name",
|
||||||
"no_cookies_in_domain": "Nincs süti beállítva ehhez a domainhez.",
|
"no_cookies_in_domain": "No cookies set for this domain",
|
||||||
"raw_tab": "Nyers",
|
"raw_tab": "Raw",
|
||||||
"set": "Süti beállítása"
|
"set": "Set a cookie"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"count": {
|
"count": {
|
||||||
@@ -221,7 +221,7 @@
|
|||||||
"generate_message": "Importáljon bármilyen Hoppscotch-gyűjteményt, hogy API-dokumentációt készítsen a folyamat során."
|
"generate_message": "Importáljon bármilyen Hoppscotch-gyűjteményt, hogy API-dokumentációt készítsen a folyamat során."
|
||||||
},
|
},
|
||||||
"empty": {
|
"empty": {
|
||||||
"authorization": "Ez a kérés nem használ azonosítást",
|
"authorization": "Ez a kérés nem használ felhatalmazást",
|
||||||
"body": "Ennek a kérésnek nincs törzse",
|
"body": "Ennek a kérésnek nincs törzse",
|
||||||
"collection": "A gyűjtemény üres",
|
"collection": "A gyűjtemény üres",
|
||||||
"collections": "A gyűjtemények üresek",
|
"collections": "A gyűjtemények üresek",
|
||||||
@@ -252,39 +252,39 @@
|
|||||||
"create_new": "Új környezet létrehozása",
|
"create_new": "Új környezet létrehozása",
|
||||||
"created": "Környezet létrehozva",
|
"created": "Környezet létrehozva",
|
||||||
"deleted": "Környezet törlése",
|
"deleted": "Környezet törlése",
|
||||||
"duplicated": "Környezet duplikálása",
|
"duplicated": "Environment duplicated",
|
||||||
"edit": "Környezet szerkesztése",
|
"edit": "Környezet szerkesztése",
|
||||||
"empty_variables": "Nincs változó",
|
"empty_variables": "No variables",
|
||||||
"global": "Globális",
|
"global": "Global",
|
||||||
"global_variables": "Globális változók",
|
"global_variables": "Global variables",
|
||||||
"import_or_create": "Környezet importálása vagy létrehozása",
|
"import_or_create": "Import or create a environment",
|
||||||
"invalid_name": "Adjon nevet a környezetnek",
|
"invalid_name": "Adjon nevet a környezetnek",
|
||||||
"list": "Környezeti változók",
|
"list": "Environment variables",
|
||||||
"my_environments": "Saját környezetek",
|
"my_environments": "Saját környezetek",
|
||||||
"name": "Név",
|
"name": "Name",
|
||||||
"nested_overflow": "az egymásba ágyazott környezeti változók 10 szintre vannak korlátozva",
|
"nested_overflow": "az egymásba ágyazott környezeti változók 10 szintre vannak korlátozva",
|
||||||
"new": "Új környezet",
|
"new": "Új környezet",
|
||||||
"no_active_environment": "Nincs aktív környezet",
|
"no_active_environment": "No active environment",
|
||||||
"no_environment": "Nincs környezet",
|
"no_environment": "Nincs környezet",
|
||||||
"no_environment_description": "Nem lettek környezetek kiválasztva. Válassza ki, hogy mit kell tenni a következő változókkal.",
|
"no_environment_description": "Nem lettek környezetek kiválasztva. Válassza ki, hogy mit kell tenni a következő változókkal.",
|
||||||
"quick_peek": "Környezet gyors megnézése",
|
"quick_peek": "Environment Quick Peek",
|
||||||
"replace_with_variable": "Cserélje le egy változóra",
|
"replace_with_variable": "Replace with variable",
|
||||||
"scope": "Hatókör",
|
"scope": "Scope",
|
||||||
"select": "Környezet kiválasztása",
|
"select": "Környezet kiválasztása",
|
||||||
"set": "Környezet beállítása",
|
"set": "Set environment",
|
||||||
"set_as_environment": "Környezetként való beállítás",
|
"set_as_environment": "Set as environment",
|
||||||
"team_environments": "Csapatkörnyezetek",
|
"team_environments": "Csapatkörnyezetek",
|
||||||
"title": "Környezetek",
|
"title": "Környezetek",
|
||||||
"updated": "Környezet frissítve",
|
"updated": "Környezet frissítve",
|
||||||
"value": "Érték",
|
"value": "Value",
|
||||||
"variable": "Változó",
|
"variable": "Variable",
|
||||||
"variable_list": "Változólista"
|
"variable_list": "Változólista"
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
"authproviders_load_error": "Nem sikerült betölteni az azonosító szolgáltatókat",
|
"authproviders_load_error": "Unable to load auth providers",
|
||||||
"browser_support_sse": "Úgy tűnik, hogy ez a böngésző nem támogatja a kiszolgáló által küldött eseményeket.",
|
"browser_support_sse": "Úgy tűnik, hogy ez a böngésző nem támogatja a kiszolgáló által küldött eseményeket.",
|
||||||
"check_console_details": "Nézze meg a konzolnaplót a részletekért.",
|
"check_console_details": "Nézze meg a konzolnaplót a részletekért.",
|
||||||
"check_how_to_add_origin": "Ellenőrizze, hogy hogyan adhat hozzá forrást",
|
"check_how_to_add_origin": "Check how you can add an origin",
|
||||||
"curl_invalid_format": "A cURL nincs megfelelően formázva",
|
"curl_invalid_format": "A cURL nincs megfelelően formázva",
|
||||||
"danger_zone": "Veszélyes zóna",
|
"danger_zone": "Veszélyes zóna",
|
||||||
"delete_account": "Az Ön fiókja jelenleg tulajdonos ezekben a csapatokban:",
|
"delete_account": "Az Ön fiókja jelenleg tulajdonos ezekben a csapatokban:",
|
||||||
@@ -300,13 +300,13 @@
|
|||||||
"json_prettify_invalid_body": "Nem sikerült csinosítani egy érvénytelen törzset, oldja meg a JSON szintaktikai hibáit, és próbálja újra",
|
"json_prettify_invalid_body": "Nem sikerült csinosítani egy érvénytelen törzset, oldja meg a JSON szintaktikai hibáit, és próbálja újra",
|
||||||
"network_error": "Úgy tűnik, hogy hálózati hiba van. Próbálja újra.",
|
"network_error": "Úgy tűnik, hogy hálózati hiba van. Próbálja újra.",
|
||||||
"network_fail": "Nem sikerült elküldeni a kérést",
|
"network_fail": "Nem sikerült elküldeni a kérést",
|
||||||
"no_collections_to_export": "Nincs exportálható gyűjtemény. Kérjük, hozzon létre egyet, hogy elkezdhesse.",
|
"no_collections_to_export": "No collections to export. Please create a collection to get started.",
|
||||||
"no_duration": "Nincs időtartam",
|
"no_duration": "Nincs időtartam",
|
||||||
"no_environments_to_export": "Nincs exportálható környezet. Kérjük, hozzon létre egyet, hogy elkezdhesse.",
|
"no_environments_to_export": "No environments to export. Please create an environment to get started.",
|
||||||
"no_results_found": "Nincs találat",
|
"no_results_found": "Nincs találat",
|
||||||
"page_not_found": "Ez az oldal nem található",
|
"page_not_found": "Ez az oldal nem található",
|
||||||
"please_install_extension": "Kérjük telepítse a bővítményt és adja hozzá a forráshoz.",
|
"please_install_extension": "Please install the extension and add origin to the extension.",
|
||||||
"proxy_error": "Proxy hiba",
|
"proxy_error": "Proxy error",
|
||||||
"script_fail": "Nem sikerült végrehajtani a kérés előtti parancsfájlt",
|
"script_fail": "Nem sikerült végrehajtani a kérés előtti parancsfájlt",
|
||||||
"something_went_wrong": "Valami elromlott",
|
"something_went_wrong": "Valami elromlott",
|
||||||
"test_script_fail": "Nem sikerült végrehajtani a kérés utáni parancsfájlt"
|
"test_script_fail": "Nem sikerült végrehajtani a kérés utáni parancsfájlt"
|
||||||
@@ -314,7 +314,7 @@
|
|||||||
"export": {
|
"export": {
|
||||||
"as_json": "Exportálás JSON formátumban",
|
"as_json": "Exportálás JSON formátumban",
|
||||||
"create_secret_gist": "Titkos Gist létrehozása",
|
"create_secret_gist": "Titkos Gist létrehozása",
|
||||||
"failed": "Valami hiba történt az exportálás közben",
|
"failed": "Something went wrong while exporting",
|
||||||
"gist_created": "Gist létrehozva",
|
"gist_created": "Gist létrehozva",
|
||||||
"require_github": "Jelentkezzen be GitHub használatával a titkos Gist létrehozásához",
|
"require_github": "Jelentkezzen be GitHub használatával a titkos Gist létrehozásához",
|
||||||
"title": "Exportálás"
|
"title": "Exportálás"
|
||||||
@@ -333,16 +333,16 @@
|
|||||||
"renamed": "Mappa átnevezve"
|
"renamed": "Mappa átnevezve"
|
||||||
},
|
},
|
||||||
"graphql": {
|
"graphql": {
|
||||||
"connection_switch_confirm": "Szeretne csatlakozni a legújabb GraphQL végponttal?",
|
"connection_switch_confirm": "Do you want to connect with the latest GraphQL endpoint?",
|
||||||
"connection_switch_new_url": "A tab váltása lecsatlakoztatta az aktív GraphQL kapcsolatról. Az új kapcsolat",
|
"connection_switch_new_url": "Switching to a tab will disconnected you from the active GraphQL connection. New connection URL is",
|
||||||
"connection_switch_url": "Kapcsolódott a GraphQL végponthoz. A kapcsolat",
|
"connection_switch_url": "You're connected to a GraphQL endpoint the connection URL is",
|
||||||
"mutations": "Mutációk",
|
"mutations": "Mutációk",
|
||||||
"schema": "Séma",
|
"schema": "Séma",
|
||||||
"subscriptions": "Feliratkozások",
|
"subscriptions": "Feliratkozások",
|
||||||
"switch_connection": "Kapcsolat váltása"
|
"switch_connection": "Switch connection"
|
||||||
},
|
},
|
||||||
"graphql_collections": {
|
"graphql_collections": {
|
||||||
"title": "GraphQL gyűjtemény"
|
"title": "GraphQL Collections"
|
||||||
},
|
},
|
||||||
"group": {
|
"group": {
|
||||||
"time": "Idő",
|
"time": "Idő",
|
||||||
@@ -354,9 +354,9 @@
|
|||||||
"save_workspace": "Saját munkaterület mentése"
|
"save_workspace": "Saját munkaterület mentése"
|
||||||
},
|
},
|
||||||
"helpers": {
|
"helpers": {
|
||||||
"authorization": "Az Azonosítás fejléc automatikusan elő lesz állítva a kérés elküldésekor.",
|
"authorization": "A felhatalmazási fejléc automatikusan elő lesz állítva a kérés elküldésekor.",
|
||||||
"collection_properties_authorization": " Ez az azonosítás be lesz állítva minden kéréshez ebben a gyűjteményben.",
|
"collection_properties_authorization": " This authorization will be set for every request in this collection.",
|
||||||
"collection_properties_header": "Ez a fejléc be lesz állítva mint minden kéréshez ebben a gyűjteményben.",
|
"collection_properties_header": "This header will be set for every request in this collection.",
|
||||||
"generate_documentation_first": "Először állítsa elő a dokumentációt",
|
"generate_documentation_first": "Először állítsa elő a dokumentációt",
|
||||||
"network_fail": "Nem lehet elérni az API-végpontot. Ellenőrizze a hálózati kapcsolatot vagy válasszon egy másik elfogót, és próbálja újra.",
|
"network_fail": "Nem lehet elérni az API-végpontot. Ellenőrizze a hálózati kapcsolatot vagy válasszon egy másik elfogót, és próbálja újra.",
|
||||||
"offline": "Úgy tűnik, hogy kapcsolat nélküli módban van. Előfordulhat, hogy a munkaterületen lévő adatok nem naprakészek.",
|
"offline": "Úgy tűnik, hogy kapcsolat nélküli módban van. Előfordulhat, hogy a munkaterületen lévő adatok nem naprakészek.",
|
||||||
@@ -376,11 +376,11 @@
|
|||||||
"import": {
|
"import": {
|
||||||
"collections": "Gyűjtemények importálása",
|
"collections": "Gyűjtemények importálása",
|
||||||
"curl": "cURL importálása",
|
"curl": "cURL importálása",
|
||||||
"environments_from_gist": "Importálás Gist-ből",
|
"environments_from_gist": "Import From Gist",
|
||||||
"environments_from_gist_description": "Hoppscotch környezetek importálása Gist-ből",
|
"environments_from_gist_description": "Import Hoppscotch Environments From Gist",
|
||||||
"failed": "Hiba az importálás során: a formátum nem azonosítható",
|
"failed": "Hiba az importálás során: a formátum nem azonosítható",
|
||||||
"from_file": "Importálás fájlból",
|
"from_file": "Import from File",
|
||||||
"from_gist": "Importálás Gist-ből",
|
"from_gist": "Importálás Gistből",
|
||||||
"from_gist_description": "Importálás Gist URL-ből",
|
"from_gist_description": "Importálás Gist URL-ből",
|
||||||
"from_insomnia": "Importálás Insomniából",
|
"from_insomnia": "Importálás Insomniából",
|
||||||
"from_insomnia_description": "Importálás Insomnia-gyűjteményből",
|
"from_insomnia_description": "Importálás Insomnia-gyűjteményből",
|
||||||
@@ -390,45 +390,45 @@
|
|||||||
"from_my_collections_description": "Importálás saját gyűjtemények fájlból",
|
"from_my_collections_description": "Importálás saját gyűjtemények fájlból",
|
||||||
"from_openapi": "Importálás OpenAPI-ból",
|
"from_openapi": "Importálás OpenAPI-ból",
|
||||||
"from_openapi_description": "Importálás OpenAPI specifikációs fájlból (YML/JSON)",
|
"from_openapi_description": "Importálás OpenAPI specifikációs fájlból (YML/JSON)",
|
||||||
"from_postman": "Importálás Postman-ből",
|
"from_postman": "Importálás Postmanből",
|
||||||
"from_postman_description": "Importálás Postman-gyűjteményből",
|
"from_postman_description": "Importálás Postman-gyűjteményből",
|
||||||
"from_url": "Importálás URL-ből",
|
"from_url": "Importálás URL-ből",
|
||||||
"gist_url": "Gist URL megadása",
|
"gist_url": "Gist URL megadása",
|
||||||
"gql_collections_from_gist_description": "GraphQL gyűjtemények importálása Gist-ből",
|
"gql_collections_from_gist_description": "Import GraphQL Collections From Gist",
|
||||||
"hoppscotch_environment": "Hoppscotch környezet",
|
"hoppscotch_environment": "Hoppscotch Environment",
|
||||||
"hoppscotch_environment_description": "Hoppscotch környezet importálása JSON fájlból",
|
"hoppscotch_environment_description": "Import Hoppscotch Environment JSON file",
|
||||||
"import_from_url_invalid_fetch": "Nem sikerült lekérni az adatokat az URL-ről",
|
"import_from_url_invalid_fetch": "Nem sikerült lekérni az adatokat az URL-ről",
|
||||||
"import_from_url_invalid_file_format": "Hiba a gyűjtemények importálása során",
|
"import_from_url_invalid_file_format": "Hiba a gyűjtemények importálása során",
|
||||||
"import_from_url_invalid_type": "Nem támogatott típus. Az elfogadott értékek: „hoppscotch”, „openapi”, „postman” vagy „insomnia”.",
|
"import_from_url_invalid_type": "Nem támogatott típus. Az elfogadott értékek: „hoppscotch”, „openapi”, „postman” vagy „insomnia”.",
|
||||||
"import_from_url_success": "Gyűjtemények importálva",
|
"import_from_url_success": "Gyűjtemények importálva",
|
||||||
"insomnia_environment_description": "Insomnia környezet importálása JSON/YAML fájlból",
|
"insomnia_environment_description": "Import Insomnia Environment from a JSON/YAML file",
|
||||||
"json_description": "Gyűjtemények importálása Hoppscotch-gyűjtemények JSON-fájlból",
|
"json_description": "Gyűjtemények importálása Hoppscotch-gyűjtemények JSON-fájlból",
|
||||||
"postman_environment": "Postman környezet",
|
"postman_environment": "Postman Environment",
|
||||||
"postman_environment_description": "Postman környezet importálása JSON fájlból",
|
"postman_environment_description": "Import Postman Environment from a JSON file",
|
||||||
"title": "Importálás"
|
"title": "Importálás"
|
||||||
},
|
},
|
||||||
"inspections": {
|
"inspections": {
|
||||||
"description": "Lehetséges hibák ellenőrzése",
|
"description": "Inspect possible errors",
|
||||||
"environment": {
|
"environment": {
|
||||||
"add_environment": "Hozzáadás a környezethez",
|
"add_environment": "Add to Environment",
|
||||||
"not_found": "\"{environment}\" környezet nem található."
|
"not_found": "Environment variable “{environment}” not found."
|
||||||
},
|
},
|
||||||
"header": {
|
"header": {
|
||||||
"cookie": "A böngésző nem engedélyezi a Hoppscotch-nak, hogy süti fejlécet állítson be. Amíg dolgozunk a Hoppscotch asztali alkalmazáson (hamarosan), kérjük használjon Authorization Header fejlécet."
|
"cookie": "The browser doesn't allow Hoppscotch to set the Cookie Header. While we're working on the Hoppscotch Desktop App (coming soon), please use the Authorization Header instead."
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"401_error": "Kérjük ellenőrizze az autentikációs adatokat.",
|
"401_error": "Please check your authentication credentials.",
|
||||||
"404_error": "Kérjük ellenőrizze a kérés URL-jét és típusát.",
|
"404_error": "Please check your request URL and method type.",
|
||||||
"cors_error": "Kérjük ellenőrizze a Cross-Origin Resource Sharing beállítást.",
|
"cors_error": "Please check your Cross-Origin Resource Sharing configuration.",
|
||||||
"default_error": "Kérjük ellenőrizze a kérését.",
|
"default_error": "Please check your request.",
|
||||||
"network_error": "Kérjük ellenőrizze a internet elérhetőségét."
|
"network_error": "Please check your network connection."
|
||||||
},
|
},
|
||||||
"title": "Inspector",
|
"title": "Inspector",
|
||||||
"url": {
|
"url": {
|
||||||
"extension_not_installed": "Bővítmény nincs telepítve.",
|
"extension_not_installed": "Extension not installed.",
|
||||||
"extension_unknown_origin": "Ellenőrizze, hogy hozzáadta az API végpont forrását Hoppscotch Browser bővítmény listájához.",
|
"extension_unknown_origin": "Make sure you've added the API endpoint's origin to the Hoppscotch Browser Extension list.",
|
||||||
"extention_enable_action": "Bővítmény engedélyezése",
|
"extention_enable_action": "Enable Browser Extension",
|
||||||
"extention_not_enabled": "Bővítmény nincs engedélyezve."
|
"extention_not_enabled": "Extension not enabled."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"layout": {
|
"layout": {
|
||||||
@@ -442,10 +442,10 @@
|
|||||||
"close_unsaved_tab": "Elmentetlen változtatásai vannak",
|
"close_unsaved_tab": "Elmentetlen változtatásai vannak",
|
||||||
"collections": "Gyűjtemények",
|
"collections": "Gyűjtemények",
|
||||||
"confirm": "Megerősítés",
|
"confirm": "Megerősítés",
|
||||||
"customize_request": "Kérés testreszabása",
|
"customize_request": "Customize Request",
|
||||||
"edit_request": "Kérés szerkesztése",
|
"edit_request": "Kérés szerkesztése",
|
||||||
"import_export": "Importálás és exportálás",
|
"import_export": "Importálás és exportálás",
|
||||||
"share_request": "Kérés megosztása"
|
"share_request": "Share Request"
|
||||||
},
|
},
|
||||||
"mqtt": {
|
"mqtt": {
|
||||||
"already_subscribed": "Ön már feliratkozott erre a témára.",
|
"already_subscribed": "Ön már feliratkozott erre a témára.",
|
||||||
@@ -511,7 +511,7 @@
|
|||||||
},
|
},
|
||||||
"request": {
|
"request": {
|
||||||
"added": "Kérés hozzáadva",
|
"added": "Kérés hozzáadva",
|
||||||
"authorization": "Azonosítás",
|
"authorization": "Felhatalmazás",
|
||||||
"body": "Kérés törzse",
|
"body": "Kérés törzse",
|
||||||
"choose_language": "Nyelv kiválasztása",
|
"choose_language": "Nyelv kiválasztása",
|
||||||
"content_type": "Tartalom típusa",
|
"content_type": "Tartalom típusa",
|
||||||
@@ -526,8 +526,8 @@
|
|||||||
"enter_curl": "cURL-parancs megadása",
|
"enter_curl": "cURL-parancs megadása",
|
||||||
"generate_code": "Kód előállítása",
|
"generate_code": "Kód előállítása",
|
||||||
"generated_code": "Előállított kód",
|
"generated_code": "Előállított kód",
|
||||||
"go_to_authorization_tab": "Navigálás az Azonosítás lapra",
|
"go_to_authorization_tab": "Go to Authorization tab",
|
||||||
"go_to_body_tab": "Navigálás a Törzs lapra.",
|
"go_to_body_tab": "Go to Body tab",
|
||||||
"header_list": "Fejléclista",
|
"header_list": "Fejléclista",
|
||||||
"invalid_name": "Adjon nevet a kérésnek",
|
"invalid_name": "Adjon nevet a kérésnek",
|
||||||
"method": "Módszer",
|
"method": "Módszer",
|
||||||
@@ -552,8 +552,8 @@
|
|||||||
"saved": "Kérés elmentve",
|
"saved": "Kérés elmentve",
|
||||||
"share": "Megosztás",
|
"share": "Megosztás",
|
||||||
"share_description": "A Hoppscotch megosztása az ismerőseivel",
|
"share_description": "A Hoppscotch megosztása az ismerőseivel",
|
||||||
"share_request": "Kérés megosztása",
|
"share_request": "Share Request",
|
||||||
"stop": "Leállítás",
|
"stop": "Stop",
|
||||||
"title": "Kérés",
|
"title": "Kérés",
|
||||||
"type": "Kérés típusa",
|
"type": "Kérés típusa",
|
||||||
"url": "URL",
|
"url": "URL",
|
||||||
@@ -587,7 +587,7 @@
|
|||||||
"account_description": "A fiókbeállítások személyre szabása.",
|
"account_description": "A fiókbeállítások személyre szabása.",
|
||||||
"account_email_description": "Az Ön elsődleges e-mail-címe.",
|
"account_email_description": "Az Ön elsődleges e-mail-címe.",
|
||||||
"account_name_description": "Ez a megjelenített neve.",
|
"account_name_description": "Ez a megjelenített neve.",
|
||||||
"additional": "További beállítások",
|
"additional": "Additional Settings",
|
||||||
"background": "Háttér",
|
"background": "Háttér",
|
||||||
"black_mode": "Fekete",
|
"black_mode": "Fekete",
|
||||||
"choose_language": "Nyelv kiválasztása",
|
"choose_language": "Nyelv kiválasztása",
|
||||||
@@ -635,29 +635,29 @@
|
|||||||
"verify_email": "E-mail-cím ellenőrzése"
|
"verify_email": "E-mail-cím ellenőrzése"
|
||||||
},
|
},
|
||||||
"shared_requests": {
|
"shared_requests": {
|
||||||
"button": "Gomb",
|
"button": "Button",
|
||||||
"button_info": "Hozza létre a 'Futtatás Hoppscotch-ban' gombot a weboldalán vagy blogján.",
|
"button_info": "Create a 'Run in Hoppscotch' button for your website, blog or a README.",
|
||||||
"copy_html": "HTML másolása",
|
"copy_html": "Copy HTML",
|
||||||
"copy_link": "Link másolása",
|
"copy_link": "Copy Link",
|
||||||
"copy_markdown": "Jelölő másolása",
|
"copy_markdown": "Copy Markdown",
|
||||||
"creating_widget": "Widget létrehozása",
|
"creating_widget": "Creating widget",
|
||||||
"customize": "Testreszabás",
|
"customize": "Customize",
|
||||||
"deleted": "Megosztott kérés törölve",
|
"deleted": "Shared request deleted",
|
||||||
"description": "Válasszon ki egy widgetet, ezt később módosíthatja és testreszabhatja",
|
"description": "Select a widget, you can change and customize this later",
|
||||||
"embed": "Beágyazás",
|
"embed": "Embed",
|
||||||
"embed_info": "Adja hozzá a \"Hoppscotch API Playground\"-ot weboldalához vagy blogjához.",
|
"embed_info": "Add a mini 'Hoppscotch API Playground' to your website, blog or documentation.",
|
||||||
"link": "Link",
|
"link": "Link",
|
||||||
"link_info": "Link létrehozása olvasási joggal való megosztáshoz.",
|
"link_info": "Create a shareable link to share with anyone on the internet with view access.",
|
||||||
"modified": "Megosztott kérés módosítva",
|
"modified": "Shared request modified",
|
||||||
"not_found": "Megosztott kérés nem található.",
|
"not_found": "Shared request not found",
|
||||||
"open_new_tab": "Megnyitás új lapon.",
|
"open_new_tab": "Open in new tab",
|
||||||
"preview": "Előnézet",
|
"preview": "Preview",
|
||||||
"run_in_hoppscotch": "Futtatás Hoppscotch-ban.",
|
"run_in_hoppscotch": "Run in Hoppscotch",
|
||||||
"theme": {
|
"theme": {
|
||||||
"dark": "Sötét",
|
"dark": "Dark",
|
||||||
"light": "Világos",
|
"light": "Light",
|
||||||
"system": "Rendszer",
|
"system": "System",
|
||||||
"title": "Téma"
|
"title": "Theme"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"shortcut": {
|
"shortcut": {
|
||||||
@@ -669,7 +669,7 @@
|
|||||||
"title": "Általános"
|
"title": "Általános"
|
||||||
},
|
},
|
||||||
"miscellaneous": {
|
"miscellaneous": {
|
||||||
"invite": "Emberek meghívása a Hoppscotch-ba",
|
"invite": "Emberek meghívása a Hoppscotchba",
|
||||||
"title": "Egyebek"
|
"title": "Egyebek"
|
||||||
},
|
},
|
||||||
"navigation": {
|
"navigation": {
|
||||||
@@ -691,19 +691,19 @@
|
|||||||
"delete_method": "DELETE módszer kiválasztása",
|
"delete_method": "DELETE módszer kiválasztása",
|
||||||
"get_method": "GET módszer kiválasztása",
|
"get_method": "GET módszer kiválasztása",
|
||||||
"head_method": "HEAD módszer kiválasztása",
|
"head_method": "HEAD módszer kiválasztása",
|
||||||
"import_curl": "cURL importálása",
|
"import_curl": "Import cURL",
|
||||||
"method": "Módszer",
|
"method": "Módszer",
|
||||||
"next_method": "Következő módszer kiválasztása",
|
"next_method": "Következő módszer kiválasztása",
|
||||||
"post_method": "POST módszer kiválasztása",
|
"post_method": "POST módszer kiválasztása",
|
||||||
"previous_method": "Előző módszer kiválasztása",
|
"previous_method": "Előző módszer kiválasztása",
|
||||||
"put_method": "PUT módszer kiválasztása",
|
"put_method": "PUT módszer kiválasztása",
|
||||||
"rename": "Kérés átnevezése",
|
"rename": "Rename Request",
|
||||||
"reset_request": "Kérés visszaállítása",
|
"reset_request": "Kérés visszaállítása",
|
||||||
"save_request": "Kérés mentése",
|
"save_request": "Save Request",
|
||||||
"save_to_collections": "Mentés a gyűjteményekbe",
|
"save_to_collections": "Mentés a gyűjteményekbe",
|
||||||
"send_request": "Kérés elküldése",
|
"send_request": "Kérés elküldése",
|
||||||
"share_request": "Kérés megosztása",
|
"share_request": "Share Request",
|
||||||
"show_code": "Kódrészlet generálása",
|
"show_code": "Generate code snippet",
|
||||||
"title": "Kérés",
|
"title": "Kérés",
|
||||||
"copy_request_link": "Kérés hivatkozásának másolása"
|
"copy_request_link": "Kérés hivatkozásának másolása"
|
||||||
},
|
},
|
||||||
@@ -735,82 +735,82 @@
|
|||||||
"url": "URL"
|
"url": "URL"
|
||||||
},
|
},
|
||||||
"spotlight": {
|
"spotlight": {
|
||||||
"change_language": "Nyelv váltása",
|
"change_language": "Change Language",
|
||||||
"environments": {
|
"environments": {
|
||||||
"delete": "Jelenlegi környezet törlése",
|
"delete": "Delete current environment",
|
||||||
"duplicate": "Jelenlegi környezet duplikálása",
|
"duplicate": "Duplicate current environment",
|
||||||
"duplicate_global": "Globális környezet duplikálása",
|
"duplicate_global": "Duplicate global environment",
|
||||||
"edit": "Jelenlegi környezet szerkesztése",
|
"edit": "Edit current environment",
|
||||||
"edit_global": "Globális környezet szerkesztése",
|
"edit_global": "Edit global environment",
|
||||||
"new": "Új környezet létrehozása",
|
"new": "Create new environment",
|
||||||
"new_variable": "Új környezeti változó létrehozása",
|
"new_variable": "Create a new environment variable",
|
||||||
"title": "Környezetek"
|
"title": "Environments"
|
||||||
},
|
},
|
||||||
"general": {
|
"general": {
|
||||||
"chat": "Üzenet a supportnak",
|
"chat": "Chat with support",
|
||||||
"help_menu": "Segítség és support",
|
"help_menu": "Help and support",
|
||||||
"open_docs": "Dokumentáció olvasása",
|
"open_docs": "Read Documentation",
|
||||||
"open_github": "GitHub repository megnyitása",
|
"open_github": "Open GitHub repository",
|
||||||
"open_keybindings": "Billentyűkombinációk megnyitása",
|
"open_keybindings": "Keyboard shortcuts",
|
||||||
"social": "Közösség",
|
"social": "Social",
|
||||||
"title": "Általános"
|
"title": "General"
|
||||||
},
|
},
|
||||||
"graphql": {
|
"graphql": {
|
||||||
"connect": "Csatlakozás a szerverhez",
|
"connect": "Connect to server",
|
||||||
"disconnect": "Lecsatlakozás a szerverről"
|
"disconnect": "Disconnect from server"
|
||||||
},
|
},
|
||||||
"miscellaneous": {
|
"miscellaneous": {
|
||||||
"invite": "Hívja meg barátait a Hoppscotch-ba",
|
"invite": "Invite your friends to Hoppscotch",
|
||||||
"title": "Egyéb"
|
"title": "Miscellaneous"
|
||||||
},
|
},
|
||||||
"request": {
|
"request": {
|
||||||
"save_as_new": "Mentés új kérésként",
|
"save_as_new": "Save as new request",
|
||||||
"select_method": "Módszer kiválasztása",
|
"select_method": "Select method",
|
||||||
"switch_to": "Váltás",
|
"switch_to": "Switch to",
|
||||||
"tab_authorization": "Azonosítás lap",
|
"tab_authorization": "Authorization tab",
|
||||||
"tab_body": "Törzs lap",
|
"tab_body": "Body tab",
|
||||||
"tab_headers": "Fejlécek lap",
|
"tab_headers": "Headers tab",
|
||||||
"tab_parameters": "Paraméterek lap",
|
"tab_parameters": "Parameters tab",
|
||||||
"tab_pre_request_script": "Előzetes script lap",
|
"tab_pre_request_script": "Pre-request script tab",
|
||||||
"tab_query": "Kérés lap",
|
"tab_query": "Query tab",
|
||||||
"tab_tests": "Tesztek lap",
|
"tab_tests": "Tests tab",
|
||||||
"tab_variables": "Változók lap"
|
"tab_variables": "Variables tab"
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"copy": "Válasz másolása",
|
"copy": "Copy response",
|
||||||
"download": "Válasz letöltése fájlként",
|
"download": "Download response as file",
|
||||||
"title": "Válasz"
|
"title": "Response"
|
||||||
},
|
},
|
||||||
"section": {
|
"section": {
|
||||||
"interceptor": "Interceptor",
|
"interceptor": "Interceptor",
|
||||||
"interface": "Interface",
|
"interface": "Interface",
|
||||||
"theme": "Téma",
|
"theme": "Theme",
|
||||||
"user": "Felhasználó"
|
"user": "User"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"change_interceptor": "Interceptor váltása",
|
"change_interceptor": "Change Interceptor",
|
||||||
"change_language": "Nyelv váltása",
|
"change_language": "Change Language",
|
||||||
"theme": {
|
"theme": {
|
||||||
"black": "Fekete",
|
"black": "Black",
|
||||||
"dark": "Sötét",
|
"dark": "Dark",
|
||||||
"light": "Világos",
|
"light": "Light",
|
||||||
"system": "Rendszer"
|
"system": "System preference"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tab": {
|
"tab": {
|
||||||
"close_current": "Jelenlegi lap bezására",
|
"close_current": "Close current tab",
|
||||||
"close_others": "Összes többi lap bezására",
|
"close_others": "Close all other tabs",
|
||||||
"duplicate": "Jelenlegi lap diplikálása",
|
"duplicate": "Duplicate current tab",
|
||||||
"new_tab": "Új lap megnyitása",
|
"new_tab": "Open a new tab",
|
||||||
"title": "Lapok"
|
"title": "Tabs"
|
||||||
},
|
},
|
||||||
"workspace": {
|
"workspace": {
|
||||||
"delete": "Jelenlegi csapat törlése",
|
"delete": "Delete current team",
|
||||||
"edit": "Jelenlegi csapat szerkesztése",
|
"edit": "Edit current team",
|
||||||
"invite": "Emberek meghívása a jelenlegi csapatba",
|
"invite": "Invite people to team",
|
||||||
"new": "Új csapat létrehozása",
|
"new": "Create new team",
|
||||||
"switch_to_personal": "Váltás a személyes munkaterületére",
|
"switch_to_personal": "Switch to your personal workspace",
|
||||||
"title": "Csapatok"
|
"title": "Teams"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sse": {
|
"sse": {
|
||||||
@@ -828,20 +828,20 @@
|
|||||||
"connection_error": "Nem sikerült kapcsolódni",
|
"connection_error": "Nem sikerült kapcsolódni",
|
||||||
"connection_failed": "A kapcsolódás sikertelen",
|
"connection_failed": "A kapcsolódás sikertelen",
|
||||||
"connection_lost": "A kapcsolat elveszett",
|
"connection_lost": "A kapcsolat elveszett",
|
||||||
"copied_interface_to_clipboard": "{language} interface típusa vágólapra másolva",
|
"copied_interface_to_clipboard": "Copied {language} interface type to clipboard",
|
||||||
"copied_to_clipboard": "Vágólapra másolva",
|
"copied_to_clipboard": "Vágólapra másolva",
|
||||||
"deleted": "Törölve",
|
"deleted": "Törölve",
|
||||||
"deprecated": "ELAVULT",
|
"deprecated": "ELAVULT",
|
||||||
"disabled": "Letiltva",
|
"disabled": "Letiltva",
|
||||||
"disconnected": "Lecsatlakoztatva",
|
"disconnected": "Leválasztva",
|
||||||
"disconnected_from": "Lecsatlakoztatva innen: {name}",
|
"disconnected_from": "Leválasztva innen: {name}",
|
||||||
"docs_generated": "Dokumentáció előállítva",
|
"docs_generated": "Dokumentáció előállítva",
|
||||||
"download_failed": "Letöltés sikertelen",
|
"download_failed": "Download failed",
|
||||||
"download_started": "A letöltés elkezdődött",
|
"download_started": "A letöltés elkezdődött",
|
||||||
"enabled": "Engedélyezve",
|
"enabled": "Engedélyezve",
|
||||||
"file_imported": "Fájl importálva",
|
"file_imported": "Fájl importálva",
|
||||||
"finished_in": "Befejeződött {duration} ms alatt",
|
"finished_in": "Befejeződött {duration} ms alatt",
|
||||||
"hide": "Elrejtés",
|
"hide": "Hide",
|
||||||
"history_deleted": "Előzmények törölve",
|
"history_deleted": "Előzmények törölve",
|
||||||
"linewrap": "Sorok tördelése",
|
"linewrap": "Sorok tördelése",
|
||||||
"loading": "Betöltés…",
|
"loading": "Betöltés…",
|
||||||
@@ -872,13 +872,13 @@
|
|||||||
"twitter": "Kövessen minket Twitteren"
|
"twitter": "Kövessen minket Twitteren"
|
||||||
},
|
},
|
||||||
"tab": {
|
"tab": {
|
||||||
"authorization": "Azonosítás",
|
"authorization": "Felhatalmazás",
|
||||||
"body": "Törzs",
|
"body": "Törzs",
|
||||||
"close": "Lap bezárása",
|
"close": "Close Tab",
|
||||||
"close_others": "Többi lap bezárása",
|
"close_others": "Close other Tabs",
|
||||||
"collections": "Gyűjtemények",
|
"collections": "Gyűjtemények",
|
||||||
"documentation": "Dokumentáció",
|
"documentation": "Dokumentáció",
|
||||||
"duplicate": "Lap duplikálása",
|
"duplicate": "Duplicate Tab",
|
||||||
"environments": "Környezetek",
|
"environments": "Környezetek",
|
||||||
"headers": "Fejlécek",
|
"headers": "Fejlécek",
|
||||||
"history": "Előzmények",
|
"history": "Előzmények",
|
||||||
@@ -905,7 +905,7 @@
|
|||||||
"email_do_not_match": "Az e-mail-cím nem egyezik a fiókja részleteivel. Vegye fel a kapcsolatot a csapat tulajdonosával.",
|
"email_do_not_match": "Az e-mail-cím nem egyezik a fiókja részleteivel. Vegye fel a kapcsolatot a csapat tulajdonosával.",
|
||||||
"exit": "Kilépés a csapatból",
|
"exit": "Kilépés a csapatból",
|
||||||
"exit_disabled": "Csak a tulajdonos nem léphet ki a csapatból",
|
"exit_disabled": "Csak a tulajdonos nem léphet ki a csapatból",
|
||||||
"failed_invites": "Hiba a meghívás közben",
|
"failed_invites": "Failed invites",
|
||||||
"invalid_coll_id": "Érvénytelen gyűjteményazonosító",
|
"invalid_coll_id": "Érvénytelen gyűjteményazonosító",
|
||||||
"invalid_email_format": "Az e-mail formátuma érvénytelen",
|
"invalid_email_format": "Az e-mail formátuma érvénytelen",
|
||||||
"invalid_id": "Érvénytelen csapatazonosító. Vegye fel a kapcsolatot a csapat tulajdonosával.",
|
"invalid_id": "Érvénytelen csapatazonosító. Vegye fel a kapcsolatot a csapat tulajdonosával.",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@hoppscotch/common",
|
"name": "@hoppscotch/common",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "2024.3.2",
|
"version": "2023.12.5",
|
||||||
"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",
|
||||||
@@ -21,147 +21,147 @@
|
|||||||
"do-lintfix": "pnpm run lintfix"
|
"do-lintfix": "pnpm run lintfix"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@apidevtools/swagger-parser": "10.1.0",
|
"@apidevtools/swagger-parser": "^10.1.0",
|
||||||
"@codemirror/autocomplete": "6.13.0",
|
"@codemirror/autocomplete": "^6.11.1",
|
||||||
"@codemirror/commands": "6.3.3",
|
"@codemirror/commands": "^6.3.2",
|
||||||
"@codemirror/lang-javascript": "6.2.2",
|
"@codemirror/lang-javascript": "^6.2.1",
|
||||||
"@codemirror/lang-json": "6.0.1",
|
"@codemirror/lang-json": "^6.0.1",
|
||||||
"@codemirror/lang-xml": "6.1.0",
|
"@codemirror/lang-xml": "^6.0.2",
|
||||||
"@codemirror/language": "6.10.1",
|
"@codemirror/language": "6.9.3",
|
||||||
"@codemirror/legacy-modes": "6.3.3",
|
"@codemirror/legacy-modes": "^6.3.3",
|
||||||
"@codemirror/lint": "6.5.0",
|
"@codemirror/lint": "^6.4.2",
|
||||||
"@codemirror/search": "6.5.6",
|
"@codemirror/search": "^6.5.5",
|
||||||
"@codemirror/state": "6.4.1",
|
"@codemirror/state": "^6.3.3",
|
||||||
"@codemirror/view": "6.25.1",
|
"@codemirror/view": "^6.22.3",
|
||||||
"@hoppscotch/codemirror-lang-graphql": "workspace:^",
|
"@hoppscotch/codemirror-lang-graphql": "workspace:^",
|
||||||
"@hoppscotch/data": "workspace:^",
|
"@hoppscotch/data": "workspace:^",
|
||||||
"@hoppscotch/js-sandbox": "workspace:^",
|
"@hoppscotch/js-sandbox": "workspace:^",
|
||||||
"@hoppscotch/ui": "0.1.0",
|
"@hoppscotch/ui": "^0.1.0",
|
||||||
"@hoppscotch/vue-toasted": "0.1.0",
|
"@hoppscotch/vue-toasted": "^0.1.0",
|
||||||
"@lezer/highlight": "1.2.0",
|
"@lezer/highlight": "1.2.0",
|
||||||
"@unhead/vue": "1.8.8",
|
"@unhead/vue": "^1.8.8",
|
||||||
"@urql/core": "4.2.0",
|
"@urql/core": "^4.2.0",
|
||||||
"@urql/devtools": "2.0.3",
|
"@urql/devtools": "^2.0.3",
|
||||||
"@urql/exchange-auth": "2.1.6",
|
"@urql/exchange-auth": "^2.1.6",
|
||||||
"@urql/exchange-graphcache": "6.4.0",
|
"@urql/exchange-graphcache": "^6.3.3",
|
||||||
"@vitejs/plugin-legacy": "4.1.1",
|
"@vitejs/plugin-legacy": "^4.1.1",
|
||||||
"@vueuse/core": "10.7.0",
|
"@vueuse/core": "^10.6.1",
|
||||||
"acorn-walk": "8.3.0",
|
"acorn-walk": "^8.3.0",
|
||||||
"axios": "1.6.2",
|
"axios": "^1.6.2",
|
||||||
"buffer": "6.0.3",
|
"buffer": "^6.0.3",
|
||||||
"cookie-es": "1.0.0",
|
"cookie-es": "^1.0.0",
|
||||||
"dioc": "3.0.1",
|
"dioc": "^1.0.1",
|
||||||
"esprima": "4.0.1",
|
"esprima": "^4.0.1",
|
||||||
"events": "3.3.0",
|
"events": "^3.3.0",
|
||||||
"fp-ts": "2.16.1",
|
"fp-ts": "^2.16.1",
|
||||||
"globalthis": "1.0.3",
|
"globalthis": "^1.0.3",
|
||||||
"graphql": "16.8.1",
|
"graphql": "^16.8.1",
|
||||||
"graphql-language-service-interface": "2.10.2",
|
"graphql-language-service-interface": "^2.10.2",
|
||||||
"graphql-tag": "2.12.6",
|
"graphql-tag": "^2.12.6",
|
||||||
"httpsnippet": "3.0.1",
|
"httpsnippet": "^3.0.1",
|
||||||
"insomnia-importers": "3.6.0",
|
"insomnia-importers": "^3.6.0",
|
||||||
"io-ts": "2.2.20",
|
"io-ts": "^2.2.20",
|
||||||
"js-yaml": "4.1.0",
|
"js-yaml": "^4.1.0",
|
||||||
"jsonpath-plus": "7.2.0",
|
"jsonpath-plus": "^7.2.0",
|
||||||
"lodash-es": "4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"lossless-json": "3.0.2",
|
"lossless-json": "^3.0.2",
|
||||||
"minisearch": "6.3.0",
|
"minisearch": "^6.3.0",
|
||||||
"nprogress": "0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
"paho-mqtt": "1.1.0",
|
"paho-mqtt": "^1.1.0",
|
||||||
"path": "0.12.7",
|
"path": "^0.12.7",
|
||||||
"postman-collection": "4.3.0",
|
"postman-collection": "^4.3.0",
|
||||||
"process": "0.11.10",
|
"process": "^0.11.10",
|
||||||
"qs": "6.11.2",
|
"qs": "^6.11.2",
|
||||||
"quicktype-core": "23.0.79",
|
"quicktype-core": "^23.0.79",
|
||||||
"rxjs": "7.8.1",
|
"rxjs": "^7.8.1",
|
||||||
"set-cookie-parser": "2.6.0",
|
"set-cookie-parser": "^2.6.0",
|
||||||
"set-cookie-parser-es": "1.0.5",
|
"set-cookie-parser-es": "^1.0.5",
|
||||||
"socket.io-client-v2": "npm:socket.io-client@2.4.0",
|
"socket.io-client-v2": "npm:socket.io-client@^2.4.0",
|
||||||
"socket.io-client-v3": "npm:socket.io-client@3.1.3",
|
"socket.io-client-v3": "npm:socket.io-client@^3.1.3",
|
||||||
"socket.io-client-v4": "npm:socket.io-client@4.4.1",
|
"socket.io-client-v4": "npm:socket.io-client@^4.4.1",
|
||||||
"socketio-wildcard": "2.0.0",
|
"socketio-wildcard": "^2.0.0",
|
||||||
"splitpanes": "3.1.5",
|
"splitpanes": "^3.1.5",
|
||||||
"stream-browserify": "3.0.0",
|
"stream-browserify": "^3.0.0",
|
||||||
"subscriptions-transport-ws": "0.11.0",
|
"subscriptions-transport-ws": "^0.11.0",
|
||||||
"tern": "0.24.3",
|
"tern": "^0.24.3",
|
||||||
"timers": "0.1.1",
|
"timers": "^0.1.1",
|
||||||
"tippy.js": "6.3.7",
|
"tippy.js": "^6.3.7",
|
||||||
"url": "0.11.3",
|
"url": "^0.11.3",
|
||||||
"util": "0.12.5",
|
"util": "^0.12.5",
|
||||||
"uuid": "9.0.1",
|
"uuid": "^9.0.1",
|
||||||
"verzod": "0.2.2",
|
"verzod": "^0.2.0",
|
||||||
"vue": "3.3.9",
|
"vue": "^3.3.8",
|
||||||
"vue-i18n": "9.8.0",
|
"vue-i18n": "^9.7.1",
|
||||||
"vue-pdf-embed": "1.2.1",
|
"vue-pdf-embed": "^1.2.1",
|
||||||
"vue-router": "4.2.5",
|
"vue-router": "^4.2.5",
|
||||||
"vue-tippy": "6.3.1",
|
"vue-tippy": "6.3.1",
|
||||||
"vuedraggable-es": "4.1.1",
|
"vuedraggable-es": "^4.1.1",
|
||||||
"wonka": "6.3.4",
|
"wonka": "^6.3.4",
|
||||||
"workbox-window": "7.0.0",
|
"workbox-window": "^7.0.0",
|
||||||
"xml-formatter": "3.6.0",
|
"xml-formatter": "^3.6.0",
|
||||||
"yargs-parser": "21.1.1",
|
"yargs-parser": "^21.1.1",
|
||||||
"zod": "3.22.4"
|
"zod": "^3.22.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@esbuild-plugins/node-globals-polyfill": "0.2.3",
|
"@esbuild-plugins/node-globals-polyfill": "^0.2.3",
|
||||||
"@esbuild-plugins/node-modules-polyfill": "0.2.2",
|
"@esbuild-plugins/node-modules-polyfill": "^0.2.2",
|
||||||
"@graphql-codegen/add": "5.0.0",
|
"@graphql-codegen/add": "^5.0.0",
|
||||||
"@graphql-codegen/cli": "5.0.0",
|
"@graphql-codegen/cli": "^5.0.0",
|
||||||
"@graphql-codegen/typed-document-node": "5.0.1",
|
"@graphql-codegen/typed-document-node": "^5.0.1",
|
||||||
"@graphql-codegen/typescript": "4.0.1",
|
"@graphql-codegen/typescript": "^4.0.1",
|
||||||
"@graphql-codegen/typescript-operations": "4.0.1",
|
"@graphql-codegen/typescript-operations": "^4.0.1",
|
||||||
"@graphql-codegen/typescript-urql-graphcache": "3.0.0",
|
"@graphql-codegen/typescript-urql-graphcache": "^3.0.0",
|
||||||
"@graphql-codegen/urql-introspection": "3.0.0",
|
"@graphql-codegen/urql-introspection": "^3.0.0",
|
||||||
"@graphql-typed-document-node/core": "3.2.0",
|
"@graphql-typed-document-node/core": "^3.2.0",
|
||||||
"@iconify-json/lucide": "1.1.144",
|
"@iconify-json/lucide": "^1.1.141",
|
||||||
"@intlify/vite-plugin-vue-i18n": "7.0.0",
|
"@intlify/vite-plugin-vue-i18n": "^7.0.0",
|
||||||
"@relmify/jest-fp-ts": "2.1.1",
|
"@relmify/jest-fp-ts": "^2.1.1",
|
||||||
"@rushstack/eslint-patch": "1.6.0",
|
"@rushstack/eslint-patch": "^1.6.0",
|
||||||
"@types/har-format": "1.2.15",
|
"@types/har-format": "^1.2.15",
|
||||||
"@types/js-yaml": "4.0.9",
|
"@types/js-yaml": "^4.0.9",
|
||||||
"@types/lodash-es": "4.17.12",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@types/lossless-json": "1.0.4",
|
"@types/lossless-json": "^1.0.4",
|
||||||
"@types/nprogress": "0.2.3",
|
"@types/nprogress": "^0.2.3",
|
||||||
"@types/paho-mqtt": "1.0.10",
|
"@types/paho-mqtt": "^1.0.10",
|
||||||
"@types/postman-collection": "3.5.10",
|
"@types/postman-collection": "^3.5.10",
|
||||||
"@types/splitpanes": "2.2.6",
|
"@types/splitpanes": "^2.2.6",
|
||||||
"@types/uuid": "9.0.7",
|
"@types/uuid": "^9.0.7",
|
||||||
"@types/yargs-parser": "21.0.3",
|
"@types/yargs-parser": "^21.0.3",
|
||||||
"@typescript-eslint/eslint-plugin": "7.3.1",
|
"@typescript-eslint/eslint-plugin": "^6.12.0",
|
||||||
"@typescript-eslint/parser": "7.3.1",
|
"@typescript-eslint/parser": "^6.12.0",
|
||||||
"@vitejs/plugin-vue": "4.5.1",
|
"@vitejs/plugin-vue": "^4.5.0",
|
||||||
"@vue/compiler-sfc": "3.3.10",
|
"@vue/compiler-sfc": "^3.3.8",
|
||||||
"@vue/eslint-config-typescript": "12.0.0",
|
"@vue/eslint-config-typescript": "^12.0.0",
|
||||||
"@vue/runtime-core": "3.3.10",
|
"@vue/runtime-core": "^3.3.8",
|
||||||
"autoprefixer": "10.4.16",
|
"autoprefixer": "^10.4.14",
|
||||||
"cross-env": "7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"dotenv": "16.3.1",
|
"dotenv": "^16.3.1",
|
||||||
"eslint": "8.57.0",
|
"eslint": "^8.54.0",
|
||||||
"eslint-plugin-prettier": "5.1.3",
|
"eslint-plugin-prettier": "^5.0.1",
|
||||||
"eslint-plugin-vue": "9.24.0",
|
"eslint-plugin-vue": "^9.18.1",
|
||||||
"glob": "10.3.10",
|
"glob": "^10.3.10",
|
||||||
"npm-run-all": "4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
"openapi-types": "12.1.3",
|
"openapi-types": "^12.1.3",
|
||||||
"postcss": "8.4.31",
|
"postcss": "^8.4.23",
|
||||||
"prettier": "3.1.0",
|
"prettier": "^3.1.0",
|
||||||
"prettier-plugin-tailwindcss": "0.5.7",
|
"prettier-plugin-tailwindcss": "^0.5.7",
|
||||||
"rollup-plugin-polyfill-node": "0.13.0",
|
"rollup-plugin-polyfill-node": "^0.13.0",
|
||||||
"sass": "1.69.5",
|
"sass": "^1.69.5",
|
||||||
"tailwindcss": "3.3.5",
|
"tailwindcss": "^3.3.2",
|
||||||
"typescript": "5.3.2",
|
"typescript": "^5.3.2",
|
||||||
"unplugin-fonts": "1.1.1",
|
"unplugin-fonts": "^1.1.1",
|
||||||
"unplugin-icons": "0.17.4",
|
"unplugin-icons": "^0.17.4",
|
||||||
"unplugin-vue-components": "0.25.2",
|
"unplugin-vue-components": "^0.25.2",
|
||||||
"vite": "4.5.0",
|
"vite": "^4.5.0",
|
||||||
"vite-plugin-checker": "0.6.2",
|
"vite-plugin-checker": "^0.6.2",
|
||||||
"vite-plugin-fonts": "0.7.0",
|
"vite-plugin-fonts": "^0.7.0",
|
||||||
"vite-plugin-html-config": "1.0.11",
|
"vite-plugin-html-config": "^1.0.11",
|
||||||
"vite-plugin-inspect": "0.7.42",
|
"vite-plugin-inspect": "^0.7.42",
|
||||||
"vite-plugin-pages": "0.31.0",
|
"vite-plugin-pages": "^0.31.0",
|
||||||
"vite-plugin-pages-sitemap": "1.6.1",
|
"vite-plugin-pages-sitemap": "^1.6.1",
|
||||||
"vite-plugin-pwa": "0.17.3",
|
"vite-plugin-pwa": "^0.17.0",
|
||||||
"vite-plugin-vue-layouts": "0.8.0",
|
"vite-plugin-vue-layouts": "^0.8.0",
|
||||||
"vitest": "0.34.6",
|
"vitest": "^0.34.6",
|
||||||
"vue-tsc": "1.8.24"
|
"vue-tsc": "^1.8.22"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
16
packages/hoppscotch-common/src/components.d.ts
vendored
16
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']
|
||||||
@@ -31,8 +31,6 @@ declare module 'vue' {
|
|||||||
AppSpotlightEntryIconSelected: typeof import('./components/app/spotlight/entry/IconSelected.vue')['default']
|
AppSpotlightEntryIconSelected: typeof import('./components/app/spotlight/entry/IconSelected.vue')['default']
|
||||||
AppSpotlightEntryRESTHistory: typeof import('./components/app/spotlight/entry/RESTHistory.vue')['default']
|
AppSpotlightEntryRESTHistory: typeof import('./components/app/spotlight/entry/RESTHistory.vue')['default']
|
||||||
AppSpotlightEntryRESTRequest: typeof import('./components/app/spotlight/entry/RESTRequest.vue')['default']
|
AppSpotlightEntryRESTRequest: typeof import('./components/app/spotlight/entry/RESTRequest.vue')['default']
|
||||||
AppSpotlightEntryRESTTeamRequestEntry: typeof import('./components/app/spotlight/entry/RESTTeamRequestEntry.vue')['default']
|
|
||||||
AppSpotlightSearch: typeof import('./components/app/SpotlightSearch.vue')['default']
|
|
||||||
AppSupport: typeof import('./components/app/Support.vue')['default']
|
AppSupport: typeof import('./components/app/Support.vue')['default']
|
||||||
Collections: typeof import('./components/collections/index.vue')['default']
|
Collections: typeof import('./components/collections/index.vue')['default']
|
||||||
CollectionsAdd: typeof import('./components/collections/Add.vue')['default']
|
CollectionsAdd: typeof import('./components/collections/Add.vue')['default']
|
||||||
@@ -133,7 +131,6 @@ declare module 'vue' {
|
|||||||
HttpRequest: typeof import('./components/http/Request.vue')['default']
|
HttpRequest: typeof import('./components/http/Request.vue')['default']
|
||||||
HttpRequestOptions: typeof import('./components/http/RequestOptions.vue')['default']
|
HttpRequestOptions: typeof import('./components/http/RequestOptions.vue')['default']
|
||||||
HttpRequestTab: typeof import('./components/http/RequestTab.vue')['default']
|
HttpRequestTab: typeof import('./components/http/RequestTab.vue')['default']
|
||||||
HttpRequestVariables: typeof import('./components/http/RequestVariables.vue')['default']
|
|
||||||
HttpResponse: typeof import('./components/http/Response.vue')['default']
|
HttpResponse: typeof import('./components/http/Response.vue')['default']
|
||||||
HttpResponseMeta: typeof import('./components/http/ResponseMeta.vue')['default']
|
HttpResponseMeta: typeof import('./components/http/ResponseMeta.vue')['default']
|
||||||
HttpSidebar: typeof import('./components/http/Sidebar.vue')['default']
|
HttpSidebar: typeof import('./components/http/Sidebar.vue')['default']
|
||||||
@@ -148,7 +145,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 +154,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 +209,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']
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user