Compare commits
125 Commits
feat/coll-
...
feat/reque
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a3e941271e | ||
|
|
e7fded89d5 | ||
|
|
40c8d7e4b7 | ||
|
|
1d93d9dabe | ||
|
|
e9f1dc7ba1 | ||
|
|
1e906bbec3 | ||
|
|
7776668e40 | ||
|
|
3d38b7678b | ||
|
|
1ca215d887 | ||
|
|
aec04a13e3 | ||
|
|
9a2058bbec | ||
|
|
1c65147a77 | ||
|
|
207eea538f | ||
|
|
e30b59e1b5 | ||
|
|
9704b3324b | ||
|
|
386bb453d4 | ||
|
|
175641246e | ||
|
|
fb615d2d2b | ||
|
|
7685409ee6 | ||
|
|
e01818444e | ||
|
|
52220d9a2e | ||
|
|
82d687f665 | ||
|
|
d44083a380 | ||
|
|
7589c57e86 | ||
|
|
c8009aec77 | ||
|
|
7114f4fd43 | ||
|
|
ca1a4ec31b | ||
|
|
359633102e | ||
|
|
b278691a9d | ||
|
|
c27e1be230 | ||
|
|
11e8ba7bb3 | ||
|
|
2a0000cfc4 | ||
|
|
0ed063724e | ||
|
|
170ec15821 | ||
|
|
3611cac241 | ||
|
|
919579b1da | ||
|
|
4798d7bbbd | ||
|
|
a0c6b22641 | ||
|
|
de8929ab18 | ||
|
|
55a94bdccc | ||
|
|
faab1d20fd | ||
|
|
bd406616ec | ||
|
|
6827e97ec5 | ||
|
|
10d2048975 | ||
|
|
291f18591e | ||
|
|
342532c9b1 | ||
|
|
cf039c482a | ||
|
|
ded2725116 | ||
|
|
9c6754c70f | ||
|
|
4bd54b12cd | ||
|
|
ed6e9b6954 | ||
|
|
dfdd44b4ed | ||
|
|
fc34871dae | ||
|
|
45b532747e | ||
|
|
de4635df23 | ||
|
|
41bad1f3dc | ||
|
|
ecca3d2032 | ||
|
|
47226be6d0 | ||
|
|
6a0e73fdec | ||
|
|
672ee69b2c | ||
|
|
b359650d96 | ||
|
|
c0fae79678 | ||
|
|
5bcc38e36b | ||
|
|
00862eb192 | ||
|
|
16803acb26 | ||
|
|
3911c9cd1f | ||
|
|
0028f6e878 | ||
|
|
0ba33ec187 | ||
|
|
3482743782 | ||
|
|
d7cdeb796a | ||
|
|
3d6adcc39d | ||
|
|
aab76f1358 | ||
|
|
a28a576c41 | ||
|
|
0d0ad7a2f8 | ||
|
|
1df9de44b7 | ||
|
|
4cba03e53f | ||
|
|
9e1466a877 | ||
|
|
b81ccb4ee3 | ||
|
|
27d0a7c437 | ||
|
|
aca96dd5f2 | ||
|
|
c0dbcc901f | ||
|
|
ba52c8cc37 | ||
|
|
d1f6f40ef8 | ||
|
|
99f5070f71 | ||
|
|
cd371fc9d4 | ||
|
|
59fef248c0 | ||
|
|
286fcd2bb0 | ||
|
|
b2d98f7b66 | ||
|
|
c6c220091a | ||
|
|
8f503479b6 | ||
|
|
54d8378ccf | ||
|
|
0df194f9c5 | ||
|
|
ddf7eb6ad6 | ||
|
|
7db7b9b068 | ||
|
|
3d25ef48d1 | ||
|
|
4f138beb8a | ||
|
|
3d7a76bced | ||
|
|
74359ea74e | ||
|
|
a694d3f7eb | ||
|
|
58a9514b67 | ||
|
|
a75bfa9d9e | ||
|
|
7374a35b41 | ||
|
|
5ad8f6c2ce | ||
|
|
f28298afe7 | ||
|
|
56c6e8c643 | ||
|
|
1b36de4fa3 | ||
|
|
2f773bec79 | ||
|
|
d3e04c59cc | ||
|
|
5179cf59a4 | ||
|
|
fad31a47ee | ||
|
|
72c71ddbd4 | ||
|
|
a0f5ebee39 | ||
|
|
f93558324f | ||
|
|
d80e6c01c8 | ||
|
|
06f0f1c91b | ||
|
|
9b870f876a | ||
|
|
cf8b5975ac | ||
|
|
93082c3816 | ||
|
|
d66537ac34 | ||
|
|
fc4c15e52d | ||
|
|
b521604b66 | ||
|
|
9bc81a6d67 | ||
|
|
c47e2e7767 | ||
|
|
5209c0a8ca | ||
|
|
47e009267b |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -81,10 +81,7 @@ web_modules/
|
|||||||
|
|
||||||
# dotenv environment variable files
|
# dotenv environment variable files
|
||||||
.env
|
.env
|
||||||
.env.development.local
|
.env.*
|
||||||
.env.test.local
|
|
||||||
.env.production.local
|
|
||||||
.env.local
|
|
||||||
|
|
||||||
# parcel-bundler cache (https://parceljs.org/)
|
# parcel-bundler cache (https://parceljs.org/)
|
||||||
.cache
|
.cache
|
||||||
|
|||||||
@@ -239,7 +239,7 @@ Help us to translate Hoppscotch. Please read [`TRANSLATIONS`](TRANSLATIONS.md) f
|
|||||||
|
|
||||||
📦 **Add-ons:** Official add-ons for hoppscotch.
|
📦 **Add-ons:** Official add-ons for hoppscotch.
|
||||||
|
|
||||||
- **[Hoppscotch CLI](https://github.com/hoppscotch/hopp-cli)** - Command-line interface for Hoppscotch.
|
- **[Hoppscotch CLI](https://github.com/hoppscotch/hoppscotch/tree/main/packages/hoppscotch-cli)** - Command-line interface for Hoppscotch.
|
||||||
- **[Proxy](https://github.com/hoppscotch/proxyscotch)** - A simple proxy server created for Hoppscotch.
|
- **[Proxy](https://github.com/hoppscotch/proxyscotch)** - A simple proxy server created for Hoppscotch.
|
||||||
- **[Browser Extensions](https://github.com/hoppscotch/hoppscotch-extension)** - Browser extensions that enhance your Hoppscotch experience.
|
- **[Browser Extensions](https://github.com/hoppscotch/hoppscotch-extension)** - Browser extensions that enhance your Hoppscotch experience.
|
||||||
|
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ services:
|
|||||||
build:
|
build:
|
||||||
dockerfile: packages/hoppscotch-backend/Dockerfile
|
dockerfile: packages/hoppscotch-backend/Dockerfile
|
||||||
context: .
|
context: .
|
||||||
target: prod
|
target: dev
|
||||||
env_file:
|
env_file:
|
||||||
- ./.env
|
- ./.env
|
||||||
restart: always
|
restart: always
|
||||||
@@ -122,7 +122,7 @@ services:
|
|||||||
- PORT=3000
|
- PORT=3000
|
||||||
volumes:
|
volumes:
|
||||||
# Uncomment the line below when modifying code. Only applicable when using the "dev" target.
|
# Uncomment the line below when modifying code. Only applicable when using the "dev" target.
|
||||||
# - ./packages/hoppscotch-backend/:/usr/src/app
|
- ./packages/hoppscotch-backend/:/usr/src/app
|
||||||
- /usr/src/app/node_modules/
|
- /usr/src/app/node_modules/
|
||||||
depends_on:
|
depends_on:
|
||||||
hoppscotch-db:
|
hoppscotch-db:
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "^16.2.3",
|
"@commitlint/cli": "^16.2.3",
|
||||||
"@commitlint/config-conventional": "^16.2.1",
|
"@commitlint/config-conventional": "^16.2.1",
|
||||||
|
"@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",
|
||||||
|
|||||||
@@ -17,9 +17,9 @@
|
|||||||
"types": "dist/index.d.ts",
|
"types": "dist/index.d.ts",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/language": "6.9.0",
|
"@codemirror/language": "6.9.3",
|
||||||
"@lezer/highlight": "1.1.4",
|
"@lezer/highlight": "1.2.0",
|
||||||
"@lezer/lr": "^1.3.13"
|
"@lezer/lr": "^1.3.14"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@lezer/generator": "^1.5.1",
|
"@lezer/generator": "^1.5.1",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "hoppscotch-backend",
|
"name": "hoppscotch-backend",
|
||||||
"version": "2023.8.4-1",
|
"version": "2023.12.6",
|
||||||
"description": "",
|
"description": "",
|
||||||
"author": "",
|
"author": "",
|
||||||
"private": true,
|
"private": true,
|
||||||
@@ -34,12 +34,14 @@
|
|||||||
"@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.6",
|
"@nestjs/platform-express": "^10.2.6",
|
||||||
|
"@nestjs/schedule": "^4.0.1",
|
||||||
"@nestjs/throttler": "^5.0.0",
|
"@nestjs/throttler": "^5.0.0",
|
||||||
"@prisma/client": "^4.16.2",
|
"@prisma/client": "^5.8.0",
|
||||||
"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",
|
||||||
|
"cron": "^3.1.6",
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
"express-session": "^1.17.3",
|
"express-session": "^1.17.3",
|
||||||
"fp-ts": "^2.13.1",
|
"fp-ts": "^2.13.1",
|
||||||
@@ -57,7 +59,8 @@
|
|||||||
"passport-jwt": "^4.0.1",
|
"passport-jwt": "^4.0.1",
|
||||||
"passport-local": "^1.0.0",
|
"passport-local": "^1.0.0",
|
||||||
"passport-microsoft": "^1.0.0",
|
"passport-microsoft": "^1.0.0",
|
||||||
"prisma": "^4.16.2",
|
"posthog-node": "^3.6.3",
|
||||||
|
"prisma": "^5.8.0",
|
||||||
"reflect-metadata": "^0.1.13",
|
"reflect-metadata": "^0.1.13",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"rxjs": "^7.6.0"
|
"rxjs": "^7.6.0"
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE
|
||||||
|
"TeamCollection"
|
||||||
|
ADD
|
||||||
|
titleSearch tsvector GENERATED ALWAYS AS (to_tsvector('english', title)) STORED;
|
||||||
|
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE
|
||||||
|
"TeamRequest"
|
||||||
|
ADD
|
||||||
|
titleSearch tsvector GENERATED ALWAYS AS (to_tsvector('english', title)) STORED;
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "TeamCollection_textSearch_idx" ON "TeamCollection" USING GIN (titleSearch);
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "TeamRequest_textSearch_idx" ON "TeamRequest" USING GIN (titleSearch);
|
||||||
@@ -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,9 +27,7 @@ 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 { User } from 'src/user/user.model';
|
import { UserDeletionResult } 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)
|
||||||
@@ -49,203 +47,6 @@ 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, {
|
||||||
@@ -269,8 +70,26 @@ 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(
|
||||||
@@ -281,12 +100,33 @@ export class AdminResolver {
|
|||||||
})
|
})
|
||||||
userUID: string,
|
userUID: string,
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
const invitedUser = await this.adminService.removeUserAccount(userUID);
|
const removedUser = await this.adminService.removeUserAccount(userUID);
|
||||||
if (E.isLeft(invitedUser)) throwErr(invitedUser.left);
|
if (E.isLeft(removedUser)) throwErr(removedUser.left);
|
||||||
return invitedUser.right;
|
return removedUser.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(
|
||||||
@@ -302,8 +142,51 @@ 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(
|
||||||
@@ -319,6 +202,23 @@ 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 } from '@prisma/client';
|
import { InvitedUsers, User as DbUser } 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,10 +13,15 @@ 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>();
|
||||||
@@ -58,20 +63,87 @@ 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 return an array of invited users', async () => {
|
test('should resolve right and apply pagination correctly', async () => {
|
||||||
// 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();
|
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 () => {
|
||||||
|
const paginationArgs: OffsetPaginationArgs = { take: 10, skip: 0 };
|
||||||
|
|
||||||
|
// 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 results = await adminService.fetchInvitedUsers(paginationArgs);
|
||||||
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();
|
const results = await adminService.fetchInvitedUsers(paginationArgs);
|
||||||
expect(results).toEqual([]);
|
expect(results).toEqual([]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -134,6 +206,58 @@ 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,13 +6,16 @@ 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';
|
||||||
@@ -26,6 +29,8 @@ 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 {
|
||||||
@@ -48,12 +53,30 @@ 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
|
||||||
@@ -110,14 +133,68 @@ 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() {
|
async fetchInvitedUsers(paginationOption: OffsetPaginationArgs) {
|
||||||
const invitedUsers = await this.prisma.invitedUsers.findMany();
|
const userEmailObjs = await this.prisma.user.findMany({
|
||||||
|
select: {
|
||||||
|
email: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const users: InvitedUser[] = invitedUsers.map(
|
const pendingInvitedUsers = await this.prisma.invitedUsers.findMany({
|
||||||
|
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 },
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -337,6 +414,7 @@ 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);
|
||||||
@@ -349,10 +427,73 @@ 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);
|
||||||
@@ -360,10 +501,22 @@ 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();
|
||||||
@@ -374,6 +527,26 @@ 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
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
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,7 +17,10 @@ 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 { PaginationArgs } from 'src/types/input-types.args';
|
import {
|
||||||
|
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';
|
||||||
@@ -29,7 +32,8 @@ import {
|
|||||||
EnableAndDisableSSOArgs,
|
EnableAndDisableSSOArgs,
|
||||||
InfraConfigArgs,
|
InfraConfigArgs,
|
||||||
} from 'src/infra-config/input-args';
|
} from 'src/infra-config/input-args';
|
||||||
import { InfraConfigEnumForClient } from 'src/types/InfraConfig';
|
import { InfraConfigEnum } from 'src/types/InfraConfig';
|
||||||
|
import { ServiceStatus } from 'src/infra-config/helper';
|
||||||
|
|
||||||
@UseGuards(GqlThrottlerGuard)
|
@UseGuards(GqlThrottlerGuard)
|
||||||
@Resolver(() => Infra)
|
@Resolver(() => Infra)
|
||||||
@@ -76,6 +80,7 @@ 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[]> {
|
||||||
@@ -83,11 +88,33 @@ 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(): Promise<InvitedUser[]> {
|
async invitedUsers(
|
||||||
const users = await this.adminService.fetchInvitedUsers();
|
@Args() args: OffsetPaginationArgs,
|
||||||
|
): Promise<InvitedUser[]> {
|
||||||
|
const users = await this.adminService.fetchInvitedUsers(args);
|
||||||
return users;
|
return users;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,10 +274,10 @@ export class InfraResolver {
|
|||||||
async infraConfigs(
|
async infraConfigs(
|
||||||
@Args({
|
@Args({
|
||||||
name: 'configNames',
|
name: 'configNames',
|
||||||
type: () => [InfraConfigEnumForClient],
|
type: () => [InfraConfigEnum],
|
||||||
description: 'Configs to fetch',
|
description: 'Configs to fetch',
|
||||||
})
|
})
|
||||||
names: InfraConfigEnumForClient[],
|
names: InfraConfigEnum[],
|
||||||
) {
|
) {
|
||||||
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);
|
||||||
@@ -284,6 +311,25 @@ 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)',
|
||||||
})
|
})
|
||||||
@@ -306,7 +352,9 @@ export class InfraResolver {
|
|||||||
})
|
})
|
||||||
providerInfo: EnableAndDisableSSOArgs[],
|
providerInfo: EnableAndDisableSSOArgs[],
|
||||||
) {
|
) {
|
||||||
const isUpdated = await this.infraConfigService.enableAndDisableSSO(providerInfo);
|
const isUpdated = await this.infraConfigService.enableAndDisableSSO(
|
||||||
|
providerInfo,
|
||||||
|
);
|
||||||
if (E.isLeft(isUpdated)) throwErr(isUpdated.left);
|
if (E.isLeft(isUpdated)) throwErr(isUpdated.left);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ 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: [
|
||||||
@@ -96,6 +98,8 @@ import { MailerModule } from './mailer/mailer.module';
|
|||||||
UserCollectionModule,
|
UserCollectionModule,
|
||||||
ShortcodeModule,
|
ShortcodeModule,
|
||||||
InfraConfigModule,
|
InfraConfigModule,
|
||||||
|
PosthogModule,
|
||||||
|
ScheduleModule.forRoot(),
|
||||||
],
|
],
|
||||||
providers: [GQLComplexityPlugin],
|
providers: [GQLComplexityPlugin],
|
||||||
controllers: [AppController],
|
controllers: [AppController],
|
||||||
|
|||||||
@@ -18,12 +18,7 @@ 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 {
|
import { AuthProvider, authCookieHandler, authProviderCheck } from './helper';
|
||||||
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';
|
||||||
@@ -31,6 +26,7 @@ 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,7 +12,10 @@ 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 { loadInfraConfiguration } from 'src/infra-config/helper';
|
import {
|
||||||
|
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({
|
||||||
@@ -34,6 +37,11 @@ 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 { AuthError } from 'src/types/AuthError';
|
import { RESTError } from 'src/types/RESTError';
|
||||||
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(<AuthError>{
|
return E.left(<RESTError>{
|
||||||
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<AuthError>> {
|
): Promise<E.Right<AuthTokens> | E.Left<RESTError>> {
|
||||||
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(<AuthError>{
|
return E.left(<RESTError>{
|
||||||
message: elevatedUser.left,
|
message: elevatedUser.left,
|
||||||
statusCode: HttpStatus.NOT_FOUND,
|
statusCode: HttpStatus.NOT_FOUND,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
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, throwHTTPErr } from '../helper';
|
import { AuthProvider, authProviderCheck } 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,9 +1,10 @@
|
|||||||
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, throwHTTPErr } from '../helper';
|
import { AuthProvider, authProviderCheck } 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,9 +1,10 @@
|
|||||||
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, throwHTTPErr } from '../helper';
|
import { AuthProvider, authProviderCheck } 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,6 +1,5 @@
|
|||||||
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';
|
||||||
@@ -25,15 +24,6 @@ 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('GITHUB_CALLBACK_URL'),
|
callbackURL: configService.get('INFRA.GITHUB_CALLBACK_URL'),
|
||||||
scope: [configService.get('GITHUB_SCOPE')],
|
scope: [configService.get('INFRA.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('GOOGLE_CALLBACK_URL'),
|
callbackURL: configService.get('INFRA.GOOGLE_CALLBACK_URL'),
|
||||||
scope: configService.get('GOOGLE_SCOPE').split(','),
|
scope: configService.get('INFRA.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('MICROSOFT_CALLBACK_URL'),
|
callbackURL: configService.get('INFRA.MICROSOFT_CALLBACK_URL'),
|
||||||
scope: [configService.get('MICROSOFT_SCOPE')],
|
scope: [configService.get('INFRA.MICROSOFT_SCOPE')],
|
||||||
tenant: configService.get('MICROSOFT_TENANT'),
|
tenant: configService.get('INFRA.MICROSOFT_TENANT'),
|
||||||
store: true,
|
store: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,14 @@ 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)
|
||||||
@@ -28,6 +36,13 @@ export const JSON_INVALID = 'json_invalid';
|
|||||||
*/
|
*/
|
||||||
export const AUTH_PROVIDER_NOT_SPECIFIED = 'auth/provider_not_specified';
|
export const AUTH_PROVIDER_NOT_SPECIFIED = 'auth/provider_not_specified';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auth Provider not specified
|
||||||
|
* (Auth)
|
||||||
|
*/
|
||||||
|
export const AUTH_PROVIDER_NOT_CONFIGURED =
|
||||||
|
'auth/provider_not_configured_correctly';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Environment variable "VITE_ALLOWED_AUTH_PROVIDERS" is not present in .env file
|
* Environment variable "VITE_ALLOWED_AUTH_PROVIDERS" is not present in .env file
|
||||||
*/
|
*/
|
||||||
@@ -92,6 +107,13 @@ 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)
|
||||||
@@ -206,6 +228,12 @@ 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)
|
||||||
@@ -261,6 +289,13 @@ 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)
|
||||||
@@ -286,6 +321,19 @@ 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)
|
||||||
@@ -676,9 +724,29 @@ export const INFRA_CONFIG_RESET_FAILED = 'infra_config/reset_failed' as const;
|
|||||||
*/
|
*/
|
||||||
export const INFRA_CONFIG_INVALID_INPUT = 'infra_config/invalid_input' as const;
|
export const INFRA_CONFIG_INVALID_INPUT = 'infra_config/invalid_input' as const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Infra Config service (auth provider/mailer/audit logs) not configured
|
||||||
|
* (InfraConfigService)
|
||||||
|
*/
|
||||||
|
export const INFRA_CONFIG_SERVICE_NOT_CONFIGURED =
|
||||||
|
'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 performed. Please check the FAQ for assistance: https://docs.hoppscotch.io/support/faq';
|
'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';
|
||||||
|
|||||||
@@ -1,10 +1,44 @@
|
|||||||
|
import { AuthProvider } from 'src/auth/helper';
|
||||||
|
import {
|
||||||
|
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 { throwErr } from 'src/utils';
|
||||||
|
import { randomBytes } from 'crypto';
|
||||||
|
|
||||||
export enum ServiceStatus {
|
export enum ServiceStatus {
|
||||||
ENABLE = 'ENABLE',
|
ENABLE = 'ENABLE',
|
||||||
DISABLE = 'DISABLE',
|
DISABLE = 'DISABLE',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const AuthProviderConfigurations = {
|
||||||
|
[AuthProvider.GOOGLE]: [
|
||||||
|
InfraConfigEnum.GOOGLE_CLIENT_ID,
|
||||||
|
InfraConfigEnum.GOOGLE_CLIENT_SECRET,
|
||||||
|
InfraConfigEnum.GOOGLE_CALLBACK_URL,
|
||||||
|
InfraConfigEnum.GOOGLE_SCOPE,
|
||||||
|
],
|
||||||
|
[AuthProvider.GITHUB]: [
|
||||||
|
InfraConfigEnum.GITHUB_CLIENT_ID,
|
||||||
|
InfraConfigEnum.GITHUB_CLIENT_SECRET,
|
||||||
|
InfraConfigEnum.GITHUB_CALLBACK_URL,
|
||||||
|
InfraConfigEnum.GITHUB_SCOPE,
|
||||||
|
],
|
||||||
|
[AuthProvider.MICROSOFT]: [
|
||||||
|
InfraConfigEnum.MICROSOFT_CLIENT_ID,
|
||||||
|
InfraConfigEnum.MICROSOFT_CLIENT_SECRET,
|
||||||
|
InfraConfigEnum.MICROSOFT_CALLBACK_URL,
|
||||||
|
InfraConfigEnum.MICROSOFT_SCOPE,
|
||||||
|
InfraConfigEnum.MICROSOFT_TENANT,
|
||||||
|
],
|
||||||
|
[AuthProvider.EMAIL]: [
|
||||||
|
InfraConfigEnum.MAILER_SMTP_URL,
|
||||||
|
InfraConfigEnum.MAILER_ADDRESS_FROM,
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load environment variables from the database and set them in the process
|
* Load environment variables from the database and set them in the process
|
||||||
*
|
*
|
||||||
@@ -30,6 +64,125 @@ 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify if 'infra_config' table is loaded with all entries
|
||||||
|
* @returns boolean
|
||||||
|
*/
|
||||||
|
export async function isInfraConfigTablePopulated(): Promise<boolean> {
|
||||||
|
const prisma = new PrismaService();
|
||||||
|
try {
|
||||||
|
const dbInfraConfigs = await prisma.infraConfig.findMany();
|
||||||
|
const infraConfigDefaultObjs = await getDefaultInfraConfigs();
|
||||||
|
|
||||||
|
const propsRemainingToInsert = infraConfigDefaultObjs.filter(
|
||||||
|
(p) => !dbInfraConfigs.find((e) => e.name === p.name),
|
||||||
|
);
|
||||||
|
|
||||||
|
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)
|
||||||
@@ -42,3 +195,51 @@ export function stopApp() {
|
|||||||
process.kill(process.pid, 'SIGTERM');
|
process.kill(process.pid, 'SIGTERM');
|
||||||
}, 5000);
|
}, 5000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the configured SSO providers
|
||||||
|
* @returns Array of configured SSO providers
|
||||||
|
*/
|
||||||
|
export function getConfiguredSSOProviders() {
|
||||||
|
const allowedAuthProviders: string[] =
|
||||||
|
process.env.VITE_ALLOWED_AUTH_PROVIDERS.split(',');
|
||||||
|
let configuredAuthProviders: string[] = [];
|
||||||
|
|
||||||
|
const addProviderIfConfigured = (provider) => {
|
||||||
|
const configParameters: string[] = AuthProviderConfigurations[provider];
|
||||||
|
|
||||||
|
const isConfigured = configParameters.every((configParameter) => {
|
||||||
|
return process.env[configParameter];
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isConfigured) configuredAuthProviders.push(provider);
|
||||||
|
};
|
||||||
|
|
||||||
|
allowedAuthProviders.forEach((provider) => addProviderIfConfigured(provider));
|
||||||
|
|
||||||
|
if (configuredAuthProviders.length === 0) {
|
||||||
|
throwErr(AUTH_PROVIDER_NOT_CONFIGURED);
|
||||||
|
} else if (allowedAuthProviders.length !== configuredAuthProviders.length) {
|
||||||
|
const unConfiguredAuthProviders = allowedAuthProviders.filter(
|
||||||
|
(provider) => {
|
||||||
|
return !configuredAuthProviders.includes(provider);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
console.log(
|
||||||
|
`${unConfiguredAuthProviders.join(
|
||||||
|
',',
|
||||||
|
)} SSO auth provider(s) are not configured properly. Do configure them from Admin Dashboard.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return configuredAuthProviders.join(',');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a hashed valued for analytics
|
||||||
|
* @returns Generated hashed value
|
||||||
|
*/
|
||||||
|
export function generateAnalyticsUserId() {
|
||||||
|
const hashedUserID = randomBytes(20).toString('hex');
|
||||||
|
return hashedUserID;
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
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 { InfraConfigEnumForClient } from 'src/types/InfraConfig';
|
import { InfraConfigEnum } 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: InfraConfigEnumForClient;
|
name: InfraConfigEnum;
|
||||||
|
|
||||||
@Field({
|
@Field({
|
||||||
description: 'Infra Config Value',
|
description: 'Infra Config Value',
|
||||||
@@ -16,7 +16,7 @@ export class InfraConfig {
|
|||||||
value: string;
|
value: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
registerEnumType(InfraConfigEnumForClient, {
|
registerEnumType(InfraConfigEnum, {
|
||||||
name: 'InfraConfigEnum',
|
name: 'InfraConfigEnum',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
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,13 +1,16 @@
|
|||||||
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 {
|
||||||
InfraConfigEnum,
|
INFRA_CONFIG_NOT_FOUND,
|
||||||
InfraConfigEnumForClient,
|
INFRA_CONFIG_OPERATION_NOT_ALLOWED,
|
||||||
} from 'src/types/InfraConfig';
|
INFRA_CONFIG_UPDATE_FAILED,
|
||||||
import { INFRA_CONFIG_NOT_FOUND, INFRA_CONFIG_UPDATE_FAILED } from 'src/errors';
|
} 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>();
|
||||||
@@ -19,12 +22,82 @@ 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';
|
||||||
@@ -71,7 +144,7 @@ describe('InfraConfigService', () => {
|
|||||||
|
|
||||||
describe('get', () => {
|
describe('get', () => {
|
||||||
it('should get the infra config', async () => {
|
it('should get the infra config', async () => {
|
||||||
const name = InfraConfigEnumForClient.GOOGLE_CLIENT_ID;
|
const name = InfraConfigEnum.GOOGLE_CLIENT_ID;
|
||||||
const value = 'true';
|
const value = 'true';
|
||||||
|
|
||||||
mockPrisma.infraConfig.findUniqueOrThrow.mockResolvedValueOnce({
|
mockPrisma.infraConfig.findUniqueOrThrow.mockResolvedValueOnce({
|
||||||
@@ -87,7 +160,7 @@ describe('InfraConfigService', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should pass correct params to prisma findUnique', async () => {
|
it('should pass correct params to prisma findUnique', async () => {
|
||||||
const name = InfraConfigEnumForClient.GOOGLE_CLIENT_ID;
|
const name = InfraConfigEnum.GOOGLE_CLIENT_ID;
|
||||||
|
|
||||||
await infraConfigService.get(name);
|
await infraConfigService.get(name);
|
||||||
|
|
||||||
@@ -98,7 +171,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 = InfraConfigEnumForClient.GOOGLE_CLIENT_ID;
|
const name = InfraConfigEnum.GOOGLE_CLIENT_ID;
|
||||||
|
|
||||||
mockPrisma.infraConfig.findUniqueOrThrow.mockRejectedValueOnce('null');
|
mockPrisma.infraConfig.findUniqueOrThrow.mockRejectedValueOnce('null');
|
||||||
|
|
||||||
@@ -106,4 +179,45 @@ 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,23 +3,27 @@ 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 {
|
import { InfraConfigEnum } from 'src/types/InfraConfig';
|
||||||
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_OPERATION_NOT_ALLOWED,
|
||||||
} from 'src/errors';
|
} from 'src/errors';
|
||||||
import { throwErr, validateEmail, validateSMTPUrl } from 'src/utils';
|
import {
|
||||||
|
throwErr,
|
||||||
|
validateSMTPEmail,
|
||||||
|
validateSMTPUrl,
|
||||||
|
validateUrl,
|
||||||
|
} from 'src/utils';
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
import { ServiceStatus, stopApp } from './helper';
|
import { ServiceStatus, getDefaultInfraConfigs, stopApp } from './helper';
|
||||||
import { EnableAndDisableSSOArgs, InfraConfigArgs } from './input-args';
|
import { EnableAndDisableSSOArgs, InfraConfigArgs } from './input-args';
|
||||||
|
import { AuthProvider } from 'src/auth/helper';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class InfraConfigService implements OnModuleInit {
|
export class InfraConfigService implements OnModuleInit {
|
||||||
@@ -28,70 +32,32 @@ 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: process.env.VITE_ALLOWED_AUTH_PROVIDERS.toLocaleUpperCase(),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
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 {
|
||||||
// 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
|
// Fetch the default values (value in .env) for configs to be saved in 'infra_config' table
|
||||||
const infraConfigDefaultObjs = this.getDefaultInfraConfigs();
|
const infraConfigDefaultObjs = await 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
|
// Eliminate the rows (from 'infraConfigDefaultObjs') that are already present in the database table
|
||||||
const dbInfraConfigs = await this.prisma.infraConfig.findMany();
|
const dbInfraConfigs = await this.prisma.infraConfig.findMany();
|
||||||
@@ -124,20 +90,31 @@ export class InfraConfigService implements OnModuleInit {
|
|||||||
cast(dbInfraConfig: DBInfraConfig) {
|
cast(dbInfraConfig: DBInfraConfig) {
|
||||||
return <InfraConfig>{
|
return <InfraConfig>{
|
||||||
name: dbInfraConfig.name,
|
name: dbInfraConfig.name,
|
||||||
value: dbInfraConfig.value,
|
value: dbInfraConfig.value ?? '',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all the InfraConfigs as map
|
||||||
|
* @returns InfraConfig map
|
||||||
|
*/
|
||||||
|
async getInfraConfigsMap() {
|
||||||
|
const infraConfigs = await this.prisma.infraConfig.findMany();
|
||||||
|
const infraConfigMap: Record<string, string> = {};
|
||||||
|
infraConfigs.forEach((config) => {
|
||||||
|
infraConfigMap[config.name] = config.value;
|
||||||
|
});
|
||||||
|
return infraConfigMap;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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(
|
async update(name: InfraConfigEnum, value: string, restartEnabled = false) {
|
||||||
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);
|
||||||
|
|
||||||
@@ -147,7 +124,7 @@ export class InfraConfigService implements OnModuleInit {
|
|||||||
data: { value },
|
data: { value },
|
||||||
});
|
});
|
||||||
|
|
||||||
stopApp();
|
if (restartEnabled) stopApp();
|
||||||
|
|
||||||
return E.right(this.cast(infraConfig));
|
return E.right(this.cast(infraConfig));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -161,6 +138,11 @@ 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);
|
||||||
|
|
||||||
@@ -182,6 +164,62 @@ export class InfraConfigService implements OnModuleInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the service is configured or not
|
||||||
|
* @param service Service can be Auth Provider, Mailer, Audit Log etc.
|
||||||
|
* @param configMap Map of all the infra configs
|
||||||
|
* @returns Either true or false
|
||||||
|
*/
|
||||||
|
isServiceConfigured(
|
||||||
|
service: AuthProvider,
|
||||||
|
configMap: Record<string, string>,
|
||||||
|
) {
|
||||||
|
switch (service) {
|
||||||
|
case AuthProvider.GOOGLE:
|
||||||
|
return (
|
||||||
|
configMap.GOOGLE_CLIENT_ID &&
|
||||||
|
configMap.GOOGLE_CLIENT_SECRET &&
|
||||||
|
configMap.GOOGLE_CALLBACK_URL &&
|
||||||
|
configMap.GOOGLE_SCOPE
|
||||||
|
);
|
||||||
|
case AuthProvider.GITHUB:
|
||||||
|
return (
|
||||||
|
configMap.GITHUB_CLIENT_ID &&
|
||||||
|
configMap.GITHUB_CLIENT_SECRET &&
|
||||||
|
configMap.GITHUB_CALLBACK_URL &&
|
||||||
|
configMap.GITHUB_SCOPE
|
||||||
|
);
|
||||||
|
case AuthProvider.MICROSOFT:
|
||||||
|
return (
|
||||||
|
configMap.MICROSOFT_CLIENT_ID &&
|
||||||
|
configMap.MICROSOFT_CLIENT_SECRET &&
|
||||||
|
configMap.MICROSOFT_CALLBACK_URL &&
|
||||||
|
configMap.MICROSOFT_SCOPE &&
|
||||||
|
configMap.MICROSOFT_TENANT
|
||||||
|
);
|
||||||
|
case AuthProvider.EMAIL:
|
||||||
|
return configMap.MAILER_SMTP_URL && configMap.MAILER_ADDRESS_FROM;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
@@ -195,8 +233,14 @@ export class InfraConfigService implements OnModuleInit {
|
|||||||
|
|
||||||
let updatedAuthProviders = allowedAuthProviders;
|
let updatedAuthProviders = allowedAuthProviders;
|
||||||
|
|
||||||
|
const infraConfigMap = await this.getInfraConfigsMap();
|
||||||
|
|
||||||
providerInfo.forEach(({ provider, status }) => {
|
providerInfo.forEach(({ provider, status }) => {
|
||||||
if (status === ServiceStatus.ENABLE) {
|
if (status === ServiceStatus.ENABLE) {
|
||||||
|
const isConfigured = this.isServiceConfigured(provider, infraConfigMap);
|
||||||
|
if (!isConfigured) {
|
||||||
|
throwErr(INFRA_CONFIG_SERVICE_NOT_CONFIGURED);
|
||||||
|
}
|
||||||
updatedAuthProviders.push(provider);
|
updatedAuthProviders.push(provider);
|
||||||
} else if (status === ServiceStatus.DISABLE) {
|
} else if (status === ServiceStatus.DISABLE) {
|
||||||
updatedAuthProviders = updatedAuthProviders.filter(
|
updatedAuthProviders = updatedAuthProviders.filter(
|
||||||
@@ -214,6 +258,7 @@ 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);
|
||||||
|
|
||||||
@@ -225,7 +270,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: InfraConfigEnumForClient) {
|
async get(name: InfraConfigEnum) {
|
||||||
try {
|
try {
|
||||||
const infraConfig = await this.prisma.infraConfig.findUniqueOrThrow({
|
const infraConfig = await this.prisma.infraConfig.findUniqueOrThrow({
|
||||||
where: { name },
|
where: { name },
|
||||||
@@ -242,7 +287,15 @@ export class InfraConfigService implements OnModuleInit {
|
|||||||
* @param names Names of the InfraConfigs
|
* @param names Names of the InfraConfigs
|
||||||
* @returns InfraConfig model
|
* @returns InfraConfig model
|
||||||
*/
|
*/
|
||||||
async getMany(names: InfraConfigEnumForClient[]) {
|
async getMany(names: InfraConfigEnum[], checkDisallowedKeys: boolean = true) {
|
||||||
|
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 } },
|
||||||
@@ -269,13 +322,24 @@ export class InfraConfigService implements OnModuleInit {
|
|||||||
*/
|
*/
|
||||||
async reset() {
|
async reset() {
|
||||||
try {
|
try {
|
||||||
const infraConfigDefaultObjs = this.getDefaultInfraConfigs();
|
const infraConfigDefaultObjs = await getDefaultInfraConfigs();
|
||||||
|
|
||||||
await this.prisma.infraConfig.deleteMany({
|
await this.prisma.infraConfig.deleteMany({
|
||||||
where: { name: { in: infraConfigDefaultObjs.map((p) => p.name) } },
|
where: { name: { in: infraConfigDefaultObjs.map((p) => p.name) } },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Hardcode t
|
||||||
|
const updatedInfraConfigDefaultObjs = infraConfigDefaultObjs.filter(
|
||||||
|
(obj) => obj.name !== InfraConfigEnum.IS_FIRST_TIME_INFRA_SETUP,
|
||||||
|
);
|
||||||
await this.prisma.infraConfig.createMany({
|
await this.prisma.infraConfig.createMany({
|
||||||
data: infraConfigDefaultObjs,
|
data: [
|
||||||
|
...updatedInfraConfigDefaultObjs,
|
||||||
|
{
|
||||||
|
name: InfraConfigEnum.IS_FIRST_TIME_INFRA_SETUP,
|
||||||
|
value: 'true',
|
||||||
|
},
|
||||||
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
stopApp();
|
stopApp();
|
||||||
@@ -286,22 +350,67 @@ export class InfraConfigService implements OnModuleInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate the values of the InfraConfigs
|
||||||
|
*/
|
||||||
validateEnvValues(
|
validateEnvValues(
|
||||||
infraConfigs: {
|
infraConfigs: {
|
||||||
name: InfraConfigEnumForClient | InfraConfigEnum;
|
name: 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 InfraConfigEnumForClient.MAILER_SMTP_URL:
|
case InfraConfigEnum.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 InfraConfigEnumForClient.MAILER_ADDRESS_FROM:
|
case InfraConfigEnum.MAILER_ADDRESS_FROM:
|
||||||
const isValidEmail = validateEmail(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:
|
||||||
|
if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT);
|
||||||
|
break;
|
||||||
|
case InfraConfigEnum.GOOGLE_CLIENT_SECRET:
|
||||||
|
if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT);
|
||||||
|
break;
|
||||||
|
case InfraConfigEnum.GOOGLE_CALLBACK_URL:
|
||||||
|
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);
|
||||||
|
break;
|
||||||
|
case InfraConfigEnum.GITHUB_CLIENT_ID:
|
||||||
|
if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT);
|
||||||
|
break;
|
||||||
|
case InfraConfigEnum.GITHUB_CLIENT_SECRET:
|
||||||
|
if (!infraConfigs[i].value) return E.left(INFRA_CONFIG_INVALID_INPUT);
|
||||||
|
break;
|
||||||
|
case InfraConfigEnum.GITHUB_CALLBACK_URL:
|
||||||
|
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);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import { Field, InputType } from '@nestjs/graphql';
|
import { Field, InputType } from '@nestjs/graphql';
|
||||||
import { InfraConfigEnumForClient } from 'src/types/InfraConfig';
|
import { InfraConfigEnum } 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(() => InfraConfigEnumForClient, {
|
@Field(() => InfraConfigEnum, {
|
||||||
description: 'Infra Config Name',
|
description: 'Infra Config Name',
|
||||||
})
|
})
|
||||||
name: InfraConfigEnumForClient;
|
name: InfraConfigEnum;
|
||||||
|
|
||||||
@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 `${mailDesc.variables.invitee} invited you to join ${mailDesc.variables.invite_team_name} in Hoppscotch`;
|
return `A user has invited you to join a team workspace in Hoppscotch`;
|
||||||
|
|
||||||
case 'user-invitation':
|
case 'user-invitation':
|
||||||
return 'Sign in to Hoppscotch';
|
return 'Sign in to Hoppscotch';
|
||||||
|
|||||||
@@ -27,6 +27,12 @@
|
|||||||
color: #3869D4;
|
color: #3869D4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a.nohighlight {
|
||||||
|
color: inherit !important;
|
||||||
|
text-decoration: none !important;
|
||||||
|
cursor: default !important;
|
||||||
|
}
|
||||||
|
|
||||||
a img {
|
a img {
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
@@ -458,7 +464,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>{{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>
|
<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>
|
||||||
<!-- 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>
|
||||||
@@ -484,7 +490,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 {{invitee}} or {{invite_team_name}}, just ignore this email.</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>
|
||||||
<!-- Sub copy -->
|
<!-- Sub copy -->
|
||||||
<table class="body-sub">
|
<table class="body-sub">
|
||||||
<tr>
|
<tr>
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
-->
|
-->
|
||||||
<style type="text/css" rel="stylesheet" media="all">
|
<style type="text/css" rel="stylesheet" media="all">
|
||||||
/* Base ------------------------------ */
|
/* Base ------------------------------ */
|
||||||
|
|
||||||
@import url("https://fonts.googleapis.com/css?family=Nunito+Sans:400,700&display=swap");
|
@import url("https://fonts.googleapis.com/css?family=Nunito+Sans:400,700&display=swap");
|
||||||
body {
|
body {
|
||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
@@ -22,19 +22,25 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
-webkit-text-size-adjust: none;
|
-webkit-text-size-adjust: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: #3869D4;
|
color: #3869D4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a.nohighlight {
|
||||||
|
color: inherit !important;
|
||||||
|
text-decoration: none !important;
|
||||||
|
cursor: default !important;
|
||||||
|
}
|
||||||
|
|
||||||
a img {
|
a img {
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
td {
|
td {
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
.preheader {
|
.preheader {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
@@ -47,13 +53,13 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
/* Type ------------------------------ */
|
/* Type ------------------------------ */
|
||||||
|
|
||||||
body,
|
body,
|
||||||
td,
|
td,
|
||||||
th {
|
th {
|
||||||
font-family: "Nunito Sans", Helvetica, Arial, sans-serif;
|
font-family: "Nunito Sans", Helvetica, Arial, sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
color: #333333;
|
color: #333333;
|
||||||
@@ -61,7 +67,7 @@
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
color: #333333;
|
color: #333333;
|
||||||
@@ -69,7 +75,7 @@
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
color: #333333;
|
color: #333333;
|
||||||
@@ -77,12 +83,12 @@
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
td,
|
td,
|
||||||
th {
|
th {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
p,
|
p,
|
||||||
ul,
|
ul,
|
||||||
ol,
|
ol,
|
||||||
@@ -91,25 +97,25 @@
|
|||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
line-height: 1.625;
|
line-height: 1.625;
|
||||||
}
|
}
|
||||||
|
|
||||||
p.sub {
|
p.sub {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
/* Utilities ------------------------------ */
|
/* Utilities ------------------------------ */
|
||||||
|
|
||||||
.align-right {
|
.align-right {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
.align-left {
|
.align-left {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.align-center {
|
.align-center {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
/* Buttons ------------------------------ */
|
/* Buttons ------------------------------ */
|
||||||
|
|
||||||
.button {
|
.button {
|
||||||
background-color: #3869D4;
|
background-color: #3869D4;
|
||||||
border-top: 10px solid #3869D4;
|
border-top: 10px solid #3869D4;
|
||||||
@@ -124,7 +130,7 @@
|
|||||||
-webkit-text-size-adjust: none;
|
-webkit-text-size-adjust: none;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button--green {
|
.button--green {
|
||||||
background-color: #22BC66;
|
background-color: #22BC66;
|
||||||
border-top: 10px solid #22BC66;
|
border-top: 10px solid #22BC66;
|
||||||
@@ -132,7 +138,7 @@
|
|||||||
border-bottom: 10px solid #22BC66;
|
border-bottom: 10px solid #22BC66;
|
||||||
border-left: 18px solid #22BC66;
|
border-left: 18px solid #22BC66;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button--red {
|
.button--red {
|
||||||
background-color: #FF6136;
|
background-color: #FF6136;
|
||||||
border-top: 10px solid #FF6136;
|
border-top: 10px solid #FF6136;
|
||||||
@@ -140,7 +146,7 @@
|
|||||||
border-bottom: 10px solid #FF6136;
|
border-bottom: 10px solid #FF6136;
|
||||||
border-left: 18px solid #FF6136;
|
border-left: 18px solid #FF6136;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 500px) {
|
@media only screen and (max-width: 500px) {
|
||||||
.button {
|
.button {
|
||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
@@ -148,21 +154,21 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Attribute list ------------------------------ */
|
/* Attribute list ------------------------------ */
|
||||||
|
|
||||||
.attributes {
|
.attributes {
|
||||||
margin: 0 0 21px;
|
margin: 0 0 21px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.attributes_content {
|
.attributes_content {
|
||||||
background-color: #F4F4F7;
|
background-color: #F4F4F7;
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.attributes_item {
|
.attributes_item {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
/* Related Items ------------------------------ */
|
/* Related Items ------------------------------ */
|
||||||
|
|
||||||
.related {
|
.related {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@@ -171,31 +177,31 @@
|
|||||||
-premailer-cellpadding: 0;
|
-premailer-cellpadding: 0;
|
||||||
-premailer-cellspacing: 0;
|
-premailer-cellspacing: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.related_item {
|
.related_item {
|
||||||
padding: 10px 0;
|
padding: 10px 0;
|
||||||
color: #CBCCCF;
|
color: #CBCCCF;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
line-height: 18px;
|
line-height: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.related_item-title {
|
.related_item-title {
|
||||||
display: block;
|
display: block;
|
||||||
margin: .5em 0 0;
|
margin: .5em 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.related_item-thumb {
|
.related_item-thumb {
|
||||||
display: block;
|
display: block;
|
||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.related_heading {
|
.related_heading {
|
||||||
border-top: 1px solid #CBCCCF;
|
border-top: 1px solid #CBCCCF;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 25px 0 10px;
|
padding: 25px 0 10px;
|
||||||
}
|
}
|
||||||
/* Discount Code ------------------------------ */
|
/* Discount Code ------------------------------ */
|
||||||
|
|
||||||
.discount {
|
.discount {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@@ -206,33 +212,33 @@
|
|||||||
background-color: #F4F4F7;
|
background-color: #F4F4F7;
|
||||||
border: 2px dashed #CBCCCF;
|
border: 2px dashed #CBCCCF;
|
||||||
}
|
}
|
||||||
|
|
||||||
.discount_heading {
|
.discount_heading {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.discount_body {
|
.discount_body {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
}
|
}
|
||||||
/* Social Icons ------------------------------ */
|
/* Social Icons ------------------------------ */
|
||||||
|
|
||||||
.social {
|
.social {
|
||||||
width: auto;
|
width: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.social td {
|
.social td {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
width: auto;
|
width: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.social_icon {
|
.social_icon {
|
||||||
height: 20px;
|
height: 20px;
|
||||||
margin: 0 8px 10px 8px;
|
margin: 0 8px 10px 8px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
/* Data table ------------------------------ */
|
/* Data table ------------------------------ */
|
||||||
|
|
||||||
.purchase {
|
.purchase {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@@ -241,7 +247,7 @@
|
|||||||
-premailer-cellpadding: 0;
|
-premailer-cellpadding: 0;
|
||||||
-premailer-cellspacing: 0;
|
-premailer-cellspacing: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.purchase_content {
|
.purchase_content {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@@ -250,50 +256,50 @@
|
|||||||
-premailer-cellpadding: 0;
|
-premailer-cellpadding: 0;
|
||||||
-premailer-cellspacing: 0;
|
-premailer-cellspacing: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.purchase_item {
|
.purchase_item {
|
||||||
padding: 10px 0;
|
padding: 10px 0;
|
||||||
color: #51545E;
|
color: #51545E;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
line-height: 18px;
|
line-height: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.purchase_heading {
|
.purchase_heading {
|
||||||
padding-bottom: 8px;
|
padding-bottom: 8px;
|
||||||
border-bottom: 1px solid #EAEAEC;
|
border-bottom: 1px solid #EAEAEC;
|
||||||
}
|
}
|
||||||
|
|
||||||
.purchase_heading p {
|
.purchase_heading p {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
color: #85878E;
|
color: #85878E;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.purchase_footer {
|
.purchase_footer {
|
||||||
padding-top: 15px;
|
padding-top: 15px;
|
||||||
border-top: 1px solid #EAEAEC;
|
border-top: 1px solid #EAEAEC;
|
||||||
}
|
}
|
||||||
|
|
||||||
.purchase_total {
|
.purchase_total {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: #333333;
|
color: #333333;
|
||||||
}
|
}
|
||||||
|
|
||||||
.purchase_total--label {
|
.purchase_total--label {
|
||||||
padding: 0 15px 0 0;
|
padding: 0 15px 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
background-color: #F2F4F6;
|
background-color: #F2F4F6;
|
||||||
color: #51545E;
|
color: #51545E;
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
color: #51545E;
|
color: #51545E;
|
||||||
}
|
}
|
||||||
|
|
||||||
.email-wrapper {
|
.email-wrapper {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@@ -303,7 +309,7 @@
|
|||||||
-premailer-cellspacing: 0;
|
-premailer-cellspacing: 0;
|
||||||
background-color: #F2F4F6;
|
background-color: #F2F4F6;
|
||||||
}
|
}
|
||||||
|
|
||||||
.email-content {
|
.email-content {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@@ -313,16 +319,16 @@
|
|||||||
-premailer-cellspacing: 0;
|
-premailer-cellspacing: 0;
|
||||||
}
|
}
|
||||||
/* Masthead ----------------------- */
|
/* Masthead ----------------------- */
|
||||||
|
|
||||||
.email-masthead {
|
.email-masthead {
|
||||||
padding: 25px 0;
|
padding: 25px 0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.email-masthead_logo {
|
.email-masthead_logo {
|
||||||
width: 94px;
|
width: 94px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.email-masthead_name {
|
.email-masthead_name {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
@@ -331,7 +337,7 @@
|
|||||||
text-shadow: 0 1px 0 white;
|
text-shadow: 0 1px 0 white;
|
||||||
}
|
}
|
||||||
/* Body ------------------------------ */
|
/* Body ------------------------------ */
|
||||||
|
|
||||||
.email-body {
|
.email-body {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@@ -340,7 +346,7 @@
|
|||||||
-premailer-cellpadding: 0;
|
-premailer-cellpadding: 0;
|
||||||
-premailer-cellspacing: 0;
|
-premailer-cellspacing: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.email-body_inner {
|
.email-body_inner {
|
||||||
width: 570px;
|
width: 570px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
@@ -350,7 +356,7 @@
|
|||||||
-premailer-cellspacing: 0;
|
-premailer-cellspacing: 0;
|
||||||
background-color: #FFFFFF;
|
background-color: #FFFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
.email-footer {
|
.email-footer {
|
||||||
width: 570px;
|
width: 570px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
@@ -360,11 +366,11 @@
|
|||||||
-premailer-cellspacing: 0;
|
-premailer-cellspacing: 0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.email-footer p {
|
.email-footer p {
|
||||||
color: #A8AAAF;
|
color: #A8AAAF;
|
||||||
}
|
}
|
||||||
|
|
||||||
.body-action {
|
.body-action {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 30px auto;
|
margin: 30px auto;
|
||||||
@@ -374,25 +380,25 @@
|
|||||||
-premailer-cellspacing: 0;
|
-premailer-cellspacing: 0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.body-sub {
|
.body-sub {
|
||||||
margin-top: 25px;
|
margin-top: 25px;
|
||||||
padding-top: 25px;
|
padding-top: 25px;
|
||||||
border-top: 1px solid #EAEAEC;
|
border-top: 1px solid #EAEAEC;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content-cell {
|
.content-cell {
|
||||||
padding: 45px;
|
padding: 45px;
|
||||||
}
|
}
|
||||||
/*Media Queries ------------------------------ */
|
/*Media Queries ------------------------------ */
|
||||||
|
|
||||||
@media only screen and (max-width: 600px) {
|
@media only screen and (max-width: 600px) {
|
||||||
.email-body_inner,
|
.email-body_inner,
|
||||||
.email-footer {
|
.email-footer {
|
||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
body,
|
body,
|
||||||
.email-body,
|
.email-body,
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ async function bootstrap() {
|
|||||||
console.log(`Port: ${configService.get('PORT')}`);
|
console.log(`Port: ${configService.get('PORT')}`);
|
||||||
|
|
||||||
checkEnvironmentAuthProvider(
|
checkEnvironmentAuthProvider(
|
||||||
configService.get('VITE_ALLOWED_AUTH_PROVIDERS'),
|
configService.get('INFRA.VITE_ALLOWED_AUTH_PROVIDERS') ??
|
||||||
|
configService.get('VITE_ALLOWED_AUTH_PROVIDERS'),
|
||||||
);
|
);
|
||||||
|
|
||||||
app.use(
|
app.use(
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
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 {}
|
||||||
58
packages/hoppscotch-backend/src/posthog/posthog.service.ts
Normal file
58
packages/hoppscotch-backend/src/posthog/posthog.service.ts
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
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');
|
||||||
|
}
|
||||||
|
}
|
||||||
14
packages/hoppscotch-backend/src/team-collection/helper.ts
Normal file
14
packages/hoppscotch-backend/src/team-collection/helper.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
// 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;
|
||||||
|
};
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import { Controller, Get, 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';
|
||||||
|
|
||||||
|
@UseGuards(ThrottlerBehindProxyGuard)
|
||||||
|
@Controller({ path: 'team-collection', version: '1' })
|
||||||
|
export class TeamCollectionController {
|
||||||
|
constructor(private readonly teamCollectionService: TeamCollectionService) {}
|
||||||
|
|
||||||
|
@Get('search/:teamID/:searchQuery')
|
||||||
|
@RequiresTeamRole(
|
||||||
|
TeamMemberRole.VIEWER,
|
||||||
|
TeamMemberRole.EDITOR,
|
||||||
|
TeamMemberRole.OWNER,
|
||||||
|
)
|
||||||
|
@UseGuards(JwtAuthGuard, RESTTeamMemberGuard)
|
||||||
|
async searchByTitle(
|
||||||
|
@Param('searchQuery') searchQuery: string,
|
||||||
|
@Param('teamID') teamID: string,
|
||||||
|
@Query('take') take: string,
|
||||||
|
@Query('skip') skip: string,
|
||||||
|
) {
|
||||||
|
const res = await this.teamCollectionService.searchByTitle(
|
||||||
|
searchQuery,
|
||||||
|
teamID,
|
||||||
|
parseInt(take),
|
||||||
|
parseInt(skip),
|
||||||
|
);
|
||||||
|
if (E.isLeft(res)) throwHTTPErr(res.left);
|
||||||
|
return res.right;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ 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],
|
||||||
@@ -15,5 +16,6 @@ import { PubSubModule } from '../pubsub/pubsub.module';
|
|||||||
GqlCollectionTeamMemberGuard,
|
GqlCollectionTeamMemberGuard,
|
||||||
],
|
],
|
||||||
exports: [TeamCollectionService, GqlCollectionTeamMemberGuard],
|
exports: [TeamCollectionService, GqlCollectionTeamMemberGuard],
|
||||||
|
controllers: [TeamCollectionController],
|
||||||
})
|
})
|
||||||
export class TeamCollectionModule {}
|
export class TeamCollectionModule {}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { HttpStatus, 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,6 +14,10 @@ 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 { isValidLength } from 'src/utils';
|
import { isValidLength } from 'src/utils';
|
||||||
@@ -22,6 +26,9 @@ 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 {
|
||||||
@@ -1056,4 +1063,266 @@ 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 titlesearch @@ to_tsquery(${searchQuery})
|
||||||
|
order by ts_rank(titlesearch,to_tsquery(${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 titlesearch @@ to_tsquery(${searchQuery})
|
||||||
|
order by ts_rank(titlesearch,to_tsquery(${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) {
|
||||||
|
const collection = parentCollections.filter((item) => item.id === id)[0];
|
||||||
|
if (collection.parentID == null) {
|
||||||
|
return {
|
||||||
|
id: collection.id,
|
||||||
|
title: collection.title,
|
||||||
|
type: 'collection',
|
||||||
|
path: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = {
|
||||||
|
id: collection.id,
|
||||||
|
title: collection.title,
|
||||||
|
type: 'collection',
|
||||||
|
path: findChildren(collection.parentID),
|
||||||
|
};
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parentCollections.length > 0) {
|
||||||
|
if (parentCollections[0].parentID == null) {
|
||||||
|
return {
|
||||||
|
id: parentCollections[0].id,
|
||||||
|
title: parentCollections[0].title,
|
||||||
|
type: 'collection',
|
||||||
|
path: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: parentCollections[0].id,
|
||||||
|
title: parentCollections[0].title,
|
||||||
|
type: 'collection',
|
||||||
|
path: findChildren(parentCollections[0].parentID),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
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 });
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
// 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,26 +4,23 @@ 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',
|
||||||
export enum InfraConfigEnumForClient {
|
ANALYTICS_USER_ID = 'ANALYTICS_USER_ID',
|
||||||
MAILER_SMTP_URL = 'MAILER_SMTP_URL',
|
IS_FIRST_TIME_INFRA_SETUP = 'IS_FIRST_TIME_INFRA_SETUP',
|
||||||
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',
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { HttpStatus } from '@nestjs/common';
|
import { HttpStatus } from '@nestjs/common';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Custom interface to handle errors specific to Auth module
|
** Custom interface to handle errors for REST modules such as Auth, Admin modules
|
||||||
** 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 AuthError = {
|
export type RESTError = {
|
||||||
message: string;
|
message: string;
|
||||||
statusCode: HttpStatus;
|
statusCode: HttpStatus;
|
||||||
};
|
};
|
||||||
@@ -17,3 +17,21 @@ 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,3 +56,22 @@ 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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { JSON_INVALID, USER_NOT_FOUND } from 'src/errors';
|
import { JSON_INVALID, USERS_NOT_FOUND, USER_NOT_FOUND } 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';
|
||||||
@@ -176,6 +176,26 @@ 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);
|
||||||
@@ -414,6 +434,54 @@ 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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
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);
|
||||||
@@ -435,6 +503,36 @@ 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);
|
||||||
@@ -556,4 +654,17 @@ 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,13 +8,14 @@ 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 { USER_NOT_FOUND } from 'src/errors';
|
import { USERS_NOT_FOUND, USER_NOT_FOUND } 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 {
|
||||||
@@ -88,6 +89,20 @@ 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
|
||||||
*
|
*
|
||||||
@@ -269,6 +284,30 @@ 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) {
|
||||||
|
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
|
||||||
@@ -286,6 +325,7 @@ 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({
|
||||||
@@ -296,6 +336,43 @@ 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
|
||||||
@@ -326,6 +403,23 @@ 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
|
||||||
@@ -444,4 +538,22 @@ 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 } from '@nestjs/common';
|
import { ExecutionContext, HttpException } 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,6 +16,7 @@ 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.
|
||||||
@@ -27,6 +28,15 @@ 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.
|
||||||
@@ -131,6 +141,28 @@ export const validateEmail = (email: string) => {
|
|||||||
).test(email);
|
).test(email);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Regular expressions for supported address object formats by nodemailer
|
||||||
|
// check out for more info https://nodemailer.com/message/addresses
|
||||||
|
const emailRegex1 = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
|
||||||
|
const emailRegex2 =
|
||||||
|
/^[\w\s]* <([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})>$/;
|
||||||
|
const emailRegex3 =
|
||||||
|
/^"[\w\s]+" <([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})>$/;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks to see if the SMTP email is valid or not
|
||||||
|
* @param email
|
||||||
|
* @returns A Boolean depending on the format of the email
|
||||||
|
*/
|
||||||
|
export const validateSMTPEmail = (email: string) => {
|
||||||
|
// Check if the input matches any of the formats
|
||||||
|
return (
|
||||||
|
emailRegex1.test(email) ||
|
||||||
|
emailRegex2.test(email) ||
|
||||||
|
emailRegex3.test(email)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks to see if the URL is valid or not
|
* Checks to see if the URL is valid or not
|
||||||
* @param url The URL to validate
|
* @param url The URL to validate
|
||||||
@@ -151,6 +183,16 @@ 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
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
// * The entry point of the CLI
|
|
||||||
require("../dist").cli(process.argv);
|
|
||||||
6
packages/hoppscotch-cli/bin/hopp.js
Executable file
6
packages/hoppscotch-cli/bin/hopp.js
Executable file
@@ -0,0 +1,6 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
// * The entry point of the CLI
|
||||||
|
|
||||||
|
import { cli } from "../dist/index.js";
|
||||||
|
|
||||||
|
cli(process.argv);
|
||||||
@@ -1,11 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@hoppscotch/cli",
|
"name": "@hoppscotch/cli",
|
||||||
"version": "0.4.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"
|
"hopp": "bin/hopp.js"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
@@ -39,27 +40,31 @@
|
|||||||
},
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"private": false,
|
"private": false,
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^1.6.6",
|
||||||
|
"chalk": "^5.3.0",
|
||||||
|
"commander": "^11.1.0",
|
||||||
|
"lodash-es": "^4.17.21",
|
||||||
|
"qs": "^6.11.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.3.92",
|
"@swc/core": "^1.3.105",
|
||||||
"@types/jest": "^29.5.5",
|
"@types/jest": "^29.5.11",
|
||||||
"@types/lodash": "^4.14.199",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@types/qs": "^6.9.8",
|
"@types/qs": "^6.9.11",
|
||||||
"axios": "^0.21.4",
|
"fp-ts": "^2.16.2",
|
||||||
"chalk": "^4.1.2",
|
|
||||||
"commander": "^11.0.0",
|
|
||||||
"esm": "^3.2.25",
|
|
||||||
"fp-ts": "^2.16.1",
|
|
||||||
"io-ts": "^2.2.20",
|
|
||||||
"jest": "^29.7.0",
|
"jest": "^29.7.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"prettier": "^3.0.3",
|
"prettier": "^3.2.4",
|
||||||
"qs": "^6.11.2",
|
"qs": "^6.11.2",
|
||||||
"ts-jest": "^29.1.1",
|
"ts-jest": "^29.1.2",
|
||||||
"tsup": "^7.2.0",
|
"tsup": "^8.0.1",
|
||||||
"typescript": "^5.2.2",
|
"typescript": "^5.3.3",
|
||||||
|
"verzod": "^0.2.2",
|
||||||
"zod": "^3.22.4"
|
"zod": "^3.22.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,140 +1,274 @@
|
|||||||
import { ExecException } from "child_process";
|
import { ExecException } from "child_process";
|
||||||
|
|
||||||
import { HoppErrorCode } from "../../types/errors";
|
import { HoppErrorCode } from "../../types/errors";
|
||||||
import { execAsync, getErrorCode, getTestJsonFilePath } from "../utils";
|
import { runCLI, getErrorCode, getTestJsonFilePath } from "../utils";
|
||||||
|
|
||||||
describe("Test 'hopp test <file>' command:", () => {
|
describe("Test `hopp test <file>` command:", () => {
|
||||||
test("No collection file path provided.", async () => {
|
describe("Argument parsing", () => {
|
||||||
const cmd = `node ./bin/hopp test`;
|
test("Errors with the code `INVALID_ARGUMENT` for not supplying enough arguments", async () => {
|
||||||
const { stderr } = await execAsync(cmd);
|
const args = "test";
|
||||||
const out = getErrorCode(stderr);
|
const { stderr } = await runCLI(args);
|
||||||
|
|
||||||
expect(out).toBe<HoppErrorCode>("INVALID_ARGUMENT");
|
const out = getErrorCode(stderr);
|
||||||
});
|
expect(out).toBe<HoppErrorCode>("INVALID_ARGUMENT");
|
||||||
|
});
|
||||||
|
|
||||||
test("Collection file not found.", async () => {
|
test("Errors with the code `INVALID_ARGUMENT` for an invalid command", async () => {
|
||||||
const cmd = `node ./bin/hopp test notfound.json`;
|
const args = "invalid-arg";
|
||||||
const { stderr } = await execAsync(cmd);
|
const { stderr } = await runCLI(args);
|
||||||
const out = getErrorCode(stderr);
|
|
||||||
|
|
||||||
expect(out).toBe<HoppErrorCode>("FILE_NOT_FOUND");
|
const out = getErrorCode(stderr);
|
||||||
});
|
expect(out).toBe<HoppErrorCode>("INVALID_ARGUMENT");
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
test("Collection file is invalid JSON.", async () => {
|
describe("Supplied collection export file validations", () => {
|
||||||
const cmd = `node ./bin/hopp test ${getTestJsonFilePath(
|
test("Errors with the code `FILE_NOT_FOUND` if the supplied collection export file doesn't exist", async () => {
|
||||||
"malformed-collection.json"
|
const args = "test notfound.json";
|
||||||
)}`;
|
const { stderr } = await runCLI(args);
|
||||||
const { stderr } = await execAsync(cmd);
|
|
||||||
const out = getErrorCode(stderr);
|
|
||||||
|
|
||||||
expect(out).toBe<HoppErrorCode>("UNKNOWN_ERROR");
|
const out = getErrorCode(stderr);
|
||||||
});
|
expect(out).toBe<HoppErrorCode>("FILE_NOT_FOUND");
|
||||||
|
});
|
||||||
|
|
||||||
test("Malformed collection file.", async () => {
|
test("Errors with the code UNKNOWN_ERROR if the supplied collection export file content isn't valid JSON", async () => {
|
||||||
const cmd = `node ./bin/hopp test ${getTestJsonFilePath(
|
const args = `test ${getTestJsonFilePath("malformed-coll.json", "collection")}`;
|
||||||
"malformed-collection2.json"
|
const { stderr } = await runCLI(args);
|
||||||
)}`;
|
|
||||||
const { stderr } = await execAsync(cmd);
|
|
||||||
const out = getErrorCode(stderr);
|
|
||||||
|
|
||||||
expect(out).toBe<HoppErrorCode>("MALFORMED_COLLECTION");
|
const out = getErrorCode(stderr);
|
||||||
});
|
expect(out).toBe<HoppErrorCode>("UNKNOWN_ERROR");
|
||||||
|
});
|
||||||
|
|
||||||
test("Invalid arguement.", async () => {
|
test("Errors with the code `MALFORMED_COLLECTION` if the supplied collection export file content is malformed", async () => {
|
||||||
const cmd = `node ./bin/hopp invalid-arg`;
|
const args = `test ${getTestJsonFilePath("malformed-coll-2.json", "collection")}`;
|
||||||
const { stderr } = await execAsync(cmd);
|
const { stderr } = await runCLI(args);
|
||||||
const out = getErrorCode(stderr);
|
|
||||||
|
|
||||||
expect(out).toBe<HoppErrorCode>("INVALID_ARGUMENT");
|
const out = getErrorCode(stderr);
|
||||||
});
|
expect(out).toBe<HoppErrorCode>("MALFORMED_COLLECTION");
|
||||||
|
});
|
||||||
|
|
||||||
test("Collection file not JSON type.", async () => {
|
test("Errors with the code `INVALID_FILE_TYPE` if the supplied collection export file doesn't end with the `.json` extension", async () => {
|
||||||
const cmd = `node ./bin/hopp test ${getTestJsonFilePath("notjson.txt")}`;
|
const args = `test ${getTestJsonFilePath("notjson-coll.txt", "collection")}`;
|
||||||
const { stderr } = await execAsync(cmd);
|
const { stderr } = await runCLI(args);
|
||||||
const out = getErrorCode(stderr);
|
|
||||||
|
|
||||||
expect(out).toBe<HoppErrorCode>("INVALID_FILE_TYPE");
|
const out = getErrorCode(stderr);
|
||||||
});
|
expect(out).toBe<HoppErrorCode>("INVALID_FILE_TYPE");
|
||||||
|
});
|
||||||
|
|
||||||
test("Some errors occured (exit code 1).", async () => {
|
test("Fails if the collection file includes scripts with incorrect API usage and failed assertions", async () => {
|
||||||
const cmd = `node ./bin/hopp test ${getTestJsonFilePath("fails.json")}`;
|
const args = `test ${getTestJsonFilePath("fails-coll.json", "collection")}`;
|
||||||
const { error } = await execAsync(cmd);
|
const { error } = await runCLI(args);
|
||||||
|
|
||||||
expect(error).not.toBeNull();
|
expect(error).not.toBeNull();
|
||||||
expect(error).toMatchObject(<ExecException>{
|
expect(error).toMatchObject(<ExecException>{
|
||||||
code: 1,
|
code: 1,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test("No errors occured (exit code 0).", async () => {
|
test("Successfully processes a supplied collection export file of the expected format", async () => {
|
||||||
const cmd = `node ./bin/hopp test ${getTestJsonFilePath("passes.json")}`;
|
const args = `test ${getTestJsonFilePath("passes-coll.json", "collection")}`;
|
||||||
const { error } = await execAsync(cmd);
|
const { error } = await runCLI(args);
|
||||||
|
|
||||||
|
expect(error).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Successfully inherits headers and authorization set at the root collection", async () => {
|
||||||
|
const args = `test ${getTestJsonFilePath(
|
||||||
|
"collection-level-headers-auth-coll.json", "collection"
|
||||||
|
)}`;
|
||||||
|
const { error } = await runCLI(args);
|
||||||
|
|
||||||
|
expect(error).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Persists environment variables set in the pre-request script for consumption in the test script", async () => {
|
||||||
|
const args = `test ${getTestJsonFilePath(
|
||||||
|
"pre-req-script-env-var-persistence-coll.json", "collection"
|
||||||
|
)}`;
|
||||||
|
const { error } = await runCLI(args);
|
||||||
|
|
||||||
expect(error).toBeNull();
|
expect(error).toBeNull();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Test 'hopp test <file> --env <file>' command:", () => {
|
describe("Test `hopp test <file> --env <file>` command:", () => {
|
||||||
const VALID_TEST_CMD = `node ./bin/hopp test ${getTestJsonFilePath(
|
describe("Supplied environment export file validations", () => {
|
||||||
"passes.json"
|
const VALID_TEST_ARGS = `test ${getTestJsonFilePath("passes-coll.json", "collection")}`;
|
||||||
)}`;
|
|
||||||
|
test("Errors with the code `INVALID_ARGUMENT` if no file is supplied", async () => {
|
||||||
|
const args = `${VALID_TEST_ARGS} --env`;
|
||||||
|
const { stderr } = await runCLI(args);
|
||||||
|
|
||||||
|
const out = getErrorCode(stderr);
|
||||||
|
expect(out).toBe<HoppErrorCode>("INVALID_ARGUMENT");
|
||||||
|
});
|
||||||
|
|
||||||
|
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(
|
||||||
|
"notjson-coll.txt", "collection"
|
||||||
|
)}`;
|
||||||
|
const { stderr } = await runCLI(args);
|
||||||
|
|
||||||
|
const out = getErrorCode(stderr);
|
||||||
|
expect(out).toBe<HoppErrorCode>("INVALID_FILE_TYPE");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Errors with the code `FILE_NOT_FOUND` if the supplied environment export file doesn't exist", async () => {
|
||||||
|
const args = `${VALID_TEST_ARGS} --env notfound.json`;
|
||||||
|
const { stderr } = await runCLI(args);
|
||||||
|
|
||||||
|
const out = getErrorCode(stderr);
|
||||||
|
expect(out).toBe<HoppErrorCode>("FILE_NOT_FOUND");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Errors with the code `MALFORMED_ENV_FILE` on supplying a malformed environment export file", async () => {
|
||||||
|
const ENV_PATH = getTestJsonFilePath("malformed-envs.json", "environment");
|
||||||
|
const args = `${VALID_TEST_ARGS} --env ${ENV_PATH}`;
|
||||||
|
const { stderr } = await runCLI(args);
|
||||||
|
|
||||||
|
const out = getErrorCode(stderr);
|
||||||
|
expect(out).toBe<HoppErrorCode>("MALFORMED_ENV_FILE");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Errors with the code `BULK_ENV_FILE` on supplying an environment export file based on the bulk environment export format", async () => {
|
||||||
|
const ENV_PATH = getTestJsonFilePath("bulk-envs.json", "environment");
|
||||||
|
const args = `${VALID_TEST_ARGS} --env ${ENV_PATH}`;
|
||||||
|
const { stderr } = await runCLI(args);
|
||||||
|
|
||||||
|
const out = getErrorCode(stderr);
|
||||||
|
expect(out).toBe<HoppErrorCode>("BULK_ENV_FILE");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Successfully resolves values from the supplied environment export file", async () => {
|
||||||
|
const TESTS_PATH = getTestJsonFilePath("env-flag-tests-coll.json", "collection");
|
||||||
|
const ENV_PATH = getTestJsonFilePath("env-flag-envs.json", "environment");
|
||||||
|
const args = `test ${TESTS_PATH} --env ${ENV_PATH}`;
|
||||||
|
|
||||||
|
const { error } = await runCLI(args);
|
||||||
|
expect(error).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Successfully resolves environment variables referenced in the request body", async () => {
|
||||||
|
const COLL_PATH = getTestJsonFilePath("req-body-env-vars-coll.json", "collection");
|
||||||
|
const ENVS_PATH = getTestJsonFilePath("req-body-env-vars-envs.json", "environment");
|
||||||
|
const args = `test ${COLL_PATH} --env ${ENVS_PATH}`;
|
||||||
|
|
||||||
|
const { error } = await runCLI(args);
|
||||||
|
expect(error).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Works with shorth `-e` flag", async () => {
|
||||||
|
const TESTS_PATH = getTestJsonFilePath("env-flag-tests-coll.json", "collection");
|
||||||
|
const ENV_PATH = getTestJsonFilePath("env-flag-envs.json", "environment");
|
||||||
|
const args = `test ${TESTS_PATH} -e ${ENV_PATH}`;
|
||||||
|
|
||||||
|
const { error } = await runCLI(args);
|
||||||
|
expect(error).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Secret environment variables", () => {
|
||||||
|
jest.setTimeout(10000);
|
||||||
|
|
||||||
|
// 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 () => {
|
||||||
|
const env = {
|
||||||
|
...process.env,
|
||||||
|
secretBearerToken: "test-token",
|
||||||
|
secretBasicAuthUsername: "test-user",
|
||||||
|
secretBasicAuthPassword: "test-pass",
|
||||||
|
secretQueryParamValue: "secret-query-param-value",
|
||||||
|
secretBodyValue: "secret-body-value",
|
||||||
|
secretHeaderValue: "secret-header-value",
|
||||||
|
};
|
||||||
|
|
||||||
|
const COLL_PATH = getTestJsonFilePath("secret-envs-coll.json", "collection");
|
||||||
|
const ENVS_PATH = getTestJsonFilePath("secret-envs.json", "environment");
|
||||||
|
const args = `test ${COLL_PATH} --env ${ENVS_PATH}`;
|
||||||
|
|
||||||
|
const { error, stdout } = await runCLI(args, { env });
|
||||||
|
|
||||||
|
expect(stdout).toContain(
|
||||||
|
"https://httpbin.org/basic-auth/*********/*********"
|
||||||
|
);
|
||||||
|
expect(error).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 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 () => {
|
||||||
|
const COLL_PATH = getTestJsonFilePath("secret-envs-coll.json", "collection");
|
||||||
|
const ENVS_PATH = getTestJsonFilePath("secret-supplied-values-envs.json", "environment");
|
||||||
|
const args = `test ${COLL_PATH} --env ${ENVS_PATH}`;
|
||||||
|
|
||||||
|
const { error, stdout } = await runCLI(args);
|
||||||
|
|
||||||
|
expect(stdout).toContain(
|
||||||
|
"https://httpbin.org/basic-auth/*********/*********"
|
||||||
|
);
|
||||||
|
expect(error).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 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 () => {
|
||||||
|
const COLL_PATH = getTestJsonFilePath(
|
||||||
|
"secret-envs-persistence-coll.json", "collection"
|
||||||
|
);
|
||||||
|
const ENVS_PATH = getTestJsonFilePath("secret-supplied-values-envs.json", "environment");
|
||||||
|
const args = `test ${COLL_PATH} --env ${ENVS_PATH}`;
|
||||||
|
|
||||||
|
const { error, stdout } = await runCLI(args);
|
||||||
|
|
||||||
|
expect(stdout).toContain(
|
||||||
|
"https://httpbin.org/basic-auth/*********/*********"
|
||||||
|
);
|
||||||
|
expect(error).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
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(
|
||||||
|
"secret-envs-persistence-scripting-coll.json", "collection"
|
||||||
|
);
|
||||||
|
const ENVS_PATH = getTestJsonFilePath(
|
||||||
|
"secret-envs-persistence-scripting-envs.json", "environment"
|
||||||
|
);
|
||||||
|
const args = `test ${COLL_PATH} --env ${ENVS_PATH}`;
|
||||||
|
|
||||||
|
const { error } = await runCLI(args);
|
||||||
|
expect(error).toBeNull();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Test `hopp test <file> --delay <delay_in_ms>` command:", () => {
|
||||||
|
const VALID_TEST_ARGS = `test ${getTestJsonFilePath("passes-coll.json", "collection")}`;
|
||||||
|
|
||||||
|
test("Errors with the code `INVALID_ARGUMENT` on not supplying a delay value", async () => {
|
||||||
|
const args = `${VALID_TEST_ARGS} --delay`;
|
||||||
|
const { stderr } = await runCLI(args);
|
||||||
|
|
||||||
test("No env file path provided.", async () => {
|
|
||||||
const cmd = `${VALID_TEST_CMD} --env`;
|
|
||||||
const { stderr } = await execAsync(cmd);
|
|
||||||
const out = getErrorCode(stderr);
|
const out = getErrorCode(stderr);
|
||||||
|
|
||||||
expect(out).toBe<HoppErrorCode>("INVALID_ARGUMENT");
|
expect(out).toBe<HoppErrorCode>("INVALID_ARGUMENT");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("ENV file not JSON type.", async () => {
|
test("Errors with the code `INVALID_ARGUMENT` on supplying an invalid delay value", async () => {
|
||||||
const cmd = `${VALID_TEST_CMD} --env ${getTestJsonFilePath("notjson.txt")}`;
|
const args = `${VALID_TEST_ARGS} --delay 'NaN'`;
|
||||||
const { stderr } = await execAsync(cmd);
|
const { stderr } = await runCLI(args);
|
||||||
const out = getErrorCode(stderr);
|
|
||||||
|
|
||||||
expect(out).toBe<HoppErrorCode>("INVALID_FILE_TYPE");
|
const out = getErrorCode(stderr);
|
||||||
|
expect(out).toBe<HoppErrorCode>("INVALID_ARGUMENT");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("ENV file not found.", async () => {
|
test("Successfully performs delayed request execution for a valid delay value", async () => {
|
||||||
const cmd = `${VALID_TEST_CMD} --env notfound.json`;
|
const args = `${VALID_TEST_ARGS} --delay 1`;
|
||||||
const { stderr } = await execAsync(cmd);
|
const { error } = await runCLI(args);
|
||||||
const out = getErrorCode(stderr);
|
|
||||||
|
|
||||||
expect(out).toBe<HoppErrorCode>("FILE_NOT_FOUND");
|
expect(error).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("No errors occured (exit code 0).", async () => {
|
test("Works with the short `-d` flag", async () => {
|
||||||
const TESTS_PATH = getTestJsonFilePath("env-flag-tests.json");
|
const args = `${VALID_TEST_ARGS} -d 1`;
|
||||||
const ENV_PATH = getTestJsonFilePath("env-flag-envs.json");
|
const { error } = await runCLI(args);
|
||||||
const cmd = `node ./bin/hopp test ${TESTS_PATH} --env ${ENV_PATH}`;
|
|
||||||
const { error, stdout } = await execAsync(cmd);
|
|
||||||
|
|
||||||
expect(error).toBeNull();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("Test 'hopp test <file> --delay <delay_in_ms>' command:", () => {
|
|
||||||
const VALID_TEST_CMD = `node ./bin/hopp test ${getTestJsonFilePath(
|
|
||||||
"passes.json"
|
|
||||||
)}`;
|
|
||||||
|
|
||||||
test("No value passed to delay flag.", async () => {
|
|
||||||
const cmd = `${VALID_TEST_CMD} --delay`;
|
|
||||||
const { stderr } = await execAsync(cmd);
|
|
||||||
const out = getErrorCode(stderr);
|
|
||||||
|
|
||||||
expect(out).toBe<HoppErrorCode>("INVALID_ARGUMENT");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("Invalid value passed to delay flag.", async () => {
|
|
||||||
const cmd = `${VALID_TEST_CMD} --delay 'NaN'`;
|
|
||||||
const { stderr } = await execAsync(cmd);
|
|
||||||
const out = getErrorCode(stderr);
|
|
||||||
expect(out).toBe<HoppErrorCode>("INVALID_ARGUMENT");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("Valid value passed to delay flag.", async () => {
|
|
||||||
const cmd = `${VALID_TEST_CMD} --delay 1`;
|
|
||||||
const { error } = await execAsync(cmd);
|
|
||||||
|
|
||||||
expect(error).toBeNull();
|
expect(error).toBeNull();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,227 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"v": 1,
|
||||||
|
"name": "CollectionA",
|
||||||
|
"folders": [
|
||||||
|
{
|
||||||
|
"v": 1,
|
||||||
|
"name": "FolderA",
|
||||||
|
"folders": [
|
||||||
|
{
|
||||||
|
"v": 1,
|
||||||
|
"name": "FolderB",
|
||||||
|
"folders": [
|
||||||
|
{
|
||||||
|
"v": 1,
|
||||||
|
"name": "FolderC",
|
||||||
|
"folders": [],
|
||||||
|
"requests": [
|
||||||
|
{
|
||||||
|
"v": "2",
|
||||||
|
"endpoint": "https://echo.hoppscotch.io",
|
||||||
|
"name": "RequestD",
|
||||||
|
"params": [],
|
||||||
|
"headers": [
|
||||||
|
{
|
||||||
|
"active": true,
|
||||||
|
"key": "X-Test-Header",
|
||||||
|
"value": "Overriden at RequestD"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"method": "GET",
|
||||||
|
"auth": {
|
||||||
|
"authType": "basic",
|
||||||
|
"authActive": true,
|
||||||
|
"username": "username",
|
||||||
|
"password": "password"
|
||||||
|
},
|
||||||
|
"preRequestScript": "",
|
||||||
|
"testScript": "pw.test(\"Overrides auth and headers set at the parent folder\", ()=> {\n pw.expect(pw.response.body.headers[\"x-test-header\"]).toBe(\"Overriden at RequestD\");\n pw.expect(pw.response.body.headers[\"authorization\"]).toBe(\"Basic dXNlcm5hbWU6cGFzc3dvcmQ=\");\n});",
|
||||||
|
"body": {
|
||||||
|
"contentType": null,
|
||||||
|
"body": null
|
||||||
|
},
|
||||||
|
"requestVariables": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"auth": {
|
||||||
|
"authType": "inherit",
|
||||||
|
"authActive": true
|
||||||
|
},
|
||||||
|
"headers": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"requests": [
|
||||||
|
{
|
||||||
|
"v": "2",
|
||||||
|
"endpoint": "https://echo.hoppscotch.io",
|
||||||
|
"name": "RequestC",
|
||||||
|
"params": [],
|
||||||
|
"headers": [],
|
||||||
|
"method": "GET",
|
||||||
|
"auth": {
|
||||||
|
"authType": "inherit",
|
||||||
|
"authActive": true
|
||||||
|
},
|
||||||
|
"preRequestScript": "",
|
||||||
|
"testScript": "pw.test(\"Correctly inherits auth and headers from the parent folder\", ()=> {\n pw.expect(pw.response.body.headers[\"x-test-header\"]).toBe(\"Overriden at FolderB\");\n pw.expect(pw.response.body.headers[\"key\"]).toBe(\"test-key\");\n});",
|
||||||
|
"body": {
|
||||||
|
"contentType": null,
|
||||||
|
"body": null
|
||||||
|
},
|
||||||
|
"requestVariables": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"auth": {
|
||||||
|
"authType": "api-key",
|
||||||
|
"authActive": true,
|
||||||
|
"addTo": "Headers",
|
||||||
|
"key": "key",
|
||||||
|
"value": "test-key"
|
||||||
|
},
|
||||||
|
"headers": [
|
||||||
|
{
|
||||||
|
"active": true,
|
||||||
|
"key": "X-Test-Header",
|
||||||
|
"value": "Overriden at FolderB"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"requests": [
|
||||||
|
{
|
||||||
|
"v": "2",
|
||||||
|
"endpoint": "https://echo.hoppscotch.io",
|
||||||
|
"name": "RequestB",
|
||||||
|
"params": [],
|
||||||
|
"headers": [],
|
||||||
|
"method": "GET",
|
||||||
|
"auth": {
|
||||||
|
"authType": "inherit",
|
||||||
|
"authActive": true
|
||||||
|
},
|
||||||
|
"preRequestScript": "",
|
||||||
|
"testScript": "pw.test(\"Correctly inherits auth and headers from the parent folder\", ()=> {\n pw.expect(pw.response.body.headers[\"x-test-header\"]).toBe(\"Set at root collection\");\n pw.expect(pw.response.body.headers[\"authorization\"]).toBe(\"Bearer BearerToken\");\n});",
|
||||||
|
"body": {
|
||||||
|
"contentType": null,
|
||||||
|
"body": null
|
||||||
|
},
|
||||||
|
"requestVariables": [],
|
||||||
|
"id": "clpttpdq00003qp16kut6doqv"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"auth": {
|
||||||
|
"authType": "inherit",
|
||||||
|
"authActive": true
|
||||||
|
},
|
||||||
|
"headers": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"requests": [
|
||||||
|
{
|
||||||
|
"v": "2",
|
||||||
|
"endpoint": "https://echo.hoppscotch.io",
|
||||||
|
"name": "RequestA",
|
||||||
|
"params": [],
|
||||||
|
"headers": [],
|
||||||
|
"method": "GET",
|
||||||
|
"auth": {
|
||||||
|
"authType": "inherit",
|
||||||
|
"authActive": true
|
||||||
|
},
|
||||||
|
"preRequestScript": "",
|
||||||
|
"testScript": "pw.test(\"Correctly inherits auth and headers from the root collection\", ()=> {\n pw.expect(pw.response.body.headers[\"x-test-header\"]).toBe(\"Set at root collection\");\n pw.expect(pw.response.body.headers[\"authorization\"]).toBe(\"Bearer BearerToken\");\n});",
|
||||||
|
"body": {
|
||||||
|
"contentType": null,
|
||||||
|
"body": null
|
||||||
|
},
|
||||||
|
"requestVariables": [],
|
||||||
|
"id": "clpttpdq00003qp16kut6doqv"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"headers": [
|
||||||
|
{
|
||||||
|
"active": true,
|
||||||
|
"key": "X-Test-Header",
|
||||||
|
"value": "Set at root collection"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"auth": {
|
||||||
|
"authType": "bearer",
|
||||||
|
"authActive": true,
|
||||||
|
"token": "BearerToken"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"v": 1,
|
||||||
|
"name": "CollectionB",
|
||||||
|
"folders": [
|
||||||
|
{
|
||||||
|
"v": 1,
|
||||||
|
"name": "FolderA",
|
||||||
|
"folders": [],
|
||||||
|
"requests": [
|
||||||
|
{
|
||||||
|
"v": "2",
|
||||||
|
"endpoint": "https://echo.hoppscotch.io",
|
||||||
|
"name": "RequestB",
|
||||||
|
"params": [],
|
||||||
|
"headers": [],
|
||||||
|
"method": "GET",
|
||||||
|
"auth": {
|
||||||
|
"authType": "inherit",
|
||||||
|
"authActive": true
|
||||||
|
},
|
||||||
|
"preRequestScript": "",
|
||||||
|
"testScript": "pw.test(\"Correctly inherits auth and headers from the parent folder\", ()=> {\n pw.expect(pw.response.body.headers[\"x-test-header\"]).toBe(\"Set at root collection\");\n pw.expect(pw.response.body.headers[\"authorization\"]).toBe(\"Bearer BearerToken\");\n});",
|
||||||
|
"body": {
|
||||||
|
"contentType": null,
|
||||||
|
"body": null
|
||||||
|
},
|
||||||
|
"requestVariables": [],
|
||||||
|
"id": "clpttpdq00003qp16kut6doqv"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"auth": {
|
||||||
|
"authType": "inherit",
|
||||||
|
"authActive": true
|
||||||
|
},
|
||||||
|
"headers": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"requests": [
|
||||||
|
{
|
||||||
|
"v": "2",
|
||||||
|
"endpoint": "https://echo.hoppscotch.io",
|
||||||
|
"name": "RequestA",
|
||||||
|
"params": [],
|
||||||
|
"headers": [],
|
||||||
|
"method": "GET",
|
||||||
|
"auth": {
|
||||||
|
"authType": "inherit",
|
||||||
|
"authActive": true
|
||||||
|
},
|
||||||
|
"preRequestScript": "",
|
||||||
|
"testScript": "pw.test(\"Correctly inherits auth and headers from the root collection\", ()=> {\n pw.expect(pw.response.body.headers[\"x-test-header\"]).toBe(\"Set at root collection\");\n pw.expect(pw.response.body.headers[\"authorization\"]).toBe(\"Bearer BearerToken\");\n});",
|
||||||
|
"body": {
|
||||||
|
"contentType": null,
|
||||||
|
"body": null
|
||||||
|
},
|
||||||
|
"requestVariables": [],
|
||||||
|
"id": "clpttpdq00003qp16kut6doqv"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"headers": [
|
||||||
|
{
|
||||||
|
"active": true,
|
||||||
|
"key": "X-Test-Header",
|
||||||
|
"value": "Set at root collection"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"auth": {
|
||||||
|
"authType": "bearer",
|
||||||
|
"authActive": true,
|
||||||
|
"token": "BearerToken"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
"folders": [],
|
"folders": [],
|
||||||
"requests": [
|
"requests": [
|
||||||
{
|
{
|
||||||
"v": "1",
|
"v": "2",
|
||||||
"endpoint": "<<URL>>",
|
"endpoint": "<<URL>>",
|
||||||
"name": "test1",
|
"name": "test1",
|
||||||
"params": [],
|
"params": [],
|
||||||
@@ -16,7 +16,8 @@
|
|||||||
"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": "1",
|
"v": "2",
|
||||||
"endpoint": "https://echo.hoppscotch.io/<<HEADERS_TYPE1>>",
|
"endpoint": "https://echo.hoppscotch.io/<<HEADERS_TYPE1>>",
|
||||||
"name": "",
|
"name": "",
|
||||||
"params": [],
|
"params": [],
|
||||||
@@ -23,10 +23,11 @@
|
|||||||
"body": {
|
"body": {
|
||||||
"contentType": "application/json",
|
"contentType": "application/json",
|
||||||
"body": "{\n\"test\": \"<<HEADERS_TYPE1>>\"\n}"
|
"body": "{\n\"test\": \"<<HEADERS_TYPE1>>\"\n}"
|
||||||
}
|
},
|
||||||
|
"requestVariables": [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"v": "1",
|
"v": "2",
|
||||||
"endpoint": "https://echo.hoppscotch.dio/<<HEADERS_TYPE2>>",
|
"endpoint": "https://echo.hoppscotch.dio/<<HEADERS_TYPE2>>",
|
||||||
"name": "success",
|
"name": "success",
|
||||||
"params": [],
|
"params": [],
|
||||||
@@ -44,7 +45,8 @@
|
|||||||
"body": {
|
"body": {
|
||||||
"contentType": "application/json",
|
"contentType": "application/json",
|
||||||
"body": "{\n\"test\": \"<<HEADERS_TYPE2>>\"\n}"
|
"body": "{\n\"test\": \"<<HEADERS_TYPE2>>\"\n}"
|
||||||
}
|
},
|
||||||
|
"requestVariables": []
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -2,9 +2,9 @@
|
|||||||
{
|
{
|
||||||
"v": 1,
|
"v": 1,
|
||||||
"folders": [],
|
"folders": [],
|
||||||
"requests":
|
"requests":
|
||||||
{
|
{
|
||||||
"v": "1",
|
"v": "2",
|
||||||
"endpoint": "https://echo.hoppscotch.io/<<HEADERS_TYPE1>>",
|
"endpoint": "https://echo.hoppscotch.io/<<HEADERS_TYPE1>>",
|
||||||
"name": "fail",
|
"name": "fail",
|
||||||
"params": [],
|
"params": [],
|
||||||
@@ -22,10 +22,11 @@
|
|||||||
"body": {
|
"body": {
|
||||||
"contentType": "application/json",
|
"contentType": "application/json",
|
||||||
"body": "{\n\"test\": \"<<HEADERS_TYPE1>>\"\n}"
|
"body": "{\n\"test\": \"<<HEADERS_TYPE1>>\"\n}"
|
||||||
}
|
},
|
||||||
|
"requestVariables": [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"v": "1",
|
"v": "2",
|
||||||
"endpoint": "https://echo.hoppscotch.io/<<HEADERS_TYPE2>>",
|
"endpoint": "https://echo.hoppscotch.io/<<HEADERS_TYPE2>>",
|
||||||
"name": "success",
|
"name": "success",
|
||||||
"params": [],
|
"params": [],
|
||||||
@@ -43,7 +44,8 @@
|
|||||||
"body": {
|
"body": {
|
||||||
"contentType": "application/json",
|
"contentType": "application/json",
|
||||||
"body": "{\n\"test\": \"<<HEADERS_TYPE2>>\"\n}"
|
"body": "{\n\"test\": \"<<HEADERS_TYPE2>>\"\n}"
|
||||||
}
|
},
|
||||||
|
"requestVariables": []
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -2,9 +2,9 @@
|
|||||||
{
|
{
|
||||||
"v": 1,
|
"v": 1,
|
||||||
"folders": [],
|
"folders": [],
|
||||||
"requests":
|
"requests":
|
||||||
{
|
{
|
||||||
"v": "1",
|
"v": "2",
|
||||||
"endpoint": "https://echo.hoppscotch.io/<<HEADERS_TYPE1>>",
|
"endpoint": "https://echo.hoppscotch.io/<<HEADERS_TYPE1>>",
|
||||||
"name": "fail",
|
"name": "fail",
|
||||||
"params": [],
|
"params": [],
|
||||||
@@ -22,7 +22,8 @@
|
|||||||
"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": "1",
|
"v": "2",
|
||||||
"endpoint": "https://echo.hoppscotch.io/<<HEADERS_TYPE1>>",
|
"endpoint": "https://echo.hoppscotch.io/<<HEADERS_TYPE1>>",
|
||||||
"name": "",
|
"name": "",
|
||||||
"params": [],
|
"params": [],
|
||||||
@@ -23,10 +23,11 @@
|
|||||||
"body": {
|
"body": {
|
||||||
"contentType": "application/json",
|
"contentType": "application/json",
|
||||||
"body": "{\n\"test\": \"<<HEADERS_TYPE1>>\"\n}"
|
"body": "{\n\"test\": \"<<HEADERS_TYPE1>>\"\n}"
|
||||||
}
|
},
|
||||||
|
"requestVariables": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"v": "1",
|
"v": "2",
|
||||||
"endpoint": "https://echo.hoppscotch.io/<<HEADERS_TYPE2>>",
|
"endpoint": "https://echo.hoppscotch.io/<<HEADERS_TYPE2>>",
|
||||||
"name": "success",
|
"name": "success",
|
||||||
"params": [],
|
"params": [],
|
||||||
@@ -44,7 +45,8 @@
|
|||||||
"body": {
|
"body": {
|
||||||
"contentType": "application/json",
|
"contentType": "application/json",
|
||||||
"body": "{\n\"test\": \"<<HEADERS_TYPE2>>\"\n}"
|
"body": "{\n\"test\": \"<<HEADERS_TYPE2>>\"\n}"
|
||||||
}
|
},
|
||||||
|
"requestVariables": []
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"v": 2,
|
||||||
|
"name": "pre-req-script-env-var-persistence-coll",
|
||||||
|
"folders": [],
|
||||||
|
"requests": [
|
||||||
|
{
|
||||||
|
"v": "2",
|
||||||
|
"auth": { "authType": "none", "authActive": true },
|
||||||
|
"body": { "body": null, "contentType": null },
|
||||||
|
"name": "sample-req",
|
||||||
|
"method": "GET",
|
||||||
|
"params": [],
|
||||||
|
"headers": [],
|
||||||
|
"endpoint": "https://echo.hoppscotch.io",
|
||||||
|
"testScript": "pw.expect(pw.env.get(\"variable\")).toBe(\"value\")",
|
||||||
|
"preRequestScript": "pw.env.set(\"variable\", \"value\");",
|
||||||
|
"requestVariables": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"auth": { "authType": "inherit", "authActive": true },
|
||||||
|
"headers": []
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"v": 2,
|
||||||
|
"name": "Test environment variables in request body",
|
||||||
|
"folders": [],
|
||||||
|
"requests": [
|
||||||
|
{
|
||||||
|
"v": "2",
|
||||||
|
"name": "test-request",
|
||||||
|
"endpoint": "https://echo.hoppscotch.io",
|
||||||
|
"method": "POST",
|
||||||
|
"headers": [],
|
||||||
|
"params": [],
|
||||||
|
"auth": {
|
||||||
|
"authType": "none",
|
||||||
|
"authActive": true
|
||||||
|
},
|
||||||
|
"body": {
|
||||||
|
"contentType": "application/json",
|
||||||
|
"body": "{\n \"firstName\": \"<<firstName>>\",\n \"lastName\": \"<<lastName>>\",\n \"greetText\": \"<<salutation>>, <<fullName>>\",\n \"fullName\": \"<<fullName>>\",\n \"id\": \"<<id>>\"\n}"
|
||||||
|
},
|
||||||
|
"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});",
|
||||||
|
"requestVariables": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"auth": {
|
||||||
|
"authType": "none",
|
||||||
|
"authActive": true
|
||||||
|
},
|
||||||
|
"headers": []
|
||||||
|
}
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
{
|
||||||
|
"v": 2,
|
||||||
|
"name": "secret-envs-coll",
|
||||||
|
"folders": [],
|
||||||
|
"requests": [
|
||||||
|
{
|
||||||
|
"v": "2",
|
||||||
|
"auth": { "authType": "none", "authActive": true },
|
||||||
|
"body": { "body": null, "contentType": null },
|
||||||
|
"name": "test-secret-headers",
|
||||||
|
"method": "GET",
|
||||||
|
"params": [],
|
||||||
|
"headers": [
|
||||||
|
{
|
||||||
|
"key": "Secret-Header-Key",
|
||||||
|
"value": "<<secretHeaderValue>>",
|
||||||
|
"active": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"requestVariables": [],
|
||||||
|
"endpoint": "<<baseURL>>/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})",
|
||||||
|
"preRequestScript": "const secretHeaderValueFromPreReqScript = pw.env.get(\"secretHeaderValue\")\npw.env.set(\"secretHeaderValueFromPreReqScript\", secretHeaderValueFromPreReqScript)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"v": "2",
|
||||||
|
"auth": { "authType": "none", "authActive": true },
|
||||||
|
"body": {
|
||||||
|
"body": "{\n \"secretBodyKey\": \"<<secretBodyValue>>\"\n}",
|
||||||
|
"contentType": "application/json"
|
||||||
|
},
|
||||||
|
"name": "test-secret-body",
|
||||||
|
"method": "POST",
|
||||||
|
"params": [],
|
||||||
|
"headers": [],
|
||||||
|
"requestVariables": [],
|
||||||
|
"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(pw.response.body.json.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)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"v": "2",
|
||||||
|
"auth": { "authType": "none", "authActive": true },
|
||||||
|
"body": { "body": null, "contentType": null },
|
||||||
|
"name": "test-secret-query-params",
|
||||||
|
"method": "GET",
|
||||||
|
"params": [
|
||||||
|
{
|
||||||
|
"key": "secretQueryParamKey",
|
||||||
|
"value": "<<secretQueryParamValue>>",
|
||||||
|
"active": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"headers": [],
|
||||||
|
"requestVariables": [],
|
||||||
|
"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})",
|
||||||
|
"preRequestScript": "const secretQueryParamValueFromPreReqScript = pw.env.get(\"secretQueryParamValue\")\npw.env.set(\"secretQueryParamValueFromPreReqScript\", secretQueryParamValueFromPreReqScript)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"v": "2",
|
||||||
|
"auth": {
|
||||||
|
"authType": "basic",
|
||||||
|
"password": "<<secretBasicAuthPassword>>",
|
||||||
|
"username": "<<secretBasicAuthUsername>>",
|
||||||
|
"authActive": true
|
||||||
|
},
|
||||||
|
"body": { "body": null, "contentType": null },
|
||||||
|
"name": "test-secret-basic-auth",
|
||||||
|
"method": "GET",
|
||||||
|
"params": [],
|
||||||
|
"headers": [],
|
||||||
|
"requestVariables": [],
|
||||||
|
"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 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": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"v": "2",
|
||||||
|
"auth": {
|
||||||
|
"token": "<<secretBearerToken>>",
|
||||||
|
"authType": "bearer",
|
||||||
|
"password": "testpassword",
|
||||||
|
"username": "testuser",
|
||||||
|
"authActive": true
|
||||||
|
},
|
||||||
|
"body": { "body": null, "contentType": null },
|
||||||
|
"name": "test-secret-bearer-auth",
|
||||||
|
"method": "GET",
|
||||||
|
"params": [],
|
||||||
|
"headers": [],
|
||||||
|
"requestVariables": [],
|
||||||
|
"endpoint": "<<baseURL>>/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});",
|
||||||
|
"preRequestScript": "const secretBearerToken = pw.env.get(\"secretBearerToken\")\npw.env.set(\"preReqSecretBearerToken\", secretBearerToken)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"v": "2",
|
||||||
|
"auth": { "authType": "none", "authActive": true },
|
||||||
|
"body": { "body": null, "contentType": null },
|
||||||
|
"name": "test-secret-fallback",
|
||||||
|
"method": "GET",
|
||||||
|
"params": [],
|
||||||
|
"headers": [],
|
||||||
|
"requestVariables": [],
|
||||||
|
"endpoint": "<<baseURL>>",
|
||||||
|
"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": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"auth": { "authType": "inherit", "authActive": false },
|
||||||
|
"headers": []
|
||||||
|
}
|
||||||
@@ -0,0 +1,149 @@
|
|||||||
|
{
|
||||||
|
"v": 2,
|
||||||
|
"name": "secret-envs-setters-coll",
|
||||||
|
"folders": [],
|
||||||
|
"requests": [
|
||||||
|
{
|
||||||
|
"v": "2",
|
||||||
|
"auth": {
|
||||||
|
"authType": "none",
|
||||||
|
"authActive": true
|
||||||
|
},
|
||||||
|
"body": {
|
||||||
|
"body": null,
|
||||||
|
"contentType": null
|
||||||
|
},
|
||||||
|
"name": "test-secret-headers",
|
||||||
|
"method": "GET",
|
||||||
|
"params": [],
|
||||||
|
"requestVariables": [],
|
||||||
|
"headers": [
|
||||||
|
{
|
||||||
|
"key": "Secret-Header-Key",
|
||||||
|
"value": "<<secretHeaderValue>>",
|
||||||
|
"active": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"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})",
|
||||||
|
"preRequestScript": "pw.env.set(\"secretHeaderValue\", \"secret-header-value\")\n\nconst secretHeaderValueFromPreReqScript = pw.env.getResolve(\"secretHeaderValue\")\npw.env.set(\"secretHeaderValueFromPreReqScript\", secretHeaderValueFromPreReqScript)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"v": "2",
|
||||||
|
"auth": {
|
||||||
|
"authType": "none",
|
||||||
|
"authActive": true
|
||||||
|
},
|
||||||
|
"body": {
|
||||||
|
"body": null,
|
||||||
|
"contentType": null
|
||||||
|
},
|
||||||
|
"name": "test-secret-headers-overrides",
|
||||||
|
"method": "GET",
|
||||||
|
"params": [],
|
||||||
|
"requestVariables": [],
|
||||||
|
"headers": [
|
||||||
|
{
|
||||||
|
"key": "Secret-Header-Key",
|
||||||
|
"value": "<<secretHeaderValue>>",
|
||||||
|
"active": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"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})",
|
||||||
|
"preRequestScript": "pw.env.set(\"secretHeaderValue\", \"secret-header-value-overriden\")\n\nconst secretHeaderValueFromPreReqScript = pw.env.getResolve(\"secretHeaderValue\")\npw.env.set(\"secretHeaderValueFromPreReqScript\", secretHeaderValueFromPreReqScript)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"v": "2",
|
||||||
|
"auth": {
|
||||||
|
"authType": "none",
|
||||||
|
"authActive": true
|
||||||
|
},
|
||||||
|
"body": {
|
||||||
|
"body": "{\n \"secretBodyKey\": \"<<secretBodyValue>>\"\n}",
|
||||||
|
"contentType": "application/json"
|
||||||
|
},
|
||||||
|
"name": "test-secret-body",
|
||||||
|
"method": "POST",
|
||||||
|
"params": [],
|
||||||
|
"requestVariables": [],
|
||||||
|
"headers": [],
|
||||||
|
"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(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)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"v": "2",
|
||||||
|
"auth": {
|
||||||
|
"authType": "none",
|
||||||
|
"authActive": true
|
||||||
|
},
|
||||||
|
"body": {
|
||||||
|
"body": null,
|
||||||
|
"contentType": null
|
||||||
|
},
|
||||||
|
"name": "test-secret-query-params",
|
||||||
|
"method": "GET",
|
||||||
|
"params": [
|
||||||
|
{
|
||||||
|
"key": "secretQueryParamKey",
|
||||||
|
"value": "<<secretQueryParamValue>>",
|
||||||
|
"active": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"requestVariables": [],
|
||||||
|
"headers": [],
|
||||||
|
"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})",
|
||||||
|
"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": "2",
|
||||||
|
"auth": {
|
||||||
|
"authType": "basic",
|
||||||
|
"password": "<<secretBasicAuthPassword>>",
|
||||||
|
"username": "<<secretBasicAuthUsername>>",
|
||||||
|
"authActive": true
|
||||||
|
},
|
||||||
|
"body": {
|
||||||
|
"body": null,
|
||||||
|
"contentType": null
|
||||||
|
},
|
||||||
|
"name": "test-secret-basic-auth",
|
||||||
|
"method": "GET",
|
||||||
|
"params": [],
|
||||||
|
"requestVariables": [],
|
||||||
|
"headers": [],
|
||||||
|
"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 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}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"v": "2",
|
||||||
|
"auth": {
|
||||||
|
"token": "<<secretBearerToken>>",
|
||||||
|
"authType": "bearer",
|
||||||
|
"password": "testpassword",
|
||||||
|
"username": "testuser",
|
||||||
|
"authActive": true
|
||||||
|
},
|
||||||
|
"body": {
|
||||||
|
"body": null,
|
||||||
|
"contentType": null
|
||||||
|
},
|
||||||
|
"name": "test-secret-bearer-auth",
|
||||||
|
"method": "GET",
|
||||||
|
"params": [],
|
||||||
|
"requestVariables": [],
|
||||||
|
"headers": [],
|
||||||
|
"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 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)"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"auth": {
|
||||||
|
"authType": "inherit",
|
||||||
|
"authActive": false
|
||||||
|
},
|
||||||
|
"headers": []
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"v": 2,
|
||||||
|
"name": "secret-envs-persistence-scripting-req",
|
||||||
|
"folders": [],
|
||||||
|
"requests": [
|
||||||
|
{
|
||||||
|
"v": "2",
|
||||||
|
"endpoint": "https://httpbin.org/post",
|
||||||
|
"name": "req",
|
||||||
|
"params": [],
|
||||||
|
"headers": [
|
||||||
|
{
|
||||||
|
"active": true,
|
||||||
|
"key": "Custom-Header",
|
||||||
|
"value": "<<customHeaderValueFromSecretVar>>"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"method": "POST",
|
||||||
|
"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\")",
|
||||||
|
"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": {
|
||||||
|
"contentType": "application/json",
|
||||||
|
"body": "{\n \"key\": \"<<customBodyValue>>\"\n}"
|
||||||
|
},
|
||||||
|
"requestVariables": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"auth": { "authType": "inherit", "authActive": false },
|
||||||
|
"headers": []
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"v": 0,
|
||||||
|
"name": "Env-I",
|
||||||
|
"variables": [
|
||||||
|
{
|
||||||
|
"key": "firstName",
|
||||||
|
"value": "John"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "lastName",
|
||||||
|
"value": "Doe"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"v": 1,
|
||||||
|
"id": "2",
|
||||||
|
"name": "Env-II",
|
||||||
|
"variables": [
|
||||||
|
{
|
||||||
|
"key": "baseUrl",
|
||||||
|
"value": "https://echo.hoppscotch.io",
|
||||||
|
"secret": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "secretVar",
|
||||||
|
"secret": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"id": 123,
|
||||||
|
"v": "1",
|
||||||
|
"name": "secret-envs",
|
||||||
|
"values": [
|
||||||
|
{
|
||||||
|
"key": "secretVar",
|
||||||
|
"secret": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "regularVar",
|
||||||
|
"secret": false,
|
||||||
|
"value": "regular-variable"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"v": 0,
|
||||||
|
"name": "Response body sample",
|
||||||
|
"variables": [
|
||||||
|
{
|
||||||
|
"key": "firstName",
|
||||||
|
"value": "John"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "lastName",
|
||||||
|
"value": "Doe"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "id",
|
||||||
|
"value": "7"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "fullName",
|
||||||
|
"value": "<<firstName>> <<lastName>>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "recursiveVarX",
|
||||||
|
"value": "<<recursiveVarY>>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "recursiveVarY",
|
||||||
|
"value": "<<salutation>>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "salutation",
|
||||||
|
"value": "Hello"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "greetText",
|
||||||
|
"value": "<<salutation>> <<fullName>>"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"v": 1,
|
||||||
|
"id": "2",
|
||||||
|
"name": "secret-envs-persistence-scripting-envs",
|
||||||
|
"variables": [
|
||||||
|
{
|
||||||
|
"key": "preReqVarOne",
|
||||||
|
"secret": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "preReqVarTwo",
|
||||||
|
"secret": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "postReqVarOne",
|
||||||
|
"secret": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "preReqVarTwo",
|
||||||
|
"secret": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "customHeaderValueFromSecretVar",
|
||||||
|
"secret": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
"id": "2",
|
||||||
|
"v": 1,
|
||||||
|
"name": "secret-envs",
|
||||||
|
"variables": [
|
||||||
|
{
|
||||||
|
"key": "secretBearerToken",
|
||||||
|
"secret": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "secretBasicAuthUsername",
|
||||||
|
"secret": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "secretBasicAuthPassword",
|
||||||
|
"secret": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "secretQueryParamValue",
|
||||||
|
"secret": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "secretBodyValue",
|
||||||
|
"secret": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "secretHeaderValue",
|
||||||
|
"secret": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "nonExistentValueInSystemEnv",
|
||||||
|
"secret": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "baseURL",
|
||||||
|
"value": "https://httpbin.org",
|
||||||
|
"secret": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
{
|
||||||
|
"v": 1,
|
||||||
|
"id": "2",
|
||||||
|
"name": "secret-values-envs",
|
||||||
|
"variables": [
|
||||||
|
{
|
||||||
|
"key": "secretBearerToken",
|
||||||
|
"value": "test-token",
|
||||||
|
"secret": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "secretBasicAuthUsername",
|
||||||
|
"value": "test-user",
|
||||||
|
"secret": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "secretBasicAuthPassword",
|
||||||
|
"value": "test-pass",
|
||||||
|
"secret": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "secretQueryParamValue",
|
||||||
|
"value": "secret-query-param-value",
|
||||||
|
"secret": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "secretBodyValue",
|
||||||
|
"value": "secret-body-value",
|
||||||
|
"secret": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "secretHeaderValue",
|
||||||
|
"value": "secret-header-value",
|
||||||
|
"secret": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "nonExistentValueInSystemEnv",
|
||||||
|
"secret": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "baseURL",
|
||||||
|
"value": "https://httpbin.org",
|
||||||
|
"secret": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,10 +1,17 @@
|
|||||||
import { exec } from "child_process";
|
import { exec } from "child_process";
|
||||||
|
import { resolve } from "path";
|
||||||
|
|
||||||
import { ExecResponse } from "./types";
|
import { ExecResponse } from "./types";
|
||||||
|
|
||||||
export const execAsync = (command: string): Promise<ExecResponse> =>
|
export const runCLI = (args: string, options = {}): Promise<ExecResponse> =>
|
||||||
new Promise((resolve) =>
|
{
|
||||||
exec(command, (error, stdout, stderr) => resolve({ error, stdout, stderr }))
|
const CLI_PATH = resolve(__dirname, "../../bin/hopp");
|
||||||
);
|
const command = `node ${CLI_PATH} ${args}`
|
||||||
|
|
||||||
|
return new Promise((resolve) =>
|
||||||
|
exec(command, options, (error, stdout, stderr) => resolve({ error, stdout, stderr }))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export const trimAnsi = (target: string) => {
|
export const trimAnsi = (target: string) => {
|
||||||
const ansiRegex =
|
const ansiRegex =
|
||||||
@@ -15,12 +22,15 @@ export const trimAnsi = (target: string) => {
|
|||||||
|
|
||||||
export const getErrorCode = (out: string) => {
|
export const getErrorCode = (out: string) => {
|
||||||
const ansiTrimmedStr = trimAnsi(out);
|
const ansiTrimmedStr = trimAnsi(out);
|
||||||
|
|
||||||
return ansiTrimmedStr.split(" ")[0];
|
return ansiTrimmedStr.split(" ")[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getTestJsonFilePath = (file: string) => {
|
export const getTestJsonFilePath = (file: string, kind: "collection" | "environment") => {
|
||||||
const filePath = `${process.cwd()}/src/__tests__/samples/${file}`;
|
const kindDir = {
|
||||||
|
collection: "collections",
|
||||||
|
environment: "environments",
|
||||||
|
}[kind];
|
||||||
|
|
||||||
|
const filePath = resolve(__dirname, `../../src/__tests__/samples/${kindDir}/${file}`);
|
||||||
return filePath;
|
return filePath;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import chalk from "chalk";
|
import chalk from "chalk";
|
||||||
import { program } from "commander";
|
import { Command } 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";
|
||||||
@@ -20,6 +20,8 @@ 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")
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ export interface RequestStack {
|
|||||||
*/
|
*/
|
||||||
export interface RequestConfig extends AxiosRequestConfig {
|
export interface RequestConfig extends AxiosRequestConfig {
|
||||||
supported: boolean;
|
supported: boolean;
|
||||||
|
displayUrl?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EffectiveHoppRESTRequest extends HoppRESTRequest {
|
export interface EffectiveHoppRESTRequest extends HoppRESTRequest {
|
||||||
@@ -30,6 +31,7 @@ export interface EffectiveHoppRESTRequest extends HoppRESTRequest {
|
|||||||
* This contains path, params and environment variables all applied to it
|
* This contains path, params and environment variables all applied to it
|
||||||
*/
|
*/
|
||||||
effectiveFinalURL: string;
|
effectiveFinalURL: string;
|
||||||
|
effectiveFinalDisplayURL?: string;
|
||||||
effectiveFinalHeaders: { key: string; value: string; active: boolean }[];
|
effectiveFinalHeaders: { key: string; value: string; active: boolean }[];
|
||||||
effectiveFinalParams: { key: string; value: string; active: boolean }[];
|
effectiveFinalParams: { key: string; value: string; active: boolean }[];
|
||||||
effectiveFinalBody: FormData | string | null;
|
effectiveFinalBody: FormData | string | null;
|
||||||
|
|||||||
@@ -1,34 +1,42 @@
|
|||||||
|
import { Environment } from "@hoppscotch/data";
|
||||||
|
import { entityReference } from "verzod";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
import { error } from "../../types/errors";
|
import { error } from "../../types/errors";
|
||||||
import {
|
import {
|
||||||
HoppEnvs,
|
|
||||||
HoppEnvPair,
|
|
||||||
HoppEnvKeyPairObject,
|
HoppEnvKeyPairObject,
|
||||||
HoppEnvExportObject,
|
HoppEnvPair,
|
||||||
HoppBulkEnvExportObject,
|
HoppEnvs
|
||||||
} from "../../types/request";
|
} from "../../types/request";
|
||||||
import { readJsonFile } from "../../utils/mutators";
|
import { readJsonFile } from "../../utils/mutators";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses env json file for given path and validates the parsed env json object.
|
* Parses env json file for given path and validates the parsed env json object
|
||||||
* @param path Path of env.json file to be parsed.
|
* @param path Path of env.json file to be parsed
|
||||||
* @returns For successful parsing we get HoppEnvs object.
|
* @returns For successful parsing we get HoppEnvs object
|
||||||
*/
|
*/
|
||||||
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> = [];
|
const envPairs: Array<Environment["variables"][number] | HoppEnvPair> = [];
|
||||||
const HoppEnvKeyPairResult = HoppEnvKeyPairObject.safeParse(contents);
|
|
||||||
const HoppEnvExportObjectResult = HoppEnvExportObject.safeParse(contents);
|
|
||||||
const HoppBulkEnvExportObjectResult =
|
|
||||||
HoppBulkEnvExportObject.safeParse(contents);
|
|
||||||
|
|
||||||
// CLI doesnt support bulk environments export.
|
// The legacy key-value pair format that is still supported
|
||||||
// Hence we check for this case and throw an error if it matches the format.
|
const HoppEnvKeyPairResult = HoppEnvKeyPairObject.safeParse(contents);
|
||||||
|
|
||||||
|
// Shape of the single environment export object that is exported from the app
|
||||||
|
const HoppEnvExportObjectResult = Environment.safeParse(contents);
|
||||||
|
|
||||||
|
// Shape of the bulk environment export object that is exported from the app
|
||||||
|
const HoppBulkEnvExportObjectResult = z.array(entityReference(Environment)).safeParse(contents)
|
||||||
|
|
||||||
|
// CLI doesnt support bulk environments export
|
||||||
|
// Hence we check for this case and throw an error if it matches the format
|
||||||
if (HoppBulkEnvExportObjectResult.success) {
|
if (HoppBulkEnvExportObjectResult.success) {
|
||||||
throw error({ code: "BULK_ENV_FILE", path, data: error });
|
throw error({ code: "BULK_ENV_FILE", path, data: error });
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 (!(HoppEnvKeyPairResult.success || HoppEnvExportObjectResult.success)) {
|
if (!HoppEnvKeyPairResult.success && HoppEnvExportObjectResult.type === "err") {
|
||||||
throw error({ code: "MALFORMED_ENV_FILE", path, data: error });
|
throw error({ code: "MALFORMED_ENV_FILE", path, data: error });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,9 +44,8 @@ export async function parseEnvsData(path: string) {
|
|||||||
for (const [key, value] of Object.entries(HoppEnvKeyPairResult.data)) {
|
for (const [key, value] of Object.entries(HoppEnvKeyPairResult.data)) {
|
||||||
envPairs.push({ key, value });
|
envPairs.push({ key, value });
|
||||||
}
|
}
|
||||||
} else if (HoppEnvExportObjectResult.success) {
|
} else if (HoppEnvExportObjectResult.type === "ok") {
|
||||||
const { key, value } = HoppEnvExportObjectResult.data.variables[0];
|
envPairs.push(...HoppEnvExportObjectResult.value.variables);
|
||||||
envPairs.push({ key, value });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return <HoppEnvs>{ global: [], selected: envPairs };
|
return <HoppEnvs>{ global: [], selected: envPairs };
|
||||||
|
|||||||
@@ -1,31 +1,18 @@
|
|||||||
import { HoppCollection, HoppRESTRequest } from "@hoppscotch/data";
|
import { Environment, HoppCollection, HoppRESTRequest } from "@hoppscotch/data";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
import { TestReport } from "../interfaces/response";
|
import { TestReport } from "../interfaces/response";
|
||||||
import { HoppCLIError } from "./errors";
|
import { HoppCLIError } from "./errors";
|
||||||
import { z } from "zod";
|
|
||||||
|
|
||||||
export type FormDataEntry = {
|
export type FormDataEntry = {
|
||||||
key: string;
|
key: string;
|
||||||
value: string | Blob;
|
value: string | Blob;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type HoppEnvPair = { key: string; value: string };
|
export type HoppEnvPair = Environment["variables"][number];
|
||||||
|
|
||||||
export const HoppEnvKeyPairObject = z.record(z.string(), z.string());
|
export const HoppEnvKeyPairObject = z.record(z.string(), z.string());
|
||||||
|
|
||||||
// Shape of the single environment export object that is exported from the app.
|
|
||||||
export const HoppEnvExportObject = z.object({
|
|
||||||
name: z.string(),
|
|
||||||
variables: z.array(
|
|
||||||
z.object({
|
|
||||||
key: z.string(),
|
|
||||||
value: z.string(),
|
|
||||||
})
|
|
||||||
),
|
|
||||||
});
|
|
||||||
|
|
||||||
// Shape of the bulk environment export object that is exported from the app.
|
|
||||||
export const HoppBulkEnvExportObject = z.array(HoppEnvExportObject);
|
|
||||||
|
|
||||||
export type HoppEnvs = {
|
export type HoppEnvs = {
|
||||||
global: HoppEnvPair[];
|
global: HoppEnvPair[];
|
||||||
selected: HoppEnvPair[];
|
selected: HoppEnvPair[];
|
||||||
|
|||||||
@@ -1,21 +1,23 @@
|
|||||||
|
import { HoppCollection, HoppRESTRequest } from "@hoppscotch/data";
|
||||||
|
import chalk from "chalk";
|
||||||
|
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 { bold } from "chalk";
|
import { round } from "lodash-es";
|
||||||
import { log } from "console";
|
|
||||||
import round from "lodash/round";
|
import { CollectionRunnerParam } from "../types/collections";
|
||||||
import { HoppCollection } from "@hoppscotch/data";
|
|
||||||
import {
|
import {
|
||||||
HoppEnvs,
|
|
||||||
CollectionStack,
|
CollectionStack,
|
||||||
RequestReport,
|
HoppEnvs,
|
||||||
ProcessRequestParams,
|
ProcessRequestParams,
|
||||||
|
RequestReport,
|
||||||
} from "../types/request";
|
} from "../types/request";
|
||||||
import {
|
import {
|
||||||
getRequestMetrics,
|
PreRequestMetrics,
|
||||||
preProcessRequest,
|
RequestMetrics,
|
||||||
processRequest,
|
TestMetrics,
|
||||||
} from "./request";
|
} from "../types/response";
|
||||||
import { exceptionColors } from "./getters";
|
import { DEFAULT_DURATION_PRECISION } from "./constants";
|
||||||
import {
|
import {
|
||||||
printErrorsReport,
|
printErrorsReport,
|
||||||
printFailedTestsReport,
|
printFailedTestsReport,
|
||||||
@@ -23,15 +25,14 @@ import {
|
|||||||
printRequestsMetrics,
|
printRequestsMetrics,
|
||||||
printTestsMetrics,
|
printTestsMetrics,
|
||||||
} from "./display";
|
} from "./display";
|
||||||
import {
|
import { exceptionColors } from "./getters";
|
||||||
PreRequestMetrics,
|
|
||||||
RequestMetrics,
|
|
||||||
TestMetrics,
|
|
||||||
} from "../types/response";
|
|
||||||
import { getTestMetrics } from "./test";
|
|
||||||
import { DEFAULT_DURATION_PRECISION } from "./constants";
|
|
||||||
import { getPreRequestMetrics } from "./pre-request";
|
import { getPreRequestMetrics } from "./pre-request";
|
||||||
import { CollectionRunnerParam } from "../types/collections";
|
import {
|
||||||
|
getRequestMetrics,
|
||||||
|
preProcessRequest,
|
||||||
|
processRequest,
|
||||||
|
} from "./request";
|
||||||
|
import { getTestMetrics } from "./test";
|
||||||
|
|
||||||
const { WARN, FAIL } = exceptionColors;
|
const { WARN, FAIL } = exceptionColors;
|
||||||
|
|
||||||
@@ -55,19 +56,19 @@ export const collectionsRunner = async (
|
|||||||
// Pop out top-most collection from stack to be processed.
|
// Pop out top-most collection from stack to be processed.
|
||||||
const { collection, path } = <CollectionStack>collectionStack.pop();
|
const { collection, path } = <CollectionStack>collectionStack.pop();
|
||||||
|
|
||||||
// Processing each request in collection
|
// Processing each request in collection
|
||||||
for (const request of collection.requests) {
|
for (const request of collection.requests) {
|
||||||
const _request = preProcessRequest(request);
|
const _request = preProcessRequest(request as HoppRESTRequest, collection);
|
||||||
const requestPath = `${path}/${_request.name}`;
|
const requestPath = `${path}/${_request.name}`;
|
||||||
const processRequestParams: ProcessRequestParams = {
|
const processRequestParams: ProcessRequestParams = {
|
||||||
path: requestPath,
|
path: requestPath,
|
||||||
request: _request,
|
request: _request,
|
||||||
envs,
|
envs,
|
||||||
delay,
|
delay,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Request processing initiated message.
|
// Request processing initiated message.
|
||||||
log(WARN(`\nRunning: ${bold(requestPath)}`));
|
log(WARN(`\nRunning: ${chalk.bold(requestPath)}`));
|
||||||
|
|
||||||
// Processing current request.
|
// Processing current request.
|
||||||
const result = await processRequest(processRequestParams)();
|
const result = await processRequest(processRequestParams)();
|
||||||
@@ -77,19 +78,34 @@ export const collectionsRunner = async (
|
|||||||
envs.global = global;
|
envs.global = global;
|
||||||
envs.selected = selected;
|
envs.selected = selected;
|
||||||
|
|
||||||
// Storing current request's report.
|
// Storing current request's report.
|
||||||
const requestReport = result.report;
|
const requestReport = result.report;
|
||||||
requestsReport.push(requestReport);
|
requestsReport.push(requestReport);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pushing remaining folders realted collection to stack.
|
// Pushing remaining folders realted collection to stack.
|
||||||
for (const folder of collection.folders) {
|
for (const folder of collection.folders) {
|
||||||
collectionStack.push({
|
const updatedFolder: HoppCollection = { ...folder }
|
||||||
path: `${path}/${folder.name}`,
|
|
||||||
collection: folder,
|
if (updatedFolder.auth?.authType === "inherit") {
|
||||||
});
|
updatedFolder.auth = collection.auth;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (collection.headers?.length) {
|
||||||
|
// Filter out header entries present in the parent collection under the same name
|
||||||
|
// This ensures the folder headers take precedence over the collection headers
|
||||||
|
const filteredHeaders = collection.headers.filter((collectionHeaderEntries) => {
|
||||||
|
return !updatedFolder.headers.some((folderHeaderEntries) => folderHeaderEntries.key === collectionHeaderEntries.key)
|
||||||
|
})
|
||||||
|
updatedFolder.headers.push(...filteredHeaders);
|
||||||
|
}
|
||||||
|
|
||||||
|
collectionStack.push({
|
||||||
|
path: `${path}/${updatedFolder.name}`,
|
||||||
|
collection: updatedFolder,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return requestsReport;
|
return requestsReport;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { bold } from "chalk";
|
import chalk 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";
|
||||||
@@ -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${bold(path)} reported errors:`);
|
const REPORTED_ERRORS_TITLE = FAIL(`\n${chalk.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${bold(path)} failed tests:`);
|
const FAILED_TESTS_PATH = FAIL(`\n${chalk.bold(path)} failed tests:`);
|
||||||
group(FAILED_TESTS_PATH);
|
group(FAILED_TESTS_PATH);
|
||||||
|
|
||||||
for (const failedTestReport of failedTestsReport) {
|
for (const failedTestReport of failedTestsReport) {
|
||||||
@@ -176,7 +176,7 @@ export const printRequestRunner = {
|
|||||||
*/
|
*/
|
||||||
start: (requestConfig: RequestConfig) => {
|
start: (requestConfig: RequestConfig) => {
|
||||||
const METHOD = BG_INFO(` ${requestConfig.method} `);
|
const METHOD = BG_INFO(` ${requestConfig.method} `);
|
||||||
const ENDPOINT = requestConfig.url;
|
const ENDPOINT = requestConfig.displayUrl || requestConfig.url;
|
||||||
|
|
||||||
process.stdout.write(`${METHOD} ${ENDPOINT}`);
|
process.stdout.write(`${METHOD} ${ENDPOINT}`);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { clone } from "lodash";
|
import { clone } from "lodash-es";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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/round";
|
import { round } from "lodash-es";
|
||||||
import { DEFAULT_DURATION_PRECISION } from "./constants";
|
import { DEFAULT_DURATION_PRECISION } from "./constants";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -36,7 +36,10 @@ import { toFormData } from "./mutators";
|
|||||||
export const preRequestScriptRunner = (
|
export const preRequestScriptRunner = (
|
||||||
request: HoppRESTRequest,
|
request: HoppRESTRequest,
|
||||||
envs: HoppEnvs
|
envs: HoppEnvs
|
||||||
): TE.TaskEither<HoppCLIError, EffectiveHoppRESTRequest> =>
|
): TE.TaskEither<
|
||||||
|
HoppCLIError,
|
||||||
|
{ effectiveRequest: EffectiveHoppRESTRequest } & { updatedEnvs: HoppEnvs }
|
||||||
|
> =>
|
||||||
pipe(
|
pipe(
|
||||||
TE.of(request),
|
TE.of(request),
|
||||||
TE.chain(({ preRequestScript }) =>
|
TE.chain(({ preRequestScript }) =>
|
||||||
@@ -68,7 +71,10 @@ export const preRequestScriptRunner = (
|
|||||||
export function getEffectiveRESTRequest(
|
export function getEffectiveRESTRequest(
|
||||||
request: HoppRESTRequest,
|
request: HoppRESTRequest,
|
||||||
environment: Environment
|
environment: Environment
|
||||||
): E.Either<HoppCLIError, EffectiveHoppRESTRequest> {
|
): E.Either<
|
||||||
|
HoppCLIError,
|
||||||
|
{ effectiveRequest: EffectiveHoppRESTRequest } & { updatedEnvs: HoppEnvs }
|
||||||
|
> {
|
||||||
const envVariables = environment.variables;
|
const envVariables = environment.variables;
|
||||||
|
|
||||||
// Parsing final headers with applied ENVs.
|
// Parsing final headers with applied ENVs.
|
||||||
@@ -162,12 +168,30 @@ export function getEffectiveRESTRequest(
|
|||||||
}
|
}
|
||||||
const effectiveFinalURL = _effectiveFinalURL.right;
|
const effectiveFinalURL = _effectiveFinalURL.right;
|
||||||
|
|
||||||
|
// Secret environment variables referenced in the request endpoint should be masked
|
||||||
|
let effectiveFinalDisplayURL;
|
||||||
|
if (envVariables.some(({ secret }) => secret)) {
|
||||||
|
const _effectiveFinalDisplayURL = parseTemplateStringE(
|
||||||
|
request.endpoint,
|
||||||
|
envVariables,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
if (E.isRight(_effectiveFinalDisplayURL)) {
|
||||||
|
effectiveFinalDisplayURL = _effectiveFinalDisplayURL.right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return E.right({
|
return E.right({
|
||||||
...request,
|
effectiveRequest: {
|
||||||
effectiveFinalURL,
|
...request,
|
||||||
effectiveFinalHeaders,
|
effectiveFinalURL,
|
||||||
effectiveFinalParams,
|
effectiveFinalDisplayURL,
|
||||||
effectiveFinalBody,
|
effectiveFinalHeaders,
|
||||||
|
effectiveFinalParams,
|
||||||
|
effectiveFinalBody,
|
||||||
|
},
|
||||||
|
updatedEnvs: { global: [], selected: envVariables },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,34 +1,66 @@
|
|||||||
|
import { Environment, HoppCollection, HoppRESTRequest } from "@hoppscotch/data";
|
||||||
import axios, { Method } from "axios";
|
import axios, { Method } from "axios";
|
||||||
import { URL } from "url";
|
|
||||||
import * as S from "fp-ts/string";
|
|
||||||
import * as A from "fp-ts/Array";
|
import * as A from "fp-ts/Array";
|
||||||
import * as T from "fp-ts/Task";
|
|
||||||
import * as E from "fp-ts/Either";
|
import * as E from "fp-ts/Either";
|
||||||
|
import * as T from "fp-ts/Task";
|
||||||
import * as TE from "fp-ts/TaskEither";
|
import * as TE from "fp-ts/TaskEither";
|
||||||
import { HoppRESTRequest } from "@hoppscotch/data";
|
import { pipe } from "fp-ts/function";
|
||||||
import { responseErrors } from "./constants";
|
import * as S from "fp-ts/string";
|
||||||
import { getDurationInSeconds, getMetaDataPairs } from "./getters";
|
import { hrtime } from "process";
|
||||||
import { testRunner, getTestScriptParams, hasFailedTestCases } from "./test";
|
import { URL } from "url";
|
||||||
import { RequestConfig, EffectiveHoppRESTRequest } from "../interfaces/request";
|
import { EffectiveHoppRESTRequest, RequestConfig } from "../interfaces/request";
|
||||||
import { RequestRunnerResponse } from "../interfaces/response";
|
import { RequestRunnerResponse } from "../interfaces/response";
|
||||||
import { preRequestScriptRunner } from "./pre-request";
|
import { HoppCLIError, error } from "../types/errors";
|
||||||
import {
|
import {
|
||||||
HoppEnvs,
|
HoppEnvs,
|
||||||
ProcessRequestParams,
|
ProcessRequestParams,
|
||||||
RequestReport,
|
RequestReport,
|
||||||
} from "../types/request";
|
} from "../types/request";
|
||||||
|
import { RequestMetrics } from "../types/response";
|
||||||
|
import { responseErrors } from "./constants";
|
||||||
import {
|
import {
|
||||||
printPreRequestRunner,
|
printPreRequestRunner,
|
||||||
printRequestRunner,
|
printRequestRunner,
|
||||||
printTestRunner,
|
printTestRunner,
|
||||||
} from "./display";
|
} from "./display";
|
||||||
import { error, HoppCLIError } from "../types/errors";
|
import { getDurationInSeconds, getMetaDataPairs } from "./getters";
|
||||||
import { hrtime } from "process";
|
import { preRequestScriptRunner } from "./pre-request";
|
||||||
import { RequestMetrics } from "../types/response";
|
import { getTestScriptParams, hasFailedTestCases, testRunner } from "./test";
|
||||||
import { pipe } from "fp-ts/function";
|
|
||||||
|
|
||||||
// !NOTE: The `config.supported` checks are temporary until OAuth2 and Multipart Forms are supported
|
// !NOTE: The `config.supported` checks are temporary until OAuth2 and Multipart Forms are supported
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes given variable, which includes checking for secret variables
|
||||||
|
* and getting value from system environment
|
||||||
|
* @param variable Variable to be processed
|
||||||
|
* @returns Updated variable with value from system environment
|
||||||
|
*/
|
||||||
|
const processVariables = (variable: Environment["variables"][number]) => {
|
||||||
|
if (variable.secret) {
|
||||||
|
return {
|
||||||
|
...variable,
|
||||||
|
value:
|
||||||
|
"value" in variable ? variable.value : process.env[variable.key] || "",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return variable
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes given envs, which includes processing each variable in global
|
||||||
|
* and selected envs
|
||||||
|
* @param envs Global + selected envs used by requests with in collection
|
||||||
|
* @returns Processed envs with each variable processed
|
||||||
|
*/
|
||||||
|
const processEnvs = (envs: HoppEnvs) => {
|
||||||
|
const processedEnvs = {
|
||||||
|
global: envs.global.map(processVariables),
|
||||||
|
selected: envs.selected.map(processVariables),
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
* perform HTTP request.
|
* perform HTTP request.
|
||||||
@@ -38,6 +70,7 @@ import { pipe } from "fp-ts/function";
|
|||||||
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
|
||||||
};
|
};
|
||||||
const { finalBody, finalEndpoint, finalHeaders, finalParams } = getRequest;
|
const { finalBody, finalEndpoint, finalHeaders, finalParams } = getRequest;
|
||||||
const reqParams = finalParams(req);
|
const reqParams = finalParams(req);
|
||||||
@@ -221,9 +254,13 @@ export const processRequest =
|
|||||||
effectiveFinalParams: [],
|
effectiveFinalParams: [],
|
||||||
effectiveFinalURL: "",
|
effectiveFinalURL: "",
|
||||||
};
|
};
|
||||||
|
let updatedEnvs = <HoppEnvs>{};
|
||||||
|
|
||||||
|
// Fetch values for secret environment variables from system environment
|
||||||
|
const processedEnvs = processEnvs(envs)
|
||||||
|
|
||||||
// Executing pre-request-script
|
// Executing pre-request-script
|
||||||
const preRequestRes = await preRequestScriptRunner(request, envs)();
|
const preRequestRes = await preRequestScriptRunner(request, processedEnvs)();
|
||||||
if (E.isLeft(preRequestRes)) {
|
if (E.isLeft(preRequestRes)) {
|
||||||
printPreRequestRunner.fail();
|
printPreRequestRunner.fail();
|
||||||
|
|
||||||
@@ -231,8 +268,8 @@ export const processRequest =
|
|||||||
report.errors.push(preRequestRes.left);
|
report.errors.push(preRequestRes.left);
|
||||||
report.result = report.result && false;
|
report.result = report.result && false;
|
||||||
} else {
|
} else {
|
||||||
// Updating effective-request
|
// Updating effective-request and consuming updated envs after pre-request script execution
|
||||||
effectiveRequest = preRequestRes.right;
|
({ effectiveRequest, updatedEnvs } = preRequestRes.right);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creating request-config for request-runner.
|
// Creating request-config for request-runner.
|
||||||
@@ -270,7 +307,7 @@ export const processRequest =
|
|||||||
const testScriptParams = getTestScriptParams(
|
const testScriptParams = getTestScriptParams(
|
||||||
_requestRunnerRes,
|
_requestRunnerRes,
|
||||||
request,
|
request,
|
||||||
envs
|
updatedEnvs
|
||||||
);
|
);
|
||||||
|
|
||||||
// Executing test-runner.
|
// Executing test-runner.
|
||||||
@@ -309,9 +346,12 @@ export const processRequest =
|
|||||||
* @returns Updated request object free of invalid/missing data.
|
* @returns Updated request object free of invalid/missing data.
|
||||||
*/
|
*/
|
||||||
export const preProcessRequest = (
|
export const preProcessRequest = (
|
||||||
request: HoppRESTRequest
|
request: HoppRESTRequest,
|
||||||
|
collection: HoppCollection,
|
||||||
): HoppRESTRequest => {
|
): HoppRESTRequest => {
|
||||||
const tempRequest = Object.assign({}, request);
|
const tempRequest = Object.assign({}, request);
|
||||||
|
const { headers: parentHeaders, auth: parentAuth } = collection;
|
||||||
|
|
||||||
if (!tempRequest.v) {
|
if (!tempRequest.v) {
|
||||||
tempRequest.v = "1";
|
tempRequest.v = "1";
|
||||||
}
|
}
|
||||||
@@ -327,18 +367,31 @@ export const preProcessRequest = (
|
|||||||
if (!tempRequest.params) {
|
if (!tempRequest.params) {
|
||||||
tempRequest.params = [];
|
tempRequest.params = [];
|
||||||
}
|
}
|
||||||
if (!tempRequest.headers) {
|
|
||||||
|
if (parentHeaders?.length) {
|
||||||
|
// 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
|
||||||
|
const filteredEntries = parentHeaders.filter((parentHeaderEntries) => {
|
||||||
|
return !tempRequest.headers.some((reqHeaderEntries) => reqHeaderEntries.key === parentHeaderEntries.key)
|
||||||
|
})
|
||||||
|
tempRequest.headers.push(...filteredEntries);
|
||||||
|
} else if (!tempRequest.headers) {
|
||||||
tempRequest.headers = [];
|
tempRequest.headers = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tempRequest.preRequestScript) {
|
if (!tempRequest.preRequestScript) {
|
||||||
tempRequest.preRequestScript = "";
|
tempRequest.preRequestScript = "";
|
||||||
}
|
}
|
||||||
if (!tempRequest.testScript) {
|
if (!tempRequest.testScript) {
|
||||||
tempRequest.testScript = "";
|
tempRequest.testScript = "";
|
||||||
}
|
}
|
||||||
if (!tempRequest.auth) {
|
|
||||||
|
if (tempRequest.auth?.authType === "inherit") {
|
||||||
|
tempRequest.auth = parentAuth;
|
||||||
|
} else if (!tempRequest.auth) {
|
||||||
tempRequest.auth = { authActive: false, authType: "none" };
|
tempRequest.auth = { authActive: false, authType: "none" };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tempRequest.body) {
|
if (!tempRequest.body) {
|
||||||
tempRequest.body = { contentType: null, body: null };
|
tempRequest.body = { contentType: null, body: null };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "ES6",
|
"target": "ESNext",
|
||||||
"module": "commonjs",
|
"module": "ESNext",
|
||||||
"outDir": ".",
|
"outDir": ".",
|
||||||
"rootDir": ".",
|
"rootDir": ".",
|
||||||
"strict": true,
|
"strict": true,
|
||||||
|
|||||||
@@ -3,17 +3,14 @@ import { defineConfig } from "tsup";
|
|||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
entry: [ "./src/index.ts" ],
|
entry: [ "./src/index.ts" ],
|
||||||
outDir: "./dist/",
|
outDir: "./dist/",
|
||||||
format: ["cjs"],
|
format: ["esm"],
|
||||||
platform: "node",
|
platform: "node",
|
||||||
sourcemap: true,
|
sourcemap: true,
|
||||||
bundle: true,
|
bundle: true,
|
||||||
target: "node12",
|
target: "esnext",
|
||||||
skipNodeModulesBundle: false,
|
skipNodeModulesBundle: false,
|
||||||
esbuildOptions(options) {
|
esbuildOptions(options) {
|
||||||
options.bundle = true
|
options.bundle = true
|
||||||
},
|
},
|
||||||
noExternal: [
|
|
||||||
/\w+/
|
|
||||||
],
|
|
||||||
clean: true,
|
clean: true,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -429,6 +429,11 @@ pre.ace_editor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.splitpanes__pane {
|
||||||
|
@apply will-change-auto;
|
||||||
|
transform: translateZ(0);
|
||||||
|
}
|
||||||
|
|
||||||
.smart-splitter .splitpanes__splitter {
|
.smart-splitter .splitpanes__splitter {
|
||||||
@apply relative;
|
@apply relative;
|
||||||
@apply before:absolute;
|
@apply before:absolute;
|
||||||
@@ -558,12 +563,22 @@ details[open] summary .indicator {
|
|||||||
.env-highlight {
|
.env-highlight {
|
||||||
@apply text-accentContrast;
|
@apply text-accentContrast;
|
||||||
|
|
||||||
&.env-found {
|
&.request-variable-highlight {
|
||||||
@apply bg-accentDark;
|
@apply bg-amber-500;
|
||||||
@apply hover:bg-accent;
|
@apply hover:bg-amber-600;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.env-not-found {
|
&.environment-variable-highlight {
|
||||||
|
@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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
--lower-tertiary-sticky-fold: 7.125rem;
|
--lower-tertiary-sticky-fold: 7.125rem;
|
||||||
--lower-fourth-sticky-fold: 9.188rem;
|
--lower-fourth-sticky-fold: 9.188rem;
|
||||||
--sidebar-primary-sticky-fold: 2rem;
|
--sidebar-primary-sticky-fold: 2rem;
|
||||||
--properties-primary-sticky-fold: 2.05rem;
|
--properties-primary-sticky-fold: 2.063rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@mixin light-theme {
|
@mixin light-theme {
|
||||||
|
|||||||
@@ -78,12 +78,6 @@
|
|||||||
"iso": "he-HE",
|
"iso": "he-HE",
|
||||||
"name": "עִברִית"
|
"name": "עִברִית"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"code": "hi",
|
|
||||||
"file": "hi.json",
|
|
||||||
"iso": "hi-HI",
|
|
||||||
"name": "हिन्दी"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"code": "hu",
|
"code": "hu",
|
||||||
"file": "hu.json",
|
"file": "hu.json",
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"action": {
|
"action": {
|
||||||
|
"add": "Add",
|
||||||
"autoscroll": "Autoscroll",
|
"autoscroll": "Autoscroll",
|
||||||
"cancel": "Kanselleer",
|
"cancel": "Kanselleer",
|
||||||
"choose_file": "Kies 'n lêer",
|
"choose_file": "Kies 'n lêer",
|
||||||
@@ -10,6 +11,7 @@
|
|||||||
"connect": "Koppel",
|
"connect": "Koppel",
|
||||||
"connecting": "Connecting",
|
"connecting": "Connecting",
|
||||||
"copy": "Kopieer",
|
"copy": "Kopieer",
|
||||||
|
"create": "Create",
|
||||||
"delete": "Vee uit",
|
"delete": "Vee uit",
|
||||||
"disconnect": "Ontkoppel",
|
"disconnect": "Ontkoppel",
|
||||||
"dismiss": "Weier",
|
"dismiss": "Weier",
|
||||||
@@ -31,6 +33,7 @@
|
|||||||
"open_workspace": "Open workspace",
|
"open_workspace": "Open workspace",
|
||||||
"paste": "Paste",
|
"paste": "Paste",
|
||||||
"prettify": "Prettify",
|
"prettify": "Prettify",
|
||||||
|
"properties": "Properties",
|
||||||
"remove": "Verwyder",
|
"remove": "Verwyder",
|
||||||
"rename": "Rename",
|
"rename": "Rename",
|
||||||
"restore": "Herstel",
|
"restore": "Herstel",
|
||||||
@@ -39,6 +42,7 @@
|
|||||||
"scroll_to_top": "Scroll to top",
|
"scroll_to_top": "Scroll to top",
|
||||||
"search": "Soek",
|
"search": "Soek",
|
||||||
"send": "Stuur",
|
"send": "Stuur",
|
||||||
|
"share": "Share",
|
||||||
"start": "Begin",
|
"start": "Begin",
|
||||||
"starting": "Starting",
|
"starting": "Starting",
|
||||||
"stop": "Stop",
|
"stop": "Stop",
|
||||||
@@ -57,7 +61,9 @@
|
|||||||
"app": {
|
"app": {
|
||||||
"chat_with_us": "Gesels met ons",
|
"chat_with_us": "Gesels met ons",
|
||||||
"contact_us": "Kontak Ons",
|
"contact_us": "Kontak Ons",
|
||||||
|
"cookies": "Cookies",
|
||||||
"copy": "Kopieer",
|
"copy": "Kopieer",
|
||||||
|
"copy_interface_type": "Copy interface type",
|
||||||
"copy_user_id": "Copy User Auth Token",
|
"copy_user_id": "Copy User Auth Token",
|
||||||
"developer_option": "Developer options",
|
"developer_option": "Developer options",
|
||||||
"developer_option_description": "Developer tools which helps in development and maintenance of Hoppscotch.",
|
"developer_option_description": "Developer tools which helps in development and maintenance of Hoppscotch.",
|
||||||
@@ -73,6 +79,7 @@
|
|||||||
"keyboard_shortcuts": "Sleutelbord kortpaaie",
|
"keyboard_shortcuts": "Sleutelbord kortpaaie",
|
||||||
"name": "Hoppscotch",
|
"name": "Hoppscotch",
|
||||||
"new_version_found": "Nuwe weergawe gevind. Herlaai om op te dateer.",
|
"new_version_found": "Nuwe weergawe gevind. Herlaai om op te dateer.",
|
||||||
|
"open_in_hoppscotch": "Open in Hoppscotch",
|
||||||
"options": "Options",
|
"options": "Options",
|
||||||
"proxy_privacy_policy": "Volmag privaatheidsbeleid",
|
"proxy_privacy_policy": "Volmag privaatheidsbeleid",
|
||||||
"reload": "Herlaai",
|
"reload": "Herlaai",
|
||||||
@@ -112,10 +119,27 @@
|
|||||||
},
|
},
|
||||||
"authorization": {
|
"authorization": {
|
||||||
"generate_token": "Genereer teken",
|
"generate_token": "Genereer teken",
|
||||||
|
"graphql_headers": "Authorization Headers are sent as part of the payload to connection_init",
|
||||||
"include_in_url": "Sluit in by URL",
|
"include_in_url": "Sluit in by URL",
|
||||||
|
"inherited_from": "Inherited from {auth} from Parent Collection {collection} ",
|
||||||
"learn": "Leer hoe",
|
"learn": "Leer hoe",
|
||||||
|
"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": "Wagwoord",
|
"password": "Wagwoord",
|
||||||
|
"save_to_inherit": "Please save this request in any collection to inherit the authorization",
|
||||||
"token": "Teken",
|
"token": "Teken",
|
||||||
"type": "Magtigingstipe",
|
"type": "Magtigingstipe",
|
||||||
"username": "Gebruikersnaam"
|
"username": "Gebruikersnaam"
|
||||||
@@ -124,6 +148,7 @@
|
|||||||
"created": "Versameling geskep",
|
"created": "Versameling geskep",
|
||||||
"different_parent": "Cannot reorder collection with different parent",
|
"different_parent": "Cannot reorder collection with different parent",
|
||||||
"edit": "Wysig versameling",
|
"edit": "Wysig versameling",
|
||||||
|
"import_or_create": "Import or create a collection",
|
||||||
"invalid_name": "Gee 'n geldige naam vir die versameling",
|
"invalid_name": "Gee 'n geldige naam vir die versameling",
|
||||||
"invalid_root_move": "Collection already in the root",
|
"invalid_root_move": "Collection already in the root",
|
||||||
"moved": "Moved Successfully",
|
"moved": "Moved Successfully",
|
||||||
@@ -132,6 +157,8 @@
|
|||||||
"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": "Nuwe versameling",
|
"new": "Nuwe versameling",
|
||||||
"order_changed": "Collection Order Updated",
|
"order_changed": "Collection Order Updated",
|
||||||
|
"properties": "Collection Properties",
|
||||||
|
"properties_updated": "Collection Properties Updated",
|
||||||
"renamed": "Versameling hernoem",
|
"renamed": "Versameling hernoem",
|
||||||
"request_in_use": "Request in use",
|
"request_in_use": "Request in use",
|
||||||
"save_as": "Stoor as",
|
"save_as": "Stoor as",
|
||||||
@@ -151,6 +178,7 @@
|
|||||||
"remove_folder": "Weet u seker dat u hierdie vouer permanent wil uitvee?",
|
"remove_folder": "Weet u seker dat u hierdie vouer permanent wil uitvee?",
|
||||||
"remove_history": "Is u seker dat u alle geskiedenis permanent wil uitvee?",
|
"remove_history": "Is u seker dat u alle geskiedenis permanent wil uitvee?",
|
||||||
"remove_request": "Is u seker dat u hierdie versoek permanent wil uitvee?",
|
"remove_request": "Is u seker dat u hierdie versoek permanent wil uitvee?",
|
||||||
|
"remove_shared_request": "Are you sure you want to permanently delete this shared request?",
|
||||||
"remove_team": "Weet u seker dat u hierdie span wil uitvee?",
|
"remove_team": "Weet u seker dat u hierdie span wil uitvee?",
|
||||||
"remove_telemetry": "Weet u seker dat u van Telemetry wil afskakel?",
|
"remove_telemetry": "Weet u seker dat u van Telemetry wil afskakel?",
|
||||||
"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.",
|
||||||
@@ -162,6 +190,24 @@
|
|||||||
"open_request_in_new_tab": "Open request in new tab",
|
"open_request_in_new_tab": "Open request in new tab",
|
||||||
"set_environment_variable": "Set as variable"
|
"set_environment_variable": "Set as variable"
|
||||||
},
|
},
|
||||||
|
"cookies": {
|
||||||
|
"modal": {
|
||||||
|
"cookie_expires": "Expires",
|
||||||
|
"cookie_name": "Name",
|
||||||
|
"cookie_path": "Path",
|
||||||
|
"cookie_string": "Cookie string",
|
||||||
|
"cookie_value": "Value",
|
||||||
|
"empty_domain": "Domain is empty",
|
||||||
|
"empty_domains": "Domain list is empty",
|
||||||
|
"enter_cookie_string": "Enter cookie string",
|
||||||
|
"interceptor_no_support": "Your currently selected interceptor does not support cookies. Select a different Interceptor and try again.",
|
||||||
|
"managed_tab": "Managed",
|
||||||
|
"new_domain_name": "New domain name",
|
||||||
|
"no_cookies_in_domain": "No cookies set for this domain",
|
||||||
|
"raw_tab": "Raw",
|
||||||
|
"set": "Set a cookie"
|
||||||
|
}
|
||||||
|
},
|
||||||
"count": {
|
"count": {
|
||||||
"header": "Koptekst {count}",
|
"header": "Koptekst {count}",
|
||||||
"message": "Boodskap {count}",
|
"message": "Boodskap {count}",
|
||||||
@@ -192,11 +238,13 @@
|
|||||||
"profile": "Login to view your profile",
|
"profile": "Login to view your profile",
|
||||||
"protocols": "Protokolle is leeg",
|
"protocols": "Protokolle is leeg",
|
||||||
"schema": "Koppel aan 'n GraphQL -eindpunt",
|
"schema": "Koppel aan 'n GraphQL -eindpunt",
|
||||||
"shortcodes": "Shortcodes are empty",
|
"shared_requests": "Shared requests are empty",
|
||||||
|
"shared_requests_logout": "Login to view your shared requests or create a new one",
|
||||||
"subscription": "Subscriptions are empty",
|
"subscription": "Subscriptions are empty",
|
||||||
"team_name": "Spannaam leeg",
|
"team_name": "Spannaam leeg",
|
||||||
"teams": "Spanne is leeg",
|
"teams": "Spanne is leeg",
|
||||||
"tests": "Daar is geen toetse vir hierdie versoek nie"
|
"tests": "Daar is geen toetse vir hierdie versoek nie",
|
||||||
|
"shortcodes": "Shortcodes are empty"
|
||||||
},
|
},
|
||||||
"environment": {
|
"environment": {
|
||||||
"add_to_global": "Add to Global",
|
"add_to_global": "Add to Global",
|
||||||
@@ -209,6 +257,7 @@
|
|||||||
"empty_variables": "No variables",
|
"empty_variables": "No variables",
|
||||||
"global": "Global",
|
"global": "Global",
|
||||||
"global_variables": "Global variables",
|
"global_variables": "Global variables",
|
||||||
|
"import_or_create": "Import or create a environment",
|
||||||
"invalid_name": "Gee 'n geldige naam vir die omgewing",
|
"invalid_name": "Gee 'n geldige naam vir die omgewing",
|
||||||
"list": "Environment variables",
|
"list": "Environment variables",
|
||||||
"my_environments": "My Environments",
|
"my_environments": "My Environments",
|
||||||
@@ -232,8 +281,10 @@
|
|||||||
"variable_list": "Veranderlike lys"
|
"variable_list": "Veranderlike lys"
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
|
"authproviders_load_error": "Unable to load auth providers",
|
||||||
"browser_support_sse": "Dit lyk nie asof hierdie blaaier ondersteuning vir bedieners gestuurde geleenthede het nie.",
|
"browser_support_sse": "Dit lyk nie asof hierdie blaaier ondersteuning vir bedieners gestuurde geleenthede het nie.",
|
||||||
"check_console_details": "Kyk na die konsole -log vir meer inligting.",
|
"check_console_details": "Kyk na die konsole -log vir meer inligting.",
|
||||||
|
"check_how_to_add_origin": "Check how you can add an origin",
|
||||||
"curl_invalid_format": "cURL is nie behoorlik geformateer nie",
|
"curl_invalid_format": "cURL is nie behoorlik geformateer nie",
|
||||||
"danger_zone": "Danger zone",
|
"danger_zone": "Danger zone",
|
||||||
"delete_account": "Your account is currently an owner in these teams:",
|
"delete_account": "Your account is currently an owner in these teams:",
|
||||||
@@ -249,9 +300,12 @@
|
|||||||
"json_prettify_invalid_body": "Kon nie 'n ongeldige liggaam mooi maak nie, los json -sintaksisfoute op en probeer weer",
|
"json_prettify_invalid_body": "Kon nie 'n ongeldige liggaam mooi maak nie, los json -sintaksisfoute op en probeer weer",
|
||||||
"network_error": "There seems to be a network error. Please try again.",
|
"network_error": "There seems to be a network error. Please try again.",
|
||||||
"network_fail": "Kon nie versoek stuur nie",
|
"network_fail": "Kon nie versoek stuur nie",
|
||||||
|
"no_collections_to_export": "No collections to export. Please create a collection to get started.",
|
||||||
"no_duration": "Geen duur nie",
|
"no_duration": "Geen duur nie",
|
||||||
|
"no_environments_to_export": "No environments to export. Please create an environment to get started.",
|
||||||
"no_results_found": "No matches found",
|
"no_results_found": "No matches found",
|
||||||
"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.",
|
||||||
"proxy_error": "Proxy error",
|
"proxy_error": "Proxy error",
|
||||||
"script_fail": "Kon nie voorafversoekskrip uitvoer nie",
|
"script_fail": "Kon nie voorafversoekskrip uitvoer nie",
|
||||||
"something_went_wrong": "Iets het verkeerd geloop",
|
"something_went_wrong": "Iets het verkeerd geloop",
|
||||||
@@ -260,6 +314,7 @@
|
|||||||
"export": {
|
"export": {
|
||||||
"as_json": "Uitvoer as JSON",
|
"as_json": "Uitvoer as JSON",
|
||||||
"create_secret_gist": "Skep geheime Gist",
|
"create_secret_gist": "Skep geheime Gist",
|
||||||
|
"failed": "Something went wrong while exporting",
|
||||||
"gist_created": "Gis geskep",
|
"gist_created": "Gis geskep",
|
||||||
"require_github": "Teken in met GitHub om 'n geheime idee te skep",
|
"require_github": "Teken in met GitHub om 'n geheime idee te skep",
|
||||||
"title": "Export"
|
"title": "Export"
|
||||||
@@ -286,6 +341,9 @@
|
|||||||
"subscriptions": "Inskrywings",
|
"subscriptions": "Inskrywings",
|
||||||
"switch_connection": "Switch connection"
|
"switch_connection": "Switch connection"
|
||||||
},
|
},
|
||||||
|
"graphql_collections": {
|
||||||
|
"title": "GraphQL Collections"
|
||||||
|
},
|
||||||
"group": {
|
"group": {
|
||||||
"time": "Time",
|
"time": "Time",
|
||||||
"url": "URL"
|
"url": "URL"
|
||||||
@@ -297,6 +355,8 @@
|
|||||||
},
|
},
|
||||||
"helpers": {
|
"helpers": {
|
||||||
"authorization": "Die magtigingskop sal outomaties gegenereer word wanneer u die versoek stuur.",
|
"authorization": "Die magtigingskop sal outomaties gegenereer word wanneer u die versoek stuur.",
|
||||||
|
"collection_properties_authorization": " This authorization will be set for every request in this collection.",
|
||||||
|
"collection_properties_header": "This header will be set for every request in this collection.",
|
||||||
"generate_documentation_first": "Genereer eers dokumentasie",
|
"generate_documentation_first": "Genereer eers dokumentasie",
|
||||||
"network_fail": "Kon nie die API -eindpunt bereik nie. Kontroleer u netwerkverbinding en probeer weer.",
|
"network_fail": "Kon nie die API -eindpunt bereik nie. Kontroleer u netwerkverbinding en probeer weer.",
|
||||||
"offline": "Dit lyk asof u vanlyn is. Data in hierdie werkruimte is moontlik nie op datum nie.",
|
"offline": "Dit lyk asof u vanlyn is. Data in hierdie werkruimte is moontlik nie op datum nie.",
|
||||||
@@ -316,7 +376,10 @@
|
|||||||
"import": {
|
"import": {
|
||||||
"collections": "Voer versamelings in",
|
"collections": "Voer versamelings in",
|
||||||
"curl": "Voer cURL in",
|
"curl": "Voer cURL in",
|
||||||
|
"environments_from_gist": "Import From Gist",
|
||||||
|
"environments_from_gist_description": "Import Hoppscotch Environments From Gist",
|
||||||
"failed": "Invoer misluk",
|
"failed": "Invoer misluk",
|
||||||
|
"from_file": "Import from File",
|
||||||
"from_gist": "Invoer vanaf Gist",
|
"from_gist": "Invoer vanaf Gist",
|
||||||
"from_gist_description": "Import from Gist URL",
|
"from_gist_description": "Import from Gist URL",
|
||||||
"from_insomnia": "Import from Insomnia",
|
"from_insomnia": "Import from Insomnia",
|
||||||
@@ -331,11 +394,17 @@
|
|||||||
"from_postman_description": "Import from Postman collection",
|
"from_postman_description": "Import from Postman collection",
|
||||||
"from_url": "Import from URL",
|
"from_url": "Import from URL",
|
||||||
"gist_url": "Voer Gist URL in",
|
"gist_url": "Voer Gist URL in",
|
||||||
|
"gql_collections_from_gist_description": "Import GraphQL Collections From Gist",
|
||||||
|
"hoppscotch_environment": "Hoppscotch Environment",
|
||||||
|
"hoppscotch_environment_description": "Import Hoppscotch Environment JSON file",
|
||||||
"import_from_url_invalid_fetch": "Couldn't get data from the url",
|
"import_from_url_invalid_fetch": "Couldn't get data from the url",
|
||||||
"import_from_url_invalid_file_format": "Error while importing collections",
|
"import_from_url_invalid_file_format": "Error while importing collections",
|
||||||
"import_from_url_invalid_type": "Unsupported type. accepted values are 'hoppscotch', 'openapi', 'postman', 'insomnia'",
|
"import_from_url_invalid_type": "Unsupported type. accepted values are 'hoppscotch', 'openapi', 'postman', 'insomnia'",
|
||||||
"import_from_url_success": "Collections Imported",
|
"import_from_url_success": "Collections Imported",
|
||||||
|
"insomnia_environment_description": "Import Insomnia Environment from a JSON/YAML file",
|
||||||
"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_description": "Import Postman Environment from a JSON file",
|
||||||
"title": "Invoer"
|
"title": "Invoer"
|
||||||
},
|
},
|
||||||
"inspections": {
|
"inspections": {
|
||||||
@@ -373,8 +442,10 @@
|
|||||||
"close_unsaved_tab": "You have unsaved changes",
|
"close_unsaved_tab": "You have unsaved changes",
|
||||||
"collections": "Versamelings",
|
"collections": "Versamelings",
|
||||||
"confirm": "Bevestig",
|
"confirm": "Bevestig",
|
||||||
|
"customize_request": "Customize Request",
|
||||||
"edit_request": "Wysig versoek",
|
"edit_request": "Wysig versoek",
|
||||||
"import_export": "Invoer uitvoer"
|
"import_export": "Invoer uitvoer",
|
||||||
|
"share_request": "Share Request"
|
||||||
},
|
},
|
||||||
"mqtt": {
|
"mqtt": {
|
||||||
"already_subscribed": "You are already subscribed to this topic.",
|
"already_subscribed": "You are already subscribed to this topic.",
|
||||||
@@ -449,13 +520,14 @@
|
|||||||
"structured": "Structured",
|
"structured": "Structured",
|
||||||
"text": "Text"
|
"text": "Text"
|
||||||
},
|
},
|
||||||
"copy_link": "Kopieer skakel",
|
|
||||||
"different_collection": "Cannot reorder requests from different collections",
|
"different_collection": "Cannot reorder requests from different collections",
|
||||||
"duplicated": "Request duplicated",
|
"duplicated": "Request duplicated",
|
||||||
"duration": "Duur",
|
"duration": "Duur",
|
||||||
"enter_curl": "Voer cURL in",
|
"enter_curl": "Voer cURL in",
|
||||||
"generate_code": "Genereer kode",
|
"generate_code": "Genereer kode",
|
||||||
"generated_code": "Kode gegenereer",
|
"generated_code": "Kode gegenereer",
|
||||||
|
"go_to_authorization_tab": "Go to Authorization tab",
|
||||||
|
"go_to_body_tab": "Go to Body tab",
|
||||||
"header_list": "Koplys",
|
"header_list": "Koplys",
|
||||||
"invalid_name": "Gee 'n naam vir die versoek",
|
"invalid_name": "Gee 'n naam vir die versoek",
|
||||||
"method": "Metode",
|
"method": "Metode",
|
||||||
@@ -480,12 +552,14 @@
|
|||||||
"saved": "Versoek gestoor",
|
"saved": "Versoek gestoor",
|
||||||
"share": "Deel",
|
"share": "Deel",
|
||||||
"share_description": "Share Hoppscotch with your friends",
|
"share_description": "Share Hoppscotch with your friends",
|
||||||
|
"share_request": "Share Request",
|
||||||
"stop": "Stop",
|
"stop": "Stop",
|
||||||
"title": "Versoek",
|
"title": "Versoek",
|
||||||
"type": "Soort versoek",
|
"type": "Soort versoek",
|
||||||
"url": "URL",
|
"url": "URL",
|
||||||
"variables": "Veranderlikes",
|
"variables": "Veranderlikes",
|
||||||
"view_my_links": "View my links"
|
"view_my_links": "View my links",
|
||||||
|
"copy_link": "Kopieer skakel"
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"audio": "Audio",
|
"audio": "Audio",
|
||||||
@@ -513,6 +587,7 @@
|
|||||||
"account_description": "Pas u rekeninginstellings aan.",
|
"account_description": "Pas u rekeninginstellings aan.",
|
||||||
"account_email_description": "Jou primêre e -posadres.",
|
"account_email_description": "Jou primêre e -posadres.",
|
||||||
"account_name_description": "Dit is u vertoonnaam.",
|
"account_name_description": "Dit is u vertoonnaam.",
|
||||||
|
"additional": "Additional Settings",
|
||||||
"background": "Agtergrond",
|
"background": "Agtergrond",
|
||||||
"black_mode": "Swart",
|
"black_mode": "Swart",
|
||||||
"choose_language": "Kies taal",
|
"choose_language": "Kies taal",
|
||||||
@@ -559,14 +634,31 @@
|
|||||||
"verified_email": "Verified email",
|
"verified_email": "Verified email",
|
||||||
"verify_email": "Verify email"
|
"verify_email": "Verify email"
|
||||||
},
|
},
|
||||||
"shortcodes": {
|
"shared_requests": {
|
||||||
"actions": "Actions",
|
"button": "Button",
|
||||||
"created_on": "Created on",
|
"button_info": "Create a 'Run in Hoppscotch' button for your website, blog or a README.",
|
||||||
"deleted": "Shortcode deleted",
|
"copy_html": "Copy HTML",
|
||||||
"method": "Method",
|
"copy_link": "Copy Link",
|
||||||
"not_found": "Shortcode not found",
|
"copy_markdown": "Copy Markdown",
|
||||||
"short_code": "Short code",
|
"creating_widget": "Creating widget",
|
||||||
"url": "URL"
|
"customize": "Customize",
|
||||||
|
"deleted": "Shared request deleted",
|
||||||
|
"description": "Select a widget, you can change and customize this later",
|
||||||
|
"embed": "Embed",
|
||||||
|
"embed_info": "Add a mini 'Hoppscotch API Playground' to your website, blog or documentation.",
|
||||||
|
"link": "Link",
|
||||||
|
"link_info": "Create a shareable link to share with anyone on the internet with view access.",
|
||||||
|
"modified": "Shared request modified",
|
||||||
|
"not_found": "Shared request not found",
|
||||||
|
"open_new_tab": "Open in new tab",
|
||||||
|
"preview": "Preview",
|
||||||
|
"run_in_hoppscotch": "Run in Hoppscotch",
|
||||||
|
"theme": {
|
||||||
|
"dark": "Dark",
|
||||||
|
"light": "Light",
|
||||||
|
"system": "System",
|
||||||
|
"title": "Theme"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"shortcut": {
|
"shortcut": {
|
||||||
"general": {
|
"general": {
|
||||||
@@ -596,7 +688,6 @@
|
|||||||
"title": "Others"
|
"title": "Others"
|
||||||
},
|
},
|
||||||
"request": {
|
"request": {
|
||||||
"copy_request_link": "Kopieer versoekskakel",
|
|
||||||
"delete_method": "Kies DELETE metode",
|
"delete_method": "Kies DELETE metode",
|
||||||
"get_method": "Kies GET -metode",
|
"get_method": "Kies GET -metode",
|
||||||
"head_method": "Kies HOOF metode",
|
"head_method": "Kies HOOF metode",
|
||||||
@@ -611,8 +702,10 @@
|
|||||||
"save_request": "Save Request",
|
"save_request": "Save Request",
|
||||||
"save_to_collections": "Stoor in versamelings",
|
"save_to_collections": "Stoor in versamelings",
|
||||||
"send_request": "Stuur versoek",
|
"send_request": "Stuur versoek",
|
||||||
|
"share_request": "Share Request",
|
||||||
"show_code": "Generate code snippet",
|
"show_code": "Generate code snippet",
|
||||||
"title": "Versoek"
|
"title": "Versoek",
|
||||||
|
"copy_request_link": "Kopieer versoekskakel"
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"copy": "Copy response to clipboard",
|
"copy": "Copy response to clipboard",
|
||||||
@@ -735,6 +828,7 @@
|
|||||||
"connection_error": "Failed to connect",
|
"connection_error": "Failed to connect",
|
||||||
"connection_failed": "Connection failed",
|
"connection_failed": "Connection failed",
|
||||||
"connection_lost": "Connection lost",
|
"connection_lost": "Connection lost",
|
||||||
|
"copied_interface_to_clipboard": "Copied {language} interface type to clipboard",
|
||||||
"copied_to_clipboard": "Na knipbord gekopieer",
|
"copied_to_clipboard": "Na knipbord gekopieer",
|
||||||
"deleted": "Uitgevee",
|
"deleted": "Uitgevee",
|
||||||
"deprecated": "GEDRAGTEER",
|
"deprecated": "GEDRAGTEER",
|
||||||
@@ -742,10 +836,12 @@
|
|||||||
"disconnected": "Ontkoppel",
|
"disconnected": "Ontkoppel",
|
||||||
"disconnected_from": "Ontkoppel van {name}",
|
"disconnected_from": "Ontkoppel van {name}",
|
||||||
"docs_generated": "Dokumentasie gegenereer",
|
"docs_generated": "Dokumentasie gegenereer",
|
||||||
|
"download_failed": "Download failed",
|
||||||
"download_started": "Aflaai begin",
|
"download_started": "Aflaai begin",
|
||||||
"enabled": "Geaktiveer",
|
"enabled": "Geaktiveer",
|
||||||
"file_imported": "Lêer ingevoer",
|
"file_imported": "Lêer ingevoer",
|
||||||
"finished_in": "Klaar in {duration} ms",
|
"finished_in": "Klaar in {duration} ms",
|
||||||
|
"hide": "Hide",
|
||||||
"history_deleted": "Geskiedenis uitgevee",
|
"history_deleted": "Geskiedenis uitgevee",
|
||||||
"linewrap": "Draai lyne toe",
|
"linewrap": "Draai lyne toe",
|
||||||
"loading": "Laai tans ...",
|
"loading": "Laai tans ...",
|
||||||
@@ -756,6 +852,7 @@
|
|||||||
"published_error": "Something went wrong while publishing msg: {topic} to topic: {message}",
|
"published_error": "Something went wrong while publishing msg: {topic} to topic: {message}",
|
||||||
"published_message": "Published message: {message} to topic: {topic}",
|
"published_message": "Published message: {message} to topic: {topic}",
|
||||||
"reconnection_error": "Failed to reconnect",
|
"reconnection_error": "Failed to reconnect",
|
||||||
|
"show": "Show",
|
||||||
"subscribed_failed": "Failed to subscribe to topic: {topic}",
|
"subscribed_failed": "Failed to subscribe to topic: {topic}",
|
||||||
"subscribed_success": "Successfully subscribed to topic: {topic}",
|
"subscribed_success": "Successfully subscribed to topic: {topic}",
|
||||||
"unsubscribed_failed": "Failed to unsubscribe from topic: {topic}",
|
"unsubscribed_failed": "Failed to unsubscribe from topic: {topic}",
|
||||||
@@ -791,6 +888,7 @@
|
|||||||
"queries": "Navrae",
|
"queries": "Navrae",
|
||||||
"query": "Navraag",
|
"query": "Navraag",
|
||||||
"schema": "Schema",
|
"schema": "Schema",
|
||||||
|
"shared_requests": "Shared Requests",
|
||||||
"socketio": "Socket.IO",
|
"socketio": "Socket.IO",
|
||||||
"sse": "SSE",
|
"sse": "SSE",
|
||||||
"tests": "Toetse",
|
"tests": "Toetse",
|
||||||
@@ -807,6 +905,7 @@
|
|||||||
"email_do_not_match": "Email doesn't match with your account details. Contact your team owner.",
|
"email_do_not_match": "Email doesn't match with your account details. Contact your team owner.",
|
||||||
"exit": "Verlaat span",
|
"exit": "Verlaat span",
|
||||||
"exit_disabled": "Slegs eienaar kan nie die span verlaat nie",
|
"exit_disabled": "Slegs eienaar kan nie die span verlaat nie",
|
||||||
|
"failed_invites": "Failed invites",
|
||||||
"invalid_coll_id": "Invalid collection ID",
|
"invalid_coll_id": "Invalid collection ID",
|
||||||
"invalid_email_format": "Die e -posformaat is ongeldig",
|
"invalid_email_format": "Die e -posformaat is ongeldig",
|
||||||
"invalid_id": "Invalid team ID. Contact your team owner.",
|
"invalid_id": "Invalid team ID. Contact your team owner.",
|
||||||
@@ -848,6 +947,7 @@
|
|||||||
"same_target_destination": "Same target and destination",
|
"same_target_destination": "Same target and destination",
|
||||||
"saved": "Span gered",
|
"saved": "Span gered",
|
||||||
"select_a_team": "Select a team",
|
"select_a_team": "Select a team",
|
||||||
|
"success_invites": "Success invites",
|
||||||
"title": "Spanne",
|
"title": "Spanne",
|
||||||
"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 team."
|
"we_sent_invite_link_description": "Ask all invitees to check their inbox. Click on the link to join the team."
|
||||||
@@ -879,5 +979,14 @@
|
|||||||
"personal": "My Workspace",
|
"personal": "My Workspace",
|
||||||
"team": "Team Workspace",
|
"team": "Team Workspace",
|
||||||
"title": "Workspaces"
|
"title": "Workspaces"
|
||||||
|
},
|
||||||
|
"shortcodes": {
|
||||||
|
"actions": "Actions",
|
||||||
|
"created_on": "Created on",
|
||||||
|
"deleted": "Shortcode deleted",
|
||||||
|
"method": "Method",
|
||||||
|
"not_found": "Shortcode not found",
|
||||||
|
"short_code": "Short code",
|
||||||
|
"url": "URL"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"action": {
|
"action": {
|
||||||
|
"add": "Add",
|
||||||
"autoscroll": "Autoscroll",
|
"autoscroll": "Autoscroll",
|
||||||
"cancel": "الغاء",
|
"cancel": "الغاء",
|
||||||
"choose_file": "اختيار ملف",
|
"choose_file": "اختيار ملف",
|
||||||
@@ -10,6 +11,7 @@
|
|||||||
"connect": "الاتصال",
|
"connect": "الاتصال",
|
||||||
"connecting": "Connecting",
|
"connecting": "Connecting",
|
||||||
"copy": "نسخ",
|
"copy": "نسخ",
|
||||||
|
"create": "Create",
|
||||||
"delete": "حذف",
|
"delete": "حذف",
|
||||||
"disconnect": "قطع الاتصال",
|
"disconnect": "قطع الاتصال",
|
||||||
"dismiss": "رفض",
|
"dismiss": "رفض",
|
||||||
@@ -31,6 +33,7 @@
|
|||||||
"open_workspace": "Open workspace",
|
"open_workspace": "Open workspace",
|
||||||
"paste": "لصق",
|
"paste": "لصق",
|
||||||
"prettify": "جمال",
|
"prettify": "جمال",
|
||||||
|
"properties": "Properties",
|
||||||
"remove": "ازالة",
|
"remove": "ازالة",
|
||||||
"rename": "Rename",
|
"rename": "Rename",
|
||||||
"restore": "اعادة",
|
"restore": "اعادة",
|
||||||
@@ -39,6 +42,7 @@
|
|||||||
"scroll_to_top": "Scroll to top",
|
"scroll_to_top": "Scroll to top",
|
||||||
"search": "بحث",
|
"search": "بحث",
|
||||||
"send": "ارسل",
|
"send": "ارسل",
|
||||||
|
"share": "Share",
|
||||||
"start": "ابدأ",
|
"start": "ابدأ",
|
||||||
"starting": "Starting",
|
"starting": "Starting",
|
||||||
"stop": "قف",
|
"stop": "قف",
|
||||||
@@ -57,7 +61,9 @@
|
|||||||
"app": {
|
"app": {
|
||||||
"chat_with_us": "دردش معنا",
|
"chat_with_us": "دردش معنا",
|
||||||
"contact_us": "اتصل بنا",
|
"contact_us": "اتصل بنا",
|
||||||
|
"cookies": "Cookies",
|
||||||
"copy": "انسخ",
|
"copy": "انسخ",
|
||||||
|
"copy_interface_type": "Copy interface type",
|
||||||
"copy_user_id": "Copy User Auth Token",
|
"copy_user_id": "Copy User Auth Token",
|
||||||
"developer_option": "Developer options",
|
"developer_option": "Developer options",
|
||||||
"developer_option_description": "Developer tools which helps in development and maintenance of Hoppscotch.",
|
"developer_option_description": "Developer tools which helps in development and maintenance of Hoppscotch.",
|
||||||
@@ -73,6 +79,7 @@
|
|||||||
"keyboard_shortcuts": "اختصارات لوحة المفاتيح",
|
"keyboard_shortcuts": "اختصارات لوحة المفاتيح",
|
||||||
"name": "هوبسكوتش",
|
"name": "هوبسكوتش",
|
||||||
"new_version_found": "تم العثور على نسخة جديدة. قم بالتحديث للتحديث.",
|
"new_version_found": "تم العثور على نسخة جديدة. قم بالتحديث للتحديث.",
|
||||||
|
"open_in_hoppscotch": "Open in Hoppscotch",
|
||||||
"options": "Options",
|
"options": "Options",
|
||||||
"proxy_privacy_policy": "سياسة خصوصية الوكيل",
|
"proxy_privacy_policy": "سياسة خصوصية الوكيل",
|
||||||
"reload": "إعادة تحميل",
|
"reload": "إعادة تحميل",
|
||||||
@@ -112,10 +119,27 @@
|
|||||||
},
|
},
|
||||||
"authorization": {
|
"authorization": {
|
||||||
"generate_token": "توليد رمز",
|
"generate_token": "توليد رمز",
|
||||||
|
"graphql_headers": "Authorization Headers are sent as part of the payload to connection_init",
|
||||||
"include_in_url": "تضمين في URL",
|
"include_in_url": "تضمين في URL",
|
||||||
|
"inherited_from": "Inherited from {auth} from Parent Collection {collection} ",
|
||||||
"learn": "تعلم كيف",
|
"learn": "تعلم كيف",
|
||||||
|
"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": "كلمة المرور",
|
"password": "كلمة المرور",
|
||||||
|
"save_to_inherit": "Please save this request in any collection to inherit the authorization",
|
||||||
"token": "رمز",
|
"token": "رمز",
|
||||||
"type": "نوع التفويض",
|
"type": "نوع التفويض",
|
||||||
"username": "اسم المستخدم"
|
"username": "اسم المستخدم"
|
||||||
@@ -124,6 +148,7 @@
|
|||||||
"created": "تم إنشاء المجموعة",
|
"created": "تم إنشاء المجموعة",
|
||||||
"different_parent": "Cannot reorder collection with different parent",
|
"different_parent": "Cannot reorder collection with different parent",
|
||||||
"edit": "تحرير المجموعة",
|
"edit": "تحرير المجموعة",
|
||||||
|
"import_or_create": "Import or create a collection",
|
||||||
"invalid_name": "الرجاء تقديم اسم صالح للمجموعة",
|
"invalid_name": "الرجاء تقديم اسم صالح للمجموعة",
|
||||||
"invalid_root_move": "Collection already in the root",
|
"invalid_root_move": "Collection already in the root",
|
||||||
"moved": "Moved Successfully",
|
"moved": "Moved Successfully",
|
||||||
@@ -132,6 +157,8 @@
|
|||||||
"name_length_insufficient": "اسم المجموعة يجب ان لايقل على 3 رموز",
|
"name_length_insufficient": "اسم المجموعة يجب ان لايقل على 3 رموز",
|
||||||
"new": "مجموعة جديدة",
|
"new": "مجموعة جديدة",
|
||||||
"order_changed": "Collection Order Updated",
|
"order_changed": "Collection Order Updated",
|
||||||
|
"properties": "Collection Properties",
|
||||||
|
"properties_updated": "Collection Properties Updated",
|
||||||
"renamed": "تمت إعادة تسمية المجموعة",
|
"renamed": "تمت إعادة تسمية المجموعة",
|
||||||
"request_in_use": "Request in use",
|
"request_in_use": "Request in use",
|
||||||
"save_as": "حفظ باسم",
|
"save_as": "حفظ باسم",
|
||||||
@@ -151,6 +178,7 @@
|
|||||||
"remove_folder": "هل أنت متأكد أنك تريد حذف هذا المجلد نهائيًا؟",
|
"remove_folder": "هل أنت متأكد أنك تريد حذف هذا المجلد نهائيًا؟",
|
||||||
"remove_history": "هل أنت متأكد أنك تريد حذف كل المحفوظات بشكل دائم؟",
|
"remove_history": "هل أنت متأكد أنك تريد حذف كل المحفوظات بشكل دائم؟",
|
||||||
"remove_request": "هل أنت متأكد أنك تريد حذف هذا الطلب نهائيًا؟",
|
"remove_request": "هل أنت متأكد أنك تريد حذف هذا الطلب نهائيًا؟",
|
||||||
|
"remove_shared_request": "Are you sure you want to permanently delete this shared request?",
|
||||||
"remove_team": "هل أنت متأكد أنك تريد حذف هذا الفريق؟",
|
"remove_team": "هل أنت متأكد أنك تريد حذف هذا الفريق؟",
|
||||||
"remove_telemetry": "هل أنت متأكد أنك تريد الانسحاب من القياس عن بعد؟",
|
"remove_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.",
|
||||||
@@ -162,6 +190,24 @@
|
|||||||
"open_request_in_new_tab": "Open request in new tab",
|
"open_request_in_new_tab": "Open request in new tab",
|
||||||
"set_environment_variable": "Set as variable"
|
"set_environment_variable": "Set as variable"
|
||||||
},
|
},
|
||||||
|
"cookies": {
|
||||||
|
"modal": {
|
||||||
|
"cookie_expires": "Expires",
|
||||||
|
"cookie_name": "Name",
|
||||||
|
"cookie_path": "Path",
|
||||||
|
"cookie_string": "Cookie string",
|
||||||
|
"cookie_value": "Value",
|
||||||
|
"empty_domain": "Domain is empty",
|
||||||
|
"empty_domains": "Domain list is empty",
|
||||||
|
"enter_cookie_string": "Enter cookie string",
|
||||||
|
"interceptor_no_support": "Your currently selected interceptor does not support cookies. Select a different Interceptor and try again.",
|
||||||
|
"managed_tab": "Managed",
|
||||||
|
"new_domain_name": "New domain name",
|
||||||
|
"no_cookies_in_domain": "No cookies set for this domain",
|
||||||
|
"raw_tab": "Raw",
|
||||||
|
"set": "Set a cookie"
|
||||||
|
}
|
||||||
|
},
|
||||||
"count": {
|
"count": {
|
||||||
"header": "رأس {count}",
|
"header": "رأس {count}",
|
||||||
"message": "الرسالة {count}",
|
"message": "الرسالة {count}",
|
||||||
@@ -192,11 +238,13 @@
|
|||||||
"profile": "سجل الدخول لرؤية فريقك",
|
"profile": "سجل الدخول لرؤية فريقك",
|
||||||
"protocols": "البروتوكولات فارغة",
|
"protocols": "البروتوكولات فارغة",
|
||||||
"schema": "اتصل بنقطة نهاية GraphQL",
|
"schema": "اتصل بنقطة نهاية GraphQL",
|
||||||
"shortcodes": "Shortcodes are empty",
|
"shared_requests": "Shared requests are empty",
|
||||||
|
"shared_requests_logout": "Login to view your shared requests or create a new one",
|
||||||
"subscription": "Subscriptions are empty",
|
"subscription": "Subscriptions are empty",
|
||||||
"team_name": "اسم الفريق فارغ",
|
"team_name": "اسم الفريق فارغ",
|
||||||
"teams": "الفرق فارغة",
|
"teams": "الفرق فارغة",
|
||||||
"tests": "لا توجد اختبارات لهذا الطلب"
|
"tests": "لا توجد اختبارات لهذا الطلب",
|
||||||
|
"shortcodes": "Shortcodes are empty"
|
||||||
},
|
},
|
||||||
"environment": {
|
"environment": {
|
||||||
"add_to_global": "Add to Global",
|
"add_to_global": "Add to Global",
|
||||||
@@ -209,6 +257,7 @@
|
|||||||
"empty_variables": "No variables",
|
"empty_variables": "No variables",
|
||||||
"global": "Global",
|
"global": "Global",
|
||||||
"global_variables": "Global variables",
|
"global_variables": "Global variables",
|
||||||
|
"import_or_create": "Import or create a environment",
|
||||||
"invalid_name": "الرجاء تقديم اسم صالح للبيئة",
|
"invalid_name": "الرجاء تقديم اسم صالح للبيئة",
|
||||||
"list": "Environment variables",
|
"list": "Environment variables",
|
||||||
"my_environments": "My Environments",
|
"my_environments": "My Environments",
|
||||||
@@ -232,8 +281,10 @@
|
|||||||
"variable_list": "قائمة متغيرة"
|
"variable_list": "قائمة متغيرة"
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
|
"authproviders_load_error": "Unable to load auth providers",
|
||||||
"browser_support_sse": "يبدو أن هذا المستعرض لا يدعم أحداث إرسال الخادم.",
|
"browser_support_sse": "يبدو أن هذا المستعرض لا يدعم أحداث إرسال الخادم.",
|
||||||
"check_console_details": "تحقق من سجل وحدة التحكم للحصول على التفاصيل.",
|
"check_console_details": "تحقق من سجل وحدة التحكم للحصول على التفاصيل.",
|
||||||
|
"check_how_to_add_origin": "Check how you can add an origin",
|
||||||
"curl_invalid_format": "لم يتم تنسيق cURL بشكل صحيح",
|
"curl_invalid_format": "لم يتم تنسيق cURL بشكل صحيح",
|
||||||
"danger_zone": "Danger zone",
|
"danger_zone": "Danger zone",
|
||||||
"delete_account": "Your account is currently an owner in these teams:",
|
"delete_account": "Your account is currently an owner in these teams:",
|
||||||
@@ -249,9 +300,12 @@
|
|||||||
"json_prettify_invalid_body": "تعذر تجميل جسم غير صالح وحل أخطاء بناء جملة json وحاول مرة أخرى",
|
"json_prettify_invalid_body": "تعذر تجميل جسم غير صالح وحل أخطاء بناء جملة json وحاول مرة أخرى",
|
||||||
"network_error": "There seems to be a network error. Please try again.",
|
"network_error": "There seems to be a network error. Please try again.",
|
||||||
"network_fail": "تعذر إرسال الطلب",
|
"network_fail": "تعذر إرسال الطلب",
|
||||||
|
"no_collections_to_export": "No collections to export. Please create a collection to get started.",
|
||||||
"no_duration": "لا مدة",
|
"no_duration": "لا مدة",
|
||||||
|
"no_environments_to_export": "No environments to export. Please create an environment to get started.",
|
||||||
"no_results_found": "No matches found",
|
"no_results_found": "No matches found",
|
||||||
"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.",
|
||||||
"proxy_error": "Proxy error",
|
"proxy_error": "Proxy error",
|
||||||
"script_fail": "تعذر تنفيذ نص الطلب المسبق",
|
"script_fail": "تعذر تنفيذ نص الطلب المسبق",
|
||||||
"something_went_wrong": "هناك خطأ ما",
|
"something_went_wrong": "هناك خطأ ما",
|
||||||
@@ -260,6 +314,7 @@
|
|||||||
"export": {
|
"export": {
|
||||||
"as_json": "تصدير بتنسيق JSON",
|
"as_json": "تصدير بتنسيق JSON",
|
||||||
"create_secret_gist": "إنشاء جوهر سري",
|
"create_secret_gist": "إنشاء جوهر سري",
|
||||||
|
"failed": "Something went wrong while exporting",
|
||||||
"gist_created": "خلقت الجست",
|
"gist_created": "خلقت الجست",
|
||||||
"require_github": "تسجيل الدخول باستخدام GitHub لإنشاء جوهر سري",
|
"require_github": "تسجيل الدخول باستخدام GitHub لإنشاء جوهر سري",
|
||||||
"title": "Export"
|
"title": "Export"
|
||||||
@@ -286,6 +341,9 @@
|
|||||||
"subscriptions": "الاشتراكات",
|
"subscriptions": "الاشتراكات",
|
||||||
"switch_connection": "Switch connection"
|
"switch_connection": "Switch connection"
|
||||||
},
|
},
|
||||||
|
"graphql_collections": {
|
||||||
|
"title": "GraphQL Collections"
|
||||||
|
},
|
||||||
"group": {
|
"group": {
|
||||||
"time": "Time",
|
"time": "Time",
|
||||||
"url": "URL"
|
"url": "URL"
|
||||||
@@ -297,6 +355,8 @@
|
|||||||
},
|
},
|
||||||
"helpers": {
|
"helpers": {
|
||||||
"authorization": "سيتم إنشاء رأس التفويض تلقائيًا عند إرسال الطلب.",
|
"authorization": "سيتم إنشاء رأس التفويض تلقائيًا عند إرسال الطلب.",
|
||||||
|
"collection_properties_authorization": " This authorization will be set for every request in this collection.",
|
||||||
|
"collection_properties_header": "This header will be set for every request in this collection.",
|
||||||
"generate_documentation_first": "قم بإنشاء الوثائق أولاً",
|
"generate_documentation_first": "قم بإنشاء الوثائق أولاً",
|
||||||
"network_fail": "تعذر الوصول إلى نقطة نهاية API. تحقق من اتصالك بالشبكة وحاول مرة أخرى.",
|
"network_fail": "تعذر الوصول إلى نقطة نهاية API. تحقق من اتصالك بالشبكة وحاول مرة أخرى.",
|
||||||
"offline": "يبدو أنك غير متصل بالإنترنت. قد لا تكون البيانات الموجودة في مساحة العمل هذه محدثة.",
|
"offline": "يبدو أنك غير متصل بالإنترنت. قد لا تكون البيانات الموجودة في مساحة العمل هذه محدثة.",
|
||||||
@@ -316,7 +376,10 @@
|
|||||||
"import": {
|
"import": {
|
||||||
"collections": "مجموعات الاستيراد",
|
"collections": "مجموعات الاستيراد",
|
||||||
"curl": "استيراد cURL",
|
"curl": "استيراد cURL",
|
||||||
|
"environments_from_gist": "Import From Gist",
|
||||||
|
"environments_from_gist_description": "Import Hoppscotch Environments From Gist",
|
||||||
"failed": "فشل الاستيراد",
|
"failed": "فشل الاستيراد",
|
||||||
|
"from_file": "Import from File",
|
||||||
"from_gist": "الاستيراد من Gist",
|
"from_gist": "الاستيراد من Gist",
|
||||||
"from_gist_description": "استيراد من Gist URL",
|
"from_gist_description": "استيراد من Gist URL",
|
||||||
"from_insomnia": "استيراد من Insomnia",
|
"from_insomnia": "استيراد من Insomnia",
|
||||||
@@ -331,11 +394,17 @@
|
|||||||
"from_postman_description": "استيراد من مجموعة Postman",
|
"from_postman_description": "استيراد من مجموعة Postman",
|
||||||
"from_url": "استيراد من رابط",
|
"from_url": "استيراد من رابط",
|
||||||
"gist_url": "أدخل عنوان URL لـ Gist",
|
"gist_url": "أدخل عنوان URL لـ Gist",
|
||||||
|
"gql_collections_from_gist_description": "Import GraphQL Collections From Gist",
|
||||||
|
"hoppscotch_environment": "Hoppscotch Environment",
|
||||||
|
"hoppscotch_environment_description": "Import Hoppscotch Environment JSON file",
|
||||||
"import_from_url_invalid_fetch": "Couldn't get data from the url",
|
"import_from_url_invalid_fetch": "Couldn't get data from the url",
|
||||||
"import_from_url_invalid_file_format": "Error while importing collections",
|
"import_from_url_invalid_file_format": "Error while importing collections",
|
||||||
"import_from_url_invalid_type": "Unsupported type. accepted values are 'hoppscotch', 'openapi', 'postman', 'insomnia'",
|
"import_from_url_invalid_type": "Unsupported type. accepted values are 'hoppscotch', 'openapi', 'postman', 'insomnia'",
|
||||||
"import_from_url_success": "Collections Imported",
|
"import_from_url_success": "Collections Imported",
|
||||||
|
"insomnia_environment_description": "Import Insomnia Environment from a JSON/YAML file",
|
||||||
"json_description": "استيراد مجموعة من ملفHoppscotch Collections JSON file",
|
"json_description": "استيراد مجموعة من ملفHoppscotch Collections JSON file",
|
||||||
|
"postman_environment": "Postman Environment",
|
||||||
|
"postman_environment_description": "Import Postman Environment from a JSON file",
|
||||||
"title": "يستورد"
|
"title": "يستورد"
|
||||||
},
|
},
|
||||||
"inspections": {
|
"inspections": {
|
||||||
@@ -373,8 +442,10 @@
|
|||||||
"close_unsaved_tab": "You have unsaved changes",
|
"close_unsaved_tab": "You have unsaved changes",
|
||||||
"collections": "المجموعات",
|
"collections": "المجموعات",
|
||||||
"confirm": "يتأكد",
|
"confirm": "يتأكد",
|
||||||
|
"customize_request": "Customize Request",
|
||||||
"edit_request": "تحرير الطلب",
|
"edit_request": "تحرير الطلب",
|
||||||
"import_export": "استيراد و تصدير"
|
"import_export": "استيراد و تصدير",
|
||||||
|
"share_request": "Share Request"
|
||||||
},
|
},
|
||||||
"mqtt": {
|
"mqtt": {
|
||||||
"already_subscribed": "You are already subscribed to this topic.",
|
"already_subscribed": "You are already subscribed to this topic.",
|
||||||
@@ -449,13 +520,14 @@
|
|||||||
"structured": "Structured",
|
"structured": "Structured",
|
||||||
"text": "Text"
|
"text": "Text"
|
||||||
},
|
},
|
||||||
"copy_link": "نسخ الوصلة",
|
|
||||||
"different_collection": "Cannot reorder requests from different collections",
|
"different_collection": "Cannot reorder requests from different collections",
|
||||||
"duplicated": "Request duplicated",
|
"duplicated": "Request duplicated",
|
||||||
"duration": "مدة",
|
"duration": "مدة",
|
||||||
"enter_curl": "أدخل cURL",
|
"enter_curl": "أدخل cURL",
|
||||||
"generate_code": "إنشاء التعليمات البرمجية",
|
"generate_code": "إنشاء التعليمات البرمجية",
|
||||||
"generated_code": "رمز تم إنشاؤه",
|
"generated_code": "رمز تم إنشاؤه",
|
||||||
|
"go_to_authorization_tab": "Go to Authorization tab",
|
||||||
|
"go_to_body_tab": "Go to Body tab",
|
||||||
"header_list": "قائمة الرأس",
|
"header_list": "قائمة الرأس",
|
||||||
"invalid_name": "يرجى تقديم اسم للطلب",
|
"invalid_name": "يرجى تقديم اسم للطلب",
|
||||||
"method": "طريقة",
|
"method": "طريقة",
|
||||||
@@ -480,12 +552,14 @@
|
|||||||
"saved": "تم حفظ الطلب",
|
"saved": "تم حفظ الطلب",
|
||||||
"share": "يشارك",
|
"share": "يشارك",
|
||||||
"share_description": "Share Hoppscotch with your friends",
|
"share_description": "Share Hoppscotch with your friends",
|
||||||
|
"share_request": "Share Request",
|
||||||
"stop": "Stop",
|
"stop": "Stop",
|
||||||
"title": "طلب",
|
"title": "طلب",
|
||||||
"type": "نوع الطلب",
|
"type": "نوع الطلب",
|
||||||
"url": "URL",
|
"url": "URL",
|
||||||
"variables": "المتغيرات",
|
"variables": "المتغيرات",
|
||||||
"view_my_links": "View my links"
|
"view_my_links": "View my links",
|
||||||
|
"copy_link": "نسخ الوصلة"
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"audio": "Audio",
|
"audio": "Audio",
|
||||||
@@ -513,6 +587,7 @@
|
|||||||
"account_description": "تخصيص إعدادات حسابك.",
|
"account_description": "تخصيص إعدادات حسابك.",
|
||||||
"account_email_description": "عنوان بريدك الإلكتروني الأساسي.",
|
"account_email_description": "عنوان بريدك الإلكتروني الأساسي.",
|
||||||
"account_name_description": "هذا هو اسم العرض الخاص بك.",
|
"account_name_description": "هذا هو اسم العرض الخاص بك.",
|
||||||
|
"additional": "Additional Settings",
|
||||||
"background": "خلفية",
|
"background": "خلفية",
|
||||||
"black_mode": "أسود",
|
"black_mode": "أسود",
|
||||||
"choose_language": "اختر اللغة",
|
"choose_language": "اختر اللغة",
|
||||||
@@ -559,14 +634,31 @@
|
|||||||
"verified_email": "Verified email",
|
"verified_email": "Verified email",
|
||||||
"verify_email": "تأكيد البريد الإلكتروني"
|
"verify_email": "تأكيد البريد الإلكتروني"
|
||||||
},
|
},
|
||||||
"shortcodes": {
|
"shared_requests": {
|
||||||
"actions": "Actions",
|
"button": "Button",
|
||||||
"created_on": "Created on",
|
"button_info": "Create a 'Run in Hoppscotch' button for your website, blog or a README.",
|
||||||
"deleted": "Shortcode deleted",
|
"copy_html": "Copy HTML",
|
||||||
"method": "Method",
|
"copy_link": "Copy Link",
|
||||||
"not_found": "Shortcode not found",
|
"copy_markdown": "Copy Markdown",
|
||||||
"short_code": "Short code",
|
"creating_widget": "Creating widget",
|
||||||
"url": "URL"
|
"customize": "Customize",
|
||||||
|
"deleted": "Shared request deleted",
|
||||||
|
"description": "Select a widget, you can change and customize this later",
|
||||||
|
"embed": "Embed",
|
||||||
|
"embed_info": "Add a mini 'Hoppscotch API Playground' to your website, blog or documentation.",
|
||||||
|
"link": "Link",
|
||||||
|
"link_info": "Create a shareable link to share with anyone on the internet with view access.",
|
||||||
|
"modified": "Shared request modified",
|
||||||
|
"not_found": "Shared request not found",
|
||||||
|
"open_new_tab": "Open in new tab",
|
||||||
|
"preview": "Preview",
|
||||||
|
"run_in_hoppscotch": "Run in Hoppscotch",
|
||||||
|
"theme": {
|
||||||
|
"dark": "Dark",
|
||||||
|
"light": "Light",
|
||||||
|
"system": "System",
|
||||||
|
"title": "Theme"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"shortcut": {
|
"shortcut": {
|
||||||
"general": {
|
"general": {
|
||||||
@@ -596,7 +688,6 @@
|
|||||||
"title": "Others"
|
"title": "Others"
|
||||||
},
|
},
|
||||||
"request": {
|
"request": {
|
||||||
"copy_request_link": "نسخ ارتباط الطلب",
|
|
||||||
"delete_method": "حدد طريقة الحذف",
|
"delete_method": "حدد طريقة الحذف",
|
||||||
"get_method": "حدد طريقة GET",
|
"get_method": "حدد طريقة GET",
|
||||||
"head_method": "حدد طريقة HEAD",
|
"head_method": "حدد طريقة HEAD",
|
||||||
@@ -611,8 +702,10 @@
|
|||||||
"save_request": "Save Request",
|
"save_request": "Save Request",
|
||||||
"save_to_collections": "حفظ في المجموعات",
|
"save_to_collections": "حفظ في المجموعات",
|
||||||
"send_request": "ارسل طلب",
|
"send_request": "ارسل طلب",
|
||||||
|
"share_request": "Share Request",
|
||||||
"show_code": "Generate code snippet",
|
"show_code": "Generate code snippet",
|
||||||
"title": "طلب"
|
"title": "طلب",
|
||||||
|
"copy_request_link": "نسخ ارتباط الطلب"
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"copy": "Copy response to clipboard",
|
"copy": "Copy response to clipboard",
|
||||||
@@ -735,6 +828,7 @@
|
|||||||
"connection_error": "Failed to connect",
|
"connection_error": "Failed to connect",
|
||||||
"connection_failed": "Connection failed",
|
"connection_failed": "Connection failed",
|
||||||
"connection_lost": "Connection lost",
|
"connection_lost": "Connection lost",
|
||||||
|
"copied_interface_to_clipboard": "Copied {language} interface type to clipboard",
|
||||||
"copied_to_clipboard": "نسخ إلى الحافظة",
|
"copied_to_clipboard": "نسخ إلى الحافظة",
|
||||||
"deleted": "تم الحذف",
|
"deleted": "تم الحذف",
|
||||||
"deprecated": "إهمال",
|
"deprecated": "إهمال",
|
||||||
@@ -742,10 +836,12 @@
|
|||||||
"disconnected": "انقطع الاتصال",
|
"disconnected": "انقطع الاتصال",
|
||||||
"disconnected_from": "انقطع الاتصال بـ {name}",
|
"disconnected_from": "انقطع الاتصال بـ {name}",
|
||||||
"docs_generated": "تم إنشاء الوثائق",
|
"docs_generated": "تم إنشاء الوثائق",
|
||||||
|
"download_failed": "Download failed",
|
||||||
"download_started": "بدأ التنزيل",
|
"download_started": "بدأ التنزيل",
|
||||||
"enabled": "ممكن",
|
"enabled": "ممكن",
|
||||||
"file_imported": "تم استيراد الملف",
|
"file_imported": "تم استيراد الملف",
|
||||||
"finished_in": "انتهى في {duration} مللي ثانية",
|
"finished_in": "انتهى في {duration} مللي ثانية",
|
||||||
|
"hide": "Hide",
|
||||||
"history_deleted": "تم حذف السجل",
|
"history_deleted": "تم حذف السجل",
|
||||||
"linewrap": "خطوط الالتفاف",
|
"linewrap": "خطوط الالتفاف",
|
||||||
"loading": "تحميل...",
|
"loading": "تحميل...",
|
||||||
@@ -756,6 +852,7 @@
|
|||||||
"published_error": "Something went wrong while publishing msg: {topic} to topic: {message}",
|
"published_error": "Something went wrong while publishing msg: {topic} to topic: {message}",
|
||||||
"published_message": "Published message: {message} to topic: {topic}",
|
"published_message": "Published message: {message} to topic: {topic}",
|
||||||
"reconnection_error": "Failed to reconnect",
|
"reconnection_error": "Failed to reconnect",
|
||||||
|
"show": "Show",
|
||||||
"subscribed_failed": "Failed to subscribe to topic: {topic}",
|
"subscribed_failed": "Failed to subscribe to topic: {topic}",
|
||||||
"subscribed_success": "Successfully subscribed to topic: {topic}",
|
"subscribed_success": "Successfully subscribed to topic: {topic}",
|
||||||
"unsubscribed_failed": "Failed to unsubscribe from topic: {topic}",
|
"unsubscribed_failed": "Failed to unsubscribe from topic: {topic}",
|
||||||
@@ -791,6 +888,7 @@
|
|||||||
"queries": "استفسارات",
|
"queries": "استفسارات",
|
||||||
"query": "استفسار",
|
"query": "استفسار",
|
||||||
"schema": "مخطط",
|
"schema": "مخطط",
|
||||||
|
"shared_requests": "Shared Requests",
|
||||||
"socketio": "مقبس",
|
"socketio": "مقبس",
|
||||||
"sse": "SSE",
|
"sse": "SSE",
|
||||||
"tests": "الاختبارات",
|
"tests": "الاختبارات",
|
||||||
@@ -807,6 +905,7 @@
|
|||||||
"email_do_not_match": "البريد الإلكتروني لا يتوافق مع معلومات حسابك. اتصل بمدير الفريق.",
|
"email_do_not_match": "البريد الإلكتروني لا يتوافق مع معلومات حسابك. اتصل بمدير الفريق.",
|
||||||
"exit": "فريق الخروج",
|
"exit": "فريق الخروج",
|
||||||
"exit_disabled": "فقط المالك لا يمكنه الخروج من الفريق",
|
"exit_disabled": "فقط المالك لا يمكنه الخروج من الفريق",
|
||||||
|
"failed_invites": "Failed invites",
|
||||||
"invalid_coll_id": "Invalid collection ID",
|
"invalid_coll_id": "Invalid collection ID",
|
||||||
"invalid_email_format": "تنسيق البريد الإلكتروني غير صالح",
|
"invalid_email_format": "تنسيق البريد الإلكتروني غير صالح",
|
||||||
"invalid_id": "معرف الفريق غير صالح. اتصل بمدير الفريق.",
|
"invalid_id": "معرف الفريق غير صالح. اتصل بمدير الفريق.",
|
||||||
@@ -848,6 +947,7 @@
|
|||||||
"same_target_destination": "Same target and destination",
|
"same_target_destination": "Same target and destination",
|
||||||
"saved": "فريق حفظ",
|
"saved": "فريق حفظ",
|
||||||
"select_a_team": "اختر فريق",
|
"select_a_team": "اختر فريق",
|
||||||
|
"success_invites": "Success invites",
|
||||||
"title": "فرق",
|
"title": "فرق",
|
||||||
"we_sent_invite_link": "لقد أرسلنا رابط دعوة لجميع المدعوين!",
|
"we_sent_invite_link": "لقد أرسلنا رابط دعوة لجميع المدعوين!",
|
||||||
"we_sent_invite_link_description": "اطلب من جميع المدعوين التحقق من صندوق الوارد الخاص بهم. انقر على الرابط للانضمام إلى الفريق."
|
"we_sent_invite_link_description": "اطلب من جميع المدعوين التحقق من صندوق الوارد الخاص بهم. انقر على الرابط للانضمام إلى الفريق."
|
||||||
@@ -879,5 +979,14 @@
|
|||||||
"personal": "My Workspace",
|
"personal": "My Workspace",
|
||||||
"team": "Team Workspace",
|
"team": "Team Workspace",
|
||||||
"title": "Workspaces"
|
"title": "Workspaces"
|
||||||
|
},
|
||||||
|
"shortcodes": {
|
||||||
|
"actions": "Actions",
|
||||||
|
"created_on": "Created on",
|
||||||
|
"deleted": "Shortcode deleted",
|
||||||
|
"method": "Method",
|
||||||
|
"not_found": "Shortcode not found",
|
||||||
|
"short_code": "Short code",
|
||||||
|
"url": "URL"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"action": {
|
"action": {
|
||||||
|
"add": "Add",
|
||||||
"autoscroll": "Autoscroll",
|
"autoscroll": "Autoscroll",
|
||||||
"cancel": "Cancel·lar",
|
"cancel": "Cancel·lar",
|
||||||
"choose_file": "Triar un fitxer",
|
"choose_file": "Triar un fitxer",
|
||||||
@@ -10,6 +11,7 @@
|
|||||||
"connect": "Connectar",
|
"connect": "Connectar",
|
||||||
"connecting": "Connecting",
|
"connecting": "Connecting",
|
||||||
"copy": "Copiar",
|
"copy": "Copiar",
|
||||||
|
"create": "Create",
|
||||||
"delete": "Eliminar",
|
"delete": "Eliminar",
|
||||||
"disconnect": "Desconnectar",
|
"disconnect": "Desconnectar",
|
||||||
"dismiss": "Tancar",
|
"dismiss": "Tancar",
|
||||||
@@ -31,6 +33,7 @@
|
|||||||
"open_workspace": "Obrir espai de treball",
|
"open_workspace": "Obrir espai de treball",
|
||||||
"paste": "Enganxar",
|
"paste": "Enganxar",
|
||||||
"prettify": "Fes-ho bonic",
|
"prettify": "Fes-ho bonic",
|
||||||
|
"properties": "Properties",
|
||||||
"remove": "Eliminar",
|
"remove": "Eliminar",
|
||||||
"rename": "Rename",
|
"rename": "Rename",
|
||||||
"restore": "Restaurar",
|
"restore": "Restaurar",
|
||||||
@@ -39,6 +42,7 @@
|
|||||||
"scroll_to_top": "Desplaceu-vos cap a dalt",
|
"scroll_to_top": "Desplaceu-vos cap a dalt",
|
||||||
"search": "Cercar",
|
"search": "Cercar",
|
||||||
"send": "Enviar",
|
"send": "Enviar",
|
||||||
|
"share": "Share",
|
||||||
"start": "Començar",
|
"start": "Començar",
|
||||||
"starting": "Starting",
|
"starting": "Starting",
|
||||||
"stop": "Aturar",
|
"stop": "Aturar",
|
||||||
@@ -57,7 +61,9 @@
|
|||||||
"app": {
|
"app": {
|
||||||
"chat_with_us": "Xateja amb nosaltres",
|
"chat_with_us": "Xateja amb nosaltres",
|
||||||
"contact_us": "Contacta amb nosaltres",
|
"contact_us": "Contacta amb nosaltres",
|
||||||
|
"cookies": "Cookies",
|
||||||
"copy": "Copiar",
|
"copy": "Copiar",
|
||||||
|
"copy_interface_type": "Copy interface type",
|
||||||
"copy_user_id": "Copiar User Auth Token",
|
"copy_user_id": "Copiar User Auth Token",
|
||||||
"developer_option": "Opcions de desenvolupador",
|
"developer_option": "Opcions de desenvolupador",
|
||||||
"developer_option_description": "Eines de desenvolupament que ajuden en el desenvolupament i manteniment de Hoppscotch.",
|
"developer_option_description": "Eines de desenvolupament que ajuden en el desenvolupament i manteniment de Hoppscotch.",
|
||||||
@@ -73,6 +79,7 @@
|
|||||||
"keyboard_shortcuts": "Dreceres de teclat",
|
"keyboard_shortcuts": "Dreceres de teclat",
|
||||||
"name": "Hoppscotch",
|
"name": "Hoppscotch",
|
||||||
"new_version_found": "S'ha trobat una nova versió. Refresca per actualitzar.",
|
"new_version_found": "S'ha trobat una nova versió. Refresca per actualitzar.",
|
||||||
|
"open_in_hoppscotch": "Open in Hoppscotch",
|
||||||
"options": "Opcions",
|
"options": "Opcions",
|
||||||
"proxy_privacy_policy": "Política de privadesa del servidor intermediari (proxy)",
|
"proxy_privacy_policy": "Política de privadesa del servidor intermediari (proxy)",
|
||||||
"reload": "Recarregar",
|
"reload": "Recarregar",
|
||||||
@@ -112,10 +119,27 @@
|
|||||||
},
|
},
|
||||||
"authorization": {
|
"authorization": {
|
||||||
"generate_token": "Generar Token",
|
"generate_token": "Generar Token",
|
||||||
|
"graphql_headers": "Authorization Headers are sent as part of the payload to connection_init",
|
||||||
"include_in_url": "Inclou a l'URL",
|
"include_in_url": "Inclou a l'URL",
|
||||||
|
"inherited_from": "Inherited from {auth} from Parent Collection {collection} ",
|
||||||
"learn": "Aprèn com",
|
"learn": "Aprèn com",
|
||||||
|
"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": "Passar per",
|
"pass_key_by": "Passar per",
|
||||||
"password": "Contrasenya",
|
"password": "Contrasenya",
|
||||||
|
"save_to_inherit": "Please save this request in any collection to inherit the authorization",
|
||||||
"token": "Token",
|
"token": "Token",
|
||||||
"type": "Tipus d'autorització",
|
"type": "Tipus d'autorització",
|
||||||
"username": "Nom d'usuari"
|
"username": "Nom d'usuari"
|
||||||
@@ -124,6 +148,7 @@
|
|||||||
"created": "Col·lecció creada",
|
"created": "Col·lecció creada",
|
||||||
"different_parent": "Cannot reorder collection with different parent",
|
"different_parent": "Cannot reorder collection with different parent",
|
||||||
"edit": "Editar la col·lecció",
|
"edit": "Editar la col·lecció",
|
||||||
|
"import_or_create": "Import or create a collection",
|
||||||
"invalid_name": "Proporcioneu un nom vàlid per a la col·lecció",
|
"invalid_name": "Proporcioneu un nom vàlid per a la col·lecció",
|
||||||
"invalid_root_move": "Collection already in the root",
|
"invalid_root_move": "Collection already in the root",
|
||||||
"moved": "Moved Successfully",
|
"moved": "Moved Successfully",
|
||||||
@@ -132,6 +157,8 @@
|
|||||||
"name_length_insufficient": "El nom de la col·lecció ha de tenir almenys 3 caràcters",
|
"name_length_insufficient": "El nom de la col·lecció ha de tenir almenys 3 caràcters",
|
||||||
"new": "Nova col · lecció",
|
"new": "Nova col · lecció",
|
||||||
"order_changed": "Collection Order Updated",
|
"order_changed": "Collection Order Updated",
|
||||||
|
"properties": "Collection Properties",
|
||||||
|
"properties_updated": "Collection Properties Updated",
|
||||||
"renamed": "S'ha canviat el nom de la col·lecció",
|
"renamed": "S'ha canviat el nom de la col·lecció",
|
||||||
"request_in_use": "Request in use",
|
"request_in_use": "Request in use",
|
||||||
"save_as": "Guardar com",
|
"save_as": "Guardar com",
|
||||||
@@ -151,6 +178,7 @@
|
|||||||
"remove_folder": "Està segur que vol suprimir definitivament aquesta carpeta?",
|
"remove_folder": "Està segur que vol suprimir definitivament aquesta carpeta?",
|
||||||
"remove_history": "Està segur que vol suprimir definitivament tot l'historial?",
|
"remove_history": "Està segur que vol suprimir definitivament tot l'historial?",
|
||||||
"remove_request": "Està segur que vol suprimir definitivament aquesta sol·licitud?",
|
"remove_request": "Està segur que vol suprimir definitivament aquesta sol·licitud?",
|
||||||
|
"remove_shared_request": "Are you sure you want to permanently delete this shared request?",
|
||||||
"remove_team": "Està segur que vol suprimir aquest equip?",
|
"remove_team": "Està segur que vol suprimir aquest equip?",
|
||||||
"remove_telemetry": "Està segur que vol desactivar Telemetry?",
|
"remove_telemetry": "Està segur que vol desactivar Telemetry?",
|
||||||
"request_change": "Està segur que vol descartar la sol·licitud actual, els canvis no desats es perdran.",
|
"request_change": "Està segur que vol descartar la sol·licitud actual, els canvis no desats es perdran.",
|
||||||
@@ -162,6 +190,24 @@
|
|||||||
"open_request_in_new_tab": "Open request in new tab",
|
"open_request_in_new_tab": "Open request in new tab",
|
||||||
"set_environment_variable": "Set as variable"
|
"set_environment_variable": "Set as variable"
|
||||||
},
|
},
|
||||||
|
"cookies": {
|
||||||
|
"modal": {
|
||||||
|
"cookie_expires": "Expires",
|
||||||
|
"cookie_name": "Name",
|
||||||
|
"cookie_path": "Path",
|
||||||
|
"cookie_string": "Cookie string",
|
||||||
|
"cookie_value": "Value",
|
||||||
|
"empty_domain": "Domain is empty",
|
||||||
|
"empty_domains": "Domain list is empty",
|
||||||
|
"enter_cookie_string": "Enter cookie string",
|
||||||
|
"interceptor_no_support": "Your currently selected interceptor does not support cookies. Select a different Interceptor and try again.",
|
||||||
|
"managed_tab": "Managed",
|
||||||
|
"new_domain_name": "New domain name",
|
||||||
|
"no_cookies_in_domain": "No cookies set for this domain",
|
||||||
|
"raw_tab": "Raw",
|
||||||
|
"set": "Set a cookie"
|
||||||
|
}
|
||||||
|
},
|
||||||
"count": {
|
"count": {
|
||||||
"header": "Capçalera {count}",
|
"header": "Capçalera {count}",
|
||||||
"message": "Missatges {count}",
|
"message": "Missatges {count}",
|
||||||
@@ -192,11 +238,13 @@
|
|||||||
"profile": "Inicia sessió per veure el vostre perfil",
|
"profile": "Inicia sessió per veure el vostre perfil",
|
||||||
"protocols": "Els protocols estan buits",
|
"protocols": "Els protocols estan buits",
|
||||||
"schema": "Connecta't a un endpoint GraphQL",
|
"schema": "Connecta't a un endpoint GraphQL",
|
||||||
"shortcodes": "Els shortcodes estan buits",
|
"shared_requests": "Shared requests are empty",
|
||||||
|
"shared_requests_logout": "Login to view your shared requests or create a new one",
|
||||||
"subscription": "Subscriptions are empty",
|
"subscription": "Subscriptions are empty",
|
||||||
"team_name": "El nom de l'equip és buit",
|
"team_name": "El nom de l'equip és buit",
|
||||||
"teams": "Els equips estan buits",
|
"teams": "Els equips estan buits",
|
||||||
"tests": "No hi ha proves per a aquesta sol·licitud"
|
"tests": "No hi ha proves per a aquesta sol·licitud",
|
||||||
|
"shortcodes": "Els shortcodes estan buits"
|
||||||
},
|
},
|
||||||
"environment": {
|
"environment": {
|
||||||
"add_to_global": "Afegir-ho a Global",
|
"add_to_global": "Afegir-ho a Global",
|
||||||
@@ -209,6 +257,7 @@
|
|||||||
"empty_variables": "No variables",
|
"empty_variables": "No variables",
|
||||||
"global": "Global",
|
"global": "Global",
|
||||||
"global_variables": "Global variables",
|
"global_variables": "Global variables",
|
||||||
|
"import_or_create": "Import or create a environment",
|
||||||
"invalid_name": "Proporcioneu un nom vàlid per a l'entorn",
|
"invalid_name": "Proporcioneu un nom vàlid per a l'entorn",
|
||||||
"list": "Environment variables",
|
"list": "Environment variables",
|
||||||
"my_environments": "My Environments",
|
"my_environments": "My Environments",
|
||||||
@@ -232,8 +281,10 @@
|
|||||||
"variable_list": "Llista de variables"
|
"variable_list": "Llista de variables"
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
|
"authproviders_load_error": "Unable to load auth providers",
|
||||||
"browser_support_sse": "Sembla que aquest navegador no és compatible amb els Esdeveniments Enviats pel Servidor (Server Sent Events).",
|
"browser_support_sse": "Sembla que aquest navegador no és compatible amb els Esdeveniments Enviats pel Servidor (Server Sent Events).",
|
||||||
"check_console_details": "Consulta el registre de la consola per obtenir més informació.",
|
"check_console_details": "Consulta el registre de la consola per obtenir més informació.",
|
||||||
|
"check_how_to_add_origin": "Check how you can add an origin",
|
||||||
"curl_invalid_format": "cURL no està formatat correctament",
|
"curl_invalid_format": "cURL no està formatat correctament",
|
||||||
"danger_zone": "Danger zone",
|
"danger_zone": "Danger zone",
|
||||||
"delete_account": "Your account is currently an owner in these teams:",
|
"delete_account": "Your account is currently an owner in these teams:",
|
||||||
@@ -249,9 +300,12 @@
|
|||||||
"json_prettify_invalid_body": "No s'ha pogut personalitzar un cos no vàlid, resol els errors de sintaxi json i tornar-ho a provar",
|
"json_prettify_invalid_body": "No s'ha pogut personalitzar un cos no vàlid, resol els errors de sintaxi json i tornar-ho a provar",
|
||||||
"network_error": "Sembla que hi ha un error de xarxa. Si us plau torna-ho a provar.",
|
"network_error": "Sembla que hi ha un error de xarxa. Si us plau torna-ho a provar.",
|
||||||
"network_fail": "No s'ha pogut enviar la sol·licitud",
|
"network_fail": "No s'ha pogut enviar la sol·licitud",
|
||||||
|
"no_collections_to_export": "No collections to export. Please create a collection to get started.",
|
||||||
"no_duration": "Sense durada",
|
"no_duration": "Sense durada",
|
||||||
|
"no_environments_to_export": "No environments to export. Please create an environment to get started.",
|
||||||
"no_results_found": "No s'ha trobat cap coincidència",
|
"no_results_found": "No s'ha trobat cap coincidència",
|
||||||
"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.",
|
||||||
"proxy_error": "Proxy error",
|
"proxy_error": "Proxy error",
|
||||||
"script_fail": "No s'ha pogut executar l'script de sol·licitud prèvia",
|
"script_fail": "No s'ha pogut executar l'script de sol·licitud prèvia",
|
||||||
"something_went_wrong": "Alguna cosa ha anat malament",
|
"something_went_wrong": "Alguna cosa ha anat malament",
|
||||||
@@ -260,6 +314,7 @@
|
|||||||
"export": {
|
"export": {
|
||||||
"as_json": "Exporta com a JSON",
|
"as_json": "Exporta com a JSON",
|
||||||
"create_secret_gist": "Crear un Gist secret",
|
"create_secret_gist": "Crear un Gist secret",
|
||||||
|
"failed": "Something went wrong while exporting",
|
||||||
"gist_created": "Gist creat",
|
"gist_created": "Gist creat",
|
||||||
"require_github": "Inicieu la sessió amb GitHub per crear un Gisst secret",
|
"require_github": "Inicieu la sessió amb GitHub per crear un Gisst secret",
|
||||||
"title": "Exportar"
|
"title": "Exportar"
|
||||||
@@ -286,6 +341,9 @@
|
|||||||
"subscriptions": "Subscripcions",
|
"subscriptions": "Subscripcions",
|
||||||
"switch_connection": "Switch connection"
|
"switch_connection": "Switch connection"
|
||||||
},
|
},
|
||||||
|
"graphql_collections": {
|
||||||
|
"title": "GraphQL Collections"
|
||||||
|
},
|
||||||
"group": {
|
"group": {
|
||||||
"time": "Time",
|
"time": "Time",
|
||||||
"url": "URL"
|
"url": "URL"
|
||||||
@@ -297,6 +355,8 @@
|
|||||||
},
|
},
|
||||||
"helpers": {
|
"helpers": {
|
||||||
"authorization": "La capçalera de l'autorització es generarà automàticament quan envieu la sol·licitud.",
|
"authorization": "La capçalera de l'autorització es generarà automàticament quan envieu la sol·licitud.",
|
||||||
|
"collection_properties_authorization": " This authorization will be set for every request in this collection.",
|
||||||
|
"collection_properties_header": "This header will be set for every request in this collection.",
|
||||||
"generate_documentation_first": "Genereu documentació primer",
|
"generate_documentation_first": "Genereu documentació primer",
|
||||||
"network_fail": "No es pot arribar al punt final de l'API. Comproveu la connexió de xarxa i torneu-ho a provar.",
|
"network_fail": "No es pot arribar al punt final de l'API. Comproveu la connexió de xarxa i torneu-ho a provar.",
|
||||||
"offline": "Sembla que estàs fora de línia. És possible que les dades d'aquest espai de treball no estiguin actualitzades.",
|
"offline": "Sembla que estàs fora de línia. És possible que les dades d'aquest espai de treball no estiguin actualitzades.",
|
||||||
@@ -316,7 +376,10 @@
|
|||||||
"import": {
|
"import": {
|
||||||
"collections": "Importar col·leccions",
|
"collections": "Importar col·leccions",
|
||||||
"curl": "Importar cURL",
|
"curl": "Importar cURL",
|
||||||
|
"environments_from_gist": "Import From Gist",
|
||||||
|
"environments_from_gist_description": "Import Hoppscotch Environments From Gist",
|
||||||
"failed": "La importació ha fallat",
|
"failed": "La importació ha fallat",
|
||||||
|
"from_file": "Import from File",
|
||||||
"from_gist": "Importar des de Gist",
|
"from_gist": "Importar des de Gist",
|
||||||
"from_gist_description": "Importar des de l'URL de Gist",
|
"from_gist_description": "Importar des de l'URL de Gist",
|
||||||
"from_insomnia": "Importar des d'Insomnia",
|
"from_insomnia": "Importar des d'Insomnia",
|
||||||
@@ -331,11 +394,17 @@
|
|||||||
"from_postman_description": "Importar des de la col·lecció de Postman",
|
"from_postman_description": "Importar des de la col·lecció de Postman",
|
||||||
"from_url": "Importar des de l'URL",
|
"from_url": "Importar des de l'URL",
|
||||||
"gist_url": "Introduïu l'URL del Gist",
|
"gist_url": "Introduïu l'URL del Gist",
|
||||||
|
"gql_collections_from_gist_description": "Import GraphQL Collections From Gist",
|
||||||
|
"hoppscotch_environment": "Hoppscotch Environment",
|
||||||
|
"hoppscotch_environment_description": "Import Hoppscotch Environment JSON file",
|
||||||
"import_from_url_invalid_fetch": "No s'han pogut obtenir dades de l'URL",
|
"import_from_url_invalid_fetch": "No s'han pogut obtenir dades de l'URL",
|
||||||
"import_from_url_invalid_file_format": "S'ha produït un error en importar les col·leccions",
|
"import_from_url_invalid_file_format": "S'ha produït un error en importar les col·leccions",
|
||||||
"import_from_url_invalid_type": "Tipus no compatible. Els valors acceptats són 'hoppscotch', 'openapi', 'postman', 'insomnia'",
|
"import_from_url_invalid_type": "Tipus no compatible. Els valors acceptats són 'hoppscotch', 'openapi', 'postman', 'insomnia'",
|
||||||
"import_from_url_success": "Col·leccions importades",
|
"import_from_url_success": "Col·leccions importades",
|
||||||
|
"insomnia_environment_description": "Import Insomnia Environment from a JSON/YAML file",
|
||||||
"json_description": "Importar col·leccions des d'un fitxer JSON de col·leccions Hoppscotch",
|
"json_description": "Importar col·leccions des d'un fitxer JSON de col·leccions Hoppscotch",
|
||||||
|
"postman_environment": "Postman Environment",
|
||||||
|
"postman_environment_description": "Import Postman Environment from a JSON file",
|
||||||
"title": "Importació"
|
"title": "Importació"
|
||||||
},
|
},
|
||||||
"inspections": {
|
"inspections": {
|
||||||
@@ -373,8 +442,10 @@
|
|||||||
"close_unsaved_tab": "You have unsaved changes",
|
"close_unsaved_tab": "You have unsaved changes",
|
||||||
"collections": "Col·leccions",
|
"collections": "Col·leccions",
|
||||||
"confirm": "Confirmar",
|
"confirm": "Confirmar",
|
||||||
|
"customize_request": "Customize Request",
|
||||||
"edit_request": "Sol·licitud d'edició",
|
"edit_request": "Sol·licitud d'edició",
|
||||||
"import_export": "Importar / Exportar"
|
"import_export": "Importar / Exportar",
|
||||||
|
"share_request": "Share Request"
|
||||||
},
|
},
|
||||||
"mqtt": {
|
"mqtt": {
|
||||||
"already_subscribed": "You are already subscribed to this topic.",
|
"already_subscribed": "You are already subscribed to this topic.",
|
||||||
@@ -449,13 +520,14 @@
|
|||||||
"structured": "Estructurat",
|
"structured": "Estructurat",
|
||||||
"text": "Text"
|
"text": "Text"
|
||||||
},
|
},
|
||||||
"copy_link": "Copia l'enllaç",
|
|
||||||
"different_collection": "Cannot reorder requests from different collections",
|
"different_collection": "Cannot reorder requests from different collections",
|
||||||
"duplicated": "Request duplicated",
|
"duplicated": "Request duplicated",
|
||||||
"duration": "Durada",
|
"duration": "Durada",
|
||||||
"enter_curl": "Introduïu cURL",
|
"enter_curl": "Introduïu cURL",
|
||||||
"generate_code": "Generar codi",
|
"generate_code": "Generar codi",
|
||||||
"generated_code": "Codi generat",
|
"generated_code": "Codi generat",
|
||||||
|
"go_to_authorization_tab": "Go to Authorization tab",
|
||||||
|
"go_to_body_tab": "Go to Body tab",
|
||||||
"header_list": "Llista de capçaleres",
|
"header_list": "Llista de capçaleres",
|
||||||
"invalid_name": "Proporcioneu un nom per a la sol·licitud",
|
"invalid_name": "Proporcioneu un nom per a la sol·licitud",
|
||||||
"method": "Mètode",
|
"method": "Mètode",
|
||||||
@@ -480,12 +552,14 @@
|
|||||||
"saved": "S'ha desat la sol·licitud",
|
"saved": "S'ha desat la sol·licitud",
|
||||||
"share": "Compartir",
|
"share": "Compartir",
|
||||||
"share_description": "Comparteix Hoppscotch amb els teus amics",
|
"share_description": "Comparteix Hoppscotch amb els teus amics",
|
||||||
|
"share_request": "Share Request",
|
||||||
"stop": "Stop",
|
"stop": "Stop",
|
||||||
"title": "Sol·licitud",
|
"title": "Sol·licitud",
|
||||||
"type": "Tipus de sol·licitud",
|
"type": "Tipus de sol·licitud",
|
||||||
"url": "URL",
|
"url": "URL",
|
||||||
"variables": "Variables",
|
"variables": "Variables",
|
||||||
"view_my_links": "Visualitzar els meus enllaços"
|
"view_my_links": "Visualitzar els meus enllaços",
|
||||||
|
"copy_link": "Copia l'enllaç"
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"audio": "Audio",
|
"audio": "Audio",
|
||||||
@@ -513,6 +587,7 @@
|
|||||||
"account_description": "Personalitzeu la configuració del compte.",
|
"account_description": "Personalitzeu la configuració del compte.",
|
||||||
"account_email_description": "La vostra adreça de correu electrònic principal.",
|
"account_email_description": "La vostra adreça de correu electrònic principal.",
|
||||||
"account_name_description": "Aquest és el vostre nom d'exposició",
|
"account_name_description": "Aquest és el vostre nom d'exposició",
|
||||||
|
"additional": "Additional Settings",
|
||||||
"background": "Fons",
|
"background": "Fons",
|
||||||
"black_mode": "Negre",
|
"black_mode": "Negre",
|
||||||
"choose_language": "Tria l'idioma",
|
"choose_language": "Tria l'idioma",
|
||||||
@@ -559,14 +634,31 @@
|
|||||||
"verified_email": "Verified email",
|
"verified_email": "Verified email",
|
||||||
"verify_email": "Verificar correu electronic"
|
"verify_email": "Verificar correu electronic"
|
||||||
},
|
},
|
||||||
"shortcodes": {
|
"shared_requests": {
|
||||||
"actions": "Accions",
|
"button": "Button",
|
||||||
"created_on": "Creat el",
|
"button_info": "Create a 'Run in Hoppscotch' button for your website, blog or a README.",
|
||||||
"deleted": "S'ha suprimit el shortcode",
|
"copy_html": "Copy HTML",
|
||||||
"method": "Mètode",
|
"copy_link": "Copy Link",
|
||||||
"not_found": "No s'ha trobat el shortcode",
|
"copy_markdown": "Copy Markdown",
|
||||||
"short_code": "Short code",
|
"creating_widget": "Creating widget",
|
||||||
"url": "URL"
|
"customize": "Customize",
|
||||||
|
"deleted": "Shared request deleted",
|
||||||
|
"description": "Select a widget, you can change and customize this later",
|
||||||
|
"embed": "Embed",
|
||||||
|
"embed_info": "Add a mini 'Hoppscotch API Playground' to your website, blog or documentation.",
|
||||||
|
"link": "Link",
|
||||||
|
"link_info": "Create a shareable link to share with anyone on the internet with view access.",
|
||||||
|
"modified": "Shared request modified",
|
||||||
|
"not_found": "Shared request not found",
|
||||||
|
"open_new_tab": "Open in new tab",
|
||||||
|
"preview": "Preview",
|
||||||
|
"run_in_hoppscotch": "Run in Hoppscotch",
|
||||||
|
"theme": {
|
||||||
|
"dark": "Dark",
|
||||||
|
"light": "Light",
|
||||||
|
"system": "System",
|
||||||
|
"title": "Theme"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"shortcut": {
|
"shortcut": {
|
||||||
"general": {
|
"general": {
|
||||||
@@ -596,7 +688,6 @@
|
|||||||
"title": "Others"
|
"title": "Others"
|
||||||
},
|
},
|
||||||
"request": {
|
"request": {
|
||||||
"copy_request_link": "Copiar l'enllaç de la sol·licitud",
|
|
||||||
"delete_method": "Seleccionar el mètode DELETE",
|
"delete_method": "Seleccionar el mètode DELETE",
|
||||||
"get_method": "Seleccionar el mètode GET",
|
"get_method": "Seleccionar el mètode GET",
|
||||||
"head_method": "Seleccionar el mètode HEAD",
|
"head_method": "Seleccionar el mètode HEAD",
|
||||||
@@ -611,8 +702,10 @@
|
|||||||
"save_request": "Save Request",
|
"save_request": "Save Request",
|
||||||
"save_to_collections": "Guardar a les col·leccions",
|
"save_to_collections": "Guardar a les col·leccions",
|
||||||
"send_request": "Enviar sol.licitud",
|
"send_request": "Enviar sol.licitud",
|
||||||
|
"share_request": "Share Request",
|
||||||
"show_code": "Generate code snippet",
|
"show_code": "Generate code snippet",
|
||||||
"title": "Sol·licitud"
|
"title": "Sol·licitud",
|
||||||
|
"copy_request_link": "Copiar l'enllaç de la sol·licitud"
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"copy": "Copy response to clipboard",
|
"copy": "Copy response to clipboard",
|
||||||
@@ -735,6 +828,7 @@
|
|||||||
"connection_error": "No s'ha pogut connectar",
|
"connection_error": "No s'ha pogut connectar",
|
||||||
"connection_failed": "Connexió fallida",
|
"connection_failed": "Connexió fallida",
|
||||||
"connection_lost": "Connexió perduda",
|
"connection_lost": "Connexió perduda",
|
||||||
|
"copied_interface_to_clipboard": "Copied {language} interface type to clipboard",
|
||||||
"copied_to_clipboard": "Copiat al porta-retalls",
|
"copied_to_clipboard": "Copiat al porta-retalls",
|
||||||
"deleted": "Eliminat",
|
"deleted": "Eliminat",
|
||||||
"deprecated": "Obsolet",
|
"deprecated": "Obsolet",
|
||||||
@@ -742,10 +836,12 @@
|
|||||||
"disconnected": "Desconnectat",
|
"disconnected": "Desconnectat",
|
||||||
"disconnected_from": "Desconnectat de {name}",
|
"disconnected_from": "Desconnectat de {name}",
|
||||||
"docs_generated": "Documentació generada",
|
"docs_generated": "Documentació generada",
|
||||||
|
"download_failed": "Download failed",
|
||||||
"download_started": "S'ha iniciat la baixada",
|
"download_started": "S'ha iniciat la baixada",
|
||||||
"enabled": "Activat",
|
"enabled": "Activat",
|
||||||
"file_imported": "Fitxer importat",
|
"file_imported": "Fitxer importat",
|
||||||
"finished_in": "Acabat en {duration} ms",
|
"finished_in": "Acabat en {duration} ms",
|
||||||
|
"hide": "Hide",
|
||||||
"history_deleted": "S'ha suprimit l'historial",
|
"history_deleted": "S'ha suprimit l'historial",
|
||||||
"linewrap": "Embolcar línies",
|
"linewrap": "Embolcar línies",
|
||||||
"loading": "S'està carregant...",
|
"loading": "S'està carregant...",
|
||||||
@@ -756,6 +852,7 @@
|
|||||||
"published_error": "S'ha produït un error en publicar el missatge: {topic} al tema: {message}",
|
"published_error": "S'ha produït un error en publicar el missatge: {topic} al tema: {message}",
|
||||||
"published_message": "Missatge publicat: {missatge} al tema: {tema}",
|
"published_message": "Missatge publicat: {missatge} al tema: {tema}",
|
||||||
"reconnection_error": "No s'ha pogut tornar a connectar",
|
"reconnection_error": "No s'ha pogut tornar a connectar",
|
||||||
|
"show": "Show",
|
||||||
"subscribed_failed": "No s'ha pogut subscriure al tema: {topic}",
|
"subscribed_failed": "No s'ha pogut subscriure al tema: {topic}",
|
||||||
"subscribed_success": "S'ha subscrit correctament al tema: {topic}",
|
"subscribed_success": "S'ha subscrit correctament al tema: {topic}",
|
||||||
"unsubscribed_failed": "No s'ha pogut cancel·lar la subscripció al tema: {topic}",
|
"unsubscribed_failed": "No s'ha pogut cancel·lar la subscripció al tema: {topic}",
|
||||||
@@ -791,6 +888,7 @@
|
|||||||
"queries": "Consultes",
|
"queries": "Consultes",
|
||||||
"query": "Consulta",
|
"query": "Consulta",
|
||||||
"schema": "Schema",
|
"schema": "Schema",
|
||||||
|
"shared_requests": "Shared Requests",
|
||||||
"socketio": "Socket.IO",
|
"socketio": "Socket.IO",
|
||||||
"sse": "SSE",
|
"sse": "SSE",
|
||||||
"tests": "Proves",
|
"tests": "Proves",
|
||||||
@@ -807,6 +905,7 @@
|
|||||||
"email_do_not_match": "El correu electrònic no coincideix amb les dades del vostre compte. Contacta amb el propietari del teu equip.",
|
"email_do_not_match": "El correu electrònic no coincideix amb les dades del vostre compte. Contacta amb el propietari del teu equip.",
|
||||||
"exit": "Sortir de l'equip",
|
"exit": "Sortir de l'equip",
|
||||||
"exit_disabled": "L'únic propietari no pot sortir de l'equip",
|
"exit_disabled": "L'únic propietari no pot sortir de l'equip",
|
||||||
|
"failed_invites": "Failed invites",
|
||||||
"invalid_coll_id": "Invalid collection ID",
|
"invalid_coll_id": "Invalid collection ID",
|
||||||
"invalid_email_format": "El format del correu electrònic no és vàlid",
|
"invalid_email_format": "El format del correu electrònic no és vàlid",
|
||||||
"invalid_id": "Identificador d'equip no vàlid. Contacta amb el propietari del teu equip.",
|
"invalid_id": "Identificador d'equip no vàlid. Contacta amb el propietari del teu equip.",
|
||||||
@@ -848,6 +947,7 @@
|
|||||||
"same_target_destination": "Same target and destination",
|
"same_target_destination": "Same target and destination",
|
||||||
"saved": "S'ha guardat l'equip",
|
"saved": "S'ha guardat l'equip",
|
||||||
"select_a_team": "Select a team",
|
"select_a_team": "Select a team",
|
||||||
|
"success_invites": "Success invites",
|
||||||
"title": "Equips",
|
"title": "Equips",
|
||||||
"we_sent_invite_link": "Hem enviat un enllaç d'invitació a tots els convidats!",
|
"we_sent_invite_link": "Hem enviat un enllaç d'invitació a tots els convidats!",
|
||||||
"we_sent_invite_link_description": "Demaneu a tots els convidats que comprovin la seva safata d'entrada. Feu clic a l'enllaç per unir-vos a l'equip."
|
"we_sent_invite_link_description": "Demaneu a tots els convidats que comprovin la seva safata d'entrada. Feu clic a l'enllaç per unir-vos a l'equip."
|
||||||
@@ -879,5 +979,14 @@
|
|||||||
"personal": "My Workspace",
|
"personal": "My Workspace",
|
||||||
"team": "Team Workspace",
|
"team": "Team Workspace",
|
||||||
"title": "Workspaces"
|
"title": "Workspaces"
|
||||||
|
},
|
||||||
|
"shortcodes": {
|
||||||
|
"actions": "Accions",
|
||||||
|
"created_on": "Creat el",
|
||||||
|
"deleted": "S'ha suprimit el shortcode",
|
||||||
|
"method": "Mètode",
|
||||||
|
"not_found": "No s'ha trobat el shortcode",
|
||||||
|
"short_code": "Short code",
|
||||||
|
"url": "URL"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
{
|
{
|
||||||
"action": {
|
"action": {
|
||||||
|
"add": "Add",
|
||||||
"autoscroll": "自动滚动",
|
"autoscroll": "自动滚动",
|
||||||
"cancel": "取消",
|
"cancel": "取消",
|
||||||
"choose_file": "选择文件",
|
"choose_file": "选择文件",
|
||||||
"clear": "清除",
|
"clear": "清除",
|
||||||
"clear_all": "全部清除",
|
"clear_all": "全部清除",
|
||||||
"clear_history": "Clear all History",
|
"clear_history": "清除全部历史记录",
|
||||||
"close": "关闭",
|
"close": "关闭",
|
||||||
"connect": "连接",
|
"connect": "连接",
|
||||||
"connecting": "连接中",
|
"connecting": "连接中",
|
||||||
"copy": "复制",
|
"copy": "复制",
|
||||||
|
"create": "Create",
|
||||||
"delete": "删除",
|
"delete": "删除",
|
||||||
"disconnect": "断开连接",
|
"disconnect": "断开连接",
|
||||||
"dismiss": "忽略",
|
"dismiss": "忽略",
|
||||||
@@ -31,14 +33,16 @@
|
|||||||
"open_workspace": "打开工作区",
|
"open_workspace": "打开工作区",
|
||||||
"paste": "粘贴",
|
"paste": "粘贴",
|
||||||
"prettify": "美化",
|
"prettify": "美化",
|
||||||
|
"properties": "Properties",
|
||||||
"remove": "移除",
|
"remove": "移除",
|
||||||
"rename": "Rename",
|
"rename": "重命名",
|
||||||
"restore": "恢复",
|
"restore": "恢复",
|
||||||
"save": "保存",
|
"save": "保存",
|
||||||
"scroll_to_bottom": "滚动至底部",
|
"scroll_to_bottom": "滚动至底部",
|
||||||
"scroll_to_top": "滚动至顶部",
|
"scroll_to_top": "滚动至顶部",
|
||||||
"search": "搜索",
|
"search": "搜索",
|
||||||
"send": "发送",
|
"send": "发送",
|
||||||
|
"share": "Share",
|
||||||
"start": "开始",
|
"start": "开始",
|
||||||
"starting": "正在开始",
|
"starting": "正在开始",
|
||||||
"stop": "停止",
|
"stop": "停止",
|
||||||
@@ -57,7 +61,9 @@
|
|||||||
"app": {
|
"app": {
|
||||||
"chat_with_us": "与我们交谈",
|
"chat_with_us": "与我们交谈",
|
||||||
"contact_us": "联系我们",
|
"contact_us": "联系我们",
|
||||||
|
"cookies": "Cookies",
|
||||||
"copy": "复制",
|
"copy": "复制",
|
||||||
|
"copy_interface_type": "Copy interface type",
|
||||||
"copy_user_id": "复制认证 Token",
|
"copy_user_id": "复制认证 Token",
|
||||||
"developer_option": "开发者选项",
|
"developer_option": "开发者选项",
|
||||||
"developer_option_description": "开发者工具,有助于开发和维护 Hoppscotch。",
|
"developer_option_description": "开发者工具,有助于开发和维护 Hoppscotch。",
|
||||||
@@ -73,14 +79,15 @@
|
|||||||
"keyboard_shortcuts": "键盘快捷键",
|
"keyboard_shortcuts": "键盘快捷键",
|
||||||
"name": "Hoppscotch",
|
"name": "Hoppscotch",
|
||||||
"new_version_found": "已发现新版本。刷新页面以更新。",
|
"new_version_found": "已发现新版本。刷新页面以更新。",
|
||||||
|
"open_in_hoppscotch": "Open in Hoppscotch",
|
||||||
"options": "选项",
|
"options": "选项",
|
||||||
"proxy_privacy_policy": "代理隐私政策",
|
"proxy_privacy_policy": "代理隐私政策",
|
||||||
"reload": "重新加载",
|
"reload": "重新加载",
|
||||||
"search": "搜索",
|
"search": "搜索",
|
||||||
"share": "分享",
|
"share": "分享",
|
||||||
"shortcuts": "快捷方式",
|
"shortcuts": "快捷方式",
|
||||||
"social_description": "Follow us on social media to stay updated with the latest news, updates and releases.",
|
"social_description": "在社交媒体上关注我们,了解最新新闻、更新和发布。",
|
||||||
"social_links": "Social links",
|
"social_links": "社交媒体链接",
|
||||||
"spotlight": "聚光灯",
|
"spotlight": "聚光灯",
|
||||||
"status": "状态",
|
"status": "状态",
|
||||||
"status_description": "检查网站状态",
|
"status_description": "检查网站状态",
|
||||||
@@ -112,10 +119,27 @@
|
|||||||
},
|
},
|
||||||
"authorization": {
|
"authorization": {
|
||||||
"generate_token": "生成令牌",
|
"generate_token": "生成令牌",
|
||||||
|
"graphql_headers": "Authorization Headers are sent as part of the payload to connection_init",
|
||||||
"include_in_url": "包含在 URL 内",
|
"include_in_url": "包含在 URL 内",
|
||||||
|
"inherited_from": "Inherited {auth} from parent collection {collection} ",
|
||||||
"learn": "了解更多",
|
"learn": "了解更多",
|
||||||
|
"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_key_by": "传递方式",
|
||||||
"password": "密码",
|
"password": "密码",
|
||||||
|
"save_to_inherit": "Please save this request in any collection to inherit the authorization",
|
||||||
"token": "令牌",
|
"token": "令牌",
|
||||||
"type": "授权类型",
|
"type": "授权类型",
|
||||||
"username": "用户名"
|
"username": "用户名"
|
||||||
@@ -124,6 +148,7 @@
|
|||||||
"created": "集合已创建",
|
"created": "集合已创建",
|
||||||
"different_parent": "不能用不同的父类来重新排序集合",
|
"different_parent": "不能用不同的父类来重新排序集合",
|
||||||
"edit": "编辑集合",
|
"edit": "编辑集合",
|
||||||
|
"import_or_create": "Import or create a collection",
|
||||||
"invalid_name": "请提供有效的集合名称",
|
"invalid_name": "请提供有效的集合名称",
|
||||||
"invalid_root_move": "该集合已经在根级了",
|
"invalid_root_move": "该集合已经在根级了",
|
||||||
"moved": "移动完成",
|
"moved": "移动完成",
|
||||||
@@ -132,18 +157,20 @@
|
|||||||
"name_length_insufficient": "集合名字至少需要 3 个字符",
|
"name_length_insufficient": "集合名字至少需要 3 个字符",
|
||||||
"new": "新建集合",
|
"new": "新建集合",
|
||||||
"order_changed": "集合顺序已更新",
|
"order_changed": "集合顺序已更新",
|
||||||
|
"properties": "Collection Properties",
|
||||||
|
"properties_updated": "Collection Properties Updated",
|
||||||
"renamed": "集合已更名",
|
"renamed": "集合已更名",
|
||||||
"request_in_use": "请求正在使用中",
|
"request_in_use": "请求正在使用中",
|
||||||
"save_as": "另存为",
|
"save_as": "另存为",
|
||||||
"save_to_collection": "Save to Collection",
|
"save_to_collection": "保存至集合",
|
||||||
"select": "选择一个集合",
|
"select": "选择一个集合",
|
||||||
"select_location": "选择位置",
|
"select_location": "选择位置",
|
||||||
"select_team": "选择一个团队",
|
"select_team": "选择一个团队",
|
||||||
"team_collections": "团队集合"
|
"team_collections": "团队集合"
|
||||||
},
|
},
|
||||||
"confirm": {
|
"confirm": {
|
||||||
"close_unsaved_tab": "Are you sure you want to close this tab?",
|
"close_unsaved_tab": "你确定要关闭此标签页吗?",
|
||||||
"close_unsaved_tabs": "Are you sure you want to close all tabs? {count} unsaved tabs will be lost.",
|
"close_unsaved_tabs": "你确定要关闭所有标签页吗? {count} 个未保存的标签页将被丢失。",
|
||||||
"exit_team": "你确定要离开此团队吗?",
|
"exit_team": "你确定要离开此团队吗?",
|
||||||
"logout": "你确定要登出吗?",
|
"logout": "你确定要登出吗?",
|
||||||
"remove_collection": "你确定要永久删除该集合吗?",
|
"remove_collection": "你确定要永久删除该集合吗?",
|
||||||
@@ -151,6 +178,7 @@
|
|||||||
"remove_folder": "你确定要永久删除该文件夹吗?",
|
"remove_folder": "你确定要永久删除该文件夹吗?",
|
||||||
"remove_history": "你确定要永久删除全部历史记录吗?",
|
"remove_history": "你确定要永久删除全部历史记录吗?",
|
||||||
"remove_request": "你确定要永久删除该请求吗?",
|
"remove_request": "你确定要永久删除该请求吗?",
|
||||||
|
"remove_shared_request": "Are you sure you want to permanently delete this shared request?",
|
||||||
"remove_team": "你确定要删除该团队吗?",
|
"remove_team": "你确定要删除该团队吗?",
|
||||||
"remove_telemetry": "你确定要退出遥测服务吗?",
|
"remove_telemetry": "你确定要退出遥测服务吗?",
|
||||||
"request_change": "你确定你要放弃当前的请求,未保存的修改将被丢失。",
|
"request_change": "你确定你要放弃当前的请求,未保存的修改将被丢失。",
|
||||||
@@ -158,9 +186,27 @@
|
|||||||
"sync": "您确定要同步该工作区吗?"
|
"sync": "您确定要同步该工作区吗?"
|
||||||
},
|
},
|
||||||
"context_menu": {
|
"context_menu": {
|
||||||
"add_parameters": "Add to parameters",
|
"add_parameters": "添加至参数",
|
||||||
"open_request_in_new_tab": "Open request in new tab",
|
"open_request_in_new_tab": "在新标签页中打开请求",
|
||||||
"set_environment_variable": "Set as variable"
|
"set_environment_variable": "设置为变量"
|
||||||
|
},
|
||||||
|
"cookies": {
|
||||||
|
"modal": {
|
||||||
|
"cookie_expires": "Expires",
|
||||||
|
"cookie_name": "Name",
|
||||||
|
"cookie_path": "Path",
|
||||||
|
"cookie_string": "Cookie string",
|
||||||
|
"cookie_value": "Value",
|
||||||
|
"empty_domain": "Domain is empty",
|
||||||
|
"empty_domains": "Domain list is empty",
|
||||||
|
"enter_cookie_string": "Enter cookie string",
|
||||||
|
"interceptor_no_support": "Your currently selected interceptor does not support cookies. Select a different Interceptor and try again.",
|
||||||
|
"managed_tab": "Managed",
|
||||||
|
"new_domain_name": "New domain name",
|
||||||
|
"no_cookies_in_domain": "No cookies set for this domain",
|
||||||
|
"raw_tab": "Raw",
|
||||||
|
"set": "Set a cookie"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"count": {
|
"count": {
|
||||||
"header": "请求头 {count}",
|
"header": "请求头 {count}",
|
||||||
@@ -192,11 +238,13 @@
|
|||||||
"profile": "登录以查看你的个人资料",
|
"profile": "登录以查看你的个人资料",
|
||||||
"protocols": "协议为空",
|
"protocols": "协议为空",
|
||||||
"schema": "连接至 GraphQL 端点",
|
"schema": "连接至 GraphQL 端点",
|
||||||
"shortcodes": "Shortcodes 为空",
|
"shared_requests": "Shared requests are empty",
|
||||||
|
"shared_requests_logout": "Login to view your shared requests or create a new one",
|
||||||
"subscription": "订阅为空",
|
"subscription": "订阅为空",
|
||||||
"team_name": "团队名称为空",
|
"team_name": "团队名称为空",
|
||||||
"teams": "团队为空",
|
"teams": "团队为空",
|
||||||
"tests": "没有针对该请求的测试"
|
"tests": "没有针对该请求的测试",
|
||||||
|
"shortcodes": "短链接为空"
|
||||||
},
|
},
|
||||||
"environment": {
|
"environment": {
|
||||||
"add_to_global": "添加到全局环境",
|
"add_to_global": "添加到全局环境",
|
||||||
@@ -204,36 +252,39 @@
|
|||||||
"create_new": "创建新环境",
|
"create_new": "创建新环境",
|
||||||
"created": "环境已创建",
|
"created": "环境已创建",
|
||||||
"deleted": "环境已删除",
|
"deleted": "环境已删除",
|
||||||
"duplicated": "Environment duplicated",
|
"duplicated": "环境已复制",
|
||||||
"edit": "编辑环境",
|
"edit": "编辑环境",
|
||||||
"empty_variables": "No variables",
|
"empty_variables": "没有变量",
|
||||||
"global": "Global",
|
"global": "全局",
|
||||||
"global_variables": "Global variables",
|
"global_variables": "全局变量",
|
||||||
|
"import_or_create": "Import or create a environment",
|
||||||
"invalid_name": "请提供有效的环境名称",
|
"invalid_name": "请提供有效的环境名称",
|
||||||
"list": "Environment variables",
|
"list": "环境变量",
|
||||||
"my_environments": "我的环境",
|
"my_environments": "我的环境",
|
||||||
"name": "Name",
|
"name": "名称",
|
||||||
"nested_overflow": "环境嵌套深度超过限制(10层)",
|
"nested_overflow": "环境嵌套深度超过限制(10层)",
|
||||||
"new": "新建环境",
|
"new": "新建环境",
|
||||||
"no_active_environment": "No active environment",
|
"no_active_environment": "没有激活的环境",
|
||||||
"no_environment": "无环境",
|
"no_environment": "无环境",
|
||||||
"no_environment_description": "没有选择环境。选择如何处理以下变量。",
|
"no_environment_description": "没有选择环境。选择如何处理以下变量。",
|
||||||
"quick_peek": "Environment Quick Peek",
|
"quick_peek": "快速浏览环境",
|
||||||
"replace_with_variable": "Replace with variable",
|
"replace_with_variable": "替换为变量",
|
||||||
"scope": "Scope",
|
"scope": "范围",
|
||||||
"select": "选择环境",
|
"select": "选择环境",
|
||||||
"set": "Set environment",
|
"set": "设置环境",
|
||||||
"set_as_environment": "Set as environment",
|
"set_as_environment": "设置为环境",
|
||||||
"team_environments": "团队环境",
|
"team_environments": "团队环境",
|
||||||
"title": "环境",
|
"title": "环境",
|
||||||
"updated": "环境已更新",
|
"updated": "环境已更新",
|
||||||
"value": "Value",
|
"value": "值",
|
||||||
"variable": "Variable",
|
"variable": "变量",
|
||||||
"variable_list": "变量列表"
|
"variable_list": "变量列表"
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
|
"authproviders_load_error": "Unable to load auth providers",
|
||||||
"browser_support_sse": "该浏览器似乎不支持 SSE。",
|
"browser_support_sse": "该浏览器似乎不支持 SSE。",
|
||||||
"check_console_details": "检查控制台日志以获悉详情",
|
"check_console_details": "检查控制台日志以获悉详情",
|
||||||
|
"check_how_to_add_origin": "Check how you can add an origin",
|
||||||
"curl_invalid_format": "cURL 格式不正确",
|
"curl_invalid_format": "cURL 格式不正确",
|
||||||
"danger_zone": "危险区域",
|
"danger_zone": "危险区域",
|
||||||
"delete_account": "您的帐号目前为这些团队的拥有者:",
|
"delete_account": "您的帐号目前为这些团队的拥有者:",
|
||||||
@@ -245,14 +296,18 @@
|
|||||||
"incorrect_email": "电子邮箱错误",
|
"incorrect_email": "电子邮箱错误",
|
||||||
"invalid_link": "无效链接",
|
"invalid_link": "无效链接",
|
||||||
"invalid_link_description": "你点击的链接无效或已过期。",
|
"invalid_link_description": "你点击的链接无效或已过期。",
|
||||||
|
"invalid_embed_link": "The embed does not exist or is invalid.",
|
||||||
"json_parsing_failed": "不合法的 JSON",
|
"json_parsing_failed": "不合法的 JSON",
|
||||||
"json_prettify_invalid_body": "无法美化无效的请求头,处理 JSON 语法错误并重试",
|
"json_prettify_invalid_body": "无法美化无效的请求头,处理 JSON 语法错误并重试",
|
||||||
"network_error": "好像发生了网络错误,请重试。",
|
"network_error": "好像发生了网络错误,请重试。",
|
||||||
"network_fail": "无法发送请求",
|
"network_fail": "无法发送请求",
|
||||||
|
"no_collections_to_export": "No collections to export. Please create a collection to get started.",
|
||||||
"no_duration": "无持续时间",
|
"no_duration": "无持续时间",
|
||||||
|
"no_environments_to_export": "No environments to export. Please create an environment to get started.",
|
||||||
"no_results_found": "找不到结果",
|
"no_results_found": "找不到结果",
|
||||||
"page_not_found": "找不到此頁面",
|
"page_not_found": "找不到此頁面",
|
||||||
"proxy_error": "Proxy error",
|
"please_install_extension": "Please install the extension and add origin to the extension.",
|
||||||
|
"proxy_error": "代理错误",
|
||||||
"script_fail": "无法执行预请求脚本",
|
"script_fail": "无法执行预请求脚本",
|
||||||
"something_went_wrong": "发生了一些错误",
|
"something_went_wrong": "发生了一些错误",
|
||||||
"test_script_fail": "无法执行请求脚本"
|
"test_script_fail": "无法执行请求脚本"
|
||||||
@@ -260,9 +315,13 @@
|
|||||||
"export": {
|
"export": {
|
||||||
"as_json": "导出为 JSON",
|
"as_json": "导出为 JSON",
|
||||||
"create_secret_gist": "创建私密 Gist",
|
"create_secret_gist": "创建私密 Gist",
|
||||||
"gist_created": "已创建 Gist",
|
"create_secret_gist_tooltip_text": "Export as secret Gist",
|
||||||
|
"failed": "Something went wrong while exporting",
|
||||||
|
"secret_gist_success": "Successfully exported as secret Gist",
|
||||||
"require_github": "使用 GitHub 登录以创建私密 Gist",
|
"require_github": "使用 GitHub 登录以创建私密 Gist",
|
||||||
"title": "导出"
|
"title": "导出",
|
||||||
|
"success": "Successfully exported",
|
||||||
|
"gist_created": "已创建 Gist"
|
||||||
},
|
},
|
||||||
"filter": {
|
"filter": {
|
||||||
"all": "全部",
|
"all": "全部",
|
||||||
@@ -278,13 +337,16 @@
|
|||||||
"renamed": "文件夹已更名"
|
"renamed": "文件夹已更名"
|
||||||
},
|
},
|
||||||
"graphql": {
|
"graphql": {
|
||||||
"connection_switch_confirm": "Do you want to connect with the latest GraphQL endpoint?",
|
"connection_switch_confirm": "您想连接最新的 GraphQL 端点吗?",
|
||||||
"connection_switch_new_url": "Switching to a tab will disconnected you from the active GraphQL connection. New connection URL is",
|
"connection_switch_new_url": "切换到标签页将使您与活动的 GraphQL 连接断开。新的连接 URL 是",
|
||||||
"connection_switch_url": "You're connected to a GraphQL endpoint the connection URL is",
|
"connection_switch_url": "您已连接到 GraphQL 端点,连接 URL 为",
|
||||||
"mutations": "变更",
|
"mutations": "变更",
|
||||||
"schema": "模式",
|
"schema": "模式",
|
||||||
"subscriptions": "订阅",
|
"subscriptions": "订阅",
|
||||||
"switch_connection": "Switch connection"
|
"switch_connection": "切换连接"
|
||||||
|
},
|
||||||
|
"graphql_collections": {
|
||||||
|
"title": "GraphQL Collections"
|
||||||
},
|
},
|
||||||
"group": {
|
"group": {
|
||||||
"time": "时间",
|
"time": "时间",
|
||||||
@@ -297,6 +359,8 @@
|
|||||||
},
|
},
|
||||||
"helpers": {
|
"helpers": {
|
||||||
"authorization": "授权头将会在你发送请求时自动生成。",
|
"authorization": "授权头将会在你发送请求时自动生成。",
|
||||||
|
"collection_properties_authorization": " This authorization will be set for every request in this collection.",
|
||||||
|
"collection_properties_header": "This header will be set for every request in this collection.",
|
||||||
"generate_documentation_first": "请先生成文档",
|
"generate_documentation_first": "请先生成文档",
|
||||||
"network_fail": "无法到达 API 端点。请检查网络连接并重试。",
|
"network_fail": "无法到达 API 端点。请检查网络连接并重试。",
|
||||||
"offline": "你似乎处于离线状态,该工作区中的数据可能不是最新。",
|
"offline": "你似乎处于离线状态,该工作区中的数据可能不是最新。",
|
||||||
@@ -316,7 +380,10 @@
|
|||||||
"import": {
|
"import": {
|
||||||
"collections": "导入集合",
|
"collections": "导入集合",
|
||||||
"curl": "导入 cURL",
|
"curl": "导入 cURL",
|
||||||
|
"environments_from_gist": "Import From Gist",
|
||||||
|
"environments_from_gist_description": "Import Hoppscotch Environments From Gist",
|
||||||
"failed": "导入失败",
|
"failed": "导入失败",
|
||||||
|
"from_file": "Import from File",
|
||||||
"from_gist": "从 Gist 导入",
|
"from_gist": "从 Gist 导入",
|
||||||
"from_gist_description": "从 Gist URL 导入",
|
"from_gist_description": "从 Gist URL 导入",
|
||||||
"from_insomnia": "从 Insomnia 导入",
|
"from_insomnia": "从 Insomnia 导入",
|
||||||
@@ -331,35 +398,41 @@
|
|||||||
"from_postman_description": "从 Postman 集合中导入",
|
"from_postman_description": "从 Postman 集合中导入",
|
||||||
"from_url": "从 URL 导入",
|
"from_url": "从 URL 导入",
|
||||||
"gist_url": "输入 Gist URL",
|
"gist_url": "输入 Gist URL",
|
||||||
|
"gql_collections_from_gist_description": "Import GraphQL Collections From Gist",
|
||||||
|
"hoppscotch_environment": "Hoppscotch Environment",
|
||||||
|
"hoppscotch_environment_description": "Import Hoppscotch Environment JSON file",
|
||||||
"import_from_url_invalid_fetch": "无法从网址取得资料",
|
"import_from_url_invalid_fetch": "无法从网址取得资料",
|
||||||
"import_from_url_invalid_file_format": "导入组合时发生错误",
|
"import_from_url_invalid_file_format": "导入组合时发生错误",
|
||||||
"import_from_url_invalid_type": "不支持此类型。可接受的值为 'hoppscotch'、'openapi'、'postman'、'insomnia'",
|
"import_from_url_invalid_type": "不支持此类型。可接受的值为 'hoppscotch'、'openapi'、'postman'、'insomnia'",
|
||||||
"import_from_url_success": "已导入组合",
|
"import_from_url_success": "已导入组合",
|
||||||
|
"insomnia_environment_description": "Import Insomnia Environment from a JSON/YAML file",
|
||||||
"json_description": "从 Hoppscotch 的集合文件导入(JSON)",
|
"json_description": "从 Hoppscotch 的集合文件导入(JSON)",
|
||||||
|
"postman_environment": "Postman Environment",
|
||||||
|
"postman_environment_description": "Import Postman Environment from a JSON file",
|
||||||
"title": "导入"
|
"title": "导入"
|
||||||
},
|
},
|
||||||
"inspections": {
|
"inspections": {
|
||||||
"description": "Inspect possible errors",
|
"description": "查可能的错误",
|
||||||
"environment": {
|
"environment": {
|
||||||
"add_environment": "Add to Environment",
|
"add_environment": "添加到环境",
|
||||||
"not_found": "Environment variable “{environment}” not found."
|
"not_found": "环境变量“{environment}”未找到。"
|
||||||
},
|
},
|
||||||
"header": {
|
"header": {
|
||||||
"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."
|
"cookie": "浏览器不允许 Hoppscotch 设置 Cookie 标头。当前我们正在开发 Hoppscotch 桌面应用程序(即将推出),与此同时请改用授权标头。"
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"401_error": "Please check your authentication credentials.",
|
"401_error": "请检查您的身份验证凭据。",
|
||||||
"404_error": "Please check your request URL and method type.",
|
"404_error": "请检查您的请求 URL 和方法类型。",
|
||||||
"cors_error": "Please check your Cross-Origin Resource Sharing configuration.",
|
"cors_error": "请检查您的跨源资源共享配置。",
|
||||||
"default_error": "Please check your request.",
|
"default_error": "请检查您的请求。",
|
||||||
"network_error": "Please check your network connection."
|
"network_error": "请检查您的网络连接。"
|
||||||
},
|
},
|
||||||
"title": "Inspector",
|
"title": "Inspector",
|
||||||
"url": {
|
"url": {
|
||||||
"extension_not_installed": "Extension not installed.",
|
"extension_not_installed": "未安装扩展。",
|
||||||
"extension_unknown_origin": "Make sure you've added the API endpoint's origin to the Hoppscotch Browser Extension list.",
|
"extension_unknown_origin": "确保您已将 API 端点的源添加到 Hoppscotch 浏览器扩展列表中。",
|
||||||
"extention_enable_action": "Enable Browser Extension",
|
"extention_enable_action": "启用浏览器扩展",
|
||||||
"extention_not_enabled": "Extension not enabled."
|
"extention_not_enabled": "扩展未启用。"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"layout": {
|
"layout": {
|
||||||
@@ -373,8 +446,10 @@
|
|||||||
"close_unsaved_tab": "有未保存的变更",
|
"close_unsaved_tab": "有未保存的变更",
|
||||||
"collections": "集合",
|
"collections": "集合",
|
||||||
"confirm": "确认",
|
"confirm": "确认",
|
||||||
|
"customize_request": "Customize Request",
|
||||||
"edit_request": "编辑请求",
|
"edit_request": "编辑请求",
|
||||||
"import_export": "导入/导出"
|
"import_export": "导入/导出",
|
||||||
|
"share_request": "Share Request"
|
||||||
},
|
},
|
||||||
"mqtt": {
|
"mqtt": {
|
||||||
"already_subscribed": "您已经订阅了此主题。",
|
"already_subscribed": "您已经订阅了此主题。",
|
||||||
@@ -389,10 +464,10 @@
|
|||||||
"invalid_topic": "请提供该订阅的主题",
|
"invalid_topic": "请提供该订阅的主题",
|
||||||
"keep_alive": "Keep Alive",
|
"keep_alive": "Keep Alive",
|
||||||
"log": "日志",
|
"log": "日志",
|
||||||
"lw_message": "Last-Will Message",
|
"lw_message": "遗嘱消息",
|
||||||
"lw_qos": "Last-Will QoS",
|
"lw_qos": "遗嘱消息QoS",
|
||||||
"lw_retain": "Last-Will Retain",
|
"lw_retain": "遗嘱消息保留",
|
||||||
"lw_topic": "Last-Will Topic",
|
"lw_topic": "遗嘱消息主题",
|
||||||
"message": "消息",
|
"message": "消息",
|
||||||
"new": "新订阅",
|
"new": "新订阅",
|
||||||
"not_connected": "请先启动MQTT连接。",
|
"not_connected": "请先启动MQTT连接。",
|
||||||
@@ -449,13 +524,14 @@
|
|||||||
"structured": "结构",
|
"structured": "结构",
|
||||||
"text": "文字"
|
"text": "文字"
|
||||||
},
|
},
|
||||||
"copy_link": "复制链接",
|
|
||||||
"different_collection": "不能对来自不同集合的请求进行重新排序",
|
"different_collection": "不能对来自不同集合的请求进行重新排序",
|
||||||
"duplicated": "重复的请求",
|
"duplicated": "重复的请求",
|
||||||
"duration": "持续时间",
|
"duration": "持续时间",
|
||||||
"enter_curl": "输入 cURL",
|
"enter_curl": "输入 cURL",
|
||||||
"generate_code": "生成代码",
|
"generate_code": "生成代码",
|
||||||
"generated_code": "已生成代码",
|
"generated_code": "已生成代码",
|
||||||
|
"go_to_authorization_tab": "Go to Authorization tab",
|
||||||
|
"go_to_body_tab": "Go to Body tab",
|
||||||
"header_list": "请求头列表",
|
"header_list": "请求头列表",
|
||||||
"invalid_name": "请提供请求名称",
|
"invalid_name": "请提供请求名称",
|
||||||
"method": "方法",
|
"method": "方法",
|
||||||
@@ -472,7 +548,7 @@
|
|||||||
"payload": "负载",
|
"payload": "负载",
|
||||||
"query": "查询",
|
"query": "查询",
|
||||||
"raw_body": "原始请求体",
|
"raw_body": "原始请求体",
|
||||||
"rename": "Rename Request",
|
"rename": "重命名请求",
|
||||||
"renamed": "请求重命名",
|
"renamed": "请求重命名",
|
||||||
"run": "运行",
|
"run": "运行",
|
||||||
"save": "保存",
|
"save": "保存",
|
||||||
@@ -480,12 +556,14 @@
|
|||||||
"saved": "请求已保存",
|
"saved": "请求已保存",
|
||||||
"share": "分享",
|
"share": "分享",
|
||||||
"share_description": "分享 Hoppscotch 给你的朋友",
|
"share_description": "分享 Hoppscotch 给你的朋友",
|
||||||
"stop": "Stop",
|
"share_request": "Share Request",
|
||||||
|
"stop": "停止",
|
||||||
"title": "请求",
|
"title": "请求",
|
||||||
"type": "请求类型",
|
"type": "请求类型",
|
||||||
"url": "URL",
|
"url": "URL",
|
||||||
"variables": "变量",
|
"variables": "变量",
|
||||||
"view_my_links": "查看我的链接"
|
"view_my_links": "查看我的链接",
|
||||||
|
"copy_link": "复制链接"
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"audio": "Audio",
|
"audio": "Audio",
|
||||||
@@ -513,6 +591,7 @@
|
|||||||
"account_description": "自定义您的帐户设置。",
|
"account_description": "自定义您的帐户设置。",
|
||||||
"account_email_description": "您的主要电子邮箱地址。",
|
"account_email_description": "您的主要电子邮箱地址。",
|
||||||
"account_name_description": "这是您的显示名称。",
|
"account_name_description": "这是您的显示名称。",
|
||||||
|
"additional": "Additional Settings",
|
||||||
"background": "背景",
|
"background": "背景",
|
||||||
"black_mode": "黑色",
|
"black_mode": "黑色",
|
||||||
"choose_language": "选择语言",
|
"choose_language": "选择语言",
|
||||||
@@ -559,14 +638,31 @@
|
|||||||
"verified_email": "已验证电子邮件地址",
|
"verified_email": "已验证电子邮件地址",
|
||||||
"verify_email": "验证电子邮箱"
|
"verify_email": "验证电子邮箱"
|
||||||
},
|
},
|
||||||
"shortcodes": {
|
"shared_requests": {
|
||||||
"actions": "操作",
|
"button": "Button",
|
||||||
"created_on": "创建于",
|
"button_info": "Create a 'Run in Hoppscotch' button for your website, blog or a README.",
|
||||||
"deleted": "已刪除快捷键",
|
"copy_html": "Copy HTML",
|
||||||
"method": "方法",
|
"copy_link": "Copy Link",
|
||||||
"not_found": "找不到快捷键",
|
"copy_markdown": "Copy Markdown",
|
||||||
"short_code": "快捷键",
|
"creating_widget": "Creating widget",
|
||||||
"url": "URL"
|
"customize": "Customize",
|
||||||
|
"deleted": "Shared request deleted",
|
||||||
|
"description": "Select a widget, you can change and customize this later",
|
||||||
|
"embed": "Embed",
|
||||||
|
"embed_info": "Add a mini 'Hoppscotch API Playground' to your website, blog or documentation.",
|
||||||
|
"link": "Link",
|
||||||
|
"link_info": "Create a shareable link to share with anyone on the internet with view access.",
|
||||||
|
"modified": "Shared request modified",
|
||||||
|
"not_found": "Shared request not found",
|
||||||
|
"open_new_tab": "Open in new tab",
|
||||||
|
"preview": "Preview",
|
||||||
|
"run_in_hoppscotch": "Run in Hoppscotch",
|
||||||
|
"theme": {
|
||||||
|
"dark": "Dark",
|
||||||
|
"light": "Light",
|
||||||
|
"system": "System",
|
||||||
|
"title": "Theme"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"shortcut": {
|
"shortcut": {
|
||||||
"general": {
|
"general": {
|
||||||
@@ -592,27 +688,28 @@
|
|||||||
"title": "导航"
|
"title": "导航"
|
||||||
},
|
},
|
||||||
"others": {
|
"others": {
|
||||||
"prettify": "Prettify Editor's Content",
|
"prettify": "美化内容",
|
||||||
"title": "Others"
|
"title": "其他"
|
||||||
},
|
},
|
||||||
"request": {
|
"request": {
|
||||||
"copy_request_link": "复制请求链接",
|
|
||||||
"delete_method": "选择 DELETE 方法",
|
"delete_method": "选择 DELETE 方法",
|
||||||
"get_method": "选择 GET 方法",
|
"get_method": "选择 GET 方法",
|
||||||
"head_method": "选择 HEAD 方法",
|
"head_method": "选择 HEAD 方法",
|
||||||
"import_curl": "Import cURL",
|
"import_curl": "导入cURL",
|
||||||
"method": "方法",
|
"method": "方法",
|
||||||
"next_method": "选择下一个方法",
|
"next_method": "选择下一个方法",
|
||||||
"post_method": "选择 POST 方法",
|
"post_method": "选择 POST 方法",
|
||||||
"previous_method": "选择上一个方法",
|
"previous_method": "选择上一个方法",
|
||||||
"put_method": "选择 PUT 方法",
|
"put_method": "选择 PUT 方法",
|
||||||
"rename": "Rename Request",
|
"rename": "重命名请求",
|
||||||
"reset_request": "重置请求",
|
"reset_request": "重置请求",
|
||||||
"save_request": "Save Request",
|
"save_request": "保存请求",
|
||||||
"save_to_collections": "保存到集合",
|
"save_to_collections": "保存到集合",
|
||||||
"send_request": "发送请求",
|
"send_request": "发送请求",
|
||||||
"show_code": "Generate code snippet",
|
"share_request": "Share Request",
|
||||||
"title": "请求"
|
"show_code": "生成代码片段",
|
||||||
|
"title": "请求",
|
||||||
|
"copy_request_link": "复制请求链接"
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"copy": "复制响应至剪贴板",
|
"copy": "复制响应至剪贴板",
|
||||||
@@ -642,82 +739,82 @@
|
|||||||
"url": "URL"
|
"url": "URL"
|
||||||
},
|
},
|
||||||
"spotlight": {
|
"spotlight": {
|
||||||
"change_language": "Change Language",
|
"change_language": "更改语言",
|
||||||
"environments": {
|
"environments": {
|
||||||
"delete": "Delete current environment",
|
"delete": "删除当前环境",
|
||||||
"duplicate": "Duplicate current environment",
|
"duplicate": "复制当前环境",
|
||||||
"duplicate_global": "Duplicate global environment",
|
"duplicate_global": "复制全局环境",
|
||||||
"edit": "Edit current environment",
|
"edit": "编辑当前环境",
|
||||||
"edit_global": "Edit global environment",
|
"edit_global": "编辑全局环境",
|
||||||
"new": "Create new environment",
|
"new": "创建新环境",
|
||||||
"new_variable": "Create a new environment variable",
|
"new_variable": "创建新的环境变量",
|
||||||
"title": "Environments"
|
"title": "环境"
|
||||||
},
|
},
|
||||||
"general": {
|
"general": {
|
||||||
"chat": "Chat with support",
|
"chat": "与支持人员聊天",
|
||||||
"help_menu": "Help and support",
|
"help_menu": "帮助和支持",
|
||||||
"open_docs": "Read Documentation",
|
"open_docs": "阅读文档",
|
||||||
"open_github": "Open GitHub repository",
|
"open_github": "打开 GitHub 存储库",
|
||||||
"open_keybindings": "Keyboard shortcuts",
|
"open_keybindings": "键盘快捷键",
|
||||||
"social": "Social",
|
"social": "社交媒体",
|
||||||
"title": "General"
|
"title": "一般"
|
||||||
},
|
},
|
||||||
"graphql": {
|
"graphql": {
|
||||||
"connect": "Connect to server",
|
"connect": "连接到服务器",
|
||||||
"disconnect": "Disconnect from server"
|
"disconnect": "与服务器断开连接"
|
||||||
},
|
},
|
||||||
"miscellaneous": {
|
"miscellaneous": {
|
||||||
"invite": "Invite your friends to Hoppscotch",
|
"invite": "邀请你的朋友来 Hoppscotch",
|
||||||
"title": "Miscellaneous"
|
"title": "杂项"
|
||||||
},
|
},
|
||||||
"request": {
|
"request": {
|
||||||
"save_as_new": "Save as new request",
|
"save_as_new": "另存为新请求",
|
||||||
"select_method": "Select method",
|
"select_method": "选择方法",
|
||||||
"switch_to": "Switch to",
|
"switch_to": "切换到",
|
||||||
"tab_authorization": "Authorization tab",
|
"tab_authorization": "授权标签页",
|
||||||
"tab_body": "Body tab",
|
"tab_body": "请求体标签页",
|
||||||
"tab_headers": "Headers tab",
|
"tab_headers": "请求头标签页",
|
||||||
"tab_parameters": "Parameters tab",
|
"tab_parameters": "参数标签页",
|
||||||
"tab_pre_request_script": "Pre-request script tab",
|
"tab_pre_request_script": "预请求脚本标签页",
|
||||||
"tab_query": "Query tab",
|
"tab_query": "查询标签页",
|
||||||
"tab_tests": "Tests tab",
|
"tab_tests": "测试标签页b",
|
||||||
"tab_variables": "Variables tab"
|
"tab_variables": "变量标签页"
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"copy": "Copy response",
|
"copy": "复制响应",
|
||||||
"download": "Download response as file",
|
"download": "将响应下载为文件",
|
||||||
"title": "Response"
|
"title": "响应"
|
||||||
},
|
},
|
||||||
"section": {
|
"section": {
|
||||||
"interceptor": "Interceptor",
|
"interceptor": "拦截器",
|
||||||
"interface": "Interface",
|
"interface": "界面",
|
||||||
"theme": "Theme",
|
"theme": "主题",
|
||||||
"user": "User"
|
"user": "用户"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"change_interceptor": "Change Interceptor",
|
"change_interceptor": "更改拦截器",
|
||||||
"change_language": "Change Language",
|
"change_language": "更改语言",
|
||||||
"theme": {
|
"theme": {
|
||||||
"black": "Black",
|
"black": "黑色",
|
||||||
"dark": "Dark",
|
"dark": "暗色",
|
||||||
"light": "Light",
|
"light": "亮色",
|
||||||
"system": "System preference"
|
"system": "系统"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tab": {
|
"tab": {
|
||||||
"close_current": "Close current tab",
|
"close_current": "关闭当前标签页",
|
||||||
"close_others": "Close all other tabs",
|
"close_others": "关闭所有其他标签页",
|
||||||
"duplicate": "Duplicate current tab",
|
"duplicate": "复制当前标签页",
|
||||||
"new_tab": "Open a new tab",
|
"new_tab": "打开新的标签页",
|
||||||
"title": "Tabs"
|
"title": "标签页"
|
||||||
},
|
},
|
||||||
"workspace": {
|
"workspace": {
|
||||||
"delete": "Delete current team",
|
"delete": "删除当前团队",
|
||||||
"edit": "Edit current team",
|
"edit": "编辑当前团队",
|
||||||
"invite": "Invite people to team",
|
"invite": "邀请人员加入团队",
|
||||||
"new": "Create new team",
|
"new": "创建新团队",
|
||||||
"switch_to_personal": "Switch to your personal workspace",
|
"switch_to_personal": "切换到您的个人工作空间",
|
||||||
"title": "Teams"
|
"title": "团队"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sse": {
|
"sse": {
|
||||||
@@ -735,6 +832,7 @@
|
|||||||
"connection_error": "连接错误",
|
"connection_error": "连接错误",
|
||||||
"connection_failed": "连接失败",
|
"connection_failed": "连接失败",
|
||||||
"connection_lost": "连接丢失",
|
"connection_lost": "连接丢失",
|
||||||
|
"copied_interface_to_clipboard": "Copied {language} interface type to clipboard",
|
||||||
"copied_to_clipboard": "已复制到剪贴板",
|
"copied_to_clipboard": "已复制到剪贴板",
|
||||||
"deleted": "已删除",
|
"deleted": "已删除",
|
||||||
"deprecated": "已弃用",
|
"deprecated": "已弃用",
|
||||||
@@ -742,10 +840,12 @@
|
|||||||
"disconnected": "断开连接",
|
"disconnected": "断开连接",
|
||||||
"disconnected_from": "与 {name} 断开连接",
|
"disconnected_from": "与 {name} 断开连接",
|
||||||
"docs_generated": "已生成文档",
|
"docs_generated": "已生成文档",
|
||||||
|
"download_failed": "Download failed",
|
||||||
"download_started": "开始下载",
|
"download_started": "开始下载",
|
||||||
"enabled": "启用",
|
"enabled": "启用",
|
||||||
"file_imported": "文件已导入",
|
"file_imported": "文件已导入",
|
||||||
"finished_in": "在 {duration} 毫秒内完成",
|
"finished_in": "在 {duration} 毫秒内完成",
|
||||||
|
"hide": "Hide",
|
||||||
"history_deleted": "历史记录已删除",
|
"history_deleted": "历史记录已删除",
|
||||||
"linewrap": "换行",
|
"linewrap": "换行",
|
||||||
"loading": "正在加载……",
|
"loading": "正在加载……",
|
||||||
@@ -756,6 +856,7 @@
|
|||||||
"published_error": "将信息:{topic}发布至主题:{message}时发生错误",
|
"published_error": "将信息:{topic}发布至主题:{message}时发生错误",
|
||||||
"published_message": "已将此信息:{message} 发布至主题:{topic}",
|
"published_message": "已将此信息:{message} 发布至主题:{topic}",
|
||||||
"reconnection_error": "重连失败",
|
"reconnection_error": "重连失败",
|
||||||
|
"show": "Show",
|
||||||
"subscribed_failed": "无法订阅此主题:{topic}",
|
"subscribed_failed": "无法订阅此主题:{topic}",
|
||||||
"subscribed_success": "成功订阅此主题:{topic}",
|
"subscribed_success": "成功订阅此主题:{topic}",
|
||||||
"unsubscribed_failed": "无法取消订阅此主题:{topic}",
|
"unsubscribed_failed": "无法取消订阅此主题:{topic}",
|
||||||
@@ -791,6 +892,7 @@
|
|||||||
"queries": "查询",
|
"queries": "查询",
|
||||||
"query": "查询",
|
"query": "查询",
|
||||||
"schema": "Schema",
|
"schema": "Schema",
|
||||||
|
"shared_requests": "Shared Requests",
|
||||||
"socketio": "Socket.IO",
|
"socketio": "Socket.IO",
|
||||||
"sse": "SSE",
|
"sse": "SSE",
|
||||||
"tests": "测试",
|
"tests": "测试",
|
||||||
@@ -807,6 +909,7 @@
|
|||||||
"email_do_not_match": "邮箱无法与你的帐户信息匹配。请联系你的团队者。",
|
"email_do_not_match": "邮箱无法与你的帐户信息匹配。请联系你的团队者。",
|
||||||
"exit": "退出团队",
|
"exit": "退出团队",
|
||||||
"exit_disabled": "团队所有者无法退出团队",
|
"exit_disabled": "团队所有者无法退出团队",
|
||||||
|
"failed_invites": "Failed invites",
|
||||||
"invalid_coll_id": "无效的集合 ID",
|
"invalid_coll_id": "无效的集合 ID",
|
||||||
"invalid_email_format": "电子邮箱格式无效",
|
"invalid_email_format": "电子邮箱格式无效",
|
||||||
"invalid_id": "无效的团队 ID,请联系你的团队者。",
|
"invalid_id": "无效的团队 ID,请联系你的团队者。",
|
||||||
@@ -848,6 +951,7 @@
|
|||||||
"same_target_destination": "目标相同",
|
"same_target_destination": "目标相同",
|
||||||
"saved": "团队已保存",
|
"saved": "团队已保存",
|
||||||
"select_a_team": "选择团队",
|
"select_a_team": "选择团队",
|
||||||
|
"success_invites": "Success invites",
|
||||||
"title": "团队",
|
"title": "团队",
|
||||||
"we_sent_invite_link": "我们向所有受邀者发送了邀请链接!",
|
"we_sent_invite_link": "我们向所有受邀者发送了邀请链接!",
|
||||||
"we_sent_invite_link_description": "请所有受邀者检查他们的收件箱,点击链接以加入团队。"
|
"we_sent_invite_link_description": "请所有受邀者检查他们的收件箱,点击链接以加入团队。"
|
||||||
@@ -879,5 +983,14 @@
|
|||||||
"personal": "我的工作空间",
|
"personal": "我的工作空间",
|
||||||
"team": "团队工作空间",
|
"team": "团队工作空间",
|
||||||
"title": "工作空间"
|
"title": "工作空间"
|
||||||
|
},
|
||||||
|
"shortcodes": {
|
||||||
|
"actions": "操作",
|
||||||
|
"created_on": "创建于",
|
||||||
|
"deleted": "已刪除短链接",
|
||||||
|
"method": "方法",
|
||||||
|
"not_found": "找不到短链接",
|
||||||
|
"short_code": "短链接",
|
||||||
|
"url": "URL"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"action": {
|
"action": {
|
||||||
|
"add": "Add",
|
||||||
"autoscroll": "Autoscroll",
|
"autoscroll": "Autoscroll",
|
||||||
"cancel": "zrušení",
|
"cancel": "zrušení",
|
||||||
"choose_file": "Vyberte soubor",
|
"choose_file": "Vyberte soubor",
|
||||||
@@ -10,6 +11,7 @@
|
|||||||
"connect": "Připojit",
|
"connect": "Připojit",
|
||||||
"connecting": "Connecting",
|
"connecting": "Connecting",
|
||||||
"copy": "kopírovat",
|
"copy": "kopírovat",
|
||||||
|
"create": "Create",
|
||||||
"delete": "Vymazat",
|
"delete": "Vymazat",
|
||||||
"disconnect": "Odpojit",
|
"disconnect": "Odpojit",
|
||||||
"dismiss": "Zavrhnout",
|
"dismiss": "Zavrhnout",
|
||||||
@@ -31,6 +33,7 @@
|
|||||||
"open_workspace": "Open workspace",
|
"open_workspace": "Open workspace",
|
||||||
"paste": "Paste",
|
"paste": "Paste",
|
||||||
"prettify": "Prettify",
|
"prettify": "Prettify",
|
||||||
|
"properties": "Properties",
|
||||||
"remove": "Odstranit",
|
"remove": "Odstranit",
|
||||||
"rename": "Rename",
|
"rename": "Rename",
|
||||||
"restore": "Obnovit",
|
"restore": "Obnovit",
|
||||||
@@ -39,6 +42,7 @@
|
|||||||
"scroll_to_top": "Scroll to top",
|
"scroll_to_top": "Scroll to top",
|
||||||
"search": "Vyhledávání",
|
"search": "Vyhledávání",
|
||||||
"send": "Poslat",
|
"send": "Poslat",
|
||||||
|
"share": "Share",
|
||||||
"start": "Start",
|
"start": "Start",
|
||||||
"starting": "Starting",
|
"starting": "Starting",
|
||||||
"stop": "Stop",
|
"stop": "Stop",
|
||||||
@@ -57,7 +61,9 @@
|
|||||||
"app": {
|
"app": {
|
||||||
"chat_with_us": "piš si s námi",
|
"chat_with_us": "piš si s námi",
|
||||||
"contact_us": "Kontaktujte nás",
|
"contact_us": "Kontaktujte nás",
|
||||||
|
"cookies": "Cookies",
|
||||||
"copy": "kopírovat",
|
"copy": "kopírovat",
|
||||||
|
"copy_interface_type": "Copy interface type",
|
||||||
"copy_user_id": "Copy User Auth Token",
|
"copy_user_id": "Copy User Auth Token",
|
||||||
"developer_option": "Developer options",
|
"developer_option": "Developer options",
|
||||||
"developer_option_description": "Developer tools which helps in development and maintenance of Hoppscotch.",
|
"developer_option_description": "Developer tools which helps in development and maintenance of Hoppscotch.",
|
||||||
@@ -73,6 +79,7 @@
|
|||||||
"keyboard_shortcuts": "Klávesové zkratky",
|
"keyboard_shortcuts": "Klávesové zkratky",
|
||||||
"name": "Hoppscotch",
|
"name": "Hoppscotch",
|
||||||
"new_version_found": "Nalezena nová verze. Aktualizujte aktualizací.",
|
"new_version_found": "Nalezena nová verze. Aktualizujte aktualizací.",
|
||||||
|
"open_in_hoppscotch": "Open in Hoppscotch",
|
||||||
"options": "Options",
|
"options": "Options",
|
||||||
"proxy_privacy_policy": "Zásady ochrany osobních údajů proxy",
|
"proxy_privacy_policy": "Zásady ochrany osobních údajů proxy",
|
||||||
"reload": "Znovu načíst",
|
"reload": "Znovu načíst",
|
||||||
@@ -112,10 +119,27 @@
|
|||||||
},
|
},
|
||||||
"authorization": {
|
"authorization": {
|
||||||
"generate_token": "Generovat token",
|
"generate_token": "Generovat token",
|
||||||
|
"graphql_headers": "Authorization Headers are sent as part of the payload to connection_init",
|
||||||
"include_in_url": "Zahrnout do adresy URL",
|
"include_in_url": "Zahrnout do adresy URL",
|
||||||
|
"inherited_from": "Inherited from {auth} from Parent Collection {collection} ",
|
||||||
"learn": "Zjistěte jak",
|
"learn": "Zjistěte jak",
|
||||||
|
"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": "Heslo",
|
"password": "Heslo",
|
||||||
|
"save_to_inherit": "Please save this request in any collection to inherit the authorization",
|
||||||
"token": "Žeton",
|
"token": "Žeton",
|
||||||
"type": "Typ autorizace",
|
"type": "Typ autorizace",
|
||||||
"username": "Uživatelské jméno"
|
"username": "Uživatelské jméno"
|
||||||
@@ -124,6 +148,7 @@
|
|||||||
"created": "Kolekce vytvořena",
|
"created": "Kolekce vytvořena",
|
||||||
"different_parent": "Cannot reorder collection with different parent",
|
"different_parent": "Cannot reorder collection with different parent",
|
||||||
"edit": "Upravit sbírku",
|
"edit": "Upravit sbírku",
|
||||||
|
"import_or_create": "Import or create a collection",
|
||||||
"invalid_name": "Uveďte prosím platný název kolekce",
|
"invalid_name": "Uveďte prosím platný název kolekce",
|
||||||
"invalid_root_move": "Collection already in the root",
|
"invalid_root_move": "Collection already in the root",
|
||||||
"moved": "Moved Successfully",
|
"moved": "Moved Successfully",
|
||||||
@@ -132,6 +157,8 @@
|
|||||||
"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": "Nová kolekce",
|
"new": "Nová kolekce",
|
||||||
"order_changed": "Collection Order Updated",
|
"order_changed": "Collection Order Updated",
|
||||||
|
"properties": "Collection Properties",
|
||||||
|
"properties_updated": "Collection Properties Updated",
|
||||||
"renamed": "Sbírka přejmenována",
|
"renamed": "Sbírka přejmenována",
|
||||||
"request_in_use": "Request in use",
|
"request_in_use": "Request in use",
|
||||||
"save_as": "Uložit jako",
|
"save_as": "Uložit jako",
|
||||||
@@ -151,6 +178,7 @@
|
|||||||
"remove_folder": "Opravdu chcete tuto složku trvale smazat?",
|
"remove_folder": "Opravdu chcete tuto složku trvale smazat?",
|
||||||
"remove_history": "Opravdu chcete trvale smazat celou historii?",
|
"remove_history": "Opravdu chcete trvale smazat celou historii?",
|
||||||
"remove_request": "Opravdu chcete tento požadavek trvale smazat?",
|
"remove_request": "Opravdu chcete tento požadavek trvale smazat?",
|
||||||
|
"remove_shared_request": "Are you sure you want to permanently delete this shared request?",
|
||||||
"remove_team": "Opravdu chcete tento tým smazat?",
|
"remove_team": "Opravdu chcete tento tým smazat?",
|
||||||
"remove_telemetry": "Opravdu se chcete odhlásit z telemetrie?",
|
"remove_telemetry": "Opravdu se chcete odhlásit z telemetrie?",
|
||||||
"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.",
|
||||||
@@ -162,6 +190,24 @@
|
|||||||
"open_request_in_new_tab": "Open request in new tab",
|
"open_request_in_new_tab": "Open request in new tab",
|
||||||
"set_environment_variable": "Set as variable"
|
"set_environment_variable": "Set as variable"
|
||||||
},
|
},
|
||||||
|
"cookies": {
|
||||||
|
"modal": {
|
||||||
|
"cookie_expires": "Expires",
|
||||||
|
"cookie_name": "Name",
|
||||||
|
"cookie_path": "Path",
|
||||||
|
"cookie_string": "Cookie string",
|
||||||
|
"cookie_value": "Value",
|
||||||
|
"empty_domain": "Domain is empty",
|
||||||
|
"empty_domains": "Domain list is empty",
|
||||||
|
"enter_cookie_string": "Enter cookie string",
|
||||||
|
"interceptor_no_support": "Your currently selected interceptor does not support cookies. Select a different Interceptor and try again.",
|
||||||
|
"managed_tab": "Managed",
|
||||||
|
"new_domain_name": "New domain name",
|
||||||
|
"no_cookies_in_domain": "No cookies set for this domain",
|
||||||
|
"raw_tab": "Raw",
|
||||||
|
"set": "Set a cookie"
|
||||||
|
}
|
||||||
|
},
|
||||||
"count": {
|
"count": {
|
||||||
"header": "Záhlaví {count}",
|
"header": "Záhlaví {count}",
|
||||||
"message": "Zpráva {count}",
|
"message": "Zpráva {count}",
|
||||||
@@ -192,11 +238,13 @@
|
|||||||
"profile": "Login to view your profile",
|
"profile": "Login to view your profile",
|
||||||
"protocols": "Protokoly jsou prázdné",
|
"protocols": "Protokoly jsou prázdné",
|
||||||
"schema": "Připojte se ke koncovému bodu GraphQL",
|
"schema": "Připojte se ke koncovému bodu GraphQL",
|
||||||
"shortcodes": "Shortcodes are empty",
|
"shared_requests": "Shared requests are empty",
|
||||||
|
"shared_requests_logout": "Login to view your shared requests or create a new one",
|
||||||
"subscription": "Subscriptions are empty",
|
"subscription": "Subscriptions are empty",
|
||||||
"team_name": "Název týmu prázdný",
|
"team_name": "Název týmu prázdný",
|
||||||
"teams": "Týmy jsou prázdné",
|
"teams": "Týmy jsou prázdné",
|
||||||
"tests": "Pro tento požadavek neexistují žádné testy"
|
"tests": "Pro tento požadavek neexistují žádné testy",
|
||||||
|
"shortcodes": "Shortcodes are empty"
|
||||||
},
|
},
|
||||||
"environment": {
|
"environment": {
|
||||||
"add_to_global": "Add to Global",
|
"add_to_global": "Add to Global",
|
||||||
@@ -209,6 +257,7 @@
|
|||||||
"empty_variables": "No variables",
|
"empty_variables": "No variables",
|
||||||
"global": "Global",
|
"global": "Global",
|
||||||
"global_variables": "Global variables",
|
"global_variables": "Global variables",
|
||||||
|
"import_or_create": "Import or create a environment",
|
||||||
"invalid_name": "Zadejte platný název prostředí",
|
"invalid_name": "Zadejte platný název prostředí",
|
||||||
"list": "Environment variables",
|
"list": "Environment variables",
|
||||||
"my_environments": "My Environments",
|
"my_environments": "My Environments",
|
||||||
@@ -232,8 +281,10 @@
|
|||||||
"variable_list": "Seznam proměnných"
|
"variable_list": "Seznam proměnných"
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
|
"authproviders_load_error": "Unable to load auth providers",
|
||||||
"browser_support_sse": "Zdá se, že tento prohlížeč nemá podporu událostí odeslaných serverem.",
|
"browser_support_sse": "Zdá se, že tento prohlížeč nemá podporu událostí odeslaných serverem.",
|
||||||
"check_console_details": "Podrobnosti najdete v protokolu konzoly.",
|
"check_console_details": "Podrobnosti najdete v protokolu konzoly.",
|
||||||
|
"check_how_to_add_origin": "Check how you can add an origin",
|
||||||
"curl_invalid_format": "cURL nemá správný formát",
|
"curl_invalid_format": "cURL nemá správný formát",
|
||||||
"danger_zone": "Danger zone",
|
"danger_zone": "Danger zone",
|
||||||
"delete_account": "Your account is currently an owner in these teams:",
|
"delete_account": "Your account is currently an owner in these teams:",
|
||||||
@@ -249,9 +300,12 @@
|
|||||||
"json_prettify_invalid_body": "Nelze předtifikovat neplatné tělo, vyřešit chyby syntaxe json a zkusit to znovu",
|
"json_prettify_invalid_body": "Nelze předtifikovat neplatné tělo, vyřešit chyby syntaxe json a zkusit to znovu",
|
||||||
"network_error": "There seems to be a network error. Please try again.",
|
"network_error": "There seems to be a network error. Please try again.",
|
||||||
"network_fail": "Žádost nelze odeslat",
|
"network_fail": "Žádost nelze odeslat",
|
||||||
|
"no_collections_to_export": "No collections to export. Please create a collection to get started.",
|
||||||
"no_duration": "Žádné trvání",
|
"no_duration": "Žádné trvání",
|
||||||
|
"no_environments_to_export": "No environments to export. Please create an environment to get started.",
|
||||||
"no_results_found": "No matches found",
|
"no_results_found": "No matches found",
|
||||||
"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.",
|
||||||
"proxy_error": "Proxy error",
|
"proxy_error": "Proxy error",
|
||||||
"script_fail": "Skript předběžného požadavku nelze spustit",
|
"script_fail": "Skript předběžného požadavku nelze spustit",
|
||||||
"something_went_wrong": "Něco se pokazilo",
|
"something_went_wrong": "Něco se pokazilo",
|
||||||
@@ -260,6 +314,7 @@
|
|||||||
"export": {
|
"export": {
|
||||||
"as_json": "Exportovat jako JSON",
|
"as_json": "Exportovat jako JSON",
|
||||||
"create_secret_gist": "Vytvořte tajnou podstatu",
|
"create_secret_gist": "Vytvořte tajnou podstatu",
|
||||||
|
"failed": "Something went wrong while exporting",
|
||||||
"gist_created": "Podstata vytvořena",
|
"gist_created": "Podstata vytvořena",
|
||||||
"require_github": "Přihlaste se pomocí GitHub a vytvořte tajný seznam",
|
"require_github": "Přihlaste se pomocí GitHub a vytvořte tajný seznam",
|
||||||
"title": "Export"
|
"title": "Export"
|
||||||
@@ -286,6 +341,9 @@
|
|||||||
"subscriptions": "Předplatné",
|
"subscriptions": "Předplatné",
|
||||||
"switch_connection": "Switch connection"
|
"switch_connection": "Switch connection"
|
||||||
},
|
},
|
||||||
|
"graphql_collections": {
|
||||||
|
"title": "GraphQL Collections"
|
||||||
|
},
|
||||||
"group": {
|
"group": {
|
||||||
"time": "Time",
|
"time": "Time",
|
||||||
"url": "URL"
|
"url": "URL"
|
||||||
@@ -297,6 +355,8 @@
|
|||||||
},
|
},
|
||||||
"helpers": {
|
"helpers": {
|
||||||
"authorization": "Autorizační hlavička se automaticky vygeneruje při odeslání požadavku.",
|
"authorization": "Autorizační hlavička se automaticky vygeneruje při odeslání požadavku.",
|
||||||
|
"collection_properties_authorization": " This authorization will be set for every request in this collection.",
|
||||||
|
"collection_properties_header": "This header will be set for every request in this collection.",
|
||||||
"generate_documentation_first": "Nejprve vytvořte dokumentaci",
|
"generate_documentation_first": "Nejprve vytvořte dokumentaci",
|
||||||
"network_fail": "Nelze dosáhnout koncového bodu API. Zkontrolujte připojení k síti a zkuste to znovu.",
|
"network_fail": "Nelze dosáhnout koncového bodu API. Zkontrolujte připojení k síti a zkuste to znovu.",
|
||||||
"offline": "Zdá se, že jste offline. Data v tomto pracovním prostoru nemusí být aktuální.",
|
"offline": "Zdá se, že jste offline. Data v tomto pracovním prostoru nemusí být aktuální.",
|
||||||
@@ -316,7 +376,10 @@
|
|||||||
"import": {
|
"import": {
|
||||||
"collections": "Import sbírek",
|
"collections": "Import sbírek",
|
||||||
"curl": "Importovat cURL",
|
"curl": "Importovat cURL",
|
||||||
|
"environments_from_gist": "Import From Gist",
|
||||||
|
"environments_from_gist_description": "Import Hoppscotch Environments From Gist",
|
||||||
"failed": "Import se nezdařil",
|
"failed": "Import se nezdařil",
|
||||||
|
"from_file": "Import from File",
|
||||||
"from_gist": "Import z Gist",
|
"from_gist": "Import z Gist",
|
||||||
"from_gist_description": "Import from Gist URL",
|
"from_gist_description": "Import from Gist URL",
|
||||||
"from_insomnia": "Import from Insomnia",
|
"from_insomnia": "Import from Insomnia",
|
||||||
@@ -331,11 +394,17 @@
|
|||||||
"from_postman_description": "Import from Postman collection",
|
"from_postman_description": "Import from Postman collection",
|
||||||
"from_url": "Import from URL",
|
"from_url": "Import from URL",
|
||||||
"gist_url": "Zadejte URL adresy",
|
"gist_url": "Zadejte URL adresy",
|
||||||
|
"gql_collections_from_gist_description": "Import GraphQL Collections From Gist",
|
||||||
|
"hoppscotch_environment": "Hoppscotch Environment",
|
||||||
|
"hoppscotch_environment_description": "Import Hoppscotch Environment JSON file",
|
||||||
"import_from_url_invalid_fetch": "Couldn't get data from the url",
|
"import_from_url_invalid_fetch": "Couldn't get data from the url",
|
||||||
"import_from_url_invalid_file_format": "Error while importing collections",
|
"import_from_url_invalid_file_format": "Error while importing collections",
|
||||||
"import_from_url_invalid_type": "Unsupported type. accepted values are 'hoppscotch', 'openapi', 'postman', 'insomnia'",
|
"import_from_url_invalid_type": "Unsupported type. accepted values are 'hoppscotch', 'openapi', 'postman', 'insomnia'",
|
||||||
"import_from_url_success": "Collections Imported",
|
"import_from_url_success": "Collections Imported",
|
||||||
|
"insomnia_environment_description": "Import Insomnia Environment from a JSON/YAML file",
|
||||||
"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_description": "Import Postman Environment from a JSON file",
|
||||||
"title": "Import"
|
"title": "Import"
|
||||||
},
|
},
|
||||||
"inspections": {
|
"inspections": {
|
||||||
@@ -373,8 +442,10 @@
|
|||||||
"close_unsaved_tab": "You have unsaved changes",
|
"close_unsaved_tab": "You have unsaved changes",
|
||||||
"collections": "Sbírky",
|
"collections": "Sbírky",
|
||||||
"confirm": "Potvrdit",
|
"confirm": "Potvrdit",
|
||||||
|
"customize_request": "Customize Request",
|
||||||
"edit_request": "Upravit požadavek",
|
"edit_request": "Upravit požadavek",
|
||||||
"import_export": "Import Export"
|
"import_export": "Import Export",
|
||||||
|
"share_request": "Share Request"
|
||||||
},
|
},
|
||||||
"mqtt": {
|
"mqtt": {
|
||||||
"already_subscribed": "You are already subscribed to this topic.",
|
"already_subscribed": "You are already subscribed to this topic.",
|
||||||
@@ -449,13 +520,14 @@
|
|||||||
"structured": "Structured",
|
"structured": "Structured",
|
||||||
"text": "Text"
|
"text": "Text"
|
||||||
},
|
},
|
||||||
"copy_link": "Kopírovat odkaz",
|
|
||||||
"different_collection": "Cannot reorder requests from different collections",
|
"different_collection": "Cannot reorder requests from different collections",
|
||||||
"duplicated": "Request duplicated",
|
"duplicated": "Request duplicated",
|
||||||
"duration": "Doba trvání",
|
"duration": "Doba trvání",
|
||||||
"enter_curl": "Zadejte cURL",
|
"enter_curl": "Zadejte cURL",
|
||||||
"generate_code": "Vygenerujte kód",
|
"generate_code": "Vygenerujte kód",
|
||||||
"generated_code": "Generovaný kód",
|
"generated_code": "Generovaný kód",
|
||||||
|
"go_to_authorization_tab": "Go to Authorization tab",
|
||||||
|
"go_to_body_tab": "Go to Body tab",
|
||||||
"header_list": "Seznam záhlaví",
|
"header_list": "Seznam záhlaví",
|
||||||
"invalid_name": "Uveďte prosím název žádosti",
|
"invalid_name": "Uveďte prosím název žádosti",
|
||||||
"method": "Metoda",
|
"method": "Metoda",
|
||||||
@@ -480,12 +552,14 @@
|
|||||||
"saved": "Žádost uložena",
|
"saved": "Žádost uložena",
|
||||||
"share": "Podíl",
|
"share": "Podíl",
|
||||||
"share_description": "Share Hoppscotch with your friends",
|
"share_description": "Share Hoppscotch with your friends",
|
||||||
|
"share_request": "Share Request",
|
||||||
"stop": "Stop",
|
"stop": "Stop",
|
||||||
"title": "Žádost",
|
"title": "Žádost",
|
||||||
"type": "Typ požadavku",
|
"type": "Typ požadavku",
|
||||||
"url": "URL",
|
"url": "URL",
|
||||||
"variables": "Proměnné",
|
"variables": "Proměnné",
|
||||||
"view_my_links": "View my links"
|
"view_my_links": "View my links",
|
||||||
|
"copy_link": "Kopírovat odkaz"
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"audio": "Audio",
|
"audio": "Audio",
|
||||||
@@ -513,6 +587,7 @@
|
|||||||
"account_description": "Přizpůsobte si nastavení účtu.",
|
"account_description": "Přizpůsobte si nastavení účtu.",
|
||||||
"account_email_description": "Vaše primární e -mailová adresa.",
|
"account_email_description": "Vaše primární e -mailová adresa.",
|
||||||
"account_name_description": "Toto je vaše zobrazované jméno.",
|
"account_name_description": "Toto je vaše zobrazované jméno.",
|
||||||
|
"additional": "Additional Settings",
|
||||||
"background": "Pozadí",
|
"background": "Pozadí",
|
||||||
"black_mode": "Černá",
|
"black_mode": "Černá",
|
||||||
"choose_language": "Vyber jazyk",
|
"choose_language": "Vyber jazyk",
|
||||||
@@ -559,14 +634,31 @@
|
|||||||
"verified_email": "Verified email",
|
"verified_email": "Verified email",
|
||||||
"verify_email": "Verify email"
|
"verify_email": "Verify email"
|
||||||
},
|
},
|
||||||
"shortcodes": {
|
"shared_requests": {
|
||||||
"actions": "Actions",
|
"button": "Button",
|
||||||
"created_on": "Created on",
|
"button_info": "Create a 'Run in Hoppscotch' button for your website, blog or a README.",
|
||||||
"deleted": "Shortcode deleted",
|
"copy_html": "Copy HTML",
|
||||||
"method": "Method",
|
"copy_link": "Copy Link",
|
||||||
"not_found": "Shortcode not found",
|
"copy_markdown": "Copy Markdown",
|
||||||
"short_code": "Short code",
|
"creating_widget": "Creating widget",
|
||||||
"url": "URL"
|
"customize": "Customize",
|
||||||
|
"deleted": "Shared request deleted",
|
||||||
|
"description": "Select a widget, you can change and customize this later",
|
||||||
|
"embed": "Embed",
|
||||||
|
"embed_info": "Add a mini 'Hoppscotch API Playground' to your website, blog or documentation.",
|
||||||
|
"link": "Link",
|
||||||
|
"link_info": "Create a shareable link to share with anyone on the internet with view access.",
|
||||||
|
"modified": "Shared request modified",
|
||||||
|
"not_found": "Shared request not found",
|
||||||
|
"open_new_tab": "Open in new tab",
|
||||||
|
"preview": "Preview",
|
||||||
|
"run_in_hoppscotch": "Run in Hoppscotch",
|
||||||
|
"theme": {
|
||||||
|
"dark": "Dark",
|
||||||
|
"light": "Light",
|
||||||
|
"system": "System",
|
||||||
|
"title": "Theme"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"shortcut": {
|
"shortcut": {
|
||||||
"general": {
|
"general": {
|
||||||
@@ -596,7 +688,6 @@
|
|||||||
"title": "Others"
|
"title": "Others"
|
||||||
},
|
},
|
||||||
"request": {
|
"request": {
|
||||||
"copy_request_link": "Kopírovat požadavek na odkaz",
|
|
||||||
"delete_method": "Vyberte metodu ODSTRANIT",
|
"delete_method": "Vyberte metodu ODSTRANIT",
|
||||||
"get_method": "Vyberte metodu ZÍSKAT",
|
"get_method": "Vyberte metodu ZÍSKAT",
|
||||||
"head_method": "Vyberte metodu HEAD",
|
"head_method": "Vyberte metodu HEAD",
|
||||||
@@ -611,8 +702,10 @@
|
|||||||
"save_request": "Save Request",
|
"save_request": "Save Request",
|
||||||
"save_to_collections": "Uložit do sbírek",
|
"save_to_collections": "Uložit do sbírek",
|
||||||
"send_request": "Poslat žádost",
|
"send_request": "Poslat žádost",
|
||||||
|
"share_request": "Share Request",
|
||||||
"show_code": "Generate code snippet",
|
"show_code": "Generate code snippet",
|
||||||
"title": "Žádost"
|
"title": "Žádost",
|
||||||
|
"copy_request_link": "Kopírovat požadavek na odkaz"
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"copy": "Copy response to clipboard",
|
"copy": "Copy response to clipboard",
|
||||||
@@ -735,6 +828,7 @@
|
|||||||
"connection_error": "Failed to connect",
|
"connection_error": "Failed to connect",
|
||||||
"connection_failed": "Connection failed",
|
"connection_failed": "Connection failed",
|
||||||
"connection_lost": "Connection lost",
|
"connection_lost": "Connection lost",
|
||||||
|
"copied_interface_to_clipboard": "Copied {language} interface type to clipboard",
|
||||||
"copied_to_clipboard": "Zkopírováno do schránky",
|
"copied_to_clipboard": "Zkopírováno do schránky",
|
||||||
"deleted": "Smazáno",
|
"deleted": "Smazáno",
|
||||||
"deprecated": "ZASTARALÉ",
|
"deprecated": "ZASTARALÉ",
|
||||||
@@ -742,10 +836,12 @@
|
|||||||
"disconnected": "Odpojeno",
|
"disconnected": "Odpojeno",
|
||||||
"disconnected_from": "Odpojeno od {name}",
|
"disconnected_from": "Odpojeno od {name}",
|
||||||
"docs_generated": "Vygenerovaná dokumentace",
|
"docs_generated": "Vygenerovaná dokumentace",
|
||||||
|
"download_failed": "Download failed",
|
||||||
"download_started": "Stahování zahájeno",
|
"download_started": "Stahování zahájeno",
|
||||||
"enabled": "Povoleno",
|
"enabled": "Povoleno",
|
||||||
"file_imported": "Soubor importován",
|
"file_imported": "Soubor importován",
|
||||||
"finished_in": "Hotovo za {duration} ms",
|
"finished_in": "Hotovo za {duration} ms",
|
||||||
|
"hide": "Hide",
|
||||||
"history_deleted": "Historie odstraněna",
|
"history_deleted": "Historie odstraněna",
|
||||||
"linewrap": "Zabalit linky",
|
"linewrap": "Zabalit linky",
|
||||||
"loading": "Načítání...",
|
"loading": "Načítání...",
|
||||||
@@ -756,6 +852,7 @@
|
|||||||
"published_error": "Something went wrong while publishing msg: {topic} to topic: {message}",
|
"published_error": "Something went wrong while publishing msg: {topic} to topic: {message}",
|
||||||
"published_message": "Published message: {message} to topic: {topic}",
|
"published_message": "Published message: {message} to topic: {topic}",
|
||||||
"reconnection_error": "Failed to reconnect",
|
"reconnection_error": "Failed to reconnect",
|
||||||
|
"show": "Show",
|
||||||
"subscribed_failed": "Failed to subscribe to topic: {topic}",
|
"subscribed_failed": "Failed to subscribe to topic: {topic}",
|
||||||
"subscribed_success": "Successfully subscribed to topic: {topic}",
|
"subscribed_success": "Successfully subscribed to topic: {topic}",
|
||||||
"unsubscribed_failed": "Failed to unsubscribe from topic: {topic}",
|
"unsubscribed_failed": "Failed to unsubscribe from topic: {topic}",
|
||||||
@@ -791,6 +888,7 @@
|
|||||||
"queries": "Dotazy",
|
"queries": "Dotazy",
|
||||||
"query": "Dotaz",
|
"query": "Dotaz",
|
||||||
"schema": "Schema",
|
"schema": "Schema",
|
||||||
|
"shared_requests": "Shared Requests",
|
||||||
"socketio": "Socket.IO",
|
"socketio": "Socket.IO",
|
||||||
"sse": "SSE",
|
"sse": "SSE",
|
||||||
"tests": "Testy",
|
"tests": "Testy",
|
||||||
@@ -807,6 +905,7 @@
|
|||||||
"email_do_not_match": "Email doesn't match with your account details. Contact your team owner.",
|
"email_do_not_match": "Email doesn't match with your account details. Contact your team owner.",
|
||||||
"exit": "Ukončete tým",
|
"exit": "Ukončete tým",
|
||||||
"exit_disabled": "Pouze vlastník nemůže opustit tým",
|
"exit_disabled": "Pouze vlastník nemůže opustit tým",
|
||||||
|
"failed_invites": "Failed invites",
|
||||||
"invalid_coll_id": "Invalid collection ID",
|
"invalid_coll_id": "Invalid collection ID",
|
||||||
"invalid_email_format": "Formát e -mailu je neplatný",
|
"invalid_email_format": "Formát e -mailu je neplatný",
|
||||||
"invalid_id": "Invalid team ID. Contact your team owner.",
|
"invalid_id": "Invalid team ID. Contact your team owner.",
|
||||||
@@ -848,6 +947,7 @@
|
|||||||
"same_target_destination": "Same target and destination",
|
"same_target_destination": "Same target and destination",
|
||||||
"saved": "Tým uložen",
|
"saved": "Tým uložen",
|
||||||
"select_a_team": "Select a team",
|
"select_a_team": "Select a team",
|
||||||
|
"success_invites": "Success invites",
|
||||||
"title": "Týmy",
|
"title": "Týmy",
|
||||||
"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 team."
|
"we_sent_invite_link_description": "Ask all invitees to check their inbox. Click on the link to join the team."
|
||||||
@@ -879,5 +979,14 @@
|
|||||||
"personal": "My Workspace",
|
"personal": "My Workspace",
|
||||||
"team": "Team Workspace",
|
"team": "Team Workspace",
|
||||||
"title": "Workspaces"
|
"title": "Workspaces"
|
||||||
|
},
|
||||||
|
"shortcodes": {
|
||||||
|
"actions": "Actions",
|
||||||
|
"created_on": "Created on",
|
||||||
|
"deleted": "Shortcode deleted",
|
||||||
|
"method": "Method",
|
||||||
|
"not_found": "Shortcode not found",
|
||||||
|
"short_code": "Short code",
|
||||||
|
"url": "URL"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"action": {
|
"action": {
|
||||||
|
"add": "Add",
|
||||||
"autoscroll": "Autoscroll",
|
"autoscroll": "Autoscroll",
|
||||||
"cancel": "Afbestille",
|
"cancel": "Afbestille",
|
||||||
"choose_file": "Vælg en fil",
|
"choose_file": "Vælg en fil",
|
||||||
@@ -10,6 +11,7 @@
|
|||||||
"connect": "Opret forbindelse",
|
"connect": "Opret forbindelse",
|
||||||
"connecting": "Connecting",
|
"connecting": "Connecting",
|
||||||
"copy": "Kopi",
|
"copy": "Kopi",
|
||||||
|
"create": "Create",
|
||||||
"delete": "Slet",
|
"delete": "Slet",
|
||||||
"disconnect": "Koble fra",
|
"disconnect": "Koble fra",
|
||||||
"dismiss": "Afskedige",
|
"dismiss": "Afskedige",
|
||||||
@@ -31,6 +33,7 @@
|
|||||||
"open_workspace": "Open workspace",
|
"open_workspace": "Open workspace",
|
||||||
"paste": "Paste",
|
"paste": "Paste",
|
||||||
"prettify": "Prettify",
|
"prettify": "Prettify",
|
||||||
|
"properties": "Properties",
|
||||||
"remove": "Fjerne",
|
"remove": "Fjerne",
|
||||||
"rename": "Rename",
|
"rename": "Rename",
|
||||||
"restore": "Gendan",
|
"restore": "Gendan",
|
||||||
@@ -39,6 +42,7 @@
|
|||||||
"scroll_to_top": "Scroll to top",
|
"scroll_to_top": "Scroll to top",
|
||||||
"search": "Søg",
|
"search": "Søg",
|
||||||
"send": "Sende",
|
"send": "Sende",
|
||||||
|
"share": "Share",
|
||||||
"start": "Start",
|
"start": "Start",
|
||||||
"starting": "Starting",
|
"starting": "Starting",
|
||||||
"stop": "Hold op",
|
"stop": "Hold op",
|
||||||
@@ -57,7 +61,9 @@
|
|||||||
"app": {
|
"app": {
|
||||||
"chat_with_us": "Chat med os",
|
"chat_with_us": "Chat med os",
|
||||||
"contact_us": "Kontakt os",
|
"contact_us": "Kontakt os",
|
||||||
|
"cookies": "Cookies",
|
||||||
"copy": "Kopi",
|
"copy": "Kopi",
|
||||||
|
"copy_interface_type": "Copy interface type",
|
||||||
"copy_user_id": "Copy User Auth Token",
|
"copy_user_id": "Copy User Auth Token",
|
||||||
"developer_option": "Developer options",
|
"developer_option": "Developer options",
|
||||||
"developer_option_description": "Developer tools which helps in development and maintenance of Hoppscotch.",
|
"developer_option_description": "Developer tools which helps in development and maintenance of Hoppscotch.",
|
||||||
@@ -73,6 +79,7 @@
|
|||||||
"keyboard_shortcuts": "Tastaturgenveje",
|
"keyboard_shortcuts": "Tastaturgenveje",
|
||||||
"name": "Hoppscotch",
|
"name": "Hoppscotch",
|
||||||
"new_version_found": "Ny version fundet. Opdater for at opdatere.",
|
"new_version_found": "Ny version fundet. Opdater for at opdatere.",
|
||||||
|
"open_in_hoppscotch": "Open in Hoppscotch",
|
||||||
"options": "Options",
|
"options": "Options",
|
||||||
"proxy_privacy_policy": "Politik til beskyttelse af personlige oplysninger i proxy",
|
"proxy_privacy_policy": "Politik til beskyttelse af personlige oplysninger i proxy",
|
||||||
"reload": "Genindlæs",
|
"reload": "Genindlæs",
|
||||||
@@ -112,10 +119,27 @@
|
|||||||
},
|
},
|
||||||
"authorization": {
|
"authorization": {
|
||||||
"generate_token": "Generer Token",
|
"generate_token": "Generer Token",
|
||||||
|
"graphql_headers": "Authorization Headers are sent as part of the payload to connection_init",
|
||||||
"include_in_url": "Inkluder i URL",
|
"include_in_url": "Inkluder i URL",
|
||||||
|
"inherited_from": "Inherited from {auth} from Parent Collection {collection} ",
|
||||||
"learn": "Lær hvordan",
|
"learn": "Lær hvordan",
|
||||||
|
"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": "Adgangskode",
|
"password": "Adgangskode",
|
||||||
|
"save_to_inherit": "Please save this request in any collection to inherit the authorization",
|
||||||
"token": "Polet",
|
"token": "Polet",
|
||||||
"type": "Godkendelse Type",
|
"type": "Godkendelse Type",
|
||||||
"username": "Brugernavn"
|
"username": "Brugernavn"
|
||||||
@@ -124,6 +148,7 @@
|
|||||||
"created": "Samlingen er oprettet",
|
"created": "Samlingen er oprettet",
|
||||||
"different_parent": "Cannot reorder collection with different parent",
|
"different_parent": "Cannot reorder collection with different parent",
|
||||||
"edit": "Rediger samling",
|
"edit": "Rediger samling",
|
||||||
|
"import_or_create": "Import or create a collection",
|
||||||
"invalid_name": "Angiv et gyldigt navn til samlingen",
|
"invalid_name": "Angiv et gyldigt navn til samlingen",
|
||||||
"invalid_root_move": "Collection already in the root",
|
"invalid_root_move": "Collection already in the root",
|
||||||
"moved": "Moved Successfully",
|
"moved": "Moved Successfully",
|
||||||
@@ -132,6 +157,8 @@
|
|||||||
"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": "Ny kollektion",
|
"new": "Ny kollektion",
|
||||||
"order_changed": "Collection Order Updated",
|
"order_changed": "Collection Order Updated",
|
||||||
|
"properties": "Collection Properties",
|
||||||
|
"properties_updated": "Collection Properties Updated",
|
||||||
"renamed": "Samling omdøbt",
|
"renamed": "Samling omdøbt",
|
||||||
"request_in_use": "Request in use",
|
"request_in_use": "Request in use",
|
||||||
"save_as": "Gem som",
|
"save_as": "Gem som",
|
||||||
@@ -151,6 +178,7 @@
|
|||||||
"remove_folder": "Er du sikker på, at du vil slette denne mappe permanent?",
|
"remove_folder": "Er du sikker på, at du vil slette denne mappe permanent?",
|
||||||
"remove_history": "Er du sikker på, at du vil slette hele historikken permanent?",
|
"remove_history": "Er du sikker på, at du vil slette hele historikken permanent?",
|
||||||
"remove_request": "Er du sikker på, at du vil slette denne anmodning permanent?",
|
"remove_request": "Er du sikker på, at du vil slette denne anmodning permanent?",
|
||||||
|
"remove_shared_request": "Are you sure you want to permanently delete this shared request?",
|
||||||
"remove_team": "Er du sikker på, at du vil slette dette hold?",
|
"remove_team": "Er du sikker på, at du vil slette dette hold?",
|
||||||
"remove_telemetry": "Er du sikker på, at du vil fravælge telemetri?",
|
"remove_telemetry": "Er du sikker på, at du vil fravælge telemetri?",
|
||||||
"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.",
|
||||||
@@ -162,6 +190,24 @@
|
|||||||
"open_request_in_new_tab": "Open request in new tab",
|
"open_request_in_new_tab": "Open request in new tab",
|
||||||
"set_environment_variable": "Set as variable"
|
"set_environment_variable": "Set as variable"
|
||||||
},
|
},
|
||||||
|
"cookies": {
|
||||||
|
"modal": {
|
||||||
|
"cookie_expires": "Expires",
|
||||||
|
"cookie_name": "Name",
|
||||||
|
"cookie_path": "Path",
|
||||||
|
"cookie_string": "Cookie string",
|
||||||
|
"cookie_value": "Value",
|
||||||
|
"empty_domain": "Domain is empty",
|
||||||
|
"empty_domains": "Domain list is empty",
|
||||||
|
"enter_cookie_string": "Enter cookie string",
|
||||||
|
"interceptor_no_support": "Your currently selected interceptor does not support cookies. Select a different Interceptor and try again.",
|
||||||
|
"managed_tab": "Managed",
|
||||||
|
"new_domain_name": "New domain name",
|
||||||
|
"no_cookies_in_domain": "No cookies set for this domain",
|
||||||
|
"raw_tab": "Raw",
|
||||||
|
"set": "Set a cookie"
|
||||||
|
}
|
||||||
|
},
|
||||||
"count": {
|
"count": {
|
||||||
"header": "Overskrift {count}",
|
"header": "Overskrift {count}",
|
||||||
"message": "Besked {count}",
|
"message": "Besked {count}",
|
||||||
@@ -192,11 +238,13 @@
|
|||||||
"profile": "Login to view your profile",
|
"profile": "Login to view your profile",
|
||||||
"protocols": "Protokoller er tomme",
|
"protocols": "Protokoller er tomme",
|
||||||
"schema": "Opret forbindelse til et GraphQL -slutpunkt",
|
"schema": "Opret forbindelse til et GraphQL -slutpunkt",
|
||||||
"shortcodes": "Shortcodes are empty",
|
"shared_requests": "Shared requests are empty",
|
||||||
|
"shared_requests_logout": "Login to view your shared requests or create a new one",
|
||||||
"subscription": "Subscriptions are empty",
|
"subscription": "Subscriptions are empty",
|
||||||
"team_name": "Teamnavn er tomt",
|
"team_name": "Teamnavn er tomt",
|
||||||
"teams": "Hold er tomme",
|
"teams": "Hold er tomme",
|
||||||
"tests": "Der er ingen test for denne anmodning"
|
"tests": "Der er ingen test for denne anmodning",
|
||||||
|
"shortcodes": "Shortcodes are empty"
|
||||||
},
|
},
|
||||||
"environment": {
|
"environment": {
|
||||||
"add_to_global": "Add to Global",
|
"add_to_global": "Add to Global",
|
||||||
@@ -209,6 +257,7 @@
|
|||||||
"empty_variables": "No variables",
|
"empty_variables": "No variables",
|
||||||
"global": "Global",
|
"global": "Global",
|
||||||
"global_variables": "Global variables",
|
"global_variables": "Global variables",
|
||||||
|
"import_or_create": "Import or create a environment",
|
||||||
"invalid_name": "Angiv et gyldigt navn på miljøet",
|
"invalid_name": "Angiv et gyldigt navn på miljøet",
|
||||||
"list": "Environment variables",
|
"list": "Environment variables",
|
||||||
"my_environments": "My Environments",
|
"my_environments": "My Environments",
|
||||||
@@ -232,8 +281,10 @@
|
|||||||
"variable_list": "Variabel liste"
|
"variable_list": "Variabel liste"
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
|
"authproviders_load_error": "Unable to load auth providers",
|
||||||
"browser_support_sse": "Det ser ikke ud til, at denne browser understøtter Server Sent Events.",
|
"browser_support_sse": "Det ser ikke ud til, at denne browser understøtter Server Sent Events.",
|
||||||
"check_console_details": "Tjek konsollog for at få flere oplysninger.",
|
"check_console_details": "Tjek konsollog for at få flere oplysninger.",
|
||||||
|
"check_how_to_add_origin": "Check how you can add an origin",
|
||||||
"curl_invalid_format": "cURL er ikke formateret korrekt",
|
"curl_invalid_format": "cURL er ikke formateret korrekt",
|
||||||
"danger_zone": "Danger zone",
|
"danger_zone": "Danger zone",
|
||||||
"delete_account": "Your account is currently an owner in these teams:",
|
"delete_account": "Your account is currently an owner in these teams:",
|
||||||
@@ -249,9 +300,12 @@
|
|||||||
"json_prettify_invalid_body": "Kunne ikke pryde et ugyldigt brødtekst, løse json -syntaksfejl og prøve igen",
|
"json_prettify_invalid_body": "Kunne ikke pryde et ugyldigt brødtekst, løse json -syntaksfejl og prøve igen",
|
||||||
"network_error": "There seems to be a network error. Please try again.",
|
"network_error": "There seems to be a network error. Please try again.",
|
||||||
"network_fail": "Anmodningen kunne ikke sendes",
|
"network_fail": "Anmodningen kunne ikke sendes",
|
||||||
|
"no_collections_to_export": "No collections to export. Please create a collection to get started.",
|
||||||
"no_duration": "Ingen varighed",
|
"no_duration": "Ingen varighed",
|
||||||
|
"no_environments_to_export": "No environments to export. Please create an environment to get started.",
|
||||||
"no_results_found": "No matches found",
|
"no_results_found": "No matches found",
|
||||||
"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.",
|
||||||
"proxy_error": "Proxy error",
|
"proxy_error": "Proxy error",
|
||||||
"script_fail": "Kunne ikke udføre pre-request script",
|
"script_fail": "Kunne ikke udføre pre-request script",
|
||||||
"something_went_wrong": "Noget gik galt",
|
"something_went_wrong": "Noget gik galt",
|
||||||
@@ -260,6 +314,7 @@
|
|||||||
"export": {
|
"export": {
|
||||||
"as_json": "Eksporter som JSON",
|
"as_json": "Eksporter som JSON",
|
||||||
"create_secret_gist": "Opret hemmelig Gist",
|
"create_secret_gist": "Opret hemmelig Gist",
|
||||||
|
"failed": "Something went wrong while exporting",
|
||||||
"gist_created": "Gist skabt",
|
"gist_created": "Gist skabt",
|
||||||
"require_github": "Log ind med GitHub for at skabe hemmelig kerne",
|
"require_github": "Log ind med GitHub for at skabe hemmelig kerne",
|
||||||
"title": "Export"
|
"title": "Export"
|
||||||
@@ -286,6 +341,9 @@
|
|||||||
"subscriptions": "Abonnementer",
|
"subscriptions": "Abonnementer",
|
||||||
"switch_connection": "Switch connection"
|
"switch_connection": "Switch connection"
|
||||||
},
|
},
|
||||||
|
"graphql_collections": {
|
||||||
|
"title": "GraphQL Collections"
|
||||||
|
},
|
||||||
"group": {
|
"group": {
|
||||||
"time": "Time",
|
"time": "Time",
|
||||||
"url": "URL"
|
"url": "URL"
|
||||||
@@ -297,6 +355,8 @@
|
|||||||
},
|
},
|
||||||
"helpers": {
|
"helpers": {
|
||||||
"authorization": "Autorisationsoverskriften genereres automatisk, når du sender anmodningen.",
|
"authorization": "Autorisationsoverskriften genereres automatisk, når du sender anmodningen.",
|
||||||
|
"collection_properties_authorization": " This authorization will be set for every request in this collection.",
|
||||||
|
"collection_properties_header": "This header will be set for every request in this collection.",
|
||||||
"generate_documentation_first": "Generer først dokumentation",
|
"generate_documentation_first": "Generer først dokumentation",
|
||||||
"network_fail": "Kunne ikke nå API -slutpunktet. Kontroller din netværksforbindelse, og prøv igen.",
|
"network_fail": "Kunne ikke nå API -slutpunktet. Kontroller din netværksforbindelse, og prøv igen.",
|
||||||
"offline": "Du ser ud til at være offline. Data i dette arbejdsområde er muligvis ikke opdaterede.",
|
"offline": "Du ser ud til at være offline. Data i dette arbejdsområde er muligvis ikke opdaterede.",
|
||||||
@@ -316,7 +376,10 @@
|
|||||||
"import": {
|
"import": {
|
||||||
"collections": "Importer samlinger",
|
"collections": "Importer samlinger",
|
||||||
"curl": "Importer cURL",
|
"curl": "Importer cURL",
|
||||||
|
"environments_from_gist": "Import From Gist",
|
||||||
|
"environments_from_gist_description": "Import Hoppscotch Environments From Gist",
|
||||||
"failed": "Import mislykkedes",
|
"failed": "Import mislykkedes",
|
||||||
|
"from_file": "Import from File",
|
||||||
"from_gist": "Import fra Gist",
|
"from_gist": "Import fra Gist",
|
||||||
"from_gist_description": "Import from Gist URL",
|
"from_gist_description": "Import from Gist URL",
|
||||||
"from_insomnia": "Import from Insomnia",
|
"from_insomnia": "Import from Insomnia",
|
||||||
@@ -331,11 +394,17 @@
|
|||||||
"from_postman_description": "Import from Postman collection",
|
"from_postman_description": "Import from Postman collection",
|
||||||
"from_url": "Import from URL",
|
"from_url": "Import from URL",
|
||||||
"gist_url": "Indtast Gist URL",
|
"gist_url": "Indtast Gist URL",
|
||||||
|
"gql_collections_from_gist_description": "Import GraphQL Collections From Gist",
|
||||||
|
"hoppscotch_environment": "Hoppscotch Environment",
|
||||||
|
"hoppscotch_environment_description": "Import Hoppscotch Environment JSON file",
|
||||||
"import_from_url_invalid_fetch": "Couldn't get data from the url",
|
"import_from_url_invalid_fetch": "Couldn't get data from the url",
|
||||||
"import_from_url_invalid_file_format": "Error while importing collections",
|
"import_from_url_invalid_file_format": "Error while importing collections",
|
||||||
"import_from_url_invalid_type": "Unsupported type. accepted values are 'hoppscotch', 'openapi', 'postman', 'insomnia'",
|
"import_from_url_invalid_type": "Unsupported type. accepted values are 'hoppscotch', 'openapi', 'postman', 'insomnia'",
|
||||||
"import_from_url_success": "Collections Imported",
|
"import_from_url_success": "Collections Imported",
|
||||||
|
"insomnia_environment_description": "Import Insomnia Environment from a JSON/YAML file",
|
||||||
"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_description": "Import Postman Environment from a JSON file",
|
||||||
"title": "Importere"
|
"title": "Importere"
|
||||||
},
|
},
|
||||||
"inspections": {
|
"inspections": {
|
||||||
@@ -373,8 +442,10 @@
|
|||||||
"close_unsaved_tab": "You have unsaved changes",
|
"close_unsaved_tab": "You have unsaved changes",
|
||||||
"collections": "Samlinger",
|
"collections": "Samlinger",
|
||||||
"confirm": "Bekræfte",
|
"confirm": "Bekræfte",
|
||||||
|
"customize_request": "Customize Request",
|
||||||
"edit_request": "Rediger anmodning",
|
"edit_request": "Rediger anmodning",
|
||||||
"import_export": "Import Eksport"
|
"import_export": "Import Eksport",
|
||||||
|
"share_request": "Share Request"
|
||||||
},
|
},
|
||||||
"mqtt": {
|
"mqtt": {
|
||||||
"already_subscribed": "You are already subscribed to this topic.",
|
"already_subscribed": "You are already subscribed to this topic.",
|
||||||
@@ -449,13 +520,14 @@
|
|||||||
"structured": "Structured",
|
"structured": "Structured",
|
||||||
"text": "Text"
|
"text": "Text"
|
||||||
},
|
},
|
||||||
"copy_link": "Kopier link",
|
|
||||||
"different_collection": "Cannot reorder requests from different collections",
|
"different_collection": "Cannot reorder requests from different collections",
|
||||||
"duplicated": "Request duplicated",
|
"duplicated": "Request duplicated",
|
||||||
"duration": "Varighed",
|
"duration": "Varighed",
|
||||||
"enter_curl": "Indtast cURL",
|
"enter_curl": "Indtast cURL",
|
||||||
"generate_code": "Generer kode",
|
"generate_code": "Generer kode",
|
||||||
"generated_code": "Genereret kode",
|
"generated_code": "Genereret kode",
|
||||||
|
"go_to_authorization_tab": "Go to Authorization tab",
|
||||||
|
"go_to_body_tab": "Go to Body tab",
|
||||||
"header_list": "Overskriftsliste",
|
"header_list": "Overskriftsliste",
|
||||||
"invalid_name": "Angiv et navn på anmodningen",
|
"invalid_name": "Angiv et navn på anmodningen",
|
||||||
"method": "Metode",
|
"method": "Metode",
|
||||||
@@ -480,12 +552,14 @@
|
|||||||
"saved": "Anmodning gemt",
|
"saved": "Anmodning gemt",
|
||||||
"share": "Del",
|
"share": "Del",
|
||||||
"share_description": "Share Hoppscotch with your friends",
|
"share_description": "Share Hoppscotch with your friends",
|
||||||
|
"share_request": "Share Request",
|
||||||
"stop": "Stop",
|
"stop": "Stop",
|
||||||
"title": "Anmodning",
|
"title": "Anmodning",
|
||||||
"type": "Anmodningstype",
|
"type": "Anmodningstype",
|
||||||
"url": "URL",
|
"url": "URL",
|
||||||
"variables": "Variabler",
|
"variables": "Variabler",
|
||||||
"view_my_links": "View my links"
|
"view_my_links": "View my links",
|
||||||
|
"copy_link": "Kopier link"
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"audio": "Audio",
|
"audio": "Audio",
|
||||||
@@ -513,6 +587,7 @@
|
|||||||
"account_description": "Tilpas dine kontoindstillinger.",
|
"account_description": "Tilpas dine kontoindstillinger.",
|
||||||
"account_email_description": "Din primære e -mail -adresse.",
|
"account_email_description": "Din primære e -mail -adresse.",
|
||||||
"account_name_description": "Dette er dit visningsnavn.",
|
"account_name_description": "Dette er dit visningsnavn.",
|
||||||
|
"additional": "Additional Settings",
|
||||||
"background": "Baggrund",
|
"background": "Baggrund",
|
||||||
"black_mode": "Sort",
|
"black_mode": "Sort",
|
||||||
"choose_language": "Vælg sprog",
|
"choose_language": "Vælg sprog",
|
||||||
@@ -559,14 +634,31 @@
|
|||||||
"verified_email": "Verified email",
|
"verified_email": "Verified email",
|
||||||
"verify_email": "Verify email"
|
"verify_email": "Verify email"
|
||||||
},
|
},
|
||||||
"shortcodes": {
|
"shared_requests": {
|
||||||
"actions": "Actions",
|
"button": "Button",
|
||||||
"created_on": "Created on",
|
"button_info": "Create a 'Run in Hoppscotch' button for your website, blog or a README.",
|
||||||
"deleted": "Shortcode deleted",
|
"copy_html": "Copy HTML",
|
||||||
"method": "Method",
|
"copy_link": "Copy Link",
|
||||||
"not_found": "Shortcode not found",
|
"copy_markdown": "Copy Markdown",
|
||||||
"short_code": "Short code",
|
"creating_widget": "Creating widget",
|
||||||
"url": "URL"
|
"customize": "Customize",
|
||||||
|
"deleted": "Shared request deleted",
|
||||||
|
"description": "Select a widget, you can change and customize this later",
|
||||||
|
"embed": "Embed",
|
||||||
|
"embed_info": "Add a mini 'Hoppscotch API Playground' to your website, blog or documentation.",
|
||||||
|
"link": "Link",
|
||||||
|
"link_info": "Create a shareable link to share with anyone on the internet with view access.",
|
||||||
|
"modified": "Shared request modified",
|
||||||
|
"not_found": "Shared request not found",
|
||||||
|
"open_new_tab": "Open in new tab",
|
||||||
|
"preview": "Preview",
|
||||||
|
"run_in_hoppscotch": "Run in Hoppscotch",
|
||||||
|
"theme": {
|
||||||
|
"dark": "Dark",
|
||||||
|
"light": "Light",
|
||||||
|
"system": "System",
|
||||||
|
"title": "Theme"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"shortcut": {
|
"shortcut": {
|
||||||
"general": {
|
"general": {
|
||||||
@@ -596,7 +688,6 @@
|
|||||||
"title": "Others"
|
"title": "Others"
|
||||||
},
|
},
|
||||||
"request": {
|
"request": {
|
||||||
"copy_request_link": "Kopiér anmodningslink",
|
|
||||||
"delete_method": "Vælg SLET metode",
|
"delete_method": "Vælg SLET metode",
|
||||||
"get_method": "Vælg GET -metode",
|
"get_method": "Vælg GET -metode",
|
||||||
"head_method": "Vælg HEAD -metode",
|
"head_method": "Vælg HEAD -metode",
|
||||||
@@ -611,8 +702,10 @@
|
|||||||
"save_request": "Save Request",
|
"save_request": "Save Request",
|
||||||
"save_to_collections": "Gem i samlinger",
|
"save_to_collections": "Gem i samlinger",
|
||||||
"send_request": "Send anmodning",
|
"send_request": "Send anmodning",
|
||||||
|
"share_request": "Share Request",
|
||||||
"show_code": "Generate code snippet",
|
"show_code": "Generate code snippet",
|
||||||
"title": "Anmodning"
|
"title": "Anmodning",
|
||||||
|
"copy_request_link": "Kopiér anmodningslink"
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"copy": "Copy response to clipboard",
|
"copy": "Copy response to clipboard",
|
||||||
@@ -735,6 +828,7 @@
|
|||||||
"connection_error": "Failed to connect",
|
"connection_error": "Failed to connect",
|
||||||
"connection_failed": "Connection failed",
|
"connection_failed": "Connection failed",
|
||||||
"connection_lost": "Connection lost",
|
"connection_lost": "Connection lost",
|
||||||
|
"copied_interface_to_clipboard": "Copied {language} interface type to clipboard",
|
||||||
"copied_to_clipboard": "Kopieret til udklipsholder",
|
"copied_to_clipboard": "Kopieret til udklipsholder",
|
||||||
"deleted": "Slettet",
|
"deleted": "Slettet",
|
||||||
"deprecated": "DEPRECATED",
|
"deprecated": "DEPRECATED",
|
||||||
@@ -742,10 +836,12 @@
|
|||||||
"disconnected": "Afbrudt",
|
"disconnected": "Afbrudt",
|
||||||
"disconnected_from": "Koblet fra {name}",
|
"disconnected_from": "Koblet fra {name}",
|
||||||
"docs_generated": "Dokumentation genereret",
|
"docs_generated": "Dokumentation genereret",
|
||||||
|
"download_failed": "Download failed",
|
||||||
"download_started": "Downloaden er startet",
|
"download_started": "Downloaden er startet",
|
||||||
"enabled": "Aktiveret",
|
"enabled": "Aktiveret",
|
||||||
"file_imported": "Fil importeret",
|
"file_imported": "Fil importeret",
|
||||||
"finished_in": "Færdig om {duration} ms",
|
"finished_in": "Færdig om {duration} ms",
|
||||||
|
"hide": "Hide",
|
||||||
"history_deleted": "Historik slettet",
|
"history_deleted": "Historik slettet",
|
||||||
"linewrap": "Wrap linjer",
|
"linewrap": "Wrap linjer",
|
||||||
"loading": "Indlæser...",
|
"loading": "Indlæser...",
|
||||||
@@ -756,6 +852,7 @@
|
|||||||
"published_error": "Something went wrong while publishing msg: {topic} to topic: {message}",
|
"published_error": "Something went wrong while publishing msg: {topic} to topic: {message}",
|
||||||
"published_message": "Published message: {message} to topic: {topic}",
|
"published_message": "Published message: {message} to topic: {topic}",
|
||||||
"reconnection_error": "Failed to reconnect",
|
"reconnection_error": "Failed to reconnect",
|
||||||
|
"show": "Show",
|
||||||
"subscribed_failed": "Failed to subscribe to topic: {topic}",
|
"subscribed_failed": "Failed to subscribe to topic: {topic}",
|
||||||
"subscribed_success": "Successfully subscribed to topic: {topic}",
|
"subscribed_success": "Successfully subscribed to topic: {topic}",
|
||||||
"unsubscribed_failed": "Failed to unsubscribe from topic: {topic}",
|
"unsubscribed_failed": "Failed to unsubscribe from topic: {topic}",
|
||||||
@@ -791,6 +888,7 @@
|
|||||||
"queries": "Forespørgsler",
|
"queries": "Forespørgsler",
|
||||||
"query": "Forespørgsel",
|
"query": "Forespørgsel",
|
||||||
"schema": "Schema",
|
"schema": "Schema",
|
||||||
|
"shared_requests": "Shared Requests",
|
||||||
"socketio": "Socket.IO",
|
"socketio": "Socket.IO",
|
||||||
"sse": "SSE",
|
"sse": "SSE",
|
||||||
"tests": "Test",
|
"tests": "Test",
|
||||||
@@ -807,6 +905,7 @@
|
|||||||
"email_do_not_match": "Email doesn't match with your account details. Contact your team owner.",
|
"email_do_not_match": "Email doesn't match with your account details. Contact your team owner.",
|
||||||
"exit": "Afslut Team",
|
"exit": "Afslut Team",
|
||||||
"exit_disabled": "Kun ejeren kan ikke forlade teamet",
|
"exit_disabled": "Kun ejeren kan ikke forlade teamet",
|
||||||
|
"failed_invites": "Failed invites",
|
||||||
"invalid_coll_id": "Invalid collection ID",
|
"invalid_coll_id": "Invalid collection ID",
|
||||||
"invalid_email_format": "E -mailformatet er ugyldigt",
|
"invalid_email_format": "E -mailformatet er ugyldigt",
|
||||||
"invalid_id": "Invalid team ID. Contact your team owner.",
|
"invalid_id": "Invalid team ID. Contact your team owner.",
|
||||||
@@ -848,6 +947,7 @@
|
|||||||
"same_target_destination": "Same target and destination",
|
"same_target_destination": "Same target and destination",
|
||||||
"saved": "Hold reddet",
|
"saved": "Hold reddet",
|
||||||
"select_a_team": "Select a team",
|
"select_a_team": "Select a team",
|
||||||
|
"success_invites": "Success invites",
|
||||||
"title": "Hold",
|
"title": "Hold",
|
||||||
"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 team."
|
"we_sent_invite_link_description": "Ask all invitees to check their inbox. Click on the link to join the team."
|
||||||
@@ -879,5 +979,14 @@
|
|||||||
"personal": "My Workspace",
|
"personal": "My Workspace",
|
||||||
"team": "Team Workspace",
|
"team": "Team Workspace",
|
||||||
"title": "Workspaces"
|
"title": "Workspaces"
|
||||||
|
},
|
||||||
|
"shortcodes": {
|
||||||
|
"actions": "Actions",
|
||||||
|
"created_on": "Created on",
|
||||||
|
"deleted": "Shortcode deleted",
|
||||||
|
"method": "Method",
|
||||||
|
"not_found": "Shortcode not found",
|
||||||
|
"short_code": "Short code",
|
||||||
|
"url": "URL"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"action": {
|
"action": {
|
||||||
|
"add": "Add",
|
||||||
"autoscroll": "Autoscroll",
|
"autoscroll": "Autoscroll",
|
||||||
"cancel": "Abbrechen",
|
"cancel": "Abbrechen",
|
||||||
"choose_file": "Datei auswählen",
|
"choose_file": "Datei auswählen",
|
||||||
@@ -10,6 +11,7 @@
|
|||||||
"connect": "Verbinden",
|
"connect": "Verbinden",
|
||||||
"connecting": "Connecting",
|
"connecting": "Connecting",
|
||||||
"copy": "Kopieren",
|
"copy": "Kopieren",
|
||||||
|
"create": "Create",
|
||||||
"delete": "Löschen",
|
"delete": "Löschen",
|
||||||
"disconnect": "Trennen",
|
"disconnect": "Trennen",
|
||||||
"dismiss": "Verwerfen",
|
"dismiss": "Verwerfen",
|
||||||
@@ -31,6 +33,7 @@
|
|||||||
"open_workspace": "Open workspace",
|
"open_workspace": "Open workspace",
|
||||||
"paste": "Einfügen",
|
"paste": "Einfügen",
|
||||||
"prettify": "Verschönern",
|
"prettify": "Verschönern",
|
||||||
|
"properties": "Properties",
|
||||||
"remove": "Entfernen",
|
"remove": "Entfernen",
|
||||||
"rename": "Rename",
|
"rename": "Rename",
|
||||||
"restore": "Wiederherstellen",
|
"restore": "Wiederherstellen",
|
||||||
@@ -39,6 +42,7 @@
|
|||||||
"scroll_to_top": "Scroll to top",
|
"scroll_to_top": "Scroll to top",
|
||||||
"search": "Suchen",
|
"search": "Suchen",
|
||||||
"send": "Senden",
|
"send": "Senden",
|
||||||
|
"share": "Share",
|
||||||
"start": "Start",
|
"start": "Start",
|
||||||
"starting": "Starting",
|
"starting": "Starting",
|
||||||
"stop": "Stopp",
|
"stop": "Stopp",
|
||||||
@@ -57,7 +61,9 @@
|
|||||||
"app": {
|
"app": {
|
||||||
"chat_with_us": "Chatte mit uns",
|
"chat_with_us": "Chatte mit uns",
|
||||||
"contact_us": "Kontaktiere uns",
|
"contact_us": "Kontaktiere uns",
|
||||||
|
"cookies": "Cookies",
|
||||||
"copy": "Kopieren",
|
"copy": "Kopieren",
|
||||||
|
"copy_interface_type": "Copy interface type",
|
||||||
"copy_user_id": "Kopiere Nutzer-Authentisierungstoken",
|
"copy_user_id": "Kopiere Nutzer-Authentisierungstoken",
|
||||||
"developer_option": "Entwickleroptionen",
|
"developer_option": "Entwickleroptionen",
|
||||||
"developer_option_description": "Entwicklungswerkzeuge, die helfen Hoppscotch weiter zu entwickeln und zu warten.",
|
"developer_option_description": "Entwicklungswerkzeuge, die helfen Hoppscotch weiter zu entwickeln und zu warten.",
|
||||||
@@ -73,6 +79,7 @@
|
|||||||
"keyboard_shortcuts": "Tastaturkürzel",
|
"keyboard_shortcuts": "Tastaturkürzel",
|
||||||
"name": "Hoppscotch",
|
"name": "Hoppscotch",
|
||||||
"new_version_found": "Neue Version gefunden. Zum Aktualisieren Seite neu laden.",
|
"new_version_found": "Neue Version gefunden. Zum Aktualisieren Seite neu laden.",
|
||||||
|
"open_in_hoppscotch": "Open in Hoppscotch",
|
||||||
"options": "Options",
|
"options": "Options",
|
||||||
"proxy_privacy_policy": "Proxy-Datenschutzrichtlinie",
|
"proxy_privacy_policy": "Proxy-Datenschutzrichtlinie",
|
||||||
"reload": "Neu laden",
|
"reload": "Neu laden",
|
||||||
@@ -112,10 +119,27 @@
|
|||||||
},
|
},
|
||||||
"authorization": {
|
"authorization": {
|
||||||
"generate_token": "Token generieren",
|
"generate_token": "Token generieren",
|
||||||
|
"graphql_headers": "Authorization Headers are sent as part of the payload to connection_init",
|
||||||
"include_in_url": "In URL einbinden",
|
"include_in_url": "In URL einbinden",
|
||||||
|
"inherited_from": "Inherited from {auth} from Parent Collection {collection} ",
|
||||||
"learn": "Dokumentation",
|
"learn": "Dokumentation",
|
||||||
|
"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": "Übertragungsart",
|
"pass_key_by": "Übertragungsart",
|
||||||
"password": "Passwort",
|
"password": "Passwort",
|
||||||
|
"save_to_inherit": "Please save this request in any collection to inherit the authorization",
|
||||||
"token": "Token",
|
"token": "Token",
|
||||||
"type": "Autorisierungsverfahren",
|
"type": "Autorisierungsverfahren",
|
||||||
"username": "Nutzername"
|
"username": "Nutzername"
|
||||||
@@ -124,6 +148,7 @@
|
|||||||
"created": "Sammlung erstellt",
|
"created": "Sammlung erstellt",
|
||||||
"different_parent": "Cannot reorder collection with different parent",
|
"different_parent": "Cannot reorder collection with different parent",
|
||||||
"edit": "Sammlung bearbeiten",
|
"edit": "Sammlung bearbeiten",
|
||||||
|
"import_or_create": "Import or create a collection",
|
||||||
"invalid_name": "Bitte gib einen gültigen Namen für die Sammlung an",
|
"invalid_name": "Bitte gib einen gültigen Namen für die Sammlung an",
|
||||||
"invalid_root_move": "Collection already in the root",
|
"invalid_root_move": "Collection already in the root",
|
||||||
"moved": "Moved Successfully",
|
"moved": "Moved Successfully",
|
||||||
@@ -132,6 +157,8 @@
|
|||||||
"name_length_insufficient": "Sammlungsname soll mindestens 3 Zeichen lang sein",
|
"name_length_insufficient": "Sammlungsname soll mindestens 3 Zeichen lang sein",
|
||||||
"new": "Neue Sammlung",
|
"new": "Neue Sammlung",
|
||||||
"order_changed": "Collection Order Updated",
|
"order_changed": "Collection Order Updated",
|
||||||
|
"properties": "Collection Properties",
|
||||||
|
"properties_updated": "Collection Properties Updated",
|
||||||
"renamed": "Sammlung umbenannt",
|
"renamed": "Sammlung umbenannt",
|
||||||
"request_in_use": "Anfrage wird ausgeführt",
|
"request_in_use": "Anfrage wird ausgeführt",
|
||||||
"save_as": "Speichern als",
|
"save_as": "Speichern als",
|
||||||
@@ -151,6 +178,7 @@
|
|||||||
"remove_folder": "Möchtest Du diesen Ordner wirklich dauerhaft löschen?",
|
"remove_folder": "Möchtest Du diesen Ordner wirklich dauerhaft löschen?",
|
||||||
"remove_history": "Möchtest Du wirklich den gesamten Verlauf dauerhaft löschen?",
|
"remove_history": "Möchtest Du wirklich den gesamten Verlauf dauerhaft löschen?",
|
||||||
"remove_request": "Möchtest Du diese Anfrage wirklich dauerhaft löschen?",
|
"remove_request": "Möchtest Du diese Anfrage wirklich dauerhaft löschen?",
|
||||||
|
"remove_shared_request": "Are you sure you want to permanently delete this shared request?",
|
||||||
"remove_team": "Möchtest Du dieses Team wirklich löschen?",
|
"remove_team": "Möchtest Du dieses Team wirklich löschen?",
|
||||||
"remove_telemetry": "Möchtest Du die Telemetrie wirklich deaktivieren?",
|
"remove_telemetry": "Möchtest Du die Telemetrie wirklich deaktivieren?",
|
||||||
"request_change": "Möchtest Du diese Anfrage verwerfen? Ungespeicherte Änderungen gehen verloren.",
|
"request_change": "Möchtest Du diese Anfrage verwerfen? Ungespeicherte Änderungen gehen verloren.",
|
||||||
@@ -162,6 +190,24 @@
|
|||||||
"open_request_in_new_tab": "Open request in new tab",
|
"open_request_in_new_tab": "Open request in new tab",
|
||||||
"set_environment_variable": "Set as variable"
|
"set_environment_variable": "Set as variable"
|
||||||
},
|
},
|
||||||
|
"cookies": {
|
||||||
|
"modal": {
|
||||||
|
"cookie_expires": "Expires",
|
||||||
|
"cookie_name": "Name",
|
||||||
|
"cookie_path": "Path",
|
||||||
|
"cookie_string": "Cookie string",
|
||||||
|
"cookie_value": "Value",
|
||||||
|
"empty_domain": "Domain is empty",
|
||||||
|
"empty_domains": "Domain list is empty",
|
||||||
|
"enter_cookie_string": "Enter cookie string",
|
||||||
|
"interceptor_no_support": "Your currently selected interceptor does not support cookies. Select a different Interceptor and try again.",
|
||||||
|
"managed_tab": "Managed",
|
||||||
|
"new_domain_name": "New domain name",
|
||||||
|
"no_cookies_in_domain": "No cookies set for this domain",
|
||||||
|
"raw_tab": "Raw",
|
||||||
|
"set": "Set a cookie"
|
||||||
|
}
|
||||||
|
},
|
||||||
"count": {
|
"count": {
|
||||||
"header": "Header {count}",
|
"header": "Header {count}",
|
||||||
"message": "Nachricht {count}",
|
"message": "Nachricht {count}",
|
||||||
@@ -192,11 +238,13 @@
|
|||||||
"profile": "Einloggen um das Profil anzusehen",
|
"profile": "Einloggen um das Profil anzusehen",
|
||||||
"protocols": "Protokolle sind leer",
|
"protocols": "Protokolle sind leer",
|
||||||
"schema": "Verbinden mit einem GraphQL-Endpunkt",
|
"schema": "Verbinden mit einem GraphQL-Endpunkt",
|
||||||
"shortcodes": "Shortcodes are empty",
|
"shared_requests": "Shared requests are empty",
|
||||||
|
"shared_requests_logout": "Login to view your shared requests or create a new one",
|
||||||
"subscription": "Subscriptions are empty",
|
"subscription": "Subscriptions are empty",
|
||||||
"team_name": "Teamname leer",
|
"team_name": "Teamname leer",
|
||||||
"teams": "Teams sind leer",
|
"teams": "Teams sind leer",
|
||||||
"tests": "Es gibt keine Tests für diese Anfrage"
|
"tests": "Es gibt keine Tests für diese Anfrage",
|
||||||
|
"shortcodes": "Shortcodes are empty"
|
||||||
},
|
},
|
||||||
"environment": {
|
"environment": {
|
||||||
"add_to_global": "Zur Globalen Umgebung hinzufügen",
|
"add_to_global": "Zur Globalen Umgebung hinzufügen",
|
||||||
@@ -209,6 +257,7 @@
|
|||||||
"empty_variables": "No variables",
|
"empty_variables": "No variables",
|
||||||
"global": "Global",
|
"global": "Global",
|
||||||
"global_variables": "Global variables",
|
"global_variables": "Global variables",
|
||||||
|
"import_or_create": "Import or create a environment",
|
||||||
"invalid_name": "Bitte gib einen gültigen Namen für die Umgebung an",
|
"invalid_name": "Bitte gib einen gültigen Namen für die Umgebung an",
|
||||||
"list": "Environment variables",
|
"list": "Environment variables",
|
||||||
"my_environments": "My Environments",
|
"my_environments": "My Environments",
|
||||||
@@ -232,8 +281,10 @@
|
|||||||
"variable_list": "Variablenliste"
|
"variable_list": "Variablenliste"
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
|
"authproviders_load_error": "Unable to load auth providers",
|
||||||
"browser_support_sse": "Dieser Browser scheint keine Unterstützung für die vom Server gesendete Ereignisse zu haben.",
|
"browser_support_sse": "Dieser Browser scheint keine Unterstützung für die vom Server gesendete Ereignisse zu haben.",
|
||||||
"check_console_details": "Einzelheiten findest Du in der Browser-Konsole.",
|
"check_console_details": "Einzelheiten findest Du in der Browser-Konsole.",
|
||||||
|
"check_how_to_add_origin": "Check how you can add an origin",
|
||||||
"curl_invalid_format": "cURL ist nicht richtig formatiert",
|
"curl_invalid_format": "cURL ist nicht richtig formatiert",
|
||||||
"danger_zone": "Danger zone",
|
"danger_zone": "Danger zone",
|
||||||
"delete_account": "Your account is currently an owner in these teams:",
|
"delete_account": "Your account is currently an owner in these teams:",
|
||||||
@@ -249,9 +300,12 @@
|
|||||||
"json_prettify_invalid_body": "Ein ungültiger Text konnte nicht verschönert werden, JSON-Syntaxfehler beheben und erneut versuchen",
|
"json_prettify_invalid_body": "Ein ungültiger Text konnte nicht verschönert werden, JSON-Syntaxfehler beheben und erneut versuchen",
|
||||||
"network_error": "Netzwerkfehler. Bitte versuche es erneut.",
|
"network_error": "Netzwerkfehler. Bitte versuche es erneut.",
|
||||||
"network_fail": "Anfrage konnte nicht gesendet werden",
|
"network_fail": "Anfrage konnte nicht gesendet werden",
|
||||||
|
"no_collections_to_export": "No collections to export. Please create a collection to get started.",
|
||||||
"no_duration": "Keine Dauer",
|
"no_duration": "Keine Dauer",
|
||||||
|
"no_environments_to_export": "No environments to export. Please create an environment to get started.",
|
||||||
"no_results_found": "No matches found",
|
"no_results_found": "No matches found",
|
||||||
"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.",
|
||||||
"proxy_error": "Proxy error",
|
"proxy_error": "Proxy error",
|
||||||
"script_fail": "Pre-Request-Skripte konnte nicht ausgeführt werden",
|
"script_fail": "Pre-Request-Skripte konnte nicht ausgeführt werden",
|
||||||
"something_went_wrong": "Etwas ist schief gelaufen",
|
"something_went_wrong": "Etwas ist schief gelaufen",
|
||||||
@@ -260,6 +314,7 @@
|
|||||||
"export": {
|
"export": {
|
||||||
"as_json": "Als JSON exportieren",
|
"as_json": "Als JSON exportieren",
|
||||||
"create_secret_gist": "Geheimen Github Gist erstellen",
|
"create_secret_gist": "Geheimen Github Gist erstellen",
|
||||||
|
"failed": "Something went wrong while exporting",
|
||||||
"gist_created": "Gist erstellt",
|
"gist_created": "Gist erstellt",
|
||||||
"require_github": "Melde Dich bei GitHub an, um einen geheimen Gist zu erstellen",
|
"require_github": "Melde Dich bei GitHub an, um einen geheimen Gist zu erstellen",
|
||||||
"title": "Export"
|
"title": "Export"
|
||||||
@@ -286,6 +341,9 @@
|
|||||||
"subscriptions": "Abonnements",
|
"subscriptions": "Abonnements",
|
||||||
"switch_connection": "Switch connection"
|
"switch_connection": "Switch connection"
|
||||||
},
|
},
|
||||||
|
"graphql_collections": {
|
||||||
|
"title": "GraphQL Collections"
|
||||||
|
},
|
||||||
"group": {
|
"group": {
|
||||||
"time": "Time",
|
"time": "Time",
|
||||||
"url": "URL"
|
"url": "URL"
|
||||||
@@ -297,6 +355,8 @@
|
|||||||
},
|
},
|
||||||
"helpers": {
|
"helpers": {
|
||||||
"authorization": "Der Autorisierungsheader wird automatisch generiert, wenn Du die Anfrage sendest.",
|
"authorization": "Der Autorisierungsheader wird automatisch generiert, wenn Du die Anfrage sendest.",
|
||||||
|
"collection_properties_authorization": " This authorization will be set for every request in this collection.",
|
||||||
|
"collection_properties_header": "This header will be set for every request in this collection.",
|
||||||
"generate_documentation_first": "Zuerst Dokumentation erstellen",
|
"generate_documentation_first": "Zuerst Dokumentation erstellen",
|
||||||
"network_fail": "Der API-Endpunkt kann nicht erreicht werden. Überprüfe Deine Netzwerkverbindung und versuche es erneut.",
|
"network_fail": "Der API-Endpunkt kann nicht erreicht werden. Überprüfe Deine Netzwerkverbindung und versuche es erneut.",
|
||||||
"offline": "Du scheinst offline zu sein. Die Daten in diesem Arbeitsbereich sind möglicherweise nicht aktuell.",
|
"offline": "Du scheinst offline zu sein. Die Daten in diesem Arbeitsbereich sind möglicherweise nicht aktuell.",
|
||||||
@@ -316,7 +376,10 @@
|
|||||||
"import": {
|
"import": {
|
||||||
"collections": "Sammlungen importieren",
|
"collections": "Sammlungen importieren",
|
||||||
"curl": "cURL importieren",
|
"curl": "cURL importieren",
|
||||||
|
"environments_from_gist": "Import From Gist",
|
||||||
|
"environments_from_gist_description": "Import Hoppscotch Environments From Gist",
|
||||||
"failed": "Importieren fehlgeschlagen",
|
"failed": "Importieren fehlgeschlagen",
|
||||||
|
"from_file": "Import from File",
|
||||||
"from_gist": "Von Github Gist importieren",
|
"from_gist": "Von Github Gist importieren",
|
||||||
"from_gist_description": "Von Github Gist URL importieren",
|
"from_gist_description": "Von Github Gist URL importieren",
|
||||||
"from_insomnia": "Von Insomnia importieren",
|
"from_insomnia": "Von Insomnia importieren",
|
||||||
@@ -331,11 +394,17 @@
|
|||||||
"from_postman_description": "Postman-Sammlung importieren",
|
"from_postman_description": "Postman-Sammlung importieren",
|
||||||
"from_url": "Von URL importieren",
|
"from_url": "Von URL importieren",
|
||||||
"gist_url": "Gist-URL eingeben",
|
"gist_url": "Gist-URL eingeben",
|
||||||
|
"gql_collections_from_gist_description": "Import GraphQL Collections From Gist",
|
||||||
|
"hoppscotch_environment": "Hoppscotch Environment",
|
||||||
|
"hoppscotch_environment_description": "Import Hoppscotch Environment JSON file",
|
||||||
"import_from_url_invalid_fetch": "Couldn't get data from the url",
|
"import_from_url_invalid_fetch": "Couldn't get data from the url",
|
||||||
"import_from_url_invalid_file_format": "Error while importing collections",
|
"import_from_url_invalid_file_format": "Error while importing collections",
|
||||||
"import_from_url_invalid_type": "Unsupported type. accepted values are 'hoppscotch', 'openapi', 'postman', 'insomnia'",
|
"import_from_url_invalid_type": "Unsupported type. accepted values are 'hoppscotch', 'openapi', 'postman', 'insomnia'",
|
||||||
"import_from_url_success": "Collections Imported",
|
"import_from_url_success": "Collections Imported",
|
||||||
|
"insomnia_environment_description": "Import Insomnia Environment from a JSON/YAML file",
|
||||||
"json_description": "Hoppscotch Sammlungsdatei (JSON) importieren",
|
"json_description": "Hoppscotch Sammlungsdatei (JSON) importieren",
|
||||||
|
"postman_environment": "Postman Environment",
|
||||||
|
"postman_environment_description": "Import Postman Environment from a JSON file",
|
||||||
"title": "Importieren"
|
"title": "Importieren"
|
||||||
},
|
},
|
||||||
"inspections": {
|
"inspections": {
|
||||||
@@ -373,8 +442,10 @@
|
|||||||
"close_unsaved_tab": "You have unsaved changes",
|
"close_unsaved_tab": "You have unsaved changes",
|
||||||
"collections": "Sammlungen",
|
"collections": "Sammlungen",
|
||||||
"confirm": "Aktion bestätigen",
|
"confirm": "Aktion bestätigen",
|
||||||
|
"customize_request": "Customize Request",
|
||||||
"edit_request": "Anfrage bearbeiten",
|
"edit_request": "Anfrage bearbeiten",
|
||||||
"import_export": "Import / Export"
|
"import_export": "Import / Export",
|
||||||
|
"share_request": "Share Request"
|
||||||
},
|
},
|
||||||
"mqtt": {
|
"mqtt": {
|
||||||
"already_subscribed": "You are already subscribed to this topic.",
|
"already_subscribed": "You are already subscribed to this topic.",
|
||||||
@@ -449,13 +520,14 @@
|
|||||||
"structured": "Structured",
|
"structured": "Structured",
|
||||||
"text": "Text"
|
"text": "Text"
|
||||||
},
|
},
|
||||||
"copy_link": "Link kopieren",
|
|
||||||
"different_collection": "Cannot reorder requests from different collections",
|
"different_collection": "Cannot reorder requests from different collections",
|
||||||
"duplicated": "Request duplicated",
|
"duplicated": "Request duplicated",
|
||||||
"duration": "Dauer",
|
"duration": "Dauer",
|
||||||
"enter_curl": "cURL eingeben",
|
"enter_curl": "cURL eingeben",
|
||||||
"generate_code": "Code generieren",
|
"generate_code": "Code generieren",
|
||||||
"generated_code": "Generierter Code",
|
"generated_code": "Generierter Code",
|
||||||
|
"go_to_authorization_tab": "Go to Authorization tab",
|
||||||
|
"go_to_body_tab": "Go to Body tab",
|
||||||
"header_list": "Header-Liste",
|
"header_list": "Header-Liste",
|
||||||
"invalid_name": "Bitte gib einen Namen für die Anfrage an",
|
"invalid_name": "Bitte gib einen Namen für die Anfrage an",
|
||||||
"method": "Methode",
|
"method": "Methode",
|
||||||
@@ -480,12 +552,14 @@
|
|||||||
"saved": "Anfrage gespeichert",
|
"saved": "Anfrage gespeichert",
|
||||||
"share": "Teilen",
|
"share": "Teilen",
|
||||||
"share_description": "Teile Hoppscotch mit Deinen Freunden",
|
"share_description": "Teile Hoppscotch mit Deinen Freunden",
|
||||||
|
"share_request": "Share Request",
|
||||||
"stop": "Stop",
|
"stop": "Stop",
|
||||||
"title": "Anfrage",
|
"title": "Anfrage",
|
||||||
"type": "Anfragetyp",
|
"type": "Anfragetyp",
|
||||||
"url": "URL",
|
"url": "URL",
|
||||||
"variables": "Variablen",
|
"variables": "Variablen",
|
||||||
"view_my_links": "View my links"
|
"view_my_links": "View my links",
|
||||||
|
"copy_link": "Link kopieren"
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"audio": "Audio",
|
"audio": "Audio",
|
||||||
@@ -513,6 +587,7 @@
|
|||||||
"account_description": "Passe Deine Kontoeinstellungen an.",
|
"account_description": "Passe Deine Kontoeinstellungen an.",
|
||||||
"account_email_description": "Deine primäre E-Mail-Adresse.",
|
"account_email_description": "Deine primäre E-Mail-Adresse.",
|
||||||
"account_name_description": "Dies ist Dein Anzeigename.",
|
"account_name_description": "Dies ist Dein Anzeigename.",
|
||||||
|
"additional": "Additional Settings",
|
||||||
"background": "Hintergrund",
|
"background": "Hintergrund",
|
||||||
"black_mode": "Schwarz",
|
"black_mode": "Schwarz",
|
||||||
"choose_language": "Sprache wählen",
|
"choose_language": "Sprache wählen",
|
||||||
@@ -559,14 +634,31 @@
|
|||||||
"verified_email": "Verified email",
|
"verified_email": "Verified email",
|
||||||
"verify_email": "E-Mail-Adresse bestätigen"
|
"verify_email": "E-Mail-Adresse bestätigen"
|
||||||
},
|
},
|
||||||
"shortcodes": {
|
"shared_requests": {
|
||||||
"actions": "Actions",
|
"button": "Button",
|
||||||
"created_on": "Created on",
|
"button_info": "Create a 'Run in Hoppscotch' button for your website, blog or a README.",
|
||||||
"deleted": "Shortcode deleted",
|
"copy_html": "Copy HTML",
|
||||||
"method": "Method",
|
"copy_link": "Copy Link",
|
||||||
"not_found": "Shortcode not found",
|
"copy_markdown": "Copy Markdown",
|
||||||
"short_code": "Short code",
|
"creating_widget": "Creating widget",
|
||||||
"url": "URL"
|
"customize": "Customize",
|
||||||
|
"deleted": "Shared request deleted",
|
||||||
|
"description": "Select a widget, you can change and customize this later",
|
||||||
|
"embed": "Embed",
|
||||||
|
"embed_info": "Add a mini 'Hoppscotch API Playground' to your website, blog or documentation.",
|
||||||
|
"link": "Link",
|
||||||
|
"link_info": "Create a shareable link to share with anyone on the internet with view access.",
|
||||||
|
"modified": "Shared request modified",
|
||||||
|
"not_found": "Shared request not found",
|
||||||
|
"open_new_tab": "Open in new tab",
|
||||||
|
"preview": "Preview",
|
||||||
|
"run_in_hoppscotch": "Run in Hoppscotch",
|
||||||
|
"theme": {
|
||||||
|
"dark": "Dark",
|
||||||
|
"light": "Light",
|
||||||
|
"system": "System",
|
||||||
|
"title": "Theme"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"shortcut": {
|
"shortcut": {
|
||||||
"general": {
|
"general": {
|
||||||
@@ -596,7 +688,6 @@
|
|||||||
"title": "Others"
|
"title": "Others"
|
||||||
},
|
},
|
||||||
"request": {
|
"request": {
|
||||||
"copy_request_link": "Anfragelink kopieren",
|
|
||||||
"delete_method": "DELETE-Methode auswählen",
|
"delete_method": "DELETE-Methode auswählen",
|
||||||
"get_method": "GET-Methode auswählen",
|
"get_method": "GET-Methode auswählen",
|
||||||
"head_method": "HEAD-Methode auswählen",
|
"head_method": "HEAD-Methode auswählen",
|
||||||
@@ -611,8 +702,10 @@
|
|||||||
"save_request": "Save Request",
|
"save_request": "Save Request",
|
||||||
"save_to_collections": "In Sammlungen speichern",
|
"save_to_collections": "In Sammlungen speichern",
|
||||||
"send_request": "Anfrage senden",
|
"send_request": "Anfrage senden",
|
||||||
|
"share_request": "Share Request",
|
||||||
"show_code": "Generate code snippet",
|
"show_code": "Generate code snippet",
|
||||||
"title": "Anfrage"
|
"title": "Anfrage",
|
||||||
|
"copy_request_link": "Anfragelink kopieren"
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"copy": "Copy response to clipboard",
|
"copy": "Copy response to clipboard",
|
||||||
@@ -735,6 +828,7 @@
|
|||||||
"connection_error": "Failed to connect",
|
"connection_error": "Failed to connect",
|
||||||
"connection_failed": "Connection failed",
|
"connection_failed": "Connection failed",
|
||||||
"connection_lost": "Connection lost",
|
"connection_lost": "Connection lost",
|
||||||
|
"copied_interface_to_clipboard": "Copied {language} interface type to clipboard",
|
||||||
"copied_to_clipboard": "In die Zwischenablage kopiert",
|
"copied_to_clipboard": "In die Zwischenablage kopiert",
|
||||||
"deleted": "Gelöscht",
|
"deleted": "Gelöscht",
|
||||||
"deprecated": "VERALTET",
|
"deprecated": "VERALTET",
|
||||||
@@ -742,10 +836,12 @@
|
|||||||
"disconnected": "Getrennt",
|
"disconnected": "Getrennt",
|
||||||
"disconnected_from": "Verbindung zu {name} getrennt",
|
"disconnected_from": "Verbindung zu {name} getrennt",
|
||||||
"docs_generated": "Dokumentation erstellt",
|
"docs_generated": "Dokumentation erstellt",
|
||||||
|
"download_failed": "Download failed",
|
||||||
"download_started": "Download gestartet",
|
"download_started": "Download gestartet",
|
||||||
"enabled": "Aktiviert",
|
"enabled": "Aktiviert",
|
||||||
"file_imported": "Datei importiert",
|
"file_imported": "Datei importiert",
|
||||||
"finished_in": "Fertig in {duration} ms",
|
"finished_in": "Fertig in {duration} ms",
|
||||||
|
"hide": "Hide",
|
||||||
"history_deleted": "Verlauf gelöscht",
|
"history_deleted": "Verlauf gelöscht",
|
||||||
"linewrap": "Zeilen umbrechen",
|
"linewrap": "Zeilen umbrechen",
|
||||||
"loading": "Wird geladen...",
|
"loading": "Wird geladen...",
|
||||||
@@ -756,6 +852,7 @@
|
|||||||
"published_error": "Something went wrong while publishing msg: {topic} to topic: {message}",
|
"published_error": "Something went wrong while publishing msg: {topic} to topic: {message}",
|
||||||
"published_message": "Published message: {message} to topic: {topic}",
|
"published_message": "Published message: {message} to topic: {topic}",
|
||||||
"reconnection_error": "Failed to reconnect",
|
"reconnection_error": "Failed to reconnect",
|
||||||
|
"show": "Show",
|
||||||
"subscribed_failed": "Failed to subscribe to topic: {topic}",
|
"subscribed_failed": "Failed to subscribe to topic: {topic}",
|
||||||
"subscribed_success": "Successfully subscribed to topic: {topic}",
|
"subscribed_success": "Successfully subscribed to topic: {topic}",
|
||||||
"unsubscribed_failed": "Failed to unsubscribe from topic: {topic}",
|
"unsubscribed_failed": "Failed to unsubscribe from topic: {topic}",
|
||||||
@@ -791,6 +888,7 @@
|
|||||||
"queries": "Anfragen",
|
"queries": "Anfragen",
|
||||||
"query": "Anfrage",
|
"query": "Anfrage",
|
||||||
"schema": "Schema",
|
"schema": "Schema",
|
||||||
|
"shared_requests": "Shared Requests",
|
||||||
"socketio": "Socket.IO",
|
"socketio": "Socket.IO",
|
||||||
"sse": "SSE",
|
"sse": "SSE",
|
||||||
"tests": "Tests",
|
"tests": "Tests",
|
||||||
@@ -807,6 +905,7 @@
|
|||||||
"email_do_not_match": "E-Mail-Adresse stimmt nicht mit Deinen Kontodaten überein, bitte kontaktiere den Teameigentümer.",
|
"email_do_not_match": "E-Mail-Adresse stimmt nicht mit Deinen Kontodaten überein, bitte kontaktiere den Teameigentümer.",
|
||||||
"exit": "Team verlassen",
|
"exit": "Team verlassen",
|
||||||
"exit_disabled": "Eigentümer können das Team nicht verlassen",
|
"exit_disabled": "Eigentümer können das Team nicht verlassen",
|
||||||
|
"failed_invites": "Failed invites",
|
||||||
"invalid_coll_id": "Invalid collection ID",
|
"invalid_coll_id": "Invalid collection ID",
|
||||||
"invalid_email_format": "E-Mail-Format ist ungültig",
|
"invalid_email_format": "E-Mail-Format ist ungültig",
|
||||||
"invalid_id": "Ungültige Team-ID, bitte kontaktiere den Teameigentümer.",
|
"invalid_id": "Ungültige Team-ID, bitte kontaktiere den Teameigentümer.",
|
||||||
@@ -848,6 +947,7 @@
|
|||||||
"same_target_destination": "Same target and destination",
|
"same_target_destination": "Same target and destination",
|
||||||
"saved": "Team gespeichert",
|
"saved": "Team gespeichert",
|
||||||
"select_a_team": "Team auswählen",
|
"select_a_team": "Team auswählen",
|
||||||
|
"success_invites": "Success invites",
|
||||||
"title": "Team",
|
"title": "Team",
|
||||||
"we_sent_invite_link": "Einladungen wurden an alle E-Mails verschickt!",
|
"we_sent_invite_link": "Einladungen wurden an alle E-Mails verschickt!",
|
||||||
"we_sent_invite_link_description": "Bitte alle eingeladenen Personen, ihren Posteingang zu überprüfen. Klicke auf den Link, um dem Team beizutreten."
|
"we_sent_invite_link_description": "Bitte alle eingeladenen Personen, ihren Posteingang zu überprüfen. Klicke auf den Link, um dem Team beizutreten."
|
||||||
@@ -879,5 +979,14 @@
|
|||||||
"personal": "My Workspace",
|
"personal": "My Workspace",
|
||||||
"team": "Team Workspace",
|
"team": "Team Workspace",
|
||||||
"title": "Workspaces"
|
"title": "Workspaces"
|
||||||
|
},
|
||||||
|
"shortcodes": {
|
||||||
|
"actions": "Actions",
|
||||||
|
"created_on": "Created on",
|
||||||
|
"deleted": "Shortcode deleted",
|
||||||
|
"method": "Method",
|
||||||
|
"not_found": "Shortcode not found",
|
||||||
|
"short_code": "Short code",
|
||||||
|
"url": "URL"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"action": {
|
"action": {
|
||||||
|
"add": "Add",
|
||||||
"autoscroll": "Autoscroll",
|
"autoscroll": "Autoscroll",
|
||||||
"cancel": "Ματαίωση",
|
"cancel": "Ματαίωση",
|
||||||
"choose_file": "Επιλέξτε ένα αρχείο",
|
"choose_file": "Επιλέξτε ένα αρχείο",
|
||||||
@@ -10,6 +11,7 @@
|
|||||||
"connect": "Συνδέω-συωδεομαι",
|
"connect": "Συνδέω-συωδεομαι",
|
||||||
"connecting": "Connecting",
|
"connecting": "Connecting",
|
||||||
"copy": "αντίγραφο",
|
"copy": "αντίγραφο",
|
||||||
|
"create": "Create",
|
||||||
"delete": "Διαγράφω",
|
"delete": "Διαγράφω",
|
||||||
"disconnect": "Αποσυνδέω",
|
"disconnect": "Αποσυνδέω",
|
||||||
"dismiss": "Απολύω",
|
"dismiss": "Απολύω",
|
||||||
@@ -31,6 +33,7 @@
|
|||||||
"open_workspace": "Open workspace",
|
"open_workspace": "Open workspace",
|
||||||
"paste": "Paste",
|
"paste": "Paste",
|
||||||
"prettify": "Ωραιοποιώ",
|
"prettify": "Ωραιοποιώ",
|
||||||
|
"properties": "Properties",
|
||||||
"remove": "Αφαιρώ",
|
"remove": "Αφαιρώ",
|
||||||
"rename": "Rename",
|
"rename": "Rename",
|
||||||
"restore": "Επαναφέρω",
|
"restore": "Επαναφέρω",
|
||||||
@@ -39,6 +42,7 @@
|
|||||||
"scroll_to_top": "Scroll to top",
|
"scroll_to_top": "Scroll to top",
|
||||||
"search": "Αναζήτηση",
|
"search": "Αναζήτηση",
|
||||||
"send": "Στείλετε",
|
"send": "Στείλετε",
|
||||||
|
"share": "Share",
|
||||||
"start": "Αρχή",
|
"start": "Αρχή",
|
||||||
"starting": "Starting",
|
"starting": "Starting",
|
||||||
"stop": "Να σταματήσει",
|
"stop": "Να σταματήσει",
|
||||||
@@ -57,7 +61,9 @@
|
|||||||
"app": {
|
"app": {
|
||||||
"chat_with_us": "μίλα μαζί μας",
|
"chat_with_us": "μίλα μαζί μας",
|
||||||
"contact_us": "Επικοινωνήστε μαζί μας",
|
"contact_us": "Επικοινωνήστε μαζί μας",
|
||||||
|
"cookies": "Cookies",
|
||||||
"copy": "αντίγραφο",
|
"copy": "αντίγραφο",
|
||||||
|
"copy_interface_type": "Copy interface type",
|
||||||
"copy_user_id": "Copy User Auth Token",
|
"copy_user_id": "Copy User Auth Token",
|
||||||
"developer_option": "Developer options",
|
"developer_option": "Developer options",
|
||||||
"developer_option_description": "Εργαλεία για προγραμματιστές που βοηθάνε στην ανάπτυξη και συντήρηση του Hoppscotch.",
|
"developer_option_description": "Εργαλεία για προγραμματιστές που βοηθάνε στην ανάπτυξη και συντήρηση του Hoppscotch.",
|
||||||
@@ -73,6 +79,7 @@
|
|||||||
"keyboard_shortcuts": "Συντομεύσεις πληκτρολογίου",
|
"keyboard_shortcuts": "Συντομεύσεις πληκτρολογίου",
|
||||||
"name": "Hoppscotch",
|
"name": "Hoppscotch",
|
||||||
"new_version_found": "Βρέθηκε νέα έκδοση. Ανανέωση για ενημέρωση.",
|
"new_version_found": "Βρέθηκε νέα έκδοση. Ανανέωση για ενημέρωση.",
|
||||||
|
"open_in_hoppscotch": "Open in Hoppscotch",
|
||||||
"options": "Options",
|
"options": "Options",
|
||||||
"proxy_privacy_policy": "Πολιτική απορρήτου μεσολάβησης",
|
"proxy_privacy_policy": "Πολιτική απορρήτου μεσολάβησης",
|
||||||
"reload": "Φορτώνω πάλι",
|
"reload": "Φορτώνω πάλι",
|
||||||
@@ -112,10 +119,27 @@
|
|||||||
},
|
},
|
||||||
"authorization": {
|
"authorization": {
|
||||||
"generate_token": "Δημιουργήστε το διακριτικό",
|
"generate_token": "Δημιουργήστε το διακριτικό",
|
||||||
|
"graphql_headers": "Authorization Headers are sent as part of the payload to connection_init",
|
||||||
"include_in_url": "Συμπερίληψη στη διεύθυνση URL",
|
"include_in_url": "Συμπερίληψη στη διεύθυνση URL",
|
||||||
|
"inherited_from": "Inherited from {auth} from Parent Collection {collection} ",
|
||||||
"learn": "Μάθε πως",
|
"learn": "Μάθε πως",
|
||||||
|
"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": "Κωδικός πρόσβασης",
|
"password": "Κωδικός πρόσβασης",
|
||||||
|
"save_to_inherit": "Please save this request in any collection to inherit the authorization",
|
||||||
"token": "Ενδειξη",
|
"token": "Ενδειξη",
|
||||||
"type": "Τύπος εξουσιοδότησης",
|
"type": "Τύπος εξουσιοδότησης",
|
||||||
"username": "Όνομα χρήστη"
|
"username": "Όνομα χρήστη"
|
||||||
@@ -124,6 +148,7 @@
|
|||||||
"created": "Η συλλογή δημιουργήθηκε",
|
"created": "Η συλλογή δημιουργήθηκε",
|
||||||
"different_parent": "Cannot reorder collection with different parent",
|
"different_parent": "Cannot reorder collection with different parent",
|
||||||
"edit": "Επεξεργασία Συλλογής",
|
"edit": "Επεξεργασία Συλλογής",
|
||||||
|
"import_or_create": "Import or create a collection",
|
||||||
"invalid_name": "Καταχωρίστε ένα έγκυρο όνομα για τη συλλογή",
|
"invalid_name": "Καταχωρίστε ένα έγκυρο όνομα για τη συλλογή",
|
||||||
"invalid_root_move": "Collection already in the root",
|
"invalid_root_move": "Collection already in the root",
|
||||||
"moved": "Moved Successfully",
|
"moved": "Moved Successfully",
|
||||||
@@ -132,6 +157,8 @@
|
|||||||
"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": "Νέα συλλογή",
|
||||||
"order_changed": "Collection Order Updated",
|
"order_changed": "Collection Order Updated",
|
||||||
|
"properties": "Collection Properties",
|
||||||
|
"properties_updated": "Collection Properties Updated",
|
||||||
"renamed": "Η συλλογή μετονομάστηκε",
|
"renamed": "Η συλλογή μετονομάστηκε",
|
||||||
"request_in_use": "Request in use",
|
"request_in_use": "Request in use",
|
||||||
"save_as": "Αποθήκευση ως",
|
"save_as": "Αποθήκευση ως",
|
||||||
@@ -151,6 +178,7 @@
|
|||||||
"remove_folder": "Είστε βέβαιοι ότι θέλετε να διαγράψετε οριστικά αυτόν τον φάκελο;",
|
"remove_folder": "Είστε βέβαιοι ότι θέλετε να διαγράψετε οριστικά αυτόν τον φάκελο;",
|
||||||
"remove_history": "Είστε βέβαιοι ότι θέλετε να διαγράψετε οριστικά όλο το ιστορικό;",
|
"remove_history": "Είστε βέβαιοι ότι θέλετε να διαγράψετε οριστικά όλο το ιστορικό;",
|
||||||
"remove_request": "Είστε βέβαιοι ότι θέλετε να διαγράψετε οριστικά αυτό το αίτημα;",
|
"remove_request": "Είστε βέβαιοι ότι θέλετε να διαγράψετε οριστικά αυτό το αίτημα;",
|
||||||
|
"remove_shared_request": "Are you sure you want to permanently delete this shared request?",
|
||||||
"remove_team": "Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτήν την ομάδα;",
|
"remove_team": "Είστε βέβαιοι ότι θέλετε να διαγράψετε αυτήν την ομάδα;",
|
||||||
"remove_telemetry": "Είστε βέβαιοι ότι θέλετε να εξαιρεθείτε από την τηλεμετρία;",
|
"remove_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.",
|
||||||
@@ -162,6 +190,24 @@
|
|||||||
"open_request_in_new_tab": "Open request in new tab",
|
"open_request_in_new_tab": "Open request in new tab",
|
||||||
"set_environment_variable": "Set as variable"
|
"set_environment_variable": "Set as variable"
|
||||||
},
|
},
|
||||||
|
"cookies": {
|
||||||
|
"modal": {
|
||||||
|
"cookie_expires": "Expires",
|
||||||
|
"cookie_name": "Name",
|
||||||
|
"cookie_path": "Path",
|
||||||
|
"cookie_string": "Cookie string",
|
||||||
|
"cookie_value": "Value",
|
||||||
|
"empty_domain": "Domain is empty",
|
||||||
|
"empty_domains": "Domain list is empty",
|
||||||
|
"enter_cookie_string": "Enter cookie string",
|
||||||
|
"interceptor_no_support": "Your currently selected interceptor does not support cookies. Select a different Interceptor and try again.",
|
||||||
|
"managed_tab": "Managed",
|
||||||
|
"new_domain_name": "New domain name",
|
||||||
|
"no_cookies_in_domain": "No cookies set for this domain",
|
||||||
|
"raw_tab": "Raw",
|
||||||
|
"set": "Set a cookie"
|
||||||
|
}
|
||||||
|
},
|
||||||
"count": {
|
"count": {
|
||||||
"header": "Κεφαλίδα {count}",
|
"header": "Κεφαλίδα {count}",
|
||||||
"message": "Μήνυμα {count}",
|
"message": "Μήνυμα {count}",
|
||||||
@@ -192,11 +238,13 @@
|
|||||||
"profile": "Συνδεθείτε για προβολή του προφίλ σας",
|
"profile": "Συνδεθείτε για προβολή του προφίλ σας",
|
||||||
"protocols": "Τα πρωτόκολλα είναι κενά",
|
"protocols": "Τα πρωτόκολλα είναι κενά",
|
||||||
"schema": "Συνδεθείτε σε ένα τελικό σημείο GraphQL",
|
"schema": "Συνδεθείτε σε ένα τελικό σημείο GraphQL",
|
||||||
"shortcodes": "Τα Shortcodes είναι κενά",
|
"shared_requests": "Shared requests are empty",
|
||||||
|
"shared_requests_logout": "Login to view your shared requests or create a new one",
|
||||||
"subscription": "Subscriptions are empty",
|
"subscription": "Subscriptions are empty",
|
||||||
"team_name": "Το όνομα της ομάδας είναι κενό",
|
"team_name": "Το όνομα της ομάδας είναι κενό",
|
||||||
"teams": "Οι ομάδες είναι άδειες",
|
"teams": "Οι ομάδες είναι άδειες",
|
||||||
"tests": "Δεν υπάρχουν δοκιμές για αυτό το αίτημα"
|
"tests": "Δεν υπάρχουν δοκιμές για αυτό το αίτημα",
|
||||||
|
"shortcodes": "Τα Shortcodes είναι κενά"
|
||||||
},
|
},
|
||||||
"environment": {
|
"environment": {
|
||||||
"add_to_global": "Προσθήκη στο Global",
|
"add_to_global": "Προσθήκη στο Global",
|
||||||
@@ -209,6 +257,7 @@
|
|||||||
"empty_variables": "No variables",
|
"empty_variables": "No variables",
|
||||||
"global": "Global",
|
"global": "Global",
|
||||||
"global_variables": "Global variables",
|
"global_variables": "Global variables",
|
||||||
|
"import_or_create": "Import or create a environment",
|
||||||
"invalid_name": "Καταχωρίστε ένα έγκυρο όνομα για το περιβάλλον",
|
"invalid_name": "Καταχωρίστε ένα έγκυρο όνομα για το περιβάλλον",
|
||||||
"list": "Environment variables",
|
"list": "Environment variables",
|
||||||
"my_environments": "Τα Περιβάλλοντα μου",
|
"my_environments": "Τα Περιβάλλοντα μου",
|
||||||
@@ -232,8 +281,10 @@
|
|||||||
"variable_list": "Λίστα μεταβλητών"
|
"variable_list": "Λίστα μεταβλητών"
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
|
"authproviders_load_error": "Unable to load auth providers",
|
||||||
"browser_support_sse": "Αυτό το πρόγραμμα περιήγησης δεν φαίνεται να υποστηρίζει διακομιστές που έχουν σταλεί συμβάντα.",
|
"browser_support_sse": "Αυτό το πρόγραμμα περιήγησης δεν φαίνεται να υποστηρίζει διακομιστές που έχουν σταλεί συμβάντα.",
|
||||||
"check_console_details": "Ελέγξτε το αρχείο καταγραφής της κονσόλας για λεπτομέρειες.",
|
"check_console_details": "Ελέγξτε το αρχείο καταγραφής της κονσόλας για λεπτομέρειες.",
|
||||||
|
"check_how_to_add_origin": "Check how you can add an origin",
|
||||||
"curl_invalid_format": "Το cURL δεν έχει μορφοποιηθεί σωστά",
|
"curl_invalid_format": "Το cURL δεν έχει μορφοποιηθεί σωστά",
|
||||||
"danger_zone": "Danger zone",
|
"danger_zone": "Danger zone",
|
||||||
"delete_account": "Your account is currently an owner in these teams:",
|
"delete_account": "Your account is currently an owner in these teams:",
|
||||||
@@ -249,9 +300,12 @@
|
|||||||
"json_prettify_invalid_body": "Δεν ήταν δυνατή η ομορφιά ενός μη έγκυρου σώματος, η επίλυση σφαλμάτων σύνταξης json και η προσπάθεια ξανά",
|
"json_prettify_invalid_body": "Δεν ήταν δυνατή η ομορφιά ενός μη έγκυρου σώματος, η επίλυση σφαλμάτων σύνταξης json και η προσπάθεια ξανά",
|
||||||
"network_error": "Από ότι φαίνεται υπάρχει ένα σφάλμα δικτύου. Παρακαλούμε προσπαθήστε ξανά.",
|
"network_error": "Από ότι φαίνεται υπάρχει ένα σφάλμα δικτύου. Παρακαλούμε προσπαθήστε ξανά.",
|
||||||
"network_fail": "Δεν ήταν δυνατή η αποστολή του αιτήματος",
|
"network_fail": "Δεν ήταν δυνατή η αποστολή του αιτήματος",
|
||||||
|
"no_collections_to_export": "No collections to export. Please create a collection to get started.",
|
||||||
"no_duration": "Χωρίς διάρκεια",
|
"no_duration": "Χωρίς διάρκεια",
|
||||||
|
"no_environments_to_export": "No environments to export. Please create an environment to get started.",
|
||||||
"no_results_found": "Δεν βρέθηκαν αντιστοιχίες",
|
"no_results_found": "Δεν βρέθηκαν αντιστοιχίες",
|
||||||
"page_not_found": "Αυτή η σελίδα δεν βρέθηκε",
|
"page_not_found": "Αυτή η σελίδα δεν βρέθηκε",
|
||||||
|
"please_install_extension": "Please install the extension and add origin to the extension.",
|
||||||
"proxy_error": "Proxy error",
|
"proxy_error": "Proxy error",
|
||||||
"script_fail": "Δεν ήταν δυνατή η εκτέλεση του σεναρίου πριν από το αίτημα",
|
"script_fail": "Δεν ήταν δυνατή η εκτέλεση του σεναρίου πριν από το αίτημα",
|
||||||
"something_went_wrong": "Κάτι πήγε στραβά",
|
"something_went_wrong": "Κάτι πήγε στραβά",
|
||||||
@@ -260,6 +314,7 @@
|
|||||||
"export": {
|
"export": {
|
||||||
"as_json": "Εξαγωγή ως JSON",
|
"as_json": "Εξαγωγή ως JSON",
|
||||||
"create_secret_gist": "Δημιουργήστε μυστική ουσία",
|
"create_secret_gist": "Δημιουργήστε μυστική ουσία",
|
||||||
|
"failed": "Something went wrong while exporting",
|
||||||
"gist_created": "Η ουσία δημιουργήθηκε",
|
"gist_created": "Η ουσία δημιουργήθηκε",
|
||||||
"require_github": "Συνδεθείτε με το GitHub για να δημιουργήσετε μυστική ουσία",
|
"require_github": "Συνδεθείτε με το GitHub για να δημιουργήσετε μυστική ουσία",
|
||||||
"title": "Export"
|
"title": "Export"
|
||||||
@@ -286,6 +341,9 @@
|
|||||||
"subscriptions": "Συνδρομές",
|
"subscriptions": "Συνδρομές",
|
||||||
"switch_connection": "Switch connection"
|
"switch_connection": "Switch connection"
|
||||||
},
|
},
|
||||||
|
"graphql_collections": {
|
||||||
|
"title": "GraphQL Collections"
|
||||||
|
},
|
||||||
"group": {
|
"group": {
|
||||||
"time": "Time",
|
"time": "Time",
|
||||||
"url": "URL"
|
"url": "URL"
|
||||||
@@ -297,6 +355,8 @@
|
|||||||
},
|
},
|
||||||
"helpers": {
|
"helpers": {
|
||||||
"authorization": "Η κεφαλίδα εξουσιοδότησης θα δημιουργηθεί αυτόματα κατά την αποστολή του αιτήματος.",
|
"authorization": "Η κεφαλίδα εξουσιοδότησης θα δημιουργηθεί αυτόματα κατά την αποστολή του αιτήματος.",
|
||||||
|
"collection_properties_authorization": " This authorization will be set for every request in this collection.",
|
||||||
|
"collection_properties_header": "This header will be set for every request in this collection.",
|
||||||
"generate_documentation_first": "Δημιουργήστε πρώτα έγγραφα",
|
"generate_documentation_first": "Δημιουργήστε πρώτα έγγραφα",
|
||||||
"network_fail": "Δεν είναι δυνατή η πρόσβαση στο τελικό σημείο API. Ελέγξτε τη σύνδεση δικτύου και δοκιμάστε ξανά.",
|
"network_fail": "Δεν είναι δυνατή η πρόσβαση στο τελικό σημείο API. Ελέγξτε τη σύνδεση δικτύου και δοκιμάστε ξανά.",
|
||||||
"offline": "Φαίνεται ότι είστε εκτός σύνδεσης. Τα δεδομένα σε αυτόν τον χώρο εργασίας ενδέχεται να μην είναι ενημερωμένα.",
|
"offline": "Φαίνεται ότι είστε εκτός σύνδεσης. Τα δεδομένα σε αυτόν τον χώρο εργασίας ενδέχεται να μην είναι ενημερωμένα.",
|
||||||
@@ -316,7 +376,10 @@
|
|||||||
"import": {
|
"import": {
|
||||||
"collections": "Εισαγωγή συλλογών",
|
"collections": "Εισαγωγή συλλογών",
|
||||||
"curl": "Εισαγωγή cURL",
|
"curl": "Εισαγωγή cURL",
|
||||||
|
"environments_from_gist": "Import From Gist",
|
||||||
|
"environments_from_gist_description": "Import Hoppscotch Environments From Gist",
|
||||||
"failed": "Η εισαγωγή απέτυχε",
|
"failed": "Η εισαγωγή απέτυχε",
|
||||||
|
"from_file": "Import from File",
|
||||||
"from_gist": "Εισαγωγή από το Gist",
|
"from_gist": "Εισαγωγή από το Gist",
|
||||||
"from_gist_description": "Εισαγωγή από Gist URL",
|
"from_gist_description": "Εισαγωγή από Gist URL",
|
||||||
"from_insomnia": "Εισαγωγή από Insomnia",
|
"from_insomnia": "Εισαγωγή από Insomnia",
|
||||||
@@ -331,11 +394,17 @@
|
|||||||
"from_postman_description": "Εισαγωγή Συλλογής από Postman",
|
"from_postman_description": "Εισαγωγή Συλλογής από Postman",
|
||||||
"from_url": "Εισαγωγή από URL",
|
"from_url": "Εισαγωγή από URL",
|
||||||
"gist_url": "Εισαγάγετε Gist URL",
|
"gist_url": "Εισαγάγετε Gist URL",
|
||||||
|
"gql_collections_from_gist_description": "Import GraphQL Collections From Gist",
|
||||||
|
"hoppscotch_environment": "Hoppscotch Environment",
|
||||||
|
"hoppscotch_environment_description": "Import Hoppscotch Environment JSON file",
|
||||||
"import_from_url_invalid_fetch": "Δεν μπορέσαμε να πάρουμε δεδομένα από το url",
|
"import_from_url_invalid_fetch": "Δεν μπορέσαμε να πάρουμε δεδομένα από το url",
|
||||||
"import_from_url_invalid_file_format": "Σφάλμα κατά την εισαγωγή των Συλλογών",
|
"import_from_url_invalid_file_format": "Σφάλμα κατά την εισαγωγή των Συλλογών",
|
||||||
"import_from_url_invalid_type": "Μη υποστηριζόμενος τύπος. Αποδεκτές τιμές είναι 'hoppscotch', 'openapi', 'postman', 'insomnia'",
|
"import_from_url_invalid_type": "Μη υποστηριζόμενος τύπος. Αποδεκτές τιμές είναι 'hoppscotch', 'openapi', 'postman', 'insomnia'",
|
||||||
"import_from_url_success": "Η εισαγωγή των Συλλογών ήταν επιτυχής",
|
"import_from_url_success": "Η εισαγωγή των Συλλογών ήταν επιτυχής",
|
||||||
|
"insomnia_environment_description": "Import Insomnia Environment from a JSON/YAML file",
|
||||||
"json_description": "Εισαγωγή συλλογών αρχείο JSON Hoppscotch Collections",
|
"json_description": "Εισαγωγή συλλογών αρχείο JSON Hoppscotch Collections",
|
||||||
|
"postman_environment": "Postman Environment",
|
||||||
|
"postman_environment_description": "Import Postman Environment from a JSON file",
|
||||||
"title": "Εισαγωγή"
|
"title": "Εισαγωγή"
|
||||||
},
|
},
|
||||||
"inspections": {
|
"inspections": {
|
||||||
@@ -373,8 +442,10 @@
|
|||||||
"close_unsaved_tab": "You have unsaved changes",
|
"close_unsaved_tab": "You have unsaved changes",
|
||||||
"collections": "Συλλογές",
|
"collections": "Συλλογές",
|
||||||
"confirm": "Επιβεβαιώνω",
|
"confirm": "Επιβεβαιώνω",
|
||||||
|
"customize_request": "Customize Request",
|
||||||
"edit_request": "Αίτημα Επεξεργασίας",
|
"edit_request": "Αίτημα Επεξεργασίας",
|
||||||
"import_export": "Εισαγωγή εξαγωγή"
|
"import_export": "Εισαγωγή εξαγωγή",
|
||||||
|
"share_request": "Share Request"
|
||||||
},
|
},
|
||||||
"mqtt": {
|
"mqtt": {
|
||||||
"already_subscribed": "You are already subscribed to this topic.",
|
"already_subscribed": "You are already subscribed to this topic.",
|
||||||
@@ -449,13 +520,14 @@
|
|||||||
"structured": "Structured",
|
"structured": "Structured",
|
||||||
"text": "Text"
|
"text": "Text"
|
||||||
},
|
},
|
||||||
"copy_link": "Αντιγραφή συνδέσμου",
|
|
||||||
"different_collection": "Cannot reorder requests from different collections",
|
"different_collection": "Cannot reorder requests from different collections",
|
||||||
"duplicated": "Request duplicated",
|
"duplicated": "Request duplicated",
|
||||||
"duration": "Διάρκεια",
|
"duration": "Διάρκεια",
|
||||||
"enter_curl": "Εισαγάγετε cURL",
|
"enter_curl": "Εισαγάγετε cURL",
|
||||||
"generate_code": "Δημιουργία κώδικα",
|
"generate_code": "Δημιουργία κώδικα",
|
||||||
"generated_code": "Παραγόμενος κώδικας",
|
"generated_code": "Παραγόμενος κώδικας",
|
||||||
|
"go_to_authorization_tab": "Go to Authorization tab",
|
||||||
|
"go_to_body_tab": "Go to Body tab",
|
||||||
"header_list": "Λίστα κεφαλίδων",
|
"header_list": "Λίστα κεφαλίδων",
|
||||||
"invalid_name": "Καταχωρίστε ένα όνομα για το αίτημα",
|
"invalid_name": "Καταχωρίστε ένα όνομα για το αίτημα",
|
||||||
"method": "Μέθοδος",
|
"method": "Μέθοδος",
|
||||||
@@ -480,12 +552,14 @@
|
|||||||
"saved": "Το αίτημα αποθηκεύτηκε",
|
"saved": "Το αίτημα αποθηκεύτηκε",
|
||||||
"share": "Μερίδιο",
|
"share": "Μερίδιο",
|
||||||
"share_description": "Κοινοποίηση Hoppscotch στους φίλους σου",
|
"share_description": "Κοινοποίηση Hoppscotch στους φίλους σου",
|
||||||
|
"share_request": "Share Request",
|
||||||
"stop": "Stop",
|
"stop": "Stop",
|
||||||
"title": "Αίτηση",
|
"title": "Αίτηση",
|
||||||
"type": "Τύπος αιτήματος",
|
"type": "Τύπος αιτήματος",
|
||||||
"url": "URL",
|
"url": "URL",
|
||||||
"variables": "Μεταβλητές",
|
"variables": "Μεταβλητές",
|
||||||
"view_my_links": "Προβολή των links μου"
|
"view_my_links": "Προβολή των links μου",
|
||||||
|
"copy_link": "Αντιγραφή συνδέσμου"
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"audio": "Audio",
|
"audio": "Audio",
|
||||||
@@ -513,6 +587,7 @@
|
|||||||
"account_description": "Προσαρμόστε τις ρυθμίσεις του λογαριασμού σας.",
|
"account_description": "Προσαρμόστε τις ρυθμίσεις του λογαριασμού σας.",
|
||||||
"account_email_description": "Η κύρια διεύθυνση email σας.",
|
"account_email_description": "Η κύρια διεύθυνση email σας.",
|
||||||
"account_name_description": "Αυτό είναι το εμφανιζόμενο όνομά σας.",
|
"account_name_description": "Αυτό είναι το εμφανιζόμενο όνομά σας.",
|
||||||
|
"additional": "Additional Settings",
|
||||||
"background": "Ιστορικό",
|
"background": "Ιστορικό",
|
||||||
"black_mode": "Μαύρος",
|
"black_mode": "Μαύρος",
|
||||||
"choose_language": "Διάλεξε γλώσσα",
|
"choose_language": "Διάλεξε γλώσσα",
|
||||||
@@ -559,14 +634,31 @@
|
|||||||
"verified_email": "Επαληθευμένο email",
|
"verified_email": "Επαληθευμένο email",
|
||||||
"verify_email": "Επαλήθευση email"
|
"verify_email": "Επαλήθευση email"
|
||||||
},
|
},
|
||||||
"shortcodes": {
|
"shared_requests": {
|
||||||
"actions": "Δράσεις",
|
"button": "Button",
|
||||||
"created_on": "Created on",
|
"button_info": "Create a 'Run in Hoppscotch' button for your website, blog or a README.",
|
||||||
"deleted": "Το Shortcode διαγράφηκε",
|
"copy_html": "Copy HTML",
|
||||||
"method": "Method",
|
"copy_link": "Copy Link",
|
||||||
"not_found": "Το Shortcode δεν βρέθηκε",
|
"copy_markdown": "Copy Markdown",
|
||||||
"short_code": "Short code",
|
"creating_widget": "Creating widget",
|
||||||
"url": "URL"
|
"customize": "Customize",
|
||||||
|
"deleted": "Shared request deleted",
|
||||||
|
"description": "Select a widget, you can change and customize this later",
|
||||||
|
"embed": "Embed",
|
||||||
|
"embed_info": "Add a mini 'Hoppscotch API Playground' to your website, blog or documentation.",
|
||||||
|
"link": "Link",
|
||||||
|
"link_info": "Create a shareable link to share with anyone on the internet with view access.",
|
||||||
|
"modified": "Shared request modified",
|
||||||
|
"not_found": "Shared request not found",
|
||||||
|
"open_new_tab": "Open in new tab",
|
||||||
|
"preview": "Preview",
|
||||||
|
"run_in_hoppscotch": "Run in Hoppscotch",
|
||||||
|
"theme": {
|
||||||
|
"dark": "Dark",
|
||||||
|
"light": "Light",
|
||||||
|
"system": "System",
|
||||||
|
"title": "Theme"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"shortcut": {
|
"shortcut": {
|
||||||
"general": {
|
"general": {
|
||||||
@@ -596,7 +688,6 @@
|
|||||||
"title": "Others"
|
"title": "Others"
|
||||||
},
|
},
|
||||||
"request": {
|
"request": {
|
||||||
"copy_request_link": "Αντιγραφή συνδέσμου αιτήματος",
|
|
||||||
"delete_method": "Επιλέξτε ΔΙΑΓΡΑΦΗ μεθόδου",
|
"delete_method": "Επιλέξτε ΔΙΑΓΡΑΦΗ μεθόδου",
|
||||||
"get_method": "Επιλέξτε μέθοδο GET",
|
"get_method": "Επιλέξτε μέθοδο GET",
|
||||||
"head_method": "Επιλέξτε μέθοδο HEAD",
|
"head_method": "Επιλέξτε μέθοδο HEAD",
|
||||||
@@ -611,8 +702,10 @@
|
|||||||
"save_request": "Save Request",
|
"save_request": "Save Request",
|
||||||
"save_to_collections": "Αποθήκευση στις Συλλογές",
|
"save_to_collections": "Αποθήκευση στις Συλλογές",
|
||||||
"send_request": "Στείλε αίτημα",
|
"send_request": "Στείλε αίτημα",
|
||||||
|
"share_request": "Share Request",
|
||||||
"show_code": "Generate code snippet",
|
"show_code": "Generate code snippet",
|
||||||
"title": "Αίτηση"
|
"title": "Αίτηση",
|
||||||
|
"copy_request_link": "Αντιγραφή συνδέσμου αιτήματος"
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"copy": "Αντιγραφή response στο πρόχειρο",
|
"copy": "Αντιγραφή response στο πρόχειρο",
|
||||||
@@ -735,6 +828,7 @@
|
|||||||
"connection_error": "Η Σύνδεση απέτυχε",
|
"connection_error": "Η Σύνδεση απέτυχε",
|
||||||
"connection_failed": "Αποτυχής Σύνδεση",
|
"connection_failed": "Αποτυχής Σύνδεση",
|
||||||
"connection_lost": "Η Σύνδεση χάθηκε",
|
"connection_lost": "Η Σύνδεση χάθηκε",
|
||||||
|
"copied_interface_to_clipboard": "Copied {language} interface type to clipboard",
|
||||||
"copied_to_clipboard": "Αντιγράφηκε στο πρόχειρο",
|
"copied_to_clipboard": "Αντιγράφηκε στο πρόχειρο",
|
||||||
"deleted": "Διαγράφηκε",
|
"deleted": "Διαγράφηκε",
|
||||||
"deprecated": "ΚΑΤΑΡΓΗΘΗΚΕ",
|
"deprecated": "ΚΑΤΑΡΓΗΘΗΚΕ",
|
||||||
@@ -742,10 +836,12 @@
|
|||||||
"disconnected": "Ασύνδετος",
|
"disconnected": "Ασύνδετος",
|
||||||
"disconnected_from": "Αποσυνδέθηκε από το {name}",
|
"disconnected_from": "Αποσυνδέθηκε από το {name}",
|
||||||
"docs_generated": "Δημιουργήθηκε τεκμηρίωση",
|
"docs_generated": "Δημιουργήθηκε τεκμηρίωση",
|
||||||
|
"download_failed": "Download failed",
|
||||||
"download_started": "Η λήψη ξεκίνησε",
|
"download_started": "Η λήψη ξεκίνησε",
|
||||||
"enabled": "Ενεργοποιημένο",
|
"enabled": "Ενεργοποιημένο",
|
||||||
"file_imported": "Το αρχείο εισήχθη",
|
"file_imported": "Το αρχείο εισήχθη",
|
||||||
"finished_in": "Ολοκληρώθηκε σε {duration} ms",
|
"finished_in": "Ολοκληρώθηκε σε {duration} ms",
|
||||||
|
"hide": "Hide",
|
||||||
"history_deleted": "Το ιστορικό διαγράφηκε",
|
"history_deleted": "Το ιστορικό διαγράφηκε",
|
||||||
"linewrap": "Τυλίξτε γραμμές",
|
"linewrap": "Τυλίξτε γραμμές",
|
||||||
"loading": "Φόρτωση...",
|
"loading": "Φόρτωση...",
|
||||||
@@ -756,6 +852,7 @@
|
|||||||
"published_error": "Κάτι πήγε στραβά κατα την αποστολή του μηνύματος: {topic} με θέμα: {message}",
|
"published_error": "Κάτι πήγε στραβά κατα την αποστολή του μηνύματος: {topic} με θέμα: {message}",
|
||||||
"published_message": "Δημοσιευμένο Μηνυμα: {message} με θέμα: {topic}",
|
"published_message": "Δημοσιευμένο Μηνυμα: {message} με θέμα: {topic}",
|
||||||
"reconnection_error": "Αποτυχία επανασύνδεσης",
|
"reconnection_error": "Αποτυχία επανασύνδεσης",
|
||||||
|
"show": "Show",
|
||||||
"subscribed_failed": "Αποτυχία εγγραφής στο Θέμα: {topic}",
|
"subscribed_failed": "Αποτυχία εγγραφής στο Θέμα: {topic}",
|
||||||
"subscribed_success": "Επιτυχία εγγραφής στο Θέμα: {topic}",
|
"subscribed_success": "Επιτυχία εγγραφής στο Θέμα: {topic}",
|
||||||
"unsubscribed_failed": "Αποτυχία απεγγραφής στο Θέμα: {topic}",
|
"unsubscribed_failed": "Αποτυχία απεγγραφής στο Θέμα: {topic}",
|
||||||
@@ -791,6 +888,7 @@
|
|||||||
"queries": "Ερωτήματα",
|
"queries": "Ερωτήματα",
|
||||||
"query": "Ερώτηση",
|
"query": "Ερώτηση",
|
||||||
"schema": "Schema",
|
"schema": "Schema",
|
||||||
|
"shared_requests": "Shared Requests",
|
||||||
"socketio": "Υποδοχή.IO",
|
"socketio": "Υποδοχή.IO",
|
||||||
"sse": "SSE",
|
"sse": "SSE",
|
||||||
"tests": "Δοκιμές",
|
"tests": "Δοκιμές",
|
||||||
@@ -807,6 +905,7 @@
|
|||||||
"email_do_not_match": "Το Email δεν ταιριάζει με τις λεπτομέριες του προφιλ σας. Επικοινωνήστε με τον Ιδιοκτήτη της Ομάδας.",
|
"email_do_not_match": "Το Email δεν ταιριάζει με τις λεπτομέριες του προφιλ σας. Επικοινωνήστε με τον Ιδιοκτήτη της Ομάδας.",
|
||||||
"exit": "Έξοδος από την ομάδα",
|
"exit": "Έξοδος από την ομάδα",
|
||||||
"exit_disabled": "Μόνο ο ιδιοκτήτης δεν μπορεί να αποχωρήσει από την ομάδα",
|
"exit_disabled": "Μόνο ο ιδιοκτήτης δεν μπορεί να αποχωρήσει από την ομάδα",
|
||||||
|
"failed_invites": "Failed invites",
|
||||||
"invalid_coll_id": "Invalid collection ID",
|
"invalid_coll_id": "Invalid collection ID",
|
||||||
"invalid_email_format": "Η μορφή ηλεκτρονικού ταχυδρομείου δεν είναι έγκυρη",
|
"invalid_email_format": "Η μορφή ηλεκτρονικού ταχυδρομείου δεν είναι έγκυρη",
|
||||||
"invalid_id": "Μή εγκυρο αναγνωριστικό ομάδας. Επικοινωνήστε με τον Ιδιοκτήτη της Ομάδας.",
|
"invalid_id": "Μή εγκυρο αναγνωριστικό ομάδας. Επικοινωνήστε με τον Ιδιοκτήτη της Ομάδας.",
|
||||||
@@ -848,6 +947,7 @@
|
|||||||
"same_target_destination": "Same target and destination",
|
"same_target_destination": "Same target and destination",
|
||||||
"saved": "Η ομάδα σώθηκε",
|
"saved": "Η ομάδα σώθηκε",
|
||||||
"select_a_team": "Επιλογή ομάδας",
|
"select_a_team": "Επιλογή ομάδας",
|
||||||
|
"success_invites": "Success invites",
|
||||||
"title": "Της ομάδας",
|
"title": "Της ομάδας",
|
||||||
"we_sent_invite_link": "Στείλαμε έναν σύνδεσμο πρόσκλησης σε όλους!",
|
"we_sent_invite_link": "Στείλαμε έναν σύνδεσμο πρόσκλησης σε όλους!",
|
||||||
"we_sent_invite_link_description": "Ζητήστε από όλους όσους στείλατε πρόσκληση να ελέγξουν τα email τους. Click στον σύνδεσμο για εισαγωγή στην ομάδα."
|
"we_sent_invite_link_description": "Ζητήστε από όλους όσους στείλατε πρόσκληση να ελέγξουν τα email τους. Click στον σύνδεσμο για εισαγωγή στην ομάδα."
|
||||||
@@ -879,5 +979,14 @@
|
|||||||
"personal": "My Workspace",
|
"personal": "My Workspace",
|
||||||
"team": "Team Workspace",
|
"team": "Team Workspace",
|
||||||
"title": "Workspaces"
|
"title": "Workspaces"
|
||||||
|
},
|
||||||
|
"shortcodes": {
|
||||||
|
"actions": "Δράσεις",
|
||||||
|
"created_on": "Created on",
|
||||||
|
"deleted": "Το Shortcode διαγράφηκε",
|
||||||
|
"method": "Method",
|
||||||
|
"not_found": "Το Shortcode δεν βρέθηκε",
|
||||||
|
"short_code": "Short code",
|
||||||
|
"url": "URL"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
"go_back": "Go back",
|
"go_back": "Go back",
|
||||||
"go_forward": "Go forward",
|
"go_forward": "Go forward",
|
||||||
"group_by": "Group by",
|
"group_by": "Group by",
|
||||||
|
"hide_secret": "Hide secret",
|
||||||
"label": "Label",
|
"label": "Label",
|
||||||
"learn_more": "Learn more",
|
"learn_more": "Learn more",
|
||||||
"less": "Less",
|
"less": "Less",
|
||||||
@@ -33,7 +34,7 @@
|
|||||||
"open_workspace": "Open workspace",
|
"open_workspace": "Open workspace",
|
||||||
"paste": "Paste",
|
"paste": "Paste",
|
||||||
"prettify": "Prettify",
|
"prettify": "Prettify",
|
||||||
"properties":"Properties",
|
"properties": "Properties",
|
||||||
"remove": "Remove",
|
"remove": "Remove",
|
||||||
"rename": "Rename",
|
"rename": "Rename",
|
||||||
"restore": "Restore",
|
"restore": "Restore",
|
||||||
@@ -43,6 +44,7 @@
|
|||||||
"search": "Search",
|
"search": "Search",
|
||||||
"send": "Send",
|
"send": "Send",
|
||||||
"share": "Share",
|
"share": "Share",
|
||||||
|
"show_secret": "Show secret",
|
||||||
"start": "Start",
|
"start": "Start",
|
||||||
"starting": "Starting",
|
"starting": "Starting",
|
||||||
"stop": "Stop",
|
"stop": "Stop",
|
||||||
@@ -58,24 +60,6 @@
|
|||||||
"new": "Add new",
|
"new": "Add new",
|
||||||
"star": "Add star"
|
"star": "Add star"
|
||||||
},
|
},
|
||||||
"cookies": {
|
|
||||||
"modal": {
|
|
||||||
"new_domain_name": "New domain name",
|
|
||||||
"set": "Set a cookie",
|
|
||||||
"cookie_string": "Cookie string",
|
|
||||||
"enter_cookie_string": "Enter cookie string",
|
|
||||||
"cookie_name": "Name",
|
|
||||||
"cookie_value": "Value",
|
|
||||||
"cookie_path": "Path",
|
|
||||||
"cookie_expires": "Expires",
|
|
||||||
"managed_tab": "Managed",
|
|
||||||
"raw_tab": "Raw",
|
|
||||||
"interceptor_no_support": "Your currently selected interceptor does not support cookies. Select a different Interceptor and try again.",
|
|
||||||
"empty_domains": "Domain list is empty",
|
|
||||||
"empty_domain": "Domain is empty",
|
|
||||||
"no_cookies_in_domain": "No cookies set for this domain"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"app": {
|
"app": {
|
||||||
"chat_with_us": "Chat with us",
|
"chat_with_us": "Chat with us",
|
||||||
"contact_us": "Contact us",
|
"contact_us": "Contact us",
|
||||||
@@ -139,26 +123,28 @@
|
|||||||
"generate_token": "Generate Token",
|
"generate_token": "Generate Token",
|
||||||
"graphql_headers": "Authorization Headers are sent as part of the payload to connection_init",
|
"graphql_headers": "Authorization Headers are sent as part of the payload to connection_init",
|
||||||
"include_in_url": "Include in URL",
|
"include_in_url": "Include in URL",
|
||||||
|
"inherited_from": "Inherited {auth} from parent collection {collection} ",
|
||||||
"learn": "Learn how",
|
"learn": "Learn how",
|
||||||
"pass_key_by": "Pass by",
|
|
||||||
"password": "Password",
|
|
||||||
"token": "Token",
|
|
||||||
"type": "Authorization Type",
|
|
||||||
"username": "Username",
|
|
||||||
"oauth": {
|
"oauth": {
|
||||||
"token_generation_oidc_discovery_failed": "Failure on token generation: OpenID Connect Discovery Failed",
|
|
||||||
"something_went_wrong_on_token_generation": "Something went wrong on token generation",
|
|
||||||
"redirect_auth_server_returned_error": "Auth Server returned an error state",
|
"redirect_auth_server_returned_error": "Auth Server returned an error state",
|
||||||
"redirect_no_auth_code": "No Authorization Code present in the redirect",
|
"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_invalid_state": "Invalid State value present in the redirect",
|
||||||
"redirect_no_token_endpoint": "No Token Endpoint Defined",
|
"redirect_no_auth_code": "No Authorization Code present in the redirect",
|
||||||
"redirect_no_client_id": "No Client ID defined",
|
"redirect_no_client_id": "No Client ID defined",
|
||||||
"redirect_no_client_secret": "No Client Secret Defined",
|
"redirect_no_client_secret": "No Client Secret Defined",
|
||||||
"redirect_no_code_verifier": "No Code Verifier Defined",
|
"redirect_no_code_verifier": "No Code Verifier Defined",
|
||||||
"redirect_auth_token_request_failed": "Request to get the auth token failed",
|
"redirect_no_token_endpoint": "No Token Endpoint Defined",
|
||||||
"redirect_auth_token_request_invalid_response": "Invalid Response from the Token Endpoint when requesting for an auth token",
|
"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",
|
||||||
}
|
"token_generation_oidc_discovery_failed": "Failure on token generation: OpenID Connect Discovery Failed"
|
||||||
|
},
|
||||||
|
"pass_key_by": "Pass by",
|
||||||
|
"password": "Password",
|
||||||
|
"save_to_inherit": "Please save this request in any collection to inherit the authorization",
|
||||||
|
"token": "Token",
|
||||||
|
"type": "Authorization Type",
|
||||||
|
"username": "Username"
|
||||||
},
|
},
|
||||||
"collection": {
|
"collection": {
|
||||||
"created": "Collection created",
|
"created": "Collection created",
|
||||||
@@ -173,7 +159,7 @@
|
|||||||
"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",
|
||||||
"order_changed": "Collection Order Updated",
|
"order_changed": "Collection Order Updated",
|
||||||
"properties":"Colection Properties",
|
"properties": "Collection Properties",
|
||||||
"properties_updated": "Collection Properties Updated",
|
"properties_updated": "Collection Properties Updated",
|
||||||
"renamed": "Collection renamed",
|
"renamed": "Collection renamed",
|
||||||
"request_in_use": "Request in use",
|
"request_in_use": "Request in use",
|
||||||
@@ -206,6 +192,24 @@
|
|||||||
"open_request_in_new_tab": "Open request in new tab",
|
"open_request_in_new_tab": "Open request in new tab",
|
||||||
"set_environment_variable": "Set as variable"
|
"set_environment_variable": "Set as variable"
|
||||||
},
|
},
|
||||||
|
"cookies": {
|
||||||
|
"modal": {
|
||||||
|
"cookie_expires": "Expires",
|
||||||
|
"cookie_name": "Name",
|
||||||
|
"cookie_path": "Path",
|
||||||
|
"cookie_string": "Cookie string",
|
||||||
|
"cookie_value": "Value",
|
||||||
|
"empty_domain": "Domain is empty",
|
||||||
|
"empty_domains": "Domain list is empty",
|
||||||
|
"enter_cookie_string": "Enter cookie string",
|
||||||
|
"interceptor_no_support": "Your currently selected interceptor does not support cookies. Select a different Interceptor and try again.",
|
||||||
|
"managed_tab": "Managed",
|
||||||
|
"new_domain_name": "New domain name",
|
||||||
|
"no_cookies_in_domain": "No cookies set for this domain",
|
||||||
|
"raw_tab": "Raw",
|
||||||
|
"set": "Set a cookie"
|
||||||
|
}
|
||||||
|
},
|
||||||
"count": {
|
"count": {
|
||||||
"header": "Header {count}",
|
"header": "Header {count}",
|
||||||
"message": "Message {count}",
|
"message": "Message {count}",
|
||||||
@@ -235,9 +239,11 @@
|
|||||||
"pending_invites": "There are no pending invites for this team",
|
"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",
|
||||||
"shared_requests_logout": "Login to view your shared requests or create a new one",
|
"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",
|
||||||
"subscription": "Subscriptions are empty",
|
"subscription": "Subscriptions are empty",
|
||||||
"team_name": "Team name empty",
|
"team_name": "Team name empty",
|
||||||
"teams": "You don't belong to any teams",
|
"teams": "You don't belong to any teams",
|
||||||
@@ -267,6 +273,8 @@
|
|||||||
"quick_peek": "Environment Quick Peek",
|
"quick_peek": "Environment Quick Peek",
|
||||||
"replace_with_variable": "Replace with variable",
|
"replace_with_variable": "Replace with variable",
|
||||||
"scope": "Scope",
|
"scope": "Scope",
|
||||||
|
"secrets": "Secrets",
|
||||||
|
"secret_value": "Secret value",
|
||||||
"select": "Select environment",
|
"select": "Select environment",
|
||||||
"set": "Set environment",
|
"set": "Set environment",
|
||||||
"set_as_environment": "Set as environment",
|
"set_as_environment": "Set as environment",
|
||||||
@@ -275,12 +283,11 @@
|
|||||||
"updated": "Environment updated",
|
"updated": "Environment updated",
|
||||||
"value": "Value",
|
"value": "Value",
|
||||||
"variable": "Variable",
|
"variable": "Variable",
|
||||||
|
"variables":"Variables",
|
||||||
"variable_list": "Variable List"
|
"variable_list": "Variable List"
|
||||||
},
|
},
|
||||||
"graphql_collections": {
|
|
||||||
"title": "GraphQL Collections"
|
|
||||||
},
|
|
||||||
"error": {
|
"error": {
|
||||||
|
"authproviders_load_error": "Unable to load auth providers",
|
||||||
"browser_support_sse": "This browser doesn't seems to have Server Sent Events support.",
|
"browser_support_sse": "This browser doesn't seems to have Server Sent Events support.",
|
||||||
"check_console_details": "Check console log for details.",
|
"check_console_details": "Check console log for details.",
|
||||||
"check_how_to_add_origin": "Check how you can add an origin",
|
"check_how_to_add_origin": "Check how you can add an origin",
|
||||||
@@ -295,6 +302,7 @@
|
|||||||
"incorrect_email": "Incorrect email",
|
"incorrect_email": "Incorrect email",
|
||||||
"invalid_link": "Invalid link",
|
"invalid_link": "Invalid link",
|
||||||
"invalid_link_description": "The link you clicked is invalid or expired.",
|
"invalid_link_description": "The link you clicked is invalid or expired.",
|
||||||
|
"invalid_embed_link": "The embed does not exist or is invalid.",
|
||||||
"json_parsing_failed": "Invalid JSON",
|
"json_parsing_failed": "Invalid JSON",
|
||||||
"json_prettify_invalid_body": "Couldn't prettify an invalid body, solve json syntax errors and try again",
|
"json_prettify_invalid_body": "Couldn't prettify an invalid body, solve json syntax errors and try again",
|
||||||
"network_error": "There seems to be a network error. Please try again.",
|
"network_error": "There seems to be a network error. Please try again.",
|
||||||
@@ -308,15 +316,18 @@
|
|||||||
"proxy_error": "Proxy error",
|
"proxy_error": "Proxy error",
|
||||||
"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",
|
||||||
"create_secret_gist": "Create secret Gist",
|
"create_secret_gist": "Create secret Gist",
|
||||||
"gist_created": "Gist created",
|
"create_secret_gist_tooltip_text": "Export as secret Gist",
|
||||||
|
"failed": "Something went wrong while exporting",
|
||||||
|
"secret_gist_success": "Successfully exported as secret Gist",
|
||||||
"require_github": "Login with GitHub to create secret gist",
|
"require_github": "Login with GitHub to create secret gist",
|
||||||
"title": "Export",
|
"title": "Export",
|
||||||
"failed": "Something went wrong while exporting"
|
"success": "Successfully exported"
|
||||||
},
|
},
|
||||||
"filter": {
|
"filter": {
|
||||||
"all": "All",
|
"all": "All",
|
||||||
@@ -340,6 +351,9 @@
|
|||||||
"subscriptions": "Subscriptions",
|
"subscriptions": "Subscriptions",
|
||||||
"switch_connection": "Switch connection"
|
"switch_connection": "Switch connection"
|
||||||
},
|
},
|
||||||
|
"graphql_collections": {
|
||||||
|
"title": "GraphQL Collections"
|
||||||
|
},
|
||||||
"group": {
|
"group": {
|
||||||
"time": "Time",
|
"time": "Time",
|
||||||
"url": "URL"
|
"url": "URL"
|
||||||
@@ -351,14 +365,14 @@
|
|||||||
},
|
},
|
||||||
"helpers": {
|
"helpers": {
|
||||||
"authorization": "The authorization header will be automatically generated when you send the request.",
|
"authorization": "The authorization header will be automatically generated when you send the request.",
|
||||||
|
"collection_properties_authorization": " This authorization will be set for every request in this collection.",
|
||||||
|
"collection_properties_header": "This header will be set for every request in this collection.",
|
||||||
"generate_documentation_first": "Generate documentation first",
|
"generate_documentation_first": "Generate documentation first",
|
||||||
"network_fail": "Unable to reach the API endpoint. Check your network connection or select a different Interceptor and try again.",
|
"network_fail": "Unable to reach the API endpoint. Check your network connection or select a different Interceptor and try again.",
|
||||||
"offline": "You're using Hoppscotch offline. Updates will sync when you're online, based on workspace settings.",
|
"offline": "You're using Hoppscotch offline. Updates will sync when you're online, based on workspace settings.",
|
||||||
"offline_short": "You're using Hoppscotch offline.",
|
"offline_short": "You're using Hoppscotch offline.",
|
||||||
"post_request_tests": "Test scripts are written in JavaScript, and are run after the response is received.",
|
"post_request_tests": "Test scripts are written in JavaScript, and are run after the response is received.",
|
||||||
"pre_request_script": "Pre-request scripts are written in JavaScript, and are run before the request is sent.",
|
"pre_request_script": "Pre-request scripts are written in JavaScript, and are run before the request is sent.",
|
||||||
"collection_properties_authorization": " This authorization will be set for every request in this collection.",
|
|
||||||
"collection_properties_header": "This header will be set for every request in this collection.",
|
|
||||||
"script_fail": "It seems there is a glitch in the pre-request script. Check the error below and fix the script accordingly.",
|
"script_fail": "It seems there is a glitch in the pre-request script. Check the error below and fix the script accordingly.",
|
||||||
"test_script_fail": "There seems to be an error with test script. Please fix the errors and run tests again",
|
"test_script_fail": "There seems to be an error with test script. Please fix the errors and run tests again",
|
||||||
"tests": "Write a test script to automate debugging."
|
"tests": "Write a test script to automate debugging."
|
||||||
@@ -372,7 +386,10 @@
|
|||||||
"import": {
|
"import": {
|
||||||
"collections": "Import collections",
|
"collections": "Import collections",
|
||||||
"curl": "Import cURL",
|
"curl": "Import cURL",
|
||||||
|
"environments_from_gist": "Import From Gist",
|
||||||
|
"environments_from_gist_description": "Import Hoppscotch Environments From Gist",
|
||||||
"failed": "Error while importing: format not recognized",
|
"failed": "Error while importing: format not recognized",
|
||||||
|
"from_file": "Import from File",
|
||||||
"from_gist": "Import from Gist",
|
"from_gist": "Import from Gist",
|
||||||
"from_gist_description": "Import from Gist URL",
|
"from_gist_description": "Import from Gist URL",
|
||||||
"from_insomnia": "Import from Insomnia",
|
"from_insomnia": "Import from Insomnia",
|
||||||
@@ -385,28 +402,30 @@
|
|||||||
"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",
|
||||||
"from_postman_description": "Import from Postman collection",
|
"from_postman_description": "Import from Postman collection",
|
||||||
"from_file": "Import from File",
|
|
||||||
"from_url": "Import from URL",
|
"from_url": "Import from URL",
|
||||||
"gist_url": "Enter Gist URL",
|
"gist_url": "Enter Gist URL",
|
||||||
|
"gql_collections_from_gist_description": "Import GraphQL Collections From Gist",
|
||||||
|
"hoppscotch_environment": "Hoppscotch Environment",
|
||||||
|
"hoppscotch_environment_description": "Import Hoppscotch Environment JSON file",
|
||||||
"import_from_url_invalid_fetch": "Couldn't get data from the url",
|
"import_from_url_invalid_fetch": "Couldn't get data from the url",
|
||||||
"import_from_url_invalid_file_format": "Error while importing collections",
|
"import_from_url_invalid_file_format": "Error while importing collections",
|
||||||
"import_from_url_invalid_type": "Unsupported type. accepted values are 'hoppscotch', 'openapi', 'postman', 'insomnia'",
|
"import_from_url_invalid_type": "Unsupported type. accepted values are 'hoppscotch', 'openapi', 'postman', 'insomnia'",
|
||||||
"import_from_url_success": "Collections Imported",
|
"import_from_url_success": "Collections Imported",
|
||||||
|
"insomnia_environment_description": "Import Insomnia Environment from a JSON/YAML file",
|
||||||
"json_description": "Import collections from a Hoppscotch Collections JSON file",
|
"json_description": "Import collections from a Hoppscotch Collections JSON file",
|
||||||
"title": "Import",
|
|
||||||
"hoppscotch_environment": "Hoppscotch Environment",
|
|
||||||
"hoppscotch_environment_description": "Import Hoppscotch Environment 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",
|
||||||
"insomnia_environment_description": "Import Insomnia Environment from a JSON/YAML file",
|
"title": "Import",
|
||||||
"environments_from_gist": "Import From Gist",
|
"file_size_limit_exceeded_warning_multiple_files": "Chosen files exceed the recommended limit of 10MB. Only the first {files} selected will be imported",
|
||||||
"environments_from_gist_description": "Import Hoppscotch Environments From Gist",
|
"file_size_limit_exceeded_warning_single_file": "The currently chosen file exceeds the recommended limit of 10MB. Please select another file.",
|
||||||
"gql_collections_from_gist_description": "Import GraphQL Collections From Gist"
|
"success": "Successfully imported"
|
||||||
},
|
},
|
||||||
"inspections": {
|
"inspections": {
|
||||||
"description": "Inspect possible errors",
|
"description": "Inspect possible errors",
|
||||||
"environment": {
|
"environment": {
|
||||||
"add_environment": "Add to Environment",
|
"add_environment": "Add to Environment",
|
||||||
|
"add_environment_value": "Add value",
|
||||||
|
"empty_value": "Environment value is empty for the variable '{variable}' ",
|
||||||
"not_found": "Environment variable “{environment}” not found."
|
"not_found": "Environment variable “{environment}” not found."
|
||||||
},
|
},
|
||||||
"header": {
|
"header": {
|
||||||
@@ -440,8 +459,8 @@
|
|||||||
"confirm": "Confirm",
|
"confirm": "Confirm",
|
||||||
"customize_request": "Customize Request",
|
"customize_request": "Customize Request",
|
||||||
"edit_request": "Edit Request",
|
"edit_request": "Edit Request",
|
||||||
"share_request": "Share Request",
|
"import_export": "Import / Export",
|
||||||
"import_export": "Import / Export"
|
"share_request": "Share Request"
|
||||||
},
|
},
|
||||||
"mqtt": {
|
"mqtt": {
|
||||||
"already_subscribed": "You are already subscribed to this topic.",
|
"already_subscribed": "You are already subscribed to this topic.",
|
||||||
@@ -542,6 +561,7 @@
|
|||||||
"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",
|
||||||
@@ -582,6 +602,7 @@
|
|||||||
"account_description": "Customize your account settings.",
|
"account_description": "Customize your account settings.",
|
||||||
"account_email_description": "Your primary email address.",
|
"account_email_description": "Your primary email address.",
|
||||||
"account_name_description": "This is your display name.",
|
"account_name_description": "This is your display name.",
|
||||||
|
"additional": "Additional Settings",
|
||||||
"background": "Background",
|
"background": "Background",
|
||||||
"black_mode": "Black",
|
"black_mode": "Black",
|
||||||
"choose_language": "Choose language",
|
"choose_language": "Choose language",
|
||||||
@@ -626,17 +647,16 @@
|
|||||||
"use_experimental_url_bar": "Use experimental URL bar with environment highlighting",
|
"use_experimental_url_bar": "Use experimental URL bar with environment highlighting",
|
||||||
"user": "User",
|
"user": "User",
|
||||||
"verified_email": "Verified email",
|
"verified_email": "Verified email",
|
||||||
"additional": "Additional Settings",
|
|
||||||
"verify_email": "Verify email"
|
"verify_email": "Verify email"
|
||||||
},
|
},
|
||||||
"shared_requests": {
|
"shared_requests": {
|
||||||
"button": "Button",
|
"button": "Button",
|
||||||
"button_info": "Create a 'Run in Hoppscotch' button for your website, blog or a README.",
|
"button_info": "Create a 'Run in Hoppscotch' button for your website, blog or a README.",
|
||||||
"customize": "Customize",
|
|
||||||
"creating_widget": "Creating widget",
|
|
||||||
"copy_html": "Copy HTML",
|
"copy_html": "Copy HTML",
|
||||||
"copy_link": "Copy Link",
|
"copy_link": "Copy Link",
|
||||||
"copy_markdown": "Copy Markdown",
|
"copy_markdown": "Copy Markdown",
|
||||||
|
"creating_widget": "Creating widget",
|
||||||
|
"customize": "Customize",
|
||||||
"deleted": "Shared request deleted",
|
"deleted": "Shared request deleted",
|
||||||
"description": "Select a widget, you can change and customize this later",
|
"description": "Select a widget, you can change and customize this later",
|
||||||
"embed": "Embed",
|
"embed": "Embed",
|
||||||
@@ -697,8 +717,8 @@
|
|||||||
"save_request": "Save Request",
|
"save_request": "Save Request",
|
||||||
"save_to_collections": "Save to Collections",
|
"save_to_collections": "Save to Collections",
|
||||||
"send_request": "Send Request",
|
"send_request": "Send Request",
|
||||||
"show_code": "Generate code snippet",
|
|
||||||
"share_request": "Share Request",
|
"share_request": "Share Request",
|
||||||
|
"show_code": "Generate code snippet",
|
||||||
"title": "Request"
|
"title": "Request"
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
@@ -822,16 +842,16 @@
|
|||||||
"connection_error": "Failed to connect",
|
"connection_error": "Failed to connect",
|
||||||
"connection_failed": "Connection failed",
|
"connection_failed": "Connection failed",
|
||||||
"connection_lost": "Connection lost",
|
"connection_lost": "Connection lost",
|
||||||
"copied_to_clipboard": "Copied to clipboard",
|
|
||||||
"copied_interface_to_clipboard": "Copied {language} interface type to clipboard",
|
"copied_interface_to_clipboard": "Copied {language} interface type to clipboard",
|
||||||
|
"copied_to_clipboard": "Copied to clipboard",
|
||||||
"deleted": "Deleted",
|
"deleted": "Deleted",
|
||||||
"deprecated": "DEPRECATED",
|
"deprecated": "DEPRECATED",
|
||||||
"disabled": "Disabled",
|
"disabled": "Disabled",
|
||||||
"disconnected": "Disconnected",
|
"disconnected": "Disconnected",
|
||||||
"disconnected_from": "Disconnected from {name}",
|
"disconnected_from": "Disconnected from {name}",
|
||||||
"docs_generated": "Documentation generated",
|
"docs_generated": "Documentation generated",
|
||||||
"download_started": "Download started",
|
|
||||||
"download_failed": "Download failed",
|
"download_failed": "Download failed",
|
||||||
|
"download_started": "Download started",
|
||||||
"enabled": "Enabled",
|
"enabled": "Enabled",
|
||||||
"file_imported": "File imported",
|
"file_imported": "File imported",
|
||||||
"finished_in": "Finished in {duration} ms",
|
"finished_in": "Finished in {duration} ms",
|
||||||
@@ -883,6 +903,7 @@
|
|||||||
"query": "Query",
|
"query": "Query",
|
||||||
"schema": "Schema",
|
"schema": "Schema",
|
||||||
"shared_requests": "Shared Requests",
|
"shared_requests": "Shared Requests",
|
||||||
|
"share_tab_request": "Share tab request",
|
||||||
"socketio": "Socket.IO",
|
"socketio": "Socket.IO",
|
||||||
"sse": "SSE",
|
"sse": "SSE",
|
||||||
"tests": "Tests",
|
"tests": "Tests",
|
||||||
@@ -899,6 +920,7 @@
|
|||||||
"email_do_not_match": "Email doesn't match with your account details. Contact your team owner.",
|
"email_do_not_match": "Email doesn't match with your account details. Contact your team owner.",
|
||||||
"exit": "Exit Team",
|
"exit": "Exit Team",
|
||||||
"exit_disabled": "Only owner cannot exit the team",
|
"exit_disabled": "Only owner cannot exit the team",
|
||||||
|
"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 team ID. Contact your team owner.",
|
"invalid_id": "Invalid team ID. Contact your team owner.",
|
||||||
@@ -935,13 +957,12 @@
|
|||||||
"not_found": "Team not found. Contact your team owner.",
|
"not_found": "Team not found. Contact your team owner.",
|
||||||
"not_valid_viewer": "You are not a valid viewer. Contact your team 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",
|
||||||
"success_invites": "Success invites",
|
|
||||||
"failed_invites": "Failed invites",
|
|
||||||
"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": "Team saved",
|
"saved": "Team saved",
|
||||||
"select_a_team": "Select a team",
|
"select_a_team": "Select a team",
|
||||||
|
"success_invites": "Success invites",
|
||||||
"title": "Teams",
|
"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 team."
|
"we_sent_invite_link_description": "Ask all invitees to check their inbox. Click on the link to join the team."
|
||||||
@@ -974,4 +995,4 @@
|
|||||||
"team": "Team Workspace",
|
"team": "Team Workspace",
|
||||||
"title": "Workspaces"
|
"title": "Workspaces"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"action": {
|
"action": {
|
||||||
|
"add": "Add",
|
||||||
"autoscroll": "Desplazamiento automático",
|
"autoscroll": "Desplazamiento automático",
|
||||||
"cancel": "Cancelar",
|
"cancel": "Cancelar",
|
||||||
"choose_file": "Seleccionar archivo",
|
"choose_file": "Seleccionar archivo",
|
||||||
@@ -10,6 +11,7 @@
|
|||||||
"connect": "Conectar",
|
"connect": "Conectar",
|
||||||
"connecting": "Conectando",
|
"connecting": "Conectando",
|
||||||
"copy": "Copiar",
|
"copy": "Copiar",
|
||||||
|
"create": "Create",
|
||||||
"delete": "Borrar",
|
"delete": "Borrar",
|
||||||
"disconnect": "Desconectar",
|
"disconnect": "Desconectar",
|
||||||
"dismiss": "Descartar",
|
"dismiss": "Descartar",
|
||||||
@@ -31,6 +33,7 @@
|
|||||||
"open_workspace": "Abrir espacio de trabajo",
|
"open_workspace": "Abrir espacio de trabajo",
|
||||||
"paste": "Pegar",
|
"paste": "Pegar",
|
||||||
"prettify": "Embellecer",
|
"prettify": "Embellecer",
|
||||||
|
"properties": "Properties",
|
||||||
"remove": "Eliminar",
|
"remove": "Eliminar",
|
||||||
"rename": "Rename",
|
"rename": "Rename",
|
||||||
"restore": "Restaurar",
|
"restore": "Restaurar",
|
||||||
@@ -39,6 +42,7 @@
|
|||||||
"scroll_to_top": "Desplazar hacia arriba",
|
"scroll_to_top": "Desplazar hacia arriba",
|
||||||
"search": "Buscar",
|
"search": "Buscar",
|
||||||
"send": "Enviar",
|
"send": "Enviar",
|
||||||
|
"share": "Share",
|
||||||
"start": "Comenzar",
|
"start": "Comenzar",
|
||||||
"starting": "Iniciando",
|
"starting": "Iniciando",
|
||||||
"stop": "Detener",
|
"stop": "Detener",
|
||||||
@@ -57,7 +61,9 @@
|
|||||||
"app": {
|
"app": {
|
||||||
"chat_with_us": "Habla con nosotros",
|
"chat_with_us": "Habla con nosotros",
|
||||||
"contact_us": "Contáctanos",
|
"contact_us": "Contáctanos",
|
||||||
|
"cookies": "Cookies",
|
||||||
"copy": "Copiar",
|
"copy": "Copiar",
|
||||||
|
"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.",
|
||||||
@@ -73,6 +79,7 @@
|
|||||||
"keyboard_shortcuts": "Atajos de teclado",
|
"keyboard_shortcuts": "Atajos de teclado",
|
||||||
"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",
|
||||||
"options": "Options",
|
"options": "Options",
|
||||||
"proxy_privacy_policy": "Política de privacidad de proxy",
|
"proxy_privacy_policy": "Política de privacidad de proxy",
|
||||||
"reload": "Recargar",
|
"reload": "Recargar",
|
||||||
@@ -112,10 +119,27 @@
|
|||||||
},
|
},
|
||||||
"authorization": {
|
"authorization": {
|
||||||
"generate_token": "Generar token",
|
"generate_token": "Generar token",
|
||||||
|
"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": "Inherited from {auth} from Parent Collection {collection} ",
|
||||||
"learn": "Aprender",
|
"learn": "Aprender",
|
||||||
|
"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": "Pasar por",
|
"pass_key_by": "Pasar por",
|
||||||
"password": "Contraseña",
|
"password": "Contraseña",
|
||||||
|
"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"
|
||||||
@@ -124,6 +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": "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",
|
||||||
@@ -132,6 +157,8 @@
|
|||||||
"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": "Collection Properties",
|
||||||
|
"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",
|
||||||
@@ -151,6 +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": "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.",
|
||||||
@@ -162,6 +190,24 @@
|
|||||||
"open_request_in_new_tab": "Open request in new tab",
|
"open_request_in_new_tab": "Open request in new tab",
|
||||||
"set_environment_variable": "Set as variable"
|
"set_environment_variable": "Set as variable"
|
||||||
},
|
},
|
||||||
|
"cookies": {
|
||||||
|
"modal": {
|
||||||
|
"cookie_expires": "Expires",
|
||||||
|
"cookie_name": "Name",
|
||||||
|
"cookie_path": "Path",
|
||||||
|
"cookie_string": "Cookie string",
|
||||||
|
"cookie_value": "Value",
|
||||||
|
"empty_domain": "Domain is empty",
|
||||||
|
"empty_domains": "Domain list is empty",
|
||||||
|
"enter_cookie_string": "Enter cookie string",
|
||||||
|
"interceptor_no_support": "Your currently selected interceptor does not support cookies. Select a different Interceptor and try again.",
|
||||||
|
"managed_tab": "Managed",
|
||||||
|
"new_domain_name": "New domain name",
|
||||||
|
"no_cookies_in_domain": "No cookies set for this domain",
|
||||||
|
"raw_tab": "Raw",
|
||||||
|
"set": "Set a cookie"
|
||||||
|
}
|
||||||
|
},
|
||||||
"count": {
|
"count": {
|
||||||
"header": "Encabezado {count}",
|
"header": "Encabezado {count}",
|
||||||
"message": "Mensaje {count}",
|
"message": "Mensaje {count}",
|
||||||
@@ -192,11 +238,13 @@
|
|||||||
"profile": "Iniciar sesión para ver tu perfil",
|
"profile": "Iniciar sesión para ver tu perfil",
|
||||||
"protocols": "Los protocolos están vacíos",
|
"protocols": "Los protocolos están vacíos",
|
||||||
"schema": "Conectarse a un punto final de GraphQL",
|
"schema": "Conectarse a un punto final de GraphQL",
|
||||||
"shortcodes": "Aún no se han creado Shortcodes",
|
"shared_requests": "Shared requests are empty",
|
||||||
|
"shared_requests_logout": "Login to view your shared requests or create a new one",
|
||||||
"subscription": "Subscriptions are empty",
|
"subscription": "Subscriptions are empty",
|
||||||
"team_name": "Nombre del equipo vacío",
|
"team_name": "Nombre del equipo vacío",
|
||||||
"teams": "Los equipos están vacíos",
|
"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"
|
||||||
},
|
},
|
||||||
"environment": {
|
"environment": {
|
||||||
"add_to_global": "Añadir a Global",
|
"add_to_global": "Añadir a Global",
|
||||||
@@ -209,6 +257,7 @@
|
|||||||
"empty_variables": "No variables",
|
"empty_variables": "No variables",
|
||||||
"global": "Global",
|
"global": "Global",
|
||||||
"global_variables": "Global variables",
|
"global_variables": "Global variables",
|
||||||
|
"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": "Environment variables",
|
"list": "Environment variables",
|
||||||
"my_environments": "Mis entornos",
|
"my_environments": "Mis entornos",
|
||||||
@@ -232,8 +281,10 @@
|
|||||||
"variable_list": "Lista de variables"
|
"variable_list": "Lista de variables"
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
|
"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": "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:",
|
||||||
@@ -249,9 +300,12 @@
|
|||||||
"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 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 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.",
|
||||||
"proxy_error": "Proxy error",
|
"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",
|
||||||
@@ -260,6 +314,7 @@
|
|||||||
"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": "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"
|
||||||
@@ -286,6 +341,9 @@
|
|||||||
"subscriptions": "Suscripciones",
|
"subscriptions": "Suscripciones",
|
||||||
"switch_connection": "Switch connection"
|
"switch_connection": "Switch connection"
|
||||||
},
|
},
|
||||||
|
"graphql_collections": {
|
||||||
|
"title": "GraphQL Collections"
|
||||||
|
},
|
||||||
"group": {
|
"group": {
|
||||||
"time": "Tiempo",
|
"time": "Tiempo",
|
||||||
"url": "URL"
|
"url": "URL"
|
||||||
@@ -297,6 +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": " This authorization will be set for every request in this collection.",
|
||||||
|
"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.",
|
||||||
@@ -316,7 +376,10 @@
|
|||||||
"import": {
|
"import": {
|
||||||
"collections": "Importar colecciones",
|
"collections": "Importar colecciones",
|
||||||
"curl": "Importar cURL",
|
"curl": "Importar cURL",
|
||||||
|
"environments_from_gist": "Import From Gist",
|
||||||
|
"environments_from_gist_description": "Import Hoppscotch Environments From Gist",
|
||||||
"failed": "Importación fallida",
|
"failed": "Importación fallida",
|
||||||
|
"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",
|
||||||
@@ -331,11 +394,17 @@
|
|||||||
"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": "Import GraphQL Collections From Gist",
|
||||||
|
"hoppscotch_environment": "Hoppscotch Environment",
|
||||||
|
"hoppscotch_environment_description": "Import Hoppscotch Environment JSON file",
|
||||||
"import_from_url_invalid_fetch": "Couldn't get data from the url",
|
"import_from_url_invalid_fetch": "Couldn't get data from the url",
|
||||||
"import_from_url_invalid_file_format": "Error while importing collections",
|
"import_from_url_invalid_file_format": "Error while importing collections",
|
||||||
"import_from_url_invalid_type": "Unsupported type. accepted values are 'hoppscotch', 'openapi', 'postman', 'insomnia'",
|
"import_from_url_invalid_type": "Unsupported type. accepted values are 'hoppscotch', 'openapi', 'postman', 'insomnia'",
|
||||||
"import_from_url_success": "Collections Imported",
|
"import_from_url_success": "Collections Imported",
|
||||||
|
"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": "Postman Environment",
|
||||||
|
"postman_environment_description": "Import Postman Environment from a JSON file",
|
||||||
"title": "Importar"
|
"title": "Importar"
|
||||||
},
|
},
|
||||||
"inspections": {
|
"inspections": {
|
||||||
@@ -373,8 +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": "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": "Share Request"
|
||||||
},
|
},
|
||||||
"mqtt": {
|
"mqtt": {
|
||||||
"already_subscribed": "Ya estás suscrito a este tema.",
|
"already_subscribed": "Ya estás suscrito a este tema.",
|
||||||
@@ -449,13 +520,14 @@
|
|||||||
"structured": "Estructurado",
|
"structured": "Estructurado",
|
||||||
"text": "Texto"
|
"text": "Texto"
|
||||||
},
|
},
|
||||||
"copy_link": "Copiar enlace",
|
|
||||||
"different_collection": "No se pueden reordenar solicitudes de diferentes colecciones",
|
"different_collection": "No se pueden reordenar solicitudes de diferentes colecciones",
|
||||||
"duplicated": "Solicitud duplicada",
|
"duplicated": "Solicitud duplicada",
|
||||||
"duration": "Duración",
|
"duration": "Duración",
|
||||||
"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": "Go to Authorization tab",
|
||||||
|
"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",
|
||||||
@@ -480,12 +552,14 @@
|
|||||||
"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": "Share Request",
|
||||||
"stop": "Stop",
|
"stop": "Stop",
|
||||||
"title": "Solicitud",
|
"title": "Solicitud",
|
||||||
"type": "Tipo de solicitud",
|
"type": "Tipo de solicitud",
|
||||||
"url": "URL",
|
"url": "URL",
|
||||||
"variables": "Variables",
|
"variables": "Variables",
|
||||||
"view_my_links": "Ver mis enlaces"
|
"view_my_links": "Ver mis enlaces",
|
||||||
|
"copy_link": "Copiar enlace"
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"audio": "Audio",
|
"audio": "Audio",
|
||||||
@@ -513,6 +587,7 @@
|
|||||||
"account_description": "Personaliza la configuración de tu cuenta.",
|
"account_description": "Personaliza la configuración de tu cuenta.",
|
||||||
"account_email_description": "Tu dirección de correo electrónico principal.",
|
"account_email_description": "Tu dirección de correo electrónico principal.",
|
||||||
"account_name_description": "Este es tu nombre para mostrar.",
|
"account_name_description": "Este es tu nombre para mostrar.",
|
||||||
|
"additional": "Additional Settings",
|
||||||
"background": "Fondo",
|
"background": "Fondo",
|
||||||
"black_mode": "Negro",
|
"black_mode": "Negro",
|
||||||
"choose_language": "Elegir idioma",
|
"choose_language": "Elegir idioma",
|
||||||
@@ -559,14 +634,31 @@
|
|||||||
"verified_email": "Correo electrónico verificado",
|
"verified_email": "Correo electrónico verificado",
|
||||||
"verify_email": "Verificar correo electrónico"
|
"verify_email": "Verificar correo electrónico"
|
||||||
},
|
},
|
||||||
"shortcodes": {
|
"shared_requests": {
|
||||||
"actions": "Acciones",
|
"button": "Button",
|
||||||
"created_on": "Creado el",
|
"button_info": "Create a 'Run in Hoppscotch' button for your website, blog or a README.",
|
||||||
"deleted": "Código corto eliminado",
|
"copy_html": "Copy HTML",
|
||||||
"method": "Método",
|
"copy_link": "Copy Link",
|
||||||
"not_found": "Shortcode no encontrado",
|
"copy_markdown": "Copy Markdown",
|
||||||
"short_code": "Short code",
|
"creating_widget": "Creating widget",
|
||||||
"url": "URL"
|
"customize": "Customize",
|
||||||
|
"deleted": "Shared request deleted",
|
||||||
|
"description": "Select a widget, you can change and customize this later",
|
||||||
|
"embed": "Embed",
|
||||||
|
"embed_info": "Add a mini 'Hoppscotch API Playground' to your website, blog or documentation.",
|
||||||
|
"link": "Link",
|
||||||
|
"link_info": "Create a shareable link to share with anyone on the internet with view access.",
|
||||||
|
"modified": "Shared request modified",
|
||||||
|
"not_found": "Shared request not found",
|
||||||
|
"open_new_tab": "Open in new tab",
|
||||||
|
"preview": "Preview",
|
||||||
|
"run_in_hoppscotch": "Run in Hoppscotch",
|
||||||
|
"theme": {
|
||||||
|
"dark": "Dark",
|
||||||
|
"light": "Light",
|
||||||
|
"system": "System",
|
||||||
|
"title": "Theme"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"shortcut": {
|
"shortcut": {
|
||||||
"general": {
|
"general": {
|
||||||
@@ -596,7 +688,6 @@
|
|||||||
"title": "Others"
|
"title": "Others"
|
||||||
},
|
},
|
||||||
"request": {
|
"request": {
|
||||||
"copy_request_link": "Copiar enlace de solicitud",
|
|
||||||
"delete_method": "Seleccionar método DELETE",
|
"delete_method": "Seleccionar método DELETE",
|
||||||
"get_method": "Seleccionar método GET",
|
"get_method": "Seleccionar método GET",
|
||||||
"head_method": "Seleccionar método HEAD",
|
"head_method": "Seleccionar método HEAD",
|
||||||
@@ -611,8 +702,10 @@
|
|||||||
"save_request": "Save Request",
|
"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": "Share Request",
|
||||||
"show_code": "Generate code snippet",
|
"show_code": "Generate code snippet",
|
||||||
"title": "Solicitud"
|
"title": "Solicitud",
|
||||||
|
"copy_request_link": "Copiar enlace de solicitud"
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"copy": "Copiar la respuesta al portapapeles",
|
"copy": "Copiar la respuesta al portapapeles",
|
||||||
@@ -735,6 +828,7 @@
|
|||||||
"connection_error": "Failed to connect",
|
"connection_error": "Failed to connect",
|
||||||
"connection_failed": "Error de conexión",
|
"connection_failed": "Error de conexión",
|
||||||
"connection_lost": "Conexión perdida",
|
"connection_lost": "Conexión perdida",
|
||||||
|
"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",
|
||||||
@@ -742,10 +836,12 @@
|
|||||||
"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": "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": "Hide",
|
||||||
"history_deleted": "Historial eliminado",
|
"history_deleted": "Historial eliminado",
|
||||||
"linewrap": "Envolver líneas",
|
"linewrap": "Envolver líneas",
|
||||||
"loading": "Cargando...",
|
"loading": "Cargando...",
|
||||||
@@ -756,6 +852,7 @@
|
|||||||
"published_error": "Algo ha ido mal al publicar el mensaje: {topic} al tema: {message}",
|
"published_error": "Algo ha ido mal al publicar el mensaje: {topic} al tema: {message}",
|
||||||
"published_message": "Mensaje publicado: {mensaje} 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",
|
||||||
"subscribed_failed": "Error al suscribirse al tema: {topic}",
|
"subscribed_failed": "Error al suscribirse al tema: {topic}",
|
||||||
"subscribed_success": "Suscrito con éxito al tema: {topic}",
|
"subscribed_success": "Suscrito con éxito al tema: {topic}",
|
||||||
"unsubscribed_failed": "Error al darse de baja del tema: {topic}",
|
"unsubscribed_failed": "Error al darse de baja del tema: {topic}",
|
||||||
@@ -791,6 +888,7 @@
|
|||||||
"queries": "Consultas",
|
"queries": "Consultas",
|
||||||
"query": "Consulta",
|
"query": "Consulta",
|
||||||
"schema": "Esquema",
|
"schema": "Esquema",
|
||||||
|
"shared_requests": "Shared Requests",
|
||||||
"socketio": "Socket.IO",
|
"socketio": "Socket.IO",
|
||||||
"sse": "SSE",
|
"sse": "SSE",
|
||||||
"tests": "Pruebas",
|
"tests": "Pruebas",
|
||||||
@@ -807,6 +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": "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.",
|
||||||
@@ -848,6 +947,7 @@
|
|||||||
"same_target_destination": "Same target and destination",
|
"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": "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 tu bandeja de entrada. Haz 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."
|
||||||
@@ -879,5 +979,14 @@
|
|||||||
"personal": "Mi espacio de trabajo",
|
"personal": "Mi espacio de trabajo",
|
||||||
"team": "Espacio de trabajo en equipo",
|
"team": "Espacio de trabajo en equipo",
|
||||||
"title": "Espacios de trabajo"
|
"title": "Espacios de trabajo"
|
||||||
|
},
|
||||||
|
"shortcodes": {
|
||||||
|
"actions": "Acciones",
|
||||||
|
"created_on": "Creado el",
|
||||||
|
"deleted": "Código corto eliminado",
|
||||||
|
"method": "Método",
|
||||||
|
"not_found": "Shortcode no encontrado",
|
||||||
|
"short_code": "Short code",
|
||||||
|
"url": "URL"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user