Compare commits

..

6 Commits

Author SHA1 Message Date
Mir Arif Hasan
aab52a1fdb fix: url of the magic link 2023-05-09 15:55:30 +05:30
Mir Arif Hasan
00fcc78f85 fix: returning response from authCookieHandler (#3025) 2023-05-09 15:55:01 +05:30
Anwarul Islam
81e090bbba feat: picture component moved to hoppscotch-ui (#3032) 2023-05-09 00:32:54 +05:30
Anwarul Islam
87ba02053b 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-09 00:30:27 +05:30
Akash K
fb08147c66 fix: update the hoppscotch-sh-admin magic link route to match hoppscotch-app (#3029) 2023-05-03 23:12:50 +05:30
Nivedin
d129676cd6 fix: pane layout broken when wrap line is off (#3027)
Co-authored-by: Liyas Thomas <liyascthomas@gmail.com>
2023-05-03 20:39:22 +05:30
129 changed files with 1062 additions and 2856 deletions

View File

@@ -31,7 +31,6 @@ MICROSOFT_CLIENT_ID="************************************************"
MICROSOFT_CLIENT_SECRET="************************************************"
MICROSOFT_CALLBACK_URL="http://localhost:3170/v1/auth/microsoft/callback"
MICROSOFT_SCOPE="user.read"
MICROSOFT_TENANT="common"
# Mailer config
MAILER_SMTP_URL="smtps://user@domain.com:pass@smtp.domain.com"
@@ -52,7 +51,7 @@ VITE_ADMIN_URL=http://localhost:3100
# Backend URLs
VITE_BACKEND_GQL_URL=http://localhost:3170/graphql
VITE_BACKEND_WS_URL=ws://localhost:3170/graphql
VITE_BACKEND_WS_URL=wss://localhost:3170/graphql
VITE_BACKEND_API_URL=http://localhost:3170/v1
# Terms Of Service And Privacy Policy Links (Optional)

View File

@@ -1,42 +0,0 @@
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",
"gen-gql": "cross-env GQL_SCHEMA_EMIT_LOCATION='../../../gql-gen/backend-schema.gql' pnpm -r generate-gql-sdl",
"generate": "pnpm -r do-build-prod",
"start": "http-server packages/hoppscotch-selfhost-web/dist -p 3000",
"start": "http-server packages/hoppscotch-web/dist -p 3000",
"lint": "pnpm -r do-lint",
"typecheck": "pnpm -r do-typecheck",
"lintfix": "pnpm -r do-lintfix",

View File

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

View File

@@ -236,11 +236,11 @@ export class AdminService {
const user = await this.userService.findUserByEmail(userEmail);
if (O.isNone(user)) return E.left(USER_NOT_FOUND);
const teamMember = await this.teamService.getTeamMemberTE(
const isUserAlreadyMember = await this.teamService.getTeamMemberTE(
teamID,
user.value.uid,
)();
if (E.isLeft(teamMember)) {
if (E.left(isUserAlreadyMember)) {
const addedUser = await this.teamService.addMemberToTeamWithEmail(
teamID,
userEmail,
@@ -248,18 +248,6 @@ export class AdminService {
);
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);
}

View File

@@ -17,7 +17,7 @@ export class MicrosoftStrategy extends PassportStrategy(Strategy) {
clientSecret: process.env.MICROSOFT_CLIENT_SECRET,
callbackURL: process.env.MICROSOFT_CALLBACK_URL,
scope: [process.env.MICROSOFT_SCOPE],
tenant: process.env.MICROSOFT_TENANT,
passReqToCallback: true,
store: true,
});
}

View File

@@ -23,7 +23,7 @@ export const AUTH_FAIL = 'auth/fail';
export const JSON_INVALID = 'json_invalid';
/**
* Tried to delete a user data document from fb firestore but failed.
* Tried to delete an user data document from fb firestore but failed.
* (FirebaseService)
*/
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;
/**
* Tried to perform an action on a request that doesn't accept their member role level
* Tried to perform action on a request that doesn't accept their member role level
* (GqlRequestTeamMemberGuard)
*/
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;
/**
* Tried to perform an action on a request when the user is not even a member of the team
* Tried to perform action on a request when the user is not even member of the team
* (GqlRequestTeamMemberGuard, GqlCollectionTeamMemberGuard)
*/
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;
/**
* Invalid or non-existent TEAM ENVIRONMENT ID
* Invalid or non-existent TEAM ENVIRONMMENT ID
* (TeamEnvironmentsService)
*/
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;
/*
* Global environment doesn't exist for the user
* Global environment doesnt exists for the user
* (UserEnvironmentsService)
*/
export const USER_ENVIRONMENT_GLOBAL_ENV_DOES_NOT_EXISTS =

View File

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

View File

@@ -3,7 +3,6 @@ import * as T from 'fp-ts/Task';
import * as O from 'fp-ts/Option';
import * as TO from 'fp-ts/TaskOption';
import * as TE from 'fp-ts/TaskEither';
import * as E from 'fp-ts/Either';
import { pipe, flow, constVoid } from 'fp-ts/function';
import { PrismaService } from 'src/prisma/prisma.service';
import { Team, TeamMemberRole } from 'src/team/team.model';
@@ -11,7 +10,6 @@ import { Email } from 'src/types/Email';
import { User } from 'src/user/user.model';
import { TeamService } from 'src/team/team.service';
import {
INVALID_EMAIL,
TEAM_INVITE_ALREADY_MEMBER,
TEAM_INVITE_EMAIL_DO_NOT_MATCH,
TEAM_INVITE_MEMBER_HAS_INVITE,
@@ -21,7 +19,6 @@ import { TeamInvitation } from './team-invitation.model';
import { MailerService } from 'src/mailer/mailer.service';
import { UserService } from 'src/user/user.service';
import { PubSubService } from 'src/pubsub/pubsub.service';
import { validateEmail } from '../utils';
@Injectable()
export class TeamInvitationService {
@@ -66,32 +63,6 @@ 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(
creator: User,
team: Team,
@@ -155,7 +126,7 @@ export class TeamInvitationService {
template: 'team-invitation',
variables: {
invitee: creator.displayName ?? 'A Hoppscotch User',
action_url: `${process.env.VITE_BASE_URL}/join-team?id=${invitation.id}`,
action_url: `https://hoppscotch.io/join-team?id=${invitation.id}`,
invite_team_name: team.name,
},
}),

View File

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

View File

@@ -33,7 +33,7 @@ export class TeamInviteeGuard implements CanActivate {
// Get user
TE.bindW('user', ({ gqlCtx }) =>
pipe(
O.fromNullable(gqlCtx.getContext().req.user),
O.fromNullable(gqlCtx.getContext<{ user?: User }>().user),
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
** Since its REST we need to return the HTTP status code along with the error message
** Since its REST we need to return HTTP status code along with error message
*/
export type AuthError = {
message: string;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -122,7 +122,7 @@
"edit": "Koleksiyonu düzenle",
"invalid_name": "Lütfen koleksiyon için geçerli bir ad girin",
"invalid_root_move": "Collection already in the root",
"moved": "Başarıyla taşındı",
"moved": "Moved Successfully",
"my_collections": "Koleksiyonlarım",
"name": "Yeni Koleksiyonum",
"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_telemetry": "Telemetriden çıkmak istediğinizden emin misiniz?",
"request_change": "Are you sure you want to discard current request, unsaved changes will be lost.",
"save_unsaved_tab": "Bu sekmede yapılan değişiklikleri kaydetmek istiyor musunuz?",
"save_unsaved_tab": "Do you want to save changes made in this tab?",
"sync": "Bu çalışma alanını senkronize etmek istediğinizden emin misiniz?"
},
"count": {
@@ -368,9 +368,9 @@
},
"profile": {
"app_settings": "Uygulama ayarları",
"default_hopp_displayname": "Adsız Kullanıcı",
"editor": "Editör",
"editor_description": "Editörler istekleri ekleyebilir, düzenleyebilir ve silebilir.",
"default_hopp_displayname": "Unnamed User",
"editor": "Düzenleyici",
"editor_description": "Editors can add, edit, and delete requests.",
"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.",
"owner": "Kurucu",
@@ -432,7 +432,6 @@
"view_my_links": "View my links"
},
"response": {
"audio": "Audio",
"body": "Yanıt gövdesi",
"filter_response_body": "Filter JSON response body (uses JSONPath syntax)",
"headers": "Başlıklar",
@@ -446,7 +445,6 @@
"status": "Durum",
"time": "Zaman",
"title": "Cevap",
"video": "Video",
"waiting_for_connection": "Bağlantı için bekleniyor",
"xml": "XML"
},

View File

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

View File

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

View File

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

View File

@@ -8,9 +8,7 @@ export const APP_INFO = {
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",
app: {
background: "#181818",
lightThemeColor: "#ffffff",
darkThemeColor: "#181818",
background: "#202124",
},
social: {
twitter: "@hoppscotch_io",
@@ -110,17 +108,7 @@ export const META_TAGS = (env: Record<string, string>): IHTMLTag[] => [
// PWA
{
name: "theme-color",
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",
content: APP_INFO.app.background,
},
{
name: "mask-icon",

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 666 KiB

After

Width:  |  Height:  |  Size: 595 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 400 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 871 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 358 KiB

After

Width:  |  Height:  |  Size: 331 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 382 KiB

After

Width:  |  Height:  |  Size: 352 KiB

View File

@@ -57,7 +57,6 @@ declare module '@vue/runtime-core' {
EnvironmentsMy: typeof import('./components/environments/my/index.vue')['default']
EnvironmentsMyDetails: typeof import('./components/environments/my/Details.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']
EnvironmentsTeamsDetails: typeof import('./components/environments/teams/Details.vue')['default']
EnvironmentsTeamsEnvironment: typeof import('./components/environments/teams/Environment.vue')['default']
@@ -86,7 +85,6 @@ declare module '@vue/runtime-core' {
HoppSmartLink: typeof import('@hoppscotch/ui')['HoppSmartLink']
HoppSmartModal: typeof import('@hoppscotch/ui')['HoppSmartModal']
HoppSmartPicture: typeof import('@hoppscotch/ui')['HoppSmartPicture']
HoppSmartPlaceholder: typeof import('@hoppscotch/ui')['HoppSmartPlaceholder']
HoppSmartProgressRing: typeof import('@hoppscotch/ui')['HoppSmartProgressRing']
HoppSmartRadioGroup: typeof import('@hoppscotch/ui')['HoppSmartRadioGroup']
HoppSmartSlideOver: typeof import('@hoppscotch/ui')['HoppSmartSlideOver']
@@ -132,18 +130,18 @@ declare module '@vue/runtime-core' {
IconLucideListEnd: typeof import('~icons/lucide/list-end')['default']
IconLucideMinus: typeof import('~icons/lucide/minus')['default']
IconLucideSearch: typeof import('~icons/lucide/search')['default']
IconLucideUser: typeof import('~icons/lucide/user')['default']
IconLucideUsers: typeof import('~icons/lucide/users')['default']
LensesHeadersRenderer: typeof import('./components/lenses/HeadersRenderer.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']
LensesRenderersImageLensRenderer: typeof import('./components/lenses/renderers/ImageLensRenderer.vue')['default']
LensesRenderersJSONLensRenderer: typeof import('./components/lenses/renderers/JSONLensRenderer.vue')['default']
LensesRenderersPDFLensRenderer: typeof import('./components/lenses/renderers/PDFLensRenderer.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']
LensesResponseBodyRenderer: typeof import('./components/lenses/ResponseBodyRenderer.vue')['default']
ProfilePicture: typeof import('./components/profile/Picture.vue')['default']
ProfileShortcode: typeof import('./components/profile/Shortcode.vue')['default']
ProfileShortcodes: typeof import('./components/profile/Shortcodes.vue')['default']
ProfileUserDelete: typeof import('./components/profile/UserDelete.vue')['default']

View File

@@ -44,9 +44,8 @@
class="flex flex-col items-center justify-center p-4 text-secondaryLight"
>
<icon-lucide-search class="pb-2 opacity-75 svg-icons" />
<span class="my-2 text-center flex flex-col">
{{ t("state.nothing_found") }}
<span class="break-all">"{{ filterText }}"</span>
<span class="my-2 text-center">
{{ t("state.nothing_found") }} "{{ filterText }}"
</span>
</div>
</div>

View File

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

View File

@@ -284,14 +284,6 @@ const importerAction = async (stepResults: StepReturnValue[]) => {
emit("import-to-teams", result)
} else {
appendRESTCollections(result)
platform.analytics?.logEvent({
type: "HOPP_IMPORT_COLLECTION",
importer: importerModule.value!.name,
platform: "rest",
workspaceType: "personal",
})
fileImported()
}
}

View File

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

View File

@@ -89,7 +89,6 @@ import {
import { GQLError } from "~/helpers/backend/GQLClient"
import { computedWithControl } from "@vueuse/core"
import { currentActiveTab } from "~/helpers/rest/tab"
import { platform } from "~/platform"
const t = useI18n()
const toast = useToast()
@@ -137,11 +136,11 @@ const requestName = ref(
)
watch(
() => [currentActiveTab.value, gqlRequestName.value],
() => [currentActiveTab.value.document.request.name, gqlRequestName.value],
() => {
if (props.mode === "rest") {
requestName.value = currentActiveTab.value?.document.request.name ?? ""
} else requestName.value = gqlRequestName.value
if (props.mode === "rest")
requestName.value = currentActiveTab.value.document.request.name
else requestName.value = gqlRequestName.value
}
)
@@ -224,13 +223,6 @@ const saveRequestAs = async () => {
},
}
platform.analytics?.logEvent({
type: "HOPP_SAVE_REQUEST",
createdNow: true,
platform: "rest",
workspaceType: "personal",
})
requestSaved()
} else if (picked.value.pickedType === "my-folder") {
if (!isHoppRESTRequest(requestUpdated))
@@ -251,13 +243,6 @@ const saveRequestAs = async () => {
},
}
platform.analytics?.logEvent({
type: "HOPP_SAVE_REQUEST",
createdNow: true,
platform: "rest",
workspaceType: "personal",
})
requestSaved()
} else if (picked.value.pickedType === "my-request") {
if (!isHoppRESTRequest(requestUpdated))
@@ -279,38 +264,17 @@ const saveRequestAs = async () => {
},
}
platform.analytics?.logEvent({
type: "HOPP_SAVE_REQUEST",
createdNow: false,
platform: "rest",
workspaceType: "personal",
})
requestSaved()
} else if (picked.value.pickedType === "teams-collection") {
if (!isHoppRESTRequest(requestUpdated))
throw new Error("requestUpdated is not a REST Request")
updateTeamCollectionOrFolder(picked.value.collectionID, requestUpdated)
platform.analytics?.logEvent({
type: "HOPP_SAVE_REQUEST",
createdNow: true,
platform: "rest",
workspaceType: "team",
})
} else if (picked.value.pickedType === "teams-folder") {
if (!isHoppRESTRequest(requestUpdated))
throw new Error("requestUpdated is not a REST Request")
updateTeamCollectionOrFolder(picked.value.folderID, requestUpdated)
platform.analytics?.logEvent({
type: "HOPP_SAVE_REQUEST",
createdNow: true,
platform: "rest",
workspaceType: "team",
})
} else if (picked.value.pickedType === "teams-request") {
if (!isHoppRESTRequest(requestUpdated))
throw new Error("requestUpdated is not a REST Request")
@@ -328,13 +292,6 @@ const saveRequestAs = async () => {
title: requestUpdated.name,
}
platform.analytics?.logEvent({
type: "HOPP_SAVE_REQUEST",
createdNow: false,
platform: "rest",
workspaceType: "team",
})
pipe(
updateTeamRequest(picked.value.requestID, data),
TE.match(
@@ -356,13 +313,6 @@ const saveRequestAs = async () => {
requestUpdated as HoppGQLRequest
)
platform.analytics?.logEvent({
type: "HOPP_SAVE_REQUEST",
createdNow: false,
platform: "gql",
workspaceType: "team",
})
requestSaved()
} else if (picked.value.pickedType === "gql-my-folder") {
// TODO: Check for GQL request ?
@@ -371,13 +321,6 @@ const saveRequestAs = async () => {
requestUpdated as HoppGQLRequest
)
platform.analytics?.logEvent({
type: "HOPP_SAVE_REQUEST",
createdNow: true,
platform: "gql",
workspaceType: "team",
})
requestSaved()
} else if (picked.value.pickedType === "gql-my-collection") {
// TODO: Check for GQL request ?
@@ -386,13 +329,6 @@ const saveRequestAs = async () => {
requestUpdated as HoppGQLRequest
)
platform.analytics?.logEvent({
type: "HOPP_SAVE_REQUEST",
createdNow: true,
platform: "gql",
workspaceType: "team",
})
requestSaved()
}
}

View File

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

View File

@@ -46,7 +46,6 @@ import { useToast } from "@composables/toast"
import { useI18n } from "@composables/i18n"
import { HoppGQLRequest, makeCollection } from "@hoppscotch/data"
import { addGraphqlCollection } from "~/newstore/collections"
import { platform } from "~/platform"
export default defineComponent({
props: {
@@ -80,13 +79,6 @@ export default defineComponent({
)
this.hideModal()
platform.analytics?.logEvent({
type: "HOPP_CREATE_COLLECTION",
isRootCollection: true,
platform: "gql",
workspaceType: "personal",
})
},
hideModal() {
this.name = null

View File

@@ -244,14 +244,6 @@ const importFromJSON = () => {
return
}
appendGraphqlCollections(collections)
platform.analytics?.logEvent({
type: "HOPP_IMPORT_COLLECTION",
importer: "json",
workspaceType: "personal",
platform: "gql",
})
fileImported()
}
reader.readAsText(inputChooseFileToImportFrom.value.files[0])
@@ -265,12 +257,6 @@ const exportJSON = () => {
const url = URL.createObjectURL(file)
a.href = url
platform?.analytics?.logEvent({
type: "HOPP_EXPORT_COLLECTION",
exporter: "json",
platform: "gql",
})
// TODO: get uri from meta
a.download = `${url.split("/").pop()!.split("#")[0].split("?")[0]}.json`
document.body.appendChild(a)

View File

@@ -153,7 +153,6 @@ import IconArchive from "~icons/lucide/archive"
import { useI18n } from "@composables/i18n"
import { useReadonlyStream } from "@composables/stream"
import { useColorMode } from "@composables/theming"
import { platform } from "~/platform"
export default defineComponent({
props: {
@@ -286,13 +285,6 @@ export default defineComponent({
response: "",
})
platform.analytics?.logEvent({
type: "HOPP_SAVE_REQUEST",
platform: "gql",
createdNow: true,
workspaceType: "personal",
})
this.displayModalAddRequest(false)
},
addRequest(payload) {
@@ -302,14 +294,6 @@ export default defineComponent({
},
onAddFolder({ name, path }) {
addGraphqlFolder(name, path)
platform.analytics?.logEvent({
type: "HOPP_CREATE_COLLECTION",
isRootCollection: false,
platform: "gql",
workspaceType: "personal",
})
this.displayModalAddFolder(false)
},
addFolder(payload) {

View File

@@ -125,8 +125,8 @@
@hide-modal="displayModalEditFolder(false)"
/>
<CollectionsEditRequest
v-model="editingRequestName"
:show="showModalEditRequest"
:editing-request-name="editingRequest ? editingRequest.name : ''"
:loading-state="modalLoadingState"
@submit="updateEditingRequest"
@hide-modal="displayModalEditRequest(false)"
@@ -157,7 +157,7 @@
</template>
<script setup lang="ts">
import { computed, nextTick, PropType, ref, watch } from "vue"
import { computed, PropType, ref, watch } from "vue"
import { useToast } from "@composables/toast"
import { useI18n } from "@composables/i18n"
import { Picked } from "~/helpers/types/HoppPicked"
@@ -288,7 +288,6 @@ const editingFolder = ref<
const editingFolderName = ref<string | null>(null)
const editingFolderPath = ref<string | null>(null)
const editingRequest = ref<HoppRESTRequest | null>(null)
const editingRequestName = ref("")
const editingRequestIndex = ref<number | null>(null)
const editingRequestID = ref<string | null>(null)
@@ -599,25 +598,11 @@ const addNewRootCollection = (name: string) => {
})
)
platform.analytics?.logEvent({
type: "HOPP_CREATE_COLLECTION",
platform: "rest",
workspaceType: "personal",
isRootCollection: true,
})
displayModalAdd(false)
} else if (hasTeamWriteAccess.value) {
if (!collectionsType.value.selectedTeam) return
modalLoadingState.value = true
platform.analytics?.logEvent({
type: "HOPP_CREATE_COLLECTION",
platform: "rest",
workspaceType: "team",
isRootCollection: true,
})
pipe(
createNewRootCollection(name, collectionsType.value.selectedTeam.id),
TE.match(
@@ -666,13 +651,6 @@ const onAddRequest = (requestName: string) => {
},
})
platform.analytics?.logEvent({
type: "HOPP_SAVE_REQUEST",
workspaceType: "personal",
createdNow: true,
platform: "rest",
})
displayModalAddRequest(false)
} else if (hasTeamWriteAccess.value) {
const folder = editingFolder.value
@@ -688,13 +666,6 @@ const onAddRequest = (requestName: string) => {
title: requestName,
}
platform.analytics?.logEvent({
type: "HOPP_SAVE_REQUEST",
workspaceType: "team",
platform: "rest",
createdNow: true,
})
pipe(
createRequestInCollection(folder.id, data),
TE.match(
@@ -740,14 +711,6 @@ const onAddFolder = (folderName: string) => {
if (collectionsType.value.type === "my-collections") {
if (!path) return
addRESTFolder(folderName, path)
platform.analytics?.logEvent({
type: "HOPP_CREATE_COLLECTION",
workspaceType: "personal",
isRootCollection: false,
platform: "rest",
})
displayModalAddFolder(false)
} else if (hasTeamWriteAccess.value) {
const folder = editingFolder.value
@@ -755,13 +718,6 @@ const onAddFolder = (folderName: string) => {
modalLoadingState.value = true
platform.analytics?.logEvent({
type: "HOPP_CREATE_COLLECTION",
workspaceType: "personal",
isRootCollection: false,
platform: "rest",
})
pipe(
createChildCollection(folderName, folder.id),
TE.match(
@@ -904,7 +860,6 @@ const editRequest = (payload: {
}) => {
const { folderPath, requestIndex, request } = payload
editingRequest.value = request
editingRequestName.value = request.name ?? ""
if (collectionsType.value.type === "my-collections" && folderPath) {
editingFolderPath.value = folderPath
editingRequestIndex.value = parseInt(requestIndex)
@@ -938,9 +893,6 @@ const updateEditingRequest = (newName: string) => {
if (possibleActiveTab) {
possibleActiveTab.value.document.request.name = requestUpdated.name
nextTick(() => {
possibleActiveTab.value.document.isDirty = false
})
}
displayModalEditRequest(false)
@@ -979,9 +931,6 @@ const updateEditingRequest = (newName: string) => {
if (possibleTab) {
possibleTab.value.document.request.name = requestName
nextTick(() => {
possibleTab.value.document.isDirty = false
})
}
}
}
@@ -1927,12 +1876,6 @@ const exportData = async (
}
const exportJSONCollection = async () => {
platform.analytics?.logEvent({
type: "HOPP_EXPORT_COLLECTION",
exporter: "json",
platform: "rest",
})
await getJSONCollection()
initializeDownloadCollection(collectionJSON.value, null)
@@ -1944,12 +1887,6 @@ const createCollectionGist = async () => {
return
}
platform.analytics?.logEvent({
type: "HOPP_EXPORT_COLLECTION",
exporter: "gist",
platform: "rest",
})
creatingGistCollection.value = true
await getJSONCollection()
@@ -1980,12 +1917,6 @@ const importToTeams = async (collection: HoppCollection<HoppRESTRequest>[]) => {
importingMyCollections.value = true
platform.analytics?.logEvent({
type: "HOPP_EXPORT_COLLECTION",
exporter: "import-to-teams",
platform: "rest",
})
pipe(
importJSONToTeam(
JSON.stringify(collection),

View File

@@ -190,12 +190,6 @@ const createEnvironmentGist = async () => {
)
toast.success(t("export.gist_created").toString())
platform.analytics?.logEvent({
type: "HOPP_EXPORT_ENVIRONMENT",
platform: "rest",
})
window.open(res.data.html_url)
} catch (e) {
toast.error(t("error.something_went_wrong").toString())
@@ -255,13 +249,6 @@ const openDialogChooseFileToImportFrom = () => {
const importToTeams = async (content: Environment[]) => {
loading.value = true
platform.analytics?.logEvent({
type: "HOPP_IMPORT_ENVIRONMENT",
platform: "rest",
workspaceType: "team",
})
for (const [i, env] of content.entries()) {
if (i === content.length - 1) {
await pipe(
@@ -314,12 +301,6 @@ const importFromJSON = () => {
return
}
platform.analytics?.logEvent({
type: "HOPP_IMPORT_ENVIRONMENT",
platform: "rest",
workspaceType: "personal",
})
const reader = new FileReader()
reader.onload = ({ target }) => {
@@ -371,7 +352,6 @@ const importFromPostman = ({
const environment: Environment = { name, variables: [] }
values.forEach(({ key, value }) => environment.variables.push({ key, value }))
const environments = [environment]
importFromHoppscotch(environments)
}

View File

@@ -1,295 +0,0 @@
<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,6 +4,153 @@
class="sticky top-0 z-10 flex flex-col flex-shrink-0 overflow-x-auto bg-primary"
>
<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
environment-index="Global"
:environment="globalEnvironment"
@@ -37,11 +184,15 @@ import { GetMyTeamsQuery } from "~/helpers/backend/graphql"
import { useReadonlyStream, useStream } from "@composables/stream"
import { useI18n } from "~/composables/i18n"
import {
environments$,
globalEnv$,
selectedEnvironmentIndex$,
setSelectedEnvironmentIndex,
} from "~/newstore/environments"
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 { workspaceStatus$ } from "~/newstore/workspace"
import TeamListAdapter from "~/helpers/teams/TeamListAdapter"
@@ -110,7 +261,7 @@ const switchToMyEnvironments = () => {
adapter.changeTeamID(undefined)
}
const updateSelectedTeam = (newSelectedTeam: SelectedTeam | undefined) => {
const updateSelectedTeam = (newSelectedTeam: SelectedTeam) => {
if (newSelectedTeam) {
environmentType.value.selectedTeam = newSelectedTeam
REMEMBERED_TEAM_ID.value = newSelectedTeam.id
@@ -136,21 +287,22 @@ onLoggedIn(() => {
const workspace = useReadonlyStream(workspaceStatus$, { type: "personal" })
// Switch to my environments if workspace is personal and to team environments if workspace is team
// also resets selected environment if workspace is personal and the previous selected environment was a team environment
watch(workspace, (newWorkspace) => {
if (newWorkspace.type === "personal") {
switchToMyEnvironments()
if (selectedEnvironmentIndex.value.type !== "MY_ENV") {
setSelectedEnvironmentIndex({
type: "NO_ENV_SELECTED",
})
// Used to switch environment type and team when user switch workspace in the global workspace switcher
// Check if there is a teamID in the workspace, if yes, switch to team environment and select the team
// If there is no teamID, switch to my environment
watch(
() => workspace.value.teamID,
(teamID) => {
if (!teamID) {
switchToMyEnvironments()
} 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(
() => currentUser.value,
@@ -191,6 +343,8 @@ defineActionHandler(
}
)
const myEnvironments = useReadonlyStream(environments$, [])
const selectedEnvironmentIndex = useStream(
selectedEnvironmentIndex$,
{ type: "NO_ENV_SELECTED" },
@@ -233,4 +387,47 @@ watch(
},
{ 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>

View File

@@ -148,7 +148,6 @@ import { useToast } from "@composables/toast"
import { useReadonlyStream } from "@composables/stream"
import { useColorMode } from "@composables/theming"
import { environmentsStore } from "~/newstore/environments"
import { platform } from "~/platform"
type EnvironmentVariable = {
id: number
@@ -166,8 +165,8 @@ const props = withDefaults(
defineProps<{
show: boolean
action: "edit" | "new"
editingEnvironmentIndex?: number | "Global" | null
editingVariableName?: string | null
editingEnvironmentIndex: number | "Global" | null
editingVariableName: string | null
envVars?: () => Environment["variables"]
}>(),
{
@@ -312,11 +311,6 @@ const saveEnvironment = () => {
index: envList.value.length - 1,
})
toast.success(`${t("environment.created")}`)
platform.analytics?.logEvent({
type: "HOPP_CREATE_ENVIRONMENT",
workspaceType: "personal",
})
} else if (props.editingEnvironmentIndex === "Global") {
// Editing the Global environment
setGlobalEnvVariables(environmentUpdated.variables)

View File

@@ -140,7 +140,7 @@ import * as A from "fp-ts/Array"
import * as O from "fp-ts/Option"
import * as TE from "fp-ts/TaskEither"
import { flow, pipe } from "fp-ts/function"
import { Environment, parseTemplateStringE } from "@hoppscotch/data"
import { parseTemplateStringE } from "@hoppscotch/data"
import { refAutoReset } from "@vueuse/core"
import { clone } from "lodash-es"
import { useToast } from "@composables/toast"
@@ -156,7 +156,6 @@ import IconTrash from "~icons/lucide/trash"
import IconTrash2 from "~icons/lucide/trash-2"
import IconDone from "~icons/lucide/check"
import IconPlus from "~icons/lucide/plus"
import { platform } from "~/platform"
type EnvironmentVariable = {
id: number
@@ -174,20 +173,16 @@ const props = withDefaults(
defineProps<{
show: boolean
action: "edit" | "new"
editingEnvironment?: TeamEnvironment | null
editingEnvironment: TeamEnvironment | null
editingTeamId: string | undefined
editingVariableName?: string | null
isViewer?: boolean
envVars?: () => Environment["variables"]
editingVariableName: string | null
isViewer: boolean
}>(),
{
show: false,
action: "edit",
editingEnvironment: null,
editingTeamId: "",
editingVariableName: null,
isViewer: false,
envVars: () => [],
}
)
@@ -231,16 +226,10 @@ watch(
() => props.show,
(show) => {
if (show) {
if (props.action === "new") {
if (props.editingEnvironment === null) {
name.value = null
vars.value = pipe(
props.envVars() ?? [],
A.map((e: { key: string; value: string }) => ({
id: idTicker.value++,
env: clone(e),
}))
)
} else if (props.editingEnvironment !== null) {
vars.value = []
} else {
name.value = props.editingEnvironment.environment.name ?? null
vars.value = pipe(
props.editingEnvironment.environment.variables ?? [],
@@ -295,11 +284,6 @@ const saveEnvironment = async () => {
)
if (props.action === "new") {
platform.analytics?.logEvent({
type: "HOPP_CREATE_ENVIRONMENT",
workspaceType: "team",
})
await pipe(
createTeamEnvironment(
JSON.stringify(filterdVariables),

View File

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

View File

@@ -143,51 +143,33 @@
<div class="flex flex-1 border-b border-dividerLight">
<SmartEnvInput
v-model="basicUsername"
:environment-highlights="false"
:placeholder="t('authorization.username')"
/>
</div>
<div class="flex flex-1 border-b border-dividerLight">
<SmartEnvInput
v-model="basicPassword"
:environment-highlights="false"
:placeholder="t('authorization.password')"
/>
</div>
</div>
<div v-if="authType === 'bearer'">
<div class="flex flex-1 border-b border-dividerLight">
<SmartEnvInput
v-model="bearerToken"
:environment-highlights="false"
placeholder="Token"
/>
<SmartEnvInput v-model="bearerToken" placeholder="Token" />
</div>
</div>
<div v-if="authType === 'oauth-2'">
<div class="flex flex-1 border-b border-dividerLight">
<SmartEnvInput
v-model="oauth2Token"
:environment-highlights="false"
placeholder="Token"
/>
<SmartEnvInput v-model="oauth2Token" placeholder="Token" />
</div>
<HttpOAuth2Authorization />
</div>
<div v-if="authType === 'api-key'">
<div class="flex flex-1 border-b border-dividerLight">
<SmartEnvInput
v-model="apiKey"
:environment-highlights="false"
placeholder="Key"
/>
<SmartEnvInput v-model="apiKey" placeholder="Key" />
</div>
<div class="flex flex-1 border-b border-dividerLight">
<SmartEnvInput
v-model="apiValue"
:environment-highlights="false"
placeholder="Value"
/>
<SmartEnvInput v-model="apiValue" placeholder="Value" />
</div>
<div class="flex items-center border-b border-dividerLight">
<span class="flex items-center">

View File

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

View File

@@ -748,8 +748,7 @@ const runQuery = async () => {
console.error(e)
}
platform.analytics?.logEvent({
type: "HOPP_REQUEST_RUN",
platform.analytics?.logHoppRequestRunToAnalytics({
platform: "graphql-query",
strategy: getCurrentStrategyID(),
})

View File

@@ -72,11 +72,9 @@
class="flex items-center justify-between flex-1 min-w-0 transition cursor-pointer focus:outline-none text-secondaryLight text-tiny group"
>
<span
class="inline-flex items-center justify-center px-4 py-2 transition group-hover:text-secondary truncate"
class="inline-flex items-center justify-center px-4 py-2 transition group-hover:text-secondary"
>
<icon-lucide-chevron-right
class="mr-2 indicator flex flex-shrink-0"
/>
<icon-lucide-chevron-right class="mr-2 indicator" />
<span
:class="[
{ 'capitalize-first': groupSelection === 'TIME' },

View File

@@ -165,7 +165,6 @@ import IconCheck from "~icons/lucide/check"
import IconWrapText from "~icons/lucide/wrap-text"
import { currentActiveTab } from "~/helpers/rest/tab"
import cloneDeep from "lodash-es/cloneDeep"
import { platform } from "~/platform"
const t = useI18n()
@@ -249,10 +248,6 @@ watch(
(goingToShow) => {
if (goingToShow) {
request.value = cloneDeep(currentActiveTab.value.document.request)
platform.analytics?.logEvent({
type: "HOPP_REST_CODEGEN_OPENED",
})
}
}
)

View File

@@ -338,7 +338,7 @@ watch(workingHeaders, (headersList) => {
// Sync logic between headers and working/bulk headers
watch(
() => request.value.headers,
request.value.headers,
(newHeadersList) => {
// Sync should overwrite working headers
const filteredWorkingHeaders = pipe(

View File

@@ -94,7 +94,6 @@ import IconClipboard from "~icons/lucide/clipboard"
import IconCheck from "~icons/lucide/check"
import IconTrash2 from "~icons/lucide/trash-2"
import { currentActiveTab } from "~/helpers/rest/tab"
import { platform } from "~/platform"
const t = useI18n()
@@ -145,10 +144,6 @@ const handleImport = () => {
try {
const req = parseCurlToHoppRESTReq(text)
platform.analytics?.logEvent({
type: "HOPP_REST_IMPORT_CURL",
})
currentActiveTab.value.document.request = req
} catch (e) {
console.error(e)

View File

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

View File

@@ -217,7 +217,6 @@
@hide-modal="showCodegenModal = false"
/>
<CollectionsSaveRequest
v-if="showSaveRequestModal"
mode="rest"
:show="showSaveRequestModal"
@hide-modal="showSaveRequestModal = false"
@@ -230,10 +229,11 @@ import { useI18n } from "@composables/i18n"
import { useSetting } from "@composables/settings"
import { useStreamSubscriber } from "@composables/stream"
import { useToast } from "@composables/toast"
import { completePageProgress, startPageProgress } from "@modules/loadingbar"
import { refAutoReset, useVModel } from "@vueuse/core"
import * as E from "fp-ts/Either"
import { isLeft, isRight } from "fp-ts/lib/Either"
import { computed, onBeforeUnmount, ref } from "vue"
import { computed, ref, watch } from "vue"
import { defineActionHandler } from "~/helpers/actions"
import { runMutation } from "~/helpers/backend/GQLClient"
import { UpdateRequestDocument } from "~/helpers/backend/graphql"
@@ -259,8 +259,6 @@ import IconSave from "~icons/lucide/save"
import IconShare2 from "~icons/lucide/share-2"
import { HoppRESTTab } from "~/helpers/rest/tab"
import { getDefaultRESTRequest } from "~/helpers/rest/default"
import { platform } from "~/platform"
import { getCurrentStrategyID } from "~/helpers/network"
const t = useI18n()
@@ -313,6 +311,39 @@ const clearAll = ref<any | null>(null)
const copyRequestAction = 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 () => {
if (newEndpoint.value === "" || /^\s+$/.test(newEndpoint.value)) {
toast.error(`${t("empty.endpoint")}`)
@@ -323,13 +354,6 @@ const newSendRequest = async () => {
loading.value = true
// Log the request run into analytics
platform.analytics?.logEvent({
type: "HOPP_REQUEST_RUN",
platform: "rest",
strategy: getCurrentStrategyID(),
})
// Double calling is because the function returns a TaskEither than should be executed
const streamResult = await runRESTRequest$(tab)()
@@ -447,11 +471,6 @@ const copyRequest = async () => {
shareLink.value = ""
fetchingShareLink.value = true
const shortcodeResult = await createShortcode(tab.value.document.request)()
platform.analytics?.logEvent({
type: "HOPP_SHORTCODE_CREATED",
})
if (E.isLeft(shortcodeResult)) {
toast.error(`${shortcodeResult.left.error}`)
shareLink.value = `${t("error.something_went_wrong")}`
@@ -522,14 +541,6 @@ const saveRequest = () => {
editRESTRequest(saveCtx.folderPath, saveCtx.requestIndex, req)
tab.value.document.isDirty = false
platform.analytics?.logEvent({
type: "HOPP_SAVE_REQUEST",
platform: "rest",
createdNow: false,
workspaceType: "personal",
})
toast.success(`${t("request.saved")}`)
} catch (e) {
tab.value.document.saveContext = undefined
@@ -540,13 +551,6 @@ const saveRequest = () => {
// TODO: handle error case (NOTE: overwriteRequestTeams is async)
try {
platform.analytics?.logEvent({
type: "HOPP_SAVE_REQUEST",
platform: "rest",
createdNow: false,
workspaceType: "team",
})
runMutation(UpdateRequestDocument, {
requestID: saveCtx.requestID,
data: {
@@ -570,10 +574,6 @@ const saveRequest = () => {
}
}
onBeforeUnmount(() => {
if (loading.value) cancelRequest()
})
defineActionHandler("request.send-cancel", () => {
if (!loading.value) newSendRequest()
else cancelRequest()

View File

@@ -54,8 +54,7 @@
<script setup lang="ts">
import { useI18n } from "@composables/i18n"
import { HoppRESTRequest } from "@hoppscotch/data"
import { useVModel } from "@vueuse/core"
import { computed, ref } from "vue"
import { computed, ref, watch } from "vue"
export type RequestOptionTabs =
| "params"
@@ -71,7 +70,15 @@ const emit = defineEmits<{
(e: "update:modelValue", value: HoppRESTRequest): void
}>()
const request = useVModel(props, "modelValue", emit)
const request = ref(props.modelValue)
watch(
() => request.value,
(newVal) => {
emit("update:modelValue", newVal)
},
{ deep: true }
)
const selectedRealtimeTab = ref<RequestOptionTabs>("params")

View File

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

View File

@@ -28,11 +28,9 @@
class="flex items-center justify-between flex-1 min-w-0 transition cursor-pointer focus:outline-none text-secondaryLight text-tiny group"
>
<span
class="inline-flex items-center justify-center px-4 py-2 transition group-hover:text-secondary truncate"
class="inline-flex items-center justify-center px-4 py-2 transition group-hover:text-secondary"
>
<icon-lucide-chevron-right
class="mr-2 indicator flex flex-shrink-0"
/>
<icon-lucide-chevron-right class="mr-2 indicator" />
<span class="truncate capitalize-first">
{{ t("environment.title") }}
</span>
@@ -199,20 +197,11 @@
/>
</div>
<EnvironmentsMyDetails
:show="showMyEnvironmentDetailsModal"
:show="showModalDetails"
action="new"
:env-vars="getAdditionVars"
@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>
</template>
@@ -236,7 +225,6 @@ import IconClose from "~icons/lucide/x"
import { useColorMode } from "~/composables/theming"
import { useVModel } from "@vueuse/core"
import { workspaceStatus$ } from "~/newstore/workspace"
const props = defineProps<{
modelValue: HoppTestResult | null | undefined
@@ -251,15 +239,10 @@ const testResults = useVModel(props, "modelValue", emit)
const t = useI18n()
const colorMode = useColorMode()
const workspace = useReadonlyStream(workspaceStatus$, { type: "personal" })
const showMyEnvironmentDetailsModal = ref(false)
const showTeamEnvironmentDetailsModal = ref(false)
const showModalDetails = ref(false)
const displayModalAdd = (shouldDisplay: boolean) => {
if (workspace.value.type === "personal")
showMyEnvironmentDetailsModal.value = shouldDisplay
else showTeamEnvironmentDetailsModal.value = shouldDisplay
showModalDetails.value = shouldDisplay
}
/**

View File

@@ -1,79 +0,0 @@
<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

@@ -1,79 +0,0 @@
<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

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

View File

@@ -44,7 +44,6 @@ import { createTeam } from "~/helpers/backend/mutations/Team"
import { TeamNameCodec } from "~/helpers/backend/types/TeamName"
import { useI18n } from "@composables/i18n"
import { useToast } from "@composables/toast"
import { platform } from "~/platform"
const t = useI18n()
@@ -69,12 +68,6 @@ const addNewTeam = async () => {
TE.fromEither,
TE.mapLeft(() => "invalid_name" as const),
TE.chainW(createTeam),
TE.chainFirstIOK(
() => () =>
platform.analytics?.logEvent({
type: "HOPP_CREATE_TEAM",
})
),
TE.match(
(err) => {
// err is of type "invalid_name" | GQLError<Err>

View File

@@ -38,8 +38,6 @@ import {
baseHighlightStyle,
} from "@helpers/editor/themes/baseTheme"
import { HoppEnvironmentPlugin } from "@helpers/editor/extensions/HoppEnvironment"
import xmlFormat from "xml-formatter"
import { platform } from "~/platform"
// TODO: Migrate from legacy mode
type ExtendedEditorConfig = {
@@ -153,27 +151,6 @@ const getLanguage = (langMime: string): Language | 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 = (
langMime: string,
linter: LinterDefinition | undefined,
@@ -209,8 +186,6 @@ export function useCodemirror(
: null
const initView = (el: any) => {
if (el) platform.ui?.onCodemirrorInstanceMount?.(el)
const extensions = [
basicSetup,
baseTheme,
@@ -283,7 +258,7 @@ export function useCodemirror(
view.value = new EditorView({
parent: el,
state: EditorState.create({
doc: parseDoc(value.value, options.extendedEditorConfig.mode ?? ""),
doc: value.value,
extensions,
}),
})

View File

@@ -99,7 +99,7 @@ export class GQLConnection {
private timeoutSubscription: any
public connect(url: string, headers: GQLHeader[], auth: HoppGQLAuth) {
public connect(url: string, headers: GQLHeader[]) {
if (this.connected$.value) {
throw new Error(
"A connection is already running. Close it before starting another."
@@ -110,7 +110,7 @@ export class GQLConnection {
this.connected$.next(true)
const poll = async () => {
await this.getSchema(url, headers, auth)
await this.getSchema(url, headers)
this.timeoutSubscription = setTimeout(() => {
poll()
}, GQL_SCHEMA_POLL_INTERVAL)
@@ -135,11 +135,7 @@ export class GQLConnection {
this.schema$.next(null)
}
private async getSchema(
url: string,
reqHeaders: GQLHeader[],
auth: HoppGQLAuth
) {
private async getSchema(url: string, headers: GQLHeader[]) {
try {
this.isLoading$.next(true)
@@ -147,38 +143,10 @@ export class GQLConnection {
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> = {}
headers.forEach((x) => (finalHeaders[x.key] = x.value))
headers
.filter((x) => x.active && x.key !== "")
.forEach((x) => (finalHeaders[x.key] = x.value))
const reqOptions = {
method: "POST",

View File

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

View File

@@ -6,7 +6,6 @@ import { pipe, flow } from "fp-ts/function"
import { tupleToRecord } from "~/helpers/functional/record"
import { safeParseJSON } from "~/helpers/functional/json"
import { optionChoose } from "~/helpers/functional/option"
import xmlFormat from "xml-formatter"
const isJSON = flow(safeParseJSON, O.isSome)
@@ -214,18 +213,45 @@ export function parseBody(
*/
/**
* Prettifies XML string using xml-formatter
* Prettifies XML string
* @param sourceXml The string to format
* @returns Indented XML string (uses spaces)
*/
function prettifyXml(sourceXml: string) {
return pipe(
O.tryCatch(() => {
return xmlFormat(sourceXml, {
indentation: " ",
collapseContent: true,
lineSeparator: "\n",
})
const xmlDoc = new DOMParser().parseFromString(
sourceXml,
"application/xml"
)
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

@@ -71,11 +71,9 @@ const parseURL = (urlText: string | number) =>
* @returns URL object
*/
export function getURLObject(parsedArguments: parser.Arguments) {
const location = parsedArguments.location ?? undefined
return pipe(
// contains raw url strings
[...parsedArguments._.slice(1), location],
parsedArguments._.slice(1),
A.findFirstMap(parseURL),
// no url found
O.getOrElse(() => new URL(defaultRESTReq.endpoint))

View File

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

View File

@@ -1,16 +0,0 @@
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,8 +5,6 @@ import imageLens from "./imageLens"
import htmlLens from "./htmlLens"
import xmlLens from "./xmlLens"
import pdfLens from "./pdfLens"
import audioLens from "./audioLens"
import videoLens from "./videoLens"
import { defineAsyncComponent } from "vue"
export type Lens = {
@@ -22,8 +20,6 @@ export const lenses: Lens[] = [
htmlLens,
xmlLens,
pdfLens,
audioLens,
videoLens,
rawLens,
]

View File

@@ -1,16 +0,0 @@
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

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