Compare commits
24 Commits
hotfix/fet
...
pr/JoelJac
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1afabec3a8 | ||
|
|
c9927ef032 | ||
|
|
d9bddb1094 | ||
|
|
14a3dad013 | ||
|
|
c683a5471c | ||
|
|
1b215be382 | ||
|
|
9e0453d3bb | ||
|
|
caf5d7ec0f | ||
|
|
6e7db67c9b | ||
|
|
27eb7690ba | ||
|
|
a875ab1ca9 | ||
|
|
d5e4211347 | ||
|
|
24f32d79b3 | ||
|
|
f48083ca7e | ||
|
|
c0ee3d02ae | ||
|
|
fb234cbf7e | ||
|
|
c19a8be6e9 | ||
|
|
b0e29b2e6c | ||
|
|
0962718b0c | ||
|
|
a08760351d | ||
|
|
55c191305c | ||
|
|
dfabf7e8bc | ||
|
|
834efce1c2 | ||
|
|
cdbc580ada |
@@ -1,2 +1 @@
|
||||
node_modules
|
||||
**/*/node_modules
|
||||
*/**/node_modules
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
:3000 {
|
||||
try_files {path} /
|
||||
root * /site/selfhost-web
|
||||
file_server
|
||||
}
|
||||
|
||||
:3100 {
|
||||
try_files {path} /
|
||||
root * /site/sh-admin
|
||||
file_server
|
||||
}
|
||||
72
aio_run.mjs
72
aio_run.mjs
@@ -1,72 +0,0 @@
|
||||
#!/usr/local/bin/node
|
||||
// @ts-check
|
||||
|
||||
import { execSync, spawn } from "child_process"
|
||||
import fs from "fs"
|
||||
import process from "process"
|
||||
|
||||
function runChildProcessWithPrefix(command, args, prefix) {
|
||||
const childProcess = spawn(command, args);
|
||||
|
||||
childProcess.stdout.on('data', (data) => {
|
||||
const output = data.toString().trim().split('\n');
|
||||
output.forEach((line) => {
|
||||
console.log(`${prefix} | ${line}`);
|
||||
});
|
||||
});
|
||||
|
||||
childProcess.stderr.on('data', (data) => {
|
||||
const error = data.toString().trim().split('\n');
|
||||
error.forEach((line) => {
|
||||
console.error(`${prefix} | ${line}`);
|
||||
});
|
||||
});
|
||||
|
||||
childProcess.on('close', (code) => {
|
||||
console.log(`${prefix} Child process exited with code ${code}`);
|
||||
});
|
||||
|
||||
childProcess.on('error', (stuff) => {
|
||||
console.log("error")
|
||||
console.log(stuff)
|
||||
})
|
||||
|
||||
return childProcess
|
||||
}
|
||||
|
||||
const envFileContent = Object.entries(process.env)
|
||||
.filter(([env]) => env.startsWith("VITE_"))
|
||||
.map(([env, val]) => `${env}=${
|
||||
(val.startsWith("\"") && val.endsWith("\""))
|
||||
? val
|
||||
: `"${val}"`
|
||||
}`)
|
||||
.join("\n")
|
||||
|
||||
fs.writeFileSync("build.env", envFileContent)
|
||||
|
||||
execSync(`npx import-meta-env -x build.env -e build.env -p "/site/**/*"`)
|
||||
|
||||
fs.rmSync("build.env")
|
||||
|
||||
const caddyProcess = runChildProcessWithPrefix("caddy", ["run", "--config", "/etc/caddy/Caddyfile", "--adapter", "caddyfile"], "App/Admin Dashboard Caddy")
|
||||
const backendProcess = runChildProcessWithPrefix("pnpm", ["run", "start:prod"], "Backend Server")
|
||||
|
||||
caddyProcess.on("exit", (code) => {
|
||||
console.log(`Exiting process because Caddy Server exited with code ${code}`)
|
||||
process.exit(code)
|
||||
})
|
||||
|
||||
backendProcess.on("exit", (code) => {
|
||||
console.log(`Exiting process because Backend Server exited with code ${code}`)
|
||||
process.exit(code)
|
||||
})
|
||||
|
||||
process.on('SIGINT', () => {
|
||||
console.log("SIGINT received, exiting...")
|
||||
|
||||
caddyProcess.kill("SIGINT")
|
||||
backendProcess.kill("SIGINT")
|
||||
|
||||
process.exit(0)
|
||||
})
|
||||
@@ -7,103 +7,6 @@ services:
|
||||
# This service runs the backend app in the port 3170
|
||||
hoppscotch-backend:
|
||||
container_name: hoppscotch-backend
|
||||
build:
|
||||
dockerfile: prod.Dockerfile
|
||||
context: .
|
||||
target: backend
|
||||
env_file:
|
||||
- ./.env
|
||||
restart: always
|
||||
environment:
|
||||
# Edit the below line to match your PostgresDB URL if you have an outside DB (make sure to update the .env file as well)
|
||||
- DATABASE_URL=postgresql://postgres:testpass@hoppscotch-db:5432/hoppscotch?connect_timeout=300
|
||||
- PORT=3170
|
||||
volumes:
|
||||
# Uncomment the line below when modifying code. Only applicable when using the "dev" target.
|
||||
# - ./packages/hoppscotch-backend/:/usr/src/app
|
||||
- /usr/src/app/node_modules/
|
||||
depends_on:
|
||||
hoppscotch-db:
|
||||
condition: service_healthy
|
||||
ports:
|
||||
- "3170:3170"
|
||||
|
||||
# The main hoppscotch app. This will be hosted at port 3000
|
||||
# NOTE: To do TLS or play around with how the app is hosted, you can look into the Caddyfile for
|
||||
# the SH admin dashboard server at packages/hoppscotch-selfhost-web/Caddyfile
|
||||
hoppscotch-app:
|
||||
container_name: hoppscotch-app
|
||||
build:
|
||||
dockerfile: prod.Dockerfile
|
||||
context: .
|
||||
target: app
|
||||
env_file:
|
||||
- ./.env
|
||||
depends_on:
|
||||
- hoppscotch-backend
|
||||
ports:
|
||||
- "3000:8080"
|
||||
|
||||
# The Self Host dashboard for managing the app. This will be hosted at port 3100
|
||||
# NOTE: To do TLS or play around with how the app is hosted, you can look into the Caddyfile for
|
||||
# the SH admin dashboard server at packages/hoppscotch-sh-admin/Caddyfile
|
||||
hoppscotch-sh-admin:
|
||||
container_name: hoppscotch-sh-admin
|
||||
build:
|
||||
dockerfile: prod.Dockerfile
|
||||
context: .
|
||||
target: sh_admin
|
||||
env_file:
|
||||
- ./.env
|
||||
depends_on:
|
||||
- hoppscotch-backend
|
||||
ports:
|
||||
- "3100:8080"
|
||||
|
||||
# The service that spins up all 3 services at once in one container
|
||||
hoppscotch-aio:
|
||||
container_name: hoppscotch-aio
|
||||
build:
|
||||
dockerfile: prod.Dockerfile
|
||||
context: .
|
||||
target: aio
|
||||
env_file:
|
||||
- ./.env
|
||||
depends_on:
|
||||
hoppscotch-db:
|
||||
condition: service_healthy
|
||||
ports:
|
||||
- "3000:3000"
|
||||
- "3100:3100"
|
||||
- "3170:3170"
|
||||
|
||||
# The preset DB service, you can delete/comment the below lines if
|
||||
# you are using an external postgres instance
|
||||
# This will be exposed at port 5432
|
||||
hoppscotch-db:
|
||||
image: postgres:15
|
||||
ports:
|
||||
- "5432:5432"
|
||||
user: postgres
|
||||
environment:
|
||||
# The default user defined by the docker image
|
||||
POSTGRES_USER: postgres
|
||||
# NOTE: Please UPDATE THIS PASSWORD!
|
||||
POSTGRES_PASSWORD: testpass
|
||||
POSTGRES_DB: hoppscotch
|
||||
healthcheck:
|
||||
test:
|
||||
[
|
||||
"CMD-SHELL",
|
||||
"sh -c 'pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}'"
|
||||
]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
|
||||
# All the services listed below are deprececated
|
||||
hoppscotch-old-backend:
|
||||
container_name: hoppscotch-old-backend
|
||||
build:
|
||||
dockerfile: packages/hoppscotch-backend/Dockerfile
|
||||
context: .
|
||||
@@ -125,26 +28,54 @@ services:
|
||||
ports:
|
||||
- "3170:3000"
|
||||
|
||||
hoppscotch-old-app:
|
||||
container_name: hoppscotch-old-app
|
||||
# The main hoppscotch app. This will be hosted at port 3000
|
||||
# NOTE: To do TLS or play around with how the app is hosted, you can look into the Caddyfile for
|
||||
# the SH admin dashboard server at packages/hoppscotch-selfhost-web/Caddyfile
|
||||
hoppscotch-app:
|
||||
container_name: hoppscotch-app
|
||||
build:
|
||||
dockerfile: packages/hoppscotch-selfhost-web/Dockerfile
|
||||
context: .
|
||||
env_file:
|
||||
- ./.env
|
||||
depends_on:
|
||||
- hoppscotch-old-backend
|
||||
- hoppscotch-backend
|
||||
ports:
|
||||
- "3000:8080"
|
||||
|
||||
hoppscotch-old-sh-admin:
|
||||
container_name: hoppscotch-old-sh-admin
|
||||
# The Self Host dashboard for managing the app. This will be hosted at port 3100
|
||||
# NOTE: To do TLS or play around with how the app is hosted, you can look into the Caddyfile for
|
||||
# the SH admin dashboard server at packages/hoppscotch-sh-admin/Caddyfile
|
||||
hoppscotch-sh-admin:
|
||||
container_name: hoppscotch-sh-admin
|
||||
build:
|
||||
dockerfile: packages/hoppscotch-sh-admin/Dockerfile
|
||||
context: .
|
||||
env_file:
|
||||
- ./.env
|
||||
depends_on:
|
||||
- hoppscotch-old-backend
|
||||
- hoppscotch-backend
|
||||
ports:
|
||||
- "3100:8080"
|
||||
|
||||
# The preset DB service, you can delete/comment the below lines if
|
||||
# you are using an external postgres instance
|
||||
# This will be exposed at port 5432
|
||||
hoppscotch-db:
|
||||
image: postgres:15
|
||||
ports:
|
||||
- "5432:5432"
|
||||
user: postgres
|
||||
environment:
|
||||
# The default user defined by the docker image
|
||||
POSTGRES_USER: postgres
|
||||
# NOTE: Please UPDATE THIS PASSWORD!
|
||||
POSTGRES_PASSWORD: testpass
|
||||
POSTGRES_DB: hoppscotch
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "sh -c 'pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}'"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
|
||||
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
curlCheck() {
|
||||
if ! curl -s --head "$1" | head -n 1 | grep -q "HTTP/1.[01] [23].."; then
|
||||
echo "URL request failed!"
|
||||
exit 1
|
||||
else
|
||||
echo "URL request succeeded!"
|
||||
fi
|
||||
}
|
||||
|
||||
curlCheck "http://localhost:3000"
|
||||
curlCheck "http://localhost:3100"
|
||||
curlCheck "http://localhost:3170/ping"
|
||||
@@ -33,7 +33,7 @@
|
||||
"@nestjs/passport": "^9.0.0",
|
||||
"@nestjs/platform-express": "^9.2.1",
|
||||
"@nestjs/throttler": "^4.0.0",
|
||||
"@prisma/client": "^4.16.2",
|
||||
"@prisma/client": "^4.7.1",
|
||||
"apollo-server-express": "^3.11.1",
|
||||
"apollo-server-plugin-base": "^3.7.1",
|
||||
"argon2": "^0.30.3",
|
||||
@@ -57,7 +57,7 @@
|
||||
"passport-jwt": "^4.0.1",
|
||||
"passport-local": "^1.0.0",
|
||||
"passport-microsoft": "^1.0.0",
|
||||
"prisma": "^4.16.2",
|
||||
"prisma": "^4.7.1",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rimraf": "^3.0.2",
|
||||
"rxjs": "^7.6.0"
|
||||
|
||||
@@ -5,7 +5,7 @@ datasource db {
|
||||
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
binaryTargets = ["native", "debian-openssl-1.1.x", "debian-openssl-3.0.x"]
|
||||
binaryTargets = ["native", "debian-openssl-1.1.x"]
|
||||
}
|
||||
|
||||
model Team {
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
import { Controller, Get } from '@nestjs/common';
|
||||
|
||||
@Controller('ping')
|
||||
export class AppController {
|
||||
@Get()
|
||||
ping(): string {
|
||||
return 'Success';
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,6 @@ import { UserCollectionModule } from './user-collection/user-collection.module';
|
||||
import { ShortcodeModule } from './shortcode/shortcode.module';
|
||||
import { COOKIES_NOT_FOUND } from './errors';
|
||||
import { ThrottlerModule } from '@nestjs/throttler';
|
||||
import { AppController } from './app.controller';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@@ -82,6 +81,5 @@ import { AppController } from './app.controller';
|
||||
ShortcodeModule,
|
||||
],
|
||||
providers: [GQLComplexityPlugin],
|
||||
controllers: [AppController],
|
||||
})
|
||||
export class AppModule {}
|
||||
|
||||
@@ -150,7 +150,7 @@ export class ShortcodeService implements UserDataHandler, OnModuleInit {
|
||||
orderBy: {
|
||||
createdOn: 'desc',
|
||||
},
|
||||
skip: args.cursor ? 1 : 0,
|
||||
skip: 1,
|
||||
take: args.take,
|
||||
cursor: args.cursor ? { id: args.cursor } : undefined,
|
||||
});
|
||||
|
||||
@@ -24,8 +24,6 @@ beforeEach(() => {
|
||||
mockPubSub.publish.mockClear();
|
||||
});
|
||||
|
||||
const date = new Date();
|
||||
|
||||
describe('UserHistoryService', () => {
|
||||
describe('fetchUserHistory', () => {
|
||||
test('Should return a list of users REST history if exists', async () => {
|
||||
@@ -402,7 +400,7 @@ describe('UserHistoryService', () => {
|
||||
request: [{}],
|
||||
responseMetadata: [{}],
|
||||
reqType: ReqType.REST,
|
||||
executedOn: date,
|
||||
executedOn: new Date(),
|
||||
isStarred: false,
|
||||
});
|
||||
|
||||
@@ -412,7 +410,7 @@ describe('UserHistoryService', () => {
|
||||
request: JSON.stringify([{}]),
|
||||
responseMetadata: JSON.stringify([{}]),
|
||||
reqType: ReqType.REST,
|
||||
executedOn: date,
|
||||
executedOn: new Date(),
|
||||
isStarred: false,
|
||||
};
|
||||
|
||||
|
||||
@@ -166,6 +166,12 @@ a {
|
||||
@apply truncate;
|
||||
@apply sm:inline-flex;
|
||||
}
|
||||
|
||||
.env-icon {
|
||||
@apply transition;
|
||||
@apply inline-flex;
|
||||
@apply items-center;
|
||||
}
|
||||
}
|
||||
|
||||
.tippy-svg-arrow {
|
||||
@@ -326,7 +332,7 @@ pre.ace_editor {
|
||||
@apply after:font-icon;
|
||||
@apply after:text-current;
|
||||
@apply after:right-3;
|
||||
@apply after:content-["\e5cf"];
|
||||
@apply after:content-["\e313"];
|
||||
@apply after:text-lg;
|
||||
}
|
||||
|
||||
@@ -481,10 +487,6 @@ pre.ace_editor {
|
||||
}
|
||||
}
|
||||
|
||||
.cm-scroller {
|
||||
@apply overscroll-y-auto;
|
||||
}
|
||||
|
||||
.cm-editor {
|
||||
.cm-line::selection {
|
||||
@apply bg-accentDark #{!important};
|
||||
@@ -574,9 +576,9 @@ details[open] summary .indicator {
|
||||
}
|
||||
|
||||
.gql-operation-not-highlight {
|
||||
@apply opacity-50;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.gql-operation-highlight {
|
||||
@apply opacity-100;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@@ -159,8 +159,8 @@
|
||||
},
|
||||
"context_menu": {
|
||||
"set_environment_variable": "Set as variable",
|
||||
"add_parameters": "Add to parameters",
|
||||
"open_request_in_new_tab": "Open request in new tab"
|
||||
"add_parameter": "Add to parameter",
|
||||
"open_link_in_new_tab": "Open link in new tab"
|
||||
},
|
||||
"count": {
|
||||
"header": "Header {count}",
|
||||
@@ -185,6 +185,7 @@
|
||||
"folder": "Folder is empty",
|
||||
"headers": "This request does not have any headers",
|
||||
"history": "History is empty",
|
||||
"history_suggestions": "History does not have any matching entries",
|
||||
"invites": "Invite list is empty",
|
||||
"members": "Team is empty",
|
||||
"parameters": "This request does not have any parameters",
|
||||
@@ -194,6 +195,7 @@
|
||||
"schema": "Connect to a GraphQL endpoint to view schema",
|
||||
"shortcodes": "Shortcodes are empty",
|
||||
"subscription": "Subscriptions are empty",
|
||||
"suggestions": "No matching suggestions found",
|
||||
"team_name": "Team name empty",
|
||||
"teams": "You don't belong to any teams",
|
||||
"tests": "There are no tests for this request"
|
||||
@@ -606,7 +608,7 @@
|
||||
"delete_method": "Select DELETE method",
|
||||
"get_method": "Select GET method",
|
||||
"head_method": "Select HEAD method",
|
||||
"rename": "Rename Request",
|
||||
"rename": "Rename Current Request",
|
||||
"import_curl": "Import cURL",
|
||||
"show_code": "Generate code snippet",
|
||||
"method": "Method",
|
||||
@@ -649,11 +651,11 @@
|
||||
},
|
||||
"spotlight": {
|
||||
"general": {
|
||||
"help_menu": "Help and support",
|
||||
"help_menu": "Open help and support menu",
|
||||
"chat": "Chat with support",
|
||||
"open_docs": "Read Documentation",
|
||||
"open_keybindings": "Keyboard shortcuts",
|
||||
"social": "Social",
|
||||
"open_keybindings": "Open keyboard shortcuts",
|
||||
"social": "Social links and GitHub",
|
||||
"title": "General"
|
||||
},
|
||||
"miscellaneous": {
|
||||
@@ -661,18 +663,15 @@
|
||||
"title": "Miscellaneous"
|
||||
},
|
||||
"request": {
|
||||
"switch_to": "Switch to",
|
||||
"select_method": "Select method",
|
||||
"save_as_new": "Save as new request",
|
||||
"tab_parameters": "Parameters tab",
|
||||
"tab_body": "Body tab",
|
||||
"tab_headers": "Headers tab",
|
||||
"tab_authorization": "Authorization tab",
|
||||
"tab_pre_request_script": "Pre-request script tab",
|
||||
"tab_tests": "Tests tab"
|
||||
"tab_parameters": "Open parameters tab",
|
||||
"tab_body": "Open body tab",
|
||||
"tab_headers": "Open headers tab",
|
||||
"tab_authorization": "Open authorization tab",
|
||||
"tab_pre_request_script": "Open pre-request script tab",
|
||||
"tab_tests": "Open tests tab"
|
||||
},
|
||||
"response": {
|
||||
"copy": "Copy response",
|
||||
"copy": "Copy response as JSON",
|
||||
"download": "Download response as file",
|
||||
"title": "Response"
|
||||
},
|
||||
@@ -695,7 +694,6 @@
|
||||
"title": "Teams"
|
||||
},
|
||||
"tab": {
|
||||
"duplicate": "Duplicate tab",
|
||||
"close_current": "Close current tab",
|
||||
"close_others": "Close other tabs",
|
||||
"new_tab": "Open a new tab",
|
||||
@@ -707,7 +705,9 @@
|
||||
"interface": "Interface",
|
||||
"interceptor": "Interceptor"
|
||||
},
|
||||
"change_interceptor": "Change Interceptor",
|
||||
"change_language": "Change Language",
|
||||
"install_extension": "Install Browser Extension",
|
||||
"settings": {
|
||||
"theme": {
|
||||
"black": "Black Mode",
|
||||
@@ -721,7 +721,8 @@
|
||||
"size_lg": "Change to Large"
|
||||
},
|
||||
"change_interceptor": "Change Interceptor",
|
||||
"change_language": "Change Language"
|
||||
"change_language": "Change Language",
|
||||
"install_extension": "Install Browser Extension"
|
||||
}
|
||||
},
|
||||
"sse": {
|
||||
|
||||
427
packages/hoppscotch-common/src/components.d.ts
vendored
427
packages/hoppscotch-common/src/components.d.ts
vendored
@@ -5,221 +5,218 @@
|
||||
// Read more: https://github.com/vuejs/core/pull/3399
|
||||
export {}
|
||||
|
||||
declare module 'vue' {
|
||||
declare module "vue" {
|
||||
export interface GlobalComponents {
|
||||
AppActionHandler: typeof import('./components/app/ActionHandler.vue')['default']
|
||||
AppAnnouncement: typeof import('./components/app/Announcement.vue')['default']
|
||||
AppContextMenu: typeof import('./components/app/ContextMenu.vue')['default']
|
||||
AppDeveloperOptions: typeof import('./components/app/DeveloperOptions.vue')['default']
|
||||
AppFooter: typeof import('./components/app/Footer.vue')['default']
|
||||
AppGitHubStarButton: typeof import('./components/app/GitHubStarButton.vue')['default']
|
||||
AppHeader: typeof import('./components/app/Header.vue')['default']
|
||||
AppInspection: typeof import('./components/app/Inspection.vue')['default']
|
||||
AppInterceptor: typeof import('./components/app/Interceptor.vue')['default']
|
||||
AppLogo: typeof import('./components/app/Logo.vue')['default']
|
||||
AppOptions: typeof import('./components/app/Options.vue')['default']
|
||||
AppPaneLayout: typeof import('./components/app/PaneLayout.vue')['default']
|
||||
AppShare: typeof import('./components/app/Share.vue')['default']
|
||||
AppShortcuts: typeof import('./components/app/Shortcuts.vue')['default']
|
||||
AppShortcutsEntry: typeof import('./components/app/ShortcutsEntry.vue')['default']
|
||||
AppShortcutsPrompt: typeof import('./components/app/ShortcutsPrompt.vue')['default']
|
||||
AppSidenav: typeof import('./components/app/Sidenav.vue')['default']
|
||||
AppSocial: typeof import('./components/app/Social.vue')['default']
|
||||
AppSpotlight: typeof import('./components/app/spotlight/index.vue')['default']
|
||||
AppSpotlightEntry: typeof import('./components/app/spotlight/Entry.vue')['default']
|
||||
AppSpotlightEntryGQLHistory: typeof import('./components/app/spotlight/entry/GQLHistory.vue')['default']
|
||||
AppSpotlightEntryGQLRequest: typeof import('./components/app/spotlight/entry/GQLRequest.vue')['default']
|
||||
AppSpotlightEntryIconSelected: typeof import('./components/app/spotlight/entry/IconSelected.vue')['default']
|
||||
AppSpotlightEntryRESTHistory: typeof import('./components/app/spotlight/entry/RESTHistory.vue')['default']
|
||||
AppSpotlightEntryRESTRequest: typeof import('./components/app/spotlight/entry/RESTRequest.vue')['default']
|
||||
AppSupport: typeof import('./components/app/Support.vue')['default']
|
||||
ButtonPrimary: typeof import('./../../hoppscotch-ui/src/components/button/Primary.vue')['default']
|
||||
ButtonSecondary: typeof import('./../../hoppscotch-ui/src/components/button/Secondary.vue')['default']
|
||||
Collections: typeof import('./components/collections/index.vue')['default']
|
||||
CollectionsAdd: typeof import('./components/collections/Add.vue')['default']
|
||||
CollectionsAddFolder: typeof import('./components/collections/AddFolder.vue')['default']
|
||||
CollectionsAddRequest: typeof import('./components/collections/AddRequest.vue')['default']
|
||||
CollectionsCollection: typeof import('./components/collections/Collection.vue')['default']
|
||||
CollectionsEdit: typeof import('./components/collections/Edit.vue')['default']
|
||||
CollectionsEditFolder: typeof import('./components/collections/EditFolder.vue')['default']
|
||||
CollectionsEditRequest: typeof import('./components/collections/EditRequest.vue')['default']
|
||||
CollectionsGraphql: typeof import('./components/collections/graphql/index.vue')['default']
|
||||
CollectionsGraphqlAdd: typeof import('./components/collections/graphql/Add.vue')['default']
|
||||
CollectionsGraphqlAddFolder: typeof import('./components/collections/graphql/AddFolder.vue')['default']
|
||||
CollectionsGraphqlAddRequest: typeof import('./components/collections/graphql/AddRequest.vue')['default']
|
||||
CollectionsGraphqlCollection: typeof import('./components/collections/graphql/Collection.vue')['default']
|
||||
CollectionsGraphqlEdit: typeof import('./components/collections/graphql/Edit.vue')['default']
|
||||
CollectionsGraphqlEditFolder: typeof import('./components/collections/graphql/EditFolder.vue')['default']
|
||||
CollectionsGraphqlEditRequest: typeof import('./components/collections/graphql/EditRequest.vue')['default']
|
||||
CollectionsGraphqlFolder: typeof import('./components/collections/graphql/Folder.vue')['default']
|
||||
CollectionsGraphqlImportExport: typeof import('./components/collections/graphql/ImportExport.vue')['default']
|
||||
CollectionsGraphqlRequest: typeof import('./components/collections/graphql/Request.vue')['default']
|
||||
CollectionsImportExport: typeof import('./components/collections/ImportExport.vue')['default']
|
||||
CollectionsMyCollections: typeof import('./components/collections/MyCollections.vue')['default']
|
||||
CollectionsRequest: typeof import('./components/collections/Request.vue')['default']
|
||||
CollectionsSaveRequest: typeof import('./components/collections/SaveRequest.vue')['default']
|
||||
CollectionsTeamCollections: typeof import('./components/collections/TeamCollections.vue')['default']
|
||||
Environments: typeof import('./components/environments/index.vue')['default']
|
||||
EnvironmentsAdd: typeof import('./components/environments/Add.vue')['default']
|
||||
EnvironmentsImportExport: typeof import('./components/environments/ImportExport.vue')['default']
|
||||
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']
|
||||
FirebaseLogin: typeof import('./components/firebase/Login.vue')['default']
|
||||
FirebaseLogout: typeof import('./components/firebase/Logout.vue')['default']
|
||||
GraphqlAuthorization: typeof import('./components/graphql/Authorization.vue')['default']
|
||||
GraphqlField: typeof import('./components/graphql/Field.vue')['default']
|
||||
GraphqlHeaders: typeof import('./components/graphql/Headers.vue')['default']
|
||||
GraphqlQuery: typeof import('./components/graphql/Query.vue')['default']
|
||||
GraphqlRequest: typeof import('./components/graphql/Request.vue')['default']
|
||||
GraphqlRequestOptions: typeof import('./components/graphql/RequestOptions.vue')['default']
|
||||
GraphqlRequestTab: typeof import('./components/graphql/RequestTab.vue')['default']
|
||||
GraphqlResponse: typeof import('./components/graphql/Response.vue')['default']
|
||||
GraphqlSidebar: typeof import('./components/graphql/Sidebar.vue')['default']
|
||||
GraphqlSubscriptionLog: typeof import('./components/graphql/SubscriptionLog.vue')['default']
|
||||
GraphqlTabHead: typeof import('./components/graphql/TabHead.vue')['default']
|
||||
GraphqlType: typeof import('./components/graphql/Type.vue')['default']
|
||||
GraphqlTypeLink: typeof import('./components/graphql/TypeLink.vue')['default']
|
||||
GraphqlVariable: typeof import('./components/graphql/Variable.vue')['default']
|
||||
History: typeof import('./components/history/index.vue')['default']
|
||||
HistoryGraphqlCard: typeof import('./components/history/graphql/Card.vue')['default']
|
||||
HistoryRestCard: typeof import('./components/history/rest/Card.vue')['default']
|
||||
HoppButtonPrimary: typeof import('@hoppscotch/ui')['HoppButtonPrimary']
|
||||
HoppButtonSecondary: typeof import('@hoppscotch/ui')['HoppButtonSecondary']
|
||||
HoppSmartAnchor: typeof import('@hoppscotch/ui')['HoppSmartAnchor']
|
||||
HoppSmartAutoComplete: typeof import('@hoppscotch/ui')['HoppSmartAutoComplete']
|
||||
HoppSmartCheckbox: typeof import('@hoppscotch/ui')['HoppSmartCheckbox']
|
||||
HoppSmartConfirmModal: typeof import('@hoppscotch/ui')['HoppSmartConfirmModal']
|
||||
HoppSmartExpand: typeof import('@hoppscotch/ui')['HoppSmartExpand']
|
||||
HoppSmartFileChip: typeof import('@hoppscotch/ui')['HoppSmartFileChip']
|
||||
HoppSmartInput: typeof import('@hoppscotch/ui')['HoppSmartInput']
|
||||
HoppSmartIntersection: typeof import('@hoppscotch/ui')['HoppSmartIntersection']
|
||||
HoppSmartItem: typeof import('@hoppscotch/ui')['HoppSmartItem']
|
||||
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']
|
||||
HoppSmartRadio: typeof import('@hoppscotch/ui')['HoppSmartRadio']
|
||||
HoppSmartRadioGroup: typeof import('@hoppscotch/ui')['HoppSmartRadioGroup']
|
||||
HoppSmartSlideOver: typeof import('@hoppscotch/ui')['HoppSmartSlideOver']
|
||||
HoppSmartSpinner: typeof import('@hoppscotch/ui')['HoppSmartSpinner']
|
||||
HoppSmartTab: typeof import('@hoppscotch/ui')['HoppSmartTab']
|
||||
HoppSmartTabs: typeof import('@hoppscotch/ui')['HoppSmartTabs']
|
||||
HoppSmartToggle: typeof import('@hoppscotch/ui')['HoppSmartToggle']
|
||||
HoppSmartTree: typeof import('@hoppscotch/ui')['HoppSmartTree']
|
||||
HoppSmartWindow: typeof import('@hoppscotch/ui')['HoppSmartWindow']
|
||||
HoppSmartWindows: typeof import('@hoppscotch/ui')['HoppSmartWindows']
|
||||
HttpAuthorization: typeof import('./components/http/Authorization.vue')['default']
|
||||
HttpAuthorizationApiKey: typeof import('./components/http/authorization/ApiKey.vue')['default']
|
||||
HttpAuthorizationBasic: typeof import('./components/http/authorization/Basic.vue')['default']
|
||||
HttpBody: typeof import('./components/http/Body.vue')['default']
|
||||
HttpBodyParameters: typeof import('./components/http/BodyParameters.vue')['default']
|
||||
HttpCodegenModal: typeof import('./components/http/CodegenModal.vue')['default']
|
||||
HttpHeaders: typeof import('./components/http/Headers.vue')['default']
|
||||
HttpImportCurl: typeof import('./components/http/ImportCurl.vue')['default']
|
||||
HttpOAuth2Authorization: typeof import('./components/http/OAuth2Authorization.vue')['default']
|
||||
HttpParameters: typeof import('./components/http/Parameters.vue')['default']
|
||||
HttpPreRequestScript: typeof import('./components/http/PreRequestScript.vue')['default']
|
||||
HttpRawBody: typeof import('./components/http/RawBody.vue')['default']
|
||||
HttpReqChangeConfirmModal: typeof import('./components/http/ReqChangeConfirmModal.vue')['default']
|
||||
HttpRequest: typeof import('./components/http/Request.vue')['default']
|
||||
HttpRequestOptions: typeof import('./components/http/RequestOptions.vue')['default']
|
||||
HttpRequestTab: typeof import('./components/http/RequestTab.vue')['default']
|
||||
HttpResponse: typeof import('./components/http/Response.vue')['default']
|
||||
HttpResponseMeta: typeof import('./components/http/ResponseMeta.vue')['default']
|
||||
HttpSidebar: typeof import('./components/http/Sidebar.vue')['default']
|
||||
HttpTabHead: typeof import('./components/http/TabHead.vue')['default']
|
||||
HttpTestResult: typeof import('./components/http/TestResult.vue')['default']
|
||||
HttpTestResultEntry: typeof import('./components/http/TestResultEntry.vue')['default']
|
||||
HttpTestResultEnv: typeof import('./components/http/TestResultEnv.vue')['default']
|
||||
HttpTestResultReport: typeof import('./components/http/TestResultReport.vue')['default']
|
||||
HttpTests: typeof import('./components/http/Tests.vue')['default']
|
||||
HttpURLEncodedParams: typeof import('./components/http/URLEncodedParams.vue')['default']
|
||||
IconLucideActivity: typeof import('~icons/lucide/activity')['default']
|
||||
IconLucideAlertTriangle: typeof import('~icons/lucide/alert-triangle')['default']
|
||||
IconLucideArrowLeft: typeof import('~icons/lucide/arrow-left')['default']
|
||||
IconLucideArrowUpRight: typeof import('~icons/lucide/arrow-up-right')['default']
|
||||
IconLucideCheckCircle: typeof import('~icons/lucide/check-circle')['default']
|
||||
IconLucideChevronRight: typeof import('~icons/lucide/chevron-right')['default']
|
||||
IconLucideGlobe: typeof import('~icons/lucide/globe')['default']
|
||||
IconLucideHelpCircle: typeof import('~icons/lucide/help-circle')['default']
|
||||
IconLucideInbox: typeof import('~icons/lucide/inbox')['default']
|
||||
IconLucideInfo: typeof import('~icons/lucide/info')['default']
|
||||
IconLucideLayers: typeof import('~icons/lucide/layers')['default']
|
||||
IconLucideListEnd: typeof import('~icons/lucide/list-end')['default']
|
||||
IconLucideMinus: typeof import('~icons/lucide/minus')['default']
|
||||
IconLucideRss: typeof import('~icons/lucide/rss')['default']
|
||||
IconLucideSearch: typeof import('~icons/lucide/search')['default']
|
||||
IconLucideUsers: typeof import('~icons/lucide/users')['default']
|
||||
IconLucideVerified: typeof import('~icons/lucide/verified')['default']
|
||||
InterceptorsExtensionSubtitle: typeof import('./components/interceptors/ExtensionSubtitle.vue')['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']
|
||||
ProfileShortcodes: typeof import('./components/profile/Shortcodes.vue')['default']
|
||||
ProfileUserDelete: typeof import('./components/profile/UserDelete.vue')['default']
|
||||
RealtimeCommunication: typeof import('./components/realtime/Communication.vue')['default']
|
||||
RealtimeConnectionConfig: typeof import('./components/realtime/ConnectionConfig.vue')['default']
|
||||
RealtimeLog: typeof import('./components/realtime/Log.vue')['default']
|
||||
RealtimeLogEntry: typeof import('./components/realtime/LogEntry.vue')['default']
|
||||
RealtimeSubscription: typeof import('./components/realtime/Subscription.vue')['default']
|
||||
SettingsExtension: typeof import('./components/settings/Extension.vue')['default']
|
||||
SettingsProxy: typeof import('./components/settings/Proxy.vue')['default']
|
||||
SmartAccentModePicker: typeof import('./components/smart/AccentModePicker.vue')['default']
|
||||
SmartAnchor: typeof import('./../../hoppscotch-ui/src/components/smart/Anchor.vue')['default']
|
||||
SmartAutoComplete: typeof import('./../../hoppscotch-ui/src/components/smart/AutoComplete.vue')['default']
|
||||
SmartChangeLanguage: typeof import('./components/smart/ChangeLanguage.vue')['default']
|
||||
SmartCheckbox: typeof import('./../../hoppscotch-ui/src/components/smart/Checkbox.vue')['default']
|
||||
SmartColorModePicker: typeof import('./components/smart/ColorModePicker.vue')['default']
|
||||
SmartConfirmModal: typeof import('./../../hoppscotch-ui/src/components/smart/ConfirmModal.vue')['default']
|
||||
SmartEnvInput: typeof import('./components/smart/EnvInput.vue')['default']
|
||||
SmartExpand: typeof import('./../../hoppscotch-ui/src/components/smart/Expand.vue')['default']
|
||||
SmartFileChip: typeof import('./../../hoppscotch-ui/src/components/smart/FileChip.vue')['default']
|
||||
SmartFontSizePicker: typeof import('./components/smart/FontSizePicker.vue')['default']
|
||||
SmartInput: typeof import('./../../hoppscotch-ui/src/components/smart/Input.vue')['default']
|
||||
SmartIntersection: typeof import('./../../hoppscotch-ui/src/components/smart/Intersection.vue')['default']
|
||||
SmartItem: typeof import('./../../hoppscotch-ui/src/components/smart/Item.vue')['default']
|
||||
SmartLink: typeof import('./../../hoppscotch-ui/src/components/smart/Link.vue')['default']
|
||||
SmartModal: typeof import('./../../hoppscotch-ui/src/components/smart/Modal.vue')['default']
|
||||
SmartPicture: typeof import('./../../hoppscotch-ui/src/components/smart/Picture.vue')['default']
|
||||
SmartPlaceholder: typeof import('./../../hoppscotch-ui/src/components/smart/Placeholder.vue')['default']
|
||||
SmartProgressRing: typeof import('./../../hoppscotch-ui/src/components/smart/ProgressRing.vue')['default']
|
||||
SmartRadio: typeof import('./../../hoppscotch-ui/src/components/smart/Radio.vue')['default']
|
||||
SmartRadioGroup: typeof import('./../../hoppscotch-ui/src/components/smart/RadioGroup.vue')['default']
|
||||
SmartSlideOver: typeof import('./../../hoppscotch-ui/src/components/smart/SlideOver.vue')['default']
|
||||
SmartSpinner: typeof import('./../../hoppscotch-ui/src/components/smart/Spinner.vue')['default']
|
||||
SmartTab: typeof import('./../../hoppscotch-ui/src/components/smart/Tab.vue')['default']
|
||||
SmartTabs: typeof import('./../../hoppscotch-ui/src/components/smart/Tabs.vue')['default']
|
||||
SmartToggle: typeof import('./../../hoppscotch-ui/src/components/smart/Toggle.vue')['default']
|
||||
SmartTree: typeof import('./../../hoppscotch-ui/src/components/smart/Tree.vue')['default']
|
||||
SmartTreeBranch: typeof import('./../../hoppscotch-ui/src/components/smart/TreeBranch.vue')['default']
|
||||
SmartWindow: typeof import('./../../hoppscotch-ui/src/components/smart/Window.vue')['default']
|
||||
SmartWindows: typeof import('./../../hoppscotch-ui/src/components/smart/Windows.vue')['default']
|
||||
TabPrimary: typeof import('./components/tab/Primary.vue')['default']
|
||||
TabSecondary: typeof import('./components/tab/Secondary.vue')['default']
|
||||
Teams: typeof import('./components/teams/index.vue')['default']
|
||||
TeamsAdd: typeof import('./components/teams/Add.vue')['default']
|
||||
TeamsEdit: typeof import('./components/teams/Edit.vue')['default']
|
||||
TeamsInvite: typeof import('./components/teams/Invite.vue')['default']
|
||||
TeamsMemberStack: typeof import('./components/teams/MemberStack.vue')['default']
|
||||
TeamsModal: typeof import('./components/teams/Modal.vue')['default']
|
||||
TeamsTeam: typeof import('./components/teams/Team.vue')['default']
|
||||
Tippy: typeof import('vue-tippy')['Tippy']
|
||||
WorkspaceCurrent: typeof import('./components/workspace/Current.vue')['default']
|
||||
WorkspaceSelector: typeof import('./components/workspace/Selector.vue')['default']
|
||||
AppActionHandler: typeof import("./components/app/ActionHandler.vue")["default"]
|
||||
AppAnnouncement: typeof import("./components/app/Announcement.vue")["default"]
|
||||
AppContextMenu: typeof import("./components/app/ContextMenu.vue")["default"]
|
||||
AppDeveloperOptions: typeof import("./components/app/DeveloperOptions.vue")["default"]
|
||||
AppFooter: typeof import("./components/app/Footer.vue")["default"]
|
||||
AppGitHubStarButton: typeof import("./components/app/GitHubStarButton.vue")["default"]
|
||||
AppHeader: typeof import("./components/app/Header.vue")["default"]
|
||||
AppInspection: typeof import("./components/app/Inspection.vue")["default"]
|
||||
AppInterceptor: typeof import("./components/app/Interceptor.vue")["default"]
|
||||
AppLogo: typeof import("./components/app/Logo.vue")["default"]
|
||||
AppOptions: typeof import("./components/app/Options.vue")["default"]
|
||||
AppPaneLayout: typeof import("./components/app/PaneLayout.vue")["default"]
|
||||
AppShare: typeof import("./components/app/Share.vue")["default"]
|
||||
AppShortcuts: typeof import("./components/app/Shortcuts.vue")["default"]
|
||||
AppShortcutsEntry: typeof import("./components/app/ShortcutsEntry.vue")["default"]
|
||||
AppShortcutsPrompt: typeof import("./components/app/ShortcutsPrompt.vue")["default"]
|
||||
AppSidenav: typeof import("./components/app/Sidenav.vue")["default"]
|
||||
AppSocial: typeof import("./components/app/Social.vue")["default"]
|
||||
AppSpotlight: typeof import("./components/app/spotlight/index.vue")["default"]
|
||||
AppSpotlightEntry: typeof import("./components/app/spotlight/Entry.vue")["default"]
|
||||
AppSpotlightEntryGQLHistory: typeof import("./components/app/spotlight/entry/GQLHistory.vue")["default"]
|
||||
AppSpotlightEntryGQLRequest: typeof import("./components/app/spotlight/entry/GQLRequest.vue")["default"]
|
||||
AppSpotlightEntryRESTHistory: typeof import("./components/app/spotlight/entry/RESTHistory.vue")["default"]
|
||||
AppSpotlightEntryRESTRequest: typeof import("./components/app/spotlight/entry/RESTRequest.vue")["default"]
|
||||
AppSupport: typeof import("./components/app/Support.vue")["default"]
|
||||
ButtonPrimary: typeof import("./../../hoppscotch-ui/src/components/button/Primary.vue")["default"]
|
||||
ButtonSecondary: typeof import("./../../hoppscotch-ui/src/components/button/Secondary.vue")["default"]
|
||||
Collections: typeof import("./components/collections/index.vue")["default"]
|
||||
CollectionsAdd: typeof import("./components/collections/Add.vue")["default"]
|
||||
CollectionsAddFolder: typeof import("./components/collections/AddFolder.vue")["default"]
|
||||
CollectionsAddRequest: typeof import("./components/collections/AddRequest.vue")["default"]
|
||||
CollectionsCollection: typeof import("./components/collections/Collection.vue")["default"]
|
||||
CollectionsEdit: typeof import("./components/collections/Edit.vue")["default"]
|
||||
CollectionsEditFolder: typeof import("./components/collections/EditFolder.vue")["default"]
|
||||
CollectionsEditRequest: typeof import("./components/collections/EditRequest.vue")["default"]
|
||||
CollectionsGraphql: typeof import("./components/collections/graphql/index.vue")["default"]
|
||||
CollectionsGraphqlAdd: typeof import("./components/collections/graphql/Add.vue")["default"]
|
||||
CollectionsGraphqlAddFolder: typeof import("./components/collections/graphql/AddFolder.vue")["default"]
|
||||
CollectionsGraphqlAddRequest: typeof import("./components/collections/graphql/AddRequest.vue")["default"]
|
||||
CollectionsGraphqlCollection: typeof import("./components/collections/graphql/Collection.vue")["default"]
|
||||
CollectionsGraphqlEdit: typeof import("./components/collections/graphql/Edit.vue")["default"]
|
||||
CollectionsGraphqlEditFolder: typeof import("./components/collections/graphql/EditFolder.vue")["default"]
|
||||
CollectionsGraphqlEditRequest: typeof import("./components/collections/graphql/EditRequest.vue")["default"]
|
||||
CollectionsGraphqlFolder: typeof import("./components/collections/graphql/Folder.vue")["default"]
|
||||
CollectionsGraphqlImportExport: typeof import("./components/collections/graphql/ImportExport.vue")["default"]
|
||||
CollectionsGraphqlRequest: typeof import("./components/collections/graphql/Request.vue")["default"]
|
||||
CollectionsImportExport: typeof import("./components/collections/ImportExport.vue")["default"]
|
||||
CollectionsMyCollections: typeof import("./components/collections/MyCollections.vue")["default"]
|
||||
CollectionsRequest: typeof import("./components/collections/Request.vue")["default"]
|
||||
CollectionsSaveRequest: typeof import("./components/collections/SaveRequest.vue")["default"]
|
||||
CollectionsTeamCollections: typeof import("./components/collections/TeamCollections.vue")["default"]
|
||||
Environments: typeof import("./components/environments/index.vue")["default"]
|
||||
EnvironmentsAdd: typeof import("./components/environments/Add.vue")["default"]
|
||||
EnvironmentsImportExport: typeof import("./components/environments/ImportExport.vue")["default"]
|
||||
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"]
|
||||
FirebaseLogin: typeof import("./components/firebase/Login.vue")["default"]
|
||||
FirebaseLogout: typeof import("./components/firebase/Logout.vue")["default"]
|
||||
GraphqlAuthorization: typeof import("./components/graphql/Authorization.vue")["default"]
|
||||
GraphqlField: typeof import("./components/graphql/Field.vue")["default"]
|
||||
GraphqlHeaders: typeof import("./components/graphql/Headers.vue")["default"]
|
||||
GraphqlQuery: typeof import("./components/graphql/Query.vue")["default"]
|
||||
GraphqlRequest: typeof import("./components/graphql/Request.vue")["default"]
|
||||
GraphqlRequestOptions: typeof import("./components/graphql/RequestOptions.vue")["default"]
|
||||
GraphqlRequestTab: typeof import("./components/graphql/RequestTab.vue")["default"]
|
||||
GraphqlResponse: typeof import("./components/graphql/Response.vue")["default"]
|
||||
GraphqlSidebar: typeof import("./components/graphql/Sidebar.vue")["default"]
|
||||
GraphqlSubscriptionLog: typeof import("./components/graphql/SubscriptionLog.vue")["default"]
|
||||
GraphqlType: typeof import("./components/graphql/Type.vue")["default"]
|
||||
GraphqlTypeLink: typeof import("./components/graphql/TypeLink.vue")["default"]
|
||||
GraphqlVariable: typeof import("./components/graphql/Variable.vue")["default"]
|
||||
History: typeof import("./components/history/index.vue")["default"]
|
||||
HistoryGraphqlCard: typeof import("./components/history/graphql/Card.vue")["default"]
|
||||
HistoryRestCard: typeof import("./components/history/rest/Card.vue")["default"]
|
||||
HoppButtonPrimary: typeof import("@hoppscotch/ui")["HoppButtonPrimary"]
|
||||
HoppButtonSecondary: typeof import("@hoppscotch/ui")["HoppButtonSecondary"]
|
||||
HoppSmartAnchor: typeof import("@hoppscotch/ui")["HoppSmartAnchor"]
|
||||
HoppSmartAutoComplete: typeof import("@hoppscotch/ui")["HoppSmartAutoComplete"]
|
||||
HoppSmartCheckbox: typeof import("@hoppscotch/ui")["HoppSmartCheckbox"]
|
||||
HoppSmartConfirmModal: typeof import("@hoppscotch/ui")["HoppSmartConfirmModal"]
|
||||
HoppSmartExpand: typeof import("@hoppscotch/ui")["HoppSmartExpand"]
|
||||
HoppSmartFileChip: typeof import("@hoppscotch/ui")["HoppSmartFileChip"]
|
||||
HoppSmartInput: typeof import("@hoppscotch/ui")["HoppSmartInput"]
|
||||
HoppSmartIntersection: typeof import("@hoppscotch/ui")["HoppSmartIntersection"]
|
||||
HoppSmartItem: typeof import("@hoppscotch/ui")["HoppSmartItem"]
|
||||
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"]
|
||||
HoppSmartRadio: typeof import("@hoppscotch/ui")["HoppSmartRadio"]
|
||||
HoppSmartRadioGroup: typeof import("@hoppscotch/ui")["HoppSmartRadioGroup"]
|
||||
HoppSmartSlideOver: typeof import("@hoppscotch/ui")["HoppSmartSlideOver"]
|
||||
HoppSmartSpinner: typeof import("@hoppscotch/ui")["HoppSmartSpinner"]
|
||||
HoppSmartTab: typeof import("@hoppscotch/ui")["HoppSmartTab"]
|
||||
HoppSmartTabs: typeof import("@hoppscotch/ui")["HoppSmartTabs"]
|
||||
HoppSmartToggle: typeof import("@hoppscotch/ui")["HoppSmartToggle"]
|
||||
HoppSmartTree: typeof import("@hoppscotch/ui")["HoppSmartTree"]
|
||||
HoppSmartWindow: typeof import("@hoppscotch/ui")["HoppSmartWindow"]
|
||||
HoppSmartWindows: typeof import("@hoppscotch/ui")["HoppSmartWindows"]
|
||||
HttpAuthorization: typeof import("./components/http/Authorization.vue")["default"]
|
||||
HttpAuthorizationApiKey: typeof import("./components/http/authorization/ApiKey.vue")["default"]
|
||||
HttpAuthorizationBasic: typeof import("./components/http/authorization/Basic.vue")["default"]
|
||||
HttpBody: typeof import("./components/http/Body.vue")["default"]
|
||||
HttpBodyParameters: typeof import("./components/http/BodyParameters.vue")["default"]
|
||||
HttpCodegenModal: typeof import("./components/http/CodegenModal.vue")["default"]
|
||||
HttpHeaders: typeof import("./components/http/Headers.vue")["default"]
|
||||
HttpImportCurl: typeof import("./components/http/ImportCurl.vue")["default"]
|
||||
HttpOAuth2Authorization: typeof import("./components/http/OAuth2Authorization.vue")["default"]
|
||||
HttpParameters: typeof import("./components/http/Parameters.vue")["default"]
|
||||
HttpPreRequestScript: typeof import("./components/http/PreRequestScript.vue")["default"]
|
||||
HttpRawBody: typeof import("./components/http/RawBody.vue")["default"]
|
||||
HttpReqChangeConfirmModal: typeof import("./components/http/ReqChangeConfirmModal.vue")["default"]
|
||||
HttpRequest: typeof import("./components/http/Request.vue")["default"]
|
||||
HttpRequestOptions: typeof import("./components/http/RequestOptions.vue")["default"]
|
||||
HttpRequestTab: typeof import("./components/http/RequestTab.vue")["default"]
|
||||
HttpResponse: typeof import("./components/http/Response.vue")["default"]
|
||||
HttpResponseMeta: typeof import("./components/http/ResponseMeta.vue")["default"]
|
||||
HttpSidebar: typeof import("./components/http/Sidebar.vue")["default"]
|
||||
HttpTabHead: typeof import("./components/http/TabHead.vue")["default"]
|
||||
HttpTestResult: typeof import("./components/http/TestResult.vue")["default"]
|
||||
HttpTestResultEntry: typeof import("./components/http/TestResultEntry.vue")["default"]
|
||||
HttpTestResultEnv: typeof import("./components/http/TestResultEnv.vue")["default"]
|
||||
HttpTestResultReport: typeof import("./components/http/TestResultReport.vue")["default"]
|
||||
HttpTests: typeof import("./components/http/Tests.vue")["default"]
|
||||
HttpURLEncodedParams: typeof import("./components/http/URLEncodedParams.vue")["default"]
|
||||
IconLucideActivity: typeof import("~icons/lucide/activity")["default"]
|
||||
IconLucideAlertTriangle: typeof import("~icons/lucide/alert-triangle")["default"]
|
||||
IconLucideArrowLeft: typeof import("~icons/lucide/arrow-left")["default"]
|
||||
IconLucideArrowUpRight: typeof import("~icons/lucide/arrow-up-right")["default"]
|
||||
IconLucideCheckCircle: typeof import("~icons/lucide/check-circle")["default"]
|
||||
IconLucideChevronRight: typeof import("~icons/lucide/chevron-right")["default"]
|
||||
IconLucideGlobe: typeof import("~icons/lucide/globe")["default"]
|
||||
IconLucideHelpCircle: typeof import("~icons/lucide/help-circle")["default"]
|
||||
IconLucideInbox: typeof import("~icons/lucide/inbox")["default"]
|
||||
IconLucideInfo: typeof import("~icons/lucide/info")["default"]
|
||||
IconLucideLayers: typeof import("~icons/lucide/layers")["default"]
|
||||
IconLucideListEnd: typeof import("~icons/lucide/list-end")["default"]
|
||||
IconLucideMinus: typeof import("~icons/lucide/minus")["default"]
|
||||
IconLucideSearch: typeof import("~icons/lucide/search")["default"]
|
||||
IconLucideUsers: typeof import("~icons/lucide/users")["default"]
|
||||
IconLucideVerified: typeof import("~icons/lucide/verified")["default"]
|
||||
InterceptorsExtensionSubtitle: typeof import("./components/interceptors/ExtensionSubtitle.vue")["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"]
|
||||
ProfileShortcodes: typeof import("./components/profile/Shortcodes.vue")["default"]
|
||||
ProfileUserDelete: typeof import("./components/profile/UserDelete.vue")["default"]
|
||||
RealtimeCommunication: typeof import("./components/realtime/Communication.vue")["default"]
|
||||
RealtimeConnectionConfig: typeof import("./components/realtime/ConnectionConfig.vue")["default"]
|
||||
RealtimeLog: typeof import("./components/realtime/Log.vue")["default"]
|
||||
RealtimeLogEntry: typeof import("./components/realtime/LogEntry.vue")["default"]
|
||||
RealtimeSubscription: typeof import("./components/realtime/Subscription.vue")["default"]
|
||||
SettingsExtension: typeof import("./components/settings/Extension.vue")["default"]
|
||||
SettingsProxy: typeof import("./components/settings/Proxy.vue")["default"]
|
||||
SmartAccentModePicker: typeof import("./components/smart/AccentModePicker.vue")["default"]
|
||||
SmartAnchor: typeof import("./../../hoppscotch-ui/src/components/smart/Anchor.vue")["default"]
|
||||
SmartAutoComplete: typeof import("./../../hoppscotch-ui/src/components/smart/AutoComplete.vue")["default"]
|
||||
SmartChangeLanguage: typeof import("./components/smart/ChangeLanguage.vue")["default"]
|
||||
SmartCheckbox: typeof import("./../../hoppscotch-ui/src/components/smart/Checkbox.vue")["default"]
|
||||
SmartColorModePicker: typeof import("./components/smart/ColorModePicker.vue")["default"]
|
||||
SmartConfirmModal: typeof import("./../../hoppscotch-ui/src/components/smart/ConfirmModal.vue")["default"]
|
||||
SmartEnvInput: typeof import("./components/smart/EnvInput.vue")["default"]
|
||||
SmartExpand: typeof import("./../../hoppscotch-ui/src/components/smart/Expand.vue")["default"]
|
||||
SmartFileChip: typeof import("./../../hoppscotch-ui/src/components/smart/FileChip.vue")["default"]
|
||||
SmartFontSizePicker: typeof import("./components/smart/FontSizePicker.vue")["default"]
|
||||
SmartInput: typeof import("./../../hoppscotch-ui/src/components/smart/Input.vue")["default"]
|
||||
SmartIntersection: typeof import("./../../hoppscotch-ui/src/components/smart/Intersection.vue")["default"]
|
||||
SmartItem: typeof import("./../../hoppscotch-ui/src/components/smart/Item.vue")["default"]
|
||||
SmartLink: typeof import("./../../hoppscotch-ui/src/components/smart/Link.vue")["default"]
|
||||
SmartModal: typeof import("./../../hoppscotch-ui/src/components/smart/Modal.vue")["default"]
|
||||
SmartPicture: typeof import("./../../hoppscotch-ui/src/components/smart/Picture.vue")["default"]
|
||||
SmartPlaceholder: typeof import("./../../hoppscotch-ui/src/components/smart/Placeholder.vue")["default"]
|
||||
SmartProgressRing: typeof import("./../../hoppscotch-ui/src/components/smart/ProgressRing.vue")["default"]
|
||||
SmartRadio: typeof import("./../../hoppscotch-ui/src/components/smart/Radio.vue")["default"]
|
||||
SmartRadioGroup: typeof import("./../../hoppscotch-ui/src/components/smart/RadioGroup.vue")["default"]
|
||||
SmartSlideOver: typeof import("./../../hoppscotch-ui/src/components/smart/SlideOver.vue")["default"]
|
||||
SmartSpinner: typeof import("./../../hoppscotch-ui/src/components/smart/Spinner.vue")["default"]
|
||||
SmartTab: typeof import("./../../hoppscotch-ui/src/components/smart/Tab.vue")["default"]
|
||||
SmartTabs: typeof import("./../../hoppscotch-ui/src/components/smart/Tabs.vue")["default"]
|
||||
SmartToggle: typeof import("./../../hoppscotch-ui/src/components/smart/Toggle.vue")["default"]
|
||||
SmartTree: typeof import("./../../hoppscotch-ui/src/components/smart/Tree.vue")["default"]
|
||||
SmartTreeBranch: typeof import("./../../hoppscotch-ui/src/components/smart/TreeBranch.vue")["default"]
|
||||
SmartWindow: typeof import("./../../hoppscotch-ui/src/components/smart/Window.vue")["default"]
|
||||
SmartWindows: typeof import("./../../hoppscotch-ui/src/components/smart/Windows.vue")["default"]
|
||||
TabPrimary: typeof import("./components/tab/Primary.vue")["default"]
|
||||
TabSecondary: typeof import("./components/tab/Secondary.vue")["default"]
|
||||
Teams: typeof import("./components/teams/index.vue")["default"]
|
||||
TeamsAdd: typeof import("./components/teams/Add.vue")["default"]
|
||||
TeamsEdit: typeof import("./components/teams/Edit.vue")["default"]
|
||||
TeamsInvite: typeof import("./components/teams/Invite.vue")["default"]
|
||||
TeamsMemberStack: typeof import("./components/teams/MemberStack.vue")["default"]
|
||||
TeamsModal: typeof import("./components/teams/Modal.vue")["default"]
|
||||
TeamsTeam: typeof import("./components/teams/Team.vue")["default"]
|
||||
Tippy: typeof import("vue-tippy")["Tippy"]
|
||||
WorkspaceCurrent: typeof import("./components/workspace/Current.vue")["default"]
|
||||
WorkspaceSelector: typeof import("./components/workspace/Selector.vue")["default"]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<template>
|
||||
<AppShortcuts :show="showShortcuts" @close="showShortcuts = false" />
|
||||
<AppShare :show="showShare" @hide-modal="showShare = false" />
|
||||
<AppSocial :show="showSocial" @hide-modal="showSocial = false" />
|
||||
<FirebaseLogin :show="showLogin" @hide-modal="showLogin = false" />
|
||||
|
||||
<HoppSmartConfirmModal
|
||||
@@ -26,6 +27,7 @@ const t = useI18n()
|
||||
|
||||
const showShortcuts = ref(false)
|
||||
const showShare = ref(false)
|
||||
const showSocial = ref(false)
|
||||
const showLogin = ref(false)
|
||||
|
||||
const confirmRemove = ref(false)
|
||||
@@ -58,6 +60,10 @@ defineActionHandler("modals.share.toggle", () => {
|
||||
showShare.value = !showShare.value
|
||||
})
|
||||
|
||||
defineActionHandler("modals.social.toggle", () => {
|
||||
showSocial.value = !showSocial.value
|
||||
})
|
||||
|
||||
defineActionHandler("modals.login.toggle", () => {
|
||||
showLogin.value = !showLogin.value
|
||||
})
|
||||
|
||||
135
packages/hoppscotch-common/src/components/app/Social.vue
Normal file
135
packages/hoppscotch-common/src/components/app/Social.vue
Normal file
@@ -0,0 +1,135 @@
|
||||
<template>
|
||||
<HoppSmartModal
|
||||
v-if="show"
|
||||
dialog
|
||||
:title="t('app.social_links')"
|
||||
@close="hideModal"
|
||||
>
|
||||
<template #body>
|
||||
<div class="flex flex-col space-y-2">
|
||||
<div class="grid grid-cols-3 gap-4">
|
||||
<a
|
||||
v-for="(platform, index) in platforms"
|
||||
:key="`platform-${index}`"
|
||||
:href="platform.link"
|
||||
target="_blank"
|
||||
class="social-link"
|
||||
tabindex="0"
|
||||
>
|
||||
<component :is="platform.icon" class="w-6 h-6" />
|
||||
<span class="mt-3">
|
||||
{{ platform.name }}
|
||||
</span>
|
||||
</a>
|
||||
<button class="social-link" @click="copyAppLink">
|
||||
<component :is="copyIcon" class="w-6 h-6 text-xl" />
|
||||
<span class="mt-3">
|
||||
{{ t("app.copy") }}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #footer>
|
||||
<p class="text-secondaryLight">
|
||||
{{ t("app.social_description") }}
|
||||
</p>
|
||||
</template>
|
||||
</HoppSmartModal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useI18n } from "@composables/i18n"
|
||||
import { useToast } from "@composables/toast"
|
||||
import { refAutoReset } from "@vueuse/core"
|
||||
import { copyToClipboard } from "~/helpers/utils/clipboard"
|
||||
import IconFacebook from "~icons/brands/facebook"
|
||||
import IconLinkedIn from "~icons/brands/linkedin"
|
||||
import IconReddit from "~icons/brands/reddit"
|
||||
import IconTwitter from "~icons/brands/twitter"
|
||||
import IconCheck from "~icons/lucide/check"
|
||||
import IconCopy from "~icons/lucide/copy"
|
||||
import IconGitHub from "~icons/lucide/github"
|
||||
|
||||
const t = useI18n()
|
||||
|
||||
const toast = useToast()
|
||||
|
||||
defineProps<{
|
||||
show: boolean
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: "hide-modal"): void
|
||||
}>()
|
||||
|
||||
const url = "https://hoppscotch.io"
|
||||
|
||||
const copyIcon = refAutoReset<typeof IconCopy | typeof IconCheck>(
|
||||
IconCopy,
|
||||
1000
|
||||
)
|
||||
|
||||
const platforms = [
|
||||
{
|
||||
name: "GitHub",
|
||||
icon: IconGitHub,
|
||||
link: `https://hoppscotch.io/github`,
|
||||
},
|
||||
{
|
||||
name: "Twitter",
|
||||
icon: IconTwitter,
|
||||
link: `https://twitter.com/hoppscotch_io`,
|
||||
},
|
||||
{
|
||||
name: "Facebook",
|
||||
icon: IconFacebook,
|
||||
link: `https://www.facebook.com/hoppscotch.io`,
|
||||
},
|
||||
{
|
||||
name: "Reddit",
|
||||
icon: IconReddit,
|
||||
link: `https://www.reddit.com/r/hoppscotch`,
|
||||
},
|
||||
{
|
||||
name: "LinkedIn",
|
||||
icon: IconLinkedIn,
|
||||
link: `https://www.linkedin.com/company/hoppscotch/`,
|
||||
},
|
||||
]
|
||||
|
||||
const copyAppLink = () => {
|
||||
copyToClipboard(url)
|
||||
copyIcon.value = IconCheck
|
||||
toast.success(`${t("state.copied_to_clipboard")}`)
|
||||
}
|
||||
|
||||
const hideModal = () => {
|
||||
emit("hide-modal")
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.social-link {
|
||||
@apply border border-dividerLight;
|
||||
@apply rounded;
|
||||
@apply flex-col flex;
|
||||
@apply p-4;
|
||||
@apply items-center;
|
||||
@apply justify-center;
|
||||
@apply font-semibold;
|
||||
@apply hover: (bg-primaryLight text-secondaryDark);
|
||||
@apply focus: outline-none;
|
||||
@apply focus-visible: border-divider;
|
||||
|
||||
svg {
|
||||
@apply opacity-80;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
svg {
|
||||
@apply opacity-100;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,3 +0,0 @@
|
||||
<template>
|
||||
<IconLucideCheckCircle class="text-accent" />
|
||||
</template>
|
||||
@@ -111,7 +111,6 @@ import {
|
||||
SwitchWorkspaceSpotlightSearcherService,
|
||||
WorkspaceSpotlightSearcherService,
|
||||
} from "~/services/spotlight/searchers/workspace.searcher"
|
||||
import { InterceptorSpotlightSearcherService } from "~/services/spotlight/searchers/interceptor.searcher"
|
||||
|
||||
const t = useI18n()
|
||||
|
||||
@@ -139,7 +138,6 @@ useService(EnvironmentsSpotlightSearcherService)
|
||||
useService(SwitchEnvSpotlightSearcherService)
|
||||
useService(WorkspaceSpotlightSearcherService)
|
||||
useService(SwitchWorkspaceSpotlightSearcherService)
|
||||
useService(InterceptorSpotlightSearcherService)
|
||||
|
||||
const search = ref("")
|
||||
|
||||
@@ -266,3 +264,4 @@ function newUseArrowKeysForNavigation() {
|
||||
return { selectedEntry }
|
||||
}
|
||||
</script>
|
||||
~/services/spotlight/searchers/workspace.searcher
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
@click="
|
||||
emit('add-request', {
|
||||
path: `${collectionIndex}`,
|
||||
index: collection.requests.length,
|
||||
})
|
||||
"
|
||||
/>
|
||||
@@ -220,7 +219,6 @@ import {
|
||||
moveGraphqlRequest,
|
||||
} from "~/newstore/collections"
|
||||
import { Picked } from "~/helpers/types/HoppPicked"
|
||||
import { getTabsRefTo } from "~/helpers/graphql/tab"
|
||||
|
||||
const props = defineProps({
|
||||
picked: { type: Object, default: null },
|
||||
@@ -295,22 +293,6 @@ const removeCollection = () => {
|
||||
emit("select", null)
|
||||
}
|
||||
|
||||
const possibleTabs = getTabsRefTo((tab) => {
|
||||
const ctx = tab.document.saveContext
|
||||
|
||||
if (!ctx) return false
|
||||
|
||||
return (
|
||||
ctx.originLocation === "user-collection" &&
|
||||
ctx.folderPath.startsWith(props.collectionIndex.toString())
|
||||
)
|
||||
})
|
||||
|
||||
for (const tab of possibleTabs) {
|
||||
tab.value.document.saveContext = undefined
|
||||
tab.value.document.isDirty = true
|
||||
}
|
||||
|
||||
removeGraphqlCollection(props.collectionIndex, props.collection.id)
|
||||
toast.success(`${t("state.deleted")}`)
|
||||
}
|
||||
|
||||
@@ -34,12 +34,7 @@
|
||||
:icon="IconFilePlus"
|
||||
:title="t('request.new')"
|
||||
class="hidden group-hover:inline-flex"
|
||||
@click="
|
||||
emit('add-request', {
|
||||
path: folderPath,
|
||||
index: folder.requests.length,
|
||||
})
|
||||
"
|
||||
@click="emit('add-request', { path: folderPath })"
|
||||
/>
|
||||
<HoppButtonSecondary
|
||||
v-tippy="{ theme: 'tooltip' }"
|
||||
@@ -203,7 +198,6 @@ import { useI18n } from "@composables/i18n"
|
||||
import { useColorMode } from "@composables/theming"
|
||||
import { removeGraphqlFolder, moveGraphqlRequest } from "~/newstore/collections"
|
||||
import { computed, ref } from "vue"
|
||||
import { getTabsRefTo } from "~/helpers/graphql/tab"
|
||||
|
||||
const toast = useToast()
|
||||
const t = useI18n()
|
||||
@@ -255,8 +249,10 @@ const collectionIcon = computed(() => {
|
||||
|
||||
const pick = () => {
|
||||
emit("select", {
|
||||
pickedType: "gql-my-folder",
|
||||
folderPath: props.folderPath,
|
||||
picked: {
|
||||
pickedType: "gql-my-folder",
|
||||
folderPath: props.folderPath,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -277,22 +273,6 @@ const removeFolder = () => {
|
||||
emit("select", { picked: null })
|
||||
}
|
||||
|
||||
const possibleTabs = getTabsRefTo((tab) => {
|
||||
const ctx = tab.document.saveContext
|
||||
|
||||
if (!ctx) return false
|
||||
|
||||
return (
|
||||
ctx.originLocation === "user-collection" &&
|
||||
ctx.folderPath.startsWith(props.folderPath)
|
||||
)
|
||||
})
|
||||
|
||||
for (const tab of possibleTabs) {
|
||||
tab.value.document.saveContext = undefined
|
||||
tab.value.document.isDirty = true
|
||||
}
|
||||
|
||||
removeGraphqlFolder(props.folderPath, props.folder.id)
|
||||
toast.success(t("state.deleted"))
|
||||
}
|
||||
|
||||
@@ -20,28 +20,22 @@
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="flex items-center flex-1 min-w-0 py-2 pr-2 cursor-pointer transition group-hover:text-secondaryDark"
|
||||
class="flex flex-1 min-w-0 py-2 pr-2 cursor-pointer transition group-hover:text-secondaryDark"
|
||||
@click="selectRequest()"
|
||||
>
|
||||
<span class="truncate" :class="{ 'text-accent': isSelected }">
|
||||
{{ request.name }}
|
||||
</span>
|
||||
<span
|
||||
v-if="isActive"
|
||||
v-tippy="{ theme: 'tooltip' }"
|
||||
class="relative h-1.5 w-1.5 flex flex-shrink-0 mx-3"
|
||||
:title="`${t('collection.request_in_use')}`"
|
||||
>
|
||||
<span
|
||||
class="absolute inline-flex flex-shrink-0 w-full h-full bg-green-500 rounded-full opacity-75 animate-ping"
|
||||
>
|
||||
</span>
|
||||
<span
|
||||
class="relative inline-flex flex-shrink-0 rounded-full h-1.5 w-1.5 bg-green-500"
|
||||
></span>
|
||||
</span>
|
||||
</span>
|
||||
<div class="flex">
|
||||
<HoppButtonSecondary
|
||||
v-if="!saveRequest"
|
||||
v-tippy="{ theme: 'tooltip' }"
|
||||
:icon="IconRotateCCW"
|
||||
:title="t('action.restore')"
|
||||
class="hidden group-hover:inline-flex"
|
||||
@click="selectRequest()"
|
||||
/>
|
||||
<span>
|
||||
<tippy
|
||||
ref="options"
|
||||
@@ -127,6 +121,7 @@
|
||||
<script setup lang="ts">
|
||||
import IconCheckCircle from "~icons/lucide/check-circle"
|
||||
import IconFile from "~icons/lucide/file"
|
||||
import IconRotateCCW from "~icons/lucide/rotate-ccw"
|
||||
import IconMoreVertical from "~icons/lucide/more-vertical"
|
||||
import IconEdit from "~icons/lucide/edit"
|
||||
import IconCopy from "~icons/lucide/copy"
|
||||
@@ -137,12 +132,7 @@ import { useToast } from "@composables/toast"
|
||||
import { HoppGQLRequest, makeGQLRequest } from "@hoppscotch/data"
|
||||
import { cloneDeep } from "lodash-es"
|
||||
import { removeGraphqlRequest } from "~/newstore/collections"
|
||||
import {
|
||||
createNewTab,
|
||||
getTabRefWithSaveContext,
|
||||
currentTabID,
|
||||
currentActiveTab,
|
||||
} from "~/helpers/graphql/tab"
|
||||
import { createNewTab } from "~/helpers/graphql/tab"
|
||||
|
||||
// Template refs
|
||||
const tippyActions = ref<any | null>(null)
|
||||
@@ -164,18 +154,6 @@ const props = defineProps({
|
||||
requestIndex: { type: Number, default: null },
|
||||
})
|
||||
|
||||
const isActive = computed(() => {
|
||||
const saveCtx = currentActiveTab.value?.document.saveContext
|
||||
|
||||
if (!saveCtx) return false
|
||||
|
||||
return (
|
||||
saveCtx.originLocation === "user-collection" &&
|
||||
saveCtx.folderPath === props.folderPath &&
|
||||
saveCtx.requestIndex === props.requestIndex
|
||||
)
|
||||
})
|
||||
|
||||
// TODO: Better types please
|
||||
const emit = defineEmits(["select", "edit-request", "duplicate-request"])
|
||||
|
||||
@@ -201,24 +179,7 @@ const selectRequest = () => {
|
||||
if (props.saveRequest) {
|
||||
pick()
|
||||
} else {
|
||||
const possibleTab = getTabRefWithSaveContext({
|
||||
originLocation: "user-collection",
|
||||
folderPath: props.folderPath,
|
||||
requestIndex: props.requestIndex,
|
||||
})
|
||||
|
||||
// Switch to that request if that request is open
|
||||
if (possibleTab) {
|
||||
currentTabID.value = possibleTab.value.id
|
||||
return
|
||||
}
|
||||
|
||||
createNewTab({
|
||||
saveContext: {
|
||||
originLocation: "user-collection",
|
||||
folderPath: props.folderPath,
|
||||
requestIndex: props.requestIndex,
|
||||
},
|
||||
request: cloneDeep(
|
||||
makeGQLRequest({
|
||||
name: props.request.name,
|
||||
@@ -252,18 +213,6 @@ const removeRequest = () => {
|
||||
emit("select", null)
|
||||
}
|
||||
|
||||
// Detach the request from any of the tabs
|
||||
const possibleTab = getTabRefWithSaveContext({
|
||||
originLocation: "user-collection",
|
||||
folderPath: props.folderPath,
|
||||
requestIndex: props.requestIndex,
|
||||
})
|
||||
|
||||
if (possibleTab) {
|
||||
possibleTab.value.document.saveContext = undefined
|
||||
possibleTab.value.document.isDirty = true
|
||||
}
|
||||
|
||||
removeGraphqlRequest(props.folderPath, props.requestIndex, props.request.id)
|
||||
toast.success(`${t("state.deleted")}`)
|
||||
}
|
||||
|
||||
@@ -265,7 +265,7 @@ export default defineComponent({
|
||||
this.$data.editingCollectionIndex = collectionIndex
|
||||
this.displayModalEdit(true)
|
||||
},
|
||||
onAddRequest({ name, path, index }) {
|
||||
onAddRequest({ name, path }) {
|
||||
const newRequest = {
|
||||
...currentActiveTab.value.document.request,
|
||||
name,
|
||||
@@ -274,11 +274,6 @@ export default defineComponent({
|
||||
saveGraphqlRequestAs(path, newRequest)
|
||||
|
||||
createNewTab({
|
||||
saveContext: {
|
||||
originLocation: "user-collection",
|
||||
folderPath: path,
|
||||
requestIndex: index,
|
||||
},
|
||||
request: newRequest,
|
||||
isDirty: false,
|
||||
})
|
||||
|
||||
@@ -239,7 +239,6 @@ import {
|
||||
resetTeamRequestsContext,
|
||||
} from "~/helpers/collection/collection"
|
||||
import { currentReorderingStatus$ } from "~/newstore/reordering"
|
||||
import { defineActionHandler } from "~/helpers/actions"
|
||||
|
||||
const t = useI18n()
|
||||
const toast = useToast()
|
||||
@@ -2068,8 +2067,4 @@ const getErrorMessage = (err: GQLError<string>) => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
defineActionHandler("collection.new", () => {
|
||||
displayModalAdd(true)
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -34,13 +34,6 @@
|
||||
@hide-modal="displayModalNew(false)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<HoppSmartConfirmModal
|
||||
:show="showConfirmRemoveEnvModal"
|
||||
:title="t('confirm.remove_team')"
|
||||
@hide-modal="showConfirmRemoveEnvModal = false"
|
||||
@resolve="removeSelectedEnvironment()"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
@@ -51,7 +44,6 @@ import { GetMyTeamsQuery } from "~/helpers/backend/graphql"
|
||||
import { useReadonlyStream, useStream } from "@composables/stream"
|
||||
import { useI18n } from "~/composables/i18n"
|
||||
import {
|
||||
getSelectedEnvironmentIndex,
|
||||
globalEnv$,
|
||||
selectedEnvironmentIndex$,
|
||||
setSelectedEnvironmentIndex,
|
||||
@@ -62,15 +54,8 @@ import { workspaceStatus$ } from "~/newstore/workspace"
|
||||
import TeamListAdapter from "~/helpers/teams/TeamListAdapter"
|
||||
import { useLocalState } from "~/newstore/localstate"
|
||||
import { onLoggedIn } from "~/composables/auth"
|
||||
import { pipe } from "fp-ts/function"
|
||||
import * as TE from "fp-ts/TaskEither"
|
||||
import { GQLError } from "~/helpers/backend/GQLClient"
|
||||
import { deleteEnvironment } from "~/newstore/environments"
|
||||
import { deleteTeamEnvironment } from "~/helpers/backend/mutations/TeamEnvironment"
|
||||
import { useToast } from "~/composables/toast"
|
||||
|
||||
const t = useI18n()
|
||||
const toast = useToast()
|
||||
|
||||
type EnvironmentType = "my-environments" | "team-environments"
|
||||
|
||||
@@ -183,7 +168,6 @@ watch(
|
||||
}
|
||||
)
|
||||
|
||||
const showConfirmRemoveEnvModal = ref(false)
|
||||
const showModalNew = ref(false)
|
||||
const showModalDetails = ref(false)
|
||||
const action = ref<"new" | "edit">("edit")
|
||||
@@ -210,30 +194,6 @@ const editEnvironment = (environmentIndex: "Global") => {
|
||||
displayModalEdit(true)
|
||||
}
|
||||
|
||||
const removeSelectedEnvironment = () => {
|
||||
const selectedEnvIndex = getSelectedEnvironmentIndex()
|
||||
if (selectedEnvIndex?.type === "NO_ENV_SELECTED") return
|
||||
|
||||
if (selectedEnvIndex?.type === "MY_ENV") {
|
||||
deleteEnvironment(selectedEnvIndex.index)
|
||||
toast.success(`${t("state.deleted")}`)
|
||||
}
|
||||
|
||||
if (selectedEnvIndex?.type === "TEAM_ENV") {
|
||||
pipe(
|
||||
deleteTeamEnvironment(selectedEnvIndex.teamEnvID),
|
||||
TE.match(
|
||||
(err: GQLError<string>) => {
|
||||
console.error(err)
|
||||
},
|
||||
() => {
|
||||
toast.success(`${t("team_environment.deleted")}`)
|
||||
}
|
||||
)
|
||||
)()
|
||||
}
|
||||
}
|
||||
|
||||
const resetSelectedData = () => {
|
||||
editingEnvironmentIndex.value = null
|
||||
}
|
||||
@@ -243,10 +203,6 @@ defineActionHandler("modals.environment.new", () => {
|
||||
showModalDetails.value = true
|
||||
})
|
||||
|
||||
defineActionHandler("modals.environment.delete-selected", () => {
|
||||
showConfirmRemoveEnvModal.value = true
|
||||
})
|
||||
|
||||
defineActionHandler(
|
||||
"modals.my.environment.edit",
|
||||
({ envName, variableName }) => {
|
||||
|
||||
@@ -312,10 +312,8 @@ const authProviders: AuthProviderItem[] = [
|
||||
},
|
||||
]
|
||||
|
||||
// Do not format the `import.meta.env.VITE_ALLOWED_AUTH_PROVIDERS` call into multiple lines!
|
||||
// prettier-ignore
|
||||
const allowedAuthProvidersIDsString =
|
||||
import.meta.env.VITE_ALLOWED_AUTH_PROVIDERS
|
||||
const allowedAuthProvidersIDsString: string | undefined = import.meta.env
|
||||
.VITE_ALLOWED_AUTH_PROVIDERS
|
||||
|
||||
const allowedAuthProvidersIDs = allowedAuthProvidersIDsString
|
||||
? allowedAuthProvidersIDsString.split(",")
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="flex flex-col flex-1">
|
||||
<div
|
||||
class="sticky top-sidebarPrimaryStickyFold z-10 flex items-center justify-between pl-4 border-y bg-primary border-dividerLight"
|
||||
class="sticky z-10 flex items-center justify-between flex-shrink-0 pl-4 overflow-x-auto border-b bg-primary border-dividerLight"
|
||||
>
|
||||
<span class="flex items-center">
|
||||
<label class="font-semibold truncate text-secondaryLight">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div
|
||||
class="sticky top-sidebarPrimaryStickyFold z-10 flex items-center justify-between pl-4 border-y bg-primary border-dividerLight"
|
||||
class="sticky z-10 flex items-center justify-between pl-4 border-b bg-primary border-dividerLight"
|
||||
>
|
||||
<label class="font-semibold text-secondaryLight">
|
||||
{{ t("tab.headers") }}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div
|
||||
class="sticky top-sidebarPrimaryStickyFold z-10 flex items-center justify-between pl-4 border-y bg-primary border-dividerLight"
|
||||
class="sticky z-10 flex items-center justify-between pl-4 border-b bg-primary border-dividerLight gqlRunQuery"
|
||||
>
|
||||
<label class="font-semibold text-secondaryLight">
|
||||
{{ t("request.query") }}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="flex flex-col flex-1 h-full">
|
||||
<HoppSmartTabs
|
||||
v-model="selectedOptionTab"
|
||||
styles="sticky top-0 bg-primary z-10 border-b-0"
|
||||
styles="sticky bg-primary z-10"
|
||||
:render-inactive-tabs="true"
|
||||
>
|
||||
<HoppSmartTab
|
||||
@@ -67,7 +67,6 @@ import {
|
||||
} from "~/helpers/graphql/connection"
|
||||
import { useService } from "dioc/vue"
|
||||
import { InterceptorService } from "~/services/interceptor.service"
|
||||
import { editGraphqlRequest } from "~/newstore/collections"
|
||||
|
||||
type OptionTabs = "query" | "headers" | "variables" | "authorization"
|
||||
const selectedOptionTab = ref<OptionTabs>("query")
|
||||
@@ -181,29 +180,12 @@ const hideRequestModal = () => {
|
||||
showSaveRequestModal.value = false
|
||||
}
|
||||
const saveRequest = () => {
|
||||
if (
|
||||
currentActiveTab.value.document.saveContext &&
|
||||
currentActiveTab.value.document.saveContext.originLocation ===
|
||||
"user-collection"
|
||||
) {
|
||||
editGraphqlRequest(
|
||||
currentActiveTab.value.document.saveContext.folderPath,
|
||||
currentActiveTab.value.document.saveContext.requestIndex,
|
||||
currentActiveTab.value.document.request
|
||||
)
|
||||
|
||||
currentActiveTab.value.document.isDirty = false
|
||||
} else {
|
||||
showSaveRequestModal.value = true
|
||||
}
|
||||
showSaveRequestModal.value = true
|
||||
}
|
||||
const clearGQLQuery = () => {
|
||||
request.value.query = ""
|
||||
}
|
||||
defineActionHandler("request.send-cancel", runQuery)
|
||||
defineActionHandler("request.save", saveRequest)
|
||||
defineActionHandler("request.save-as", () => {
|
||||
showSaveRequestModal.value = true
|
||||
})
|
||||
defineActionHandler("request.reset", clearGQLQuery)
|
||||
</script>
|
||||
|
||||
@@ -129,7 +129,9 @@ const downloadResponse = (str: string) => {
|
||||
}
|
||||
|
||||
defineActionHandler("response.file.download", () =>
|
||||
downloadResponse(responseString.value)
|
||||
downloadResponse.bind(responseString.value)
|
||||
)
|
||||
defineActionHandler("response.copy", () =>
|
||||
copyResponse.bind(responseString.value)
|
||||
)
|
||||
defineActionHandler("response.copy", () => copyResponse(responseString.value))
|
||||
</script>
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
<template>
|
||||
<div
|
||||
v-tippy="{ theme: 'tooltip', delay: [500, 20] }"
|
||||
:title="tab.document.request.name"
|
||||
class="truncate px-2 flex items-center"
|
||||
@dblclick="emit('open-rename-modal')"
|
||||
@contextmenu.prevent="options?.tippy?.show()"
|
||||
@click.middle="emit('close-tab')"
|
||||
>
|
||||
<tippy
|
||||
ref="options"
|
||||
trigger="manual"
|
||||
interactive
|
||||
theme="popover"
|
||||
:on-shown="() => tippyActions!.focus()"
|
||||
>
|
||||
<span class="leading-8 px-2 truncate">
|
||||
{{ tab.document.request.name }}
|
||||
</span>
|
||||
<template #content="{ hide }">
|
||||
<div
|
||||
ref="tippyActions"
|
||||
class="flex flex-col focus:outline-none"
|
||||
tabindex="0"
|
||||
@keyup.r="renameAction?.$el.click()"
|
||||
@keyup.d="duplicateAction?.$el.click()"
|
||||
@keyup.w="closeAction?.$el.click()"
|
||||
@keyup.x="closeOthersAction?.$el.click()"
|
||||
@keyup.escape="hide()"
|
||||
>
|
||||
<HoppSmartItem
|
||||
ref="renameAction"
|
||||
:icon="IconFileEdit"
|
||||
:label="t('request.rename')"
|
||||
:shortcut="['R']"
|
||||
@click="
|
||||
() => {
|
||||
emit('open-rename-modal')
|
||||
hide()
|
||||
}
|
||||
"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
ref="duplicateAction"
|
||||
:icon="IconCopy"
|
||||
:label="t('tab.duplicate')"
|
||||
:shortcut="['D']"
|
||||
@click="
|
||||
() => {
|
||||
emit('duplicate-tab')
|
||||
hide()
|
||||
}
|
||||
"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
v-if="isRemovable"
|
||||
ref="closeAction"
|
||||
:icon="IconXCircle"
|
||||
:label="t('tab.close')"
|
||||
:shortcut="['W']"
|
||||
@click="
|
||||
() => {
|
||||
emit('close-tab')
|
||||
hide()
|
||||
}
|
||||
"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
v-if="isRemovable"
|
||||
ref="closeOthersAction"
|
||||
:icon="IconXSquare"
|
||||
:label="t('tab.close_others')"
|
||||
:shortcut="['X']"
|
||||
@click="
|
||||
() => {
|
||||
emit('close-other-tabs')
|
||||
hide()
|
||||
}
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</tippy>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue"
|
||||
import { TippyComponent } from "vue-tippy"
|
||||
import { useI18n } from "~/composables/i18n"
|
||||
import IconXCircle from "~icons/lucide/x-circle"
|
||||
import IconXSquare from "~icons/lucide/x-square"
|
||||
import IconFileEdit from "~icons/lucide/file-edit"
|
||||
import IconCopy from "~icons/lucide/copy"
|
||||
import { HoppGQLTab } from "~/helpers/graphql/tab"
|
||||
|
||||
const t = useI18n()
|
||||
|
||||
defineProps<{
|
||||
tab: HoppGQLTab
|
||||
isRemovable: boolean
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(event: "open-rename-modal"): void
|
||||
(event: "close-tab"): void
|
||||
(event: "close-other-tabs"): void
|
||||
(event: "duplicate-tab"): void
|
||||
}>()
|
||||
|
||||
const tippyActions = ref<TippyComponent | null>(null)
|
||||
const options = ref<TippyComponent | null>(null)
|
||||
|
||||
const renameAction = ref<HTMLButtonElement | null>(null)
|
||||
const closeAction = ref<HTMLButtonElement | null>(null)
|
||||
const closeOthersAction = ref<HTMLButtonElement | null>(null)
|
||||
const duplicateAction = ref<HTMLButtonElement | null>(null)
|
||||
</script>
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div
|
||||
class="sticky top-sidebarPrimaryStickyFold z-10 flex items-center justify-between pl-4 border-y bg-primary border-dividerLight"
|
||||
class="sticky z-10 flex items-center justify-between pl-4 border-b bg-primary border-dividerLight"
|
||||
>
|
||||
<label class="font-semibold text-secondaryLight">
|
||||
{{ t("request.variables") }}
|
||||
|
||||
@@ -56,7 +56,13 @@
|
||||
:inspection-results="tabResults"
|
||||
@paste="onPasteUrl($event)"
|
||||
@enter="newSendRequest"
|
||||
/>
|
||||
>
|
||||
<template #empty>
|
||||
<span>
|
||||
{{ t("empty.history_suggestions") }}
|
||||
</span>
|
||||
</template>
|
||||
</SmartEnvInput>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex mt-2 sm:mt-0">
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
:title="tab.document.request.name"
|
||||
class="truncate px-2 flex items-center"
|
||||
@dblclick="emit('open-rename-modal')"
|
||||
@contextmenu.prevent="options?.tippy?.show()"
|
||||
@contextmenu.prevent="options?.tippy.show()"
|
||||
@click.middle="emit('close-tab')"
|
||||
>
|
||||
<span
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div ref="autoCompleteWrapper" class="autocomplete-wrapper">
|
||||
<div class="autocomplete-wrapper">
|
||||
<div
|
||||
class="absolute inset-0 flex flex-1 divide-x divide-dividerLight overflow-x-auto"
|
||||
>
|
||||
@@ -18,9 +18,7 @@
|
||||
/>
|
||||
</div>
|
||||
<ul
|
||||
v-if="
|
||||
showSuggestionPopover && autoCompleteSource && suggestions.length > 0
|
||||
"
|
||||
v-if="showSuggestionPopover && autoCompleteSource"
|
||||
ref="suggestionsMenu"
|
||||
class="suggestions"
|
||||
>
|
||||
@@ -41,12 +39,20 @@
|
||||
<span class="ml-2 truncate">to select</span>
|
||||
</div>
|
||||
</li>
|
||||
<li v-if="suggestions.length === 0" class="pointer-events-none">
|
||||
<div v-if="slots.empty" class="truncate py-0.5">
|
||||
<slot name="empty"></slot>
|
||||
</div>
|
||||
<span v-else class="truncate py-0.5">
|
||||
{{ t("empty.suggestions") }}
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, watch, nextTick, computed, Ref } from "vue"
|
||||
import { ref, onMounted, watch, nextTick, computed, Ref, useSlots } from "vue"
|
||||
import {
|
||||
EditorView,
|
||||
placeholder as placeholderExt,
|
||||
@@ -63,6 +69,7 @@ import { HoppReactiveEnvPlugin } from "~/helpers/editor/extensions/HoppEnvironme
|
||||
import { useReadonlyStream } from "@composables/stream"
|
||||
import { AggregateEnvironment, aggregateEnvs$ } from "~/newstore/environments"
|
||||
import { platform } from "~/platform"
|
||||
import { useI18n } from "~/composables/i18n"
|
||||
import { onClickOutside, useDebounceFn } from "@vueuse/core"
|
||||
import { InspectorResult } from "~/services/inspection"
|
||||
import { invokeAction } from "~/helpers/actions"
|
||||
@@ -104,6 +111,10 @@ const emit = defineEmits<{
|
||||
(e: "click", ev: any): void
|
||||
}>()
|
||||
|
||||
const slots = useSlots()
|
||||
|
||||
const t = useI18n()
|
||||
|
||||
const cachedValue = ref(props.modelValue)
|
||||
|
||||
const view = ref<EditorView>()
|
||||
@@ -114,9 +125,8 @@ const currentSuggestionIndex = ref(-1)
|
||||
const showSuggestionPopover = ref(false)
|
||||
|
||||
const suggestionsMenu = ref<any | null>(null)
|
||||
const autoCompleteWrapper = ref<any | null>(null)
|
||||
|
||||
onClickOutside(autoCompleteWrapper, () => {
|
||||
onClickOutside(suggestionsMenu, () => {
|
||||
showSuggestionPopover.value = false
|
||||
})
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ import { BehaviorSubject } from "rxjs"
|
||||
import { HoppRESTDocument } from "./rest/document"
|
||||
import { HoppGQLRequest, HoppRESTRequest } from "@hoppscotch/data"
|
||||
import { RequestOptionTabs } from "~/components/http/RequestOptions.vue"
|
||||
import { HoppGQLSaveContext } from "./graphql/document"
|
||||
|
||||
export type HoppAction =
|
||||
| "contextmenu.open" // Send/Cancel a Hoppscotch Request
|
||||
@@ -26,15 +25,14 @@ export type HoppAction =
|
||||
| "request.method.delete" // Select DELETE Method
|
||||
| "request.import-curl" // Import cURL
|
||||
| "request.show-code" // Show generated code
|
||||
| "collection.new" // Create root collection
|
||||
| "flyouts.chat.open" // Shows the keybinds flyout
|
||||
| "flyouts.keybinds.toggle" // Shows the keybinds flyout
|
||||
| "modals.search.toggle" // Shows the search modal
|
||||
| "modals.support.toggle" // Shows the support modal
|
||||
| "modals.share.toggle" // Shows the share modal
|
||||
| "modals.social.toggle" // Shows the social links modal
|
||||
| "modals.environment.add" // Show add environment modal via context menu
|
||||
| "modals.environment.new" // Add new environment
|
||||
| "modals.environment.delete-selected" // Delete Selected Environment
|
||||
| "modals.my.environment.edit" // Edit current personal environment
|
||||
| "modals.team.environment.edit" // Edit current team environment
|
||||
| "modals.team.new" // Add new team
|
||||
@@ -109,13 +107,8 @@ type HoppActionArgsMap = {
|
||||
tab: RequestOptionTabs
|
||||
}
|
||||
|
||||
"request.duplicate-tab": {
|
||||
tabID: string
|
||||
}
|
||||
|
||||
"gql.request.open": {
|
||||
request: HoppGQLRequest
|
||||
saveContext?: HoppGQLSaveContext
|
||||
}
|
||||
"modals.environment.add": {
|
||||
envName: string
|
||||
|
||||
@@ -17,9 +17,6 @@ import {
|
||||
getSelectedEnvironmentType,
|
||||
} from "~/newstore/environments"
|
||||
import { invokeAction } from "~/helpers/actions"
|
||||
import IconUser from "~icons/lucide/user?raw"
|
||||
import IconUsers from "~icons/lucide/users?raw"
|
||||
import IconEdit from "~icons/lucide/edit?raw"
|
||||
|
||||
const HOPP_ENVIRONMENT_REGEX = /(<<[a-zA-Z0-9-_]+>>)/g
|
||||
|
||||
@@ -74,14 +71,14 @@ const cursorTooltipField = (aggregateEnvs: AggregateEnvironment[]) =>
|
||||
|
||||
const selectedEnvType = getSelectedEnvironmentType()
|
||||
|
||||
const envTypeIcon = `<span class="inline-flex items-center justify-center my-1">${
|
||||
selectedEnvType === "TEAM_ENV" ? IconUsers : IconUser
|
||||
const envTypeIcon = `<span class="inline-flex items-center opacity-65 -mx-0.5 text-base font-icon">${
|
||||
selectedEnvType === "TEAM_ENV" ? "group" : "person"
|
||||
}</span>`
|
||||
|
||||
const appendEditAction = (tooltip: HTMLElement) => {
|
||||
const editIcon = document.createElement("button")
|
||||
const editIcon = document.createElement("span")
|
||||
editIcon.className =
|
||||
"ml-2 cursor-pointer text-accent hover:text-accentDark"
|
||||
"ml-2 cursor-pointer env-icon text-accent hover:text-accentDark"
|
||||
editIcon.addEventListener("click", () => {
|
||||
const isPersonalEnv =
|
||||
envName === "Global" || selectedEnvType !== "TEAM_ENV"
|
||||
@@ -91,7 +88,7 @@ const cursorTooltipField = (aggregateEnvs: AggregateEnvironment[]) =>
|
||||
variableName: parsedEnvKey,
|
||||
})
|
||||
})
|
||||
editIcon.innerHTML = `<span class="inline-flex items-center justify-center my-1">${IconEdit}</span>`
|
||||
editIcon.innerHTML = `<span class="inline-flex items-center px-1 -mx-1 text-base font-icon">edit</span>`
|
||||
tooltip.appendChild(editIcon)
|
||||
}
|
||||
|
||||
@@ -106,7 +103,7 @@ const cursorTooltipField = (aggregateEnvs: AggregateEnvironment[]) =>
|
||||
const kbd = document.createElement("kbd")
|
||||
const icon = document.createElement("span")
|
||||
icon.innerHTML = envTypeIcon
|
||||
icon.className = "mr-2"
|
||||
icon.className = "mr-2 env-icon"
|
||||
kbd.textContent = finalEnv
|
||||
tooltipContainer.appendChild(icon)
|
||||
tooltipContainer.appendChild(document.createTextNode(`${envName} `))
|
||||
|
||||
@@ -197,30 +197,3 @@ export function getTabsRefTo(func: (tab: HoppGQLTab) => boolean) {
|
||||
.filter(func)
|
||||
.map((tab) => getTabRef(tab.id))
|
||||
}
|
||||
|
||||
export function closeOtherTabs(tabID: string) {
|
||||
if (!tabMap.has(tabID)) {
|
||||
console.warn(
|
||||
`The tab to close other tabs does not exist (tab id: ${tabID})`
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
tabOrdering.value = [tabID]
|
||||
|
||||
tabMap.forEach((_, id) => {
|
||||
if (id !== tabID) tabMap.delete(id)
|
||||
})
|
||||
|
||||
currentTabID.value = tabID
|
||||
}
|
||||
|
||||
export function getDirtyTabsCount() {
|
||||
let count = 0
|
||||
|
||||
for (const tab of tabMap.values()) {
|
||||
if (tab.document.isDirty) count++
|
||||
}
|
||||
|
||||
return count
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import * as HTTPSnippet from "httpsnippet"
|
||||
import { HTTPSnippet } from "httpsnippet"
|
||||
import { HoppRESTRequest } from "@hoppscotch/data"
|
||||
import * as O from "fp-ts/Option"
|
||||
import * as E from "fp-ts/Either"
|
||||
@@ -208,10 +208,7 @@ export const generateCode = (
|
||||
}).convert(codegenInfo.lang, codegenInfo.mode, {
|
||||
indent: " ",
|
||||
}),
|
||||
(e) => {
|
||||
console.error(e)
|
||||
return e
|
||||
}
|
||||
(e) => e
|
||||
),
|
||||
|
||||
// Only allow string output to pass through, else none
|
||||
|
||||
@@ -1,163 +0,0 @@
|
||||
import axios, { AxiosRequestConfig } from "axios"
|
||||
import { v4 } from "uuid"
|
||||
import { pipe } from "fp-ts/function"
|
||||
import * as TE from "fp-ts/TaskEither"
|
||||
import { cloneDeep } from "lodash-es"
|
||||
import { NetworkResponse, NetworkStrategy } from "../network"
|
||||
import { decodeB64StringToArrayBuffer } from "../utils/b64"
|
||||
import { settingsStore } from "~/newstore/settings"
|
||||
|
||||
let cancelSource = axios.CancelToken.source()
|
||||
|
||||
type ProxyHeaders = {
|
||||
"multipart-part-key"?: string
|
||||
}
|
||||
|
||||
type ProxyPayloadType = FormData | (AxiosRequestConfig & { wantsBinary: true })
|
||||
|
||||
export const cancelRunningAxiosRequest = () => {
|
||||
cancelSource.cancel()
|
||||
|
||||
// Create a new cancel token
|
||||
cancelSource = axios.CancelToken.source()
|
||||
}
|
||||
|
||||
const getProxyPayload = (
|
||||
req: AxiosRequestConfig,
|
||||
multipartKey: string | null
|
||||
) => {
|
||||
let payload: ProxyPayloadType = {
|
||||
...req,
|
||||
wantsBinary: true,
|
||||
accessToken: import.meta.env.VITE_PROXYSCOTCH_ACCESS_TOKEN ?? "",
|
||||
}
|
||||
|
||||
if (payload.data instanceof FormData) {
|
||||
const formData = payload.data
|
||||
payload.data = ""
|
||||
formData.append(multipartKey!, JSON.stringify(payload))
|
||||
payload = formData
|
||||
}
|
||||
|
||||
return payload
|
||||
}
|
||||
|
||||
const preProcessRequest = (req: AxiosRequestConfig): AxiosRequestConfig => {
|
||||
const reqClone = cloneDeep(req)
|
||||
|
||||
// If the parameters are URLSearchParams, inject them to URL instead
|
||||
// This prevents issues of marshalling the URLSearchParams to the proxy
|
||||
if (reqClone.params instanceof URLSearchParams) {
|
||||
try {
|
||||
const url = new URL(reqClone.url ?? "")
|
||||
|
||||
for (const [key, value] of reqClone.params.entries()) {
|
||||
url.searchParams.append(key, value)
|
||||
}
|
||||
|
||||
reqClone.url = url.toString()
|
||||
} catch (e) {
|
||||
// making this a non-empty block, so we can make the linter happy.
|
||||
// we should probably use, allowEmptyCatch, or take the time to do something with the caught errors :)
|
||||
}
|
||||
|
||||
reqClone.params = {}
|
||||
}
|
||||
|
||||
return reqClone
|
||||
}
|
||||
|
||||
const axiosWithProxy: NetworkStrategy = (req) =>
|
||||
pipe(
|
||||
TE.Do,
|
||||
|
||||
TE.bind("processedReq", () => TE.of(preProcessRequest(req))),
|
||||
|
||||
// If the request has FormData, the proxy needs a key
|
||||
TE.bind("multipartKey", ({ processedReq }) =>
|
||||
TE.of(
|
||||
processedReq.data instanceof FormData
|
||||
? `proxyRequestData-${v4()}`
|
||||
: null
|
||||
)
|
||||
),
|
||||
|
||||
// Build headers to send
|
||||
TE.bind("headers", ({ processedReq, multipartKey }) =>
|
||||
TE.of(
|
||||
processedReq.data instanceof FormData
|
||||
? <ProxyHeaders>{
|
||||
"multipart-part-key": multipartKey,
|
||||
}
|
||||
: <ProxyHeaders>{}
|
||||
)
|
||||
),
|
||||
|
||||
// Create payload
|
||||
TE.bind("payload", ({ processedReq, multipartKey }) =>
|
||||
TE.of(getProxyPayload(processedReq, multipartKey))
|
||||
),
|
||||
|
||||
// Run the proxy request
|
||||
TE.chain(({ payload, headers }) =>
|
||||
TE.tryCatch(
|
||||
() =>
|
||||
axios.post(
|
||||
settingsStore.value.PROXY_URL || "https://proxy.hoppscotch.io",
|
||||
payload,
|
||||
{
|
||||
headers,
|
||||
cancelToken: cancelSource.token,
|
||||
}
|
||||
),
|
||||
(reason) =>
|
||||
axios.isCancel(reason)
|
||||
? "cancellation" // Convert cancellation errors into cancellation strings
|
||||
: reason
|
||||
)
|
||||
),
|
||||
|
||||
// Check success predicate
|
||||
TE.chain(
|
||||
TE.fromPredicate(
|
||||
({ data }) => data.success,
|
||||
({ data }) => data.data.message || "Proxy Error"
|
||||
)
|
||||
),
|
||||
|
||||
// Process Base64
|
||||
TE.chain(({ data }) => {
|
||||
if (data.isBinary) {
|
||||
data.data = decodeB64StringToArrayBuffer(data.data)
|
||||
}
|
||||
|
||||
return TE.of(data)
|
||||
})
|
||||
)
|
||||
|
||||
const axiosWithoutProxy: NetworkStrategy = (req) =>
|
||||
pipe(
|
||||
TE.tryCatch(
|
||||
() =>
|
||||
axios({
|
||||
...req,
|
||||
cancelToken: (cancelSource && cancelSource.token) || "",
|
||||
responseType: "arraybuffer",
|
||||
}),
|
||||
(e) => (axios.isCancel(e) ? "cancellation" : (e as any))
|
||||
),
|
||||
|
||||
TE.orElse((e) =>
|
||||
e !== "cancellation" && e.response
|
||||
? TE.right(e.response as NetworkResponse)
|
||||
: TE.left(e)
|
||||
)
|
||||
)
|
||||
|
||||
const axiosStrategy: NetworkStrategy = (req) =>
|
||||
pipe(
|
||||
req,
|
||||
settingsStore.value.PROXY_ENABLED ? axiosWithProxy : axiosWithoutProxy
|
||||
)
|
||||
|
||||
export default axiosStrategy
|
||||
@@ -427,10 +427,6 @@ export function getCurrentEnvironment(): Environment {
|
||||
}
|
||||
}
|
||||
|
||||
export function getSelectedEnvironmentIndex() {
|
||||
return environmentsStore.value.selectedEnvironmentIndex
|
||||
}
|
||||
|
||||
export function getSelectedEnvironmentType() {
|
||||
return environmentsStore.value.selectedEnvironmentIndex.type
|
||||
}
|
||||
|
||||
@@ -21,14 +21,15 @@
|
||||
:close-visibility="'hover'"
|
||||
>
|
||||
<template #tabhead>
|
||||
<GraphqlTabHead
|
||||
:tab="tab"
|
||||
:is-removable="tabs.length > 1"
|
||||
@open-rename-modal="openReqRenameModal(tab)"
|
||||
@close-tab="removeTab(tab.id)"
|
||||
@close-other-tabs="closeOtherTabsAction(tab.id)"
|
||||
@duplicate-tab="duplicateTab(tab)"
|
||||
/>
|
||||
<div
|
||||
v-tippy="{ theme: 'tooltip', delay: [500, 20] }"
|
||||
:title="tab.document.request.name"
|
||||
class="truncate px-2"
|
||||
>
|
||||
<span class="leading-8 px-2">
|
||||
{{ tab.document.request.name }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #suffix>
|
||||
@@ -58,12 +59,7 @@
|
||||
<GraphqlSidebar />
|
||||
</template>
|
||||
</AppPaneLayout>
|
||||
<CollectionsEditRequest
|
||||
v-model="editReqModalReqName"
|
||||
:show="showRenamingReqNameModalForTabID !== undefined"
|
||||
@submit="renameReqName"
|
||||
@hide-modal="showRenamingReqNameModalForTabID = undefined"
|
||||
/>
|
||||
|
||||
<HoppSmartConfirmModal
|
||||
:show="confirmingCloseForTabID !== null"
|
||||
:confirm="t('modal.close_unsaved_tab')"
|
||||
@@ -71,13 +67,6 @@
|
||||
@hide-modal="onCloseConfirm"
|
||||
@resolve="onResolveConfirm"
|
||||
/>
|
||||
<HoppSmartConfirmModal
|
||||
:show="confirmingCloseAllTabs"
|
||||
:confirm="t('modal.close_unsaved_tab')"
|
||||
:title="t('confirm.close_unsaved_tabs', { count: unsavedTabsCount })"
|
||||
@hide-modal="confirmingCloseAllTabs = false"
|
||||
@resolve="onResolveConfirmCloseAllTabs"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -91,12 +80,10 @@ import { connection, disconnect } from "~/helpers/graphql/connection"
|
||||
import { getDefaultGQLRequest } from "~/helpers/graphql/default"
|
||||
import {
|
||||
HoppGQLTab,
|
||||
closeOtherTabs,
|
||||
closeTab,
|
||||
createNewTab,
|
||||
currentTabID,
|
||||
getActiveTabs,
|
||||
getDirtyTabsCount,
|
||||
getTabRef,
|
||||
updateTab,
|
||||
updateTabOrdering,
|
||||
@@ -155,27 +142,6 @@ const onResolveConfirm = () => {
|
||||
}
|
||||
}
|
||||
|
||||
const confirmingCloseAllTabs = ref(false)
|
||||
const unsavedTabsCount = ref(0)
|
||||
const exceptedTabID = ref<string | null>(null)
|
||||
|
||||
const closeOtherTabsAction = (tabID: string) => {
|
||||
const dirtyTabCount = getDirtyTabsCount()
|
||||
// If there are dirty tabs, show the confirm modal
|
||||
if (dirtyTabCount > 0) {
|
||||
confirmingCloseAllTabs.value = true
|
||||
unsavedTabsCount.value = dirtyTabCount
|
||||
exceptedTabID.value = tabID
|
||||
} else {
|
||||
closeOtherTabs(tabID)
|
||||
}
|
||||
}
|
||||
|
||||
const onResolveConfirmCloseAllTabs = () => {
|
||||
if (exceptedTabID.value) closeOtherTabs(exceptedTabID.value)
|
||||
confirmingCloseAllTabs.value = false
|
||||
}
|
||||
|
||||
const onTabUpdate = (tab: HoppGQLTab) => {
|
||||
updateTab(tab)
|
||||
}
|
||||
@@ -186,34 +152,8 @@ onBeforeUnmount(() => {
|
||||
}
|
||||
})
|
||||
|
||||
const editReqModalReqName = ref("")
|
||||
const showRenamingReqNameModalForTabID = ref<string>()
|
||||
|
||||
const openReqRenameModal = (tab: HoppGQLTab) => {
|
||||
editReqModalReqName.value = tab.document.request.name
|
||||
showRenamingReqNameModalForTabID.value = tab.id
|
||||
}
|
||||
|
||||
const renameReqName = () => {
|
||||
const tab = getTabRef(showRenamingReqNameModalForTabID.value!)
|
||||
if (tab.value) {
|
||||
tab.value.document.request.name = editReqModalReqName.value
|
||||
updateTab(tab.value)
|
||||
}
|
||||
showRenamingReqNameModalForTabID.value = undefined
|
||||
}
|
||||
|
||||
const duplicateTab = (tab: HoppGQLTab) => {
|
||||
const newTab = createNewTab({
|
||||
request: tab.document.request,
|
||||
isDirty: true,
|
||||
})
|
||||
currentTabID.value = newTab.id
|
||||
}
|
||||
|
||||
defineActionHandler("gql.request.open", ({ request, saveContext }) => {
|
||||
defineActionHandler("gql.request.open", ({ request }) => {
|
||||
createNewTab({
|
||||
saveContext,
|
||||
request: request,
|
||||
isDirty: false,
|
||||
})
|
||||
|
||||
@@ -150,7 +150,6 @@ const showRenamingReqNameModal = ref(false)
|
||||
const reqName = ref<string>("")
|
||||
const unsavedTabsCount = ref(0)
|
||||
const exceptedTabID = ref<string | null>(null)
|
||||
const renameTabID = ref<string | null>(null)
|
||||
|
||||
const t = useI18n()
|
||||
const toast = useToast()
|
||||
@@ -258,7 +257,6 @@ const openReqRenameModal = (tabID?: string) => {
|
||||
if (tabID) {
|
||||
const tab = getTabRef(tabID)
|
||||
reqName.value = tab.value.document.request.name
|
||||
renameTabID.value = tabID
|
||||
} else {
|
||||
reqName.value = currentActiveTab.value.document.request.name
|
||||
}
|
||||
@@ -266,7 +264,7 @@ const openReqRenameModal = (tabID?: string) => {
|
||||
}
|
||||
|
||||
const renameReqName = () => {
|
||||
const tab = getTabRef(renameTabID.value ?? currentTabID.value)
|
||||
const tab = getTabRef(currentTabID.value)
|
||||
if (tab.value) {
|
||||
tab.value.document.request.name = reqName.value
|
||||
updateTab(tab.value)
|
||||
@@ -461,9 +459,6 @@ defineActionHandler("rest.request.open", ({ doc }) => {
|
||||
})
|
||||
|
||||
defineActionHandler("rest.request.rename", openReqRenameModal)
|
||||
defineActionHandler("request.duplicate-tab", ({ tabID }) => {
|
||||
duplicateTab(tabID)
|
||||
})
|
||||
|
||||
const inspectionService = useService(InspectionService)
|
||||
useService(HeaderInspectorService)
|
||||
|
||||
@@ -114,7 +114,7 @@ export class ParameterMenuService extends Service implements ContextMenu {
|
||||
id: "environment",
|
||||
text: {
|
||||
type: "text",
|
||||
text: this.t("context_menu.add_parameters"),
|
||||
text: this.t("context_menu.add_parameter"),
|
||||
},
|
||||
icon: markRaw(IconArrowDownRight),
|
||||
action: () => {
|
||||
|
||||
@@ -70,7 +70,7 @@ export class URLMenuService extends Service implements ContextMenu {
|
||||
id: "link-tab",
|
||||
text: {
|
||||
type: "text",
|
||||
text: this.t("context_menu.open_request_in_new_tab"),
|
||||
text: this.t("context_menu.open_link_in_new_tab"),
|
||||
},
|
||||
icon: markRaw(IconCopyPlus),
|
||||
action: () => {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Service } from "dioc"
|
||||
import {
|
||||
SpotlightResultTextType,
|
||||
SpotlightSearcher,
|
||||
SpotlightSearcherResult,
|
||||
SpotlightSearcherSessionState,
|
||||
@@ -27,7 +26,6 @@ import {
|
||||
} from "@hoppscotch/data"
|
||||
import { hoppWorkspaceStore } from "~/newstore/workspace"
|
||||
import { changeWorkspace } from "~/newstore/workspace"
|
||||
import { invokeAction } from "~/helpers/actions"
|
||||
|
||||
/**
|
||||
* A spotlight searcher that searches through the user's collections
|
||||
@@ -145,13 +143,6 @@ export class CollectionsSpotlightSearcherService
|
||||
},
|
||||
})
|
||||
|
||||
if (pageCategory === "rest" || pageCategory === "graphql") {
|
||||
minisearch.add({
|
||||
id: `create-collection`,
|
||||
name: this.t("collection.new"),
|
||||
})
|
||||
}
|
||||
|
||||
if (pageCategory === "rest") {
|
||||
this.loadRESTDocsIntoMinisearch(minisearch)
|
||||
} else if (pageCategory === "graphql") {
|
||||
@@ -162,11 +153,6 @@ export class CollectionsSpotlightSearcherService
|
||||
|
||||
const scopeHandle = effectScope()
|
||||
|
||||
const newCollectionText: SpotlightResultTextType<any> = {
|
||||
type: "text",
|
||||
text: this.t("collection.new"),
|
||||
}
|
||||
|
||||
scopeHandle.run(() => {
|
||||
watch(query, (query) => {
|
||||
if (pageCategory === "other") {
|
||||
@@ -179,34 +165,28 @@ export class CollectionsSpotlightSearcherService
|
||||
|
||||
results.value = searchResults.map((result) => ({
|
||||
id: result.id,
|
||||
text:
|
||||
result.id === "create-collection"
|
||||
? newCollectionText
|
||||
: {
|
||||
type: "custom",
|
||||
component: markRaw(RESTRequestSpotlightEntry),
|
||||
componentProps: {
|
||||
folderPath: result.id.split("rest-")[1],
|
||||
},
|
||||
},
|
||||
text: {
|
||||
type: "custom",
|
||||
component: markRaw(RESTRequestSpotlightEntry),
|
||||
componentProps: {
|
||||
folderPath: result.id.split("rest-")[1],
|
||||
},
|
||||
},
|
||||
icon: markRaw(IconFolder),
|
||||
score: result.score,
|
||||
}))
|
||||
} else if (pageCategory === "graphql") {
|
||||
} else {
|
||||
const searchResults = minisearch.search(query).slice(0, 10)
|
||||
|
||||
results.value = searchResults.map((result) => ({
|
||||
id: result.id,
|
||||
text:
|
||||
result.id === "create-collection"
|
||||
? newCollectionText
|
||||
: {
|
||||
type: "custom",
|
||||
component: markRaw(GQLRequestSpotlightEntry),
|
||||
componentProps: {
|
||||
folderPath: result.id.split("gql-")[1],
|
||||
},
|
||||
},
|
||||
text: {
|
||||
type: "custom",
|
||||
component: markRaw(GQLRequestSpotlightEntry),
|
||||
componentProps: {
|
||||
folderPath: result.id.split("gql-")[1],
|
||||
},
|
||||
},
|
||||
icon: markRaw(IconFolder),
|
||||
score: result.score,
|
||||
}))
|
||||
@@ -276,8 +256,6 @@ export class CollectionsSpotlightSearcherService
|
||||
}
|
||||
|
||||
public onResultSelect(result: SpotlightSearcherResult): void {
|
||||
if (result.id === "create-collection") return invokeAction("collection.new")
|
||||
|
||||
const [type, path] = result.id.split("-")
|
||||
|
||||
if (type === "rest") {
|
||||
@@ -326,15 +304,13 @@ export class CollectionsSpotlightSearcherService
|
||||
|
||||
if (!req) return
|
||||
|
||||
createNewGQLTab({
|
||||
saveContext: {
|
||||
originLocation: "user-collection",
|
||||
folderPath: folderPath.join("/"),
|
||||
requestIndex: reqIndex,
|
||||
createNewGQLTab(
|
||||
{
|
||||
request: req,
|
||||
isDirty: false,
|
||||
},
|
||||
request: req,
|
||||
isDirty: false,
|
||||
})
|
||||
true
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,29 +21,30 @@ import {
|
||||
StaticSpotlightSearcherService,
|
||||
} from "./base/static.searcher"
|
||||
|
||||
import IconCopy from "~icons/lucide/copy"
|
||||
import IconEdit from "~icons/lucide/edit"
|
||||
import IconLayers from "~icons/lucide/layers"
|
||||
import IconTrash2 from "~icons/lucide/trash-2"
|
||||
import IconCopy from "~icons/lucide/copy"
|
||||
import IconLayers from "~icons/lucide/layers"
|
||||
|
||||
import { Service } from "dioc"
|
||||
import * as TE from "fp-ts/TaskEither"
|
||||
import { pipe } from "fp-ts/function"
|
||||
import { cloneDeep } from "lodash-es"
|
||||
import MiniSearch from "minisearch"
|
||||
import { map } from "rxjs"
|
||||
import { useStreamStatic } from "~/composables/stream"
|
||||
import { GQLError } from "~/helpers/backend/GQLClient"
|
||||
import { deleteTeamEnvironment } from "~/helpers/backend/mutations/TeamEnvironment"
|
||||
import {
|
||||
createEnvironment,
|
||||
currentEnvironment$,
|
||||
deleteEnvironment,
|
||||
duplicateEnvironment,
|
||||
environmentsStore,
|
||||
getGlobalVariables,
|
||||
selectedEnvironmentIndex$,
|
||||
setSelectedEnvironmentIndex,
|
||||
} from "~/newstore/environments"
|
||||
import { pipe } from "fp-ts/function"
|
||||
import * as TE from "fp-ts/TaskEither"
|
||||
import { deleteTeamEnvironment } from "~/helpers/backend/mutations/TeamEnvironment"
|
||||
import { GQLError } from "~/helpers/backend/GQLClient"
|
||||
import { cloneDeep } from "lodash-es"
|
||||
import { Service } from "dioc"
|
||||
import MiniSearch from "minisearch"
|
||||
import { map } from "rxjs"
|
||||
|
||||
type Doc = {
|
||||
text: string
|
||||
@@ -187,6 +188,29 @@ export class EnvironmentsSpotlightSearcherService extends StaticSpotlightSearche
|
||||
}
|
||||
}
|
||||
|
||||
removeSelectedEnvironment = () => {
|
||||
if (this.selectedEnvIndex.value?.type === "NO_ENV_SELECTED") return
|
||||
|
||||
if (this.selectedEnvIndex.value?.type === "MY_ENV") {
|
||||
deleteEnvironment(this.selectedEnvIndex.value.index)
|
||||
// this.toast.success(`${t("state.deleted")}`)
|
||||
}
|
||||
|
||||
if (this.selectedEnvIndex.value?.type === "TEAM_ENV") {
|
||||
pipe(
|
||||
deleteTeamEnvironment(this.selectedEnvIndex.value.teamEnvID),
|
||||
TE.match(
|
||||
(err: GQLError<string>) => {
|
||||
console.error(err)
|
||||
},
|
||||
() => {
|
||||
// this.toast.success(`${this.t("team_environment.deleted")}`)
|
||||
}
|
||||
)
|
||||
)()
|
||||
}
|
||||
}
|
||||
|
||||
public onDocSelected(id: string): void {
|
||||
switch (id) {
|
||||
case "new_environment":
|
||||
@@ -205,7 +229,7 @@ export class EnvironmentsSpotlightSearcherService extends StaticSpotlightSearche
|
||||
})
|
||||
break
|
||||
case "delete_selected_env":
|
||||
invokeAction(`modals.environment.delete-selected`)
|
||||
this.removeSelectedEnvironment()
|
||||
break
|
||||
case "duplicate_selected_env":
|
||||
this.duplicateSelectedEnv()
|
||||
|
||||
@@ -7,17 +7,14 @@ import {
|
||||
StaticSpotlightSearcherService,
|
||||
} from "./base/static.searcher"
|
||||
|
||||
import IconLinkedIn from "~icons/brands/linkedin"
|
||||
import IconTwitter from "~icons/brands/twitter"
|
||||
import IconBook from "~icons/lucide/book"
|
||||
import IconDiscord from "~icons/lucide/link"
|
||||
import IconGitHub from "~icons/lucide/github"
|
||||
import IconGithub from "~icons/lucide/github"
|
||||
import IconLifeBuoy from "~icons/lucide/life-buoy"
|
||||
import IconMessageCircle from "~icons/lucide/message-circle"
|
||||
import IconZap from "~icons/lucide/zap"
|
||||
|
||||
type Doc = {
|
||||
text: string | string[]
|
||||
text: string
|
||||
alternates: string[]
|
||||
icon: object | Component
|
||||
}
|
||||
@@ -59,25 +56,10 @@ export class GeneralSpotlightSearcherService extends StaticSpotlightSearcherServ
|
||||
alternates: ["key", "shortcuts", "binding"],
|
||||
icon: markRaw(IconZap),
|
||||
},
|
||||
link_github: {
|
||||
text: [this.t("spotlight.general.social"), "GitHub"],
|
||||
alternates: ["social", "github", "link"],
|
||||
icon: markRaw(IconGitHub),
|
||||
},
|
||||
link_twitter: {
|
||||
text: [this.t("spotlight.general.social"), "Twitter"],
|
||||
alternates: ["social", "twitter", "link"],
|
||||
icon: markRaw(IconTwitter),
|
||||
},
|
||||
link_discord: {
|
||||
text: [this.t("spotlight.general.social"), "Discord"],
|
||||
alternates: ["social", "discord", "link"],
|
||||
icon: markRaw(IconDiscord),
|
||||
},
|
||||
link_linkedin: {
|
||||
text: [this.t("spotlight.general.social"), "LinkedIn"],
|
||||
alternates: ["social", "linkedin", "link"],
|
||||
icon: markRaw(IconLinkedIn),
|
||||
social_links: {
|
||||
text: this.t("spotlight.general.social"),
|
||||
alternates: ["social", "github", "binding"],
|
||||
icon: markRaw(IconGithub),
|
||||
},
|
||||
})
|
||||
|
||||
@@ -105,7 +87,8 @@ export class GeneralSpotlightSearcherService extends StaticSpotlightSearcherServ
|
||||
}
|
||||
}
|
||||
|
||||
private openURL(url: string) {
|
||||
private openDocs() {
|
||||
const url = "https://docs.hoppscotch.io"
|
||||
window.open(url, "_blank")
|
||||
}
|
||||
|
||||
@@ -118,22 +101,13 @@ export class GeneralSpotlightSearcherService extends StaticSpotlightSearcherServ
|
||||
invokeAction("flyouts.chat.open")
|
||||
break
|
||||
case "open_docs":
|
||||
this.openURL("https://docs.hoppscotch.io")
|
||||
this.openDocs()
|
||||
break
|
||||
case "open_keybindings":
|
||||
invokeAction("flyouts.keybinds.toggle")
|
||||
break
|
||||
case "link_github":
|
||||
this.openURL("https://hoppscotch.io/github")
|
||||
break
|
||||
case "link_twitter":
|
||||
this.openURL("https://twitter.com/hoppscotch_io")
|
||||
break
|
||||
case "link_discord":
|
||||
this.openURL("https://hoppscotch.io/discord")
|
||||
break
|
||||
case "link_linkedin":
|
||||
this.openURL("https://www.linkedin.com/company/hoppscotch/")
|
||||
case "social_links":
|
||||
invokeAction("modals.social.toggle")
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,126 +0,0 @@
|
||||
import { Ref, computed, effectScope, markRaw, ref, unref, watch } from "vue"
|
||||
import { getI18n } from "~/modules/i18n"
|
||||
import {
|
||||
SpotlightSearcher,
|
||||
SpotlightSearcherResult,
|
||||
SpotlightSearcherSessionState,
|
||||
SpotlightService,
|
||||
} from ".."
|
||||
|
||||
import { Service } from "dioc"
|
||||
import { useService } from "dioc/vue"
|
||||
import MiniSearch from "minisearch"
|
||||
import IconCheckCircle from "~/components/app/spotlight/entry/IconSelected.vue"
|
||||
import { InterceptorService } from "~/services/interceptor.service"
|
||||
import IconCircle from "~icons/lucide/circle"
|
||||
|
||||
/**
|
||||
* This searcher is responsible for searching through the interceptor.
|
||||
* And switching between them.
|
||||
*/
|
||||
export class InterceptorSpotlightSearcherService
|
||||
extends Service
|
||||
implements SpotlightSearcher
|
||||
{
|
||||
public static readonly ID = "INTERCEPTOR_SPOTLIGHT_SEARCHER_SERVICE"
|
||||
|
||||
private t = getI18n()
|
||||
|
||||
public searcherID = "interceptor"
|
||||
public searcherSectionTitle = this.t("settings.interceptor")
|
||||
|
||||
private readonly spotlight = this.bind(SpotlightService)
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
|
||||
this.spotlight.registerSearcher(this)
|
||||
}
|
||||
|
||||
private interceptorService = useService(InterceptorService)
|
||||
|
||||
createSearchSession(
|
||||
query: Readonly<Ref<string>>
|
||||
): [Ref<SpotlightSearcherSessionState>, () => void] {
|
||||
const loading = ref(false)
|
||||
const results = ref<SpotlightSearcherResult[]>([])
|
||||
|
||||
const minisearch = new MiniSearch({
|
||||
fields: ["name", "alternates"],
|
||||
storeFields: ["name"],
|
||||
})
|
||||
|
||||
const interceptorSelection = this.interceptorService
|
||||
.currentInterceptorID as Ref<string>
|
||||
|
||||
const interceptors = this.interceptorService.availableInterceptors
|
||||
|
||||
minisearch.addAll(
|
||||
interceptors.value.map((entry) => {
|
||||
let id = `interceptor-${entry.interceptorID}`
|
||||
if (entry.interceptorID === interceptorSelection.value) {
|
||||
id += "-selected"
|
||||
}
|
||||
const name = unref(entry.name(this.t))
|
||||
return {
|
||||
id,
|
||||
name,
|
||||
alternates: ["interceptor", "change", name],
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
const scopeHandle = effectScope()
|
||||
|
||||
scopeHandle.run(() => {
|
||||
watch(
|
||||
[query],
|
||||
([query]) => {
|
||||
results.value = minisearch
|
||||
.search(query, {
|
||||
prefix: true,
|
||||
fuzzy: true,
|
||||
boost: {
|
||||
reltime: 2,
|
||||
},
|
||||
weights: {
|
||||
fuzzy: 0.2,
|
||||
prefix: 0.8,
|
||||
},
|
||||
})
|
||||
.map((x) => {
|
||||
return {
|
||||
id: x.id,
|
||||
icon: markRaw(
|
||||
x.id.endsWith("-selected") ? IconCheckCircle : IconCircle
|
||||
),
|
||||
score: x.score,
|
||||
text: {
|
||||
type: "text",
|
||||
text: [this.t("spotlight.section.interceptor"), x.name],
|
||||
},
|
||||
}
|
||||
})
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
})
|
||||
|
||||
const onSessionEnd = () => {
|
||||
scopeHandle.stop()
|
||||
minisearch.removeAll()
|
||||
}
|
||||
|
||||
const resultObj = computed<SpotlightSearcherSessionState>(() => ({
|
||||
loading: loading.value,
|
||||
results: results.value,
|
||||
}))
|
||||
|
||||
return [resultObj, onSessionEnd]
|
||||
}
|
||||
|
||||
onResultSelect(result: SpotlightSearcherResult): void {
|
||||
const selectedInterceptor = result.id.split("-")[1]
|
||||
this.interceptorService.currentInterceptorID.value = selectedInterceptor
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, computed, markRaw, reactive } from "vue"
|
||||
import { Component, markRaw, reactive } from "vue"
|
||||
import { invokeAction } from "~/helpers/actions"
|
||||
import { getI18n } from "~/modules/i18n"
|
||||
import { SpotlightSearcherResult, SpotlightService } from ".."
|
||||
@@ -7,11 +7,12 @@ import {
|
||||
StaticSpotlightSearcherService,
|
||||
} from "./base/static.searcher"
|
||||
|
||||
import { useRoute } from "vue-router"
|
||||
import { RequestOptionTabs } from "~/components/http/RequestOptions.vue"
|
||||
import { currentActiveTab } from "~/helpers/rest/tab"
|
||||
import IconWindow from "~icons/lucide/app-window"
|
||||
import IconCheckCircle from "~icons/lucide/check-circle"
|
||||
import IconCheck from "~icons/lucide/check"
|
||||
import IconChevronLeft from "~icons/lucide/chevron-left"
|
||||
import IconChevronRight from "~icons/lucide/chevron-right"
|
||||
import IconCode2 from "~icons/lucide/code-2"
|
||||
import IconCopy from "~icons/lucide/copy"
|
||||
import IconFileCode from "~icons/lucide/file-code"
|
||||
@@ -24,7 +25,6 @@ type Doc = {
|
||||
text: string | string[]
|
||||
alternates: string[]
|
||||
icon: object | Component
|
||||
excludeFromSearch?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -43,160 +43,116 @@ export class RequestSpotlightSearcherService extends StaticSpotlightSearcherServ
|
||||
|
||||
private readonly spotlight = this.bind(SpotlightService)
|
||||
|
||||
private route = useRoute()
|
||||
private isRESTPage = computed(() => this.route.name === "index")
|
||||
private isGQLPage = computed(() => this.route.name === "graphql")
|
||||
|
||||
private documents: Record<string, Doc> = reactive({
|
||||
send_request: {
|
||||
text: this.t("shortcut.request.send_request"),
|
||||
alternates: ["request", "send"],
|
||||
icon: markRaw(IconPlay),
|
||||
excludeFromSearch: computed(
|
||||
() => !this.isRESTPage.value ?? !this.isGQLPage.value
|
||||
),
|
||||
},
|
||||
save_to_collections: {
|
||||
text: this.t("spotlight.request.save_as_new"),
|
||||
text: [
|
||||
this.t("request.save_as"),
|
||||
this.t("shortcut.request.save_to_collections"),
|
||||
],
|
||||
alternates: ["save", "collections"],
|
||||
icon: markRaw(IconSave),
|
||||
excludeFromSearch: computed(
|
||||
() => !this.isRESTPage.value ?? !this.isGQLPage.value
|
||||
),
|
||||
},
|
||||
save_request: {
|
||||
text: this.t("shortcut.request.save_request"),
|
||||
alternates: ["save", "request"],
|
||||
icon: markRaw(IconSave),
|
||||
excludeFromSearch: computed(
|
||||
() => !this.isRESTPage.value ?? !this.isGQLPage.value
|
||||
),
|
||||
},
|
||||
rename_request: {
|
||||
text: this.t("shortcut.request.rename"),
|
||||
alternates: ["rename", "request"],
|
||||
icon: markRaw(IconRename),
|
||||
excludeFromSearch: computed(
|
||||
() => !this.isRESTPage.value ?? !this.isGQLPage.value
|
||||
),
|
||||
},
|
||||
copy_request_link: {
|
||||
text: this.t("shortcut.request.copy_request_link"),
|
||||
alternates: ["copy", "link"],
|
||||
icon: markRaw(IconCopy),
|
||||
excludeFromSearch: computed(() => !this.isRESTPage.value),
|
||||
},
|
||||
reset_request: {
|
||||
text: this.t("shortcut.request.reset_request"),
|
||||
alternates: ["reset", "request"],
|
||||
icon: markRaw(IconRotateCCW),
|
||||
excludeFromSearch: computed(() => !this.isRESTPage.value),
|
||||
},
|
||||
import_curl: {
|
||||
text: this.t("shortcut.request.import_curl"),
|
||||
alternates: ["import", "curl"],
|
||||
icon: markRaw(IconFileCode),
|
||||
excludeFromSearch: computed(() => !this.isRESTPage.value),
|
||||
},
|
||||
show_code: {
|
||||
text: this.t("shortcut.request.show_code"),
|
||||
alternates: ["show", "code"],
|
||||
icon: markRaw(IconCode2),
|
||||
excludeFromSearch: computed(() => !this.isRESTPage.value),
|
||||
},
|
||||
// Change request method
|
||||
next_method: {
|
||||
text: this.t("shortcut.request.next_method"),
|
||||
alternates: ["next", "method"],
|
||||
icon: markRaw(IconChevronRight),
|
||||
},
|
||||
previous_method: {
|
||||
text: this.t("shortcut.request.previous_method"),
|
||||
alternates: ["previous", "method"],
|
||||
icon: markRaw(IconChevronLeft),
|
||||
},
|
||||
get_method: {
|
||||
text: [this.t("spotlight.request.select_method"), "GET"],
|
||||
text: this.t("shortcut.request.get_method"),
|
||||
alternates: ["get", "method"],
|
||||
icon: markRaw(IconCheckCircle),
|
||||
excludeFromSearch: computed(() => !this.isRESTPage.value),
|
||||
icon: markRaw(IconCheck),
|
||||
},
|
||||
head_method: {
|
||||
text: [this.t("spotlight.request.select_method"), "HEAD"],
|
||||
text: this.t("shortcut.request.head_method"),
|
||||
alternates: ["head", "method"],
|
||||
icon: markRaw(IconCheckCircle),
|
||||
excludeFromSearch: computed(() => !this.isRESTPage.value),
|
||||
icon: markRaw(IconCheck),
|
||||
},
|
||||
post_method: {
|
||||
text: [this.t("spotlight.request.select_method"), "POST"],
|
||||
text: this.t("shortcut.request.post_method"),
|
||||
alternates: ["post", "method"],
|
||||
icon: markRaw(IconCheckCircle),
|
||||
excludeFromSearch: computed(() => !this.isRESTPage.value),
|
||||
icon: markRaw(IconCheck),
|
||||
},
|
||||
put_method: {
|
||||
text: [this.t("spotlight.request.select_method"), "PUT"],
|
||||
text: this.t("shortcut.request.put_method"),
|
||||
alternates: ["put", "method"],
|
||||
icon: markRaw(IconCheckCircle),
|
||||
excludeFromSearch: computed(() => !this.isRESTPage.value),
|
||||
icon: markRaw(IconCheck),
|
||||
},
|
||||
delete_method: {
|
||||
text: [this.t("spotlight.request.select_method"), "DELETE"],
|
||||
text: this.t("shortcut.request.delete_method"),
|
||||
alternates: ["delete", "method"],
|
||||
icon: markRaw(IconCheckCircle),
|
||||
excludeFromSearch: computed(() => !this.isRESTPage.value),
|
||||
icon: markRaw(IconCheck),
|
||||
},
|
||||
// Change sub tabs
|
||||
tab_parameters: {
|
||||
text: [
|
||||
this.t("spotlight.request.switch_to"),
|
||||
this.t("spotlight.request.tab_parameters"),
|
||||
],
|
||||
text: this.t("spotlight.request.tab_parameters"),
|
||||
alternates: ["parameters", "tab"],
|
||||
icon: markRaw(IconWindow),
|
||||
excludeFromSearch: computed(
|
||||
() => !this.isRESTPage.value ?? !this.isGQLPage.value
|
||||
),
|
||||
},
|
||||
tab_body: {
|
||||
text: [
|
||||
this.t("spotlight.request.switch_to"),
|
||||
this.t("spotlight.request.tab_body"),
|
||||
],
|
||||
text: this.t("spotlight.request.tab_body"),
|
||||
alternates: ["body", "tab"],
|
||||
icon: markRaw(IconWindow),
|
||||
excludeFromSearch: computed(
|
||||
() => !this.isRESTPage.value ?? !this.isGQLPage.value
|
||||
),
|
||||
},
|
||||
tab_headers: {
|
||||
text: [
|
||||
this.t("spotlight.request.switch_to"),
|
||||
this.t("spotlight.request.tab_headers"),
|
||||
],
|
||||
text: this.t("spotlight.request.tab_headers"),
|
||||
alternates: ["headers", "tab"],
|
||||
icon: markRaw(IconWindow),
|
||||
excludeFromSearch: computed(
|
||||
() => !this.isRESTPage.value ?? !this.isGQLPage.value
|
||||
),
|
||||
},
|
||||
tab_authorization: {
|
||||
text: [
|
||||
this.t("spotlight.request.switch_to"),
|
||||
this.t("spotlight.request.tab_authorization"),
|
||||
],
|
||||
text: this.t("spotlight.request.tab_authorization"),
|
||||
alternates: ["authorization", "tab"],
|
||||
icon: markRaw(IconWindow),
|
||||
excludeFromSearch: computed(
|
||||
() => !this.isRESTPage.value ?? !this.isGQLPage.value
|
||||
),
|
||||
},
|
||||
tab_pre_request_script: {
|
||||
text: [
|
||||
this.t("spotlight.request.switch_to"),
|
||||
this.t("spotlight.request.tab_pre_request_script"),
|
||||
],
|
||||
text: this.t("spotlight.request.tab_pre_request_script"),
|
||||
alternates: ["pre-request", "script", "tab"],
|
||||
icon: markRaw(IconWindow),
|
||||
excludeFromSearch: computed(() => !this.isRESTPage.value),
|
||||
},
|
||||
tab_tests: {
|
||||
text: [
|
||||
this.t("spotlight.request.switch_to"),
|
||||
this.t("spotlight.request.tab_tests"),
|
||||
],
|
||||
text: this.t("spotlight.request.tab_tests"),
|
||||
alternates: ["tests", "tab"],
|
||||
icon: markRaw(IconWindow),
|
||||
excludeFromSearch: computed(() => !this.isRESTPage.value),
|
||||
},
|
||||
})
|
||||
|
||||
@@ -253,6 +209,12 @@ export class RequestSpotlightSearcherService extends StaticSpotlightSearcherServ
|
||||
case "reset_request":
|
||||
invokeAction("request.reset")
|
||||
break
|
||||
case "next_method":
|
||||
invokeAction("request.method.next")
|
||||
break
|
||||
case "previous_method":
|
||||
invokeAction("request.method.prev")
|
||||
break
|
||||
case "get_method":
|
||||
invokeAction("request.method.get")
|
||||
break
|
||||
|
||||
@@ -10,10 +10,11 @@ import {
|
||||
} from "./base/static.searcher"
|
||||
|
||||
import IconCloud from "~icons/lucide/cloud"
|
||||
import IconGlobe from "~icons/lucide/globe"
|
||||
import IconMonitor from "~icons/lucide/monitor"
|
||||
import IconMoon from "~icons/lucide/moon"
|
||||
import IconSun from "~icons/lucide/sun"
|
||||
import IconGlobe from "~icons/lucide/globe"
|
||||
import IconShieldCheck from "~icons/lucide/shield-check"
|
||||
import IconType from "~icons/lucide/type"
|
||||
|
||||
type Doc = {
|
||||
@@ -127,6 +128,22 @@ export class SettingsSpotlightSearcherService extends StaticSpotlightSearcherSer
|
||||
alternates: ["language", "change language"],
|
||||
icon: markRaw(IconGlobe),
|
||||
},
|
||||
change_interceptor: {
|
||||
text: [
|
||||
this.t("spotlight.section.interceptor"),
|
||||
this.t("spotlight.settings.change_interceptor"),
|
||||
],
|
||||
alternates: ["interceptor", "change interceptor"],
|
||||
icon: markRaw(IconShieldCheck),
|
||||
},
|
||||
install_ext: {
|
||||
text: [
|
||||
this.t("spotlight.section.interceptor"),
|
||||
this.t("spotlight.settings.install_extension"),
|
||||
],
|
||||
alternates: ["install extension", "extension", "interceptor"],
|
||||
icon: markRaw(IconShieldCheck),
|
||||
},
|
||||
})
|
||||
|
||||
constructor() {
|
||||
@@ -157,12 +174,27 @@ export class SettingsSpotlightSearcherService extends StaticSpotlightSearcherSer
|
||||
applySetting("BG_COLOR", theme)
|
||||
}
|
||||
|
||||
installExtension() {
|
||||
const url = navigator.userAgent.includes("Firefox")
|
||||
? "https://addons.mozilla.org/en-US/firefox/addon/hoppscotch"
|
||||
: "https://chrome.google.com/webstore/detail/hoppscotch-browser-extens/amknoiejhlmhancpahfcfcfhllgkpbld"
|
||||
window.open(url, "_blank")
|
||||
}
|
||||
|
||||
public onDocSelected(id: string): void {
|
||||
switch (id) {
|
||||
case "change_interceptor":
|
||||
invokeAction("navigation.jump.settings")
|
||||
break
|
||||
|
||||
case "change_lang":
|
||||
invokeAction("navigation.jump.settings")
|
||||
break
|
||||
|
||||
case "install_ext":
|
||||
this.installExtension()
|
||||
break
|
||||
|
||||
// theme actions
|
||||
case "theme_system":
|
||||
invokeAction("settings.theme.system")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, computed, markRaw, reactive } from "vue"
|
||||
import { Component, markRaw, reactive } from "vue"
|
||||
import { getI18n } from "~/modules/i18n"
|
||||
import { SpotlightSearcherResult, SpotlightService } from ".."
|
||||
import {
|
||||
@@ -6,23 +6,19 @@ import {
|
||||
StaticSpotlightSearcherService,
|
||||
} from "./base/static.searcher"
|
||||
|
||||
import { useRoute } from "vue-router"
|
||||
import { getDefaultRESTRequest } from "~/helpers/rest/default"
|
||||
import {
|
||||
closeOtherTabs,
|
||||
closeTab,
|
||||
createNewTab,
|
||||
currentTabID,
|
||||
getActiveTabs,
|
||||
} from "~/helpers/rest/tab"
|
||||
import IconWindow from "~icons/lucide/app-window"
|
||||
import { invokeAction } from "~/helpers/actions"
|
||||
import { getDefaultRESTRequest } from "~/helpers/rest/default"
|
||||
|
||||
type Doc = {
|
||||
text: string
|
||||
alternates: string[]
|
||||
icon: object | Component
|
||||
excludeFromSearch?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -41,39 +37,21 @@ export class TabSpotlightSearcherService extends StaticSpotlightSearcherService<
|
||||
|
||||
private readonly spotlight = this.bind(SpotlightService)
|
||||
|
||||
private route = useRoute()
|
||||
private showAction = computed(
|
||||
() => this.route.name === "index" ?? this.route.name === "graphql"
|
||||
)
|
||||
|
||||
private documents: Record<string, Doc> = reactive({
|
||||
duplicate_tab: {
|
||||
text: this.t("spotlight.tab.duplicate"),
|
||||
alternates: ["tab", "duplicate", "duplicate tab"],
|
||||
icon: markRaw(IconWindow),
|
||||
excludeFromSearch: computed(() => !this.showAction.value),
|
||||
},
|
||||
close_current_tab: {
|
||||
text: this.t("spotlight.tab.close_current"),
|
||||
alternates: ["tab", "close", "close tab"],
|
||||
icon: markRaw(IconWindow),
|
||||
excludeFromSearch: computed(
|
||||
() => !this.showAction.value ?? getActiveTabs().value.length === 1
|
||||
),
|
||||
},
|
||||
close_other_tabs: {
|
||||
text: this.t("spotlight.tab.close_others"),
|
||||
alternates: ["tab", "close", "close all"],
|
||||
icon: markRaw(IconWindow),
|
||||
excludeFromSearch: computed(
|
||||
() => !this.showAction.value ?? getActiveTabs().value.length < 2
|
||||
),
|
||||
},
|
||||
open_new_tab: {
|
||||
text: this.t("spotlight.tab.new_tab"),
|
||||
alternates: ["tab", "new", "open tab"],
|
||||
icon: markRaw(IconWindow),
|
||||
excludeFromSearch: computed(() => !this.showAction.value),
|
||||
},
|
||||
})
|
||||
|
||||
@@ -102,10 +80,6 @@ export class TabSpotlightSearcherService extends StaticSpotlightSearcherService<
|
||||
}
|
||||
|
||||
public onDocSelected(id: string): void {
|
||||
if (id === "duplicate_tab")
|
||||
invokeAction("request.duplicate-tab", {
|
||||
tabID: currentTabID.value,
|
||||
})
|
||||
if (id === "close_current_tab") closeTab(currentTabID.value)
|
||||
if (id === "close_other_tabs") closeOtherTabs(currentTabID.value)
|
||||
if (id === "open_new_tab")
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
ref,
|
||||
watch,
|
||||
} from "vue"
|
||||
import { invokeAction } from "~/helpers/actions"
|
||||
import { activeActions$, invokeAction } from "~/helpers/actions"
|
||||
import { getI18n } from "~/modules/i18n"
|
||||
import {
|
||||
SpotlightSearcher,
|
||||
@@ -24,7 +24,6 @@ import {
|
||||
import { Service } from "dioc"
|
||||
import * as E from "fp-ts/Either"
|
||||
import MiniSearch from "minisearch"
|
||||
import IconCheckCircle from "~/components/app/spotlight/entry/IconSelected.vue"
|
||||
import { useStreamStatic } from "~/composables/stream"
|
||||
import { runGQLQuery } from "~/helpers/backend/GQLClient"
|
||||
import { GetMyTeamsDocument, GetMyTeamsQuery } from "~/helpers/backend/graphql"
|
||||
@@ -37,7 +36,7 @@ import IconUserPlus from "~icons/lucide/user-plus"
|
||||
import IconUsers from "~icons/lucide/users"
|
||||
|
||||
type Doc = {
|
||||
text: string | string[]
|
||||
text: string
|
||||
alternates: string[]
|
||||
icon: object | Component
|
||||
excludeFromSearch?: boolean
|
||||
@@ -67,6 +66,14 @@ export class WorkspaceSpotlightSearcherService extends StaticSpotlightSearcherSe
|
||||
}
|
||||
)[0]
|
||||
|
||||
private activeActions = useStreamStatic(activeActions$, [], () => {
|
||||
/* noop */
|
||||
})[0]
|
||||
|
||||
private isLoggedInUser = computed(() =>
|
||||
this.activeActions.value.includes("user.logout")
|
||||
)
|
||||
|
||||
private isTeamSelected = computed(
|
||||
() =>
|
||||
this.workspace.value.type === "team" &&
|
||||
@@ -75,33 +82,31 @@ export class WorkspaceSpotlightSearcherService extends StaticSpotlightSearcherSe
|
||||
|
||||
private documents: Record<string, Doc> = reactive({
|
||||
new_team: {
|
||||
text: [this.t("team.title"), this.t("spotlight.workspace.new")],
|
||||
text: this.t("spotlight.workspace.new"),
|
||||
alternates: ["new", "team", "workspace"],
|
||||
icon: markRaw(IconUsers),
|
||||
excludeFromSearch: computed(() => !this.isLoggedInUser.value),
|
||||
},
|
||||
edit_team: {
|
||||
text: [this.t("team.title"), this.t("spotlight.workspace.edit")],
|
||||
text: this.t("spotlight.workspace.edit"),
|
||||
alternates: ["edit", "team", "workspace"],
|
||||
icon: markRaw(IconEdit),
|
||||
excludeFromSearch: computed(() => !this.isTeamSelected.value),
|
||||
},
|
||||
invite_members: {
|
||||
text: [this.t("team.title"), this.t("spotlight.workspace.invite")],
|
||||
text: this.t("spotlight.workspace.invite"),
|
||||
alternates: ["invite", "members", "workspace"],
|
||||
icon: markRaw(IconUserPlus),
|
||||
excludeFromSearch: computed(() => !this.isTeamSelected.value),
|
||||
},
|
||||
delete_team: {
|
||||
text: [this.t("team.title"), this.t("spotlight.workspace.delete")],
|
||||
text: this.t("spotlight.workspace.delete"),
|
||||
alternates: ["delete", "team", "workspace"],
|
||||
icon: markRaw(IconTrash2),
|
||||
excludeFromSearch: computed(() => !this.isTeamSelected.value),
|
||||
},
|
||||
switch_to_personal: {
|
||||
text: [
|
||||
this.t("team.title"),
|
||||
this.t("spotlight.workspace.switch_to_personal"),
|
||||
],
|
||||
text: this.t("spotlight.workspace.switch_to_personal"),
|
||||
alternates: ["switch", "team", "workspace", "personal"],
|
||||
icon: markRaw(IconUser),
|
||||
excludeFromSearch: computed(() => !this.isTeamSelected.value),
|
||||
@@ -140,13 +145,8 @@ export class WorkspaceSpotlightSearcherService extends StaticSpotlightSearcherSe
|
||||
}
|
||||
|
||||
public onDocSelected(id: string): void {
|
||||
if (id === "new_team") {
|
||||
if (platform.auth.getCurrentUser()) {
|
||||
invokeAction(`modals.team.new`)
|
||||
} else {
|
||||
invokeAction(`modals.login.toggle`)
|
||||
}
|
||||
} else if (id === "edit_team") invokeAction(`modals.team.edit`)
|
||||
if (id === "new_team") invokeAction(`modals.team.new`)
|
||||
else if (id === "edit_team") invokeAction(`modals.team.edit`)
|
||||
else if (id === "invite_members") invokeAction(`modals.team.invite`)
|
||||
else if (id === "delete_team") this.deleteTeam()
|
||||
else if (id === "switch_to_personal")
|
||||
@@ -197,14 +197,6 @@ export class SwitchWorkspaceSpotlightSearcherService
|
||||
})
|
||||
}
|
||||
|
||||
private workspace = useStreamStatic(
|
||||
workspaceStatus$,
|
||||
{ type: "personal" },
|
||||
() => {
|
||||
/* noop */
|
||||
}
|
||||
)[0]
|
||||
|
||||
createSearchSession(
|
||||
query: Readonly<Ref<string>>
|
||||
): [Ref<SpotlightSearcherSessionState>, () => void] {
|
||||
@@ -219,16 +211,8 @@ export class SwitchWorkspaceSpotlightSearcherService
|
||||
this.fetchMyTeams().then((teams) => {
|
||||
minisearch.addAll(
|
||||
teams.map((entry) => {
|
||||
let id = `workspace-${entry.id}`
|
||||
// if id matches add -selected to it
|
||||
if (
|
||||
this.workspace.value.type === "team" &&
|
||||
this.workspace.value.teamID === entry.id
|
||||
) {
|
||||
id += "-selected"
|
||||
}
|
||||
return {
|
||||
id,
|
||||
id: `workspace-${entry.id}`,
|
||||
name: entry.name,
|
||||
alternates: ["team", "workspace", "change", "switch"],
|
||||
}
|
||||
@@ -257,9 +241,7 @@ export class SwitchWorkspaceSpotlightSearcherService
|
||||
.map((x) => {
|
||||
return {
|
||||
id: x.id,
|
||||
icon: markRaw(
|
||||
x.id.endsWith("-selected") ? IconCheckCircle : IconUsers
|
||||
),
|
||||
icon: markRaw(IconUsers),
|
||||
score: x.score,
|
||||
text: {
|
||||
type: "text",
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<script>
|
||||
globalThis.import_meta_env = JSON.parse('"import_meta_env_placeholder"')
|
||||
</script>
|
||||
<title>Hoppscotch • Open source API development ecosystem</title>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
|
||||
@@ -36,7 +36,7 @@ export const META_TAGS = (env: Record<string, string>): IHTMLTag[] => [
|
||||
},
|
||||
{
|
||||
name: "image",
|
||||
content: `${env.APP_BASE_URL}/banner.png`,
|
||||
content: `${env.VITE_BASE_URL}/banner.png`,
|
||||
},
|
||||
// Open Graph tags
|
||||
{
|
||||
@@ -49,7 +49,7 @@ export const META_TAGS = (env: Record<string, string>): IHTMLTag[] => [
|
||||
},
|
||||
{
|
||||
name: "og:image",
|
||||
content: `${env.APP_BASE_URL}/banner.png`,
|
||||
content: `${env.VITE_BASE_URL}/banner.png`,
|
||||
},
|
||||
// Twitter tags
|
||||
{
|
||||
@@ -74,7 +74,7 @@ export const META_TAGS = (env: Record<string, string>): IHTMLTag[] => [
|
||||
},
|
||||
{
|
||||
name: "twitter:image",
|
||||
content: `${env.APP_BASE_URL}/banner.png`,
|
||||
content: `${env.VITE_BASE_URL}/banner.png`,
|
||||
},
|
||||
// Add to homescreen for Chrome on Android. Fallback for PWA (handled by nuxt)
|
||||
{
|
||||
@@ -84,7 +84,7 @@ export const META_TAGS = (env: Record<string, string>): IHTMLTag[] => [
|
||||
// Windows phone tile icon
|
||||
{
|
||||
name: "msapplication-TileImage",
|
||||
content: `${env.APP_BASE_URL}/icon.png`,
|
||||
content: `${env.VITE_BASE_URL}/icon.png`,
|
||||
},
|
||||
{
|
||||
name: "msapplication-TileColor",
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
"@hoppscotch/common": "workspace:^",
|
||||
"@hoppscotch/data": "workspace:^",
|
||||
"axios": "^1.4.0",
|
||||
"@import-meta-env/unplugin": "^0.4.8",
|
||||
"buffer": "^6.0.3",
|
||||
"fp-ts": "^2.16.1",
|
||||
"process": "^0.11.10",
|
||||
@@ -75,7 +74,6 @@
|
||||
"vite-plugin-windicss": "^1.9.1",
|
||||
"vitest": "^0.34.2",
|
||||
"vue-tsc": "^1.8.8",
|
||||
"vite-plugin-fonts": "^0.6.0",
|
||||
"windicss": "^3.5.6"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
#!/usr/local/bin/node
|
||||
import { execSync } from "child_process"
|
||||
import fs from "fs"
|
||||
|
||||
const envFileContent = Object.entries(process.env)
|
||||
.filter(([env]) => env.startsWith("VITE_"))
|
||||
.map(
|
||||
([env, val]) =>
|
||||
`${env}=${val.startsWith('"') && val.endsWith('"') ? val : `"${val}"`}`
|
||||
)
|
||||
.join("\n")
|
||||
|
||||
fs.writeFileSync("build.env", envFileContent)
|
||||
|
||||
execSync(`npx import-meta-env -x build.env -e build.env -p "/site/**/*"`)
|
||||
|
||||
fs.rmSync("build.env")
|
||||
@@ -17,12 +17,10 @@ import { FileSystemIconLoader } from "unplugin-icons/loaders"
|
||||
import * as path from "path"
|
||||
import Unfonts from "unplugin-fonts/vite"
|
||||
import legacy from "@vitejs/plugin-legacy"
|
||||
import ImportMetaEnv from "@import-meta-env/unplugin"
|
||||
|
||||
const ENV = loadEnv("development", path.resolve(__dirname, "../../"), ["VITE_"])
|
||||
const ENV = loadEnv("development", path.resolve(__dirname, "../../"))
|
||||
|
||||
export default defineConfig({
|
||||
envPrefix: process.env.HOPP_ALLOW_RUNTIME_ENV ? "VITE_BUILDTIME_" : "VITE_",
|
||||
envDir: path.resolve(__dirname, "../../"),
|
||||
// TODO: Migrate @hoppscotch/data to full ESM
|
||||
define: {
|
||||
@@ -67,7 +65,6 @@ export default defineConfig({
|
||||
"@lib": path.resolve(__dirname, "./src/lib"),
|
||||
stream: "stream-browserify",
|
||||
util: "util",
|
||||
querystring: "qs",
|
||||
},
|
||||
dedupe: ["vue"],
|
||||
},
|
||||
@@ -81,15 +78,14 @@ export default defineConfig({
|
||||
routeStyle: "nuxt",
|
||||
dirs: "../hoppscotch-common/src/pages",
|
||||
importMode: "async",
|
||||
onRoutesGenerated(routes) {
|
||||
onRoutesGenerated: (routes) =>
|
||||
generateSitemap({
|
||||
routes,
|
||||
nuxtStyle: true,
|
||||
allowRobots: true,
|
||||
dest: ".sitemap-gen",
|
||||
hostname: ENV.VITE_BASE_URL,
|
||||
})
|
||||
},
|
||||
}),
|
||||
}),
|
||||
StaticCopy({
|
||||
targets: [
|
||||
@@ -243,11 +239,5 @@ export default defineConfig({
|
||||
modernPolyfills: ["es.string.replace-all"],
|
||||
renderLegacyChunks: false,
|
||||
}),
|
||||
process.env.HOPP_ALLOW_RUNTIME_ENV
|
||||
? ImportMetaEnv.vite({
|
||||
example: "../../.env.example",
|
||||
env: "../../.env",
|
||||
})
|
||||
: [],
|
||||
],
|
||||
})
|
||||
|
||||
@@ -166,6 +166,12 @@ a {
|
||||
@apply truncate;
|
||||
@apply sm:inline-flex;
|
||||
}
|
||||
|
||||
.env-icon {
|
||||
@apply transition;
|
||||
@apply inline-flex;
|
||||
@apply items-center;
|
||||
}
|
||||
}
|
||||
|
||||
.tippy-svg-arrow {
|
||||
@@ -326,7 +332,7 @@ pre.ace_editor {
|
||||
@apply after:font-icon;
|
||||
@apply after:text-current;
|
||||
@apply after:right-3;
|
||||
@apply after:content-["\e5cf"];
|
||||
@apply after:content-["\e313"];
|
||||
@apply after:text-lg;
|
||||
}
|
||||
|
||||
@@ -481,10 +487,6 @@ pre.ace_editor {
|
||||
}
|
||||
}
|
||||
|
||||
.cm-scroller {
|
||||
@apply overscroll-y-auto;
|
||||
}
|
||||
|
||||
.cm-editor {
|
||||
.cm-line::selection {
|
||||
@apply bg-accentDark #{!important};
|
||||
@@ -572,11 +574,3 @@ details[open] summary .indicator {
|
||||
@apply rounded;
|
||||
@apply border-0;
|
||||
}
|
||||
|
||||
.gql-operation-not-highlight {
|
||||
@apply opacity-50;
|
||||
}
|
||||
|
||||
.gql-operation-highlight {
|
||||
@apply opacity-100;
|
||||
}
|
||||
|
||||
@@ -2,9 +2,6 @@
|
||||
<html lang="en" data-font-size="large">
|
||||
|
||||
<head>
|
||||
<script>
|
||||
globalThis.import_meta_env = JSON.parse('"import_meta_env_placeholder"')
|
||||
</script>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
@@ -17,4 +14,4 @@
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
@@ -96,9 +96,10 @@
|
||||
"load_info_error": "Unable to load team info",
|
||||
"load_list_error": "Unable to Load Teams List",
|
||||
"members": "Number of members",
|
||||
"name": "Team name",
|
||||
"name": "Team Name",
|
||||
"no_members": "No members in this team. Add members to this team to collaborate",
|
||||
"no_pending_invites": "No pending invites",
|
||||
"no_teams": "No teams found",
|
||||
"pending_invites": "Pending invites",
|
||||
"remove": "Remove",
|
||||
"rename": "Rename",
|
||||
@@ -110,6 +111,7 @@
|
||||
"team_members_tab": "Team members",
|
||||
"teams": "Teams",
|
||||
"uid": "UID",
|
||||
"unnamed": "(Unnamed Team)",
|
||||
"valid_name": "Please enter a valid team name",
|
||||
"valid_owner_email": "Please enter a valid owner email"
|
||||
},
|
||||
@@ -123,6 +125,7 @@
|
||||
"created_on": "Created On",
|
||||
"date": "Date",
|
||||
"delete": "Delete",
|
||||
"delete_user": "Delete User",
|
||||
"email": "Email",
|
||||
"email_address": "Email Address",
|
||||
"id": "User ID",
|
||||
|
||||
@@ -51,12 +51,9 @@
|
||||
"@graphql-codegen/typescript-document-nodes": "3.0.0",
|
||||
"@graphql-codegen/typescript-operations": "3.0.0",
|
||||
"@graphql-codegen/urql-introspection": "2.2.1",
|
||||
"@import-meta-env/cli": "^0.6.3",
|
||||
"@import-meta-env/unplugin": "^0.4.8",
|
||||
"@intlify/vite-plugin-vue-i18n": "^7.0.0",
|
||||
"@vitejs/plugin-vue": "^3.1.0",
|
||||
"@vue/compiler-sfc": "^3.2.6",
|
||||
"dotenv": "^16.0.3",
|
||||
"graphql-tag": "^2.12.6",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"sass": "^1.57.1",
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
#!/usr/local/bin/node
|
||||
import { execSync } from "child_process"
|
||||
import fs from "fs"
|
||||
|
||||
const envFileContent = Object.entries(process.env)
|
||||
.filter(([env]) => env.startsWith("VITE_"))
|
||||
.map(([env, val]) => `${env}=${
|
||||
(val.startsWith("\"") && val.endsWith("\""))
|
||||
? val
|
||||
: `"${val}"`
|
||||
}`)
|
||||
.join("\n")
|
||||
|
||||
fs.writeFileSync("build.env", envFileContent)
|
||||
|
||||
execSync(`npx import-meta-env -x build.env -e build.env -p "/site/**/*"`)
|
||||
|
||||
fs.rmSync("build.env")
|
||||
50
packages/hoppscotch-sh-admin/src/components.d.ts
vendored
50
packages/hoppscotch-sh-admin/src/components.d.ts
vendored
@@ -1,44 +1,12 @@
|
||||
// generated by unplugin-vue-components
|
||||
// We suggest you to commit this file into source control
|
||||
// Read more: https://github.com/vuejs/core/pull/3399
|
||||
import '@vue/runtime-core';
|
||||
import '@vue/runtime-core'
|
||||
|
||||
export {};
|
||||
export {}
|
||||
|
||||
declare module '@vue/runtime-core' {
|
||||
export interface GlobalComponents {
|
||||
AppHeader: typeof import('./components/app/Header.vue')['default'];
|
||||
AppLogin: typeof import('./components/app/Login.vue')['default'];
|
||||
AppLogout: typeof import('./components/app/Logout.vue')['default'];
|
||||
AppModal: typeof import('./components/app/Modal.vue')['default'];
|
||||
AppSidebar: typeof import('./components/app/Sidebar.vue')['default'];
|
||||
AppToast: typeof import('./components/app/Toast.vue')['default'];
|
||||
DashboardMetricsCard: typeof import('./components/dashboard/MetricsCard.vue')['default'];
|
||||
HoppButtonPrimary: typeof import('@hoppscotch/ui')['HoppButtonPrimary'];
|
||||
HoppButtonSecondary: typeof import('@hoppscotch/ui')['HoppButtonSecondary'];
|
||||
HoppSmartAnchor: typeof import('@hoppscotch/ui')['HoppSmartAnchor'];
|
||||
HoppSmartAutoComplete: typeof import('@hoppscotch/ui')['HoppSmartAutoComplete'];
|
||||
HoppSmartConfirmModal: typeof import('@hoppscotch/ui')['HoppSmartConfirmModal'];
|
||||
HoppSmartInput: typeof import('@hoppscotch/ui')['HoppSmartInput'];
|
||||
HoppSmartItem: typeof import('@hoppscotch/ui')['HoppSmartItem'];
|
||||
HoppSmartModal: typeof import('@hoppscotch/ui')['HoppSmartModal'];
|
||||
HoppSmartPicture: typeof import('@hoppscotch/ui')['HoppSmartPicture'];
|
||||
HoppSmartSpinner: typeof import('@hoppscotch/ui')['HoppSmartSpinner'];
|
||||
HoppSmartTab: typeof import('@hoppscotch/ui')['HoppSmartTab'];
|
||||
IconLucideArrowLeft: typeof import('~icons/lucide/arrow-left')['default'];
|
||||
IconLucideChevronDown: typeof import('~icons/lucide/chevron-down')['default'];
|
||||
IconLucideHelpCircle: typeof import('~icons/lucide/help-circle')['default'];
|
||||
IconLucideInbox: typeof import('~icons/lucide/inbox')['default'];
|
||||
IconLucideUser: typeof import('~icons/lucide/user')['default'];
|
||||
TeamsAdd: typeof import('./components/teams/Add.vue')['default'];
|
||||
TeamsDetails: typeof import('./components/teams/Details.vue')['default'];
|
||||
TeamsInvite: typeof import('./components/teams/Invite.vue')['default'];
|
||||
TeamsMembers: typeof import('./components/teams/Members.vue')['default'];
|
||||
TeamsPendingInvites: typeof import('./components/teams/PendingInvites.vue')['default'];
|
||||
TeamsTable: typeof import('./components/teams/Table.vue')['default'];
|
||||
Tippy: typeof import('vue-tippy')['Tippy'];
|
||||
UsersInviteModal: typeof import('./components/users/InviteModal.vue')['default'];
|
||||
UsersTable: typeof import('./components/users/Table.vue')['default'];
|
||||
AppHeader: typeof import('./components/app/Header.vue')['default']
|
||||
AppLogin: typeof import('./components/app/Login.vue')['default']
|
||||
AppLogout: typeof import('./components/app/Logout.vue')['default']
|
||||
@@ -49,18 +17,28 @@ declare module '@vue/runtime-core' {
|
||||
HoppButtonPrimary: typeof import('@hoppscotch/ui')['HoppButtonPrimary']
|
||||
HoppButtonSecondary: typeof import('@hoppscotch/ui')['HoppButtonSecondary']
|
||||
HoppSmartAnchor: typeof import('@hoppscotch/ui')['HoppSmartAnchor']
|
||||
HoppSmartAutoComplete: typeof import('@hoppscotch/ui')['HoppSmartAutoComplete']
|
||||
HoppSmartConfirmModal: typeof import('@hoppscotch/ui')['HoppSmartConfirmModal']
|
||||
HoppSmartInput: typeof import('@hoppscotch/ui')['HoppSmartInput']
|
||||
HoppSmartItem: typeof import('@hoppscotch/ui')['HoppSmartItem']
|
||||
HoppSmartModal: typeof import('@hoppscotch/ui')['HoppSmartModal']
|
||||
HoppSmartPicture: typeof import('@hoppscotch/ui')['HoppSmartPicture']
|
||||
HoppSmartPlaceholder: typeof import('@hoppscotch/ui')['HoppSmartPlaceholder']
|
||||
HoppSmartSpinner: typeof import('@hoppscotch/ui')['HoppSmartSpinner']
|
||||
HoppSmartTab: typeof import('@hoppscotch/ui')['HoppSmartTab']
|
||||
HoppSmartTable: typeof import('@hoppscotch/ui')['HoppSmartTable']
|
||||
IconLucideArrowLeft: typeof import('~icons/lucide/arrow-left')['default']
|
||||
IconLucideChevronDown: typeof import('~icons/lucide/chevron-down')['default']
|
||||
IconLucideHelpCircle: typeof import('~icons/lucide/help-circle')['default']
|
||||
IconLucideInbox: typeof import('~icons/lucide/inbox')['default']
|
||||
IconLucideUser: typeof import('~icons/lucide/user')['default']
|
||||
TeamsAdd: typeof import('./components/teams/Add.vue')['default']
|
||||
TeamsDetails: typeof import('./components/teams/Details.vue')['default']
|
||||
TeamsInvite: typeof import('./components/teams/Invite.vue')['default']
|
||||
TeamsMembers: typeof import('./components/teams/Members.vue')['default']
|
||||
TeamsPendingInvites: typeof import('./components/teams/PendingInvites.vue')['default']
|
||||
TeamsTable: typeof import('./components/teams/Table.vue')['default']
|
||||
Tippy: typeof import('vue-tippy')['Tippy']
|
||||
UsersInviteModal: typeof import('./components/users/InviteModal.vue')['default']
|
||||
UsersTable: typeof import('./components/users/Table.vue')['default']
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
<template>
|
||||
<table class="w-full">
|
||||
<thead>
|
||||
<tr class="text-secondary border-b border-dividerDark text-sm text-left">
|
||||
<th class="px-3 pb-3">Team ID</th>
|
||||
<th class="px-3 pb-3">Team Name</th>
|
||||
<th class="px-3 pb-3">Number of Members</th>
|
||||
<th class="px-3 pb-3"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody class="divide-y divide-divider">
|
||||
<tr v-if="teamList.length === 0">
|
||||
<div class="py-6 px-3">No teams found ...</div>
|
||||
</tr>
|
||||
<tr
|
||||
v-else
|
||||
v-for="team in teamList"
|
||||
:key="team.id"
|
||||
class="text-secondaryDark hover:bg-divider hover:cursor-pointer rounded-xl"
|
||||
>
|
||||
<td
|
||||
@click="$emit('go-to-team-details', team.id)"
|
||||
class="py-4 px-3 max-w-50"
|
||||
>
|
||||
<div class="flex">
|
||||
<span class="truncate">
|
||||
{{ team.id }}
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td
|
||||
@click="$emit('go-to-team-details', team.id)"
|
||||
class="py-4 px-3 min-w-80"
|
||||
>
|
||||
<span v-if="team.name" class="flex items-center ml-4 truncate">
|
||||
{{ team.name }}
|
||||
</span>
|
||||
<span v-else class="flex items-center ml-4"> (Unnamed team) </span>
|
||||
</td>
|
||||
|
||||
<td @click="$emit('go-to-team-details', team.id)" class="py-4 px-3">
|
||||
<span class="ml-7">
|
||||
{{ team.members?.length }}
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<div class="relative">
|
||||
<tippy interactive trigger="click" theme="popover">
|
||||
<HoppButtonSecondary
|
||||
v-tippy="{ theme: 'tooltip' }"
|
||||
:icon="IconMoreHorizontal"
|
||||
/>
|
||||
<template #content="{ hide }">
|
||||
<div
|
||||
ref="tippyActions"
|
||||
class="flex flex-col focus:outline-none"
|
||||
tabindex="0"
|
||||
@keyup.escape="hide()"
|
||||
>
|
||||
<HoppSmartItem
|
||||
:icon="IconTrash"
|
||||
:label="'Delete Team'"
|
||||
class="!hover:bg-red-600 w-full"
|
||||
@click="
|
||||
() => {
|
||||
$emit('delete-team', team.id);
|
||||
hide();
|
||||
}
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</tippy>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { TippyComponent } from 'vue-tippy';
|
||||
import { ref } from 'vue';
|
||||
import IconTrash from '~icons/lucide/trash';
|
||||
import IconMoreHorizontal from '~icons/lucide/more-horizontal';
|
||||
import { TeamListQuery } from '~/helpers/backend/graphql';
|
||||
|
||||
// Template refs
|
||||
const tippyActions = ref<TippyComponent | null>(null);
|
||||
|
||||
defineProps<{
|
||||
teamList: TeamListQuery['admin']['allTeams'];
|
||||
}>();
|
||||
|
||||
defineEmits<{
|
||||
(event: 'go-to-team-details', teamID: string): void;
|
||||
(event: 'delete-team', teamID: string): void;
|
||||
}>();
|
||||
</script>
|
||||
@@ -1,168 +0,0 @@
|
||||
<template>
|
||||
<table class="w-full">
|
||||
<thead>
|
||||
<tr class="text-secondary border-b border-dividerDark text-sm text-left">
|
||||
<th class="px-3 pb-3">{{ t('users.id') }}</th>
|
||||
<th class="px-3 pb-3">{{ t('users.name') }}</th>
|
||||
<th class="px-3 pb-3">{{ t('users.email') }}</th>
|
||||
<th class="px-3 pb-3">{{ t('users.date') }}</th>
|
||||
<th class="px-3 pb-3"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody class="divide-y divide-divider">
|
||||
<tr
|
||||
v-for="user in usersList"
|
||||
:key="user.uid"
|
||||
class="text-secondaryDark hover:bg-divider hover:cursor-pointer rounded-xl"
|
||||
>
|
||||
<td
|
||||
@click="$emit('goToUserDetails', user.uid)"
|
||||
class="py-2 px-3 max-w-30"
|
||||
>
|
||||
<div class="flex">
|
||||
<span class="truncate">
|
||||
{{ user.uid }}
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td @click="$emit('goToUserDetails', user.uid)" class="py-2 px-3">
|
||||
<div v-if="user.displayName" class="flex items-center space-x-3">
|
||||
<span>
|
||||
{{ user.displayName }}
|
||||
</span>
|
||||
<span
|
||||
v-if="user.isAdmin"
|
||||
class="text-xs font-medium px-3 py-0.5 rounded-full bg-green-900 text-green-300"
|
||||
>
|
||||
{{ t('users.admin') }}
|
||||
</span>
|
||||
</div>
|
||||
<div v-else class="flex items-center space-x-3">
|
||||
<span> {{ t('users.unnamed') }} </span>
|
||||
<span
|
||||
v-if="user.isAdmin"
|
||||
class="text-xs font-medium px-3 py-0.5 rounded-full bg-green-900 text-green-300"
|
||||
>
|
||||
{{ t('users.admin') }}
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td @click="$emit('goToUserDetails', user.uid)" class="py-2 px-3">
|
||||
<span>
|
||||
{{ user.email }}
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td @click="$emit('goToUserDetails', user.uid)" class="py-2 px-3">
|
||||
<div class="flex items-center">
|
||||
<div class="flex flex-col">
|
||||
{{ getCreatedDate(user.createdOn) }}
|
||||
<div class="text-gray-400 text-tiny">
|
||||
{{ getCreatedTime(user.createdOn) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<div class="relative">
|
||||
<span>
|
||||
<tippy interactive trigger="click" theme="popover">
|
||||
<HoppButtonSecondary
|
||||
v-tippy="{ theme: 'tooltip' }"
|
||||
:icon="IconMoreHorizontal"
|
||||
/>
|
||||
<template #content="{ hide }">
|
||||
<div
|
||||
ref="tippyActions"
|
||||
class="flex flex-col focus:outline-none"
|
||||
tabindex="0"
|
||||
@keyup.escape="hide()"
|
||||
>
|
||||
<HoppSmartItem
|
||||
v-if="!user.isAdmin"
|
||||
:icon="IconUserCheck"
|
||||
:label="'Make Admin'"
|
||||
class="!hover:bg-emerald-600"
|
||||
@click="
|
||||
() => {
|
||||
$emit('makeUserAdmin', user.uid);
|
||||
hide();
|
||||
}
|
||||
"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
v-else
|
||||
:icon="IconUserMinus"
|
||||
:label="'Remove Admin Status'"
|
||||
class="!hover:bg-emerald-600"
|
||||
@click="
|
||||
() => {
|
||||
$emit('makeAdminToUser', user.uid);
|
||||
hide();
|
||||
}
|
||||
"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
v-if="!user.isAdmin"
|
||||
:icon="IconTrash"
|
||||
:label="'Delete User'"
|
||||
class="!hover:bg-red-600"
|
||||
@click="
|
||||
() => {
|
||||
$emit('deleteUser', user.uid);
|
||||
hide();
|
||||
}
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</tippy>
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { format } from 'date-fns';
|
||||
import { ref } from 'vue';
|
||||
import IconTrash from '~icons/lucide/trash';
|
||||
import IconUserMinus from '~icons/lucide/user-minus';
|
||||
import IconUserCheck from '~icons/lucide/user-check';
|
||||
import IconMoreHorizontal from '~icons/lucide/more-horizontal';
|
||||
import { UsersListQuery } from '~/helpers/backend/graphql';
|
||||
import { TippyComponent } from 'vue-tippy';
|
||||
import { useI18n } from '~/composables/i18n';
|
||||
|
||||
const t = useI18n();
|
||||
|
||||
defineProps<{
|
||||
usersList: UsersListQuery['admin']['allUsers'];
|
||||
}>();
|
||||
|
||||
defineEmits<{
|
||||
(event: 'goToUserDetails', uid: string): void;
|
||||
(event: 'makeUserAdmin', uid: string): void;
|
||||
(event: 'makeAdminToUser', uid: string): void;
|
||||
(event: 'deleteUser', uid: string): void;
|
||||
}>();
|
||||
|
||||
// Get Proper Date Formats
|
||||
const getCreatedDate = (date: string) => format(new Date(date), 'dd-MM-yyyy');
|
||||
const getCreatedTime = (date: string) => format(new Date(date), 'hh:mm a');
|
||||
|
||||
// Template refs
|
||||
const tippyActions = ref<TippyComponent | null>(null);
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tippy-box[data-theme~='popover'] .tippy-content {
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
<div class="overflow-x-auto">
|
||||
<div
|
||||
v-if="fetching && !error && teamList.length === 0"
|
||||
v-if="fetching && !error && teamsList.length === 0"
|
||||
class="flex justify-center"
|
||||
>
|
||||
<HoppSmartSpinner />
|
||||
@@ -21,16 +21,94 @@
|
||||
|
||||
<div v-else-if="error">{{ t('teams.load_list_error') }}</div>
|
||||
|
||||
<TeamsTable
|
||||
v-else
|
||||
:teamList="teamList"
|
||||
@goToTeamDetails="goToTeamDetails"
|
||||
@deleteTeam="deleteTeam"
|
||||
class=""
|
||||
/>
|
||||
<div v-else-if="teamsList.length == 0" class="px-2">
|
||||
<p class="text-lg">
|
||||
{{ t('teams.no_teams') }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div v-else>
|
||||
<HoppSmartTable :list="teamsList">
|
||||
<template #head>
|
||||
<tr
|
||||
class="text-secondary border-b border-dividerDark text-sm text-left bg-primaryLight"
|
||||
>
|
||||
<th class="px-6 py-2">{{ t('teams.id') }}</th>
|
||||
<th class="px-6 py-3">{{ t('teams.name') }}</th>
|
||||
<th class="px-6 py-2">{{ t('teams.members') }}</th>
|
||||
<th class="px-6 py-2"></th>
|
||||
</tr>
|
||||
</template>
|
||||
<template #body="{ list }">
|
||||
<tr
|
||||
v-for="team in list"
|
||||
:key="team.id"
|
||||
class="text-secondaryDark hover:bg-divider hover:cursor-pointer rounded-xl"
|
||||
@click="goToTeamDetails(team.id)"
|
||||
>
|
||||
<td class="py-4 px-3 max-w-50">
|
||||
<div class="flex">
|
||||
<span class="truncate">
|
||||
{{ team.id }}
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td class="py-4 px-3 min-w-80">
|
||||
<span
|
||||
v-if="team.name"
|
||||
class="flex items-center ml-4 truncate"
|
||||
>
|
||||
{{ team.name }}
|
||||
</span>
|
||||
<span v-else class="flex items-center ml-4">
|
||||
{{ t('teams.unnamed') }}
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td class="py-4 px-3">
|
||||
<span class="ml-7">
|
||||
{{ team.members?.length }}
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td @click.stop>
|
||||
<div class="relative">
|
||||
<tippy interactive trigger="click" theme="popover">
|
||||
<HoppButtonSecondary
|
||||
v-tippy="{ theme: 'tooltip' }"
|
||||
:icon="IconMoreHorizontal"
|
||||
/>
|
||||
<template #content="{ hide }">
|
||||
<div
|
||||
ref="tippyActions"
|
||||
class="flex flex-col focus:outline-none"
|
||||
tabindex="0"
|
||||
@keyup.escape="hide()"
|
||||
>
|
||||
<HoppSmartItem
|
||||
:icon="IconTrash"
|
||||
:label="t('teams.delete_team')"
|
||||
class="!hover:bg-red-600 w-full"
|
||||
@click="
|
||||
() => {
|
||||
deleteTeam(team.id);
|
||||
hide();
|
||||
}
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</tippy>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
</HoppSmartTable>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="hasNextPage && teamList.length >= teamsPerPage"
|
||||
v-if="hasNextPage && teamsList.length >= teamsPerPage"
|
||||
class="flex justify-center my-5 px-3 py-2 cursor-pointer font-semibold rounded-3xl bg-dividerDark hover:bg-divider transition mx-auto w-38 text-secondaryDark"
|
||||
@click="fetchNextTeams"
|
||||
>
|
||||
@@ -66,10 +144,12 @@ import {
|
||||
UsersListDocument,
|
||||
} from '../../helpers/backend/graphql';
|
||||
import { usePagedQuery } from '~/composables/usePagedQuery';
|
||||
import { ref, watch, computed } from 'vue';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { useMutation, useQuery } from '@urql/vue';
|
||||
import { useToast } from '~/composables/toast';
|
||||
import IconAddUsers from '~icons/lucide/plus';
|
||||
import IconTrash from '~icons/lucide/trash';
|
||||
import IconMoreHorizontal from '~icons/lucide/more-horizontal';
|
||||
import { useI18n } from '~/composables/i18n';
|
||||
|
||||
const t = useI18n();
|
||||
@@ -96,7 +176,7 @@ const {
|
||||
error,
|
||||
goToNextPage: fetchNextTeams,
|
||||
refetch,
|
||||
list: teamList,
|
||||
list: teamsList,
|
||||
hasNextPage,
|
||||
} = usePagedQuery(
|
||||
TeamListDocument,
|
||||
@@ -143,9 +223,7 @@ const createTeam = async (newTeamName: string, ownerEmail: string) => {
|
||||
|
||||
// Go To Individual Team Details Page
|
||||
const router = useRouter();
|
||||
const goToTeamDetails = (teamId: string) => {
|
||||
router.push('/teams/' + teamId);
|
||||
};
|
||||
const goToTeamDetails = (teamId: string) => router.push('/teams/' + teamId);
|
||||
|
||||
// Reload Teams Page when routed back to the teams page
|
||||
const route = useRoute();
|
||||
@@ -175,7 +253,7 @@ const deleteTeamMutation = async (id: string | null) => {
|
||||
if (result.error) {
|
||||
toast.error(`${t('state.delete_team_failure')}`);
|
||||
} else {
|
||||
teamList.value = teamList.value.filter((team) => team.id !== id);
|
||||
teamsList.value = teamsList.value.filter((team) => team.id !== id);
|
||||
toast.success(`${t('state.delete_team_success')}`);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
t('users.uid')
|
||||
}}</label>
|
||||
<div
|
||||
class="w-full p-3 mt-2 bg-zinc-800 border-gray-600 rounded-md focus:border-emerald-600 focus:ring focus:ring-opacity-40 focus:ring-emerald-500"
|
||||
class="w-full p-3 mt-2 bg-divider border-gray-600 rounded-md focus:border-emerald-600 focus:ring focus:ring-opacity-40 focus:ring-emerald-500"
|
||||
>
|
||||
{{ user.uid }}
|
||||
</div>
|
||||
@@ -47,7 +47,7 @@
|
||||
t('users.name')
|
||||
}}</label>
|
||||
<div
|
||||
class="w-full p-3 mt-2 bg-zinc-800 border-gray-600 rounded-md focus:border-emerald-600 focus:ring focus:ring-opacity-40 focus:ring-emerald-500"
|
||||
class="w-full p-3 mt-2 bg-divider border-gray-600 rounded-md focus:border-emerald-600 focus:ring focus:ring-opacity-40 focus:ring-emerald-500"
|
||||
>
|
||||
<span v-if="user.displayName">
|
||||
{{ user.displayName }}
|
||||
@@ -60,7 +60,7 @@
|
||||
t('users.email')
|
||||
}}</label>
|
||||
<div
|
||||
class="w-full p-3 mt-2 bg-zinc-800 border-gray-200 border-gray-600 rounded-md focus:border-emerald-600 focus:ring focus:ring-opacity-40 focus:ring-emerald-500"
|
||||
class="w-full p-3 mt-2 bg-divider border-gray-200 border-gray-600 rounded-md focus:border-emerald-600 focus:ring focus:ring-opacity-40 focus:ring-emerald-500"
|
||||
>
|
||||
{{ user.email }}
|
||||
</div>
|
||||
@@ -70,7 +70,7 @@
|
||||
t('users.created_on')
|
||||
}}</label>
|
||||
<div
|
||||
class="w-full p-3 mt-2 bg-zinc-800 border-gray-600 rounded-md focus:border-emerald-600 focus:ring focus:ring-opacity-40 focus:ring-emerald-500"
|
||||
class="w-full p-3 mt-2 bg-divider border-gray-600 rounded-md focus:border-emerald-600 focus:ring focus:ring-opacity-40 focus:ring-emerald-500"
|
||||
>
|
||||
{{ getCreatedDateAndTime(user.createdOn) }}
|
||||
</div>
|
||||
|
||||
@@ -31,16 +31,139 @@
|
||||
|
||||
<div v-else-if="error">{{ t('users.load_list_error') }}</div>
|
||||
|
||||
<UsersTable
|
||||
v-else-if="usersList.length >= 1"
|
||||
:usersList="usersList"
|
||||
:fetching="fetching"
|
||||
:error="error"
|
||||
@goToUserDetails="goToUserDetails"
|
||||
@makeUserAdmin="makeUserAdmin"
|
||||
@makeAdminToUser="makeAdminToUser"
|
||||
@deleteUser="deleteUser"
|
||||
/>
|
||||
<div v-else-if="usersList.length > 0">
|
||||
<HoppSmartTable :list="usersList">
|
||||
<template #head>
|
||||
<tr
|
||||
class="text-secondary border-b border-dividerDark text-sm text-left bg-primaryLight"
|
||||
>
|
||||
<th class="px-6 py-2">{{ t('users.id') }}</th>
|
||||
<th class="px-6 py-2">{{ t('users.name') }}</th>
|
||||
<th class="px-6 py-2">{{ t('users.email') }}</th>
|
||||
<th class="px-6 py-2">{{ t('users.date') }}</th>
|
||||
<th class="px-6 py-2"></th>
|
||||
</tr>
|
||||
</template>
|
||||
|
||||
<template #body="{ list }">
|
||||
<tr
|
||||
v-for="user in list"
|
||||
:key="user.uid"
|
||||
class="text-secondaryDark hover:bg-divider hover:cursor-pointer rounded-xl"
|
||||
@click="goToUserDetails(user.uid)"
|
||||
>
|
||||
<td class="py-2 px-3 max-w-30">
|
||||
<div class="flex">
|
||||
<span class="truncate">
|
||||
{{ user.uid }}
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td class="py-2 px-3">
|
||||
<div
|
||||
v-if="user.displayName"
|
||||
class="flex items-center space-x-3"
|
||||
>
|
||||
<span>
|
||||
{{ user.displayName }}
|
||||
</span>
|
||||
<span
|
||||
v-if="user.isAdmin"
|
||||
class="text-xs font-medium px-3 py-0.5 rounded-full bg-green-900 text-green-300"
|
||||
>
|
||||
{{ t('users.admin') }}
|
||||
</span>
|
||||
</div>
|
||||
<div v-else class="flex items-center space-x-3">
|
||||
<span> {{ t('users.unnamed') }} </span>
|
||||
<span
|
||||
v-if="user.isAdmin"
|
||||
class="text-xs font-medium px-3 py-0.5 rounded-full bg-green-900 text-green-300"
|
||||
>
|
||||
{{ t('users.admin') }}
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td class="py-2 px-3">
|
||||
<span>
|
||||
{{ user.email }}
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td class="py-2 px-3">
|
||||
<div class="flex items-center">
|
||||
<div class="flex flex-col">
|
||||
{{ getCreatedDate(user.createdOn) }}
|
||||
<div class="text-gray-400 text-tiny">
|
||||
{{ getCreatedTime(user.createdOn) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td @click.stop>
|
||||
<div class="relative">
|
||||
<span>
|
||||
<tippy interactive trigger="click" theme="popover">
|
||||
<HoppButtonSecondary
|
||||
v-tippy="{ theme: 'tooltip' }"
|
||||
:icon="IconMoreHorizontal"
|
||||
/>
|
||||
<template #content="{ hide }">
|
||||
<div
|
||||
ref="tippyActions"
|
||||
class="flex flex-col focus:outline-none"
|
||||
tabindex="0"
|
||||
@keyup.escape="hide()"
|
||||
>
|
||||
<HoppSmartItem
|
||||
v-if="!user.isAdmin"
|
||||
:icon="IconUserCheck"
|
||||
:label="t('users.make_admin')"
|
||||
class="!hover:bg-emerald-600"
|
||||
@click="
|
||||
() => {
|
||||
makeUserAdmin(user.uid);
|
||||
hide();
|
||||
}
|
||||
"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
v-else
|
||||
:icon="IconUserMinus"
|
||||
:label="t('users.remove_admin_status')"
|
||||
class="!hover:bg-emerald-600"
|
||||
@click="
|
||||
() => {
|
||||
makeAdminToUser(user.uid);
|
||||
hide();
|
||||
}
|
||||
"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
v-if="!user.isAdmin"
|
||||
:icon="IconTrash"
|
||||
:label="t('users.delete_user')"
|
||||
class="!hover:bg-red-600"
|
||||
@click="
|
||||
() => {
|
||||
deleteUser(user.uid);
|
||||
hide();
|
||||
}
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</tippy>
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
</HoppSmartTable>
|
||||
</div>
|
||||
|
||||
<div v-else class="flex justify-center">{{ t('users.no_users') }}</div>
|
||||
|
||||
@@ -82,6 +205,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { format } from 'date-fns';
|
||||
import { ref, watch } from 'vue';
|
||||
import { useMutation } from '@urql/vue';
|
||||
import {
|
||||
@@ -96,8 +220,16 @@ import { useRoute, useRouter } from 'vue-router';
|
||||
import { useToast } from '~/composables/toast';
|
||||
import { HoppButtonSecondary } from '@hoppscotch/ui';
|
||||
import IconAddUser from '~icons/lucide/user-plus';
|
||||
import IconTrash from '~icons/lucide/trash';
|
||||
import IconUserMinus from '~icons/lucide/user-minus';
|
||||
import IconUserCheck from '~icons/lucide/user-check';
|
||||
import IconMoreHorizontal from '~icons/lucide/more-horizontal';
|
||||
import { useI18n } from '~/composables/i18n';
|
||||
|
||||
// Get Proper Date Formats
|
||||
const getCreatedDate = (date: string) => format(new Date(date), 'dd-MM-yyyy');
|
||||
const getCreatedTime = (date: string) => format(new Date(date), 'hh:mm a');
|
||||
|
||||
const t = useI18n();
|
||||
|
||||
const toast = useToast();
|
||||
@@ -141,9 +273,7 @@ const sendInvite = async (email: string) => {
|
||||
// Go to Individual User Details Page
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const goToUserDetails = (uid: string) => {
|
||||
router.push('/users/' + uid);
|
||||
};
|
||||
const goToUserDetails = (uid: string) => router.push('/users/' + uid);
|
||||
|
||||
watch(
|
||||
() => route.params.id,
|
||||
|
||||
@@ -16,64 +16,36 @@
|
||||
<div v-if="fetching" class="flex justify-center">
|
||||
<HoppSmartSpinner />
|
||||
</div>
|
||||
<div v-else-if="error || invitedUsers === undefined">
|
||||
<div
|
||||
v-else-if="
|
||||
error || invitedUsers === undefined || invitedUsers.length === 0
|
||||
"
|
||||
>
|
||||
<p class="text-xl">{{ t('users.no_invite') }}</p>
|
||||
</div>
|
||||
|
||||
<table v-else class="w-full text-left">
|
||||
<thead>
|
||||
<tr
|
||||
class="text-secondary border-b border-dividerDark text-sm text-left"
|
||||
>
|
||||
<th class="px-3 pb-3">{{ t('users.admin_id') }}</th>
|
||||
<th class="px-3 pb-3">{{ t('users.admin_email') }}</th>
|
||||
<th class="px-3 pb-3">{{ t('users.invitee_email') }}</th>
|
||||
<th class="px-3 pb-3">{{ t('users.invited_on') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-divider">
|
||||
<tr
|
||||
v-if="invitedUsers.length === 0"
|
||||
class="text-secondaryDark py-4"
|
||||
>
|
||||
<div class="py-6 px-3">{{ t('users.no_invite') }}</div>
|
||||
</tr>
|
||||
<tr
|
||||
v-else
|
||||
v-for="(user, index) in invitedUsers"
|
||||
:key="index"
|
||||
class="text-secondaryDark hover:bg-zinc-800 hover:cursor-pointer rounded-xl"
|
||||
>
|
||||
<td class="py-2 px-3 max-w-30">
|
||||
<div v-else>
|
||||
<HoppSmartTable :list="newInvitedUsersList" :headings="headings">
|
||||
<template #invitedOn="{ item }">
|
||||
<div class="flex flex-col truncate">
|
||||
<span v-if="item" class="truncate">
|
||||
{{ getCreatedDate(item.invitedOn) }}
|
||||
</span>
|
||||
<span v-else> - </span>
|
||||
|
||||
<div>
|
||||
<span class="truncate">
|
||||
{{ user?.adminUid }}
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="py-2 px-3">
|
||||
<span class="flex items-center">
|
||||
{{ user?.adminEmail }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="py-2 px-3">
|
||||
<span>
|
||||
{{ user?.inviteeEmail }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="py-2 px-3">
|
||||
<div class="flex items-center">
|
||||
<div class="flex flex-col">
|
||||
{{ getCreatedDate(user?.invitedOn) }}
|
||||
<div class="text-gray-400 text-xs">
|
||||
{{ getCreatedTime(user?.invitedOn) }}
|
||||
</div>
|
||||
<div class="text-gray-400 text-tiny">
|
||||
<span>
|
||||
<span>
|
||||
{{ getCreatedTime(item.invitedOn) }}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</template>
|
||||
</HoppSmartTable>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -100,4 +72,24 @@ const getCreatedTime = (date: string) => format(new Date(date), 'hh:mm a');
|
||||
// Get Invited Users
|
||||
const { fetching, error, data } = useQuery({ query: InvitedUsersDocument });
|
||||
const invitedUsers = computed(() => data?.value?.admin.invitedUsers);
|
||||
|
||||
// The new invited users list that is used in the table
|
||||
const newInvitedUsersList = computed(() => {
|
||||
return invitedUsers.value?.map((user) => {
|
||||
return {
|
||||
adminUid: user.adminUid,
|
||||
adminEmail: user.adminEmail,
|
||||
inviteeEmail: user.inviteeEmail,
|
||||
invitedOn: user.invitedOn,
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
// Table Headings
|
||||
const headings = [
|
||||
{ key: 'adminUid', label: t('users.admin_id') },
|
||||
{ key: 'adminEmail', label: t('users.admin_email') },
|
||||
{ key: 'inviteeEmail', label: t('users.invitee_email') },
|
||||
{ key: 'invitedOn', label: t('users.invited_on') },
|
||||
];
|
||||
</script>
|
||||
|
||||
@@ -10,15 +10,10 @@ import Pages from 'vite-plugin-pages';
|
||||
import Layouts from 'vite-plugin-vue-layouts';
|
||||
import VueI18n from '@intlify/vite-plugin-vue-i18n';
|
||||
import path from 'path';
|
||||
import ImportMetaEnv from "@import-meta-env/unplugin"
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
envPrefix:
|
||||
process.env.HOPP_ALLOW_RUNTIME_ENV
|
||||
? "VITE_BUILDTIME_"
|
||||
: "VITE_",
|
||||
envDir: path.resolve(__dirname, "../.."),
|
||||
envDir: path.resolve(__dirname, '../../'),
|
||||
server: {
|
||||
port: 3100,
|
||||
},
|
||||
@@ -90,13 +85,7 @@ export default defineConfig({
|
||||
variables: ["variable-full"],
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
}),
|
||||
process.env.HOPP_ALLOW_RUNTIME_ENV
|
||||
? ImportMetaEnv.vite({
|
||||
example: "../../.env.example",
|
||||
env: "../../.env",
|
||||
})
|
||||
: [],
|
||||
],
|
||||
});
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
"do-build-ui": "pnpm run story:build"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vue": "^3.2.25"
|
||||
"vue": "^3.2.25",
|
||||
"vue-router": "^4.0.16"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fontsource-variable/inter": "^5.0.5",
|
||||
@@ -24,10 +25,25 @@
|
||||
"@lezer/highlight": "^1.0.0",
|
||||
"@vitejs/plugin-legacy": "^2.3.0",
|
||||
"@vueuse/core": "^8.7.5",
|
||||
"@vueuse/head": "^0.7.9",
|
||||
"acorn-walk": "^8.2.0",
|
||||
"esprima": "^4.0.1",
|
||||
"events": "^3.3.0",
|
||||
"fp-ts": "^2.12.1",
|
||||
"globalthis": "^1.0.3",
|
||||
"lodash-es": "^4.17.21",
|
||||
"path": "^0.12.7",
|
||||
"rxjs": "^7.5.5",
|
||||
"splitpanes": "^3.1.1",
|
||||
"tern": "^0.24.3",
|
||||
"timers": "^0.1.1",
|
||||
"tippy.js": "^6.3.7",
|
||||
"url": "^0.11.0",
|
||||
"util": "^0.12.4",
|
||||
"vite-plugin-eslint": "^1.8.1",
|
||||
"vue-github-button": "^3.0.3",
|
||||
"vue-router": "^4.0.16",
|
||||
"vue-tippy": "6.0.0-alpha.58",
|
||||
"vuedraggable-es": "^4.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -45,10 +61,12 @@
|
||||
"@vue/compiler-sfc": "^3.2.39",
|
||||
"@vue/eslint-config-typescript": "^11.0.1",
|
||||
"@vue/runtime-core": "^3.2.39",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "^8.24.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"eslint-plugin-vue": "^9.5.1",
|
||||
"histoire": "^0.12.4",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"rollup-plugin-polyfill-node": "^0.10.1",
|
||||
"sass": "^1.53.0",
|
||||
"typescript": "^4.5.4",
|
||||
@@ -67,6 +85,8 @@
|
||||
"vite-plugin-vue-layouts": "^0.7.0",
|
||||
"vite-plugin-windicss": "^1.8.8",
|
||||
"vue": "^3.2.25",
|
||||
"vue-loader": "^16.8.3",
|
||||
"vue-router": "^4.0.16",
|
||||
"vue-tsc": "^0.38.2",
|
||||
"windicss": "^3.5.6"
|
||||
},
|
||||
|
||||
@@ -166,6 +166,12 @@ a {
|
||||
@apply truncate;
|
||||
@apply sm:inline-flex;
|
||||
}
|
||||
|
||||
.env-icon {
|
||||
@apply transition;
|
||||
@apply inline-flex;
|
||||
@apply items-center;
|
||||
}
|
||||
}
|
||||
|
||||
.tippy-svg-arrow {
|
||||
@@ -326,7 +332,7 @@ pre.ace_editor {
|
||||
@apply after:font-icon;
|
||||
@apply after:text-current;
|
||||
@apply after:right-3;
|
||||
@apply after:content-["\e5cf"];
|
||||
@apply after:content-["\e313"];
|
||||
@apply after:text-lg;
|
||||
}
|
||||
|
||||
@@ -481,10 +487,6 @@ pre.ace_editor {
|
||||
}
|
||||
}
|
||||
|
||||
.cm-scroller {
|
||||
@apply overscroll-y-auto;
|
||||
}
|
||||
|
||||
.cm-editor {
|
||||
.cm-line::selection {
|
||||
@apply bg-accentDark #{!important};
|
||||
@@ -572,11 +574,3 @@ details[open] summary .indicator {
|
||||
@apply rounded;
|
||||
@apply border-0;
|
||||
}
|
||||
|
||||
.gql-operation-not-highlight {
|
||||
@apply opacity-50;
|
||||
}
|
||||
|
||||
.gql-operation-highlight {
|
||||
@apply opacity-100;
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ const emit = defineEmits<{
|
||||
@apply font-icon;
|
||||
@apply mr-2;
|
||||
@apply transition;
|
||||
@apply content-["\e5ca"];
|
||||
@apply content-["\e876"];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
68
packages/hoppscotch-ui/src/components/smart/Table.vue
Normal file
68
packages/hoppscotch-ui/src/components/smart/Table.vue
Normal file
@@ -0,0 +1,68 @@
|
||||
<template>
|
||||
<div class="overflow-auto rounded-md border border-dividerDark shadow-md">
|
||||
<table class="w-full">
|
||||
<thead>
|
||||
<slot name="head">
|
||||
<tr
|
||||
class="text-secondary border-b border-dividerDark text-sm text-left bg-primaryLight"
|
||||
>
|
||||
<th v-for="th in headings" scope="col" class="px-6 py-3">
|
||||
{{ th.label ?? th.key }}
|
||||
</th>
|
||||
</tr>
|
||||
</slot>
|
||||
</thead>
|
||||
|
||||
<tbody class="divide-y divide-divider">
|
||||
<slot name="body" :list="list">
|
||||
<tr
|
||||
v-for="(rowData, rowIndex) in list"
|
||||
:key="rowIndex"
|
||||
class="text-secondaryDark hover:bg-divider hover:cursor-pointer rounded-xl"
|
||||
:class="yBorder ? 'divide-x divide-divider' : ''"
|
||||
>
|
||||
<td
|
||||
v-for="cellHeading in headings"
|
||||
:key="cellHeading.key"
|
||||
@click="!cellHeading.preventClick && onRowClicked(rowData)"
|
||||
class="max-w-40 pl-6 py-1"
|
||||
>
|
||||
<!-- Dynamic column slot -->
|
||||
<slot :name="cellHeading.key" :item="rowData">
|
||||
<!-- Generic implementation of the column -->
|
||||
<div class="flex flex-col truncate">
|
||||
<span class="truncate">
|
||||
{{ rowData[cellHeading.key] ?? "-" }}
|
||||
</span>
|
||||
</div>
|
||||
</slot>
|
||||
</td>
|
||||
</tr>
|
||||
</slot>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup generic="Item extends Record<string, unknown>">
|
||||
export type CellHeading = {
|
||||
key: string
|
||||
label?: string
|
||||
preventClick?: boolean
|
||||
}
|
||||
|
||||
defineProps<{
|
||||
/** Whether to show the vertical border between columns */
|
||||
yBorder?: boolean
|
||||
/** The list of items to be displayed in the table */
|
||||
list?: Item[]
|
||||
/** The headings of the table */
|
||||
headings?: CellHeading[]
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(event: "onRowClicked", item: Item): void
|
||||
}>()
|
||||
|
||||
const onRowClicked = (item: Item) => emit("onRowClicked", item)
|
||||
</script>
|
||||
@@ -16,6 +16,7 @@ export { default as HoppSmartSlideOver } from "./SlideOver.vue"
|
||||
export { default as HoppSmartSpinner } from "./Spinner.vue"
|
||||
export { default as HoppSmartTab } from "./Tab.vue"
|
||||
export { default as HoppSmartTabs } from "./Tabs.vue"
|
||||
export { default as HoppSmartTable } from "./Table.vue"
|
||||
export { default as HoppSmartToggle } from "./Toggle.vue"
|
||||
export { default as HoppSmartWindow } from "./Window.vue"
|
||||
export { default as HoppSmartWindows } from "./Windows.vue"
|
||||
|
||||
58
packages/hoppscotch-ui/src/stories/Table.story.vue
Normal file
58
packages/hoppscotch-ui/src/stories/Table.story.vue
Normal file
@@ -0,0 +1,58 @@
|
||||
<template>
|
||||
<Story title="Table">
|
||||
<Variant title="General">
|
||||
<HoppSmartTable :list="list" :headings="headings" />
|
||||
</Variant>
|
||||
<Variant title="Custom">
|
||||
<HoppSmartTable>
|
||||
<template #head>
|
||||
<th>ID</th>
|
||||
<th>Name</th>
|
||||
<th>Members</th>
|
||||
<th>Role</th>
|
||||
</template>
|
||||
<template #body>
|
||||
<tr>
|
||||
<td>123454</td>
|
||||
<td>Joel</td>
|
||||
<td>10</td>
|
||||
<td>Frontend Engineer</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>123456</td>
|
||||
<td>Anwar</td>
|
||||
<td>12</td>
|
||||
<td>Frontend Engineer</td>
|
||||
</tr>
|
||||
</template>
|
||||
</HoppSmartTable>
|
||||
</Variant>
|
||||
</Story>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { HoppSmartTable } from "../components/smart"
|
||||
|
||||
// Table Headings
|
||||
const headings = [
|
||||
{ key: "id", label: "ID" },
|
||||
{ key: "name", label: "Name" },
|
||||
{ key: "members", label: "Members" },
|
||||
{ key: "role", label: "Role" },
|
||||
]
|
||||
|
||||
const list = [
|
||||
{
|
||||
id: "123455",
|
||||
name: "Joel",
|
||||
members: 10,
|
||||
role: "Frontend Engineer",
|
||||
},
|
||||
{
|
||||
id: "123456",
|
||||
name: "Anwar",
|
||||
members: 12,
|
||||
role: "Frontend Engineer",
|
||||
},
|
||||
]
|
||||
</script>
|
||||
@@ -23,7 +23,14 @@
|
||||
"@workers/*": ["./src/workers/*"],
|
||||
"@functional/*": ["./src/helpers/functional/*"]
|
||||
},
|
||||
"types": ["vite/client", "unplugin-icons/types/vue"]
|
||||
"types": [
|
||||
"vite/client",
|
||||
"unplugin-icons/types/vue",
|
||||
"unplugin-fonts/client",
|
||||
"vite-plugin-pages/client",
|
||||
"vite-plugin-vue-layouts/client",
|
||||
"vite-plugin-pwa/client"
|
||||
]
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"]
|
||||
}
|
||||
|
||||
@@ -11,8 +11,7 @@ export default defineConfig({
|
||||
vue(),
|
||||
dts({
|
||||
insertTypesEntry: true,
|
||||
skipDiagnostics: true,
|
||||
outputDir: ["dist"],
|
||||
outDir: ["dist"],
|
||||
}),
|
||||
WindiCSS({
|
||||
root: path.resolve(__dirname),
|
||||
@@ -49,7 +48,7 @@ export default defineConfig({
|
||||
fileName: (format, entry) => `${entry}.${format}.js`,
|
||||
},
|
||||
rollupOptions: {
|
||||
external: ["vue"],
|
||||
external: ["vue", "vue-router"],
|
||||
output: {
|
||||
exports: "named",
|
||||
},
|
||||
|
||||
384
pnpm-lock.yaml
generated
384
pnpm-lock.yaml
generated
@@ -107,8 +107,8 @@ importers:
|
||||
specifier: ^4.0.0
|
||||
version: 4.0.0(@nestjs/common@9.2.1)(@nestjs/core@9.2.1)(reflect-metadata@0.1.13)
|
||||
'@prisma/client':
|
||||
specifier: ^4.16.2
|
||||
version: 4.16.2(prisma@4.16.2)
|
||||
specifier: ^4.7.1
|
||||
version: 4.8.1(prisma@4.8.1)
|
||||
apollo-server-express:
|
||||
specifier: ^3.11.1
|
||||
version: 3.11.1(express@4.18.2)(graphql@15.8.0)
|
||||
@@ -179,8 +179,8 @@ importers:
|
||||
specifier: ^1.0.0
|
||||
version: 1.0.0
|
||||
prisma:
|
||||
specifier: ^4.16.2
|
||||
version: 4.16.2
|
||||
specifier: ^4.7.1
|
||||
version: 4.8.1
|
||||
reflect-metadata:
|
||||
specifier: ^0.1.13
|
||||
version: 0.1.13
|
||||
@@ -881,9 +881,6 @@ importers:
|
||||
'@hoppscotch/data':
|
||||
specifier: workspace:^
|
||||
version: link:../hoppscotch-data
|
||||
'@import-meta-env/unplugin':
|
||||
specifier: ^0.4.8
|
||||
version: 0.4.8(@import-meta-env/cli@0.6.3)(dotenv@16.3.1)
|
||||
axios:
|
||||
specifier: ^1.4.0
|
||||
version: 1.4.0
|
||||
@@ -987,9 +984,6 @@ importers:
|
||||
vite:
|
||||
specifier: ^4.4.9
|
||||
version: 4.4.9(@types/node@17.0.45)(sass@1.53.0)(terser@5.19.2)
|
||||
vite-plugin-fonts:
|
||||
specifier: ^0.6.0
|
||||
version: 0.6.0(vite@4.4.9)
|
||||
vite-plugin-html-config:
|
||||
specifier: ^1.0.11
|
||||
version: 1.0.11(vite@4.4.9)
|
||||
@@ -1097,7 +1091,7 @@ importers:
|
||||
version: 0.14.9(@vue/compiler-sfc@3.2.45)(vite@3.2.4)
|
||||
unplugin-vue-components:
|
||||
specifier: ^0.21.0
|
||||
version: 0.21.0(esbuild@0.19.2)(rollup@2.79.1)(vite@3.2.4)(vue@3.2.45)
|
||||
version: 0.21.0(esbuild@0.19.2)(rollup@2.79.1)(vite@3.2.4)(vue@3.2.45)(webpack@5.88.2)
|
||||
vue:
|
||||
specifier: ^3.2.6
|
||||
version: 3.2.45
|
||||
@@ -1135,12 +1129,6 @@ importers:
|
||||
'@graphql-codegen/urql-introspection':
|
||||
specifier: 2.2.1
|
||||
version: 2.2.1(graphql@16.6.0)
|
||||
'@import-meta-env/cli':
|
||||
specifier: ^0.6.3
|
||||
version: 0.6.3(@import-meta-env/unplugin@0.4.8)(dotenv@16.3.1)
|
||||
'@import-meta-env/unplugin':
|
||||
specifier: ^0.4.8
|
||||
version: 0.4.8(@import-meta-env/cli@0.6.3)(dotenv@16.3.1)
|
||||
'@intlify/vite-plugin-vue-i18n':
|
||||
specifier: ^7.0.0
|
||||
version: 7.0.0(vite@3.2.4)(vue-i18n@9.2.2)
|
||||
@@ -1150,9 +1138,6 @@ importers:
|
||||
'@vue/compiler-sfc':
|
||||
specifier: ^3.2.6
|
||||
version: 3.2.45
|
||||
dotenv:
|
||||
specifier: ^16.0.3
|
||||
version: 16.3.1
|
||||
graphql-tag:
|
||||
specifier: ^2.12.6
|
||||
version: 2.12.6(graphql@16.6.0)
|
||||
@@ -1213,18 +1198,63 @@ importers:
|
||||
'@vueuse/core':
|
||||
specifier: ^8.7.5
|
||||
version: 8.7.5(vue@3.2.45)
|
||||
'@vueuse/head':
|
||||
specifier: ^0.7.9
|
||||
version: 0.7.9(vue@3.2.45)
|
||||
acorn-walk:
|
||||
specifier: ^8.2.0
|
||||
version: 8.2.0
|
||||
esprima:
|
||||
specifier: ^4.0.1
|
||||
version: 4.0.1
|
||||
events:
|
||||
specifier: ^3.3.0
|
||||
version: 3.3.0
|
||||
fp-ts:
|
||||
specifier: ^2.12.1
|
||||
version: 2.13.1
|
||||
globalthis:
|
||||
specifier: ^1.0.3
|
||||
version: 1.0.3
|
||||
lodash-es:
|
||||
specifier: ^4.17.21
|
||||
version: 4.17.21
|
||||
path:
|
||||
specifier: ^0.12.7
|
||||
version: 0.12.7
|
||||
rxjs:
|
||||
specifier: ^7.5.5
|
||||
version: 7.6.0
|
||||
splitpanes:
|
||||
specifier: ^3.1.1
|
||||
version: 3.1.1
|
||||
tern:
|
||||
specifier: ^0.24.3
|
||||
version: 0.24.3
|
||||
timers:
|
||||
specifier: ^0.1.1
|
||||
version: 0.1.1
|
||||
tippy.js:
|
||||
specifier: ^6.3.7
|
||||
version: 6.3.7
|
||||
url:
|
||||
specifier: ^0.11.0
|
||||
version: 0.11.0
|
||||
util:
|
||||
specifier: ^0.12.4
|
||||
version: 0.12.4
|
||||
vite-plugin-eslint:
|
||||
specifier: ^1.8.1
|
||||
version: 1.8.1(eslint@8.29.0)(vite@3.2.4)
|
||||
vue-github-button:
|
||||
specifier: ^3.0.3
|
||||
version: 3.0.3
|
||||
vue-router:
|
||||
specifier: ^4.0.16
|
||||
version: 4.1.0(vue@3.2.45)
|
||||
vue-tippy:
|
||||
specifier: 6.0.0-alpha.58
|
||||
version: 6.0.0-alpha.58(vue@3.2.45)
|
||||
vuedraggable-es:
|
||||
specifier: ^4.1.1
|
||||
version: 4.1.1(vue@3.2.45)
|
||||
@@ -1271,6 +1301,9 @@ importers:
|
||||
'@vue/runtime-core':
|
||||
specifier: ^3.2.39
|
||||
version: 3.2.45
|
||||
cross-env:
|
||||
specifier: ^7.0.3
|
||||
version: 7.0.3
|
||||
eslint:
|
||||
specifier: ^8.24.0
|
||||
version: 8.29.0
|
||||
@@ -1283,6 +1316,9 @@ importers:
|
||||
histoire:
|
||||
specifier: ^0.12.4
|
||||
version: 0.12.4(@types/node@17.0.45)(sass@1.53.0)(terser@5.19.2)(vite@3.2.4)
|
||||
npm-run-all:
|
||||
specifier: ^4.1.5
|
||||
version: 4.1.5
|
||||
rollup-plugin-polyfill-node:
|
||||
specifier: ^0.10.1
|
||||
version: 0.10.1(rollup@2.79.1)
|
||||
@@ -1300,7 +1336,7 @@ importers:
|
||||
version: 0.15.3(@vue/compiler-sfc@3.2.45)
|
||||
unplugin-vue-components:
|
||||
specifier: ^0.21.0
|
||||
version: 0.21.0(esbuild@0.19.2)(rollup@2.79.1)(vite@3.2.4)(vue@3.2.45)
|
||||
version: 0.21.0(esbuild@0.19.2)(rollup@2.79.1)(vite@3.2.4)(vue@3.2.45)(webpack@5.88.2)
|
||||
vite:
|
||||
specifier: ^3.2.3
|
||||
version: 3.2.4(@types/node@17.0.45)(sass@1.53.0)(terser@5.19.2)
|
||||
@@ -1337,6 +1373,9 @@ importers:
|
||||
vue:
|
||||
specifier: ^3.2.25
|
||||
version: 3.2.45
|
||||
vue-loader:
|
||||
specifier: ^16.8.3
|
||||
version: 16.8.3(@vue/compiler-sfc@3.2.45)(vue@3.2.45)(webpack@5.88.2)
|
||||
vue-tsc:
|
||||
specifier: ^0.38.2
|
||||
version: 0.38.2(typescript@4.9.3)
|
||||
@@ -5978,47 +6017,6 @@ packages:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/@import-meta-env/cli@0.6.3(@import-meta-env/unplugin@0.4.8)(dotenv@16.3.1):
|
||||
resolution: {integrity: sha512-R0tAmEpNXjqvFgWpnPkODAKaBUKQzCUVzb7DDsOxe1OQxz32ja4W1jdtZikapkh4ZjGnJ7S+kCjKTOfh8qSUOQ==}
|
||||
engines: {node: '>= 14'}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
'@import-meta-env/babel': ^0.4.3
|
||||
'@import-meta-env/swc': ^0.4.5
|
||||
'@import-meta-env/unplugin': ^0.4.8
|
||||
dotenv: ^11.0.0 || ^12.0.4 || ^13.0.1 || ^14.3.2 || ^15.0.1 || ^16.0.0
|
||||
peerDependenciesMeta:
|
||||
'@import-meta-env/babel':
|
||||
optional: true
|
||||
'@import-meta-env/swc':
|
||||
optional: true
|
||||
'@import-meta-env/unplugin':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@import-meta-env/unplugin': 0.4.8(@import-meta-env/cli@0.6.3)(dotenv@16.3.1)
|
||||
commander: 10.0.1
|
||||
dotenv: 16.3.1
|
||||
glob: 10.2.7
|
||||
picocolors: 1.0.0
|
||||
serialize-javascript: 6.0.1
|
||||
|
||||
/@import-meta-env/unplugin@0.4.8(@import-meta-env/cli@0.6.3)(dotenv@16.3.1):
|
||||
resolution: {integrity: sha512-NMyC8BzR8+cl7Ht6vZPMqYeR60zxEwB5Yo/OsM5DSaLpD/L04jqQQIxeQDmg5/jRqi+OPc7KPTBhYccjSByNpA==}
|
||||
engines: {node: '>= 14'}
|
||||
peerDependencies:
|
||||
'@import-meta-env/cli': ^0.5.1 || ^0.6.0
|
||||
dotenv: ^11.0.0 || ^12.0.4 || ^13.0.1 || ^14.3.2 || ^15.0.1 || ^16.0.0
|
||||
peerDependenciesMeta:
|
||||
'@import-meta-env/cli':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@import-meta-env/cli': 0.6.3(@import-meta-env/unplugin@0.4.8)(dotenv@16.3.1)
|
||||
dotenv: 16.3.1
|
||||
magic-string: 0.30.2
|
||||
object-hash: 3.0.0
|
||||
picocolors: 1.0.0
|
||||
unplugin: 1.2.0
|
||||
|
||||
/@intlify/bundle-utils@3.4.0(vue-i18n@9.2.2):
|
||||
resolution: {integrity: sha512-2UQkqiSAOSPEHMGWlybqWm4G2K0X+FyYho5AwXz6QklSX1EY5EDmOSxZmwscn2qmKBnp6OYsme5kUrnN9xrWzQ==}
|
||||
engines: {node: '>= 12'}
|
||||
@@ -6210,17 +6208,6 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@isaacs/cliui@8.0.2:
|
||||
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
|
||||
engines: {node: '>=12'}
|
||||
dependencies:
|
||||
string-width: 5.1.2
|
||||
string-width-cjs: /string-width@4.2.3
|
||||
strip-ansi: 7.1.0
|
||||
strip-ansi-cjs: /strip-ansi@6.0.1
|
||||
wrap-ansi: 8.1.0
|
||||
wrap-ansi-cjs: /wrap-ansi@7.0.0
|
||||
|
||||
/@istanbuljs/load-nyc-config@1.1.0:
|
||||
resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -7281,12 +7268,6 @@ packages:
|
||||
resolution: {integrity: sha512-m7X9U6BG2+J+R1lSOdCiITLLrxm+cWlNI3HUFA92oLO77ObGNzaKdh8pMLqdZcshtkKuV84olNNXDfMc4FezBQ==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
/@pkgjs/parseargs@0.11.0:
|
||||
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
|
||||
engines: {node: '>=14'}
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/@pkgr/utils@2.4.2:
|
||||
resolution: {integrity: sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw==}
|
||||
engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
|
||||
@@ -7307,8 +7288,8 @@ packages:
|
||||
resolution: {integrity: sha512-9X2obfABZuDVLCgPK9aX0a/x4jaOEweTTWE2+9sr0Qqqevj2Uv5XorvusThmc9XGYpS9yI+fhh8RTafBtGposw==}
|
||||
dev: false
|
||||
|
||||
/@prisma/client@4.16.2(prisma@4.16.2):
|
||||
resolution: {integrity: sha512-qCoEyxv1ZrQ4bKy39GnylE8Zq31IRmm8bNhNbZx7bF2cU5aiCCnSa93J2imF88MBjn7J9eUQneNxUQVJdl/rPQ==}
|
||||
/@prisma/client@4.8.1(prisma@4.8.1):
|
||||
resolution: {integrity: sha512-d4xhZhETmeXK/yZ7K0KcVOzEfI5YKGGEr4F5SBV04/MU4ncN/HcE28sy3e4Yt8UFW0ZuImKFQJE+9rWt9WbGSQ==}
|
||||
engines: {node: '>=14.17'}
|
||||
requiresBuild: true
|
||||
peerDependencies:
|
||||
@@ -7317,16 +7298,16 @@ packages:
|
||||
prisma:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@prisma/engines-version': 4.16.1-1.4bc8b6e1b66cb932731fb1bdbbc550d1e010de81
|
||||
prisma: 4.16.2
|
||||
'@prisma/engines-version': 4.8.0-61.d6e67a83f971b175a593ccc12e15c4a757f93ffe
|
||||
prisma: 4.8.1
|
||||
dev: false
|
||||
|
||||
/@prisma/engines-version@4.16.1-1.4bc8b6e1b66cb932731fb1bdbbc550d1e010de81:
|
||||
resolution: {integrity: sha512-q617EUWfRIDTriWADZ4YiWRZXCa/WuhNgLTVd+HqWLffjMSPzyM5uOWoauX91wvQClSKZU4pzI4JJLQ9Kl62Qg==}
|
||||
/@prisma/engines-version@4.8.0-61.d6e67a83f971b175a593ccc12e15c4a757f93ffe:
|
||||
resolution: {integrity: sha512-MHSOSexomRMom8QN4t7bu87wPPD+pa+hW9+71JnVcF3DqyyO/ycCLhRL1we3EojRpZxKvuyGho2REQsMCvxcJw==}
|
||||
dev: false
|
||||
|
||||
/@prisma/engines@4.16.2:
|
||||
resolution: {integrity: sha512-vx1nxVvN4QeT/cepQce68deh/Turxy5Mr+4L4zClFuK1GlxN3+ivxfuv+ej/gvidWn1cE1uAhW7ALLNlYbRUAw==}
|
||||
/@prisma/engines@4.8.1:
|
||||
resolution: {integrity: sha512-93tctjNXcIS+i/e552IO6tqw17sX8liivv8WX9lDMCpEEe3ci+nT9F+1oHtAafqruXLepKF80i/D20Mm+ESlOw==}
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
|
||||
@@ -8000,7 +7981,6 @@ packages:
|
||||
dependencies:
|
||||
'@types/eslint': 8.4.10
|
||||
'@types/estree': 0.0.51
|
||||
dev: true
|
||||
|
||||
/@types/eslint@8.4.10:
|
||||
resolution: {integrity: sha512-Sl/HOqN8NKPmhWo2VBEPm0nvHnu2LL3v9vKo8MEq0EtbJ4eVzGPl41VNPvn5E1i5poMk4/XD8UriLHpJvEP/Nw==}
|
||||
@@ -8017,7 +7997,6 @@ packages:
|
||||
|
||||
/@types/estree@1.0.1:
|
||||
resolution: {integrity: sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==}
|
||||
dev: true
|
||||
|
||||
/@types/express-serve-static-core@4.17.31:
|
||||
resolution: {integrity: sha512-DxMhY+NAsTwMMFHBTtJFNp5qiHKJ7TeqOo23zVEM9alT1Ml27Q3xcTH0xwxn7Q0BbMcVEJOs/7aQtUWupUQN3Q==}
|
||||
@@ -9679,6 +9658,14 @@ packages:
|
||||
- vue
|
||||
dev: false
|
||||
|
||||
/@vueuse/head@0.7.9(vue@3.2.45):
|
||||
resolution: {integrity: sha512-5wnRiH2XIUSLLXJDLDDTcpvAg5QXgTIVZl46AU7to/T91KHsdBLHSE4WhRO7kP0jbkAhlxnx64E29cQtwBrMjg==}
|
||||
peerDependencies:
|
||||
vue: '>=3'
|
||||
dependencies:
|
||||
vue: 3.2.45
|
||||
dev: false
|
||||
|
||||
/@vueuse/head@1.3.1(vue@3.3.4):
|
||||
resolution: {integrity: sha512-XCcHGfDzkGlHS7KIPJVYN//L7jpfASLsN7MUE19ndHVQLnPIDxqFLDl7IROsY81PKzawVAUe4OYVWcGixseWxA==}
|
||||
peerDependencies:
|
||||
@@ -9748,7 +9735,6 @@ packages:
|
||||
dependencies:
|
||||
'@webassemblyjs/helper-numbers': 1.11.6
|
||||
'@webassemblyjs/helper-wasm-bytecode': 1.11.6
|
||||
dev: true
|
||||
|
||||
/@webassemblyjs/floating-point-hex-parser@1.11.1:
|
||||
resolution: {integrity: sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==}
|
||||
@@ -9756,7 +9742,6 @@ packages:
|
||||
|
||||
/@webassemblyjs/floating-point-hex-parser@1.11.6:
|
||||
resolution: {integrity: sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==}
|
||||
dev: true
|
||||
|
||||
/@webassemblyjs/helper-api-error@1.11.1:
|
||||
resolution: {integrity: sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==}
|
||||
@@ -9764,7 +9749,6 @@ packages:
|
||||
|
||||
/@webassemblyjs/helper-api-error@1.11.6:
|
||||
resolution: {integrity: sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==}
|
||||
dev: true
|
||||
|
||||
/@webassemblyjs/helper-buffer@1.11.1:
|
||||
resolution: {integrity: sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==}
|
||||
@@ -9772,7 +9756,6 @@ packages:
|
||||
|
||||
/@webassemblyjs/helper-buffer@1.11.6:
|
||||
resolution: {integrity: sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==}
|
||||
dev: true
|
||||
|
||||
/@webassemblyjs/helper-numbers@1.11.1:
|
||||
resolution: {integrity: sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==}
|
||||
@@ -9788,7 +9771,6 @@ packages:
|
||||
'@webassemblyjs/floating-point-hex-parser': 1.11.6
|
||||
'@webassemblyjs/helper-api-error': 1.11.6
|
||||
'@xtuc/long': 4.2.2
|
||||
dev: true
|
||||
|
||||
/@webassemblyjs/helper-wasm-bytecode@1.11.1:
|
||||
resolution: {integrity: sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==}
|
||||
@@ -9796,7 +9778,6 @@ packages:
|
||||
|
||||
/@webassemblyjs/helper-wasm-bytecode@1.11.6:
|
||||
resolution: {integrity: sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==}
|
||||
dev: true
|
||||
|
||||
/@webassemblyjs/helper-wasm-section@1.11.1:
|
||||
resolution: {integrity: sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==}
|
||||
@@ -9814,7 +9795,6 @@ packages:
|
||||
'@webassemblyjs/helper-buffer': 1.11.6
|
||||
'@webassemblyjs/helper-wasm-bytecode': 1.11.6
|
||||
'@webassemblyjs/wasm-gen': 1.11.6
|
||||
dev: true
|
||||
|
||||
/@webassemblyjs/ieee754@1.11.1:
|
||||
resolution: {integrity: sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==}
|
||||
@@ -9826,7 +9806,6 @@ packages:
|
||||
resolution: {integrity: sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==}
|
||||
dependencies:
|
||||
'@xtuc/ieee754': 1.2.0
|
||||
dev: true
|
||||
|
||||
/@webassemblyjs/leb128@1.11.1:
|
||||
resolution: {integrity: sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==}
|
||||
@@ -9838,7 +9817,6 @@ packages:
|
||||
resolution: {integrity: sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==}
|
||||
dependencies:
|
||||
'@xtuc/long': 4.2.2
|
||||
dev: true
|
||||
|
||||
/@webassemblyjs/utf8@1.11.1:
|
||||
resolution: {integrity: sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==}
|
||||
@@ -9846,7 +9824,6 @@ packages:
|
||||
|
||||
/@webassemblyjs/utf8@1.11.6:
|
||||
resolution: {integrity: sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==}
|
||||
dev: true
|
||||
|
||||
/@webassemblyjs/wasm-edit@1.11.1:
|
||||
resolution: {integrity: sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==}
|
||||
@@ -9872,7 +9849,6 @@ packages:
|
||||
'@webassemblyjs/wasm-opt': 1.11.6
|
||||
'@webassemblyjs/wasm-parser': 1.11.6
|
||||
'@webassemblyjs/wast-printer': 1.11.6
|
||||
dev: true
|
||||
|
||||
/@webassemblyjs/wasm-gen@1.11.1:
|
||||
resolution: {integrity: sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==}
|
||||
@@ -9892,7 +9868,6 @@ packages:
|
||||
'@webassemblyjs/ieee754': 1.11.6
|
||||
'@webassemblyjs/leb128': 1.11.6
|
||||
'@webassemblyjs/utf8': 1.11.6
|
||||
dev: true
|
||||
|
||||
/@webassemblyjs/wasm-opt@1.11.1:
|
||||
resolution: {integrity: sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==}
|
||||
@@ -9910,7 +9885,6 @@ packages:
|
||||
'@webassemblyjs/helper-buffer': 1.11.6
|
||||
'@webassemblyjs/wasm-gen': 1.11.6
|
||||
'@webassemblyjs/wasm-parser': 1.11.6
|
||||
dev: true
|
||||
|
||||
/@webassemblyjs/wasm-parser@1.11.1:
|
||||
resolution: {integrity: sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==}
|
||||
@@ -9932,7 +9906,6 @@ packages:
|
||||
'@webassemblyjs/ieee754': 1.11.6
|
||||
'@webassemblyjs/leb128': 1.11.6
|
||||
'@webassemblyjs/utf8': 1.11.6
|
||||
dev: true
|
||||
|
||||
/@webassemblyjs/wast-printer@1.11.1:
|
||||
resolution: {integrity: sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==}
|
||||
@@ -9946,7 +9919,6 @@ packages:
|
||||
dependencies:
|
||||
'@webassemblyjs/ast': 1.11.6
|
||||
'@xtuc/long': 4.2.2
|
||||
dev: true
|
||||
|
||||
/@wessberg/stringutil@1.0.19:
|
||||
resolution: {integrity: sha512-9AZHVXWlpN8Cn9k5BC/O0Dzb9E9xfEMXzYrNunwvkUTvuK7xgQPVRZpLo+jWCOZ5r8oBa8NIrHuPEu1hzbb6bg==}
|
||||
@@ -10103,11 +10075,9 @@ packages:
|
||||
|
||||
/@xtuc/ieee754@1.2.0:
|
||||
resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==}
|
||||
dev: true
|
||||
|
||||
/@xtuc/long@4.2.2:
|
||||
resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==}
|
||||
dev: true
|
||||
|
||||
/JSONStream@1.3.5:
|
||||
resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==}
|
||||
@@ -10166,7 +10136,6 @@ packages:
|
||||
acorn: ^8
|
||||
dependencies:
|
||||
acorn: 8.10.0
|
||||
dev: true
|
||||
|
||||
/acorn-jsx@5.3.2(acorn@7.4.1):
|
||||
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
|
||||
@@ -10287,7 +10256,6 @@ packages:
|
||||
ajv: ^6.9.1
|
||||
dependencies:
|
||||
ajv: 6.12.6
|
||||
dev: true
|
||||
|
||||
/ajv@6.12.6:
|
||||
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
|
||||
@@ -10916,6 +10884,10 @@ packages:
|
||||
engines: {node: '>=0.6'}
|
||||
dev: true
|
||||
|
||||
/big.js@5.2.2:
|
||||
resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==}
|
||||
dev: true
|
||||
|
||||
/binary-extensions@2.2.0:
|
||||
resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -11368,7 +11340,6 @@ packages:
|
||||
/chrome-trace-event@1.0.3:
|
||||
resolution: {integrity: sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==}
|
||||
engines: {node: '>=6.0'}
|
||||
dev: true
|
||||
|
||||
/ci-info@3.3.2:
|
||||
resolution: {integrity: sha512-xmDt/QIAdeZ9+nfdPsaBCpMvHNLFiLdjj59qjqn+6iPe6YmHGQ35sBnQ8uslRBXFmXkiZQOJRjvQeoGppoTjjg==}
|
||||
@@ -11508,10 +11479,6 @@ packages:
|
||||
dependencies:
|
||||
delayed-stream: 1.0.0
|
||||
|
||||
/commander@10.0.1:
|
||||
resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
/commander@2.20.3:
|
||||
resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
|
||||
|
||||
@@ -12372,6 +12339,7 @@ packages:
|
||||
/dotenv@16.3.1:
|
||||
resolution: {integrity: sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==}
|
||||
engines: {node: '>=12'}
|
||||
dev: true
|
||||
|
||||
/dset@3.1.2:
|
||||
resolution: {integrity: sha512-g/M9sqy3oHe477Ar4voQxWtaPIFw1jTdKZuomOjhCcBx9nHUNn0pu6NopuFFrTh/TRZIKEj+76vLWFu9BNKk+Q==}
|
||||
@@ -12445,6 +12413,11 @@ packages:
|
||||
/emoji-regex@9.2.2:
|
||||
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
|
||||
|
||||
/emojis-list@3.0.0:
|
||||
resolution: {integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==}
|
||||
engines: {node: '>= 4'}
|
||||
dev: true
|
||||
|
||||
/encodeurl@1.0.2:
|
||||
resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==}
|
||||
engines: {node: '>= 0.8'}
|
||||
@@ -12563,7 +12536,6 @@ packages:
|
||||
dependencies:
|
||||
graceful-fs: 4.2.11
|
||||
tapable: 2.2.1
|
||||
dev: true
|
||||
|
||||
/entities@2.1.0:
|
||||
resolution: {integrity: sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==}
|
||||
@@ -12682,7 +12654,6 @@ packages:
|
||||
|
||||
/es-module-lexer@1.3.0:
|
||||
resolution: {integrity: sha512-vZK7T0N2CBmBOixhmjdqx2gWVbFZ4DXZ/NyRMZVlJXPa7CyFS+/a4QQsDGDQy9ZfEzxFuNEsMLeQJnKP2p5/JA==}
|
||||
dev: true
|
||||
|
||||
/es-set-tostringtag@2.0.1:
|
||||
resolution: {integrity: sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==}
|
||||
@@ -13330,7 +13301,6 @@ packages:
|
||||
dependencies:
|
||||
esrecurse: 4.3.0
|
||||
estraverse: 4.3.0
|
||||
dev: true
|
||||
|
||||
/eslint-scope@7.1.1:
|
||||
resolution: {integrity: sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==}
|
||||
@@ -14077,13 +14047,6 @@ packages:
|
||||
dependencies:
|
||||
is-callable: 1.2.7
|
||||
|
||||
/foreground-child@3.1.1:
|
||||
resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==}
|
||||
engines: {node: '>=14'}
|
||||
dependencies:
|
||||
cross-spawn: 7.0.3
|
||||
signal-exit: 4.1.0
|
||||
|
||||
/fork-ts-checker-webpack-plugin@7.2.13(typescript@4.8.4)(webpack@5.74.0):
|
||||
resolution: {integrity: sha512-fR3WRkOb4bQdWB/y7ssDUlVdrclvwtyCUIHCfivAoYxq9dF7XfrDKbMdZIfwJ7hxIAqkYSGeU7lLJE6xrxIBdg==}
|
||||
engines: {node: '>=12.13.0', yarn: '>=1.0.0'}
|
||||
@@ -14391,6 +14354,10 @@ packages:
|
||||
through2: 4.0.2
|
||||
dev: true
|
||||
|
||||
/github-buttons@2.21.1:
|
||||
resolution: {integrity: sha512-n9bCQ8sj+5oX1YH5NeyWGbAclRDtHEhMBzqw2ctsWpdEHOwVgfruRu0VIVy01Ah10dd/iFajMHYU71L7IBWBOw==}
|
||||
dev: false
|
||||
|
||||
/glob-parent@5.1.2:
|
||||
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
|
||||
engines: {node: '>= 6'}
|
||||
@@ -14405,18 +14372,6 @@ packages:
|
||||
|
||||
/glob-to-regexp@0.4.1:
|
||||
resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==}
|
||||
dev: true
|
||||
|
||||
/glob@10.2.7:
|
||||
resolution: {integrity: sha512-jTKehsravOJo8IJxUGfZILnkvVJM/MOfHRs8QcXolVef2zNI9Tqyy5+SeuOAZd3upViEZQLyFpQhYiHLrMUNmA==}
|
||||
engines: {node: '>=16 || 14 >=14.17'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
foreground-child: 3.1.1
|
||||
jackspeak: 2.3.0
|
||||
minimatch: 9.0.3
|
||||
minipass: 6.0.2
|
||||
path-scurry: 1.10.1
|
||||
|
||||
/glob@7.1.6:
|
||||
resolution: {integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==}
|
||||
@@ -14922,6 +14877,10 @@ packages:
|
||||
dependencies:
|
||||
function-bind: 1.1.1
|
||||
|
||||
/hash-sum@2.0.0:
|
||||
resolution: {integrity: sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==}
|
||||
dev: true
|
||||
|
||||
/he@1.2.0:
|
||||
resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
|
||||
hasBin: true
|
||||
@@ -15912,14 +15871,6 @@ packages:
|
||||
resolution: {integrity: sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
/jackspeak@2.3.0:
|
||||
resolution: {integrity: sha512-uKmsITSsF4rUWQHzqaRUuyAir3fZfW3f202Ee34lz/gZCi970CPZwyQXLGNgWJvvZbvFyzeyGq0+4fcG/mBKZg==}
|
||||
engines: {node: '>=14'}
|
||||
dependencies:
|
||||
'@isaacs/cliui': 8.0.2
|
||||
optionalDependencies:
|
||||
'@pkgjs/parseargs': 0.11.0
|
||||
|
||||
/jake@10.8.5:
|
||||
resolution: {integrity: sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==}
|
||||
engines: {node: '>=10'}
|
||||
@@ -16936,7 +16887,6 @@ packages:
|
||||
'@types/node': 18.16.17
|
||||
merge-stream: 2.0.0
|
||||
supports-color: 8.1.1
|
||||
dev: true
|
||||
|
||||
/jest-worker@29.4.1:
|
||||
resolution: {integrity: sha512-O9doU/S1EBe+yp/mstQ0VpPwpv0Clgn68TkNwGxL6/usX/KUW9Arnn4ag8C3jc6qHcXznhsT5Na1liYzAsuAbQ==}
|
||||
@@ -17474,6 +17424,14 @@ packages:
|
||||
/loader-runner@4.3.0:
|
||||
resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==}
|
||||
engines: {node: '>=6.11.5'}
|
||||
|
||||
/loader-utils@2.0.4:
|
||||
resolution: {integrity: sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==}
|
||||
engines: {node: '>=8.9.0'}
|
||||
dependencies:
|
||||
big.js: 5.2.2
|
||||
emojis-list: 3.0.0
|
||||
json5: 2.2.3
|
||||
dev: true
|
||||
|
||||
/local-pkg@0.4.2:
|
||||
@@ -17602,10 +17560,6 @@ packages:
|
||||
dependencies:
|
||||
tslib: 2.6.2
|
||||
|
||||
/lru-cache@10.0.1:
|
||||
resolution: {integrity: sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==}
|
||||
engines: {node: 14 || >=16.14}
|
||||
|
||||
/lru-cache@4.1.5:
|
||||
resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==}
|
||||
dependencies:
|
||||
@@ -17948,6 +17902,7 @@ packages:
|
||||
engines: {node: '>=16 || 14 >=14.17'}
|
||||
dependencies:
|
||||
brace-expansion: 2.0.1
|
||||
dev: true
|
||||
|
||||
/minimist-options@4.1.0:
|
||||
resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==}
|
||||
@@ -17973,10 +17928,6 @@ packages:
|
||||
dependencies:
|
||||
yallist: 4.0.0
|
||||
|
||||
/minipass@6.0.2:
|
||||
resolution: {integrity: sha512-MzWSV5nYVT7mVyWCwn2o7JH13w2TBRmmSqSRCKzTw+lmft9X4z+3wjvs06Tzijo5z4W/kahUCDpRXTF+ZrmF/w==}
|
||||
engines: {node: '>=16 || 14 >=14.17'}
|
||||
|
||||
/minisearch@6.1.0:
|
||||
resolution: {integrity: sha512-PNxA/X8pWk+TiqPbsoIYH0GQ5Di7m6326/lwU/S4mlo4wGQddIcf/V//1f9TB0V4j59b57b+HZxt8h3iMROGvg==}
|
||||
dev: false
|
||||
@@ -19142,13 +19093,6 @@ packages:
|
||||
path-root-regex: 0.1.2
|
||||
dev: true
|
||||
|
||||
/path-scurry@1.10.1:
|
||||
resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==}
|
||||
engines: {node: '>=16 || 14 >=14.17'}
|
||||
dependencies:
|
||||
lru-cache: 10.0.1
|
||||
minipass: 6.0.2
|
||||
|
||||
/path-to-regexp@0.1.7:
|
||||
resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==}
|
||||
|
||||
@@ -19452,13 +19396,13 @@ packages:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
/prisma@4.16.2:
|
||||
resolution: {integrity: sha512-SYCsBvDf0/7XSJyf2cHTLjLeTLVXYfqp7pG5eEVafFLeT0u/hLFz/9W196nDRGUOo1JfPatAEb+uEnTQImQC1g==}
|
||||
/prisma@4.8.1:
|
||||
resolution: {integrity: sha512-ZMLnSjwulIeYfaU1O6/LF6PEJzxN5par5weykxMykS9Z6ara/j76JH3Yo2AH3bgJbPN4Z6NeCK9s5fDkzf33cg==}
|
||||
engines: {node: '>=14.17'}
|
||||
hasBin: true
|
||||
requiresBuild: true
|
||||
dependencies:
|
||||
'@prisma/engines': 4.16.2
|
||||
'@prisma/engines': 4.8.1
|
||||
dev: false
|
||||
|
||||
/process-nextick-args@2.0.1:
|
||||
@@ -19620,6 +19564,10 @@ packages:
|
||||
once: 1.4.0
|
||||
dev: true
|
||||
|
||||
/punycode@1.3.2:
|
||||
resolution: {integrity: sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==}
|
||||
dev: false
|
||||
|
||||
/punycode@1.4.1:
|
||||
resolution: {integrity: sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==}
|
||||
|
||||
@@ -19660,6 +19608,12 @@ packages:
|
||||
dependencies:
|
||||
side-channel: 1.0.4
|
||||
|
||||
/querystring@0.2.0:
|
||||
resolution: {integrity: sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=}
|
||||
engines: {node: '>=0.4.x'}
|
||||
deprecated: The querystring API is considered Legacy. new code should use the URLSearchParams API instead.
|
||||
dev: false
|
||||
|
||||
/querystringify@2.2.0:
|
||||
resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==}
|
||||
dev: true
|
||||
@@ -19698,7 +19652,6 @@ packages:
|
||||
resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
|
||||
dependencies:
|
||||
safe-buffer: 5.2.1
|
||||
dev: true
|
||||
|
||||
/range-parser@1.2.1:
|
||||
resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
|
||||
@@ -20299,7 +20252,6 @@ packages:
|
||||
'@types/json-schema': 7.0.12
|
||||
ajv: 6.12.6
|
||||
ajv-keywords: 3.5.2(ajv@6.12.6)
|
||||
dev: true
|
||||
|
||||
/scuid@1.1.0:
|
||||
resolution: {integrity: sha512-MuCAyrGZcTLfQoH2XoBlQ8C6bzwN88XT/0slOGz0pn8+gIP85BOAfYa44ZXQUTOwRwPU0QvgU+V+OSajl/59Xg==}
|
||||
@@ -20397,7 +20349,6 @@ packages:
|
||||
resolution: {integrity: sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==}
|
||||
dependencies:
|
||||
randombytes: 2.1.0
|
||||
dev: true
|
||||
|
||||
/serve-static@1.15.0:
|
||||
resolution: {integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==}
|
||||
@@ -20488,10 +20439,6 @@ packages:
|
||||
/signal-exit@3.0.7:
|
||||
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
|
||||
|
||||
/signal-exit@4.1.0:
|
||||
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
/signedsource@1.0.0:
|
||||
resolution: {integrity: sha512-6+eerH9fEnNmi/hyM1DXcRK3pWdoMQtlkQ+ns0ntzunjKqp5i3sKCc80ym8Fib3iaYhdJUOPdhlJWj1tvge2Ww==}
|
||||
dev: true
|
||||
@@ -20751,6 +20698,10 @@ packages:
|
||||
through: 2.3.8
|
||||
dev: false
|
||||
|
||||
/splitpanes@3.1.1:
|
||||
resolution: {integrity: sha512-VUkxDJfIGSvTM/fm/+OSrx8ha9URwE/9B8FPvfzoBuAxVELIHBWpsfnJXIXv77zVwuex//QQL4kTU9SDBPeHjA==}
|
||||
dev: false
|
||||
|
||||
/splitpanes@3.1.5:
|
||||
resolution: {integrity: sha512-r3Mq2ITFQ5a2VXLOy4/Sb2Ptp7OfEO8YIbhVJqJXoFc9hc5nTXXkCvtVDjIGbvC0vdE7tse+xTM9BMjsszP6bw==}
|
||||
dev: false
|
||||
@@ -21135,7 +21086,6 @@ packages:
|
||||
engines: {node: '>=10'}
|
||||
dependencies:
|
||||
has-flag: 4.0.0
|
||||
dev: true
|
||||
|
||||
/supports-color@9.2.2:
|
||||
resolution: {integrity: sha512-XC6g/Kgux+rJXmwokjm9ECpD6k/smUoS5LKlUCcsYr4IY3rW0XyAympon2RmxGrlnZURMpg5T18gWDP9CsHXFA==}
|
||||
@@ -21219,7 +21169,6 @@ packages:
|
||||
/tapable@2.2.1:
|
||||
resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==}
|
||||
engines: {node: '>=6'}
|
||||
dev: true
|
||||
|
||||
/tar@6.1.13:
|
||||
resolution: {integrity: sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==}
|
||||
@@ -21292,7 +21241,7 @@ packages:
|
||||
webpack: 5.74.0
|
||||
dev: true
|
||||
|
||||
/terser-webpack-plugin@5.3.9(webpack@5.88.2):
|
||||
/terser-webpack-plugin@5.3.9(esbuild@0.19.2)(webpack@5.88.2):
|
||||
resolution: {integrity: sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==}
|
||||
engines: {node: '>= 10.13.0'}
|
||||
peerDependencies:
|
||||
@@ -21309,12 +21258,12 @@ packages:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@jridgewell/trace-mapping': 0.3.19
|
||||
esbuild: 0.19.2
|
||||
jest-worker: 27.5.1
|
||||
schema-utils: 3.3.0
|
||||
serialize-javascript: 6.0.1
|
||||
terser: 5.19.2
|
||||
webpack: 5.88.2
|
||||
dev: true
|
||||
webpack: 5.88.2(esbuild@0.19.2)
|
||||
|
||||
/terser@5.14.1:
|
||||
resolution: {integrity: sha512-+ahUAE+iheqBTDxXhTisdA8hgvbEG1hHOQ9xmNjeUJSoi6DU/gMrKNcfZjHkyY6Alnuyc+ikYJaxxfHkT3+WuQ==}
|
||||
@@ -21642,7 +21591,7 @@ packages:
|
||||
micromatch: 4.0.5
|
||||
semver: 7.3.8
|
||||
typescript: 4.9.3
|
||||
webpack: 5.88.2
|
||||
webpack: 5.88.2(esbuild@0.19.2)
|
||||
dev: true
|
||||
|
||||
/ts-log@2.2.4:
|
||||
@@ -22295,7 +22244,7 @@ packages:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/unplugin-vue-components@0.21.0(esbuild@0.19.2)(rollup@2.79.1)(vite@3.2.4)(vue@3.2.45):
|
||||
/unplugin-vue-components@0.21.0(esbuild@0.19.2)(rollup@2.79.1)(vite@3.2.4)(vue@3.2.45)(webpack@5.88.2):
|
||||
resolution: {integrity: sha512-U7uOMNmRJ2eAv9CNjP8QRvxs6nAe3FVQUEIUphC1FGguBp3BWSLgGAcSHaX2nQy0gFoDY2mLF2M52W/t/eDaKg==}
|
||||
engines: {node: '>=14'}
|
||||
peerDependencies:
|
||||
@@ -22314,7 +22263,7 @@ packages:
|
||||
magic-string: 0.26.7
|
||||
minimatch: 5.1.6
|
||||
resolve: 1.22.4
|
||||
unplugin: 0.7.1(esbuild@0.19.2)(rollup@2.79.1)(vite@3.2.4)
|
||||
unplugin: 0.7.1(esbuild@0.19.2)(rollup@2.79.1)(vite@3.2.4)(webpack@5.88.2)
|
||||
vue: 3.2.45
|
||||
transitivePeerDependencies:
|
||||
- esbuild
|
||||
@@ -22352,7 +22301,7 @@ packages:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/unplugin@0.7.1(esbuild@0.19.2)(rollup@2.79.1)(vite@3.2.4):
|
||||
/unplugin@0.7.1(esbuild@0.19.2)(rollup@2.79.1)(vite@3.2.4)(webpack@5.88.2):
|
||||
resolution: {integrity: sha512-Z6hNDXDNh9aimMkPU1mEjtk+2ova8gh0y7rJeJdGH1vWZOHwF2lLQiQ/R97rv9ymmzEQXsR2fyMet72T8jy6ew==}
|
||||
peerDependencies:
|
||||
esbuild: '>=0.13'
|
||||
@@ -22374,6 +22323,7 @@ packages:
|
||||
esbuild: 0.19.2
|
||||
rollup: 2.79.1
|
||||
vite: 3.2.4(@types/node@17.0.45)(sass@1.53.0)(terser@5.19.2)
|
||||
webpack: 5.88.2(esbuild@0.19.2)
|
||||
webpack-sources: 3.2.3
|
||||
webpack-virtual-modules: 0.4.4
|
||||
|
||||
@@ -22410,14 +22360,6 @@ packages:
|
||||
webpack-virtual-modules: 0.5.0
|
||||
dev: true
|
||||
|
||||
/unplugin@1.2.0:
|
||||
resolution: {integrity: sha512-7lJXQY4CxOK4jZyVskZuuNBqBSOlxezKqBpfQEpH+Odk2Ban3moKAlvzs9rZuZoZp6/1FEhvY9TZXav2FRhaBg==}
|
||||
dependencies:
|
||||
acorn: 8.10.0
|
||||
chokidar: 3.5.3
|
||||
webpack-sources: 3.2.3
|
||||
webpack-virtual-modules: 0.5.0
|
||||
|
||||
/unplugin@1.4.0:
|
||||
resolution: {integrity: sha512-5x4eIEL6WgbzqGtF9UV8VEC/ehKptPXDS6L2b0mv4FRMkJxRtjaJfOWDd6a8+kYbqsjklix7yWP0N3SUepjXcg==}
|
||||
dependencies:
|
||||
@@ -22493,6 +22435,13 @@ packages:
|
||||
requires-port: 1.0.0
|
||||
dev: true
|
||||
|
||||
/url@0.11.0:
|
||||
resolution: {integrity: sha512-kbailJa29QrtXnxgq+DdCEGlbTeYM2eJUxsz6vjZavrCYPMIFHMKQmSKYAIuUK2i7hgPm28a8piX5NTUtM/LKQ==}
|
||||
dependencies:
|
||||
punycode: 1.3.2
|
||||
querystring: 0.2.0
|
||||
dev: false
|
||||
|
||||
/url@0.11.1:
|
||||
resolution: {integrity: sha512-rWS3H04/+mzzJkv0eZ7vEDGiQbgquI1fGfOad6zKvgYQi1SzMmhl7c/DdRGxhaWrVH6z0qWITo8rpnxK/RfEhA==}
|
||||
dependencies:
|
||||
@@ -22523,6 +22472,17 @@ packages:
|
||||
inherits: 2.0.3
|
||||
dev: false
|
||||
|
||||
/util@0.12.4:
|
||||
resolution: {integrity: sha512-bxZ9qtSlGUWSOy9Qa9Xgk11kSslpuZwaxCg4sNIDj6FLucDab2JxnHwyNTCpHMtK1MjoQiWQ6DiUMZYbSrO+Sw==}
|
||||
dependencies:
|
||||
inherits: 2.0.4
|
||||
is-arguments: 1.1.1
|
||||
is-generator-function: 1.0.10
|
||||
is-typed-array: 1.1.12
|
||||
safe-buffer: 5.2.1
|
||||
which-typed-array: 1.1.11
|
||||
dev: false
|
||||
|
||||
/util@0.12.5:
|
||||
resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==}
|
||||
dependencies:
|
||||
@@ -22812,19 +22772,10 @@ packages:
|
||||
peerDependencies:
|
||||
vite: ^2.0.0 || ^3.0.0
|
||||
dependencies:
|
||||
fast-glob: 3.3.1
|
||||
fast-glob: 3.2.12
|
||||
vite: 3.2.4(@types/node@17.0.45)(sass@1.53.0)(terser@5.19.2)
|
||||
dev: true
|
||||
|
||||
/vite-plugin-fonts@0.6.0(vite@4.4.9):
|
||||
resolution: {integrity: sha512-dV6nnLEju8k5EmvlBH6egxkVZ+rgc5zWsJr9+cNRXBMEDnpRGHcZPI260UEDNg2yB99wSTNER2eduEvZFbMIGw==}
|
||||
peerDependencies:
|
||||
vite: ^2.0.0 || ^3.0.0
|
||||
dependencies:
|
||||
fast-glob: 3.3.1
|
||||
vite: 4.4.9(@types/node@17.0.45)(sass@1.53.0)(terser@5.19.2)
|
||||
dev: true
|
||||
|
||||
/vite-plugin-html-config@1.0.10(vite@3.2.4):
|
||||
resolution: {integrity: sha512-qJCVKC/mR4BIy4EG7AHQ3nGo1BF+3fOjVIka0kXKQMlxT12dl9G5YKmjhLohDzySijOb03R2PzYiAdavwKkqQQ==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
@@ -23635,6 +23586,12 @@ packages:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/vue-github-button@3.0.3:
|
||||
resolution: {integrity: sha512-O2Kv5HxRMn1qqgt2sSy8N7y2C6WGOeICzgGj6y+JFcnLjorTTzNR8vY5abiPOYDiW03WZ/9hUIn7Gm9CG9pIuA==}
|
||||
dependencies:
|
||||
github-buttons: 2.21.1
|
||||
dev: false
|
||||
|
||||
/vue-i18n@9.2.2(vue@3.2.45):
|
||||
resolution: {integrity: sha512-yswpwtj89rTBhegUAv9Mu37LNznyu3NpyLQmozF3i1hYOhwpG8RjcjIFIIfnu+2MDZJGSZPXaKWvnQA71Yv9TQ==}
|
||||
engines: {node: '>= 14'}
|
||||
@@ -23659,6 +23616,26 @@ packages:
|
||||
'@vue/devtools-api': 6.2.1
|
||||
vue: 3.3.4
|
||||
|
||||
/vue-loader@16.8.3(@vue/compiler-sfc@3.2.45)(vue@3.2.45)(webpack@5.88.2):
|
||||
resolution: {integrity: sha512-7vKN45IxsKxe5GcVCbc2qFU5aWzyiLrYJyUuMz4BQLKctCj/fmCa0w6fGiiQ2cLFetNcek1ppGJQDCup0c1hpA==}
|
||||
peerDependencies:
|
||||
'@vue/compiler-sfc': ^3.0.8
|
||||
vue: ^3.2.13
|
||||
webpack: ^4.1.0 || ^5.0.0-0
|
||||
peerDependenciesMeta:
|
||||
'@vue/compiler-sfc':
|
||||
optional: true
|
||||
vue:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@vue/compiler-sfc': 3.2.45
|
||||
chalk: 4.1.2
|
||||
hash-sum: 2.0.0
|
||||
loader-utils: 2.0.4
|
||||
vue: 3.2.45
|
||||
webpack: 5.88.2(esbuild@0.19.2)
|
||||
dev: true
|
||||
|
||||
/vue-pdf-embed@1.1.6(vue@3.3.4):
|
||||
resolution: {integrity: sha512-CRQIw8OxiD6H1n8KT2zVWbp/00fA3PgSV/JYJ0Ut+FdC1jHrRDHNBj3BvaRVwZFZg3EJ8LLjyEDYxWWUMOjrDw==}
|
||||
peerDependencies:
|
||||
@@ -23830,7 +23807,6 @@ packages:
|
||||
dependencies:
|
||||
glob-to-regexp: 0.4.1
|
||||
graceful-fs: 4.2.10
|
||||
dev: true
|
||||
|
||||
/wcwidth@1.0.1:
|
||||
resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==}
|
||||
@@ -23916,6 +23892,7 @@ packages:
|
||||
|
||||
/webpack-virtual-modules@0.5.0:
|
||||
resolution: {integrity: sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw==}
|
||||
dev: true
|
||||
|
||||
/webpack@5.74.0:
|
||||
resolution: {integrity: sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==}
|
||||
@@ -23957,7 +23934,7 @@ packages:
|
||||
- uglify-js
|
||||
dev: true
|
||||
|
||||
/webpack@5.88.2:
|
||||
/webpack@5.88.2(esbuild@0.19.2):
|
||||
resolution: {integrity: sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ==}
|
||||
engines: {node: '>=10.13.0'}
|
||||
hasBin: true
|
||||
@@ -23988,14 +23965,13 @@ packages:
|
||||
neo-async: 2.6.2
|
||||
schema-utils: 3.3.0
|
||||
tapable: 2.2.1
|
||||
terser-webpack-plugin: 5.3.9(webpack@5.88.2)
|
||||
terser-webpack-plugin: 5.3.9(esbuild@0.19.2)(webpack@5.88.2)
|
||||
watchpack: 2.4.0
|
||||
webpack-sources: 3.2.3
|
||||
transitivePeerDependencies:
|
||||
- '@swc/core'
|
||||
- esbuild
|
||||
- uglify-js
|
||||
dev: true
|
||||
|
||||
/whatwg-encoding@1.0.5:
|
||||
resolution: {integrity: sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==}
|
||||
@@ -24462,14 +24438,6 @@ packages:
|
||||
string-width: 4.2.3
|
||||
strip-ansi: 6.0.1
|
||||
|
||||
/wrap-ansi@8.1.0:
|
||||
resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
|
||||
engines: {node: '>=12'}
|
||||
dependencies:
|
||||
ansi-styles: 6.1.0
|
||||
string-width: 5.1.2
|
||||
strip-ansi: 7.1.0
|
||||
|
||||
/wrappy@1.0.2:
|
||||
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
|
||||
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
FROM node:18-alpine3.16 as base_builder
|
||||
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
ENV HOPP_ALLOW_RUNTIME_ENV=true
|
||||
|
||||
RUN npm install -g pnpm
|
||||
COPY pnpm-lock.yaml .
|
||||
RUN pnpm fetch
|
||||
|
||||
COPY . .
|
||||
RUN pnpm install -f --offline
|
||||
|
||||
|
||||
FROM base_builder as backend
|
||||
WORKDIR /usr/src/app/packages/hoppscotch-backend
|
||||
RUN pnpm exec prisma generate
|
||||
RUN pnpm run build
|
||||
# Remove the env file to avoid backend copying it in and using it
|
||||
RUN rm "../../.env"
|
||||
ENV PRODUCTION="true"
|
||||
ENV PORT=3170
|
||||
ENV APP_PORT=${PORT}
|
||||
ENV DB_URL=${DATABASE_URL}
|
||||
CMD ["pnpm", "run", "start:prod"]
|
||||
EXPOSE 3170
|
||||
|
||||
FROM base_builder as fe_builder
|
||||
WORKDIR /usr/src/app/packages/hoppscotch-selfhost-web
|
||||
RUN pnpm run generate
|
||||
|
||||
FROM caddy:2-alpine as app
|
||||
WORKDIR /site
|
||||
COPY --from=fe_builder /usr/src/app/packages/hoppscotch-sh-admin/prod_run.mjs /usr
|
||||
COPY --from=fe_builder /usr/src/app/packages/hoppscotch-selfhost-web/Caddyfile /etc/caddy/Caddyfile
|
||||
COPY --from=fe_builder /usr/src/app/packages/hoppscotch-selfhost-web/dist/ .
|
||||
RUN apk add nodejs npm
|
||||
RUN npm install -g @import-meta-env/cli
|
||||
EXPOSE 8080
|
||||
CMD ["/bin/sh", "-c", "node /usr/prod_run.mjs && caddy run --config /etc/caddy/Caddyfile --adapter caddyfile"]
|
||||
|
||||
FROM base_builder as sh_admin_builder
|
||||
WORKDIR /usr/src/app/packages/hoppscotch-sh-admin
|
||||
RUN pnpm run build
|
||||
|
||||
FROM caddy:2-alpine as sh_admin
|
||||
WORKDIR /site
|
||||
COPY --from=sh_admin_builder /usr/src/app/packages/hoppscotch-sh-admin/prod_run.mjs /usr
|
||||
COPY --from=sh_admin_builder /usr/src/app/packages/hoppscotch-sh-admin/Caddyfile /etc/caddy/Caddyfile
|
||||
COPY --from=sh_admin_builder /usr/src/app/packages/hoppscotch-sh-admin/dist/ .
|
||||
RUN apk add nodejs npm
|
||||
RUN npm install -g @import-meta-env/cli
|
||||
EXPOSE 8080
|
||||
CMD ["/bin/sh", "-c", "node /usr/prod_run.mjs && caddy run --config /etc/caddy/Caddyfile --adapter caddyfile"]
|
||||
|
||||
FROM backend as aio
|
||||
RUN apk add caddy tini
|
||||
RUN npm install -g @import-meta-env/cli
|
||||
COPY --from=fe_builder /usr/src/app/packages/hoppscotch-selfhost-web/dist /site/selfhost-web
|
||||
COPY --from=sh_admin_builder /usr/src/app/packages/hoppscotch-sh-admin/dist /site/sh-admin
|
||||
COPY aio.Caddyfile /etc/caddy/Caddyfile
|
||||
ENTRYPOINT [ "tini", "--" ]
|
||||
RUN apk --no-cache add curl
|
||||
COPY --chmod=755 healthcheck.sh .
|
||||
HEALTHCHECK --interval=2s CMD /bin/sh ./healthcheck.sh
|
||||
CMD ["node", "/usr/src/app/aio_run.mjs"]
|
||||
EXPOSE 3170
|
||||
EXPOSE 3000
|
||||
EXPOSE 3100
|
||||
Reference in New Issue
Block a user