Compare commits
1 Commits
fix/shortc
...
fix/pretti
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ca54c8498c |
@@ -51,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)
|
||||
|
||||
42
.github/workflows/ui.yml
vendored
42
.github/workflows/ui.yml
vendored
@@ -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 }}
|
||||
@@ -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",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "hoppscotch-backend",
|
||||
"version": "2023.4.6",
|
||||
"version": "2023.4.3",
|
||||
"description": "",
|
||||
"author": "",
|
||||
"private": true,
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -126,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,
|
||||
},
|
||||
}),
|
||||
|
||||
@@ -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),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -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),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
@@ -432,7 +432,6 @@
|
||||
"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)",
|
||||
"headers": "Encabezados",
|
||||
@@ -446,7 +445,6 @@
|
||||
"status": "Estado",
|
||||
"time": "Tiempo",
|
||||
"title": "Respuesta",
|
||||
"video": "Video",
|
||||
"waiting_for_connection": "esperando la conexión",
|
||||
"xml": "XML"
|
||||
},
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
@@ -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": "एक्सएमएल"
|
||||
},
|
||||
|
||||
@@ -432,7 +432,6 @@
|
||||
"view_my_links": "View my links"
|
||||
},
|
||||
"response": {
|
||||
"audio": "Audio",
|
||||
"body": "Válasz törzse",
|
||||
"filter_response_body": "Filter JSON response body (uses JSONPath syntax)",
|
||||
"headers": "Fejlécek",
|
||||
@@ -446,7 +445,6 @@
|
||||
"status": "Állapot",
|
||||
"time": "Idő",
|
||||
"title": "Válasz",
|
||||
"video": "Video",
|
||||
"waiting_for_connection": "várakozás kapcsolódásra",
|
||||
"xml": "XML"
|
||||
},
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
@@ -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": "КСМЛ"
|
||||
},
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
@@ -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 tất 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"
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@hoppscotch/common",
|
||||
"private": true,
|
||||
"version": "2023.4.6",
|
||||
"version": "2023.4.3",
|
||||
"scripts": {
|
||||
"dev": "pnpm exec npm-run-all -p -l dev:*",
|
||||
"dev:vite": "vite",
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 7.9 KiB |
@@ -134,13 +134,11 @@ declare module '@vue/runtime-core' {
|
||||
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']
|
||||
ProfileShortcode: typeof import('./components/profile/Shortcode.vue')['default']
|
||||
|
||||
@@ -125,8 +125,8 @@
|
||||
@hide-modal="displayModalEditFolder(false)"
|
||||
/>
|
||||
<CollectionsEditRequest
|
||||
v-model="editingRequestName"
|
||||
:show="showModalEditRequest"
|
||||
v-bind:model-value="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)
|
||||
|
||||
@@ -861,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)
|
||||
@@ -895,9 +893,6 @@ const updateEditingRequest = (newName: string) => {
|
||||
|
||||
if (possibleActiveTab) {
|
||||
possibleActiveTab.value.document.request.name = requestUpdated.name
|
||||
nextTick(() => {
|
||||
possibleActiveTab.value.document.isDirty = false
|
||||
})
|
||||
}
|
||||
|
||||
displayModalEditRequest(false)
|
||||
@@ -936,9 +931,6 @@ const updateEditingRequest = (newName: string) => {
|
||||
|
||||
if (possibleTab) {
|
||||
possibleTab.value.document.request.name = requestName
|
||||
nextTick(() => {
|
||||
possibleTab.value.document.isDirty = false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,14 +11,13 @@
|
||||
class="bg-transparent border-b border-dividerLight select-wrapper"
|
||||
>
|
||||
<HoppButtonSecondary
|
||||
:icon="IconLayers"
|
||||
:label="
|
||||
mdAndLarger
|
||||
? selectedEnv.type !== 'NO_ENV_SELECTED'
|
||||
? selectedEnv.name
|
||||
: `${t('environment.select')}`
|
||||
: ''
|
||||
"
|
||||
v-if="selectedEnv.type !== 'NO_ENV_SELECTED'"
|
||||
: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>
|
||||
@@ -47,149 +46,93 @@
|
||||
}
|
||||
"
|
||||
/>
|
||||
<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')}`"
|
||||
<div v-if="environmentType === 'my-environments'" class="flex flex-col">
|
||||
<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>
|
||||
<div v-else class="flex flex-col">
|
||||
<div
|
||||
v-if="teamEnvLoading"
|
||||
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="isTeamSelected" class="flex flex-col">
|
||||
<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"
|
||||
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: 'MY_ENV', index: index }
|
||||
selectedEnvironmentIndex = {
|
||||
type: 'TEAM_ENV',
|
||||
teamEnvID: gen.id,
|
||||
teamID: gen.teamID,
|
||||
environment: gen.environment,
|
||||
}
|
||||
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>
|
||||
<div
|
||||
v-if="!teamEnvLoading && isAdapterError"
|
||||
class="flex flex-col items-center py-4"
|
||||
>
|
||||
<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>
|
||||
<icon-lucide-help-circle class="mb-4 svg-icons" />
|
||||
{{ errorMessage }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</tippy>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref, watch } from "vue"
|
||||
import { computed, ref } 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 { Environment } from "@hoppscotch/data"
|
||||
import { TeamEnvironment } from "~/helpers/teams/TeamEnvironment"
|
||||
import { 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 props = defineProps<{
|
||||
environmentType: EnvironmentType
|
||||
myEnvironments: Environment[]
|
||||
teamEnvironmentList: TeamEnvironment[]
|
||||
teamEnvLoading: boolean
|
||||
isAdapterError: boolean
|
||||
errorMessage: GQLError<string>
|
||||
isTeamSelected: boolean
|
||||
}>()
|
||||
|
||||
const selectedEnvironmentIndex = useStream(
|
||||
selectedEnvironmentIndex$,
|
||||
@@ -197,67 +140,15 @@ const selectedEnvironmentIndex = useStream(
|
||||
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,
|
||||
name: props.myEnvironments[selectedEnvironmentIndex.value.index].name,
|
||||
}
|
||||
} else if (selectedEnvironmentIndex.value.type === "TEAM_ENV") {
|
||||
const teamEnv = teamEnvironmentList.value.find(
|
||||
const teamEnv = props.teamEnvironmentList.find(
|
||||
(env) =>
|
||||
env.id ===
|
||||
(selectedEnvironmentIndex.value.type === "TEAM_ENV" &&
|
||||
@@ -279,17 +170,4 @@ const selectedEnv = computed(() => {
|
||||
|
||||
// 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>
|
||||
|
||||
@@ -4,6 +4,15 @@
|
||||
class="sticky top-0 z-10 flex flex-col flex-shrink-0 overflow-x-auto bg-primary"
|
||||
>
|
||||
<WorkspaceCurrent :section="t('tab.environments')" />
|
||||
<EnvironmentsSelector
|
||||
:environment-type="environmentType.type"
|
||||
:my-environments="myEnvironments"
|
||||
:team-env-loading="loading"
|
||||
:team-environment-list="teamEnvironmentList"
|
||||
:is-adapter-error="adapterError !== null"
|
||||
:error-message="adapterError ? getErrorMessage(adapterError) : ''"
|
||||
:is-team-selected="environmentType.selectedTeam !== undefined"
|
||||
/>
|
||||
<EnvironmentsMyEnvironment
|
||||
environment-index="Global"
|
||||
:environment="globalEnvironment"
|
||||
@@ -37,11 +46,13 @@ 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 { defineActionHandler } from "~/helpers/actions"
|
||||
import { workspaceStatus$ } from "~/newstore/workspace"
|
||||
import TeamListAdapter from "~/helpers/teams/TeamListAdapter"
|
||||
@@ -136,19 +147,24 @@ 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
|
||||
// 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, (newWorkspace) => {
|
||||
if (newWorkspace.type === "personal") {
|
||||
switchToMyEnvironments()
|
||||
setSelectedEnvironmentIndex({
|
||||
type: "NO_ENV_SELECTED",
|
||||
})
|
||||
} else if (newWorkspace.type === "team") {
|
||||
const team = myTeams.value?.find((t) => t.id === newWorkspace.teamID)
|
||||
updateSelectedTeam(team)
|
||||
|
||||
if (selectedEnvironmentIndex.value.type !== "MY_ENV") {
|
||||
setSelectedEnvironmentIndex({
|
||||
type: "NO_ENV_SELECTED",
|
||||
})
|
||||
}
|
||||
} else if (newWorkspace.type === "team") {
|
||||
const team = myTeams.value?.find((t) => t.id === newWorkspace.teamID)
|
||||
updateSelectedTeam(team)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -191,6 +207,8 @@ defineActionHandler(
|
||||
}
|
||||
)
|
||||
|
||||
const myEnvironments = useReadonlyStream(environments$, [])
|
||||
|
||||
const selectedEnvironmentIndex = useStream(
|
||||
selectedEnvironmentIndex$,
|
||||
{ type: "NO_ENV_SELECTED" },
|
||||
@@ -233,4 +251,17 @@ watch(
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
|
||||
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>
|
||||
|
||||
@@ -165,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"]
|
||||
}>(),
|
||||
{
|
||||
|
||||
@@ -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"
|
||||
@@ -173,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: () => [],
|
||||
}
|
||||
)
|
||||
|
||||
@@ -230,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 ?? [],
|
||||
|
||||
@@ -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'"
|
||||
|
||||
@@ -217,7 +217,6 @@
|
||||
@hide-modal="showCodegenModal = false"
|
||||
/>
|
||||
<CollectionsSaveRequest
|
||||
v-if="showSaveRequestModal"
|
||||
mode="rest"
|
||||
:show="showSaveRequestModal"
|
||||
@hide-modal="showSaveRequestModal = false"
|
||||
|
||||
@@ -197,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>
|
||||
|
||||
@@ -234,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
|
||||
@@ -249,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
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
import { distinctUntilChanged, pluck } from "rxjs"
|
||||
import DispatchingStore, { defineDispatchers } from "./DispatchingStore"
|
||||
|
||||
type SyncState = {
|
||||
isInitialSync: boolean
|
||||
shouldSync: boolean
|
||||
}
|
||||
|
||||
type CurrentSyncingState = {
|
||||
currentSyncingItem: SyncState
|
||||
}
|
||||
|
||||
const initialState: CurrentSyncingState = {
|
||||
currentSyncingItem: {
|
||||
isInitialSync: false,
|
||||
shouldSync: false,
|
||||
},
|
||||
}
|
||||
|
||||
const dispatchers = defineDispatchers({
|
||||
changeCurrentSyncStatus(_, { syncItem }: { syncItem: SyncState }) {
|
||||
return {
|
||||
currentSyncingItem: syncItem,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
export const currentSyncStore = new DispatchingStore(initialState, dispatchers)
|
||||
|
||||
export const currentSyncingStatus$ = currentSyncStore.subject$.pipe(
|
||||
pluck("currentSyncingItem"),
|
||||
distinctUntilChanged()
|
||||
)
|
||||
|
||||
export function changeCurrentSyncStatus(syncItem: SyncState) {
|
||||
currentSyncStore.dispatch({
|
||||
dispatcher: "changeCurrentSyncStatus",
|
||||
payload: { syncItem },
|
||||
})
|
||||
}
|
||||
@@ -56,9 +56,6 @@
|
||||
@update:model-value="onTabUpdate"
|
||||
/>
|
||||
</HoppSmartWindow>
|
||||
<template #actions>
|
||||
<EnvironmentsSelector class="h-full" />
|
||||
</template>
|
||||
</HoppSmartWindows>
|
||||
</template>
|
||||
<template #sidebar>
|
||||
@@ -66,8 +63,8 @@
|
||||
</template>
|
||||
</AppPaneLayout>
|
||||
<CollectionsEditRequest
|
||||
v-model="reqName"
|
||||
:show="showRenamingReqNameModal"
|
||||
v-model="reqName"
|
||||
@submit="renameReqName"
|
||||
@hide-modal="showRenamingReqNameModal = false"
|
||||
/>
|
||||
@@ -79,16 +76,15 @@
|
||||
@resolve="onResolveConfirmSaveTab"
|
||||
/>
|
||||
<CollectionsSaveRequest
|
||||
v-if="savingRequest"
|
||||
mode="rest"
|
||||
:show="savingRequest"
|
||||
:mode="'rest'"
|
||||
@hide-modal="onSaveModalClose"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted, onBeforeUnmount, onBeforeMount } from "vue"
|
||||
import { ref, onMounted, onBeforeUnmount, watch, onBeforeMount } from "vue"
|
||||
import { safelyExtractRESTRequest } from "@hoppscotch/data"
|
||||
import { translateExtURLParams } from "~/helpers/RESTExtURLParams"
|
||||
import { useRoute } from "vue-router"
|
||||
@@ -124,11 +120,6 @@ import { useToast } from "~/composables/toast"
|
||||
import { PersistableRESTTabState } from "~/helpers/rest/tab"
|
||||
import { watchDebounced } from "@vueuse/core"
|
||||
import { oauthRedirect } from "~/helpers/oauth"
|
||||
import { useReadonlyStream } from "~/composables/stream"
|
||||
import {
|
||||
changeCurrentSyncStatus,
|
||||
currentSyncingStatus$,
|
||||
} from "~/newstore/syncing"
|
||||
|
||||
const savingRequest = ref(false)
|
||||
const confirmingCloseForTabID = ref<string | null>(null)
|
||||
@@ -140,10 +131,7 @@ const toast = useToast()
|
||||
|
||||
const tabs = getActiveTabs()
|
||||
|
||||
const confirmSync = useReadonlyStream(currentSyncingStatus$, {
|
||||
isInitialSync: false,
|
||||
shouldSync: true,
|
||||
})
|
||||
const confirmSync = ref(false)
|
||||
const tabStateForSync = ref<PersistableRESTTabState | null>(null)
|
||||
|
||||
function bindRequestToURLParams() {
|
||||
@@ -154,11 +142,8 @@ function bindRequestToURLParams() {
|
||||
// If query params are empty, or contains code or error param (these are from Oauth Redirect)
|
||||
// We skip URL params parsing
|
||||
if (Object.keys(query).length === 0 || query.code || query.error) return
|
||||
|
||||
const request = currentActiveTab.value.document.request
|
||||
|
||||
currentActiveTab.value.document.request = safelyExtractRESTRequest(
|
||||
translateExtURLParams(query, request),
|
||||
translateExtURLParams(query),
|
||||
getDefaultRESTRequest()
|
||||
)
|
||||
})
|
||||
@@ -241,6 +226,29 @@ const onSaveModalClose = () => {
|
||||
}
|
||||
}
|
||||
|
||||
watch(confirmSync, (newValue) => {
|
||||
if (newValue) {
|
||||
toast.show(t("confirm.sync"), {
|
||||
duration: 0,
|
||||
action: [
|
||||
{
|
||||
text: `${t("action.yes")}`,
|
||||
onClick: (_, toastObject) => {
|
||||
syncTabState()
|
||||
toastObject.goAway(0)
|
||||
},
|
||||
},
|
||||
{
|
||||
text: `${t("action.no")}`,
|
||||
onClick: (_, toastObject) => {
|
||||
toastObject.goAway(0)
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const syncTabState = () => {
|
||||
if (tabStateForSync.value) loadTabsFromPersistedState(tabStateForSync.value)
|
||||
}
|
||||
@@ -279,35 +287,6 @@ function startTabStateSync(): Subscription {
|
||||
return sub
|
||||
}
|
||||
|
||||
const showSyncToast = () => {
|
||||
toast.show(t("confirm.sync"), {
|
||||
duration: 0,
|
||||
action: [
|
||||
{
|
||||
text: `${t("action.yes")}`,
|
||||
onClick: (_, toastObject) => {
|
||||
syncTabState()
|
||||
changeCurrentSyncStatus({
|
||||
isInitialSync: true,
|
||||
shouldSync: true,
|
||||
})
|
||||
toastObject.goAway(0)
|
||||
},
|
||||
},
|
||||
{
|
||||
text: `${t("action.no")}`,
|
||||
onClick: (_, toastObject) => {
|
||||
changeCurrentSyncStatus({
|
||||
isInitialSync: true,
|
||||
shouldSync: false,
|
||||
})
|
||||
toastObject.goAway(0)
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
}
|
||||
|
||||
function setupTabStateSync() {
|
||||
const route = useRoute()
|
||||
|
||||
@@ -323,15 +302,9 @@ function setupTabStateSync() {
|
||||
const tabStateFromSync =
|
||||
await platform.sync.tabState.loadTabStateFromSync()
|
||||
|
||||
if (tabStateFromSync && !confirmSync.value.isInitialSync) {
|
||||
if (tabStateFromSync) {
|
||||
tabStateForSync.value = tabStateFromSync
|
||||
showSyncToast()
|
||||
// Have to set isInitialSync to true here because the toast is shown
|
||||
// and the user does not click on any of the actions
|
||||
changeCurrentSyncStatus({
|
||||
isInitialSync: true,
|
||||
shouldSync: false,
|
||||
})
|
||||
confirmSync.value = true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,14 +11,6 @@
|
||||
<p class="mt-2 text-center">
|
||||
{{ t("error.invalid_link_description") }}
|
||||
</p>
|
||||
<p class="mt-4">
|
||||
<HoppButtonSecondary
|
||||
to="/"
|
||||
:icon="IconHome"
|
||||
filled
|
||||
:label="t('app.home')"
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
<div v-else class="flex flex-col items-center justify-center flex-1 p-4">
|
||||
<div
|
||||
@@ -115,11 +107,6 @@ const addRequestToTab = () => {
|
||||
const data = shortcodeDetails.data
|
||||
|
||||
if (E.isRight(data)) {
|
||||
if (!data.right.shortcode?.request) {
|
||||
invalidLink.value = true
|
||||
return
|
||||
}
|
||||
|
||||
const request: unknown = JSON.parse(data.right.shortcode?.request as string)
|
||||
|
||||
createNewTab({
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@hoppscotch/selfhost-web",
|
||||
"private": true,
|
||||
"version": "2023.4.6",
|
||||
"version": "2023.4.3",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev:vite": "vite",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "hoppscotch-sh-admin",
|
||||
"private": true,
|
||||
"version": "2023.4.6",
|
||||
"version": "2023.4.3",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "pnpm exec npm-run-all -p -l dev:*",
|
||||
|
||||
@@ -100,9 +100,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="hasActions" :class="mdAndLarger ? 'w-64' : 'w-16'">
|
||||
<slot name="actions" />
|
||||
</div>
|
||||
<slot name="actions" />
|
||||
|
||||
<input
|
||||
type="range"
|
||||
@@ -113,12 +111,10 @@
|
||||
:class="{
|
||||
'!block': scrollThumb.show,
|
||||
}"
|
||||
:style="[
|
||||
`--thumb-width: ${scrollThumb.width}px`,
|
||||
`width: calc(100% - ${
|
||||
hasActions ? (mdAndLarger ? '19rem' : '7rem') : '3rem'
|
||||
})`,
|
||||
]"
|
||||
:style="{
|
||||
'--thumb-width': scrollThumb.width + 'px',
|
||||
}"
|
||||
style="width: calc(100% - 3rem)"
|
||||
id="myRange"
|
||||
/>
|
||||
</div>
|
||||
@@ -144,13 +140,8 @@ import {
|
||||
inject,
|
||||
watch,
|
||||
nextTick,
|
||||
useSlots,
|
||||
} from "vue"
|
||||
import {
|
||||
breakpointsTailwind,
|
||||
useBreakpoints,
|
||||
useElementSize,
|
||||
} from "@vueuse/core"
|
||||
import { useElementSize } from "@vueuse/core"
|
||||
import type { Slot } from "vue"
|
||||
import draggable from "vuedraggable-es"
|
||||
import { HoppUIPluginOptions, HOPP_UI_OPTIONS } from "./../../index"
|
||||
@@ -173,9 +164,6 @@ export type TabProvider = {
|
||||
removeTabEntry: (tabID: string) => void
|
||||
}
|
||||
|
||||
const breakpoints = useBreakpoints(breakpointsTailwind)
|
||||
const mdAndLarger = breakpoints.greater("md")
|
||||
|
||||
const { t } = inject<HoppUIPluginOptions>(HOPP_UI_OPTIONS) ?? {}
|
||||
|
||||
const props = withDefaults(
|
||||
@@ -203,12 +191,6 @@ const emit = defineEmits<{
|
||||
(e: "addTab"): void
|
||||
}>()
|
||||
|
||||
const slots = useSlots()
|
||||
|
||||
const hasActions = computed(() => {
|
||||
return !!slots.actions
|
||||
})
|
||||
|
||||
const throwError = (message: string): never => {
|
||||
throw new Error(message)
|
||||
}
|
||||
@@ -356,8 +338,8 @@ watch(
|
||||
rootMargin: "0px",
|
||||
threshold: 1.0,
|
||||
})
|
||||
observer.observe(element!)
|
||||
|
||||
if (element) observer.observe(element)
|
||||
element?.scrollIntoView({ behavior: "smooth", inline: "center" })
|
||||
})
|
||||
},
|
||||
|
||||
481
pnpm-lock.yaml
generated
481
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user