Compare commits

...

57 Commits

Author SHA1 Message Date
ankitsridhar16
596ea7e364 chore: update variable names 2023-06-22 23:35:58 +05:30
ankitsridhar16
2c7f5f6173 fix: add check for existing invitation for the invitee and revoke 2023-06-22 23:35:58 +05:30
ankitsridhar16
f19dc700ef refactor: add service method to take invitee email and team ID as string to fetch invitation 2023-06-22 23:35:58 +05:30
Anwarul Islam
039de8015f fix: graphql authorization headers (#3136) 2023-06-22 23:32:23 +05:30
Nivedin
f67b366b90 fix: unified bg color in collection tree (#3155) 2023-06-22 00:38:28 +05:30
Omer Baflah
77e8a36ab0 fix: correct typos (#3153) 2023-06-22 00:35:57 +05:30
Webysther Sperandio
d7cc9f5dbc feat: custom location on admin redirect to base (#3103) 2023-06-21 00:13:40 +05:30
Balázs Úr
4ba135f3b9 chore(i18n): updated hungarian translation (#3151) 2023-06-20 14:28:53 +05:30
Nivedin
24894e05dc fix: shortcode resolution screen is stuck on invalid shortcodes (#3142)
Co-authored-by: Andrew Bastin <andrewbastin.k@gmail.com>
2023-06-19 14:04:07 +05:30
Balu Babu
84b0c30d64 fix: fixed issue with team-invitations and new user accounts (#3137) 2023-06-15 17:15:06 +05:30
Andrew Bastin
e3dd9e99a1 chore: bump version to 2023.4.6 2023-06-12 10:43:44 +05:30
Hoai-Thu Vuong
e3091cb6db chore(i18n): fix typo in translation of clear_all (#3133) 2023-06-12 10:31:58 +05:30
Akash K
270f796683 fix: fix url getting overridden when query params are present (#3130) 2023-06-09 21:53:55 +05:30
Anwarul Islam
24c6bce02d fix: failed to execute 'observe' on 'IntersectionObserver' (#3122) 2023-06-09 09:40:09 +05:30
Anwarul Islam
2db567589f fix: collection request name edit issue (#3115)
Co-authored-by: Liyas Thomas <liyascthomas@gmail.com>
Co-authored-by: Nivedin <nivedinp@gmail.com>
2023-06-09 09:36:41 +05:30
Liyas Thomas
1fe83ebdc8 chore: updated i18n strings (#3106) 2023-06-07 23:59:04 +05:30
islamzeki
8320d4f222 chore(i18n): update tr.json 2023-06-07 23:56:49 +05:30
Liyas Thomas
e76c1bc64c fix: stack order of tab inside environment selector (#3108) 2023-06-07 23:47:24 +05:30
Nivedin
1f3f8464ea fix: team environment lost when route changes (#3113)
Co-authored-by: Liyas Thomas <liyascthomas@gmail.com>
2023-06-07 23:46:09 +05:30
Liyas Thomas
e75391cdf1 chore: updated icon with correct size (#3105) 2023-06-04 23:46:47 -04:00
Andrew Bastin
a213c0c26c chore: bump version to 2023.4.5 2023-06-04 23:41:01 -04:00
Andrew Bastin
15424903ed fix: stop logging DATABASE_URL in logs 2023-06-04 23:33:32 -04:00
Andrew Bastin
1cce117b0a chore: bump version to 2023.4.4 2023-06-02 11:06:51 -04:00
Liyas Thomas
abc7b4b6f3 chore: improve mobile responsiveness on environment selector (#3100) 2023-06-02 10:56:18 -04:00
Ankit Sridhar
05e32ef9e4 fix: update team invitation link to domain specified in .env [HBE-202] (#3096) 2023-05-31 10:36:34 -04:00
Nivedin
f0a1fc319c fix: sync popup firing multiple times (#3063) 2023-05-30 23:36:37 -04:00
Allen Zhang
385cabc6aa fix: update package.json script (#3083) 2023-05-30 17:50:47 -04:00
Liyas Thomas
397b26a9f3 chore: environment selector with new ux (#3052)
Co-authored-by: Nivedin <nivedinp@gmail.com>
2023-05-30 17:47:37 -04:00
Nivedin
9a40058329 fix: set team environment from test (#3059) 2023-05-30 17:38:28 -04:00
Akash K
7ec2380ed5 chore: update wss url to ws in .env.example (#3081) 2023-05-29 20:23:02 -04:00
安正超
3d4825305d chore(i18n): Update zh-CN translations (#3068) 2023-05-29 20:19:43 -04:00
Nivedin
26e564288b feat: prettify XML response (#3079) 2023-05-29 20:18:19 -04:00
Sawako
385a587cfd feat(locales): fix and update es (spanish) locale (#3086) 2023-05-29 20:15:39 -04:00
Liyas Thomas
215df02783 chore: make style sheets consistent (#3074) 2023-05-29 20:12:58 -04:00
Liyas Thomas
7c7ed68b20 fix: 403 forbidden error when trying to load profile picture (#3045)
Co-authored-by: Liyas Thomas <liyascthomas@gmail.com>
Co-authored-by: Nivedin <53208152+nivedin@users.noreply.github.com>
Co-authored-by: Anwarul Islam <anwaarulislaam@gmail.com>
fix: pane layout broken when wrap line is off (#3027)
Fix issue with disappearing tab when opening request tabs with long text in body/script (#3030)
2023-05-24 16:23:44 -04:00
Anwarul Islam
c910a0314a feat: rename request by double clicking its name on tabs (#3057)
Co-authored-by: Liyas Thomas <liyascthomas@gmail.com>
2023-05-24 16:18:19 -04:00
Liyas Thomas
ddaec1b9ac feat: add support to audio and video API responses (#3044) 2023-05-24 16:16:14 -04:00
Anwarul Islam
9dbdef9286 fix: dead key issue in mac (#3058) 2023-05-23 16:41:37 -04:00
Bart Kerkvliet
e77eef1532 Fix typo, rename cuttentTime to currentTime (#3053) 2023-05-23 16:38:01 -04:00
Liyas Thomas
1fe0b8861d fix: don't cut off the part that's already been typed (#3054) 2023-05-23 16:36:02 -04:00
Andrew Bastin
aeb9172144 fix: analytics logging behavior being incorrect (#3064) 2023-05-23 16:34:28 -04:00
Mir Arif Hasan
1b413e2f47 fix: timing dependency on test case (#3070) 2023-05-23 16:32:39 -04:00
Andrew Bastin
d6c8400116 chore: bump version to 2023.4.3 2023-05-11 17:05:28 +05:30
Andrew Bastin
4a0205e622 fix: environment section being broken 2023-05-11 16:34:57 +05:30
Andrew Bastin
c2520006ac chore: bump version to 2023.4.2 2023-05-11 14:09:38 +05:30
Nivedin
99817fd8bd fix: reset envs when user switches workspaces (#3039)
Co-authored-by: Liyas Thomas <liyascthomas@gmail.com>
2023-05-11 14:09:38 +05:30
Anwarul Islam
3f35fedd9d fix: tab system breaks when a new tab is created while waiting for response in another tab (#3031) 2023-05-11 14:09:38 +05:30
Akash K
b7c2d13992 fix: invalid environment index can break the app (#3041) 2023-05-11 14:09:38 +05:30
Akash K
a6426587fb chore: add onCodemirrorInstanceMount hook to platform (#3043) 2023-05-11 14:09:38 +05:30
Anwarul Islam
5f68356278 feat: scroll to show the new active tab header (#3013)
Co-authored-by: Liyas Thomas <liyascthomas@gmail.com>
2023-05-11 14:09:38 +05:30
Mir Arif Hasan
08f61e7408 fix: magic link URL (#3028) 2023-05-11 14:09:38 +05:30
Mir Arif Hasan
9beda15f00 fix: returning response from authCookieHandler (#3025) 2023-05-11 14:09:38 +05:30
Anwarul Islam
09d1663f81 feat: picture component moved to hoppscotch-ui (#3032) 2023-05-11 14:09:38 +05:30
Anwarul Islam
f43b6e7cff Fix issue with disappearing tab when opening request tabs with long text in body/script (#3030)
Co-authored-by: Liyas Thomas <liyascthomas@gmail.com>
2023-05-11 14:09:38 +05:30
Akash K
6581eb4fd1 fix: update the hoppscotch-sh-admin magic link route to match hoppscotch-app (#3029) 2023-05-11 14:09:38 +05:30
Nivedin
caedfe5c1e fix: pane layout broken when wrap line is off (#3027)
Co-authored-by: Liyas Thomas <liyascthomas@gmail.com>
2023-05-11 14:09:38 +05:30
Liyas Thomas
f6a234aaf9 docs: updated screenshots (#3046) 2023-05-10 19:17:47 +05:30
119 changed files with 2580 additions and 1182 deletions

View File

@@ -51,7 +51,7 @@ VITE_ADMIN_URL=http://localhost:3100
# Backend URLs # Backend URLs
VITE_BACKEND_GQL_URL=http://localhost:3170/graphql VITE_BACKEND_GQL_URL=http://localhost:3170/graphql
VITE_BACKEND_WS_URL=wss://localhost:3170/graphql VITE_BACKEND_WS_URL=ws://localhost:3170/graphql
VITE_BACKEND_API_URL=http://localhost:3170/v1 VITE_BACKEND_API_URL=http://localhost:3170/v1
# Terms Of Service And Privacy Policy Links (Optional) # Terms Of Service And Privacy Policy Links (Optional)

42
.github/workflows/ui.yml vendored Normal file
View File

@@ -0,0 +1,42 @@
name: Deploy to Netlify (ui)
on:
push:
branches: [main]
# run this workflow only if an update is made to the ui package
paths:
- "packages/hoppscotch-ui/**"
workflow_dispatch:
jobs:
deploy:
name: Deploy
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup environment
run: mv .env.example .env
- name: Setup pnpm
uses: pnpm/action-setup@v2.2.4
with:
version: 8
run_install: true
- name: Setup node
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node }}
cache: pnpm
- name: Build site
run: pnpm run generate-ui
# Deploy the ui site with netlify-cli
- name: Deploy to Netlify (ui)
run: npx netlify-cli deploy --dir=packages/hoppscotch-ui/.histoire/dist --prod
env:
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_UI_SITE_ID }}
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}

View File

@@ -11,7 +11,7 @@
"dev": "pnpm -r do-dev", "dev": "pnpm -r do-dev",
"gen-gql": "cross-env GQL_SCHEMA_EMIT_LOCATION='../../../gql-gen/backend-schema.gql' pnpm -r generate-gql-sdl", "gen-gql": "cross-env GQL_SCHEMA_EMIT_LOCATION='../../../gql-gen/backend-schema.gql' pnpm -r generate-gql-sdl",
"generate": "pnpm -r do-build-prod", "generate": "pnpm -r do-build-prod",
"start": "http-server packages/hoppscotch-web/dist -p 3000", "start": "http-server packages/hoppscotch-selfhost-web/dist -p 3000",
"lint": "pnpm -r do-lint", "lint": "pnpm -r do-lint",
"typecheck": "pnpm -r do-typecheck", "typecheck": "pnpm -r do-typecheck",
"lintfix": "pnpm -r do-lintfix", "lintfix": "pnpm -r do-lintfix",

View File

@@ -1,6 +1,6 @@
{ {
"name": "hoppscotch-backend", "name": "hoppscotch-backend",
"version": "2023.4.1", "version": "2023.4.6",
"description": "", "description": "",
"author": "", "author": "",
"private": true, "private": true,

View File

@@ -236,11 +236,11 @@ export class AdminService {
const user = await this.userService.findUserByEmail(userEmail); const user = await this.userService.findUserByEmail(userEmail);
if (O.isNone(user)) return E.left(USER_NOT_FOUND); if (O.isNone(user)) return E.left(USER_NOT_FOUND);
const isUserAlreadyMember = await this.teamService.getTeamMemberTE( const teamMember = await this.teamService.getTeamMemberTE(
teamID, teamID,
user.value.uid, user.value.uid,
)(); )();
if (E.left(isUserAlreadyMember)) { if (E.isLeft(teamMember)) {
const addedUser = await this.teamService.addMemberToTeamWithEmail( const addedUser = await this.teamService.addMemberToTeamWithEmail(
teamID, teamID,
userEmail, userEmail,
@@ -248,6 +248,18 @@ export class AdminService {
); );
if (E.isLeft(addedUser)) return E.left(addedUser.left); if (E.isLeft(addedUser)) return E.left(addedUser.left);
const userInvitation =
await this.teamInvitationService.getTeamInviteByEmailAndTeamID(
userEmail,
teamID,
);
if (E.isRight(userInvitation)) {
await this.teamInvitationService.revokeInvitation(
userInvitation.right.id,
)();
}
return E.right(addedUser.right); return E.right(addedUser.right);
} }

View File

@@ -232,7 +232,7 @@ export class AuthService {
template: 'code-your-own', template: 'code-your-own',
variables: { variables: {
inviteeEmail: email, inviteeEmail: email,
magicLink: `${url}/magic-link?token=${generatedTokens.token}`, magicLink: `${url}/enter?token=${generatedTokens.token}`,
}, },
}); });

View File

@@ -63,7 +63,7 @@ export const authCookieHandler = (
}); });
if (!redirect) { if (!redirect) {
res.status(HttpStatus.OK).send(); return res.status(HttpStatus.OK).send();
} }
// check to see if redirectUrl is a whitelisted url // check to see if redirectUrl is a whitelisted url
@@ -72,7 +72,7 @@ export const authCookieHandler = (
// if it is not redirect by default to REDIRECT_URL // if it is not redirect by default to REDIRECT_URL
redirectUrl = process.env.REDIRECT_URL; redirectUrl = process.env.REDIRECT_URL;
res.status(HttpStatus.OK).redirect(redirectUrl); return res.status(HttpStatus.OK).redirect(redirectUrl);
}; };
/** /**

View File

@@ -23,7 +23,7 @@ export const AUTH_FAIL = 'auth/fail';
export const JSON_INVALID = 'json_invalid'; export const JSON_INVALID = 'json_invalid';
/** /**
* Tried to delete an user data document from fb firestore but failed. * Tried to delete a user data document from fb firestore but failed.
* (FirebaseService) * (FirebaseService)
*/ */
export const USER_FB_DOCUMENT_DELETION_FAILED = export const USER_FB_DOCUMENT_DELETION_FAILED =
@@ -231,7 +231,7 @@ export const TEAM_COLL_INVALID_JSON = 'team_coll/invalid_json';
export const TEAM_NOT_OWNER = 'team_coll/team_not_owner' as const; export const TEAM_NOT_OWNER = 'team_coll/team_not_owner' as const;
/** /**
* Tried to perform 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)
*/ */
export const TEAM_REQ_NOT_REQUIRED_ROLE = 'team_req/not_required_role'; export const TEAM_REQ_NOT_REQUIRED_ROLE = 'team_req/not_required_role';
@@ -262,7 +262,7 @@ export const TEAM_REQ_REORDERING_FAILED = 'team_req/reordering_failed' as const;
export const SENDER_EMAIL_INVALID = 'mailer/sender_email_invalid' as const; export const SENDER_EMAIL_INVALID = 'mailer/sender_email_invalid' as const;
/** /**
* Tried to perform action on a request when the user is not even member of the team * Tried to perform an action on a request when the user is not even a member of the team
* (GqlRequestTeamMemberGuard, GqlCollectionTeamMemberGuard) * (GqlRequestTeamMemberGuard, GqlCollectionTeamMemberGuard)
*/ */
export const TEAM_REQ_NOT_MEMBER = 'team_req/not_member'; export const TEAM_REQ_NOT_MEMBER = 'team_req/not_member';
@@ -307,7 +307,7 @@ export const SHORTCODE_INVALID_JSON = 'shortcode/invalid_json' as const;
export const SHORTCODE_ALREADY_EXISTS = 'shortcode/already_exists' as const; export const SHORTCODE_ALREADY_EXISTS = 'shortcode/already_exists' as const;
/** /**
* Invalid or non-existent TEAM ENVIRONMMENT ID * Invalid or non-existent TEAM ENVIRONMENT ID
* (TeamEnvironmentsService) * (TeamEnvironmentsService)
*/ */
export const TEAM_ENVIRONMENT_NOT_FOUND = 'team_environment/not_found' as const; export const TEAM_ENVIRONMENT_NOT_FOUND = 'team_environment/not_found' as const;
@@ -340,7 +340,7 @@ export const USER_SETTINGS_NULL_SETTINGS =
'user_settings/null_settings' as const; 'user_settings/null_settings' as const;
/* /*
* Global environment doesnt exists for the user * Global environment doesn't exist for the user
* (UserEnvironmentsService) * (UserEnvironmentsService)
*/ */
export const USER_ENVIRONMENT_GLOBAL_ENV_DOES_NOT_EXISTS = export const USER_ENVIRONMENT_GLOBAL_ENV_DOES_NOT_EXISTS =

View File

@@ -9,7 +9,6 @@ import { emitGQLSchemaFile } from './gql-schema';
async function bootstrap() { async function bootstrap() {
console.log(`Running in production: ${process.env.PRODUCTION}`); console.log(`Running in production: ${process.env.PRODUCTION}`);
console.log(`Port: ${process.env.PORT}`); console.log(`Port: ${process.env.PORT}`);
console.log(`Database: ${process.env.DATABASE_URL}`);
const app = await NestFactory.create(AppModule); const app = await NestFactory.create(AppModule);

View File

@@ -3,6 +3,7 @@ import * as T from 'fp-ts/Task';
import * as O from 'fp-ts/Option'; import * as O from 'fp-ts/Option';
import * as TO from 'fp-ts/TaskOption'; import * as TO from 'fp-ts/TaskOption';
import * as TE from 'fp-ts/TaskEither'; import * as TE from 'fp-ts/TaskEither';
import * as E from 'fp-ts/Either';
import { pipe, flow, constVoid } from 'fp-ts/function'; import { pipe, flow, constVoid } from 'fp-ts/function';
import { PrismaService } from 'src/prisma/prisma.service'; import { PrismaService } from 'src/prisma/prisma.service';
import { Team, TeamMemberRole } from 'src/team/team.model'; import { Team, TeamMemberRole } from 'src/team/team.model';
@@ -10,6 +11,7 @@ import { Email } from 'src/types/Email';
import { User } from 'src/user/user.model'; import { User } from 'src/user/user.model';
import { TeamService } from 'src/team/team.service'; import { TeamService } from 'src/team/team.service';
import { import {
INVALID_EMAIL,
TEAM_INVITE_ALREADY_MEMBER, TEAM_INVITE_ALREADY_MEMBER,
TEAM_INVITE_EMAIL_DO_NOT_MATCH, TEAM_INVITE_EMAIL_DO_NOT_MATCH,
TEAM_INVITE_MEMBER_HAS_INVITE, TEAM_INVITE_MEMBER_HAS_INVITE,
@@ -19,6 +21,7 @@ import { TeamInvitation } from './team-invitation.model';
import { MailerService } from 'src/mailer/mailer.service'; import { MailerService } from 'src/mailer/mailer.service';
import { UserService } from 'src/user/user.service'; import { UserService } from 'src/user/user.service';
import { PubSubService } from 'src/pubsub/pubsub.service'; import { PubSubService } from 'src/pubsub/pubsub.service';
import { validateEmail } from '../utils';
@Injectable() @Injectable()
export class TeamInvitationService { export class TeamInvitationService {
@@ -63,6 +66,32 @@ export class TeamInvitationService {
); );
} }
/**
* Get the team invite for an invitee with email and teamID.
* @param inviteeEmail invitee email
* @param teamID team id
* @returns an Either of team invitation for the invitee or error
*/
async getTeamInviteByEmailAndTeamID(inviteeEmail: string, teamID: string) {
const isEmailValid = validateEmail(inviteeEmail);
if (!isEmailValid) return E.left(INVALID_EMAIL);
try {
const teamInvite = await this.prisma.teamInvitation.findUniqueOrThrow({
where: {
teamID_inviteeEmail: {
inviteeEmail: inviteeEmail,
teamID: teamID,
},
},
});
return E.right(teamInvite);
} catch (e) {
return E.left(TEAM_INVITE_NO_INVITE_FOUND);
}
}
createInvitation( createInvitation(
creator: User, creator: User,
team: Team, team: Team,
@@ -126,7 +155,7 @@ export class TeamInvitationService {
template: 'team-invitation', template: 'team-invitation',
variables: { variables: {
invitee: creator.displayName ?? 'A Hoppscotch User', invitee: creator.displayName ?? 'A Hoppscotch User',
action_url: `https://hoppscotch.io/join-team?id=${invitation.id}`, action_url: `${process.env.VITE_BASE_URL}/join-team?id=${invitation.id}`,
invite_team_name: team.name, invite_team_name: team.name,
}, },
}), }),

View File

@@ -32,7 +32,7 @@ export class TeamInviteViewerGuard implements CanActivate {
// Get user // Get user
TE.bindW('user', ({ gqlCtx }) => TE.bindW('user', ({ gqlCtx }) =>
pipe( pipe(
O.fromNullable(gqlCtx.getContext<{ user?: User }>().user), O.fromNullable(gqlCtx.getContext().req.user),
TE.fromOption(() => BUG_AUTH_NO_USER_CTX), TE.fromOption(() => BUG_AUTH_NO_USER_CTX),
), ),
), ),

View File

@@ -33,7 +33,7 @@ export class TeamInviteeGuard implements CanActivate {
// Get user // Get user
TE.bindW('user', ({ gqlCtx }) => TE.bindW('user', ({ gqlCtx }) =>
pipe( pipe(
O.fromNullable(gqlCtx.getContext<{ user?: User }>().user), O.fromNullable(gqlCtx.getContext().req.user),
TE.fromOption(() => BUG_AUTH_NO_USER_CTX), TE.fromOption(() => BUG_AUTH_NO_USER_CTX),
), ),
), ),

View File

@@ -2,7 +2,7 @@ import { HttpStatus } from '@nestjs/common';
/** /**
** Custom interface to handle errors specific to Auth module ** Custom interface to handle errors specific to Auth module
** Since its REST we need to return HTTP status code along with error message ** Since its REST we need to return the HTTP status code along with the error message
*/ */
export type AuthError = { export type AuthError = {
message: string; message: string;

View File

@@ -360,13 +360,15 @@ describe('UserHistoryService', () => {
}); });
describe('removeRequestFromHistory', () => { describe('removeRequestFromHistory', () => {
test('Should resolve right and delete request from users history', async () => { test('Should resolve right and delete request from users history', async () => {
const executedOn = new Date();
mockPrisma.userHistory.delete.mockResolvedValueOnce({ mockPrisma.userHistory.delete.mockResolvedValueOnce({
userUid: 'abc', userUid: 'abc',
id: '1', id: '1',
request: [{}], request: [{}],
responseMetadata: [{}], responseMetadata: [{}],
reqType: ReqType.REST, reqType: ReqType.REST,
executedOn: new Date(), executedOn: executedOn,
isStarred: false, isStarred: false,
}); });
@@ -376,7 +378,7 @@ describe('UserHistoryService', () => {
request: JSON.stringify([{}]), request: JSON.stringify([{}]),
responseMetadata: JSON.stringify([{}]), responseMetadata: JSON.stringify([{}]),
reqType: ReqType.REST, reqType: ReqType.REST,
executedOn: new Date(), executedOn: executedOn,
isStarred: false, isStarred: false,
}; };
@@ -384,7 +386,7 @@ describe('UserHistoryService', () => {
await userHistoryService.removeRequestFromHistory('abc', '1'), await userHistoryService.removeRequestFromHistory('abc', '1'),
).toEqualRight(userHistory); ).toEqualRight(userHistory);
}); });
test('Should resolve left and error out when req id is invalid ', async () => { test('Should resolve left and error out when req id is invalid', async () => {
mockPrisma.userHistory.delete.mockResolvedValueOnce(null); mockPrisma.userHistory.delete.mockResolvedValueOnce(null);
return expect( return expect(

View File

@@ -207,16 +207,19 @@
:root.light { :root.light {
@include light-theme; @include light-theme;
@include light-editor-theme; @include light-editor-theme;
color-scheme: light;
} }
:root.dark { :root.dark {
@include dark-theme; @include dark-theme;
@include dark-editor-theme; @include dark-editor-theme;
color-scheme: dark;
} }
:root.black { :root.black {
@include black-theme; @include black-theme;
@include black-editor-theme; @include black-editor-theme;
color-scheme: dark;
} }
:root[data-accent="blue"] { :root[data-accent="blue"] {

View File

@@ -432,6 +432,7 @@
"view_my_links": "View my links" "view_my_links": "View my links"
}, },
"response": { "response": {
"audio": "Audio",
"body": "Reaksie liggaam", "body": "Reaksie liggaam",
"filter_response_body": "Filter JSON response body (uses JSONPath syntax)", "filter_response_body": "Filter JSON response body (uses JSONPath syntax)",
"headers": "Opskrifte", "headers": "Opskrifte",
@@ -445,6 +446,7 @@
"status": "Status", "status": "Status",
"time": "Tyd", "time": "Tyd",
"title": "Reaksie", "title": "Reaksie",
"video": "Video",
"waiting_for_connection": "wag vir verbinding", "waiting_for_connection": "wag vir verbinding",
"xml": "XML" "xml": "XML"
}, },

View File

@@ -432,6 +432,7 @@
"view_my_links": "View my links" "view_my_links": "View my links"
}, },
"response": { "response": {
"audio": "Audio",
"body": "هيئة الاستجابة", "body": "هيئة الاستجابة",
"filter_response_body": "Filter JSON response body (uses JSONPath syntax)", "filter_response_body": "Filter JSON response body (uses JSONPath syntax)",
"headers": "الرؤوس", "headers": "الرؤوس",
@@ -445,6 +446,7 @@
"status": "حالة", "status": "حالة",
"time": "وقت", "time": "وقت",
"title": "إجابة", "title": "إجابة",
"video": "Video",
"waiting_for_connection": "في انتظار الاتصال", "waiting_for_connection": "في انتظار الاتصال",
"xml": "XML" "xml": "XML"
}, },

View File

@@ -432,6 +432,7 @@
"view_my_links": "Visualitzar els meus enllaços" "view_my_links": "Visualitzar els meus enllaços"
}, },
"response": { "response": {
"audio": "Audio",
"body": "Cos de resposta", "body": "Cos de resposta",
"filter_response_body": "Filtrar el cos de la resposta JSON (utilitza la sintaxi JSONPath)", "filter_response_body": "Filtrar el cos de la resposta JSON (utilitza la sintaxi JSONPath)",
"headers": "Capçaleres", "headers": "Capçaleres",
@@ -445,6 +446,7 @@
"status": "Estat", "status": "Estat",
"time": "Temps", "time": "Temps",
"title": "Resposta", "title": "Resposta",
"video": "Video",
"waiting_for_connection": "esperant la connexió", "waiting_for_connection": "esperant la connexió",
"xml": "XML" "xml": "XML"
}, },

View File

@@ -19,7 +19,7 @@
"edit": "编辑", "edit": "编辑",
"filter": "过滤", "filter": "过滤",
"go_back": "返回", "go_back": "返回",
"go_forward": "Go forward", "go_forward": "前进",
"group_by": "分组方式", "group_by": "分组方式",
"label": "标签", "label": "标签",
"learn_more": "了解更多", "learn_more": "了解更多",
@@ -40,9 +40,9 @@
"start": "开始", "start": "开始",
"starting": "正在开始", "starting": "正在开始",
"stop": "停止", "stop": "停止",
"to_close": "关闭", "to_close": "关闭",
"to_navigate": "定位", "to_navigate": "定位",
"to_select": "选择", "to_select": "选择",
"turn_off": "关闭", "turn_off": "关闭",
"turn_on": "开启", "turn_on": "开启",
"undo": "撤消", "undo": "撤消",
@@ -118,16 +118,16 @@
}, },
"collection": { "collection": {
"created": "集合已创建", "created": "集合已创建",
"different_parent": "Cannot reorder collection with different parent", "different_parent": "不能用不同的父类来重新排序集合",
"edit": "编辑集合", "edit": "编辑集合",
"invalid_name": "请提供有效的集合名称", "invalid_name": "请提供有效的集合名称",
"invalid_root_move": "Collection already in the root", "invalid_root_move": "该集合已经在根级了",
"moved": "Moved Successfully", "moved": "移动完成",
"my_collections": "我的集合", "my_collections": "我的集合",
"name": "我的新集合", "name": "我的新集合",
"name_length_insufficient": "集合名字至少需要 3 个字符", "name_length_insufficient": "集合名字至少需要 3 个字符",
"new": "新建集合", "new": "新建集合",
"order_changed": "Collection Order Updated", "order_changed": "集合顺序已更新",
"renamed": "集合已更名", "renamed": "集合已更名",
"request_in_use": "请求正在使用中", "request_in_use": "请求正在使用中",
"save_as": "另存为", "save_as": "另存为",
@@ -147,7 +147,7 @@
"remove_team": "你确定要删除该团队吗?", "remove_team": "你确定要删除该团队吗?",
"remove_telemetry": "你确定要退出遥测服务吗?", "remove_telemetry": "你确定要退出遥测服务吗?",
"request_change": "你确定你要放弃当前的请求,未保存的修改将被丢失。", "request_change": "你确定你要放弃当前的请求,未保存的修改将被丢失。",
"save_unsaved_tab": "Do you want to save changes made in this tab?", "save_unsaved_tab": "你想保存在此标签页中所作的修改吗?",
"sync": "您确定要同步该工作区吗?" "sync": "您确定要同步该工作区吗?"
}, },
"count": { "count": {
@@ -177,7 +177,7 @@
"members": "团队为空", "members": "团队为空",
"parameters": "该请求没有任何参数", "parameters": "该请求没有任何参数",
"pending_invites": "此团队无待办邀请", "pending_invites": "此团队无待办邀请",
"profile": "登录以查看你的个人档案", "profile": "登录以查看你的个人资料",
"protocols": "协议为空", "protocols": "协议为空",
"schema": "连接至 GraphQL 端点", "schema": "连接至 GraphQL 端点",
"shortcodes": "Shortcodes 为空", "shortcodes": "Shortcodes 为空",
@@ -209,7 +209,7 @@
"browser_support_sse": "该浏览器似乎不支持 SSE。", "browser_support_sse": "该浏览器似乎不支持 SSE。",
"check_console_details": "检查控制台日志以获悉详情", "check_console_details": "检查控制台日志以获悉详情",
"curl_invalid_format": "cURL 格式不正确", "curl_invalid_format": "cURL 格式不正确",
"danger_zone": "Danger zone", "danger_zone": "危险区域",
"delete_account": "您的帐号目前为这些团队的拥有者:", "delete_account": "您的帐号目前为这些团队的拥有者:",
"delete_account_description": "您在删除帐号前必须先将您自己从团队中移除、转移拥有权,或是删除团队。", "delete_account_description": "您在删除帐号前必须先将您自己从团队中移除、转移拥有权,或是删除团队。",
"empty_req_name": "空请求名称", "empty_req_name": "空请求名称",
@@ -219,7 +219,7 @@
"incorrect_email": "电子邮箱错误", "incorrect_email": "电子邮箱错误",
"invalid_link": "无效链接", "invalid_link": "无效链接",
"invalid_link_description": "你点击的链接无效或已过期。", "invalid_link_description": "你点击的链接无效或已过期。",
"json_parsing_failed": "Invalid JSON", "json_parsing_failed": "不合法的 JSON",
"json_prettify_invalid_body": "无法美化无效的请求头,处理 JSON 语法错误并重试", "json_prettify_invalid_body": "无法美化无效的请求头,处理 JSON 语法错误并重试",
"network_error": "好像发生了网络错误,请重试。", "network_error": "好像发生了网络错误,请重试。",
"network_fail": "无法发送请求", "network_fail": "无法发送请求",
@@ -316,14 +316,14 @@
"zen_mode": "ZEN 模式" "zen_mode": "ZEN 模式"
}, },
"modal": { "modal": {
"close_unsaved_tab": "You have unsaved changes", "close_unsaved_tab": "有未保存的变更",
"collections": "集合", "collections": "集合",
"confirm": "确认", "confirm": "确认",
"edit_request": "编辑请求", "edit_request": "编辑请求",
"import_export": "导入/导出" "import_export": "导入/导出"
}, },
"mqtt": { "mqtt": {
"already_subscribed": "您已经订阅了此主。", "already_subscribed": "您已经订阅了此主。",
"clean_session": "清除会话", "clean_session": "清除会话",
"clear_input": "清除输入", "clear_input": "清除输入",
"clear_input_on_send": "发送后清除输入", "clear_input_on_send": "发送后清除输入",
@@ -355,7 +355,7 @@
"navigation": { "navigation": {
"doc": "文档", "doc": "文档",
"graphql": "GraphQL", "graphql": "GraphQL",
"profile": "个人档案", "profile": "个人资料",
"realtime": "实时", "realtime": "实时",
"rest": "REST", "rest": "REST",
"settings": "设置" "settings": "设置"
@@ -377,7 +377,7 @@
"owner_description": "所有者可以添加、编辑和删除请求、集合及团队成员。", "owner_description": "所有者可以添加、编辑和删除请求、集合及团队成员。",
"roles": "角色", "roles": "角色",
"roles_description": "角色用以控制共享集合的访问权限。", "roles_description": "角色用以控制共享集合的访问权限。",
"updated": "档案已更新", "updated": "已更新",
"viewer": "查看者", "viewer": "查看者",
"viewer_description": "查看者只可查看与使用请求。" "viewer_description": "查看者只可查看与使用请求。"
}, },
@@ -396,8 +396,8 @@
"text": "文字" "text": "文字"
}, },
"copy_link": "复制链接", "copy_link": "复制链接",
"different_collection": "Cannot reorder requests from different collections", "different_collection": "不能对来自不同集合的请求进行重新排序",
"duplicated": "Request duplicated", "duplicated": "重复的请求",
"duration": "持续时间", "duration": "持续时间",
"enter_curl": "输入 cURL", "enter_curl": "输入 cURL",
"generate_code": "生成代码", "generate_code": "生成代码",
@@ -405,10 +405,10 @@
"header_list": "请求头列表", "header_list": "请求头列表",
"invalid_name": "请提供请求名称", "invalid_name": "请提供请求名称",
"method": "方法", "method": "方法",
"moved": "Request moved", "moved": "请求移动完成",
"name": "请求名称", "name": "请求名称",
"new": "新请求", "new": "新请求",
"order_changed": "Request Order Updated", "order_changed": "请求顺序更新完成",
"override": "覆盖", "override": "覆盖",
"override_help": "设置 <kbd>Content-Type</kbd> 头", "override_help": "设置 <kbd>Content-Type</kbd> 头",
"overriden": "覆盖", "overriden": "覆盖",
@@ -432,6 +432,7 @@
"view_my_links": "查看我的链接" "view_my_links": "查看我的链接"
}, },
"response": { "response": {
"audio": "Audio",
"body": "响应体", "body": "响应体",
"filter_response_body": "筛选JSON响应本体使用JSONPath语法", "filter_response_body": "筛选JSON响应本体使用JSONPath语法",
"headers": "响应头", "headers": "响应头",
@@ -445,6 +446,7 @@
"status": "状态", "status": "状态",
"time": "时间", "time": "时间",
"title": "响应", "title": "响应",
"video": "Video",
"waiting_for_connection": "等待连接", "waiting_for_connection": "等待连接",
"xml": "XML" "xml": "XML"
}, },
@@ -479,10 +481,10 @@
"language": "语言", "language": "语言",
"light_mode": "亮色", "light_mode": "亮色",
"official_proxy_hosting": "官方代理由 Hoppscotch 托管。", "official_proxy_hosting": "官方代理由 Hoppscotch 托管。",
"profile": "个人档案", "profile": "个人资料",
"profile_description": "更新你的档案详情", "profile_description": "更新你的资料",
"profile_email": "电子邮箱地址", "profile_email": "电子邮箱地址",
"profile_name": "档案名称", "profile_name": "名称",
"proxy": "网络代理", "proxy": "网络代理",
"proxy_url": "代理网址", "proxy_url": "代理网址",
"proxy_use_toggle": "使用代理中间件发送请求", "proxy_use_toggle": "使用代理中间件发送请求",
@@ -532,7 +534,7 @@
"documentation": "前往文档页面", "documentation": "前往文档页面",
"forward": "前往下一页面", "forward": "前往下一页面",
"graphql": "前往 GraphQL 页面", "graphql": "前往 GraphQL 页面",
"profile": "前往个人档案页面", "profile": "前往个人资料页面",
"realtime": "前往实时页面", "realtime": "前往实时页面",
"rest": "前往 REST 页面", "rest": "前往 REST 页面",
"settings": "前往设置页面", "settings": "前往设置页面",
@@ -574,7 +576,7 @@
}, },
"socketio": { "socketio": {
"communication": "通讯", "communication": "通讯",
"connection_not_authorized": "此SocketIO连接未使用任何验证。", "connection_not_authorized": "此 SocketIO 连接未使用任何验证。",
"event_name": "事件名称", "event_name": "事件名称",
"events": "事件", "events": "事件",
"log": "日志", "log": "日志",
@@ -614,12 +616,12 @@
"none": "无", "none": "无",
"nothing_found": "没有找到", "nothing_found": "没有找到",
"published_error": "将信息:{topic}发布至主题:{message}时发生错误", "published_error": "将信息:{topic}发布至主题:{message}时发生错误",
"published_message": "已将此信息:{message}发布至主题:{topic}", "published_message": "已将此信息:{message} 发布至主题:{topic}",
"reconnection_error": "重连失败", "reconnection_error": "重连失败",
"subscribed_failed": "无法订阅此主{topic}", "subscribed_failed": "无法订阅此主{topic}",
"subscribed_success": "成功订阅此主{topic}", "subscribed_success": "成功订阅此主{topic}",
"unsubscribed_failed": "无法取消订阅此主{topic}", "unsubscribed_failed": "无法取消订阅此主{topic}",
"unsubscribed_success": "成功取消订阅此主{topic}", "unsubscribed_success": "成功取消订阅此主{topic}",
"waiting_send_request": "等待发送请求" "waiting_send_request": "等待发送请求"
}, },
"support": { "support": {
@@ -639,7 +641,7 @@
"body": "请求体", "body": "请求体",
"collections": "集合", "collections": "集合",
"documentation": "帮助文档", "documentation": "帮助文档",
"environments": "Environments", "environments": "环境",
"headers": "请求头", "headers": "请求头",
"history": "历史记录", "history": "历史记录",
"mqtt": "MQTT", "mqtt": "MQTT",
@@ -664,7 +666,7 @@
"email_do_not_match": "邮箱无法与你的帐户信息匹配。请联系你的团队者。", "email_do_not_match": "邮箱无法与你的帐户信息匹配。请联系你的团队者。",
"exit": "退出团队", "exit": "退出团队",
"exit_disabled": "团队所有者无法退出团队", "exit_disabled": "团队所有者无法退出团队",
"invalid_coll_id": "Invalid collection ID", "invalid_coll_id": "无效的集合 ID",
"invalid_email_format": "电子邮箱格式无效", "invalid_email_format": "电子邮箱格式无效",
"invalid_id": "无效的团队 ID请联系你的团队者。", "invalid_id": "无效的团队 ID请联系你的团队者。",
"invalid_invite_link": "无效的邀请链接", "invalid_invite_link": "无效的邀请链接",
@@ -688,7 +690,7 @@
"member_removed": "用户已移除", "member_removed": "用户已移除",
"member_role_updated": "用户角色已更新", "member_role_updated": "用户角色已更新",
"members": "成员", "members": "成员",
"more_members": "+{count} more", "more_members": "+{count} 更多",
"name_length_insufficient": "团队名称至少为 6 个字符", "name_length_insufficient": "团队名称至少为 6 个字符",
"name_updated": "团队名称已更新", "name_updated": "团队名称已更新",
"new": "新团队", "new": "新团队",
@@ -696,13 +698,13 @@
"new_name": "我的新团队", "new_name": "我的新团队",
"no_access": "你没有编辑集合的权限", "no_access": "你没有编辑集合的权限",
"no_invite_found": "未找到邀请。请联系你的团队者。", "no_invite_found": "未找到邀请。请联系你的团队者。",
"no_request_found": "Request not found.", "no_request_found": "请求不存在",
"not_found": "没有找到团队,请联系您的团队所有者。", "not_found": "没有找到团队,请联系您的团队所有者。",
"not_valid_viewer": "你不是有效的查看者。请联系你的团队者。", "not_valid_viewer": "你不是有效的查看者。请联系你的团队者。",
"parent_coll_move": "Cannot move collection to a child collection", "parent_coll_move": "不能将集合移动到一个子集合",
"pending_invites": "待办邀请", "pending_invites": "待办邀请",
"permissions": "权限", "permissions": "权限",
"same_target_destination": "Same target and destination", "same_target_destination": "目标相同",
"saved": "团队已保存", "saved": "团队已保存",
"select_a_team": "选择团队", "select_a_team": "选择团队",
"title": "团队", "title": "团队",
@@ -732,9 +734,9 @@
"url": "URL" "url": "URL"
}, },
"workspace": { "workspace": {
"change": "Change workspace", "change": "切换工作空间",
"personal": "My Workspace", "personal": "我的工作空间",
"team": "Team Workspace", "team": "团队工作空间",
"title": "Workspaces" "title": "工作空间"
} }
} }

View File

@@ -432,6 +432,7 @@
"view_my_links": "View my links" "view_my_links": "View my links"
}, },
"response": { "response": {
"audio": "Audio",
"body": "Odpovědní orgán", "body": "Odpovědní orgán",
"filter_response_body": "Filter JSON response body (uses JSONPath syntax)", "filter_response_body": "Filter JSON response body (uses JSONPath syntax)",
"headers": "Záhlaví", "headers": "Záhlaví",
@@ -445,6 +446,7 @@
"status": "Postavení", "status": "Postavení",
"time": "Čas", "time": "Čas",
"title": "Odezva", "title": "Odezva",
"video": "Video",
"waiting_for_connection": "čekání na připojení", "waiting_for_connection": "čekání na připojení",
"xml": "XML" "xml": "XML"
}, },

View File

@@ -432,6 +432,7 @@
"view_my_links": "View my links" "view_my_links": "View my links"
}, },
"response": { "response": {
"audio": "Audio",
"body": "Svarorgan", "body": "Svarorgan",
"filter_response_body": "Filter JSON response body (uses JSONPath syntax)", "filter_response_body": "Filter JSON response body (uses JSONPath syntax)",
"headers": "Overskrifter", "headers": "Overskrifter",
@@ -445,6 +446,7 @@
"status": "Status", "status": "Status",
"time": "Tid", "time": "Tid",
"title": "Respons", "title": "Respons",
"video": "Video",
"waiting_for_connection": "venter på forbindelse", "waiting_for_connection": "venter på forbindelse",
"xml": "XML" "xml": "XML"
}, },

View File

@@ -432,6 +432,7 @@
"view_my_links": "View my links" "view_my_links": "View my links"
}, },
"response": { "response": {
"audio": "Audio",
"body": "Antworttext", "body": "Antworttext",
"filter_response_body": "Filter JSON response body (uses JSONPath syntax)", "filter_response_body": "Filter JSON response body (uses JSONPath syntax)",
"headers": "Header", "headers": "Header",
@@ -445,6 +446,7 @@
"status": "Status", "status": "Status",
"time": "Zeit", "time": "Zeit",
"title": "Antwort", "title": "Antwort",
"video": "Video",
"waiting_for_connection": "auf Verbindung warten", "waiting_for_connection": "auf Verbindung warten",
"xml": "XML" "xml": "XML"
}, },

View File

@@ -432,6 +432,7 @@
"view_my_links": "Προβολή των links μου" "view_my_links": "Προβολή των links μου"
}, },
"response": { "response": {
"audio": "Audio",
"body": "Σώμα απόκρισης", "body": "Σώμα απόκρισης",
"filter_response_body": "Filter JSON response body (uses JSONPath syntax)", "filter_response_body": "Filter JSON response body (uses JSONPath syntax)",
"headers": "Κεφαλίδες", "headers": "Κεφαλίδες",
@@ -445,6 +446,7 @@
"status": "Κατάσταση", "status": "Κατάσταση",
"time": "χρόνος", "time": "χρόνος",
"title": "Απάντηση", "title": "Απάντηση",
"video": "Video",
"waiting_for_connection": "περιμένοντας τη σύνδεση", "waiting_for_connection": "περιμένοντας τη σύνδεση",
"xml": "XML" "xml": "XML"
}, },

View File

@@ -432,6 +432,7 @@
"view_my_links": "View my links" "view_my_links": "View my links"
}, },
"response": { "response": {
"audio": "Audio",
"body": "Response Body", "body": "Response Body",
"filter_response_body": "Filter JSON response body (uses JSONPath syntax)", "filter_response_body": "Filter JSON response body (uses JSONPath syntax)",
"headers": "Headers", "headers": "Headers",
@@ -445,6 +446,7 @@
"status": "Status", "status": "Status",
"time": "Time", "time": "Time",
"title": "Response", "title": "Response",
"video": "Video",
"waiting_for_connection": "waiting for connection", "waiting_for_connection": "waiting for connection",
"xml": "XML" "xml": "XML"
}, },

View File

@@ -1,44 +1,44 @@
{ {
"action": { "action": {
"autoscroll": "Autoscroll", "autoscroll": "Desplazamiento automático",
"cancel": "Cancelar", "cancel": "Cancelar",
"choose_file": "Seleccionar archivo", "choose_file": "Seleccionar archivo",
"clear": "Limpiar", "clear": "Limpiar",
"clear_all": "Limpiar todo", "clear_all": "Limpiar todo",
"close": "Cerrar", "close": "Cerrar",
"connect": "Conectar", "connect": "Conectar",
"connecting": "Connecting", "connecting": "Conectando",
"copy": "Copiar", "copy": "Copiar",
"delete": "Borrar", "delete": "Borrar",
"disconnect": "Desconectar", "disconnect": "Desconectar",
"dismiss": "Descartar", "dismiss": "Descartar",
"dont_save": "Don't save", "dont_save": "No guardar",
"download_file": "Descargar archivo", "download_file": "Descargar archivo",
"drag_to_reorder": "Arrastrar para reordenar", "drag_to_reorder": "Arrastrar para reordenar",
"duplicate": "Duplicar", "duplicate": "Duplicar",
"edit": "Editar", "edit": "Editar",
"filter": "Filter", "filter": "Filtrar",
"go_back": "Volver", "go_back": "Volver",
"go_forward": "Go forward", "go_forward": "Adelante",
"group_by": "Group by", "group_by": "Agrupar por",
"label": "Etiqueta", "label": "Etiqueta",
"learn_more": "Aprender más", "learn_more": "Aprender más",
"less": "Menos", "less": "Menos",
"more": "Más", "more": "Más",
"new": "Nuevo", "new": "Nuevo",
"no": "No", "no": "No",
"open_workspace": "Open workspace", "open_workspace": "Abrir espacio de trabajo",
"paste": "Pegar", "paste": "Pegar",
"prettify": "Embellecer", "prettify": "Embellecer",
"remove": "Eliminar", "remove": "Eliminar",
"restore": "Restaurar", "restore": "Restaurar",
"save": "Guardar", "save": "Guardar",
"scroll_to_bottom": "Scroll to bottom", "scroll_to_bottom": "Desplazar hacia abajo",
"scroll_to_top": "Scroll to top", "scroll_to_top": "Desplazar hacia arriba",
"search": "Buscar", "search": "Buscar",
"send": "Enviar", "send": "Enviar",
"start": "Comenzar", "start": "Comenzar",
"starting": "Starting", "starting": "Iniciando",
"stop": "Detener", "stop": "Detener",
"to_close": "para cerrar", "to_close": "para cerrar",
"to_navigate": "para navegar", "to_navigate": "para navegar",
@@ -56,16 +56,16 @@
"chat_with_us": "Habla con nosotros", "chat_with_us": "Habla con nosotros",
"contact_us": "Contáctanos", "contact_us": "Contáctanos",
"copy": "Copiar", "copy": "Copiar",
"copy_user_id": "Copy User Auth Token", "copy_user_id": "Copiar token de autenticación de usuario",
"developer_option": "Developer options", "developer_option": "Opciones para desarrolladores",
"developer_option_description": "Developer tools which helps in development and maintenance of Hoppscotch.", "developer_option_description": "Herramientas para desarrolladores que ayudan en el desarrollo y mantenimiento de Hoppscotch.",
"discord": "Discord", "discord": "Discord",
"documentation": "Documentación", "documentation": "Documentación",
"github": "GitHub", "github": "GitHub",
"help": "Ayuda y comentarios", "help": "Ayuda y comentarios",
"home": "Inicio", "home": "Inicio",
"invite": "Invitar", "invite": "Invitar",
"invite_description": "En Hoppscotch, diseñamos una interfaz simple e intuitiva para crear y administrar sus APIs. Hoppscotch es una herramienta que le ayuda a crear, probar, documentar y compartir sus APIs.", "invite_description": "En Hoppscotch, diseñamos una interfaz simple e intuitiva para crear y administrar tus APIs. Hoppscotch es una herramienta que le ayuda a crear, probar, documentar y compartir tus APIs.",
"invite_your_friends": "Invita a tus amigos", "invite_your_friends": "Invita a tus amigos",
"join_discord_community": "Únete a nuestra comunidad Discord", "join_discord_community": "Únete a nuestra comunidad Discord",
"keyboard_shortcuts": "Atajos de teclado", "keyboard_shortcuts": "Atajos de teclado",
@@ -79,7 +79,7 @@
"shortcuts": "Atajos", "shortcuts": "Atajos",
"spotlight": "Destacar", "spotlight": "Destacar",
"status": "Estado", "status": "Estado",
"status_description": "Check the status of the website", "status_description": "Comprobar el estado del sitio web",
"terms_and_privacy": "Términos y privacidad", "terms_and_privacy": "Términos y privacidad",
"twitter": "Twitter", "twitter": "Twitter",
"type_a_command_search": "Escribe un comando o buscar algo…", "type_a_command_search": "Escribe un comando o buscar algo…",
@@ -118,18 +118,18 @@
}, },
"collection": { "collection": {
"created": "Colección creada", "created": "Colección creada",
"different_parent": "Cannot reorder collection with different parent", "different_parent": "No se puede reordenar la colección con un padre diferente",
"edit": "Editar colección", "edit": "Editar colección",
"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": "Collection already in the root", "invalid_root_move": "La colección ya está en la raíz",
"moved": "Moved Successfully", "moved": "Movido con éxito",
"my_collections": "Mis colecciones", "my_collections": "Mis colecciones",
"name": "Mi nueva colección", "name": "Mi nueva colección",
"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": "Collection Order Updated", "order_changed": "Orden de colección actualizada",
"renamed": "Colección renombrada", "renamed": "Colección renombrada",
"request_in_use": "Petición en uso", "request_in_use": "Solicitud en uso",
"save_as": "Guardar como", "save_as": "Guardar como",
"select": "Seleccionar colección", "select": "Seleccionar colección",
"select_location": "Seleccionar ubicación", "select_location": "Seleccionar ubicación",
@@ -138,17 +138,17 @@
}, },
"confirm": { "confirm": {
"exit_team": "¿Estás seguro de que quieres dejar este equipo?", "exit_team": "¿Estás seguro de que quieres dejar este equipo?",
"logout": "¿Está seguro de que desea cerrar la sesión?", "logout": "¿Estás seguro de que deseas cerrar la sesión?",
"remove_collection": "¿Está seguro de que desea eliminar esta colección de forma permanente?", "remove_collection": "¿Estás seguro de que deseas eliminar esta colección de forma permanente?",
"remove_environment": "¿Está seguro de que desea eliminar este entorno de forma permanente?", "remove_environment": "¿Estás seguro de que deseas eliminar este entorno de forma permanente?",
"remove_folder": "¿Está seguro de que desea eliminar esta carpeta de forma permanente?", "remove_folder": "¿Estás seguro de que deseas eliminar esta carpeta de forma permanente?",
"remove_history": "¿Está seguro de que desea 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á seguro de que desea eliminar esta petición de forma permanente?", "remove_request": "¿Estás seguro de que deseas eliminar esta solicitud de forma permanente?",
"remove_team": "¿Está seguro de que desea eliminar este equipo?", "remove_team": "¿Estás seguro de que deseas eliminar este equipo?",
"remove_telemetry": "¿Está seguro de que desea darse de baja de la telemetría?", "remove_telemetry": "¿Estás seguro de que deseas darse de baja de la telemetría?",
"request_change": "Are you sure you want to discard current request, unsaved changes will be lost.", "request_change": "¿Estás seguro de que deseas descartar la solicitud actual, los cambios no guardados se perderán.",
"save_unsaved_tab": "Do you want to save changes made in this tab?", "save_unsaved_tab": "¿Deseas guardar los cambios realizados en esta pestaña?",
"sync": "¿Está seguro de que desea sincronizar este espacio de trabajo?" "sync": "¿Estás seguro de que deseas sincronizar este espacio de trabajo?"
}, },
"count": { "count": {
"header": "Encabezado {count}", "header": "Encabezado {count}",
@@ -163,28 +163,28 @@
"generate_message": "Importar cualquier colección de Hoppscotch para generar documentación de la API sobre la marcha." "generate_message": "Importar cualquier colección de Hoppscotch para generar documentación de la API sobre la marcha."
}, },
"empty": { "empty": {
"authorization": "Esta petición no utiliza ninguna autorización.", "authorization": "Esta solicitud no utiliza ninguna autorización.",
"body": "Esta petición no tiene cuerpo", "body": "Esta solicitud no tiene cuerpo",
"collection": "La colección está vacía", "collection": "La colección está vacía",
"collections": "Las colecciones están vacías", "collections": "Las colecciones están vacías",
"documentation": "Conectarse a un punto final de GraphQL para ver la documentación", "documentation": "Conectarse a un punto final de GraphQL para ver la documentación",
"endpoint": "El punto final no puede estar vacío", "endpoint": "El punto final no puede estar vacío",
"environments": "Los entornos están vacíos", "environments": "Los entornos están vacíos",
"folder": "La carpeta está vacía", "folder": "La carpeta está vacía",
"headers": "Esta petición no tiene encabezados", "headers": "Esta solicitud no tiene encabezados",
"history": "El historial está vacío", "history": "El historial está vacío",
"invites": "La lista de invitados está vacía", "invites": "La lista de invitados está vacía",
"members": "El equipo está vacío", "members": "El equipo está vacío",
"parameters": "Esta petición no tiene ningún parámetro", "parameters": "Esta solicitud no tiene ningún parámetro",
"pending_invites": "No hay invitaciones pendientes para este equipo", "pending_invites": "No hay invitaciones pendientes para este equipo",
"profile": "Iniciar sesión para ver tu perfil", "profile": "Iniciar sesión para ver tu perfil",
"protocols": "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": "Los shortcodes están vacíos", "shortcodes": "Aún no se han creado Shortcodes",
"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 petición" "tests": "No hay pruebas para esta solicitud"
}, },
"environment": { "environment": {
"add_to_global": "Añadir a Global", "add_to_global": "Añadir a Global",
@@ -194,38 +194,38 @@
"deleted": "Eliminar el entorno", "deleted": "Eliminar el entorno",
"edit": "Editar entorno", "edit": "Editar entorno",
"invalid_name": "Proporciona un nombre válido para el entorno.", "invalid_name": "Proporciona un nombre válido para el entorno.",
"my_environments": "My Environments", "my_environments": "Mis entornos",
"nested_overflow": "las variables de entorno anidadas están limitadas a 10 niveles", "nested_overflow": "las variables de entorno anidadas están limitadas a 10 niveles",
"new": "Nuevo entorno", "new": "Nuevo entorno",
"no_environment": "Sin entorno", "no_environment": "Sin entorno",
"no_environment_description": "No se ha seleccionado ningún entorno. Elije qué hacer con las siguientes variables.", "no_environment_description": "No se ha seleccionado ningún entorno. Elije qué hacer con las siguientes variables.",
"select": "Seleccionar entorno", "select": "Seleccionar entorno",
"team_environments": "Team Environments", "team_environments": "Entornos de trabajo en equipo",
"title": "Entornos", "title": "Entornos",
"updated": "Actualización del entorno", "updated": "Entorno actualizado",
"variable_list": "Lista de variables" "variable_list": "Lista de variables"
}, },
"error": { "error": {
"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.",
"curl_invalid_format": "cURL no está formateado correctamente", "curl_invalid_format": "cURL no está formateado correctamente",
"danger_zone": "Danger zone", "danger_zone": "Zona de peligro",
"delete_account": "Your account is currently an owner in these teams:", "delete_account": "Tu cuenta es actualmente propietaria en estos equipos:",
"delete_account_description": "You must either remove yourself, transfer ownership, or delete these teams before you can delete your account.", "delete_account_description": "Para poder eliminar tu cuenta, debes darte de baja, transferir la propiedad o eliminar estos equipos.",
"empty_req_name": "Nombre de petición vacío", "empty_req_name": "Nombre de solicitud vacío",
"f12_details": "(F12 para más detalles)", "f12_details": "(F12 para más detalles)",
"gql_prettify_invalid_query": "No se puede aplicar embellecedor a una consulta no válida, resuelve los errores de sintaxis de la consulta y vuelve a intentarlo", "gql_prettify_invalid_query": "No se puede aplicar embellecedor a una consulta no válida, resuelve los errores de sintaxis de la consulta y vuelve a intentarlo",
"incomplete_config_urls": "URLs de configuración incompletas", "incomplete_config_urls": "URLs de configuración incompletas",
"incorrect_email": "Correo electrónico incorrecto", "incorrect_email": "Correo electrónico incorrecto",
"invalid_link": "Enlace no válido", "invalid_link": "Enlace no válido",
"invalid_link_description": "El enlace que has pulsado no es válido o ha caducado.", "invalid_link_description": "El enlace que has pulsado no es válido o ha caducado.",
"json_parsing_failed": "Invalid JSON", "json_parsing_failed": "JSON no válido",
"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 petición", "network_fail": "No se pudo enviar la solicitud",
"no_duration": "Sin duración", "no_duration": "Sin duración",
"no_results_found": "No matches found", "no_results_found": "No se han encontrado coincidencias",
"page_not_found": "This page could not be found", "page_not_found": "No se ha podido encontrar esta página",
"script_fail": "No se pudo ejecutar el script de solicitud previa", "script_fail": "No se pudo ejecutar el script de solicitud previa",
"something_went_wrong": "Algo salió mal", "something_went_wrong": "Algo salió mal",
"test_script_fail": "No se ha podido ejecutar la secuencia de comandos posterior a la solicitud" "test_script_fail": "No se ha podido ejecutar la secuencia de comandos posterior a la solicitud"
@@ -256,7 +256,7 @@
"subscriptions": "Suscripciones" "subscriptions": "Suscripciones"
}, },
"group": { "group": {
"time": "Time", "time": "Tiempo",
"url": "URL" "url": "URL"
}, },
"header": { "header": {
@@ -265,19 +265,19 @@
"save_workspace": "Guardar mi espacio de trabajo" "save_workspace": "Guardar mi espacio de trabajo"
}, },
"helpers": { "helpers": {
"authorization": "El encabezado de autorización se generará automáticamente cuando se envía la petición.", "authorization": "El encabezado de autorización se generará automáticamente cuando se envía la solicitud.",
"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.",
"offline_short": "Pareces estar desconectado.", "offline_short": "Pareces estar desconectado.",
"post_request_tests": "Los scripts de prueba están escritos en JavaScript y se ejecutan después de recibir la respuesta.", "post_request_tests": "Los scripts de prueba están escritos en JavaScript y se ejecutan después de recibir la respuesta.",
"pre_request_script": "Los scripts previos a la petición están escritos en JavaScript y se ejecutan antes de que se envíe la petición.", "pre_request_script": "Los scripts previos a la solicitud están escritos en JavaScript y se ejecutan antes de que se envíe la solicitud.",
"script_fail": "Parece que hay un problema técnico en el script de solicitud previa. Comprueba el error a continuación y corrige el script en consecuencia.", "script_fail": "Parece que hay un problema técnico en el script de solicitud previa. Comprueba el error a continuación y corrige el script en consecuencia.",
"test_script_fail": "Parece que hay un error con el script de prueba. Por favor, corrige los errores y ejecute las pruebas de nuevo", "test_script_fail": "Parece que hay un error con el script de prueba. Por favor, corrige los errores y ejecute las pruebas de nuevo",
"tests": "Escribir un script de prueba para automatizar la depuración." "tests": "Escribir un script de prueba para automatizar la depuración."
}, },
"hide": { "hide": {
"collection": "Collapse Collection Panel", "collection": "Colapsar el panel de colecciones",
"more": "Ocultar más", "more": "Ocultar más",
"preview": "Ocultar vista previa", "preview": "Ocultar vista previa",
"sidebar": "Ocultar barra lateral" "sidebar": "Ocultar barra lateral"
@@ -308,40 +308,40 @@
"title": "Importar" "title": "Importar"
}, },
"layout": { "layout": {
"collapse_collection": "Collapse or Expand Collections", "collapse_collection": "Contraer o expandir colecciones",
"collapse_sidebar": "Collapse or Expand the sidebar", "collapse_sidebar": "Contraer o expandir la barra lateral",
"column": "Disposición vertical", "column": "Disposición vertical",
"name": "Layout", "name": "Diseño",
"row": "Disposición horizontal", "row": "Disposición horizontal",
"zen_mode": "Modo zen" "zen_mode": "Modo zen"
}, },
"modal": { "modal": {
"close_unsaved_tab": "You have unsaved changes", "close_unsaved_tab": "Tienes cambios sin guardar",
"collections": "Colecciones", "collections": "Colecciones",
"confirm": "Confirmar", "confirm": "Confirmar",
"edit_request": "Editar petición", "edit_request": "Editar solicitud",
"import_export": "Importación y exportación" "import_export": "Importación y exportación"
}, },
"mqtt": { "mqtt": {
"already_subscribed": "You are already subscribed to this topic.", "already_subscribed": "Ya estás suscrito a este tema.",
"clean_session": "Clean Session", "clean_session": "Borrar sesión",
"clear_input": "Clear input", "clear_input": "Borrar entrada",
"clear_input_on_send": "Clear input on send", "clear_input_on_send": "Borrar entrada al enviar",
"client_id": "Client ID", "client_id": "Identificación del cliente",
"color": "Pick a color", "color": "Elige un color",
"communication": "Comunicación", "communication": "Comunicación",
"connection_config": "Connection Config", "connection_config": "Configuración de conexión",
"connection_not_authorized": "This MQTT connection does not use any authentication.", "connection_not_authorized": "Esta conexión MQTT no utiliza ninguna autenticación.",
"invalid_topic": "Please provide a topic for the subscription", "invalid_topic": "Indica un tema para la suscripción",
"keep_alive": "Keep Alive", "keep_alive": "Mantenerse vivo",
"log": "Registro", "log": "Registro",
"lw_message": "Last-Will Message", "lw_message": "Mensaje de última voluntad",
"lw_qos": "Last-Will QoS", "lw_qos": "QoS de última voluntad",
"lw_retain": "Last-Will Retain", "lw_retain": "Última voluntad",
"lw_topic": "Last-Will Topic", "lw_topic": "Tema de última voluntad",
"message": "Mensaje", "message": "Mensaje",
"new": "New Subscription", "new": "Nueva suscripción",
"not_connected": "Please start a MQTT connection first.", "not_connected": "Por favor, inicia primero una conexión MQTT.",
"publish": "Publicar", "publish": "Publicar",
"qos": "QoS", "qos": "QoS",
"ssl": "SSL", "ssl": "SSL",
@@ -353,7 +353,7 @@
"url": "URL" "url": "URL"
}, },
"navigation": { "navigation": {
"doc": "Docs", "doc": "Documentación",
"graphql": "GraphQL", "graphql": "GraphQL",
"profile": "Perfil", "profile": "Perfil",
"realtime": "Tiempo real", "realtime": "Tiempo real",
@@ -363,7 +363,7 @@
"preRequest": { "preRequest": {
"javascript_code": "Código JavaScript", "javascript_code": "Código JavaScript",
"learn": "Leer documentación", "learn": "Leer documentación",
"script": "Script previo a la petición", "script": "Script previo a la solicitud",
"snippets": "Fragmentos" "snippets": "Fragmentos"
}, },
"profile": { "profile": {
@@ -385,55 +385,56 @@
"star": "Eliminar estrella" "star": "Eliminar estrella"
}, },
"request": { "request": {
"added": "Petición agregada", "added": "Solicitud agregada",
"authorization": "Autorización", "authorization": "Autorización",
"body": "Cuerpo de la petición", "body": "Cuerpo de la solicitud",
"choose_language": "Seleccionar lenguaje", "choose_language": "Seleccionar lenguaje",
"content_type": "Tipo de contenido", "content_type": "Tipo de contenido",
"content_type_titles": { "content_type_titles": {
"others": "Others", "others": "Otros",
"structured": "Structured", "structured": "Estructurado",
"text": "Text" "text": "Texto"
}, },
"copy_link": "Copiar enlace", "copy_link": "Copiar enlace",
"different_collection": "Cannot reorder requests from different collections", "different_collection": "No se pueden reordenar solicitudes de diferentes colecciones",
"duplicated": "Request duplicated", "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",
"header_list": "Lista de encabezados", "header_list": "Lista de encabezados",
"invalid_name": "Proporciona un nombre para la petición.", "invalid_name": "Proporciona un nombre para la solicitud.",
"method": "Método", "method": "Método",
"moved": "Request moved", "moved": "Request moved",
"name": "Nombre de petición", "name": "Nombre de solicitud",
"new": "New Request", "new": "Nueva solicitud",
"order_changed": "Request Order Updated", "order_changed": "Orden de solicitudes actualizadas",
"override": "Override", "override": "Anular",
"override_help": "Set <kbd>Content-Type</kbd> in Headers", "override_help": "Establecer <kbd>Content-Type</kbd> en las cabeceras",
"overriden": "Overridden", "overriden": "Anulado",
"parameter_list": "Parámetros de consulta", "parameter_list": "Parámetros de consulta",
"parameters": "Parámetros", "parameters": "Parámetros",
"path": "Ruta", "path": "Ruta",
"payload": "Carga útil", "payload": "Carga útil",
"query": "Consulta", "query": "Consulta",
"raw_body": "Cuerpo de petición sin procesar", "raw_body": "Cuerpo de solicitud sin procesar",
"renamed": "Petición renombrada", "renamed": "Solicitud renombrada",
"run": "Ejecutar", "run": "Ejecutar",
"save": "Guardar", "save": "Guardar",
"save_as": "Guardar como", "save_as": "Guardar como",
"saved": "Petición guardada", "saved": "Solicitud guardada",
"share": "Compartir", "share": "Compartir",
"share_description": "Share Hoppscotch with your friends", "share_description": "Comparte Hoppscotch con tus amigos",
"title": "Petición", "title": "Solicitud",
"type": "Tipo de petición", "type": "Tipo de solicitud",
"url": "URL", "url": "URL",
"variables": "Variables", "variables": "Variables",
"view_my_links": "Ver mis enlaces" "view_my_links": "Ver mis enlaces"
}, },
"response": { "response": {
"audio": "Audio",
"body": "Cuerpo de respuesta", "body": "Cuerpo de respuesta",
"filter_response_body": "Filter JSON response body (uses JSONPath syntax)", "filter_response_body": "Filtrar el cuerpo de la respuesta JSON (utiliza la sintaxis JSONPath)",
"headers": "Encabezados", "headers": "Encabezados",
"html": "HTML", "html": "HTML",
"image": "Imagen", "image": "Imagen",
@@ -445,13 +446,14 @@
"status": "Estado", "status": "Estado",
"time": "Tiempo", "time": "Tiempo",
"title": "Respuesta", "title": "Respuesta",
"video": "Video",
"waiting_for_connection": "esperando la conexión", "waiting_for_connection": "esperando la conexión",
"xml": "XML" "xml": "XML"
}, },
"settings": { "settings": {
"accent_color": "Color de acentuación", "accent_color": "Color de acentuación",
"account": "Cuenta", "account": "Cuenta",
"account_deleted": "Your account has been deleted", "account_deleted": "Tu cuenta ha sido eliminada",
"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.",
@@ -460,8 +462,8 @@
"change_font_size": "Cambiar tamaño de fuente", "change_font_size": "Cambiar tamaño de fuente",
"choose_language": "Elegir idioma", "choose_language": "Elegir idioma",
"dark_mode": "Oscuro", "dark_mode": "Oscuro",
"delete_account": "Delete account", "delete_account": "Eliminar cuenta",
"delete_account_description": "Once you delete your account, all your data will be permanently deleted. This action cannot be undone.", "delete_account_description": "Una vez que elimines tu cuenta, todos tus datos se borrarán permanentemente. Esta acción no se puede deshacer.",
"expand_navigation": "Expandir la navegación", "expand_navigation": "Expandir la navegación",
"experiments": "Experimentos", "experiments": "Experimentos",
"experiments_notice": "Esta es una colección de experimentos en los que estamos trabajando que podrían resultar útiles, divertidos, ambos o ninguno. No son definitivos y es posible que no sean estables, por lo que si sucede algo demasiado extraño, no se asuste. Solo apaga la maldita cosa. Fuera de bromas,", "experiments_notice": "Esta es una colección de experimentos en los que estamos trabajando que podrían resultar útiles, divertidos, ambos o ninguno. No son definitivos y es posible que no sean estables, por lo que si sucede algo demasiado extraño, no se asuste. Solo apaga la maldita cosa. Fuera de bromas,",
@@ -480,7 +482,7 @@
"light_mode": "Luz", "light_mode": "Luz",
"official_proxy_hosting": "El proxy oficial está alojado en Hoppscotch.", "official_proxy_hosting": "El proxy oficial está alojado en Hoppscotch.",
"profile": "Perfil", "profile": "Perfil",
"profile_description": "Update your profile details", "profile_description": "Actualiza los datos de tu perfil",
"profile_email": "Correo electrónico", "profile_email": "Correo electrónico",
"profile_name": "Nombre de perfil", "profile_name": "Nombre de perfil",
"proxy": "Proxy", "proxy": "Proxy",
@@ -488,8 +490,8 @@
"proxy_use_toggle": "Utilizar el middleware de proxy para enviar peticiones", "proxy_use_toggle": "Utilizar el middleware de proxy para enviar peticiones",
"read_the": "Leer el", "read_the": "Leer el",
"reset_default": "Restablecer a los predeterminados", "reset_default": "Restablecer a los predeterminados",
"short_codes": "Short codes", "short_codes": "Shortcodes",
"short_codes_description": "Short codes which were created by you.", "short_codes_description": "Shortcodes creados por ti.",
"sidebar_on_left": "Barra lateral a la izquierda", "sidebar_on_left": "Barra lateral a la izquierda",
"sync": "Sincronizar", "sync": "Sincronizar",
"sync_collections": "Colecciones", "sync_collections": "Colecciones",
@@ -503,15 +505,15 @@
"theme_description": "Personaliza el tema de tu aplicación.", "theme_description": "Personaliza el tema de tu aplicación.",
"use_experimental_url_bar": "Utilizar la barra de URL experimental con resaltado de entorno", "use_experimental_url_bar": "Utilizar la barra de URL experimental con resaltado de entorno",
"user": "Usuario", "user": "Usuario",
"verified_email": "Verified email", "verified_email": "Correo electrónico verificado",
"verify_email": "Verificar correo electrónico" "verify_email": "Verificar correo electrónico"
}, },
"shortcodes": { "shortcodes": {
"actions": "Actions", "actions": "Acciones",
"created_on": "Created on", "created_on": "Creado el",
"deleted": "Shortcode deleted", "deleted": "Código corto eliminado",
"method": "Method", "method": "Método",
"not_found": "Shortcode not found", "not_found": "Shortcode no encontrado",
"short_code": "Short code", "short_code": "Short code",
"url": "URL" "url": "URL"
}, },
@@ -539,7 +541,7 @@
"title": "Navegación" "title": "Navegación"
}, },
"request": { "request": {
"copy_request_link": "Copiar enlace de petición", "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",
@@ -548,10 +550,10 @@
"post_method": "Seleccionar método POST", "post_method": "Seleccionar método POST",
"previous_method": "Seleccionar método anterior", "previous_method": "Seleccionar método anterior",
"put_method": "Seleccionar método PUT", "put_method": "Seleccionar método PUT",
"reset_request": "Petición de reinicio", "reset_request": "Solicitud de reinicio",
"save_to_collections": "Guardar en colecciones", "save_to_collections": "Guardar en colecciones",
"send_request": "Enviar petición", "send_request": "Enviar solicitud",
"title": "Petición" "title": "Solicitud"
}, },
"response": { "response": {
"copy": "Copiar la respuesta al portapapeles", "copy": "Copiar la respuesta al portapapeles",
@@ -593,8 +595,8 @@
"connected_to": "Conectado a {name}", "connected_to": "Conectado a {name}",
"connecting_to": "Conectando con {name}...", "connecting_to": "Conectando con {name}...",
"connection_error": "Failed to connect", "connection_error": "Failed to connect",
"connection_failed": "Connection failed", "connection_failed": "Error de conexión",
"connection_lost": "Connection lost", "connection_lost": "Conexión perdida",
"copied_to_clipboard": "Copiado al portapapeles", "copied_to_clipboard": "Copiado al portapapeles",
"deleted": "Eliminado", "deleted": "Eliminado",
"deprecated": "OBSOLETO", "deprecated": "OBSOLETO",
@@ -609,18 +611,18 @@
"history_deleted": "Historial eliminado", "history_deleted": "Historial eliminado",
"linewrap": "Envolver líneas", "linewrap": "Envolver líneas",
"loading": "Cargando...", "loading": "Cargando...",
"message_received": "Message: {message} arrived on topic: {topic}", "message_received": "Mensaje: {mensaje} llegó sobre el tema: {topic}",
"mqtt_subscription_failed": "Something went wrong while subscribing to topic: {topic}", "mqtt_subscription_failed": "Algo ha ido mal al suscribirse al tema: {topic}",
"none": "Ninguno", "none": "Ninguno",
"nothing_found": "Nada encontrado para", "nothing_found": "Nada encontrado para",
"published_error": "Something went wrong while publishing msg: {topic} to topic: {message}", "published_error": "Algo ha ido mal al publicar el mensaje: {topic} al tema: {message}",
"published_message": "Published message: {message} to topic: {topic}", "published_message": "Mensaje publicado: {mensaje} al tema: {topic}",
"reconnection_error": "Failed to reconnect", "reconnection_error": "Fallo en la reconexión",
"subscribed_failed": "Failed to subscribe to topic: {topic}", "subscribed_failed": "Error al suscribirse al tema: {topic}",
"subscribed_success": "Successfully subscribed to topic: {topic}", "subscribed_success": "Suscrito con éxito al tema: {topic}",
"unsubscribed_failed": "Failed to unsubscribe from topic: {topic}", "unsubscribed_failed": "Error al darse de baja del tema: {topic}",
"unsubscribed_success": "Successfully unsubscribed from topic: {topic}", "unsubscribed_success": "Se ha cancelado la suscripción al tema: {topic}",
"waiting_send_request": "Esperando para enviar petición" "waiting_send_request": "Esperando para enviar solicitud"
}, },
"support": { "support": {
"changelog": "Leer más sobre los últimos lanzamientos", "changelog": "Leer más sobre los últimos lanzamientos",
@@ -644,7 +646,7 @@
"history": "Historial", "history": "Historial",
"mqtt": "MQTT", "mqtt": "MQTT",
"parameters": "Parámetros", "parameters": "Parámetros",
"pre_request_script": "Script previo a la petición", "pre_request_script": "Script previo a la solicitud",
"queries": "Consultas", "queries": "Consultas",
"query": "Consulta", "query": "Consulta",
"schema": "Esquema", "schema": "Esquema",
@@ -664,9 +666,9 @@
"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",
"invalid_coll_id": "Invalid collection ID", "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": "ID 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.",
"invalid_invite_link": "Enlace de invitación inválido", "invalid_invite_link": "Enlace de invitación inválido",
"invalid_invite_link_description": "El enlace que has seguido no es válido. Ponte en contacto con el propietario de tu equipo.", "invalid_invite_link_description": "El enlace que has seguido no es válido. Ponte en contacto con el propietario de tu equipo.",
"invalid_member_permission": "Proporcionar un permiso válido al miembro del equipo", "invalid_member_permission": "Proporcionar un permiso válido al miembro del equipo",
@@ -683,7 +685,7 @@
"login_to_continue": "Iniciar sesión para continuar", "login_to_continue": "Iniciar sesión para continuar",
"login_to_continue_description": "Tienes que estar conectado para unirte a un equipo.", "login_to_continue_description": "Tienes que estar conectado para unirte a un equipo.",
"logout_and_try_again": "Cerrar la sesión e iniciar sesión con otra cuenta", "logout_and_try_again": "Cerrar la sesión e iniciar sesión con otra cuenta",
"member_has_invite": "Este ID de correo electrónico ya tiene una invitación. Ponte en contacto con el propietario de tu equipo.", "member_has_invite": "Este Identificador de correo electrónico ya tiene una invitación. Ponte en contacto con el propietario de tu equipo.",
"member_not_found": "Miembro no encontrado. Ponte en contacto con el propietario de tu equipo.", "member_not_found": "Miembro no encontrado. Ponte en contacto con el propietario de tu equipo.",
"member_removed": "Usuario eliminado", "member_removed": "Usuario eliminado",
"member_role_updated": "Funciones de usuario actualizadas", "member_role_updated": "Funciones de usuario actualizadas",
@@ -696,10 +698,10 @@
"new_name": "Mi nuevo equipo", "new_name": "Mi nuevo equipo",
"no_access": "No tienes acceso de edición a estas colecciones.", "no_access": "No tienes acceso de edición a estas colecciones.",
"no_invite_found": "No se ha encontrado la invitación. Ponte en contacto con el propietario de tu equipo.", "no_invite_found": "No se ha encontrado la invitación. Ponte en contacto con el propietario de tu equipo.",
"no_request_found": "Request not found.", "no_request_found": "Solicitud no encontrada.",
"not_found": "Equipo no encontrado. Ponte en contacto con el propietario de tu equipo.", "not_found": "Equipo no encontrado. Ponte en contacto con el propietario de tu equipo.",
"not_valid_viewer": "No eres un espectador válido. Ponte en contacto con el propietario de tu equipo.", "not_valid_viewer": "No eres un espectador válido. Ponte en contacto con el propietario de tu equipo.",
"parent_coll_move": "Cannot move collection to a child collection", "parent_coll_move": "No se puede mover la colección a una colección hija",
"pending_invites": "Invitaciones pendientes", "pending_invites": "Invitaciones pendientes",
"permissions": "Permisos", "permissions": "Permisos",
"same_target_destination": "Same target and destination", "same_target_destination": "Same target and destination",
@@ -707,12 +709,12 @@
"select_a_team": "Seleccionar un equipo", "select_a_team": "Seleccionar un equipo",
"title": "Equipos", "title": "Equipos",
"we_sent_invite_link": "¡Hemos enviado un enlace de invitación a todos los invitados!", "we_sent_invite_link": "¡Hemos enviado un enlace de invitación a todos los invitados!",
"we_sent_invite_link_description": "Pide a todos los invitados que revisen su bandeja de entrada. 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."
}, },
"team_environment": { "team_environment": {
"deleted": "Environment Deleted", "deleted": "Entorno eliminado",
"duplicate": "Environment Duplicated", "duplicate": "Entorno duplicado",
"not_found": "Environment not found." "not_found": "Entorno no encontrado."
}, },
"test": { "test": {
"failed": "prueba fallida", "failed": "prueba fallida",
@@ -732,9 +734,9 @@
"url": "URL" "url": "URL"
}, },
"workspace": { "workspace": {
"change": "Change workspace", "change": "Cambiar el espacio de trabajo",
"personal": "My Workspace", "personal": "Mi espacio de trabajo",
"team": "Team Workspace", "team": "Espacio de trabajo en equipo",
"title": "Workspaces" "title": "Espacios de trabajo"
} }
} }

View File

@@ -432,6 +432,7 @@
"view_my_links": "View my links" "view_my_links": "View my links"
}, },
"response": { "response": {
"audio": "Audio",
"body": "Vastauselin", "body": "Vastauselin",
"filter_response_body": "Filter JSON response body (uses JSONPath syntax)", "filter_response_body": "Filter JSON response body (uses JSONPath syntax)",
"headers": "Otsikot", "headers": "Otsikot",
@@ -445,6 +446,7 @@
"status": "Tila", "status": "Tila",
"time": "Aika", "time": "Aika",
"title": "Vastaus", "title": "Vastaus",
"video": "Video",
"waiting_for_connection": "yhteyttä odotellessa", "waiting_for_connection": "yhteyttä odotellessa",
"xml": "XML" "xml": "XML"
}, },

View File

@@ -432,6 +432,7 @@
"view_my_links": "Voir mes liens" "view_my_links": "Voir mes liens"
}, },
"response": { "response": {
"audio": "Audio",
"body": "Corps de réponse", "body": "Corps de réponse",
"filter_response_body": "Filter JSON response body (uses JSONPath syntax)", "filter_response_body": "Filter JSON response body (uses JSONPath syntax)",
"headers": "En-têtes", "headers": "En-têtes",
@@ -445,6 +446,7 @@
"status": "Statut", "status": "Statut",
"time": "Temps", "time": "Temps",
"title": "Réponse", "title": "Réponse",
"video": "Video",
"waiting_for_connection": "En attente de connexion", "waiting_for_connection": "En attente de connexion",
"xml": "XML" "xml": "XML"
}, },

View File

@@ -432,6 +432,7 @@
"view_my_links": "View my links" "view_my_links": "View my links"
}, },
"response": { "response": {
"audio": "Audio",
"body": "גוף תגובה", "body": "גוף תגובה",
"filter_response_body": "Filter JSON response body (uses JSONPath syntax)", "filter_response_body": "Filter JSON response body (uses JSONPath syntax)",
"headers": "כותרות", "headers": "כותרות",
@@ -445,6 +446,7 @@
"status": "סטָטוּס", "status": "סטָטוּס",
"time": "זְמַן", "time": "זְמַן",
"title": "תְגוּבָה", "title": "תְגוּבָה",
"video": "Video",
"waiting_for_connection": "מחכה לחיבור", "waiting_for_connection": "מחכה לחיבור",
"xml": "XML" "xml": "XML"
}, },

View File

@@ -433,6 +433,7 @@
"view_my_links": "मेरे लिंक देखें" "view_my_links": "मेरे लिंक देखें"
}, },
"response": { "response": {
"audio": "Audio",
"body": "प्रतिक्रिया निकाय", "body": "प्रतिक्रिया निकाय",
"filter_response_body": "फ़िल्टर JSON रिस्पांस बॉडी (JSONPATH सिंटैक्स का उपयोग करता है)", "filter_response_body": "फ़िल्टर JSON रिस्पांस बॉडी (JSONPATH सिंटैक्स का उपयोग करता है)",
"headers": "हेडर", "headers": "हेडर",
@@ -446,6 +447,7 @@
"status": "दर्जा", "status": "दर्जा",
"time": "समय", "time": "समय",
"title": "जवाब", "title": "जवाब",
"video": "Video",
"waiting_for_connection": "जुडने के लिए इंतजार", "waiting_for_connection": "जुडने के लिए इंतजार",
"xml": "एक्सएमएल" "xml": "एक्सएमएल"
}, },

View File

@@ -5,29 +5,29 @@
"choose_file": "Válasszon egy fájlt", "choose_file": "Válasszon egy fájlt",
"clear": "Törlés", "clear": "Törlés",
"clear_all": "Összes törlése", "clear_all": "Összes törlése",
"close": "Close", "close": "Bezárás",
"connect": "Kapcsolódás", "connect": "Kapcsolódás",
"connecting": "Connecting", "connecting": "Kapcsolódás",
"copy": "Másolás", "copy": "Másolás",
"delete": "Törlés", "delete": "Törlés",
"disconnect": "Leválasztás", "disconnect": "Leválasztás",
"dismiss": "Eltüntetés", "dismiss": "Eltüntetés",
"dont_save": "Ne mentse", "dont_save": "Ne mentse",
"download_file": "Fájl letöltése", "download_file": "Fájl letöltése",
"drag_to_reorder": "Drag to reorder", "drag_to_reorder": "Húzza az átrendezéshez",
"duplicate": "Kettőzés", "duplicate": "Kettőzés",
"edit": "Szerkesztés", "edit": "Szerkesztés",
"filter": "Filter", "filter": "Szűrő",
"go_back": "Vissza", "go_back": "Vissza",
"go_forward": "Go forward", "go_forward": "Előre",
"group_by": "Group by", "group_by": "Csoportosítás",
"label": "Címke", "label": "Címke",
"learn_more": "Tudjon meg többet", "learn_more": "Tudjon meg többet",
"less": "Kevesebb", "less": "Kevesebb",
"more": "Több", "more": "Több",
"new": "Új", "new": "Új",
"no": "Nem", "no": "Nem",
"open_workspace": "Open workspace", "open_workspace": "Munkaterület megnyitása",
"paste": "Beillesztés", "paste": "Beillesztés",
"prettify": "Csinosítás", "prettify": "Csinosítás",
"remove": "Eltávolítás", "remove": "Eltávolítás",
@@ -38,7 +38,7 @@
"search": "Keresés", "search": "Keresés",
"send": "Küldés", "send": "Küldés",
"start": "Indítás", "start": "Indítás",
"starting": "Starting", "starting": "Indítás",
"stop": "Leállítás", "stop": "Leállítás",
"to_close": "a bezáráshoz", "to_close": "a bezáráshoz",
"to_navigate": "a navigáláshoz", "to_navigate": "a navigáláshoz",
@@ -118,16 +118,16 @@
}, },
"collection": { "collection": {
"created": "Gyűjtemény létrehozva", "created": "Gyűjtemény létrehozva",
"different_parent": "Cannot reorder collection with different parent", "different_parent": "Nem lehet átrendezni a különböző szülővel rendelkező gyűjteményt",
"edit": "Gyűjtemény szerkesztése", "edit": "Gyűjtemény szerkesztése",
"invalid_name": "Adjon nevet a gyűjteménynek", "invalid_name": "Adjon nevet a gyűjteménynek",
"invalid_root_move": "Collection already in the root", "invalid_root_move": "A gyűjtemény már a gyökérben van",
"moved": "Moved Successfully", "moved": "Sikeresen áthelyezve",
"my_collections": "Saját gyűjtemények", "my_collections": "Saját gyűjtemények",
"name": "Saját új gyűjtemény", "name": "Saját új gyűjtemény",
"name_length_insufficient": "A gyűjtemény nevének legalább 3 karakter hosszúságúnak kell lennie", "name_length_insufficient": "A gyűjtemény nevének legalább 3 karakter hosszúságúnak kell lennie",
"new": "Új gyűjtemény", "new": "Új gyűjtemény",
"order_changed": "Collection Order Updated", "order_changed": "Gyűjtemény sorrendje frissítve",
"renamed": "Gyűjtemény átnevezve", "renamed": "Gyűjtemény átnevezve",
"request_in_use": "A kérés használatban", "request_in_use": "A kérés használatban",
"save_as": "Mentés másként", "save_as": "Mentés másként",
@@ -147,7 +147,7 @@
"remove_team": "Biztosan törölni szeretné ezt a csapatot?", "remove_team": "Biztosan törölni szeretné ezt a csapatot?",
"remove_telemetry": "Biztosan ki szeretné kapcsolni a telemetriát?", "remove_telemetry": "Biztosan ki szeretné kapcsolni a telemetriát?",
"request_change": "Biztosan el szeretné vetni a jelenlegi kérést? Minden mentetlen változtatás el fog veszni.", "request_change": "Biztosan el szeretné vetni a jelenlegi kérést? Minden mentetlen változtatás el fog veszni.",
"save_unsaved_tab": "Do you want to save changes made in this tab?", "save_unsaved_tab": "Szeretné menteni az ezen a lapon elvégzett változtatásokat?",
"sync": "Szeretné visszaállítani a munkaterületét a felhőből? Ez el fogja vetni a helyi folyamatát." "sync": "Szeretné visszaállítani a munkaterületét a felhőből? Ez el fogja vetni a helyi folyamatát."
}, },
"count": { "count": {
@@ -180,8 +180,8 @@
"profile": "Jelentkezzen be a profilja megtekintéséhez", "profile": "Jelentkezzen be a profilja megtekintéséhez",
"protocols": "A protokollok üresek", "protocols": "A protokollok üresek",
"schema": "Kapcsolódjon egy GraphQL-végponthoz a séma megtekintéséhez", "schema": "Kapcsolódjon egy GraphQL-végponthoz a séma megtekintéséhez",
"shortcodes": "Shortcodes are empty", "shortcodes": "A rövid kódok üresek",
"subscription": "Subscriptions are empty", "subscription": "A feliratkozások üresek",
"team_name": "A csapat neve üres", "team_name": "A csapat neve üres",
"teams": "Ön nem tartozik semmilyen csapathoz", "teams": "Ön nem tartozik semmilyen csapathoz",
"tests": "Nincsenek tesztek ehhez a kéréshez" "tests": "Nincsenek tesztek ehhez a kéréshez"
@@ -194,13 +194,13 @@
"deleted": "Környezet törlése", "deleted": "Környezet törlése",
"edit": "Környezet szerkesztése", "edit": "Környezet szerkesztése",
"invalid_name": "Adjon nevet a környezetnek", "invalid_name": "Adjon nevet a környezetnek",
"my_environments": "My Environments", "my_environments": "Saját környezetek",
"nested_overflow": "az egymásba ágyazott környezeti változók 10 szintre vannak korlátozva", "nested_overflow": "az egymásba ágyazott környezeti változók 10 szintre vannak korlátozva",
"new": "Új környezet", "new": "Új környezet",
"no_environment": "Nincs környezet", "no_environment": "Nincs környezet",
"no_environment_description": "Nem lettek környezetek kiválasztva. Válassza ki, hogy mit kell tenni a következő változókkal.", "no_environment_description": "Nem lettek környezetek kiválasztva. Válassza ki, hogy mit kell tenni a következő változókkal.",
"select": "Környezet kiválasztása", "select": "Környezet kiválasztása",
"team_environments": "Team Environments", "team_environments": "Csapatkörnyezetek",
"title": "Környezetek", "title": "Környezetek",
"updated": "Környezet frissítve", "updated": "Környezet frissítve",
"variable_list": "Változólista" "variable_list": "Változólista"
@@ -209,9 +209,9 @@
"browser_support_sse": "Úgy tűnik, hogy ez a böngésző nem támogatja a kiszolgáló által küldött eseményeket.", "browser_support_sse": "Úgy tűnik, hogy ez a böngésző nem támogatja a kiszolgáló által küldött eseményeket.",
"check_console_details": "Nézze meg a konzolnaplót a részletekért.", "check_console_details": "Nézze meg a konzolnaplót a részletekért.",
"curl_invalid_format": "A cURL nincs megfelelően formázva", "curl_invalid_format": "A cURL nincs megfelelően formázva",
"danger_zone": "Danger zone", "danger_zone": "Veszélyes zóna",
"delete_account": "Your account is currently an owner in these teams:", "delete_account": "Az Ön fiókja jelenleg tulajdonos ezekben a csapatokban:",
"delete_account_description": "You must either remove yourself, transfer ownership, or delete these teams before you can delete your account.", "delete_account_description": "El kell távolítani magát, át kell adnia a tulajdonjogot vagy törölnie kell ezeket a csapatokat, mielőtt törölhetné a fiókját.",
"empty_req_name": "Üres kérésnév", "empty_req_name": "Üres kérésnév",
"f12_details": "(F12 a részletekért)", "f12_details": "(F12 a részletekért)",
"gql_prettify_invalid_query": "Nem sikerült csinosítani egy érvénytelen lekérdezést, oldja meg a lekérdezés szintaktikai hibáit, és próbálja újra", "gql_prettify_invalid_query": "Nem sikerült csinosítani egy érvénytelen lekérdezést, oldja meg a lekérdezés szintaktikai hibáit, és próbálja újra",
@@ -219,13 +219,13 @@
"incorrect_email": "Hibás e-mail", "incorrect_email": "Hibás e-mail",
"invalid_link": "Érvénytelen hivatkozás", "invalid_link": "Érvénytelen hivatkozás",
"invalid_link_description": "A kattintott hivatkozás érvénytelen vagy lejárt.", "invalid_link_description": "A kattintott hivatkozás érvénytelen vagy lejárt.",
"json_parsing_failed": "Invalid JSON", "json_parsing_failed": "Érvénytelen JSON",
"json_prettify_invalid_body": "Nem sikerült csinosítani egy érvénytelen törzset, oldja meg a JSON szintaktikai hibáit, és próbálja újra", "json_prettify_invalid_body": "Nem sikerült csinosítani egy érvénytelen törzset, oldja meg a JSON szintaktikai hibáit, és próbálja újra",
"network_error": "Úgy tűnik, hogy hálózati hiba van. Próbálja újra.", "network_error": "Úgy tűnik, hogy hálózati hiba van. Próbálja újra.",
"network_fail": "Nem sikerült elküldeni a kérést", "network_fail": "Nem sikerült elküldeni a kérést",
"no_duration": "Nincs időtartam", "no_duration": "Nincs időtartam",
"no_results_found": "No matches found", "no_results_found": "Nincs találat",
"page_not_found": "This page could not be found", "page_not_found": "Ez az oldal nem található",
"script_fail": "Nem sikerült végrehajtani a kérés előtti parancsfájlt", "script_fail": "Nem sikerült végrehajtani a kérés előtti parancsfájlt",
"something_went_wrong": "Valami elromlott", "something_went_wrong": "Valami elromlott",
"test_script_fail": "Nem sikerült végrehajtani a kérés utáni parancsfájlt" "test_script_fail": "Nem sikerült végrehajtani a kérés utáni parancsfájlt"
@@ -238,9 +238,9 @@
"title": "Exportálás" "title": "Exportálás"
}, },
"filter": { "filter": {
"all": "All", "all": "Összes",
"none": "None", "none": "Nincs",
"starred": "Starred" "starred": "Csillagozott"
}, },
"folder": { "folder": {
"created": "Mappa létrehozva", "created": "Mappa létrehozva",
@@ -256,7 +256,7 @@
"subscriptions": "Feliratkozások" "subscriptions": "Feliratkozások"
}, },
"group": { "group": {
"time": "Time", "time": "Idő",
"url": "URL" "url": "URL"
}, },
"header": { "header": {
@@ -316,32 +316,32 @@
"zen_mode": "Zen mód" "zen_mode": "Zen mód"
}, },
"modal": { "modal": {
"close_unsaved_tab": "You have unsaved changes", "close_unsaved_tab": "Elmentetlen változtatásai vannak",
"collections": "Gyűjtemények", "collections": "Gyűjtemények",
"confirm": "Megerősítés", "confirm": "Megerősítés",
"edit_request": "Kérés szerkesztése", "edit_request": "Kérés szerkesztése",
"import_export": "Importálás és exportálás" "import_export": "Importálás és exportálás"
}, },
"mqtt": { "mqtt": {
"already_subscribed": "You are already subscribed to this topic.", "already_subscribed": "Ön már feliratkozott erre a témára.",
"clean_session": "Clean Session", "clean_session": "Munkamenet törlése",
"clear_input": "Clear input", "clear_input": "Bevitel törlése",
"clear_input_on_send": "Clear input on send", "clear_input_on_send": "Bevitel törlése küldéskor",
"client_id": "Client ID", "client_id": "Ügyfél-azonosító",
"color": "Pick a color", "color": "Válasszon színt",
"communication": "Kommunikáció", "communication": "Kommunikáció",
"connection_config": "Connection Config", "connection_config": "Kapcsolat beállításai",
"connection_not_authorized": "This MQTT connection does not use any authentication.", "connection_not_authorized": "Ez az MQTT-kapcsolat nem használ semmilyen hitelesítést.",
"invalid_topic": "Please provide a topic for the subscription", "invalid_topic": "Adjon témát a feliratkozáshoz",
"keep_alive": "Keep Alive", "keep_alive": "Életben tartás",
"log": "Napló", "log": "Napló",
"lw_message": "Last-Will Message", "lw_message": "Utolsó kívánság üzenet",
"lw_qos": "Last-Will QoS", "lw_qos": "Utolsó kívánság QoS",
"lw_retain": "Last-Will Retain", "lw_retain": "Utolsó kívánság megtartás",
"lw_topic": "Last-Will Topic", "lw_topic": "Utolsó kívánság téma",
"message": "Üzenet", "message": "Üzenet",
"new": "New Subscription", "new": "Új feliratkozás",
"not_connected": "Please start a MQTT connection first.", "not_connected": "Először indítson egy MQTT-kapcsolatot.",
"publish": "Közzététel", "publish": "Közzététel",
"qos": "QoS", "qos": "QoS",
"ssl": "SSL", "ssl": "SSL",
@@ -368,7 +368,7 @@
}, },
"profile": { "profile": {
"app_settings": "Alkalmazás beállításai", "app_settings": "Alkalmazás beállításai",
"default_hopp_displayname": "Unnamed User", "default_hopp_displayname": "Névtelen felhasználó",
"editor": "Szerkesztő", "editor": "Szerkesztő",
"editor_description": "A szerkesztők hozzáadhatnak, szerkeszthetnek és törölhetnek kéréseket.", "editor_description": "A szerkesztők hozzáadhatnak, szerkeszthetnek és törölhetnek kéréseket.",
"email_verification_mail": "Egy ellenőrző e-mail el lett küldve az e-mail-címére. Kattintson a hivatkozásra az e-mail-címe ellenőrzéséhez.", "email_verification_mail": "Egy ellenőrző e-mail el lett küldve az e-mail-címére. Kattintson a hivatkozásra az e-mail-címe ellenőrzéséhez.",
@@ -391,26 +391,26 @@
"choose_language": "Nyelv kiválasztása", "choose_language": "Nyelv kiválasztása",
"content_type": "Tartalom típusa", "content_type": "Tartalom típusa",
"content_type_titles": { "content_type_titles": {
"others": "Others", "others": "Egyebek",
"structured": "Structured", "structured": "Szerkesztett",
"text": "Text" "text": "Szöveg"
}, },
"copy_link": "Hivatkozás másolása", "copy_link": "Hivatkozás másolása",
"different_collection": "Cannot reorder requests from different collections", "different_collection": "Nem lehet átrendezni a különböző gyűjteményekből érkező kéréseket",
"duplicated": "Request duplicated", "duplicated": "Kérés megkettőzve",
"duration": "Időtartam", "duration": "Időtartam",
"enter_curl": "cURL megadása", "enter_curl": "cURL-parancs megadása",
"generate_code": "Kód előállítása", "generate_code": "Kód előállítása",
"generated_code": "Előállított kód", "generated_code": "Előállított kód",
"header_list": "Fejléclista", "header_list": "Fejléclista",
"invalid_name": "Adjon nevet a kérésnek", "invalid_name": "Adjon nevet a kérésnek",
"method": "Módszer", "method": "Módszer",
"moved": "Request moved", "moved": "Kérés áthelyezve",
"name": "Kérés neve", "name": "Kérés neve",
"new": "Új kérés", "new": "Új kérés",
"order_changed": "Request Order Updated", "order_changed": "Kérés sorrendje frissítve",
"override": "Felülbírálás", "override": "Felülbírálás",
"override_help": "A <kbd>Content-Type</kbd> beállítása a fejlécekben", "override_help": "<kbd>Content-Type</kbd> beállítása a fejlécekben",
"overriden": "Felülbírálva", "overriden": "Felülbírálva",
"parameter_list": "Lekérdezési paraméterek", "parameter_list": "Lekérdezési paraméterek",
"parameters": "Paraméterek", "parameters": "Paraméterek",
@@ -429,11 +429,12 @@
"type": "Kérés típusa", "type": "Kérés típusa",
"url": "URL", "url": "URL",
"variables": "Változók", "variables": "Változók",
"view_my_links": "View my links" "view_my_links": "Saját hivatkozások megtekintése"
}, },
"response": { "response": {
"audio": "Hang",
"body": "Válasz törzse", "body": "Válasz törzse",
"filter_response_body": "Filter JSON response body (uses JSONPath syntax)", "filter_response_body": "JSON-válasz törzsének szűrése (JSONPath szintaxist használ)",
"headers": "Fejlécek", "headers": "Fejlécek",
"html": "HTML", "html": "HTML",
"image": "Kép", "image": "Kép",
@@ -445,13 +446,14 @@
"status": "Állapot", "status": "Állapot",
"time": "Idő", "time": "Idő",
"title": "Válasz", "title": "Válasz",
"video": "Videó",
"waiting_for_connection": "várakozás kapcsolódásra", "waiting_for_connection": "várakozás kapcsolódásra",
"xml": "XML" "xml": "XML"
}, },
"settings": { "settings": {
"accent_color": "Kiemelőszín", "accent_color": "Kiemelőszín",
"account": "Fiók", "account": "Fiók",
"account_deleted": "Your account has been deleted", "account_deleted": "A fiókja törölve lett",
"account_description": "A fiókbeállítások személyre szabása.", "account_description": "A fiókbeállítások személyre szabása.",
"account_email_description": "Az Ön elsődleges e-mail-címe.", "account_email_description": "Az Ön elsődleges e-mail-címe.",
"account_name_description": "Ez a megjelenített neve.", "account_name_description": "Ez a megjelenített neve.",
@@ -460,8 +462,8 @@
"change_font_size": "Betűméret megváltoztatása", "change_font_size": "Betűméret megváltoztatása",
"choose_language": "Nyelv kiválasztása", "choose_language": "Nyelv kiválasztása",
"dark_mode": "Sötét", "dark_mode": "Sötét",
"delete_account": "Delete account", "delete_account": "Fiók törlése",
"delete_account_description": "Once you delete your account, all your data will be permanently deleted. This action cannot be undone.", "delete_account_description": "Ha törli a fiókját, akkor az összes adata véglegesen törlésre kerül. Ezt a műveletet nem lehet visszavonni.",
"expand_navigation": "Navigáció kinyitása", "expand_navigation": "Navigáció kinyitása",
"experiments": "Kísérletek", "experiments": "Kísérletek",
"experiments_notice": "Ez olyan kísérletek gyűjteménye, amelyeken dolgozunk, és amelyek hasznosak, szórakoztatóak lehetnek, mindkettő, vagy egyik sem. Ezek nem véglegesek és nem stabilak, ezért ha valami túl furcsa dolog történik, ne essen pánikba. Egyszerűen kapcsolja ki a hibás dolgot. Viccet félretéve, ", "experiments_notice": "Ez olyan kísérletek gyűjteménye, amelyeken dolgozunk, és amelyek hasznosak, szórakoztatóak lehetnek, mindkettő, vagy egyik sem. Ezek nem véglegesek és nem stabilak, ezért ha valami túl furcsa dolog történik, ne essen pánikba. Egyszerűen kapcsolja ki a hibás dolgot. Viccet félretéve, ",
@@ -488,8 +490,8 @@
"proxy_use_toggle": "A proxy középprogram használata a kérések küldéséhez", "proxy_use_toggle": "A proxy középprogram használata a kérések küldéséhez",
"read_the": "Olvassa el:", "read_the": "Olvassa el:",
"reset_default": "Visszaállítás az alapértelmezettre", "reset_default": "Visszaállítás az alapértelmezettre",
"short_codes": "Short codes", "short_codes": "Rövid kódok",
"short_codes_description": "Short codes which were created by you.", "short_codes_description": "Az Ön által létrehozott rövid kódok.",
"sidebar_on_left": "Oldalsáv a bal oldalon", "sidebar_on_left": "Oldalsáv a bal oldalon",
"sync": "Szinkronizálás", "sync": "Szinkronizálás",
"sync_collections": "Gyűjtemények", "sync_collections": "Gyűjtemények",
@@ -503,16 +505,16 @@
"theme_description": "Az alkalmazás témájának személyre szabása.", "theme_description": "Az alkalmazás témájának személyre szabása.",
"use_experimental_url_bar": "Kísérleti URL-sáv használata a környezet kiemelésével", "use_experimental_url_bar": "Kísérleti URL-sáv használata a környezet kiemelésével",
"user": "Felhasználó", "user": "Felhasználó",
"verified_email": "Verified email", "verified_email": "Ellenőrzött e-mail-cím",
"verify_email": "E-mail-cím ellenőrzése" "verify_email": "E-mail-cím ellenőrzése"
}, },
"shortcodes": { "shortcodes": {
"actions": "Actions", "actions": "Műveletek",
"created_on": "Created on", "created_on": "Létrehozva",
"deleted": "Shortcode deleted", "deleted": "Rövid kód törölve",
"method": "Method", "method": "Módszer",
"not_found": "Shortcode not found", "not_found": "A rövid kód nem található",
"short_code": "Short code", "short_code": "Rövid kód",
"url": "URL" "url": "URL"
}, },
"shortcut": { "shortcut": {
@@ -554,9 +556,9 @@
"title": "Kérés" "title": "Kérés"
}, },
"response": { "response": {
"copy": "Copy response to clipboard", "copy": "Válasz másolása a vágólapra",
"download": "Download response as file", "download": "Válasz letöltés fájlként",
"title": "Response" "title": "Válasz"
}, },
"theme": { "theme": {
"black": "Téma átváltása fekete módra", "black": "Téma átváltása fekete módra",
@@ -574,8 +576,8 @@
}, },
"socketio": { "socketio": {
"communication": "Kommunikáció", "communication": "Kommunikáció",
"connection_not_authorized": "This SocketIO connection does not use any authentication.", "connection_not_authorized": "Ez a SocketIO-kapcsolat nem használ semmilyen hitelesítést.",
"event_name": "Esemény neve", "event_name": "Esemény vagy téma neve",
"events": "Események", "events": "Események",
"log": "Napló", "log": "Napló",
"url": "URL" "url": "URL"
@@ -592,9 +594,9 @@
"connected": "Kapcsolódva", "connected": "Kapcsolódva",
"connected_to": "Kapcsolódva ehhez: {name}", "connected_to": "Kapcsolódva ehhez: {name}",
"connecting_to": "Kapcsolódás ehhez: {name}…", "connecting_to": "Kapcsolódás ehhez: {name}…",
"connection_error": "Failed to connect", "connection_error": "Nem sikerült kapcsolódni",
"connection_failed": "Connection failed", "connection_failed": "A kapcsolódás sikertelen",
"connection_lost": "Connection lost", "connection_lost": "A kapcsolat elveszett",
"copied_to_clipboard": "Vágólapra másolva", "copied_to_clipboard": "Vágólapra másolva",
"deleted": "Törölve", "deleted": "Törölve",
"deprecated": "ELAVULT", "deprecated": "ELAVULT",
@@ -609,17 +611,17 @@
"history_deleted": "Előzmények törölve", "history_deleted": "Előzmények törölve",
"linewrap": "Sorok tördelése", "linewrap": "Sorok tördelése",
"loading": "Betöltés…", "loading": "Betöltés…",
"message_received": "Message: {message} arrived on topic: {topic}", "message_received": "Üzenet: {message} érkezett ehhez a témához: {topic}",
"mqtt_subscription_failed": "Something went wrong while subscribing to topic: {topic}", "mqtt_subscription_failed": "Valami elromlott a következő témára való feliratkozás során: {topic}",
"none": "Nincs", "none": "Nincs",
"nothing_found": "Semmi sem található ehhez:", "nothing_found": "Semmi sem található ehhez:",
"published_error": "Something went wrong while publishing msg: {topic} to topic: {message}", "published_error": "Valami elromlott a következő üzenet közzététele során: {topic}, ehhez a témához: {message}",
"published_message": "Published message: {message} to topic: {topic}", "published_message": "Közzétett üzenet: {message}, ehhez a témához: {topic}",
"reconnection_error": "Failed to reconnect", "reconnection_error": "Nem sikerült újrakapcsolódni",
"subscribed_failed": "Failed to subscribe to topic: {topic}", "subscribed_failed": "Nem sikerült feliratkozni erre a témára: {topic}",
"subscribed_success": "Successfully subscribed to topic: {topic}", "subscribed_success": "Sikeresen feliratkozott erre a témára: {topic}",
"unsubscribed_failed": "Failed to unsubscribe from topic: {topic}", "unsubscribed_failed": "Nem sikerült leiratkozni erről a témáról: {topic}",
"unsubscribed_success": "Successfully unsubscribed from topic: {topic}", "unsubscribed_success": "Sikeresen leiratkozott erről a témáról: {topic}",
"waiting_send_request": "Várakozás a kérés elküldésére" "waiting_send_request": "Várakozás a kérés elküldésére"
}, },
"support": { "support": {
@@ -639,7 +641,7 @@
"body": "Törzs", "body": "Törzs",
"collections": "Gyűjtemények", "collections": "Gyűjtemények",
"documentation": "Dokumentáció", "documentation": "Dokumentáció",
"environments": "Environments", "environments": "Környezetek",
"headers": "Fejlécek", "headers": "Fejlécek",
"history": "Előzmények", "history": "Előzmények",
"mqtt": "MQTT", "mqtt": "MQTT",
@@ -664,7 +666,7 @@
"email_do_not_match": "Az e-mail-cím nem egyezik a fiókja részleteivel. Vegye fel a kapcsolatot a csapat tulajdonosával.", "email_do_not_match": "Az e-mail-cím nem egyezik a fiókja részleteivel. Vegye fel a kapcsolatot a csapat tulajdonosával.",
"exit": "Kilépés a csapatból", "exit": "Kilépés a csapatból",
"exit_disabled": "Csak a tulajdonos nem léphet ki a csapatból", "exit_disabled": "Csak a tulajdonos nem léphet ki a csapatból",
"invalid_coll_id": "Invalid collection ID", "invalid_coll_id": "Érvénytelen gyűjteményazonosító",
"invalid_email_format": "Az e-mail formátuma érvénytelen", "invalid_email_format": "Az e-mail formátuma érvénytelen",
"invalid_id": "Érvénytelen csapatazonosító. Vegye fel a kapcsolatot a csapat tulajdonosával.", "invalid_id": "Érvénytelen csapatazonosító. Vegye fel a kapcsolatot a csapat tulajdonosával.",
"invalid_invite_link": "Érvénytelen meghívási hivatkozás", "invalid_invite_link": "Érvénytelen meghívási hivatkozás",
@@ -688,7 +690,7 @@
"member_removed": "Felhasználó eltávolítva", "member_removed": "Felhasználó eltávolítva",
"member_role_updated": "Felhasználói szerepek frissítve", "member_role_updated": "Felhasználói szerepek frissítve",
"members": "Tagok", "members": "Tagok",
"more_members": "+{count} more", "more_members": "+{count} további",
"name_length_insufficient": "A csapat nevének legalább 6 karakter hosszúságúnak kell lennie", "name_length_insufficient": "A csapat nevének legalább 6 karakter hosszúságúnak kell lennie",
"name_updated": "Csapatnév frissítve", "name_updated": "Csapatnév frissítve",
"new": "Új csapat", "new": "Új csapat",
@@ -696,13 +698,13 @@
"new_name": "Saját új csapat", "new_name": "Saját új csapat",
"no_access": "Nincs szerkesztési jogosultsága ezekhez a gyűjteményekhez", "no_access": "Nincs szerkesztési jogosultsága ezekhez a gyűjteményekhez",
"no_invite_found": "A meghívás nem található. Vegye fel a kapcsolatot a csapat tulajdonosával.", "no_invite_found": "A meghívás nem található. Vegye fel a kapcsolatot a csapat tulajdonosával.",
"no_request_found": "Request not found.", "no_request_found": "A kérés nem található.",
"not_found": "A csapat nem található. Vegye fel a kapcsolatot a csapat tulajdonosával.", "not_found": "A csapat nem található. Vegye fel a kapcsolatot a csapat tulajdonosával.",
"not_valid_viewer": "Ön nem érvényes megtekintő. Vegye fel a kapcsolatot a csapat tulajdonosával.", "not_valid_viewer": "Ön nem érvényes megtekintő. Vegye fel a kapcsolatot a csapat tulajdonosával.",
"parent_coll_move": "Cannot move collection to a child collection", "parent_coll_move": "Nem lehet áthelyezni a gyűjteményt egy gyermekgyűjteménybe",
"pending_invites": "Függőben lévő meghívások", "pending_invites": "Függőben lévő meghívások",
"permissions": "Jogosultságok", "permissions": "Jogosultságok",
"same_target_destination": "Same target and destination", "same_target_destination": "Ugyanaz a cél és célhely",
"saved": "Csapat elmentve", "saved": "Csapat elmentve",
"select_a_team": "Csapat kiválasztása", "select_a_team": "Csapat kiválasztása",
"title": "Csapatok", "title": "Csapatok",
@@ -710,9 +712,9 @@
"we_sent_invite_link_description": "Kérje meg az összes meghívottat, hogy nézzék meg a beérkező leveleiket. Kattintsanak a hivatkozásra a csapathoz való csatlakozáshoz." "we_sent_invite_link_description": "Kérje meg az összes meghívottat, hogy nézzék meg a beérkező leveleiket. Kattintsanak a hivatkozásra a csapathoz való csatlakozáshoz."
}, },
"team_environment": { "team_environment": {
"deleted": "Environment Deleted", "deleted": "Környezet törölve",
"duplicate": "Environment Duplicated", "duplicate": "Környezet megkettőzve",
"not_found": "Environment not found." "not_found": "A környezet nem található."
}, },
"test": { "test": {
"failed": "teszt sikertelen", "failed": "teszt sikertelen",
@@ -732,9 +734,9 @@
"url": "URL" "url": "URL"
}, },
"workspace": { "workspace": {
"change": "Change workspace", "change": "Munkaterület váltása",
"personal": "My Workspace", "personal": "Saját munkaterület",
"team": "Team Workspace", "team": "Csapat-munkaterület",
"title": "Workspaces" "title": "Munkaterületek"
} }
} }

View File

@@ -432,6 +432,7 @@
"view_my_links": "Lihat tautan saya" "view_my_links": "Lihat tautan saya"
}, },
"response": { "response": {
"audio": "Audio",
"body": "Response Body", "body": "Response Body",
"filter_response_body": "Filter body respons JSON (menggunakan sintaks JSONPath)", "filter_response_body": "Filter body respons JSON (menggunakan sintaks JSONPath)",
"headers": "Headers", "headers": "Headers",
@@ -445,6 +446,7 @@
"status": "Status", "status": "Status",
"time": "Waktu", "time": "Waktu",
"title": "Response", "title": "Response",
"video": "Video",
"waiting_for_connection": "Menunggu koneksi", "waiting_for_connection": "Menunggu koneksi",
"xml": "XML" "xml": "XML"
}, },

View File

@@ -432,6 +432,7 @@
"view_my_links": "View my links" "view_my_links": "View my links"
}, },
"response": { "response": {
"audio": "Audio",
"body": "Corpo della risposta", "body": "Corpo della risposta",
"filter_response_body": "Filter JSON response body (uses JSONPath syntax)", "filter_response_body": "Filter JSON response body (uses JSONPath syntax)",
"headers": "Intestazioni", "headers": "Intestazioni",
@@ -445,6 +446,7 @@
"status": "Stato", "status": "Stato",
"time": "Tempo impiegato", "time": "Tempo impiegato",
"title": "Risposta", "title": "Risposta",
"video": "Video",
"waiting_for_connection": "In attesa di connessione", "waiting_for_connection": "In attesa di connessione",
"xml": "XML" "xml": "XML"
}, },

View File

@@ -432,6 +432,7 @@
"view_my_links": "自分のリンクを見る" "view_my_links": "自分のリンクを見る"
}, },
"response": { "response": {
"audio": "Audio",
"body": "レスポンスボディ", "body": "レスポンスボディ",
"filter_response_body": "JSONレスポンスボディをフィルタ (JSONPathシンタックスを使用)", "filter_response_body": "JSONレスポンスボディをフィルタ (JSONPathシンタックスを使用)",
"headers": "ヘッダー", "headers": "ヘッダー",
@@ -445,6 +446,7 @@
"status": "ステータス", "status": "ステータス",
"time": "時間", "time": "時間",
"title": "レスポンス", "title": "レスポンス",
"video": "Video",
"waiting_for_connection": "接続を待っています", "waiting_for_connection": "接続を待っています",
"xml": "XML" "xml": "XML"
}, },

View File

@@ -432,6 +432,7 @@
"view_my_links": "내 링크 보기" "view_my_links": "내 링크 보기"
}, },
"response": { "response": {
"audio": "Audio",
"body": "응답 본문", "body": "응답 본문",
"filter_response_body": "Filter JSON response body (uses JSONPath syntax)", "filter_response_body": "Filter JSON response body (uses JSONPath syntax)",
"headers": "헤더", "headers": "헤더",
@@ -445,6 +446,7 @@
"status": "상태", "status": "상태",
"time": "시간", "time": "시간",
"title": "제목", "title": "제목",
"video": "Video",
"waiting_for_connection": "연결 대기 중", "waiting_for_connection": "연결 대기 중",
"xml": "XML" "xml": "XML"
}, },

View File

@@ -432,6 +432,7 @@
"view_my_links": "View my links" "view_my_links": "View my links"
}, },
"response": { "response": {
"audio": "Audio",
"body": "Reactie inhoud", "body": "Reactie inhoud",
"filter_response_body": "Filter JSON response body (uses JSONPath syntax)", "filter_response_body": "Filter JSON response body (uses JSONPath syntax)",
"headers": "Headers", "headers": "Headers",
@@ -445,6 +446,7 @@
"status": "Status", "status": "Status",
"time": "Tijd", "time": "Tijd",
"title": "Antwoord", "title": "Antwoord",
"video": "Video",
"waiting_for_connection": "wachten op verbinding", "waiting_for_connection": "wachten op verbinding",
"xml": "XML" "xml": "XML"
}, },

View File

@@ -432,6 +432,7 @@
"view_my_links": "View my links" "view_my_links": "View my links"
}, },
"response": { "response": {
"audio": "Audio",
"body": "Svarkropp", "body": "Svarkropp",
"filter_response_body": "Filter JSON response body (uses JSONPath syntax)", "filter_response_body": "Filter JSON response body (uses JSONPath syntax)",
"headers": "Overskrifter", "headers": "Overskrifter",
@@ -445,6 +446,7 @@
"status": "Status", "status": "Status",
"time": "Tid", "time": "Tid",
"title": "Respons", "title": "Respons",
"video": "Video",
"waiting_for_connection": "venter på tilkobling", "waiting_for_connection": "venter på tilkobling",
"xml": "XML" "xml": "XML"
}, },

View File

@@ -432,6 +432,7 @@
"view_my_links": "View my links" "view_my_links": "View my links"
}, },
"response": { "response": {
"audio": "Audio",
"body": "Ciało odpowiedzi", "body": "Ciało odpowiedzi",
"filter_response_body": "Filter JSON response body (uses JSONPath syntax)", "filter_response_body": "Filter JSON response body (uses JSONPath syntax)",
"headers": "Nagłówki", "headers": "Nagłówki",
@@ -445,6 +446,7 @@
"status": "Status", "status": "Status",
"time": "Czas", "time": "Czas",
"title": "Odpowiedź", "title": "Odpowiedź",
"video": "Video",
"waiting_for_connection": "oczekiwanie na połączenie", "waiting_for_connection": "oczekiwanie na połączenie",
"xml": "XML" "xml": "XML"
}, },

View File

@@ -432,6 +432,7 @@
"view_my_links": "View my links" "view_my_links": "View my links"
}, },
"response": { "response": {
"audio": "Audio",
"body": "Corpo de Resposta", "body": "Corpo de Resposta",
"filter_response_body": "Filter JSON response body (uses JSONPath syntax)", "filter_response_body": "Filter JSON response body (uses JSONPath syntax)",
"headers": "Cabeçalhos", "headers": "Cabeçalhos",
@@ -445,6 +446,7 @@
"status": "Status", "status": "Status",
"time": "Tempo", "time": "Tempo",
"title": "Resposta", "title": "Resposta",
"video": "Video",
"waiting_for_connection": "aguardando conexão", "waiting_for_connection": "aguardando conexão",
"xml": "XML" "xml": "XML"
}, },

View File

@@ -432,6 +432,7 @@
"view_my_links": "View my links" "view_my_links": "View my links"
}, },
"response": { "response": {
"audio": "Audio",
"body": "Corpo de Resposta", "body": "Corpo de Resposta",
"filter_response_body": "Filter JSON response body (uses JSONPath syntax)", "filter_response_body": "Filter JSON response body (uses JSONPath syntax)",
"headers": "Cabeçalhos", "headers": "Cabeçalhos",
@@ -445,6 +446,7 @@
"status": "Status", "status": "Status",
"time": "Tempo", "time": "Tempo",
"title": "Resposta", "title": "Resposta",
"video": "Video",
"waiting_for_connection": "aguardando conexão", "waiting_for_connection": "aguardando conexão",
"xml": "XML" "xml": "XML"
}, },

View File

@@ -432,6 +432,7 @@
"view_my_links": "Vizualizare link-uri" "view_my_links": "Vizualizare link-uri"
}, },
"response": { "response": {
"audio": "Audio",
"body": "Corpul de răspuns", "body": "Corpul de răspuns",
"filter_response_body": "Filtrează corpul răspunsului JSON (folosește sintaxa JSONPath)", "filter_response_body": "Filtrează corpul răspunsului JSON (folosește sintaxa JSONPath)",
"headers": "Anteturi", "headers": "Anteturi",
@@ -445,6 +446,7 @@
"status": "Stare", "status": "Stare",
"time": "Timp", "time": "Timp",
"title": "Raspuns", "title": "Raspuns",
"video": "Video",
"waiting_for_connection": "Așteptând conexiunea", "waiting_for_connection": "Așteptând conexiunea",
"xml": "XML" "xml": "XML"
}, },

View File

@@ -432,6 +432,7 @@
"view_my_links": "View my links" "view_my_links": "View my links"
}, },
"response": { "response": {
"audio": "Audio",
"body": "Тело ответа", "body": "Тело ответа",
"filter_response_body": "Filter JSON response body (uses JSONPath syntax)", "filter_response_body": "Filter JSON response body (uses JSONPath syntax)",
"headers": "Заголовки", "headers": "Заголовки",
@@ -445,6 +446,7 @@
"status": "Статус", "status": "Статус",
"time": "Время", "time": "Время",
"title": "Ответ", "title": "Ответ",
"video": "Video",
"waiting_for_connection": "Ожидание соединения", "waiting_for_connection": "Ожидание соединения",
"xml": "XML" "xml": "XML"
}, },

View File

@@ -432,6 +432,7 @@
"view_my_links": "View my links" "view_my_links": "View my links"
}, },
"response": { "response": {
"audio": "Audio",
"body": "Тело за одговор", "body": "Тело за одговор",
"filter_response_body": "Filter JSON response body (uses JSONPath syntax)", "filter_response_body": "Filter JSON response body (uses JSONPath syntax)",
"headers": "Заглавља", "headers": "Заглавља",
@@ -445,6 +446,7 @@
"status": "Статус", "status": "Статус",
"time": "време", "time": "време",
"title": "Одговор", "title": "Одговор",
"video": "Video",
"waiting_for_connection": "чека везу", "waiting_for_connection": "чека везу",
"xml": "КСМЛ" "xml": "КСМЛ"
}, },

View File

@@ -432,6 +432,7 @@
"view_my_links": "View my links" "view_my_links": "View my links"
}, },
"response": { "response": {
"audio": "Audio",
"body": "Svarskommitté", "body": "Svarskommitté",
"filter_response_body": "Filter JSON response body (uses JSONPath syntax)", "filter_response_body": "Filter JSON response body (uses JSONPath syntax)",
"headers": "Rubriker", "headers": "Rubriker",
@@ -445,6 +446,7 @@
"status": "Status", "status": "Status",
"time": "Tid", "time": "Tid",
"title": "Svar", "title": "Svar",
"video": "Video",
"waiting_for_connection": "väntar på anslutning", "waiting_for_connection": "väntar på anslutning",
"xml": "XML" "xml": "XML"
}, },

View File

@@ -122,7 +122,7 @@
"edit": "Koleksiyonu düzenle", "edit": "Koleksiyonu düzenle",
"invalid_name": "Lütfen koleksiyon için geçerli bir ad girin", "invalid_name": "Lütfen koleksiyon için geçerli bir ad girin",
"invalid_root_move": "Collection already in the root", "invalid_root_move": "Collection already in the root",
"moved": "Moved Successfully", "moved": "Başarıyla taşındı",
"my_collections": "Koleksiyonlarım", "my_collections": "Koleksiyonlarım",
"name": "Yeni Koleksiyonum", "name": "Yeni Koleksiyonum",
"name_length_insufficient": "Koleksiyon adı en az 3 karakter uzunluğunda olmalıdır", "name_length_insufficient": "Koleksiyon adı en az 3 karakter uzunluğunda olmalıdır",
@@ -147,7 +147,7 @@
"remove_team": "Bu takımı silmek istediğinizden emin misiniz?", "remove_team": "Bu takımı silmek istediğinizden emin misiniz?",
"remove_telemetry": "Telemetriden çıkmak istediğinizden emin misiniz?", "remove_telemetry": "Telemetriden çıkmak istediğinizden emin misiniz?",
"request_change": "Are you sure you want to discard current request, unsaved changes will be lost.", "request_change": "Are you sure you want to discard current request, unsaved changes will be lost.",
"save_unsaved_tab": "Do you want to save changes made in this tab?", "save_unsaved_tab": "Bu sekmede yapılan değişiklikleri kaydetmek istiyor musunuz?",
"sync": "Bu çalışma alanını senkronize etmek istediğinizden emin misiniz?" "sync": "Bu çalışma alanını senkronize etmek istediğinizden emin misiniz?"
}, },
"count": { "count": {
@@ -368,9 +368,9 @@
}, },
"profile": { "profile": {
"app_settings": "Uygulama ayarları", "app_settings": "Uygulama ayarları",
"default_hopp_displayname": "Unnamed User", "default_hopp_displayname": "Adsız Kullanıcı",
"editor": "Düzenleyici", "editor": "Editör",
"editor_description": "Editors can add, edit, and delete requests.", "editor_description": "Editörler istekleri ekleyebilir, düzenleyebilir ve silebilir.",
"email_verification_mail": "Doğrulama bağlantısı e-postanıza gönderildi. E-postanızı doğrulamak için gelen bağlantıya tıklayınız.", "email_verification_mail": "Doğrulama bağlantısı e-postanıza gönderildi. E-postanızı doğrulamak için gelen bağlantıya tıklayınız.",
"no_permission": "Bu eylemi gerçekleştirmek için gerekli yetkiniz yok.", "no_permission": "Bu eylemi gerçekleştirmek için gerekli yetkiniz yok.",
"owner": "Kurucu", "owner": "Kurucu",
@@ -432,6 +432,7 @@
"view_my_links": "View my links" "view_my_links": "View my links"
}, },
"response": { "response": {
"audio": "Audio",
"body": "Yanıt gövdesi", "body": "Yanıt gövdesi",
"filter_response_body": "Filter JSON response body (uses JSONPath syntax)", "filter_response_body": "Filter JSON response body (uses JSONPath syntax)",
"headers": "Başlıklar", "headers": "Başlıklar",
@@ -445,6 +446,7 @@
"status": "Durum", "status": "Durum",
"time": "Zaman", "time": "Zaman",
"title": "Cevap", "title": "Cevap",
"video": "Video",
"waiting_for_connection": "Bağlantı için bekleniyor", "waiting_for_connection": "Bağlantı için bekleniyor",
"xml": "XML" "xml": "XML"
}, },

View File

@@ -432,6 +432,7 @@
"view_my_links": "檢視我的連結" "view_my_links": "檢視我的連結"
}, },
"response": { "response": {
"audio": "Audio",
"body": "回應本體", "body": "回應本體",
"filter_response_body": "篩選 JSON 回應本體 (使用 JSONPath 語法)", "filter_response_body": "篩選 JSON 回應本體 (使用 JSONPath 語法)",
"headers": "回應標頭", "headers": "回應標頭",
@@ -445,6 +446,7 @@
"status": "狀態", "status": "狀態",
"time": "時間", "time": "時間",
"title": "回應", "title": "回應",
"video": "Video",
"waiting_for_connection": "等待連線", "waiting_for_connection": "等待連線",
"xml": "XML" "xml": "XML"
}, },

View File

@@ -432,6 +432,7 @@
"view_my_links": "Переглянути мої посилання" "view_my_links": "Переглянути мої посилання"
}, },
"response": { "response": {
"audio": "Audio",
"body": "Орган реагування", "body": "Орган реагування",
"filter_response_body": "Фільтр тіла відповідей JSON (використовує синтаксис JSONPath)", "filter_response_body": "Фільтр тіла відповідей JSON (використовує синтаксис JSONPath)",
"headers": "Заголовки", "headers": "Заголовки",
@@ -445,6 +446,7 @@
"status": "Статус", "status": "Статус",
"time": "Час", "time": "Час",
"title": "Відповідь", "title": "Відповідь",
"video": "Video",
"waiting_for_connection": "очікування підключення", "waiting_for_connection": "очікування підключення",
"xml": "XML" "xml": "XML"
}, },

View File

@@ -4,7 +4,7 @@
"cancel": "Hủy bỏ", "cancel": "Hủy bỏ",
"choose_file": "Chọn một tệp", "choose_file": "Chọn một tệp",
"clear": "Thông thoáng", "clear": "Thông thoáng",
"clear_all": "Quet sạch tât cả", "clear_all": "Quet sạch tt cả",
"close": "Close", "close": "Close",
"connect": "Liên kết", "connect": "Liên kết",
"connecting": "Connecting", "connecting": "Connecting",
@@ -432,6 +432,7 @@
"view_my_links": "View my links" "view_my_links": "View my links"
}, },
"response": { "response": {
"audio": "Audio",
"body": "Cơ quan phản hồi", "body": "Cơ quan phản hồi",
"filter_response_body": "Filter JSON response body (uses JSONPath syntax)", "filter_response_body": "Filter JSON response body (uses JSONPath syntax)",
"headers": "Tiêu đề", "headers": "Tiêu đề",
@@ -445,6 +446,7 @@
"status": "Tình trạng", "status": "Tình trạng",
"time": "Thời gian", "time": "Thời gian",
"title": "Phản ứng", "title": "Phản ứng",
"video": "Video",
"waiting_for_connection": "Đang đợi kết nối", "waiting_for_connection": "Đang đợi kết nối",
"xml": "XML" "xml": "XML"
}, },

View File

@@ -8,7 +8,9 @@ export const APP_INFO = {
keywords: keywords:
"hoppscotch, hopp scotch, hoppscotch online, hoppscotch app, postwoman, postwoman chrome, postwoman online, postwoman for mac, postwoman app, postwoman for windows, postwoman google chrome, postwoman chrome app, get postwoman, postwoman web, postwoman android, postwoman app for chrome, postwoman mobile app, postwoman web app, api, request, testing, tool, rest, websocket, sse, graphql, socketio", "hoppscotch, hopp scotch, hoppscotch online, hoppscotch app, postwoman, postwoman chrome, postwoman online, postwoman for mac, postwoman app, postwoman for windows, postwoman google chrome, postwoman chrome app, get postwoman, postwoman web, postwoman android, postwoman app for chrome, postwoman mobile app, postwoman web app, api, request, testing, tool, rest, websocket, sse, graphql, socketio",
app: { app: {
background: "#202124", background: "#181818",
lightThemeColor: "#ffffff",
darkThemeColor: "#181818",
}, },
social: { social: {
twitter: "@hoppscotch_io", twitter: "@hoppscotch_io",
@@ -108,7 +110,17 @@ export const META_TAGS = (env: Record<string, string>): IHTMLTag[] => [
// PWA // PWA
{ {
name: "theme-color", name: "theme-color",
content: APP_INFO.app.background, content: APP_INFO.app.darkThemeColor,
media: "(prefers-color-scheme: dark)",
},
{
name: "theme-color",
content: APP_INFO.app.lightThemeColor,
media: "(prefers-color-scheme: light)",
},
{
name: "supported-color-schemes",
content: "light dark",
}, },
{ {
name: "mask-icon", name: "mask-icon",

View File

@@ -1,7 +1,7 @@
{ {
"name": "@hoppscotch/common", "name": "@hoppscotch/common",
"private": true, "private": true,
"version": "2023.4.1", "version": "2023.4.6",
"scripts": { "scripts": {
"dev": "pnpm exec npm-run-all -p -l dev:*", "dev": "pnpm exec npm-run-all -p -l dev:*",
"dev:vite": "vite", "dev:vite": "vite",
@@ -92,6 +92,7 @@
"vuedraggable-es": "^4.1.1", "vuedraggable-es": "^4.1.1",
"wonka": "^4.0.15", "wonka": "^4.0.15",
"workbox-window": "^6.5.4", "workbox-window": "^6.5.4",
"xml-formatter": "^3.4.1",
"yargs-parser": "^21.1.1" "yargs-parser": "^21.1.1"
}, },
"devDependencies": { "devDependencies": {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 595 KiB

After

Width:  |  Height:  |  Size: 666 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 400 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 871 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 331 KiB

After

Width:  |  Height:  |  Size: 358 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 352 KiB

After

Width:  |  Height:  |  Size: 382 KiB

View File

@@ -57,6 +57,7 @@ declare module '@vue/runtime-core' {
EnvironmentsMy: typeof import('./components/environments/my/index.vue')['default'] EnvironmentsMy: typeof import('./components/environments/my/index.vue')['default']
EnvironmentsMyDetails: typeof import('./components/environments/my/Details.vue')['default'] EnvironmentsMyDetails: typeof import('./components/environments/my/Details.vue')['default']
EnvironmentsMyEnvironment: typeof import('./components/environments/my/Environment.vue')['default'] EnvironmentsMyEnvironment: typeof import('./components/environments/my/Environment.vue')['default']
EnvironmentsSelector: typeof import('./components/environments/Selector.vue')['default']
EnvironmentsTeams: typeof import('./components/environments/teams/index.vue')['default'] EnvironmentsTeams: typeof import('./components/environments/teams/index.vue')['default']
EnvironmentsTeamsDetails: typeof import('./components/environments/teams/Details.vue')['default'] EnvironmentsTeamsDetails: typeof import('./components/environments/teams/Details.vue')['default']
EnvironmentsTeamsEnvironment: typeof import('./components/environments/teams/Environment.vue')['default'] EnvironmentsTeamsEnvironment: typeof import('./components/environments/teams/Environment.vue')['default']
@@ -84,6 +85,8 @@ declare module '@vue/runtime-core' {
HoppSmartItem: typeof import('@hoppscotch/ui')['HoppSmartItem'] HoppSmartItem: typeof import('@hoppscotch/ui')['HoppSmartItem']
HoppSmartLink: typeof import('@hoppscotch/ui')['HoppSmartLink'] HoppSmartLink: typeof import('@hoppscotch/ui')['HoppSmartLink']
HoppSmartModal: typeof import('@hoppscotch/ui')['HoppSmartModal'] HoppSmartModal: typeof import('@hoppscotch/ui')['HoppSmartModal']
HoppSmartPicture: typeof import('@hoppscotch/ui')['HoppSmartPicture']
HoppSmartPlaceholder: typeof import('@hoppscotch/ui')['HoppSmartPlaceholder']
HoppSmartProgressRing: typeof import('@hoppscotch/ui')['HoppSmartProgressRing'] HoppSmartProgressRing: typeof import('@hoppscotch/ui')['HoppSmartProgressRing']
HoppSmartRadioGroup: typeof import('@hoppscotch/ui')['HoppSmartRadioGroup'] HoppSmartRadioGroup: typeof import('@hoppscotch/ui')['HoppSmartRadioGroup']
HoppSmartSlideOver: typeof import('@hoppscotch/ui')['HoppSmartSlideOver'] HoppSmartSlideOver: typeof import('@hoppscotch/ui')['HoppSmartSlideOver']
@@ -129,18 +132,18 @@ declare module '@vue/runtime-core' {
IconLucideListEnd: typeof import('~icons/lucide/list-end')['default'] IconLucideListEnd: typeof import('~icons/lucide/list-end')['default']
IconLucideMinus: typeof import('~icons/lucide/minus')['default'] IconLucideMinus: typeof import('~icons/lucide/minus')['default']
IconLucideSearch: typeof import('~icons/lucide/search')['default'] IconLucideSearch: typeof import('~icons/lucide/search')['default']
IconLucideUser: typeof import('~icons/lucide/user')['default']
IconLucideUsers: typeof import('~icons/lucide/users')['default'] IconLucideUsers: typeof import('~icons/lucide/users')['default']
LensesHeadersRenderer: typeof import('./components/lenses/HeadersRenderer.vue')['default'] LensesHeadersRenderer: typeof import('./components/lenses/HeadersRenderer.vue')['default']
LensesHeadersRendererEntry: typeof import('./components/lenses/HeadersRendererEntry.vue')['default'] LensesHeadersRendererEntry: typeof import('./components/lenses/HeadersRendererEntry.vue')['default']
LensesRenderersAudioLensRenderer: typeof import('./components/lenses/renderers/AudioLensRenderer.vue')['default']
LensesRenderersHTMLLensRenderer: typeof import('./components/lenses/renderers/HTMLLensRenderer.vue')['default'] LensesRenderersHTMLLensRenderer: typeof import('./components/lenses/renderers/HTMLLensRenderer.vue')['default']
LensesRenderersImageLensRenderer: typeof import('./components/lenses/renderers/ImageLensRenderer.vue')['default'] LensesRenderersImageLensRenderer: typeof import('./components/lenses/renderers/ImageLensRenderer.vue')['default']
LensesRenderersJSONLensRenderer: typeof import('./components/lenses/renderers/JSONLensRenderer.vue')['default'] LensesRenderersJSONLensRenderer: typeof import('./components/lenses/renderers/JSONLensRenderer.vue')['default']
LensesRenderersPDFLensRenderer: typeof import('./components/lenses/renderers/PDFLensRenderer.vue')['default'] LensesRenderersPDFLensRenderer: typeof import('./components/lenses/renderers/PDFLensRenderer.vue')['default']
LensesRenderersRawLensRenderer: typeof import('./components/lenses/renderers/RawLensRenderer.vue')['default'] LensesRenderersRawLensRenderer: typeof import('./components/lenses/renderers/RawLensRenderer.vue')['default']
LensesRenderersVideoLensRenderer: typeof import('./components/lenses/renderers/VideoLensRenderer.vue')['default']
LensesRenderersXMLLensRenderer: typeof import('./components/lenses/renderers/XMLLensRenderer.vue')['default'] LensesRenderersXMLLensRenderer: typeof import('./components/lenses/renderers/XMLLensRenderer.vue')['default']
LensesResponseBodyRenderer: typeof import('./components/lenses/ResponseBodyRenderer.vue')['default'] LensesResponseBodyRenderer: typeof import('./components/lenses/ResponseBodyRenderer.vue')['default']
ProfilePicture: typeof import('./components/profile/Picture.vue')['default']
ProfileShortcode: typeof import('./components/profile/Shortcode.vue')['default'] ProfileShortcode: typeof import('./components/profile/Shortcode.vue')['default']
ProfileShortcodes: typeof import('./components/profile/Shortcodes.vue')['default'] ProfileShortcodes: typeof import('./components/profile/Shortcodes.vue')['default']
ProfileUserDelete: typeof import('./components/profile/UserDelete.vue')['default'] ProfileUserDelete: typeof import('./components/profile/UserDelete.vue')['default']
@@ -164,6 +167,7 @@ declare module '@vue/runtime-core' {
SmartItem: typeof import('./../../hoppscotch-ui/src/components/smart/Item.vue')['default'] SmartItem: typeof import('./../../hoppscotch-ui/src/components/smart/Item.vue')['default']
SmartLink: typeof import('./../../hoppscotch-ui/src/components/smart/Link.vue')['default'] SmartLink: typeof import('./../../hoppscotch-ui/src/components/smart/Link.vue')['default']
SmartModal: typeof import('./../../hoppscotch-ui/src/components/smart/Modal.vue')['default'] SmartModal: typeof import('./../../hoppscotch-ui/src/components/smart/Modal.vue')['default']
SmartPicture: typeof import('./../../hoppscotch-ui/src/components/smart/Picture.vue')['default']
SmartProgressRing: typeof import('./../../hoppscotch-ui/src/components/smart/ProgressRing.vue')['default'] SmartProgressRing: typeof import('./../../hoppscotch-ui/src/components/smart/ProgressRing.vue')['default']
SmartRadio: typeof import('./../../hoppscotch-ui/src/components/smart/Radio.vue')['default'] SmartRadio: typeof import('./../../hoppscotch-ui/src/components/smart/Radio.vue')['default']
SmartRadioGroup: typeof import('./../../hoppscotch-ui/src/components/smart/RadioGroup.vue')['default'] SmartRadioGroup: typeof import('./../../hoppscotch-ui/src/components/smart/RadioGroup.vue')['default']

View File

@@ -124,7 +124,7 @@
theme="popover" theme="popover"
:on-shown="() => tippyActions.focus()" :on-shown="() => tippyActions.focus()"
> >
<ProfilePicture <HoppSmartPicture
v-if="currentUser.photoURL" v-if="currentUser.photoURL"
v-tippy="{ v-tippy="{
theme: 'tooltip', theme: 'tooltip',
@@ -144,7 +144,7 @@
network.isOnline ? 'bg-green-500' : 'bg-red-500' network.isOnline ? 'bg-green-500' : 'bg-red-500'
" "
/> />
<ProfilePicture <HoppSmartPicture
v-else v-else
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title=" :title="

View File

@@ -42,9 +42,9 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, watch } from "vue"
import { useI18n } from "@composables/i18n" import { useI18n } from "@composables/i18n"
import { useToast } from "@composables/toast" import { useToast } from "@composables/toast"
import { useVModel } from "@vueuse/core"
const toast = useToast() const toast = useToast()
const t = useI18n() const t = useI18n()
@@ -53,28 +53,22 @@ const props = withDefaults(
defineProps<{ defineProps<{
show: boolean show: boolean
loadingState: boolean loadingState: boolean
editingRequestName: string modelValue?: string
}>(), }>(),
{ {
show: false, show: false,
loadingState: false, loadingState: false,
editingRequestName: "", modelValue: "",
} }
) )
const emit = defineEmits<{ const emit = defineEmits<{
(e: "submit", name: string): void (e: "submit", name: string): void
(e: "hide-modal"): void (e: "hide-modal"): void
(e: "update:modelValue", value: string): void
}>() }>()
const name = ref("") const name = useVModel(props, "modelValue")
watch(
() => props.editingRequestName,
(newName) => {
name.value = newName
}
)
const editRequest = () => { const editRequest = () => {
if (name.value.trim() === "") { if (name.value.trim() === "") {

View File

@@ -1,5 +1,5 @@
<template> <template>
<div class="flex flex-col flex-1 bg-primary"> <div class="flex flex-col flex-1 bg-primaryContrast">
<div <div
class="sticky z-10 flex justify-between flex-1 border-b bg-primary border-dividerLight" class="sticky z-10 flex justify-between flex-1 border-b bg-primary border-dividerLight"
:style=" :style="

View File

@@ -136,11 +136,11 @@ const requestName = ref(
) )
watch( watch(
() => [currentActiveTab.value.document.request.name, gqlRequestName.value], () => [currentActiveTab.value, gqlRequestName.value],
() => { () => {
if (props.mode === "rest") if (props.mode === "rest") {
requestName.value = currentActiveTab.value.document.request.name requestName.value = currentActiveTab.value?.document.request.name ?? ""
else requestName.value = gqlRequestName.value } else requestName.value = gqlRequestName.value
} }
) )

View File

@@ -1,5 +1,5 @@
<template> <template>
<div class="flex flex-col flex-1 bg-primary"> <div class="flex flex-col flex-1 bg-primaryContrast">
<div <div
class="sticky z-10 flex justify-between flex-1 border-b bg-primary border-dividerLight" class="sticky z-10 flex justify-between flex-1 border-b bg-primary border-dividerLight"
:style=" :style="

View File

@@ -125,8 +125,8 @@
@hide-modal="displayModalEditFolder(false)" @hide-modal="displayModalEditFolder(false)"
/> />
<CollectionsEditRequest <CollectionsEditRequest
v-model="editingRequestName"
:show="showModalEditRequest" :show="showModalEditRequest"
:editing-request-name="editingRequest ? editingRequest.name : ''"
:loading-state="modalLoadingState" :loading-state="modalLoadingState"
@submit="updateEditingRequest" @submit="updateEditingRequest"
@hide-modal="displayModalEditRequest(false)" @hide-modal="displayModalEditRequest(false)"
@@ -157,7 +157,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed, PropType, ref, watch } from "vue" import { computed, nextTick, PropType, ref, watch } from "vue"
import { useToast } from "@composables/toast" import { useToast } from "@composables/toast"
import { useI18n } from "@composables/i18n" import { useI18n } from "@composables/i18n"
import { Picked } from "~/helpers/types/HoppPicked" import { Picked } from "~/helpers/types/HoppPicked"
@@ -288,6 +288,7 @@ const editingFolder = ref<
const editingFolderName = ref<string | null>(null) const editingFolderName = ref<string | null>(null)
const editingFolderPath = ref<string | null>(null) const editingFolderPath = ref<string | null>(null)
const editingRequest = ref<HoppRESTRequest | null>(null) const editingRequest = ref<HoppRESTRequest | null>(null)
const editingRequestName = ref("")
const editingRequestIndex = ref<number | null>(null) const editingRequestIndex = ref<number | null>(null)
const editingRequestID = ref<string | null>(null) const editingRequestID = ref<string | null>(null)
@@ -860,6 +861,7 @@ const editRequest = (payload: {
}) => { }) => {
const { folderPath, requestIndex, request } = payload const { folderPath, requestIndex, request } = payload
editingRequest.value = request editingRequest.value = request
editingRequestName.value = request.name ?? ""
if (collectionsType.value.type === "my-collections" && folderPath) { if (collectionsType.value.type === "my-collections" && folderPath) {
editingFolderPath.value = folderPath editingFolderPath.value = folderPath
editingRequestIndex.value = parseInt(requestIndex) editingRequestIndex.value = parseInt(requestIndex)
@@ -893,6 +895,9 @@ const updateEditingRequest = (newName: string) => {
if (possibleActiveTab) { if (possibleActiveTab) {
possibleActiveTab.value.document.request.name = requestUpdated.name possibleActiveTab.value.document.request.name = requestUpdated.name
nextTick(() => {
possibleActiveTab.value.document.isDirty = false
})
} }
displayModalEditRequest(false) displayModalEditRequest(false)
@@ -931,6 +936,9 @@ const updateEditingRequest = (newName: string) => {
if (possibleTab) { if (possibleTab) {
possibleTab.value.document.request.name = requestName possibleTab.value.document.request.name = requestName
nextTick(() => {
possibleTab.value.document.isDirty = false
})
} }
} }
} }

View File

@@ -0,0 +1,295 @@
<template>
<tippy
interactive
trigger="click"
theme="popover"
:on-shown="() => tippyActions!.focus()"
>
<span
v-tippy="{ theme: 'tooltip' }"
:title="`${t('environment.select')}`"
class="bg-transparent border-b border-dividerLight select-wrapper"
>
<HoppButtonSecondary
:icon="IconLayers"
:label="
mdAndLarger
? selectedEnv.type !== 'NO_ENV_SELECTED'
? selectedEnv.name
: `${t('environment.select')}`
: ''
"
class="flex-1 !justify-start pr-8 rounded-none"
/>
</span>
<template #content="{ hide }">
<div
ref="tippyActions"
role="menu"
class="flex flex-col focus:outline-none"
tabindex="0"
@keyup.escape="hide()"
>
<HoppSmartItem
:label="`${t('environment.no_environment')}`"
:info-icon="
selectedEnvironmentIndex.type === 'NO_ENV_SELECTED'
? IconCheck
: undefined
"
:active-info-icon="
selectedEnvironmentIndex.type === 'NO_ENV_SELECTED'
"
@click="
() => {
selectedEnvironmentIndex = { type: 'NO_ENV_SELECTED' }
hide()
}
"
/>
<HoppSmartTabs
v-model="selectedEnvTab"
styles="sticky overflow-x-auto my-2 border border-divider rounded flex-shrink-0 z-10 top-0 bg-primary"
render-inactive-tabs
>
<HoppSmartTab
:id="'my-environments'"
:label="`${t('environment.my_environments')}`"
>
<HoppSmartItem
v-for="(gen, index) in myEnvironments"
:key="`gen-${index}`"
:icon="IconLayers"
:label="gen.name"
:info-icon="index === selectedEnv.index ? IconCheck : undefined"
:active-info-icon="index === selectedEnv.index"
@click="
() => {
selectedEnvironmentIndex = { type: 'MY_ENV', index: index }
hide()
}
"
/>
<div
v-if="myEnvironments.length === 0"
class="flex flex-col items-center justify-center text-secondaryLight"
>
<img
:src="`/images/states/${colorMode.value}/blockchain.svg`"
loading="lazy"
class="inline-flex flex-col object-contain object-center w-16 h-16 mb-2"
:alt="`${t('empty.environments')}`"
/>
<span class="pb-2 text-center">
{{ t("empty.environments") }}
</span>
</div>
</HoppSmartTab>
<HoppSmartTab
:id="'team-environments'"
:label="`${t('environment.team_environments')}`"
:disabled="!isTeamSelected || workspace.type === 'personal'"
>
<div
v-if="teamListLoading"
class="flex flex-col items-center justify-center p-4"
>
<HoppSmartSpinner class="my-4" />
<span class="text-secondaryLight">{{ t("state.loading") }}</span>
</div>
<div v-else-if="isTeamSelected" class="flex flex-col">
<HoppSmartItem
v-for="(gen, index) in teamEnvironmentList"
:key="`gen-team-${index}`"
:icon="IconLayers"
:label="gen.environment.name"
:info-icon="
gen.id === selectedEnv.teamEnvID ? IconCheck : undefined
"
:active-info-icon="gen.id === selectedEnv.teamEnvID"
@click="
() => {
selectedEnvironmentIndex = {
type: 'TEAM_ENV',
teamEnvID: gen.id,
teamID: gen.teamID,
environment: gen.environment,
}
hide()
}
"
/>
<div
v-if="teamEnvironmentList.length === 0"
class="flex flex-col items-center justify-center text-secondaryLight"
>
<img
:src="`/images/states/${colorMode.value}/blockchain.svg`"
loading="lazy"
class="inline-flex flex-col object-contain object-center w-16 h-16 mb-2"
:alt="`${t('empty.environments')}`"
/>
<span class="pb-2 text-center">
{{ t("empty.environments") }}
</span>
</div>
</div>
<div
v-if="!teamListLoading && teamAdapterError"
class="flex flex-col items-center py-4"
>
<icon-lucide-help-circle class="mb-4 svg-icons" />
{{ getErrorMessage(teamAdapterError) }}
</div>
</HoppSmartTab>
</HoppSmartTabs>
</div>
</template>
</tippy>
</template>
<script lang="ts" setup>
import { computed, ref, watch } from "vue"
import IconCheck from "~icons/lucide/check"
import IconLayers from "~icons/lucide/layers"
import { TippyComponent } from "vue-tippy"
import { useI18n } from "~/composables/i18n"
import { GQLError } from "~/helpers/backend/GQLClient"
import { useReadonlyStream, useStream } from "~/composables/stream"
import {
environments$,
selectedEnvironmentIndex$,
setSelectedEnvironmentIndex,
} from "~/newstore/environments"
import { changeWorkspace, workspaceStatus$ } from "~/newstore/workspace"
import TeamEnvironmentAdapter from "~/helpers/teams/TeamEnvironmentAdapter"
import { useColorMode } from "@composables/theming"
import { breakpointsTailwind, useBreakpoints } from "@vueuse/core"
import TeamListAdapter from "~/helpers/teams/TeamListAdapter"
import { useLocalState } from "~/newstore/localstate"
import { onLoggedIn } from "~/composables/auth"
import { GetMyTeamsQuery } from "~/helpers/backend/graphql"
const breakpoints = useBreakpoints(breakpointsTailwind)
const mdAndLarger = breakpoints.greater("md")
const t = useI18n()
const colorMode = useColorMode()
type EnvironmentType = "my-environments" | "team-environments"
const myEnvironments = useReadonlyStream(environments$, [])
const workspace = useReadonlyStream(workspaceStatus$, { type: "personal" })
const teamEnvListAdapter = new TeamEnvironmentAdapter(undefined)
const teamListLoading = useReadonlyStream(teamEnvListAdapter.loading$, false)
const teamAdapterError = useReadonlyStream(teamEnvListAdapter.error$, null)
const teamEnvironmentList = useReadonlyStream(
teamEnvListAdapter.teamEnvironmentList$,
[]
)
const selectedEnvironmentIndex = useStream(
selectedEnvironmentIndex$,
{ type: "NO_ENV_SELECTED" },
setSelectedEnvironmentIndex
)
const isTeamSelected = computed(
() => workspace.value.type === "team" && workspace.value.teamID !== undefined
)
const selectedEnvTab = ref<EnvironmentType>("my-environments")
watch(
() => workspace.value,
(newVal) => {
if (newVal.type === "personal") {
selectedEnvTab.value = "my-environments"
} else {
selectedEnvTab.value = "team-environments"
if (newVal.teamID) {
teamEnvListAdapter.changeTeamID(newVal.teamID)
}
}
}
)
// TeamList-Adapter
const teamListAdapter = new TeamListAdapter(true)
const myTeams = useReadonlyStream(teamListAdapter.teamList$, null)
const teamListFetched = ref(false)
const REMEMBERED_TEAM_ID = useLocalState("REMEMBERED_TEAM_ID")
onLoggedIn(() => {
!teamListAdapter.isInitialized && teamListAdapter.initialize()
})
const switchToTeamWorkspace = (team: GetMyTeamsQuery["myTeams"][number]) => {
REMEMBERED_TEAM_ID.value = team.id
changeWorkspace({
teamID: team.id,
teamName: team.name,
type: "team",
})
}
watch(
() => myTeams.value,
(newTeams) => {
if (newTeams && !teamListFetched.value) {
teamListFetched.value = true
if (REMEMBERED_TEAM_ID.value) {
const team = newTeams.find((t) => t.id === REMEMBERED_TEAM_ID.value)
if (team) switchToTeamWorkspace(team)
}
}
}
)
const selectedEnv = computed(() => {
if (selectedEnvironmentIndex.value.type === "MY_ENV") {
return {
type: "MY_ENV",
index: selectedEnvironmentIndex.value.index,
name: myEnvironments.value[selectedEnvironmentIndex.value.index].name,
}
} else if (selectedEnvironmentIndex.value.type === "TEAM_ENV") {
const teamEnv = teamEnvironmentList.value.find(
(env) =>
env.id ===
(selectedEnvironmentIndex.value.type === "TEAM_ENV" &&
selectedEnvironmentIndex.value.teamEnvID)
)
if (teamEnv) {
return {
type: "TEAM_ENV",
name: teamEnv.environment.name,
teamEnvID: selectedEnvironmentIndex.value.teamEnvID,
}
} else {
return { type: "NO_ENV_SELECTED" }
}
} else {
return { type: "NO_ENV_SELECTED" }
}
})
// Template refs
const tippyActions = ref<TippyComponent | null>(null)
const getErrorMessage = (err: GQLError<string>) => {
if (err.type === "network_error") {
return t("error.network_error")
} else {
switch (err.error) {
case "team_environment/not_found":
return t("team_environment.not_found")
default:
return t("error.something_went_wrong")
}
}
}
</script>

View File

@@ -4,153 +4,6 @@
class="sticky top-0 z-10 flex flex-col flex-shrink-0 overflow-x-auto bg-primary" class="sticky top-0 z-10 flex flex-col flex-shrink-0 overflow-x-auto bg-primary"
> >
<WorkspaceCurrent :section="t('tab.environments')" /> <WorkspaceCurrent :section="t('tab.environments')" />
<tippy
v-if="environmentType.type === 'my-environments'"
interactive
trigger="click"
theme="popover"
:on-shown="() => tippyActions!.focus()"
>
<span
v-tippy="{ theme: 'tooltip' }"
:title="`${t('environment.select')}`"
class="bg-transparent border-b border-dividerLight select-wrapper"
>
<HoppButtonSecondary
v-if="
selectedEnv.type === 'MY_ENV' && selectedEnv.index !== undefined
"
:label="myEnvironments[selectedEnv.index].name"
class="flex-1 !justify-start pr-8 rounded-none"
/>
<HoppButtonSecondary
v-else
:label="`${t('environment.select')}`"
class="flex-1 !justify-start pr-8 rounded-none"
/>
</span>
<template #content="{ hide }">
<div
ref="tippyActions"
role="menu"
class="flex flex-col focus:outline-none"
tabindex="0"
@keyup.escape="hide()"
>
<HoppSmartItem
:label="`${t('environment.no_environment')}`"
:info-icon="
selectedEnvironmentIndex.type !== 'MY_ENV'
? IconCheck
: undefined
"
:active-info-icon="selectedEnvironmentIndex.type !== 'MY_ENV'"
@click="
() => {
selectedEnvironmentIndex = { type: 'NO_ENV_SELECTED' }
hide()
}
"
/>
<hr v-if="myEnvironments.length > 0" />
<HoppSmartItem
v-for="(gen, index) in myEnvironments"
:key="`gen-${index}`"
:label="gen.name"
:info-icon="index === selectedEnv.index ? IconCheck : undefined"
:active-info-icon="index === selectedEnv.index"
@click="
() => {
selectedEnvironmentIndex = { type: 'MY_ENV', index: index }
hide()
}
"
/>
</div>
</template>
</tippy>
<tippy v-else interactive trigger="click" theme="popover">
<span
v-tippy="{ theme: 'tooltip' }"
:title="`${t('environment.select')}`"
class="bg-transparent border-b border-dividerLight select-wrapper"
>
<HoppButtonSecondary
v-if="selectedEnv.name"
:label="selectedEnv.name"
class="flex-1 !justify-start pr-8 rounded-none"
/>
<HoppButtonSecondary
v-else
:label="`${t('environment.select')}`"
class="flex-1 !justify-start pr-8 rounded-none"
/>
</span>
<template #content="{ hide }">
<div
class="flex flex-col"
role="menu"
tabindex="0"
@keyup.escape="hide()"
>
<HoppSmartItem
:label="`${t('environment.no_environment')}`"
:info-icon="
selectedEnvironmentIndex.type !== 'TEAM_ENV'
? IconCheck
: undefined
"
:active-info-icon="selectedEnvironmentIndex.type !== 'TEAM_ENV'"
@click="
() => {
selectedEnvironmentIndex = { type: 'NO_ENV_SELECTED' }
hide()
}
"
/>
<div
v-if="loading"
class="flex flex-col items-center justify-center p-4"
>
<HoppSmartSpinner class="my-4" />
<span class="text-secondaryLight">{{ t("state.loading") }}</span>
</div>
<hr v-if="teamEnvironmentList.length > 0" />
<div
v-if="environmentType.selectedTeam !== undefined"
class="flex flex-col"
>
<HoppSmartItem
v-for="(gen, index) in teamEnvironmentList"
:key="`gen-team-${index}`"
:label="gen.environment.name"
:info-icon="
gen.id === selectedEnv.teamEnvID ? IconCheck : undefined
"
:active-info-icon="gen.id === selectedEnv.teamEnvID"
@click="
() => {
selectedEnvironmentIndex = {
type: 'TEAM_ENV',
teamEnvID: gen.id,
teamID: gen.teamID,
environment: gen.environment,
}
hide()
}
"
/>
</div>
<div
v-if="!loading && adapterError"
class="flex flex-col items-center py-4"
>
<icon-lucide-help-circle class="mb-4 svg-icons" />
{{ getErrorMessage(adapterError) }}
</div>
</div>
</template>
</tippy>
<EnvironmentsMyEnvironment <EnvironmentsMyEnvironment
environment-index="Global" environment-index="Global"
:environment="globalEnvironment" :environment="globalEnvironment"
@@ -184,15 +37,11 @@ import { GetMyTeamsQuery } from "~/helpers/backend/graphql"
import { useReadonlyStream, useStream } from "@composables/stream" import { useReadonlyStream, useStream } from "@composables/stream"
import { useI18n } from "~/composables/i18n" import { useI18n } from "~/composables/i18n"
import { import {
environments$,
globalEnv$, globalEnv$,
selectedEnvironmentIndex$, selectedEnvironmentIndex$,
setSelectedEnvironmentIndex, setSelectedEnvironmentIndex,
} from "~/newstore/environments" } from "~/newstore/environments"
import TeamEnvironmentAdapter from "~/helpers/teams/TeamEnvironmentAdapter" import TeamEnvironmentAdapter from "~/helpers/teams/TeamEnvironmentAdapter"
import { GQLError } from "~/helpers/backend/GQLClient"
import IconCheck from "~icons/lucide/check"
import { TippyComponent } from "vue-tippy"
import { defineActionHandler } from "~/helpers/actions" import { defineActionHandler } from "~/helpers/actions"
import { workspaceStatus$ } from "~/newstore/workspace" import { workspaceStatus$ } from "~/newstore/workspace"
import TeamListAdapter from "~/helpers/teams/TeamListAdapter" import TeamListAdapter from "~/helpers/teams/TeamListAdapter"
@@ -261,7 +110,7 @@ const switchToMyEnvironments = () => {
adapter.changeTeamID(undefined) adapter.changeTeamID(undefined)
} }
const updateSelectedTeam = (newSelectedTeam: SelectedTeam) => { const updateSelectedTeam = (newSelectedTeam: SelectedTeam | undefined) => {
if (newSelectedTeam) { if (newSelectedTeam) {
environmentType.value.selectedTeam = newSelectedTeam environmentType.value.selectedTeam = newSelectedTeam
REMEMBERED_TEAM_ID.value = newSelectedTeam.id REMEMBERED_TEAM_ID.value = newSelectedTeam.id
@@ -287,22 +136,21 @@ onLoggedIn(() => {
const workspace = useReadonlyStream(workspaceStatus$, { type: "personal" }) const workspace = useReadonlyStream(workspaceStatus$, { type: "personal" })
// Used to switch environment type and team when user switch workspace in the global workspace switcher // Switch to my environments if workspace is personal and to team environments if workspace is team
// Check if there is a teamID in the workspace, if yes, switch to team environment and select the team // also resets selected environment if workspace is personal and the previous selected environment was a team environment
// If there is no teamID, switch to my environment watch(workspace, (newWorkspace) => {
watch( if (newWorkspace.type === "personal") {
() => workspace.value.teamID, switchToMyEnvironments()
(teamID) => { if (selectedEnvironmentIndex.value.type !== "MY_ENV") {
if (!teamID) { setSelectedEnvironmentIndex({
switchToMyEnvironments() type: "NO_ENV_SELECTED",
} else if (teamID) { })
const team = myTeams.value?.find((t) => t.id === teamID)
if (team) {
updateSelectedTeam(team)
}
} }
} else if (newWorkspace.type === "team") {
const team = myTeams.value?.find((t) => t.id === newWorkspace.teamID)
updateSelectedTeam(team)
} }
) })
watch( watch(
() => currentUser.value, () => currentUser.value,
@@ -343,8 +191,6 @@ defineActionHandler(
} }
) )
const myEnvironments = useReadonlyStream(environments$, [])
const selectedEnvironmentIndex = useStream( const selectedEnvironmentIndex = useStream(
selectedEnvironmentIndex$, selectedEnvironmentIndex$,
{ type: "NO_ENV_SELECTED" }, { type: "NO_ENV_SELECTED" },
@@ -387,47 +233,4 @@ watch(
}, },
{ deep: true } { deep: true }
) )
const selectedEnv = computed(() => {
if (selectedEnvironmentIndex.value.type === "MY_ENV") {
return {
type: "MY_ENV",
index: selectedEnvironmentIndex.value.index,
}
} else if (selectedEnvironmentIndex.value.type === "TEAM_ENV") {
const teamEnv = teamEnvironmentList.value.find(
(env) =>
env.id ===
(selectedEnvironmentIndex.value.type === "TEAM_ENV" &&
selectedEnvironmentIndex.value.teamEnvID)
)
if (teamEnv) {
return {
type: "TEAM_ENV",
name: teamEnv.environment.name,
teamEnvID: selectedEnvironmentIndex.value.teamEnvID,
}
} else {
return { type: "NO_ENV_SELECTED" }
}
} else {
return { type: "NO_ENV_SELECTED" }
}
})
const getErrorMessage = (err: GQLError<string>) => {
if (err.type === "network_error") {
return t("error.network_error")
} else {
switch (err.error) {
case "team_environment/not_found":
return t("team_environment.not_found")
default:
return t("error.something_went_wrong")
}
}
}
// Template refs
const tippyActions = ref<TippyComponent | null>(null)
</script> </script>

View File

@@ -165,8 +165,8 @@ const props = withDefaults(
defineProps<{ defineProps<{
show: boolean show: boolean
action: "edit" | "new" action: "edit" | "new"
editingEnvironmentIndex: number | "Global" | null editingEnvironmentIndex?: number | "Global" | null
editingVariableName: string | null editingVariableName?: string | null
envVars?: () => Environment["variables"] envVars?: () => Environment["variables"]
}>(), }>(),
{ {

View File

@@ -140,7 +140,7 @@ import * as A from "fp-ts/Array"
import * as O from "fp-ts/Option" import * as O from "fp-ts/Option"
import * as TE from "fp-ts/TaskEither" import * as TE from "fp-ts/TaskEither"
import { flow, pipe } from "fp-ts/function" import { flow, pipe } from "fp-ts/function"
import { parseTemplateStringE } from "@hoppscotch/data" import { Environment, parseTemplateStringE } from "@hoppscotch/data"
import { refAutoReset } from "@vueuse/core" import { refAutoReset } from "@vueuse/core"
import { clone } from "lodash-es" import { clone } from "lodash-es"
import { useToast } from "@composables/toast" import { useToast } from "@composables/toast"
@@ -173,16 +173,20 @@ const props = withDefaults(
defineProps<{ defineProps<{
show: boolean show: boolean
action: "edit" | "new" action: "edit" | "new"
editingEnvironment: TeamEnvironment | null editingEnvironment?: TeamEnvironment | null
editingTeamId: string | undefined editingTeamId: string | undefined
editingVariableName: string | null editingVariableName?: string | null
isViewer: boolean isViewer?: boolean
envVars?: () => Environment["variables"]
}>(), }>(),
{ {
show: false, show: false,
action: "edit", action: "edit",
editingEnvironment: null, editingEnvironment: null,
editingTeamId: "", editingTeamId: "",
editingVariableName: null,
isViewer: false,
envVars: () => [],
} }
) )
@@ -226,10 +230,16 @@ watch(
() => props.show, () => props.show,
(show) => { (show) => {
if (show) { if (show) {
if (props.editingEnvironment === null) { if (props.action === "new") {
name.value = null name.value = null
vars.value = [] vars.value = pipe(
} else { props.envVars() ?? [],
A.map((e: { key: string; value: string }) => ({
id: idTicker.value++,
env: clone(e),
}))
)
} else if (props.editingEnvironment !== null) {
name.value = props.editingEnvironment.environment.name ?? null name.value = props.editingEnvironment.environment.name ?? null
vars.value = pipe( vars.value = pipe(
props.editingEnvironment.environment.variables ?? [], props.editingEnvironment.environment.variables ?? [],

View File

@@ -1,7 +1,7 @@
<template> <template>
<div> <div>
<div <div
class="sticky z-10 flex justify-between flex-1 flex-shrink-0 overflow-x-auto border-b top-upperSecondaryStickyFold border-dividerLight bg-primary" class="sticky z-10 flex justify-between flex-1 flex-shrink-0 overflow-x-auto border-b top-upperPrimaryStickyFold border-dividerLight bg-primary"
> >
<HoppButtonSecondary <HoppButtonSecondary
v-if="team === undefined || team.myRole === 'VIEWER'" v-if="team === undefined || team.myRole === 'VIEWER'"

View File

@@ -142,12 +142,14 @@
<div v-if="authType === 'basic'"> <div v-if="authType === 'basic'">
<div class="flex flex-1 border-b border-dividerLight"> <div class="flex flex-1 border-b border-dividerLight">
<SmartEnvInput <SmartEnvInput
:environmentHighlights="false"
v-model="basicUsername" v-model="basicUsername"
:placeholder="t('authorization.username')" :placeholder="t('authorization.username')"
/> />
</div> </div>
<div class="flex flex-1 border-b border-dividerLight"> <div class="flex flex-1 border-b border-dividerLight">
<SmartEnvInput <SmartEnvInput
:environmentHighlights="false"
v-model="basicPassword" v-model="basicPassword"
:placeholder="t('authorization.password')" :placeholder="t('authorization.password')"
/> />
@@ -155,21 +157,37 @@
</div> </div>
<div v-if="authType === 'bearer'"> <div v-if="authType === 'bearer'">
<div class="flex flex-1 border-b border-dividerLight"> <div class="flex flex-1 border-b border-dividerLight">
<SmartEnvInput v-model="bearerToken" placeholder="Token" /> <SmartEnvInput
:environmentHighlights="false"
v-model="bearerToken"
placeholder="Token"
/>
</div> </div>
</div> </div>
<div v-if="authType === 'oauth-2'"> <div v-if="authType === 'oauth-2'">
<div class="flex flex-1 border-b border-dividerLight"> <div class="flex flex-1 border-b border-dividerLight">
<SmartEnvInput v-model="oauth2Token" placeholder="Token" /> <SmartEnvInput
:environmentHighlights="false"
v-model="oauth2Token"
placeholder="Token"
/>
</div> </div>
<HttpOAuth2Authorization /> <HttpOAuth2Authorization />
</div> </div>
<div v-if="authType === 'api-key'"> <div v-if="authType === 'api-key'">
<div class="flex flex-1 border-b border-dividerLight"> <div class="flex flex-1 border-b border-dividerLight">
<SmartEnvInput v-model="apiKey" placeholder="Key" /> <SmartEnvInput
:environmentHighlights="false"
v-model="apiKey"
placeholder="Key"
/>
</div> </div>
<div class="flex flex-1 border-b border-dividerLight"> <div class="flex flex-1 border-b border-dividerLight">
<SmartEnvInput v-model="apiValue" placeholder="Value" /> <SmartEnvInput
:environmentHighlights="false"
v-model="apiValue"
placeholder="Value"
/>
</div> </div>
<div class="flex items-center border-b border-dividerLight"> <div class="flex items-center border-b border-dividerLight">
<span class="flex items-center"> <span class="flex items-center">

View File

@@ -17,6 +17,7 @@
<HoppButtonPrimary <HoppButtonPrimary
id="get" id="get"
name="get" name="get"
:loading="isLoading"
:label="!connected ? t('action.connect') : t('action.disconnect')" :label="!connected ? t('action.connect') : t('action.disconnect')"
class="w-32" class="w-32"
@click="onConnectClick" @click="onConnectClick"
@@ -31,7 +32,12 @@ import { GQLConnection } from "~/helpers/GQLConnection"
import { getCurrentStrategyID } from "~/helpers/network" import { getCurrentStrategyID } from "~/helpers/network"
import { useReadonlyStream, useStream } from "@composables/stream" import { useReadonlyStream, useStream } from "@composables/stream"
import { useI18n } from "@composables/i18n" import { useI18n } from "@composables/i18n"
import { gqlHeaders$, gqlURL$, setGQLURL } from "~/newstore/GQLSession" import {
gqlAuth$,
gqlHeaders$,
gqlURL$,
setGQLURL,
} from "~/newstore/GQLSession"
const t = useI18n() const t = useI18n()
@@ -40,13 +46,18 @@ const props = defineProps<{
}>() }>()
const connected = useReadonlyStream(props.conn.connected$, false) const connected = useReadonlyStream(props.conn.connected$, false)
const isLoading = useReadonlyStream(props.conn.isLoading$, false)
const headers = useReadonlyStream(gqlHeaders$, []) const headers = useReadonlyStream(gqlHeaders$, [])
const auth = useReadonlyStream(gqlAuth$, {
authType: "none",
authActive: true,
})
const url = useStream(gqlURL$, "", setGQLURL) const url = useStream(gqlURL$, "", setGQLURL)
const onConnectClick = () => { const onConnectClick = () => {
if (!connected.value) { if (!connected.value) {
props.conn.connect(url.value, headers.value as any) props.conn.connect(url.value, headers.value as any, auth.value)
platform.analytics?.logHoppRequestRunToAnalytics({ platform.analytics?.logHoppRequestRunToAnalytics({
platform: "graphql-schema", platform: "graphql-schema",

View File

@@ -84,6 +84,7 @@ import { useToast } from "@composables/toast"
import { isJSONContentType } from "~/helpers/utils/contenttypes" import { isJSONContentType } from "~/helpers/utils/contenttypes"
import jsonLinter from "~/helpers/editor/linting/json" import jsonLinter from "~/helpers/editor/linting/json"
import { readFileAsText } from "~/helpers/functional/files" import { readFileAsText } from "~/helpers/functional/files"
import xmlFormat from "xml-formatter"
type PossibleContentTypes = Exclude< type PossibleContentTypes = Exclude<
ValidContentTypes, ValidContentTypes,
@@ -197,26 +198,10 @@ const prettifyRequestBody = () => {
} }
const prettifyXML = (xml: string) => { const prettifyXML = (xml: string) => {
const PADDING = " ".repeat(2) // set desired indent size here return xmlFormat(xml, {
const reg = /(>)(<)(\/*)/g indentation: " ",
let pad = 0 collapseContent: true,
xml = xml.replace(reg, "$1\r\n$2$3") lineSeparator: "\n",
return xml })
.split("\r\n")
.map((node) => {
let indent = 0
if (node.match(/.+<\/\w[^>]*>$/)) {
indent = 0
} else if (node.match(/^<\/\w/) && pad > 0) {
pad -= 1
} else if (node.match(/^<\w[^>]*[^\/]>.*$/)) {
indent = 1
} else {
indent = 0
}
pad += indent
return PADDING.repeat(pad - indent) + node
})
.join("\r\n")
} }
</script> </script>

View File

@@ -217,6 +217,7 @@
@hide-modal="showCodegenModal = false" @hide-modal="showCodegenModal = false"
/> />
<CollectionsSaveRequest <CollectionsSaveRequest
v-if="showSaveRequestModal"
mode="rest" mode="rest"
:show="showSaveRequestModal" :show="showSaveRequestModal"
@hide-modal="showSaveRequestModal = false" @hide-modal="showSaveRequestModal = false"
@@ -229,11 +230,10 @@ import { useI18n } from "@composables/i18n"
import { useSetting } from "@composables/settings" import { useSetting } from "@composables/settings"
import { useStreamSubscriber } from "@composables/stream" import { useStreamSubscriber } from "@composables/stream"
import { useToast } from "@composables/toast" import { useToast } from "@composables/toast"
import { completePageProgress, startPageProgress } from "@modules/loadingbar"
import { refAutoReset, useVModel } from "@vueuse/core" import { refAutoReset, useVModel } from "@vueuse/core"
import * as E from "fp-ts/Either" import * as E from "fp-ts/Either"
import { isLeft, isRight } from "fp-ts/lib/Either" import { isLeft, isRight } from "fp-ts/lib/Either"
import { computed, ref, watch } from "vue" import { computed, onBeforeUnmount, ref } from "vue"
import { defineActionHandler } from "~/helpers/actions" import { defineActionHandler } from "~/helpers/actions"
import { runMutation } from "~/helpers/backend/GQLClient" import { runMutation } from "~/helpers/backend/GQLClient"
import { UpdateRequestDocument } from "~/helpers/backend/graphql" import { UpdateRequestDocument } from "~/helpers/backend/graphql"
@@ -259,6 +259,8 @@ import IconSave from "~icons/lucide/save"
import IconShare2 from "~icons/lucide/share-2" import IconShare2 from "~icons/lucide/share-2"
import { HoppRESTTab } from "~/helpers/rest/tab" import { HoppRESTTab } from "~/helpers/rest/tab"
import { getDefaultRESTRequest } from "~/helpers/rest/default" import { getDefaultRESTRequest } from "~/helpers/rest/default"
import { platform } from "~/platform"
import { getCurrentStrategyID } from "~/helpers/network"
const t = useI18n() const t = useI18n()
@@ -311,39 +313,6 @@ const clearAll = ref<any | null>(null)
const copyRequestAction = ref<any | null>(null) const copyRequestAction = ref<any | null>(null)
const saveRequestAction = ref<any | null>(null) const saveRequestAction = ref<any | null>(null)
// Update Nuxt Loading bar
watch(loading, () => {
if (loading.value) {
startPageProgress()
} else {
completePageProgress()
}
})
// TODO: make this oAuthURL() work
// function oAuthURL() {
// const auth = useReadonlyStream(props.request.auth$, {
// authType: "none",
// authActive: true,
// })
// const oauth2Token = pluckRef(auth as Ref<HoppRESTAuthOAuth2>, "token")
// onBeforeMount(async () => {
// try {
// const tokenInfo = await oauthRedirect()
// if (Object.prototype.hasOwnProperty.call(tokenInfo, "access_token")) {
// if (typeof tokenInfo === "object") {
// oauth2Token.value = tokenInfo.access_token
// }
// }
// // eslint-disable-next-line no-empty
// } catch (_) {}
// })
// }
const newSendRequest = async () => { const newSendRequest = async () => {
if (newEndpoint.value === "" || /^\s+$/.test(newEndpoint.value)) { if (newEndpoint.value === "" || /^\s+$/.test(newEndpoint.value)) {
toast.error(`${t("empty.endpoint")}`) toast.error(`${t("empty.endpoint")}`)
@@ -354,6 +323,12 @@ const newSendRequest = async () => {
loading.value = true loading.value = true
// Log the request run into analytics
platform.analytics?.logHoppRequestRunToAnalytics({
platform: "rest",
strategy: getCurrentStrategyID(),
})
// Double calling is because the function returns a TaskEither than should be executed // Double calling is because the function returns a TaskEither than should be executed
const streamResult = await runRESTRequest$(tab)() const streamResult = await runRESTRequest$(tab)()
@@ -574,6 +549,10 @@ const saveRequest = () => {
} }
} }
onBeforeUnmount(() => {
if (loading.value) cancelRequest()
})
defineActionHandler("request.send-cancel", () => { defineActionHandler("request.send-cancel", () => {
if (!loading.value) newSendRequest() if (!loading.value) newSendRequest()
else cancelRequest() else cancelRequest()

View File

@@ -10,8 +10,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed, ref, watch } from "vue" import { computed, ref } from "vue"
import { startPageProgress, completePageProgress } from "@modules/loadingbar"
import { HoppRESTTab } from "~/helpers/rest/tab" import { HoppRESTTab } from "~/helpers/rest/tab"
import { useVModel } from "@vueuse/core" import { useVModel } from "@vueuse/core"
@@ -34,9 +33,4 @@ const hasResponse = computed(
) )
const loading = computed(() => tab.value.response?.type === "loading") const loading = computed(() => tab.value.response?.type === "loading")
watch(loading, (isLoading) => {
if (isLoading) startPageProgress()
else completePageProgress()
})
</script> </script>

View File

@@ -197,11 +197,20 @@
/> />
</div> </div>
<EnvironmentsMyDetails <EnvironmentsMyDetails
:show="showModalDetails" :show="showMyEnvironmentDetailsModal"
action="new" action="new"
:env-vars="getAdditionVars" :env-vars="getAdditionVars"
@hide-modal="displayModalAdd(false)" @hide-modal="displayModalAdd(false)"
/> />
<EnvironmentsTeamsDetails
:show="showTeamEnvironmentDetailsModal"
action="new"
:env-vars="getAdditionVars"
:editing-team-id="
workspace.type === 'team' ? workspace.teamID : undefined
"
@hide-modal="displayModalAdd(false)"
/>
</div> </div>
</template> </template>
@@ -225,6 +234,7 @@ import IconClose from "~icons/lucide/x"
import { useColorMode } from "~/composables/theming" import { useColorMode } from "~/composables/theming"
import { useVModel } from "@vueuse/core" import { useVModel } from "@vueuse/core"
import { workspaceStatus$ } from "~/newstore/workspace"
const props = defineProps<{ const props = defineProps<{
modelValue: HoppTestResult | null | undefined modelValue: HoppTestResult | null | undefined
@@ -239,10 +249,15 @@ const testResults = useVModel(props, "modelValue", emit)
const t = useI18n() const t = useI18n()
const colorMode = useColorMode() const colorMode = useColorMode()
const showModalDetails = ref(false) const workspace = useReadonlyStream(workspaceStatus$, { type: "personal" })
const showMyEnvironmentDetailsModal = ref(false)
const showTeamEnvironmentDetailsModal = ref(false)
const displayModalAdd = (shouldDisplay: boolean) => { const displayModalAdd = (shouldDisplay: boolean) => {
showModalDetails.value = shouldDisplay if (workspace.value.type === "personal")
showMyEnvironmentDetailsModal.value = shouldDisplay
else showTeamEnvironmentDetailsModal.value = shouldDisplay
} }
/** /**

View File

@@ -0,0 +1,79 @@
<template>
<div class="flex flex-col flex-1">
<div
class="sticky z-10 flex items-center justify-between flex-shrink-0 pl-4 overflow-x-auto border-b bg-primary border-dividerLight top-lowerSecondaryStickyFold"
>
<label class="font-semibold truncate text-secondaryLight">
{{ t("response.body") }}
</label>
<div class="flex">
<HoppButtonSecondary
v-if="response.body"
v-tippy="{ theme: 'tooltip', allowHTML: true }"
:title="`${t(
'action.download_file'
)} <kbd>${getSpecialKey()}</kbd><kbd>J</kbd>`"
:icon="downloadIcon"
@click="downloadResponse"
/>
</div>
</div>
<div class="flex flex-1 items-center justify-center overflow-auto">
<audio controls :src="audiosrc"></audio>
</div>
</div>
</template>
<script setup lang="ts">
import { computed } from "vue"
import { useI18n } from "@composables/i18n"
import { useDownloadResponse } from "@composables/lens-actions"
import { HoppRESTResponse } from "~/helpers/types/HoppRESTResponse"
import { defineActionHandler } from "~/helpers/actions"
import { getPlatformSpecialKey as getSpecialKey } from "~/helpers/platformutils"
import { flow, pipe } from "fp-ts/function"
import * as S from "fp-ts/string"
import * as RNEA from "fp-ts/ReadonlyNonEmptyArray"
import * as A from "fp-ts/Array"
import * as O from "fp-ts/Option"
import { objFieldMatches } from "~/helpers/functional/object"
const t = useI18n()
const props = defineProps<{
response: HoppRESTResponse & {
type: "success" | "fail"
}
}>()
const audiosrc = computed(() =>
URL.createObjectURL(
new Blob([props.response.body], {
type: "audio/mp3",
})
)
)
const responseType = computed(() =>
pipe(
props.response,
O.fromPredicate(objFieldMatches("type", ["fail", "success"] as const)),
O.chain(
// Try getting content-type
flow(
(res) => res.headers,
A.findFirst((h) => h.key.toLowerCase() === "content-type"),
O.map(flow((h) => h.value, S.split(";"), RNEA.head, S.toLowerCase))
)
),
O.getOrElse(() => "text/plain")
)
)
const { downloadIcon, downloadResponse } = useDownloadResponse(
responseType.value,
computed(() => props.response.body)
)
defineActionHandler("response.file.download", () => downloadResponse())
</script>

View File

@@ -0,0 +1,79 @@
<template>
<div class="flex flex-col flex-1">
<div
class="sticky z-10 flex items-center justify-between flex-shrink-0 pl-4 overflow-x-auto border-b bg-primary border-dividerLight top-lowerSecondaryStickyFold"
>
<label class="font-semibold truncate text-secondaryLight">
{{ t("response.body") }}
</label>
<div class="flex">
<HoppButtonSecondary
v-if="response.body"
v-tippy="{ theme: 'tooltip', allowHTML: true }"
:title="`${t(
'action.download_file'
)} <kbd>${getSpecialKey()}</kbd><kbd>J</kbd>`"
:icon="downloadIcon"
@click="downloadResponse"
/>
</div>
</div>
<div class="flex flex-1 items-center justify-center overflow-auto">
<video controls :src="videosrc"></video>
</div>
</div>
</template>
<script setup lang="ts">
import { computed } from "vue"
import { useI18n } from "@composables/i18n"
import { useDownloadResponse } from "@composables/lens-actions"
import { HoppRESTResponse } from "~/helpers/types/HoppRESTResponse"
import { defineActionHandler } from "~/helpers/actions"
import { getPlatformSpecialKey as getSpecialKey } from "~/helpers/platformutils"
import { flow, pipe } from "fp-ts/function"
import * as S from "fp-ts/string"
import * as RNEA from "fp-ts/ReadonlyNonEmptyArray"
import * as A from "fp-ts/Array"
import * as O from "fp-ts/Option"
import { objFieldMatches } from "~/helpers/functional/object"
const t = useI18n()
const props = defineProps<{
response: HoppRESTResponse & {
type: "success" | "fail"
}
}>()
const videosrc = computed(() =>
URL.createObjectURL(
new Blob([props.response.body], {
type: "video/mp4",
})
)
)
const responseType = computed(() =>
pipe(
props.response,
O.fromPredicate(objFieldMatches("type", ["fail", "success"] as const)),
O.chain(
// Try getting content-type
flow(
(res) => res.headers,
A.findFirst((h) => h.key.toLowerCase() === "content-type"),
O.map(flow((h) => h.value, S.split(";"), RNEA.head, S.toLowerCase))
)
),
O.getOrElse(() => "text/plain")
)
)
const { downloadIcon, downloadResponse } = useDownloadResponse(
responseType.value,
computed(() => props.response.body)
)
defineActionHandler("response.file.download", () => downloadResponse())
</script>

View File

@@ -1,87 +0,0 @@
<template>
<button
tabindex="0"
class="relative flex items-center justify-center overflow-visible cursor-pointer focus:outline-none focus-visible:ring-2 focus-visible:ring-primaryDark"
:class="[`rounded-${rounded}`, `w-${size} h-${size}`]"
>
<img
v-if="url"
class="absolute object-cover object-center transition bg-primaryDark"
:class="[`rounded-${rounded}`, `w-${size} h-${size}`]"
:src="url"
:alt="alt"
loading="lazy"
/>
<div
v-else
class="absolute flex items-center justify-center object-cover object-center transition bg-primaryDark text-accentContrast"
:class="[`rounded-${rounded}`, `w-${size} h-${size}`]"
:style="`background-color: ${initial ? toHex(initial) : '#480000'}`"
>
<template v-if="initial && initial.charAt(0).toUpperCase()">
{{ initial.charAt(0).toUpperCase() }}
</template>
<icon-lucide-user v-else></icon-lucide-user>
</div>
<span
v-if="indicator"
class="border-primary border-2 h-2.5 -top-0.5 -right-0.5 w-2.5 absolute"
:class="[`rounded-${rounded}`, indicatorStyles]"
></span>
<!-- w-5 h-5 rounded-lg -->
</button>
</template>
<script lang="ts">
import { defineComponent, PropType } from "vue"
export default defineComponent({
props: {
url: {
type: String,
default: "",
},
alt: {
type: String,
default: "Profile picture",
},
indicator: {
type: Boolean,
default: false,
},
indicatorStyles: {
type: String,
default: "bg-green-500",
},
rounded: {
type: String,
default: "full",
},
size: {
type: String,
default: "5",
},
initial: {
type: String as PropType<string | undefined | null>,
default: "",
},
},
methods: {
toHex(initial: string) {
let hash = 0
if (initial.length === 0) return hash
for (let i = 0; i < initial.length; i++) {
hash = initial.charCodeAt(i) + ((hash << 5) - hash)
hash = hash & hash
}
let color = "#"
for (let i = 0; i < 3; i++) {
const value = (hash >> (i * 8)) & 255
color += `00${value.toString(16)}`.slice(-2)
}
return color
},
},
})
</script>

View File

@@ -34,6 +34,7 @@ import { inputTheme } from "~/helpers/editor/themes/baseTheme"
import { HoppReactiveEnvPlugin } from "~/helpers/editor/extensions/HoppEnvironment" import { HoppReactiveEnvPlugin } from "~/helpers/editor/extensions/HoppEnvironment"
import { useReadonlyStream } from "@composables/stream" import { useReadonlyStream } from "@composables/stream"
import { AggregateEnvironment, aggregateEnvs$ } from "~/newstore/environments" import { AggregateEnvironment, aggregateEnvs$ } from "~/newstore/environments"
import { platform } from "~/platform"
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
@@ -43,6 +44,7 @@ const props = withDefaults(
envs?: { key: string; value: string; source: string }[] | null envs?: { key: string; value: string; source: string }[] | null
focus?: boolean focus?: boolean
selectTextOnMount?: boolean selectTextOnMount?: boolean
environmentHighlights?: boolean
readonly?: boolean readonly?: boolean
}>(), }>(),
{ {
@@ -52,6 +54,7 @@ const props = withDefaults(
envs: null, envs: null,
focus: false, focus: false,
readonly: false, readonly: false,
environmentHighlights: true,
} }
) )
@@ -141,7 +144,7 @@ const initView = (el: any) => {
tooltips({ tooltips({
position: "absolute", position: "absolute",
}), }),
envTooltipPlugin, props.environmentHighlights ? envTooltipPlugin : [],
placeholderExt(props.placeholder), placeholderExt(props.placeholder),
EditorView.domEventHandlers({ EditorView.domEventHandlers({
paste(ev) { paste(ev) {
@@ -219,6 +222,7 @@ onMounted(() => {
if (editor.value) { if (editor.value) {
if (!view.value) initView(editor.value) if (!view.value) initView(editor.value)
if (props.selectTextOnMount) triggerTextSelection() if (props.selectTextOnMount) triggerTextSelection()
platform.ui?.onCodemirrorInstanceMount?.(editor.value)
} }
}) })

View File

@@ -5,7 +5,7 @@
:key="`member-${index}`" :key="`member-${index}`"
class="inline-flex" class="inline-flex"
> >
<ProfilePicture <HoppSmartPicture
v-if="member.user.photoURL" v-if="member.user.photoURL"
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:url="member.user.photoURL" :url="member.user.photoURL"
@@ -14,7 +14,7 @@
class="ring-primary ring-2" class="ring-primary ring-2"
@click="handleClick()" @click="handleClick()"
/> />
<ProfilePicture <HoppSmartPicture
v-else v-else
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="getUserName(member)" :title="getUserName(member)"

View File

@@ -38,6 +38,8 @@ import {
baseHighlightStyle, baseHighlightStyle,
} from "@helpers/editor/themes/baseTheme" } from "@helpers/editor/themes/baseTheme"
import { HoppEnvironmentPlugin } from "@helpers/editor/extensions/HoppEnvironment" import { HoppEnvironmentPlugin } from "@helpers/editor/extensions/HoppEnvironment"
import xmlFormat from "xml-formatter"
import { platform } from "~/platform"
// TODO: Migrate from legacy mode // TODO: Migrate from legacy mode
type ExtendedEditorConfig = { type ExtendedEditorConfig = {
@@ -151,6 +153,27 @@ const getLanguage = (langMime: string): Language | null => {
return null return null
} }
/**
* Uses xml-formatter to format the XML document
* @param doc Document to parse
* @param langMime Language mime type
* @returns Parsed document if mime type is xml, else returns the original document
*/
const parseDoc = (
doc: string | undefined,
langMime: string
): string | undefined => {
if (langMime === "application/xml" && doc) {
return xmlFormat(doc, {
indentation: " ",
collapseContent: true,
lineSeparator: "\n",
})
} else {
return doc
}
}
const getEditorLanguage = ( const getEditorLanguage = (
langMime: string, langMime: string,
linter: LinterDefinition | undefined, linter: LinterDefinition | undefined,
@@ -186,6 +209,8 @@ export function useCodemirror(
: null : null
const initView = (el: any) => { const initView = (el: any) => {
if (el) platform.ui?.onCodemirrorInstanceMount?.(el)
const extensions = [ const extensions = [
basicSetup, basicSetup,
baseTheme, baseTheme,
@@ -258,7 +283,7 @@ export function useCodemirror(
view.value = new EditorView({ view.value = new EditorView({
parent: el, parent: el,
state: EditorState.create({ state: EditorState.create({
doc: value.value, doc: parseDoc(value.value, options.extendedEditorConfig.mode ?? ""),
extensions, extensions,
}), }),
}) })

View File

@@ -99,7 +99,7 @@ export class GQLConnection {
private timeoutSubscription: any private timeoutSubscription: any
public connect(url: string, headers: GQLHeader[]) { public connect(url: string, headers: GQLHeader[], auth: HoppGQLAuth) {
if (this.connected$.value) { if (this.connected$.value) {
throw new Error( throw new Error(
"A connection is already running. Close it before starting another." "A connection is already running. Close it before starting another."
@@ -110,7 +110,7 @@ export class GQLConnection {
this.connected$.next(true) this.connected$.next(true)
const poll = async () => { const poll = async () => {
await this.getSchema(url, headers) await this.getSchema(url, headers, auth)
this.timeoutSubscription = setTimeout(() => { this.timeoutSubscription = setTimeout(() => {
poll() poll()
}, GQL_SCHEMA_POLL_INTERVAL) }, GQL_SCHEMA_POLL_INTERVAL)
@@ -135,7 +135,11 @@ export class GQLConnection {
this.schema$.next(null) this.schema$.next(null)
} }
private async getSchema(url: string, headers: GQLHeader[]) { private async getSchema(
url: string,
reqHeaders: GQLHeader[],
auth: HoppGQLAuth
) {
try { try {
this.isLoading$.next(true) this.isLoading$.next(true)
@@ -143,10 +147,38 @@ export class GQLConnection {
query: getIntrospectionQuery(), query: getIntrospectionQuery(),
}) })
const headers = reqHeaders.filter((x) => x.active && x.key !== "")
// TODO: Support a better b64 implementation than btoa ?
if (auth.authType === "basic") {
const username = auth.username
const password = auth.password
headers.push({
active: true,
key: "Authorization",
value: `Basic ${btoa(`${username}:${password}`)}`,
})
} else if (auth.authType === "bearer" || auth.authType === "oauth-2") {
headers.push({
active: true,
key: "Authorization",
value: `Bearer ${auth.token}`,
})
} else if (auth.authType === "api-key") {
const { key, value, addTo } = auth
if (addTo === "Headers") {
headers.push({
active: true,
key,
value,
})
}
}
const finalHeaders: Record<string, string> = {} const finalHeaders: Record<string, string> = {}
headers headers.forEach((x) => (finalHeaders[x.key] = x.value))
.filter((x) => x.active && x.key !== "")
.forEach((x) => (finalHeaders[x.key] = x.value))
const reqOptions = { const reqOptions = {
method: "POST", method: "POST",

View File

@@ -6,14 +6,18 @@ import { isJSONContentType } from "./utils/contenttypes"
* Handles translations for all the hopp.io REST Shareable URL params * Handles translations for all the hopp.io REST Shareable URL params
*/ */
export function translateExtURLParams( export function translateExtURLParams(
urlParams: Record<string, any> urlParams: Record<string, any>,
initialReq?: HoppRESTRequest
): HoppRESTRequest { ): HoppRESTRequest {
if (urlParams.v) return parseV1ExtURL(urlParams) if (urlParams.v) return parseV1ExtURL(urlParams, initialReq)
else return parseV0ExtURL(urlParams) else return parseV0ExtURL(urlParams, initialReq)
} }
function parseV0ExtURL(urlParams: Record<string, any>): HoppRESTRequest { function parseV0ExtURL(
const resolvedReq = getDefaultRESTRequest() urlParams: Record<string, any>,
initialReq?: HoppRESTRequest
): HoppRESTRequest {
const resolvedReq = initialReq ?? getDefaultRESTRequest()
if (urlParams.method && typeof urlParams.method === "string") { if (urlParams.method && typeof urlParams.method === "string") {
resolvedReq.method = urlParams.method resolvedReq.method = urlParams.method
@@ -89,8 +93,11 @@ function parseV0ExtURL(urlParams: Record<string, any>): HoppRESTRequest {
return resolvedReq return resolvedReq
} }
function parseV1ExtURL(urlParams: Record<string, any>): HoppRESTRequest { function parseV1ExtURL(
const resolvedReq = getDefaultRESTRequest() urlParams: Record<string, any>,
initialReq?: HoppRESTRequest
): HoppRESTRequest {
const resolvedReq = initialReq ?? getDefaultRESTRequest()
if (urlParams.headers && typeof urlParams.headers === "string") { if (urlParams.headers && typeof urlParams.headers === "string") {
resolvedReq.headers = JSON.parse(urlParams.headers) resolvedReq.headers = JSON.parse(urlParams.headers)

View File

@@ -6,6 +6,7 @@ import { pipe, flow } from "fp-ts/function"
import { tupleToRecord } from "~/helpers/functional/record" import { tupleToRecord } from "~/helpers/functional/record"
import { safeParseJSON } from "~/helpers/functional/json" import { safeParseJSON } from "~/helpers/functional/json"
import { optionChoose } from "~/helpers/functional/option" import { optionChoose } from "~/helpers/functional/option"
import xmlFormat from "xml-formatter"
const isJSON = flow(safeParseJSON, O.isSome) const isJSON = flow(safeParseJSON, O.isSome)
@@ -213,45 +214,18 @@ export function parseBody(
*/ */
/** /**
* Prettifies XML string * Prettifies XML string using xml-formatter
* @param sourceXml The string to format * @param sourceXml The string to format
* @returns Indented XML string (uses spaces) * @returns Indented XML string (uses spaces)
*/ */
function prettifyXml(sourceXml: string) { function prettifyXml(sourceXml: string) {
return pipe( return pipe(
O.tryCatch(() => { O.tryCatch(() => {
const xmlDoc = new DOMParser().parseFromString( return xmlFormat(sourceXml, {
sourceXml, indentation: " ",
"application/xml" collapseContent: true,
) lineSeparator: "\n",
})
if (xmlDoc.querySelector("parsererror")) {
throw new Error("Unstructured Body")
}
const xsltDoc = new DOMParser().parseFromString(
[
// describes how we want to modify the XML - indent everything
'<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">',
' <xsl:strip-space elements="*"/>',
' <xsl:template match="para[content-style][not(text())]">', // change to just text() to strip space in text nodes
' <xsl:value-of select="normalize-space(.)"/>',
" </xsl:template>",
' <xsl:template match="node()|@*">',
' <xsl:copy><xsl:apply-templates select="node()|@*"/></xsl:copy>',
" </xsl:template>",
' <xsl:output indent="yes"/>',
"</xsl:stylesheet>",
].join("\n"),
"application/xml"
)
const xsltProcessor = new XSLTProcessor()
xsltProcessor.importStylesheet(xsltDoc)
const resultDoc = xsltProcessor.transformToDocument(xmlDoc)
const resultXml = new XMLSerializer().serializeToString(resultDoc)
return resultXml
}) })
) )
} }

View File

@@ -121,8 +121,8 @@ function getPressedKey(ev: KeyboardEvent): Key | null {
else if (val === "arrowright") return "right" else if (val === "arrowright") return "right"
// Check letter keys // Check letter keys
if (val.length === 1 && val.toUpperCase() !== val.toLowerCase()) const isLetter = ev.code.toLowerCase().startsWith("key")
return val as Key if (isLetter) return ev.code.toLowerCase().substring(3) as Key
// Check if number keys // Check if number keys
if (val.length === 1 && !isNaN(val as any)) return val as Key if (val.length === 1 && !isNaN(val as any)) return val as Key

View File

@@ -0,0 +1,16 @@
import { defineAsyncComponent } from "vue"
import { Lens } from "./lenses"
const audioLens: Lens = {
lensName: "response.audio",
isSupportedContentType: (contentType) =>
/\baudio\/(?:wav|mpeg|mp4|aac|aacp|ogg|webm|x-caf|flac|mp3|)\b/i.test(
contentType
),
renderer: "audiores",
rendererImport: defineAsyncComponent(
() => import("~/components/lenses/renderers/AudioLensRenderer.vue")
),
}
export default audioLens

View File

@@ -5,6 +5,8 @@ import imageLens from "./imageLens"
import htmlLens from "./htmlLens" import htmlLens from "./htmlLens"
import xmlLens from "./xmlLens" import xmlLens from "./xmlLens"
import pdfLens from "./pdfLens" import pdfLens from "./pdfLens"
import audioLens from "./audioLens"
import videoLens from "./videoLens"
import { defineAsyncComponent } from "vue" import { defineAsyncComponent } from "vue"
export type Lens = { export type Lens = {
@@ -20,6 +22,8 @@ export const lenses: Lens[] = [
htmlLens, htmlLens,
xmlLens, xmlLens,
pdfLens, pdfLens,
audioLens,
videoLens,
rawLens, rawLens,
] ]

View File

@@ -0,0 +1,16 @@
import { defineAsyncComponent } from "vue"
import { Lens } from "./lenses"
const videoLens: Lens = {
lensName: "response.video",
isSupportedContentType: (contentType) =>
/\bvideo\/(?:webm|x-m4v|quicktime|x-ms-wmv|x-flv|mpeg|x-msvideo|x-ms-asf|mp4|)\b/i.test(
contentType
),
renderer: "videores",
rendererImport: defineAsyncComponent(
() => import("~/components/lenses/renderers/VideoLensRenderer.vue")
),
}
export default videoLens

View File

@@ -7,8 +7,8 @@ pw.env.set("variable", "value");`,
{ {
name: "Environment: Set timestamp variable", name: "Environment: Set timestamp variable",
script: `\n\n// Set timestamp variable script: `\n\n// Set timestamp variable
const cuttentTime = Date.now(); const currentTime = Date.now();
pw.env.set("timestamp", cuttentTime.toString());`, pw.env.set("timestamp", currentTime.toString());`,
}, },
{ {
name: "Environment: Set random number variable", name: "Environment: Set random number variable",

View File

@@ -24,7 +24,10 @@
> >
<Pane class="flex flex-1 !overflow-auto"> <Pane class="flex flex-1 !overflow-auto">
<main class="flex flex-1 w-full" role="main"> <main class="flex flex-1 w-full" role="main">
<RouterView v-slot="{ Component }" class="flex flex-1"> <RouterView
v-slot="{ Component }"
class="flex flex-1 min-w-0"
>
<Transition name="fade" mode="out-in" appear> <Transition name="fade" mode="out-in" appear>
<component :is="Component" /> <component :is="Component" />
</Transition> </Transition>

View File

@@ -275,7 +275,4 @@ export const gqlResponse$ = gqlSessionStore.subject$.pipe(
distinctUntilChanged() distinctUntilChanged()
) )
export const gqlAuth$ = gqlSessionStore.subject$.pipe( export const gqlAuth$ = gqlSessionStore.subject$.pipe(pluck("request", "auth"))
pluck("request", "auth"),
distinctUntilChanged()
)

View File

@@ -37,13 +37,27 @@ type EnvironmentStore = typeof defaultEnvironmentsState
const dispatchers = defineDispatchers({ const dispatchers = defineDispatchers({
setSelectedEnvironmentIndex( setSelectedEnvironmentIndex(
_: EnvironmentStore, store: EnvironmentStore,
{ {
selectedEnvironmentIndex, selectedEnvironmentIndex,
}: { selectedEnvironmentIndex: SelectedEnvironmentIndex } }: { selectedEnvironmentIndex: SelectedEnvironmentIndex }
) { ) {
return { if (selectedEnvironmentIndex.type === "MY_ENV") {
selectedEnvironmentIndex, if (store.environments[selectedEnvironmentIndex.index]) {
return {
selectedEnvironmentIndex,
}
} else {
return {
selectedEnvironmentIndex: {
type: "NO_ENV_SELECTED",
},
}
}
} else {
return {
selectedEnvironmentIndex,
}
} }
}, },
appendEnvironments( appendEnvironments(
@@ -325,21 +339,22 @@ export const selectedEnvironmentIndex$ = environmentsStore.subject$.pipe(
distinctUntilChanged() distinctUntilChanged()
) )
export const currentEnvironment$ = environmentsStore.subject$.pipe( export const currentEnvironment$: Observable<Environment | undefined> =
map(({ environments, selectedEnvironmentIndex }) => { environmentsStore.subject$.pipe(
if (selectedEnvironmentIndex.type === "NO_ENV_SELECTED") { map(({ environments, selectedEnvironmentIndex }) => {
const env: Environment = { if (selectedEnvironmentIndex.type === "NO_ENV_SELECTED") {
name: "No environment", const env: Environment = {
variables: [], name: "No environment",
variables: [],
}
return env
} else if (selectedEnvironmentIndex.type === "MY_ENV") {
return environments[selectedEnvironmentIndex.index]
} else {
return selectedEnvironmentIndex.environment
} }
return env })
} else if (selectedEnvironmentIndex.type === "MY_ENV") { )
return environments[selectedEnvironmentIndex.index]
} else {
return selectedEnvironmentIndex.environment
}
})
)
export type AggregateEnvironment = { export type AggregateEnvironment = {
key: string key: string
@@ -358,7 +373,7 @@ export const aggregateEnvs$: Observable<AggregateEnvironment[]> = combineLatest(
map(([selectedEnv, globalVars]) => { map(([selectedEnv, globalVars]) => {
const results: AggregateEnvironment[] = [] const results: AggregateEnvironment[] = []
selectedEnv.variables.forEach(({ key, value }) => selectedEnv?.variables.forEach(({ key, value }) =>
results.push({ key, value, sourceEnv: selectedEnv.name }) results.push({ key, value, sourceEnv: selectedEnv.name })
) )
globalVars.forEach(({ key, value }) => globalVars.forEach(({ key, value }) =>

View File

@@ -47,6 +47,8 @@ import {
loadTabsFromPersistedState, loadTabsFromPersistedState,
persistableTabState, persistableTabState,
} from "~/helpers/rest/tab" } from "~/helpers/rest/tab"
import { debounceTime } from "rxjs"
import { gqlSessionStore, setGQLSession } from "./GQLSession"
function checkAndMigrateOldSettings() { function checkAndMigrateOldSettings() {
if (window.localStorage.getItem("selectedEnvIndex")) { if (window.localStorage.getItem("selectedEnvIndex")) {
@@ -333,12 +335,35 @@ export function setupRESTTabsPersistence() {
) )
} }
// temporary persistence for GQL session
export function setupGQLPersistence() {
try {
const state = window.localStorage.getItem("gqlState")
if (state) {
const data = JSON.parse(state)
data["schema"] = ""
data["response"] = ""
setGQLSession(data)
}
} catch (e) {
console.error(
`Failed parsing persisted GraphQL state, state:`,
window.localStorage.getItem("gqlState")
)
}
gqlSessionStore.subject$.pipe(debounceTime(500)).subscribe((state) => {
window.localStorage.setItem("gqlState", JSON.stringify(state))
})
}
export function setupLocalPersistence() { export function setupLocalPersistence() {
checkAndMigrateOldSettings() checkAndMigrateOldSettings()
setupLocalStatePersistence() setupLocalStatePersistence()
setupSettingsPersistence() setupSettingsPersistence()
setupRESTTabsPersistence() setupRESTTabsPersistence()
setupGQLPersistence()
setupHistoryPersistence() setupHistoryPersistence()
setupCollectionsPersistence() setupCollectionsPersistence()
setupGlobalEnvsPersistence() setupGlobalEnvsPersistence()

View File

@@ -0,0 +1,40 @@
import { distinctUntilChanged, pluck } from "rxjs"
import DispatchingStore, { defineDispatchers } from "./DispatchingStore"
type SyncState = {
isInitialSync: boolean
shouldSync: boolean
}
type CurrentSyncingState = {
currentSyncingItem: SyncState
}
const initialState: CurrentSyncingState = {
currentSyncingItem: {
isInitialSync: false,
shouldSync: false,
},
}
const dispatchers = defineDispatchers({
changeCurrentSyncStatus(_, { syncItem }: { syncItem: SyncState }) {
return {
currentSyncingItem: syncItem,
}
},
})
export const currentSyncStore = new DispatchingStore(initialState, dispatchers)
export const currentSyncingStatus$ = currentSyncStore.subject$.pipe(
pluck("currentSyncingItem"),
distinctUntilChanged()
)
export function changeCurrentSyncStatus(syncItem: SyncState) {
currentSyncStore.dispatch({
dispatcher: "changeCurrentSyncStatus",
payload: { syncItem },
})
}

View File

@@ -14,12 +14,10 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed, onBeforeUnmount, watch } from "vue"
import { useReadonlyStream } from "@composables/stream"
import { useI18n } from "@composables/i18n"
import { usePageHead } from "@composables/head" import { usePageHead } from "@composables/head"
import { startPageProgress, completePageProgress } from "@modules/loadingbar" import { useI18n } from "@composables/i18n"
import { GQLConnection } from "@helpers/GQLConnection" import { GQLConnection } from "@helpers/GQLConnection"
import { computed, onBeforeUnmount } from "vue"
const t = useI18n() const t = useI18n()
@@ -28,16 +26,10 @@ usePageHead({
}) })
const gqlConn = new GQLConnection() const gqlConn = new GQLConnection()
const isLoading = useReadonlyStream(gqlConn.isLoading$, false)
onBeforeUnmount(() => { onBeforeUnmount(() => {
if (gqlConn.connected$.value) { if (gqlConn.connected$.value) {
gqlConn.disconnect() gqlConn.disconnect()
} }
}) })
watch(isLoading, () => {
if (isLoading.value) startPageProgress()
else completePageProgress()
})
</script> </script>

View File

@@ -23,6 +23,7 @@
v-tippy="{ theme: 'tooltip', delay: [500, 20] }" v-tippy="{ theme: 'tooltip', delay: [500, 20] }"
:title="tab.document.request.name" :title="tab.document.request.name"
class="truncate px-2" class="truncate px-2"
@dblclick="openReqRenameModal()"
> >
<span <span
class="font-semibold text-tiny" class="font-semibold text-tiny"
@@ -55,12 +56,21 @@
@update:model-value="onTabUpdate" @update:model-value="onTabUpdate"
/> />
</HoppSmartWindow> </HoppSmartWindow>
<template #actions>
<EnvironmentsSelector class="h-full" />
</template>
</HoppSmartWindows> </HoppSmartWindows>
</template> </template>
<template #sidebar> <template #sidebar>
<HttpSidebar /> <HttpSidebar />
</template> </template>
</AppPaneLayout> </AppPaneLayout>
<CollectionsEditRequest
v-model="reqName"
:show="showRenamingReqNameModal"
@submit="renameReqName"
@hide-modal="showRenamingReqNameModal = false"
/>
<HoppSmartConfirmModal <HoppSmartConfirmModal
:show="confirmingCloseForTabID !== null" :show="confirmingCloseForTabID !== null"
:confirm="t('modal.close_unsaved_tab')" :confirm="t('modal.close_unsaved_tab')"
@@ -69,15 +79,16 @@
@resolve="onResolveConfirmSaveTab" @resolve="onResolveConfirmSaveTab"
/> />
<CollectionsSaveRequest <CollectionsSaveRequest
v-if="savingRequest"
mode="rest"
:show="savingRequest" :show="savingRequest"
:mode="'rest'"
@hide-modal="onSaveModalClose" @hide-modal="onSaveModalClose"
/> />
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, onMounted, onBeforeUnmount, watch, onBeforeMount } from "vue" import { ref, onMounted, onBeforeUnmount, onBeforeMount } from "vue"
import { safelyExtractRESTRequest } from "@hoppscotch/data" import { safelyExtractRESTRequest } from "@hoppscotch/data"
import { translateExtURLParams } from "~/helpers/RESTExtURLParams" import { translateExtURLParams } from "~/helpers/RESTExtURLParams"
import { useRoute } from "vue-router" import { useRoute } from "vue-router"
@@ -113,16 +124,26 @@ import { useToast } from "~/composables/toast"
import { PersistableRESTTabState } from "~/helpers/rest/tab" import { PersistableRESTTabState } from "~/helpers/rest/tab"
import { watchDebounced } from "@vueuse/core" import { watchDebounced } from "@vueuse/core"
import { oauthRedirect } from "~/helpers/oauth" import { oauthRedirect } from "~/helpers/oauth"
import { useReadonlyStream } from "~/composables/stream"
import {
changeCurrentSyncStatus,
currentSyncingStatus$,
} from "~/newstore/syncing"
const savingRequest = ref(false) const savingRequest = ref(false)
const confirmingCloseForTabID = ref<string | null>(null) const confirmingCloseForTabID = ref<string | null>(null)
const showRenamingReqNameModal = ref(false)
const reqName = ref<string>("")
const t = useI18n() const t = useI18n()
const toast = useToast() const toast = useToast()
const tabs = getActiveTabs() const tabs = getActiveTabs()
const confirmSync = ref(false) const confirmSync = useReadonlyStream(currentSyncingStatus$, {
isInitialSync: false,
shouldSync: true,
})
const tabStateForSync = ref<PersistableRESTTabState | null>(null) const tabStateForSync = ref<PersistableRESTTabState | null>(null)
function bindRequestToURLParams() { function bindRequestToURLParams() {
@@ -133,8 +154,11 @@ function bindRequestToURLParams() {
// If query params are empty, or contains code or error param (these are from Oauth Redirect) // If query params are empty, or contains code or error param (these are from Oauth Redirect)
// We skip URL params parsing // We skip URL params parsing
if (Object.keys(query).length === 0 || query.code || query.error) return if (Object.keys(query).length === 0 || query.code || query.error) return
const request = currentActiveTab.value.document.request
currentActiveTab.value.document.request = safelyExtractRESTRequest( currentActiveTab.value.document.request = safelyExtractRESTRequest(
translateExtURLParams(query), translateExtURLParams(query, request),
getDefaultRESTRequest() getDefaultRESTRequest()
) )
}) })
@@ -166,6 +190,20 @@ const removeTab = (tabID: string) => {
} }
} }
const openReqRenameModal = () => {
showRenamingReqNameModal.value = true
reqName.value = currentActiveTab.value.document.request.name
}
const renameReqName = () => {
const tab = getTabRef(currentTabID.value)
if (tab.value) {
tab.value.document.request.name = reqName.value
updateTab(tab.value)
}
showRenamingReqNameModal.value = false
}
/** /**
* This function is closed when the confirm tab is closed by some means (even saving triggers close) * This function is closed when the confirm tab is closed by some means (even saving triggers close)
*/ */
@@ -203,29 +241,6 @@ const onSaveModalClose = () => {
} }
} }
watch(confirmSync, (newValue) => {
if (newValue) {
toast.show(t("confirm.sync"), {
duration: 0,
action: [
{
text: `${t("action.yes")}`,
onClick: (_, toastObject) => {
syncTabState()
toastObject.goAway(0)
},
},
{
text: `${t("action.no")}`,
onClick: (_, toastObject) => {
toastObject.goAway(0)
},
},
],
})
}
})
const syncTabState = () => { const syncTabState = () => {
if (tabStateForSync.value) loadTabsFromPersistedState(tabStateForSync.value) if (tabStateForSync.value) loadTabsFromPersistedState(tabStateForSync.value)
} }
@@ -264,6 +279,35 @@ function startTabStateSync(): Subscription {
return sub return sub
} }
const showSyncToast = () => {
toast.show(t("confirm.sync"), {
duration: 0,
action: [
{
text: `${t("action.yes")}`,
onClick: (_, toastObject) => {
syncTabState()
changeCurrentSyncStatus({
isInitialSync: true,
shouldSync: true,
})
toastObject.goAway(0)
},
},
{
text: `${t("action.no")}`,
onClick: (_, toastObject) => {
changeCurrentSyncStatus({
isInitialSync: true,
shouldSync: false,
})
toastObject.goAway(0)
},
},
],
})
}
function setupTabStateSync() { function setupTabStateSync() {
const route = useRoute() const route = useRoute()
@@ -279,9 +323,15 @@ function setupTabStateSync() {
const tabStateFromSync = const tabStateFromSync =
await platform.sync.tabState.loadTabStateFromSync() await platform.sync.tabState.loadTabStateFromSync()
if (tabStateFromSync) { if (tabStateFromSync && !confirmSync.value.isInitialSync) {
tabStateForSync.value = tabStateFromSync tabStateForSync.value = tabStateFromSync
confirmSync.value = true showSyncToast()
// Have to set isInitialSync to true here because the toast is shown
// and the user does not click on any of the actions
changeCurrentSyncStatus({
isInitialSync: true,
shouldSync: false,
})
} }
} }

View File

@@ -34,7 +34,7 @@
></div> ></div>
<div class="flex flex-col justify-between px-4 space-y-8 md:flex-row"> <div class="flex flex-col justify-between px-4 space-y-8 md:flex-row">
<div class="flex items-end"> <div class="flex items-end">
<ProfilePicture <HoppSmartPicture
v-if="currentUser.photoURL" v-if="currentUser.photoURL"
:url="currentUser.photoURL" :url="currentUser.photoURL"
:alt=" :alt="
@@ -44,7 +44,7 @@
size="16" size="16"
rounded="lg" rounded="lg"
/> />
<ProfilePicture <HoppSmartPicture
v-else v-else
:initial="currentUser.displayName || currentUser.email" :initial="currentUser.displayName || currentUser.email"
rounded="lg" rounded="lg"

View File

@@ -11,6 +11,14 @@
<p class="mt-2 text-center"> <p class="mt-2 text-center">
{{ t("error.invalid_link_description") }} {{ t("error.invalid_link_description") }}
</p> </p>
<p class="mt-4">
<HoppButtonSecondary
to="/"
:icon="IconHome"
filled
:label="t('app.home')"
/>
</p>
</div> </div>
<div v-else class="flex flex-col items-center justify-center flex-1 p-4"> <div v-else class="flex flex-col items-center justify-center flex-1 p-4">
<div <div
@@ -107,6 +115,11 @@ const addRequestToTab = () => {
const data = shortcodeDetails.data const data = shortcodeDetails.data
if (E.isRight(data)) { if (E.isRight(data)) {
if (!data.right.shortcode?.request) {
invalidLink.value = true
return
}
const request: unknown = JSON.parse(data.right.shortcode?.request as string) const request: unknown = JSON.parse(data.right.shortcode?.request as string)
createNewTab({ createNewTab({

Some files were not shown because too many files have changed in this diff Show More