Compare commits

...

45 Commits

Author SHA1 Message Date
liyasthomas
def1b494f4 refactor: polish request section 2021-12-02 21:47:07 +05:30
liyasthomas
99b9ffd293 refactor: clean up boilerplate + init request section 2021-12-02 10:28:29 +05:30
liyasthomas
63005c01ce refactor: clean up boilerplate 2021-12-01 23:15:14 +05:30
liyasthomas
190a4c43ef refactor: clean up boilerplate 2021-11-30 18:52:28 +05:30
liyasthomas
c3fcc6e35d feat: init hoppscotch-embed package 2021-11-30 18:36:52 +05:30
Deepanshu Dhruw
520ac8ede5 fix: code generators (#1985)
Co-authored-by: liyasthomas <liyascthomas@gmail.com>
2021-11-30 07:46:45 +05:30
liyasthomas
2a59557851 chore(deps): bump 2021-11-29 06:19:32 +05:30
liyasthomas
4089bc288c chore: updated i18n translations 2021-11-29 06:14:52 +05:30
liyasthomas
1999819846 chore(deps): bump 2021-11-28 19:48:53 +05:30
liyasthomas
0bf856291c refactor: lint + minor ui fixes 2021-11-27 19:59:28 +05:30
liyasthomas
da8c446ad7 chore(deps): bump 2021-11-27 19:58:08 +05:30
liyasthomas
3614877964 fix: broken scroll to definition in graphql documentation 2021-11-26 07:22:06 +05:30
liyasthomas
85c8171aa8 refactor: use smart confirm modal instead of native confirm modal 2021-11-25 11:37:23 +05:30
liyasthomas
b58278d55e chore: hide scrollbar 2021-11-24 19:27:25 +05:30
liyasthomas
b398ed1e90 fix: improve readability on input placeholders - fixed #1974 2021-11-23 20:22:38 +05:30
liyasthomas
afa750e409 fix: validate empty endpoints before sending request - resolved #1968 2021-11-23 20:01:45 +05:30
liyasthomas
fdf12a24ed refactor: sort windi class names 2021-11-23 08:47:09 +05:30
liyasthomas
4c5ca1b31d Merge branch 'main' of https://github.com/hoppscotch/hoppscotch 2021-11-23 05:31:22 +05:30
liyasthomas
bcb9b97b6b Merge branch 'i18n' 2021-11-23 05:31:01 +05:30
Andrew Bastin
757294ae38 feat: bump dependencies 2021-11-22 19:34:23 +05:30
liyasthomas
8d4dd8c428 chore: better error message in invalid link 2021-11-22 16:31:10 +05:30
liyasthomas
508809eba1 chore: cleanup - remove writing request object to url 2021-11-22 15:02:29 +05:30
liyasthomas
d0386ef86f chore: cleanup 2021-11-22 14:52:14 +05:30
liyasthomas
56cdb79773 Merge branch 'main' into feat/short-code 2021-11-22 11:35:16 +05:30
liyasthomas
6ed4211004 feat: short code redirection 2021-11-22 11:26:43 +05:30
liyasthomas
222f0800d2 chore: better short code fetching 2021-11-22 08:26:22 +05:30
liyasthomas
12a9dd1058 feat: fetch, display and copy short code 2021-11-21 23:50:31 +05:30
Andrew Bastin
4a32fc6180 feat: mutations and queries for shortcode management 2021-11-21 20:02:09 +05:30
liyasthomas
1e08e7f73d chore(deps): bump 2021-11-21 19:47:06 +05:30
liyasthomas
8b05b063ff fix: minor ui improvements 2021-11-21 19:40:15 +05:30
SiderealArt
0bcfeb86ae chore(i18n): update tw translations (#1965) 2021-11-21 08:22:15 +05:30
liyasthomas
03a056b6c1 perf: updated issue templates 2021-11-20 22:43:19 +05:30
liyasthomas
d57e465806 fix: minor ui improvements 2021-11-20 08:28:38 +05:30
liyasthomas
5ab24d1439 docs: updated links + editor theme 2021-11-20 07:27:50 +05:30
liyasthomas
47661de974 refactor: composables for i18n and toast 2021-11-19 22:49:11 +05:30
liyasthomas
26429466e9 refactor: remove icons from toast 2021-11-19 21:13:58 +05:30
Andrew Bastin
cad8f3e856 refactor: add i18n composable 2021-11-19 21:06:04 +05:30
liyasthomas
1a4eb1fabe chore: handle short code states 2021-11-19 12:47:47 +05:30
Liyas Thomas
680f61b7dc docs: create security policy - skip ci 2021-11-19 11:07:26 +05:30
liyasthomas
f602a1e2d3 feat: loading indicator to fetch short code 2021-11-19 09:15:31 +05:30
liyasthomas
1572ff9e67 fix: regression in bulk mode to key-value pair translation 2021-11-19 08:52:58 +05:30
liyasthomas
fe7b236ad9 fix: enable native select on editor - fixed #1960 2021-11-18 18:26:48 +05:30
liyasthomas
3080af1ea5 refactor: migrate more components to setup script + fix a race condition with power search 2021-11-18 07:00:51 +05:30
liyasthomas
0f83c8b490 refactor: hightlight active only when editor is focused 2021-11-17 21:01:43 +05:30
liyasthomas
7d590ab966 feat: init short code ui 2021-11-17 02:36:40 +05:30
255 changed files with 15346 additions and 6695 deletions

View File

@@ -0,0 +1,57 @@
name: Bug report
description: Create a bug report to help us improve Hoppscotch
title: "[bug]: "
labels: [bug, need testing]
body:
- type: markdown
attributes:
value: |
Thank you for taking the time to fill out this bug report.
- type: checkboxes
attributes:
label: Is there an existing issue for this?
description: Please search to see if an issue already exists for the bug you encountered
options:
- label: I have searched the existing issues
required: true
- type: textarea
attributes:
label: Current behavior
description: A concise description of what you're experiencing and what you expect
placeholder: |
When I do <X>, <Y> happens and I see the error message attached below:
```...```
What I expect is <Z>
validations:
required: true
- type: textarea
attributes:
label: Steps to reproduce
description: Add steps to reproduce this behaviour, include console or network logs and screenshots
placeholder: |
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
validations:
required: true
- type: dropdown
id: env
attributes:
label: Environment
options:
- Production
- Release
- Deploy preview
validations:
required: true
- type: dropdown
id: version
attributes:
label: Version
options:
- Cloud
- Self-hosted
- Local
validations:
required: true

View File

@@ -0,0 +1,28 @@
name: Feature request
description: Suggest a feature to improve Hoppscotch
title: "[feature]: "
labels: [feature]
body:
- type: markdown
attributes:
value: |
Thank you for taking the time to request a feature for Hoppscotch
- type: checkboxes
attributes:
label: Is there an existing issue for this?
description: Please search to see if an issue related to this feature request already exists
options:
- label: I have searched the existing issues
required: true
- type: textarea
attributes:
label: Summary
description: One paragraph description of the feature
validations:
required: true
- type: textarea
attributes:
label: Why should this be worked on?
description: A concise description of the problems or use cases for this feature request
validations:
required: true

View File

@@ -1,38 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.

7
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,7 @@
contact_links:
- name: Help and support
url: https://github.com/hoppscotch/hoppscotch#support
about: Reach out to us on our Discord server or Telegram group or GitHub discussions.
- name: Dedicated support
url: mailto:support@hoppscotch.io
about: Write to us if you'd like dedicated support using Hoppscotch

View File

@@ -1,8 +0,0 @@
---
name: Custom issue template
about: Describe this issue template's purpose here.
title: ''
labels: ''
assignees: ''
---

View File

@@ -1,20 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@@ -46,7 +46,7 @@
#### **Support** #### **Support**
[![Chat on Discord](https://img.shields.io/badge/chat-Discord-7289DA?logo=discord)](https://hoppscotch.io/discord) [![Chat on Telegram](https://img.shields.io/badge/chat-Telegram-2CA5E0?logo=Telegram)](https://hoppscotch.io/telegram) [![Chat on Discord](https://img.shields.io/badge/chat-Discord-7289DA?logo=discord)](https://hoppscotch.io/discord) [![Chat on Telegram](https://img.shields.io/badge/chat-Telegram-2CA5E0?logo=telegram)](https://hoppscotch.io/telegram) [![Discuss on GitHub](https://img.shields.io/badge/discussions-GitHub-333333?logo=github)](https://github.com/hoppscotch/hoppscotch/discussions)
<details open> <details open>
<summary><b>Table of contents</b></summary> <summary><b>Table of contents</b></summary>

26
SECURITY.md Normal file
View File

@@ -0,0 +1,26 @@
# Security Policy
This document outlines security procedures and general policies for the Hoppscotch project.
1. [Reporting a security vulnerability](#reporting-a-security-vulnerability)
3. [Incident response process](#incident-response-process)
## Reporting a security vulnerability
Report security vulnerabilities by emailing the Hoppscotch Support team at support@hoppscotch.io.
The primary security point of contact from Hoppscotch Support team will acknowledge your email within 48 hours, and will send a more detailed response within 48 hours indicating the next steps in handling your report. After the initial reply to your report, the security team will endeavor to keep you informed of the progress towards a fix and full announcement, and may ask for additional information or guidance.
**Do not create a GitHub issue ticket to report a security vulnerability.**
The Hoppscotch team and community take all security vulnerability reports in Hoppscotch seriously. Thank you for improving the security of Hoppscotch. We appreciate your efforts and responsible disclosure and will make every effort to acknowledge your contributions.
Report security bugs in third-party modules to the person or team maintaining the module.
## Incident response process
In case an incident is discovered or reported, we will follow the following process to contain, respond, and remediate:
1. Confirm the problem and determine the affected versions.
2. Audit code to find any potential similar problems.
3. Prepare fixes for all releases still under maintenance. These fixes will be deployed as fast as possible to production.

View File

@@ -9,16 +9,19 @@ Before you start working on a new language, please look through the [open pull r
if there is no existing translation, you can create a new one by following these steps: if there is no existing translation, you can create a new one by following these steps:
1. **[Fork the repository](https://github.com/hoppscotch/hoppscotch/fork).** 1. **[Fork the repository](https://github.com/hoppscotch/hoppscotch/fork).**
2. **Create a new branch for your translation.** 2. **Checkout the `i18n` branch for latest translations.**
3. **Create target language file in the [`locales`](https://github.com/hoppscotch/hoppscotch/tree/main/packages/hoppscotch-app/locales) directory.** 3. **Create a new branch for your translation with base branch `i18n`.**
4. **Copy the contents of the source file [`locales/en.json`](https://github.com/hoppscotch/hoppscotch/blob/main/packages/hoppscotch-app/locales/en.json) to the target language file.** 4. **Create target language file in the [`locales`](https://github.com/hoppscotch/hoppscotch/tree/main/packages/hoppscotch-app/locales) directory.**
5. **Translate the strings in the target language file.** 5. **Copy the contents of the source file [`locales/en.json`](https://github.com/hoppscotch/hoppscotch/blob/main/packages/hoppscotch-app/locales/en.json) to the target language file.**
6. **Add your language entry to [`languages.json`](https://github.com/hoppscotch/hoppscotch/blob/main/packages/hoppscotch-app/languages.json).** 6. **Translate the strings in the target language file.**
7. **Save & commit changes.** 7. **Add your language entry to [`languages.json`](https://github.com/hoppscotch/hoppscotch/blob/main/packages/hoppscotch-app/languages.json).**
8. **Send a pull request.** 8. **Save & commit changes.**
9. **Send a pull request.**
_You may send a pull request before all steps above are complete: e.g., you may want to ask for help with translations, or getting tests to pass. However, your pull request will not be merged until all steps above are complete._ _You may send a pull request before all steps above are complete: e.g., you may want to ask for help with translations, or getting tests to pass. However, your pull request will not be merged until all steps above are complete._
`i18n` branch will be merged into `main` branch once every week.
Completing an initial translation of the whole site is a fairly large task. One way to break that task up is to work with other translators through pull requests on your fork. You can also [add collaborators to your fork](https://help.github.com/en/github/setting-up-and-managing-your-github-user-account/inviting-collaborators-to-a-personal-repository) if you'd like to invite other translators to commit directly to your fork and share responsibility for merging pull requests. Completing an initial translation of the whole site is a fairly large task. One way to break that task up is to work with other translators through pull requests on your fork. You can also [add collaborators to your fork](https://help.github.com/en/github/setting-up-and-managing-your-github-user-account/inviting-collaborators-to-a-personal-repository) if you'd like to invite other translators to commit directly to your fork and share responsibility for merging pull requests.
## Updating a translation ## Updating a translation

View File

@@ -4,6 +4,7 @@
"description": "Open source API development ecosystem", "description": "Open source API development ecosystem",
"author": "Hoppscotch (support@hoppscotch.io)", "author": "Hoppscotch (support@hoppscotch.io)",
"private": true, "private": true,
"license": "MIT",
"scripts": { "scripts": {
"preinstall": "npx only-allow pnpm", "preinstall": "npx only-allow pnpm",
"prepare": "husky install", "prepare": "husky install",
@@ -20,10 +21,10 @@
], ],
"dependencies": { "dependencies": {
"husky": "^7.0.4", "husky": "^7.0.4",
"lint-staged": "^12.0.2" "lint-staged": "^12.1.2"
}, },
"devDependencies": { "devDependencies": {
"@commitlint/cli": "^14.1.0", "@commitlint/cli": "^15.0.0",
"@commitlint/config-conventional": "^14.1.0" "@commitlint/config-conventional": "^15.0.0"
} }
} }

View File

@@ -2,6 +2,7 @@
"name": "@hoppscotch/codemirror-lang-graphql", "name": "@hoppscotch/codemirror-lang-graphql",
"version": "0.1.0", "version": "0.1.0",
"description": "GraphQL language support for CodeMirror", "description": "GraphQL language support for CodeMirror",
"author": "Hoppscotch (support@hoppscotch.io)",
"scripts": { "scripts": {
"prepare": "rollup -c" "prepare": "rollup -c"
}, },
@@ -15,17 +16,17 @@
"types": "dist/index.d.ts", "types": "dist/index.d.ts",
"sideEffects": false, "sideEffects": false,
"dependencies": { "dependencies": {
"@codemirror/highlight": "^0.19.0", "@codemirror/highlight": "^0.19.6",
"@codemirror/language": "^0.19.0", "@codemirror/language": "^0.19.6",
"@lezer/lr": "^0.15.0" "@lezer/lr": "^0.15.0"
}, },
"devDependencies": { "devDependencies": {
"@lezer/generator": "^0.15.0", "@lezer/generator": "^0.15.0",
"mocha": "^9.0.1", "mocha": "^9.0.1",
"rollup": "^2.35.1", "rollup": "^2.60.1",
"rollup-plugin-dts": "^3.0.2", "rollup-plugin-dts": "^4.0.1",
"rollup-plugin-ts": "^1.4.0", "rollup-plugin-ts": "^2.0.4",
"typescript": "^4.3.4" "typescript": "^4.5.2"
}, },
"license": "MIT" "license": "MIT"
} }

View File

@@ -1,10 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<line x1="12" y1="2" x2="12" y2="6"></line> <path d="M21 12a9 9 0 11-6.219-8.56"></path>
<line x1="12" y1="18" x2="12" y2="22"></line>
<line x1="4.93" y1="4.93" x2="7.76" y2="7.76"></line>
<line x1="16.24" y1="16.24" x2="19.07" y2="19.07"></line>
<line x1="2" y1="12" x2="6" y2="12"></line>
<line x1="18" y1="12" x2="22" y2="12"></line>
<line x1="4.93" y1="19.07" x2="7.76" y2="16.24"></line>
<line x1="16.24" y1="7.76" x2="19.07" y2="4.93"></line>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 608 B

After

Width:  |  Height:  |  Size: 235 B

View File

@@ -27,23 +27,24 @@
@apply h-4; @apply h-4;
} }
.hide-scrollbar {
-ms-overflow-style: none;
scrollbar-width: none;
}
.hide-scrollbar::-webkit-scrollbar { .hide-scrollbar::-webkit-scrollbar {
@apply hidden; @apply hidden;
} }
::selection { ::selection {
@apply bg-divider; @apply bg-accentDark;
} @apply text-accentContrast;
.cm-focused {
@apply !outline-none;
} }
input::placeholder, input::placeholder,
textarea::placeholder, textarea::placeholder {
.CodeMirror-empty {
@apply text-secondary; @apply text-secondary;
@apply opacity-25; @apply opacity-35;
} }
input, input,
@@ -66,7 +67,6 @@ body {
animation: fade 300ms forwards; animation: fade 300ms forwards;
font-size: var(--body-font-size); font-size: var(--body-font-size);
line-height: var(--body-line-height); line-height: var(--body-line-height);
overflow: overlay;
-webkit-tap-highlight-color: transparent; -webkit-tap-highlight-color: transparent;
-webkit-touch-callout: none; -webkit-touch-callout: none;
} }
@@ -318,7 +318,7 @@ pre.ace_editor {
&.toasted-primary { &.toasted-primary {
@apply bg-tooltip; @apply bg-tooltip;
@apply text-primary; @apply text-primary;
@apply justify-start; @apply justify-between;
@apply shadow; @apply shadow;
@apply font-medium; @apply font-medium;
@apply transition; @apply transition;
@@ -391,7 +391,7 @@ pre.ace_editor {
.smart-splitter .splitpanes__splitter::before { .smart-splitter .splitpanes__splitter::before {
@apply absolute; @apply absolute;
@apply inset-0; @apply inset-0;
@apply bg-dividerLight; @apply bg-accentLight;
@apply opacity-0; @apply opacity-0;
@apply z-20; @apply z-20;
@apply transition; @apply transition;
@@ -435,29 +435,16 @@ pre.ace_editor {
@apply w-full; @apply w-full;
} }
.CodeMirror { .cm-focused {
@apply !h-auto; @apply select-auto;
@apply !outline-none;
font-size: var(--body-font-size); .cm-activeLine {
&:not(.CodeMirror-focused) .CodeMirror-activeline-background {
background: transparent !important;
}
.CodeMirror-dialog-top {
@apply bg-primaryLight; @apply bg-primaryLight;
@apply border-dividerLight;
@apply px-4;
@apply py-2;
@apply z-5;
} }
.CodeMirror-scroll { .cm-activeLineGutter {
@apply min-h-64; @apply bg-primaryDark;
}
* {
font-family: "Roboto Mono", monospace;
} }
} }

View File

@@ -53,17 +53,17 @@
} }
@mixin dark-editor-theme { @mixin dark-editor-theme {
--editor-type-color: theme("colors.purple.500"); --editor-type-color: theme("colors.purple.400");
--editor-name-color: theme("colors.blue.500"); --editor-name-color: theme("colors.blue.400");
--editor-operator-color: theme("colors.indigo.500"); --editor-operator-color: theme("colors.indigo.400");
--editor-invalid-color: theme("colors.red.500"); --editor-invalid-color: theme("colors.red.400");
--editor-separator-color: theme("colors.gray.500"); --editor-separator-color: theme("colors.gray.400");
--editor-meta-color: theme("colors.gray.500"); --editor-meta-color: theme("colors.gray.400");
--editor-variable-color: theme("colors.green.500"); --editor-variable-color: theme("colors.green.400");
--editor-link-color: theme("colors.cyan.500"); --editor-link-color: theme("colors.cyan.400");
--editor-process-color: theme("colors.gray.400"); --editor-process-color: theme("colors.fuchsia.400");
--editor-constant-color: theme("colors.fuchsia.500"); --editor-constant-color: theme("colors.violet.400");
--editor-keyword-color: theme("colors.pink.500"); --editor-keyword-color: theme("colors.pink.400");
} }
@mixin light-editor-theme { @mixin light-editor-theme {
@@ -82,15 +82,15 @@
@mixin black-editor-theme { @mixin black-editor-theme {
--editor-type-color: theme("colors.purple.400"); --editor-type-color: theme("colors.purple.400");
--editor-name-color: theme("colors.gray.400"); --editor-name-color: theme("colors.fuchsia.400");
--editor-operator-color: theme("colors.indigo.400"); --editor-operator-color: theme("colors.indigo.400");
--editor-invalid-color: theme("colors.red.400"); --editor-invalid-color: theme("colors.red.400");
--editor-separator-color: theme("colors.gray.400"); --editor-separator-color: theme("colors.gray.400");
--editor-meta-color: theme("colors.gray.400"); --editor-meta-color: theme("colors.gray.400");
--editor-variable-color: theme("colors.green.400"); --editor-variable-color: theme("colors.green.400");
--editor-link-color: theme("colors.cyan.400"); --editor-link-color: theme("colors.cyan.400");
--editor-process-color: theme("colors.blue.400"); --editor-process-color: theme("colors.violet.400");
--editor-constant-color: theme("colors.fuchsia.400"); --editor-constant-color: theme("colors.blue.400");
--editor-keyword-color: theme("colors.pink.400"); --editor-keyword-color: theme("colors.pink.400");
} }

View File

@@ -1,26 +1,23 @@
<template> <template>
<div class="bg-error flex justify-between"> <div class="bg-error flex justify-between">
<span <span
class=" class="group relative flex items-center justify-center px-4 py-2 transition"
flex
py-2
px-4
transition
relative
items-center
justify-center
group
"
> >
<i class="mr-2 material-icons">info_outline</i> <i class="material-icons mr-2">info_outline</i>
<span class="text-secondaryDark"> <span class="text-secondaryDark">
<span class="md:hidden"> <span class="md:hidden">
{{ $t("helpers.offline_short") }} {{ t("helpers.offline_short") }}
</span> </span>
<span class="hidden md:inline"> <span class="md:inline hidden">
{{ $t("helpers.offline") }} {{ t("helpers.offline") }}
</span> </span>
</span> </span>
</span> </span>
</div> </div>
</template> </template>
<script setup lang="ts">
import { useI18n } from "~/helpers/utils/composables"
const t = useI18n()
</script>

View File

@@ -4,7 +4,7 @@
<div class="flex"> <div class="flex">
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="EXPAND_NAVIGATION ? $t('hide.sidebar') : $t('show.sidebar')" :title="EXPAND_NAVIGATION ? t('hide.sidebar') : t('show.sidebar')"
svg="sidebar" svg="sidebar"
class="transform" class="transform"
:class="{ '-rotate-180': !EXPAND_NAVIGATION }" :class="{ '-rotate-180': !EXPAND_NAVIGATION }"
@@ -12,9 +12,9 @@
/> />
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="`${ :title="`${ZEN_MODE ? t('action.turn_off') : t('action.turn_on')} ${t(
ZEN_MODE ? $t('action.turn_off') : $t('action.turn_on') 'layout.zen_mode'
} ${$t('layout.zen_mode')}`" )}`"
:svg="ZEN_MODE ? 'minimize' : 'maximize'" :svg="ZEN_MODE ? 'minimize' : 'maximize'"
:class="{ :class="{
'!text-accent !focus-visible:text-accentDark !hover:text-accentDark': '!text-accent !focus-visible:text-accentDark !hover:text-accentDark':
@@ -36,20 +36,20 @@
<ButtonSecondary <ButtonSecondary
svg="help-circle" svg="help-circle"
class="!rounded-none" class="!rounded-none"
:label="`${$t('app.help')}`" :label="`${t('app.help')}`"
/> />
</template> </template>
<div class="flex flex-col"> <div class="flex flex-col">
<SmartItem <SmartItem
svg="book" svg="book"
:label="`${$t('app.documentation')}`" :label="`${t('app.documentation')}`"
to="https://docs.hoppscotch.io" to="https://docs.hoppscotch.io"
blank blank
@click.native="$refs.options.tippy().hide()" @click.native="$refs.options.tippy().hide()"
/> />
<SmartItem <SmartItem
svg="zap" svg="zap"
:label="`${$t('app.keyboard_shortcuts')}`" :label="`${t('app.keyboard_shortcuts')}`"
@click.native=" @click.native="
() => { () => {
showShortcuts = true showShortcuts = true
@@ -59,14 +59,14 @@
/> />
<SmartItem <SmartItem
svg="gift" svg="gift"
:label="`${$t('app.whats_new')}`" :label="`${t('app.whats_new')}`"
to="https://docs.hoppscotch.io/changelog" to="https://docs.hoppscotch.io/changelog"
blank blank
@click.native="$refs.options.tippy().hide()" @click.native="$refs.options.tippy().hide()"
/> />
<SmartItem <SmartItem
svg="message-circle" svg="message-circle"
:label="`${$t('app.chat_with_us')}`" :label="`${t('app.chat_with_us')}`"
@click.native=" @click.native="
() => { () => {
chatWithUs() chatWithUs()
@@ -77,21 +77,21 @@
<hr /> <hr />
<SmartItem <SmartItem
svg="github" svg="github"
:label="`${$t('app.github')}`" :label="`${t('app.github')}`"
to="https://github.com/hoppscotch/hoppscotch" to="https://github.com/hoppscotch/hoppscotch"
blank blank
@click.native="$refs.options.tippy().hide()" @click.native="$refs.options.tippy().hide()"
/> />
<SmartItem <SmartItem
svg="twitter" svg="twitter"
:label="`${$t('app.twitter')}`" :label="`${t('app.twitter')}`"
to="https://hoppscotch.io/twitter" to="https://hoppscotch.io/twitter"
blank blank
@click.native="$refs.options.tippy().hide()" @click.native="$refs.options.tippy().hide()"
/> />
<SmartItem <SmartItem
svg="user-plus" svg="user-plus"
:label="`${$t('app.invite')}`" :label="`${t('app.invite')}`"
@click.native=" @click.native="
() => { () => {
showShare = true showShare = true
@@ -101,14 +101,14 @@
/> />
<SmartItem <SmartItem
svg="lock" svg="lock"
:label="`${$t('app.terms_and_privacy')}`" :label="`${t('app.terms_and_privacy')}`"
to="https://docs.hoppscotch.io/privacy" to="https://docs.hoppscotch.io/privacy"
blank blank
@click.native="$refs.options.tippy().hide()" @click.native="$refs.options.tippy().hide()"
/> />
<!-- <SmartItem :label="$t('app.status')" /> --> <!-- <SmartItem :label="t('app.status')" /> -->
<div class="flex opacity-50 py-2 px-4"> <div class="flex px-4 py-2 opacity-50">
{{ `${$t("app.name")} ${$t("app.version")}` }} {{ `${t("app.name")} ${t("app.version")}` }}
</div> </div>
</div> </div>
</tippy> </tippy>
@@ -116,33 +116,33 @@
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
svg="zap" svg="zap"
:title="$t('app.shortcuts')" :title="t('app.shortcuts')"
@click.native="showShortcuts = true" @click.native="showShortcuts = true"
/> />
<ButtonSecondary <ButtonSecondary
v-if="navigatorShare" v-if="navigatorShare"
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
svg="share-2" svg="share-2"
:title="$t('request.share')" :title="t('request.share')"
@click.native="nativeShare()" @click.native="nativeShare()"
/> />
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="COLUMN_LAYOUT ? $t('layout.row') : $t('layout.column')" :title="COLUMN_LAYOUT ? t('layout.row') : t('layout.column')"
svg="columns" svg="columns"
class="transform" class="transform"
:class="{ 'rotate-90': !COLUMN_LAYOUT }" :class="{ 'rotate-90': !COLUMN_LAYOUT }"
@click.native="COLUMN_LAYOUT = !COLUMN_LAYOUT" @click.native="COLUMN_LAYOUT = !COLUMN_LAYOUT"
/> />
<span <span
class="transform transition" class="transition transform"
:class="{ :class="{
'rotate-180': SIDEBAR_ON_LEFT, 'rotate-180': SIDEBAR_ON_LEFT,
}" }"
> >
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="SIDEBAR ? $t('hide.sidebar') : $t('show.sidebar')" :title="SIDEBAR ? t('hide.sidebar') : t('show.sidebar')"
svg="sidebar-open" svg="sidebar-open"
class="transform" class="transform"
:class="{ 'rotate-180': !SIDEBAR }" :class="{ 'rotate-180': !SIDEBAR }"
@@ -161,7 +161,9 @@ import { ref, watch } from "@nuxtjs/composition-api"
import { defineActionHandler } from "~/helpers/actions" import { defineActionHandler } from "~/helpers/actions"
import { showChat } from "~/helpers/support" import { showChat } from "~/helpers/support"
import { useSetting } from "~/newstore/settings" import { useSetting } from "~/newstore/settings"
import { useI18n } from "~/helpers/utils/composables"
const t = useI18n()
const showShortcuts = ref(false) const showShortcuts = ref(false)
const showShare = ref(false) const showShare = ref(false)

View File

@@ -11,11 +11,11 @@
/> />
<div <div
v-if="searchResults.length === 0" v-if="searchResults.length === 0"
class="flex flex-col text-secondaryLight p-4 items-center justify-center" class="text-secondaryLight flex flex-col items-center justify-center p-4"
> >
<i class="opacity-75 pb-2 material-icons">manage_search</i> <i class="material-icons pb-2 opacity-75">manage_search</i>
<span class="text-center"> <span class="text-center">
{{ $t("state.nothing_found") }} "{{ search }}" {{ t("state.nothing_found") }} "{{ search }}"
</span> </span>
</div> </div>
</div> </div>
@@ -26,6 +26,9 @@ import { computed, onUnmounted, onMounted } from "@nuxtjs/composition-api"
import Fuse from "fuse.js" import Fuse from "fuse.js"
import { useArrowKeysNavigation } from "~/helpers/powerSearchNavigation" import { useArrowKeysNavigation } from "~/helpers/powerSearchNavigation"
import { HoppAction } from "~/helpers/actions" import { HoppAction } from "~/helpers/actions"
import { useI18n } from "~/helpers/utils/composables"
const t = useI18n()
const props = defineProps<{ const props = defineProps<{
input: Record<string, any>[] input: Record<string, any>[]

View File

@@ -1,9 +1,9 @@
<template> <template>
<div> <div>
<header <header
class="flex space-x-2 flex-1 py-2 px-2 items-center justify-between" class="flex items-center justify-between flex-1 px-2 py-2 space-x-2"
> >
<div class="space-x-2 inline-flex items-center"> <div class="inline-flex items-center space-x-2">
<ButtonSecondary <ButtonSecondary
class="tracking-wide !font-bold !text-secondaryDark" class="tracking-wide !font-bold !text-secondaryDark"
label="HOPPSCOTCH" label="HOPPSCOTCH"
@@ -11,25 +11,25 @@
/> />
<AppGitHubStarButton class="mt-1.5 transition hidden sm:flex" /> <AppGitHubStarButton class="mt-1.5 transition hidden sm:flex" />
</div> </div>
<div class="space-x-2 inline-flex items-center"> <div class="inline-flex items-center space-x-2">
<ButtonSecondary <ButtonSecondary
id="installPWA" id="installPWA"
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('header.install_pwa')" :title="t('header.install_pwa')"
svg="download" svg="download"
class="rounded" class="rounded"
@click.native="showInstallPrompt()" @click.native="showInstallPrompt()"
/> />
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="`${$t('app.search')} <kbd>/</kbd>`" :title="`${t('app.search')} <kbd>/</kbd>`"
svg="search" svg="search"
class="rounded" class="rounded"
@click.native="showSearch = true" @click.native="showSearch = true"
/> />
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="`${$t('support.title')} <kbd>?</kbd>`" :title="`${t('support.title')} <kbd>?</kbd>`"
svg="life-buoy" svg="life-buoy"
class="rounded" class="rounded"
@click.native="showSupport = true" @click.native="showSupport = true"
@@ -37,28 +37,23 @@
<ButtonSecondary <ButtonSecondary
v-if="currentUser === null" v-if="currentUser === null"
svg="upload-cloud" svg="upload-cloud"
:label="$t('header.save_workspace')" :label="t('header.save_workspace')"
filled filled
class="hidden md:flex" class="md:flex hidden"
@click.native="showLogin = true" @click.native="showLogin = true"
/> />
<ButtonPrimary <ButtonPrimary
v-if="currentUser === null" v-if="currentUser === null"
:label="$t('header.login')" :label="t('header.login')"
@click.native="showLogin = true" @click.native="showLogin = true"
/> />
<div v-else class="space-x-2 inline-flex items-center"> <div v-else class="inline-flex items-center space-x-2">
<ButtonPrimary <ButtonPrimary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('team.invite_tooltip')" :title="t('team.invite_tooltip')"
:label="$t('team.invite')" :label="t('team.invite')"
svg="user-plus" svg="user-plus"
class=" class="!bg-green-500 !text-green-500 !bg-opacity-15 !hover:bg-opacity-10 !hover:text-green-600 !hover:bg-green-400"
!bg-green-500
!text-green-500
!bg-opacity-15
!hover:bg-opacity-10 !hover:text-green-600 !hover:bg-green-400
"
@click.native="showTeamsModal = true" @click.native="showTeamsModal = true"
/> />
<span class="px-2"> <span class="px-2">
@@ -78,7 +73,7 @@
<ButtonSecondary <ButtonSecondary
v-else v-else
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('header.account')" :title="t('header.account')"
class="rounded" class="rounded"
svg="user" svg="user"
/> />
@@ -86,13 +81,13 @@
<SmartItem <SmartItem
to="/profile" to="/profile"
svg="user" svg="user"
:label="$t('navigation.profile')" :label="t('navigation.profile')"
@click.native="$refs.user.tippy().hide()" @click.native="$refs.user.tippy().hide()"
/> />
<SmartItem <SmartItem
to="/settings" to="/settings"
svg="settings" svg="settings"
:label="$t('navigation.settings')" :label="t('navigation.settings')"
@click.native="$refs.user.tippy().hide()" @click.native="$refs.user.tippy().hide()"
/> />
<FirebaseLogout @confirm-logout="$refs.user.tippy().hide()" /> <FirebaseLogout @confirm-logout="$refs.user.tippy().hide()" />
@@ -110,18 +105,20 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, ref, useContext } from "@nuxtjs/composition-api" import { onMounted, ref } from "@nuxtjs/composition-api"
import intializePwa from "~/helpers/pwa" import intializePwa from "~/helpers/pwa"
import { probableUser$ } from "~/helpers/fb/auth" import { probableUser$ } from "~/helpers/fb/auth"
import { getLocalConfig, setLocalConfig } from "~/newstore/localpersistence" import { getLocalConfig, setLocalConfig } from "~/newstore/localpersistence"
import { useReadonlyStream } from "~/helpers/utils/composables" import {
useReadonlyStream,
useI18n,
useToast,
} from "~/helpers/utils/composables"
import { defineActionHandler } from "~/helpers/actions" import { defineActionHandler } from "~/helpers/actions"
const { const t = useI18n()
$toast,
app: { i18n }, const toast = useToast()
} = useContext()
const t = i18n.t.bind(i18n)
/** /**
* Once the PWA code is initialized, this holds a method * Once the PWA code is initialized, this holds a method
@@ -160,12 +157,11 @@ onMounted(() => {
const cookiesAllowed = getLocalConfig("cookiesAllowed") === "yes" const cookiesAllowed = getLocalConfig("cookiesAllowed") === "yes"
if (!cookiesAllowed) { if (!cookiesAllowed) {
$toast.show(t("app.we_use_cookies").toString(), { toast.show(`${t("app.we_use_cookies")}`, {
icon: "cookie",
duration: 0, duration: 0,
action: [ action: [
{ {
text: t("action.learn_more").toString(), text: `${t("action.learn_more")}`,
onClick: (_, toastObject) => { onClick: (_, toastObject) => {
setLocalConfig("cookiesAllowed", "yes") setLocalConfig("cookiesAllowed", "yes")
toastObject.goAway(0) toastObject.goAway(0)
@@ -173,7 +169,7 @@ onMounted(() => {
}, },
}, },
{ {
text: t("action.dismiss").toString(), text: `${t("action.dismiss")}`,
onClick: (_, toastObject) => { onClick: (_, toastObject) => {
setLocalConfig("cookiesAllowed", "yes") setLocalConfig("cookiesAllowed", "yes")
toastObject.goAway(0) toastObject.goAway(0)

View File

@@ -1,20 +1,20 @@
<template> <template>
<div class="flex p-4 space-y-4 items-start flex-col"> <div class="flex flex-col items-start p-4 space-y-4">
<SmartToggle <SmartToggle
:on="PROXY_ENABLED" :on="PROXY_ENABLED"
@change="toggleSettingKey('PROXY_ENABLED')" @change="toggleSettingKey('PROXY_ENABLED')"
> >
{{ $t("settings.proxy") }} {{ t("settings.proxy") }}
</SmartToggle> </SmartToggle>
<SmartToggle <SmartToggle
:on="EXTENSIONS_ENABLED" :on="EXTENSIONS_ENABLED"
@change="toggleSettingKey('EXTENSIONS_ENABLED')" @change="toggleSettingKey('EXTENSIONS_ENABLED')"
> >
{{ $t("settings.extensions") }}: {{ t("settings.extensions") }}:
{{ {{
extensionVersion != null extensionVersion != null
? `v${extensionVersion.major}.${extensionVersion.minor}` ? `v${extensionVersion.major}.${extensionVersion.minor}`
: $t("settings.extension_ver_not_reported") : t("settings.extension_ver_not_reported")
}} }}
</SmartToggle> </SmartToggle>
</div> </div>
@@ -25,6 +25,9 @@ import { defineComponent } from "@nuxtjs/composition-api"
import { KeysMatching } from "~/types/ts-utils" import { KeysMatching } from "~/types/ts-utils"
import { SettingsType, toggleSetting, useSetting } from "~/newstore/settings" import { SettingsType, toggleSetting, useSetting } from "~/newstore/settings"
import { hasExtensionInstalled } from "~/helpers/strategies/ExtensionStrategy" import { hasExtensionInstalled } from "~/helpers/strategies/ExtensionStrategy"
import { useI18n } from "~/helpers/utils/composables"
const t = useI18n()
const PROXY_ENABLED = useSetting("PROXY_ENABLED") const PROXY_ENABLED = useSetting("PROXY_ENABLED")
const EXTENSIONS_ENABLED = useSetting("EXTENSIONS_ENABLED") const EXTENSIONS_ENABLED = useSetting("EXTENSIONS_ENABLED")

View File

@@ -13,14 +13,8 @@
type="text" type="text"
autocomplete="off" autocomplete="off"
name="command" name="command"
:placeholder="`${$t('app.type_a_command_search')}`" :placeholder="`${t('app.type_a_command_search')}`"
class=" class="border-dividerLight text-secondaryDark flex flex-shrink-0 p-6 text-base bg-transparent border-b"
bg-transparent
border-b border-dividerLight
flex flex-shrink-0
text-secondaryDark text-base
p-6
"
/> />
<AppFuse <AppFuse
v-if="search && show" v-if="search && show"
@@ -30,22 +24,15 @@
/> />
<div <div
v-else v-else
class=" class="divide-dividerLight hide-scrollbar flex flex-col flex-1 space-y-4 overflow-auto divide-y"
divide-y divide-dividerLight
flex flex-col
space-y-4
flex-1
overflow-auto
hide-scrollbar
"
> >
<div <div
v-for="(map, mapIndex) in mappings" v-for="(map, mapIndex) in mappings"
:key="`map-${mapIndex}`" :key="`map-${mapIndex}`"
class="flex flex-col" class="flex flex-col"
> >
<h5 class="my-2 text-secondaryLight py-2 px-6"> <h5 class="text-secondaryLight px-6 py-2 my-2">
{{ $t(map.section) }} {{ t(map.section) }}
</h5> </h5>
<AppPowerSearchEntry <AppPowerSearchEntry
v-for="(shortcut, shortcutIndex) in map.shortcuts" v-for="(shortcut, shortcutIndex) in map.shortcuts"
@@ -66,6 +53,9 @@ import { ref, computed, watch } from "@nuxtjs/composition-api"
import { HoppAction, invokeAction } from "~/helpers/actions" import { HoppAction, invokeAction } from "~/helpers/actions"
import { spotlight as mappings, fuse } from "~/helpers/shortcuts" import { spotlight as mappings, fuse } from "~/helpers/shortcuts"
import { useArrowKeysNavigation } from "~/helpers/powerSearchNavigation" import { useArrowKeysNavigation } from "~/helpers/powerSearchNavigation"
import { useI18n } from "~/helpers/utils/composables"
const t = useI18n()
const props = defineProps<{ const props = defineProps<{
show: boolean show: boolean

View File

@@ -1,22 +1,13 @@
<template> <template>
<button <button
class=" class="search-entry focus:outline-none flex items-center flex-1 px-6 py-2 transition cursor-pointer"
cursor-pointer
flex flex-1
py-2
px-6
transition
items-center
search-entry
focus:outline-none
"
:class="{ active: active }" :class="{ active: active }"
tabindex="-1" tabindex="-1"
@click="$emit('action', shortcut.action)" @click="$emit('action', shortcut.action)"
@keydown.enter="$emit('action', shortcut.action)" @keydown.enter="$emit('action', shortcut.action)"
> >
<SmartIcon <SmartIcon
class="mr-4 opacity-50 transition svg-icons" class="svg-icons mr-4 transition opacity-50"
:class="{ 'opacity-100 text-secondaryDark': active }" :class="{ 'opacity-100 text-secondaryDark': active }"
:name="shortcut.icon" :name="shortcut.icon"
/> />
@@ -24,7 +15,7 @@
class="flex flex-1 mr-4 font-medium transition" class="flex flex-1 mr-4 font-medium transition"
:class="{ 'text-secondaryDark': active }" :class="{ 'text-secondaryDark': active }"
> >
{{ $t(shortcut.label) }} {{ t(shortcut.label) }}
</span> </span>
<span <span
v-for="(key, keyIndex) in shortcut.keys" v-for="(key, keyIndex) in shortcut.keys"
@@ -37,6 +28,10 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { useI18n } from "~/helpers/utils/composables"
const t = useI18n()
defineProps<{ defineProps<{
shortcut: Object shortcut: Object
active: Boolean active: Boolean

View File

@@ -1,5 +1,5 @@
<template> <template>
<section :id="label.toLowerCase()" class="flex flex-col flex-1 relative"> <section :id="label.toLowerCase()" class="relative flex flex-col flex-1">
<slot></slot> <slot></slot>
</section> </section>
</template> </template>

View File

@@ -1,15 +1,15 @@
<template> <template>
<SmartModal <SmartModal
v-if="show" v-if="show"
:title="$t('app.invite_your_friends')" :title="t('app.invite_your_friends')"
@close="hideModal" @close="hideModal"
> >
<template #body> <template #body>
<p class="text-secondaryLight mb-8 px-2"> <p class="text-secondaryLight px-2 mb-8">
{{ $t("app.invite_description") }} {{ t("app.invite_description") }}
</p> </p>
<div class="flex flex-col space-y-2 px-2"> <div class="flex flex-col px-2 space-y-2">
<div class="grid gap-4 grid-cols-3"> <div class="grid grid-cols-3 gap-4">
<a <a
v-for="(platform, index) in platforms" v-for="(platform, index) in platforms"
:key="`platform-${index}`" :key="`platform-${index}`"
@@ -17,15 +17,15 @@
target="_blank" target="_blank"
class="share-link" class="share-link"
> >
<SmartIcon :name="platform.icon" class="h-6 w-6" /> <SmartIcon :name="platform.icon" class="w-6 h-6" />
<span class="mt-3"> <span class="mt-3">
{{ platform.name }} {{ platform.name }}
</span> </span>
</a> </a>
<button class="share-link" @click="copyAppLink"> <button class="share-link" @click="copyAppLink">
<SmartIcon class="h-6 text-xl w-6" :name="copyIcon" /> <SmartIcon class="w-6 h-6 text-xl" :name="copyIcon" />
<span class="mt-3"> <span class="mt-3">
{{ $t("app.copy") }} {{ t("app.copy") }}
</span> </span>
</button> </button>
</div> </div>
@@ -35,14 +35,13 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, useContext } from "@nuxtjs/composition-api" import { ref } from "@nuxtjs/composition-api"
import { copyToClipboard } from "~/helpers/utils/clipboard" import { copyToClipboard } from "~/helpers/utils/clipboard"
import { useI18n, useToast } from "~/helpers/utils/composables"
const { const t = useI18n()
$toast,
app: { i18n }, const toast = useToast()
} = useContext()
const t = i18n.t.bind(i18n)
defineProps<{ defineProps<{
show: Boolean show: Boolean
@@ -92,9 +91,7 @@ const platforms = [
const copyAppLink = () => { const copyAppLink = () => {
copyToClipboard(url) copyToClipboard(url)
copyIcon.value = "check" copyIcon.value = "check"
$toast.success(t("state.copied_to_clipboard").toString(), { toast.success(`${t("state.copied_to_clipboard")}`)
icon: "content_paste",
})
setTimeout(() => (copyIcon.value = "copy"), 1000) setTimeout(() => (copyIcon.value = "copy"), 1000)
} }

View File

@@ -2,51 +2,35 @@
<AppSlideOver :show="show" @close="close()"> <AppSlideOver :show="show" @close="close()">
<template #content> <template #content>
<div <div
class=" class="bg-primary border-dividerLight sticky top-0 z-10 flex items-center justify-between p-2 border-b"
bg-primary
border-b border-dividerLight
flex
p-2
top-0
z-10
items-center
sticky
justify-between
"
> >
<h3 class="ml-4 heading">{{ $t("app.shortcuts") }}</h3> <h3 class="heading ml-4">{{ t("app.shortcuts") }}</h3>
<div class="flex"> <div class="flex">
<ButtonSecondary svg="x" class="rounded" @click.native="close()" /> <ButtonSecondary svg="x" class="rounded" @click.native="close()" />
</div> </div>
</div> </div>
<div class="bg-primary border-b border-dividerLight"> <div class="bg-primary border-dividerLight border-b">
<div class="flex flex-col my-4 mx-6"> <div class="flex flex-col mx-6 my-4">
<input <input
v-model="filterText" v-model="filterText"
type="search" type="search"
autocomplete="off" autocomplete="off"
class=" class="bg-primaryLight border-dividerLight focus-visible:border-divider flex w-full px-4 py-2 border rounded"
bg-primaryLight :placeholder="`${t('action.search')}`"
border border-dividerLight
rounded
flex
w-full
py-2
px-4
focus-visible:border-divider
"
:placeholder="`${$t('action.search')}`"
/> />
</div> </div>
</div> </div>
<div v-if="filterText"> <div
v-if="filterText"
class="divide-dividerLight hide-scrollbar flex flex-col flex-1 overflow-auto divide-y"
>
<div <div
v-for="(map, mapIndex) in searchResults" v-for="(map, mapIndex) in searchResults"
:key="`map-${mapIndex}`" :key="`map-${mapIndex}`"
class="space-y-4 py-4 px-6" class="px-6 py-4 space-y-4"
> >
<h1 class="font-semibold text-secondaryDark"> <h1 class="text-secondaryDark font-semibold">
{{ $t(map.item.section) }} {{ t(map.item.section) }}
</h1> </h1>
<AppShortcutsEntry <AppShortcutsEntry
v-for="(shortcut, index) in map.item.shortcuts" v-for="(shortcut, index) in map.item.shortcuts"
@@ -56,36 +40,25 @@
</div> </div>
<div <div
v-if="searchResults.length === 0" v-if="searchResults.length === 0"
class=" class="text-secondaryLight flex flex-col items-center justify-center p-4"
flex flex-col
text-secondaryLight
p-4
items-center
justify-center
"
> >
<i class="opacity-75 pb-2 material-icons">manage_search</i> <i class="material-icons pb-2 opacity-75">manage_search</i>
<span class="text-center"> <span class="text-center">
{{ $t("state.nothing_found") }} "{{ filterText }}" {{ t("state.nothing_found") }} "{{ filterText }}"
</span> </span>
</div> </div>
</div> </div>
<div <div
v-else v-else
class=" class="divide-dividerLight hide-scrollbar flex flex-col flex-1 overflow-auto divide-y"
divide-y divide-dividerLight
flex flex-col flex-1
overflow-auto
hide-scrollbar
"
> >
<div <div
v-for="(map, mapIndex) in mappings" v-for="(map, mapIndex) in mappings"
:key="`map-${mapIndex}`" :key="`map-${mapIndex}`"
class="space-y-4 py-4 px-6" class="px-6 py-4 space-y-4"
> >
<h1 class="font-semibold text-secondaryDark"> <h1 class="text-secondaryDark font-semibold">
{{ $t(map.section) }} {{ t(map.section) }}
</h1> </h1>
<AppShortcutsEntry <AppShortcutsEntry
v-for="(shortcut, shortcutIndex) in map.shortcuts" v-for="(shortcut, shortcutIndex) in map.shortcuts"
@@ -102,6 +75,9 @@
import { computed, ref } from "@nuxtjs/composition-api" import { computed, ref } from "@nuxtjs/composition-api"
import Fuse from "fuse.js" import Fuse from "fuse.js"
import mappings from "~/helpers/shortcuts" import mappings from "~/helpers/shortcuts"
import { useI18n } from "~/helpers/utils/composables"
const t = useI18n()
defineProps<{ defineProps<{
show: boolean show: boolean

View File

@@ -1,7 +1,7 @@
<template> <template>
<div class="flex items-center"> <div class="flex items-center">
<span class="flex flex-1 mr-4"> <span class="flex flex-1 mr-4">
{{ $t(shortcut.label) }} {{ t(shortcut.label) }}
</span> </span>
<span <span
v-for="(key, index) in shortcut.keys" v-for="(key, index) in shortcut.keys"
@@ -14,6 +14,10 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { useI18n } from "~/helpers/utils/composables"
const t = useI18n()
defineProps<{ defineProps<{
shortcut: Object shortcut: Object
}>() }>()

View File

@@ -1,6 +1,6 @@
<template> <template>
<aside class="flex h-full justify-between md:flex-col"> <aside class="md:flex-col flex justify-between h-full">
<nav class="flex flex-nowrap md:flex-col flex-1 md:flex-none"> <nav class="flex-nowrap md:flex-col md:flex-none flex flex-1">
<NuxtLink <NuxtLink
v-for="(navigation, index) in primaryNavigation" v-for="(navigation, index) in primaryNavigation"
:key="`navigation-${index}`" :key="`navigation-${index}`"
@@ -27,14 +27,11 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { useContext } from "@nuxtjs/composition-api"
import useWindowSize from "~/helpers/utils/useWindowSize" import useWindowSize from "~/helpers/utils/useWindowSize"
import { useSetting } from "~/newstore/settings" import { useSetting } from "~/newstore/settings"
import { useI18n } from "~/helpers/utils/composables"
const { const t = useI18n()
app: { i18n },
} = useContext()
const t = i18n.t.bind(i18n)
const windowInnerWidth = useWindowSize() const windowInnerWidth = useWindowSize()
const EXPAND_NAVIGATION = useSetting("EXPAND_NAVIGATION") const EXPAND_NAVIGATION = useSetting("EXPAND_NAVIGATION")

View File

@@ -1,31 +1,16 @@
<template> <template>
<div> <div>
<transition v-if="show" name="fade" appear> <transition v-if="show" name="fade" appear>
<div class="inset-0 transition-opacity z-20 fixed" @keydown.esc="close()"> <div class="fixed inset-0 z-20 transition-opacity" @keydown.esc="close()">
<div <div
class="bg-primaryLight opacity-90 inset-0 absolute" class="bg-primaryLight opacity-90 absolute inset-0"
tabindex="0" tabindex="0"
@click="close()" @click="close()"
></div> ></div>
</div> </div>
</transition> </transition>
<aside <aside
class=" class="bg-primary w-96 fixed top-0 right-0 z-30 flex flex-col h-full max-w-full overflow-auto transition duration-300 ease-in-out transform"
bg-primary
flex flex-col
h-full
max-w-full
transform
transition
top-0
ease-in-out
right-0
w-96
z-30
duration-300
fixed
overflow-auto
"
:class="show ? 'shadow-xl translate-x-0' : 'translate-x-full'" :class="show ? 'shadow-xl translate-x-0' : 'translate-x-full'"
> >
<slot name="content"></slot> <slot name="content"></slot>

View File

@@ -1,7 +1,7 @@
<template> <template>
<SmartModal <SmartModal
v-if="show" v-if="show"
:title="$t('support.title')" :title="t('support.title')"
max-width="sm:max-w-md" max-width="sm:max-w-md"
@close="$emit('hide-modal')" @close="$emit('hide-modal')"
> >
@@ -9,9 +9,9 @@
<div class="flex flex-col space-y-2"> <div class="flex flex-col space-y-2">
<SmartItem <SmartItem
svg="book" svg="book"
:label="$t('app.documentation')" :label="t('app.documentation')"
to="https://docs.hoppscotch.io" to="https://docs.hoppscotch.io"
:description="$t('support.documentation')" :description="t('support.documentation')"
info-icon="chevron_right" info-icon="chevron_right"
active active
blank blank
@@ -19,17 +19,17 @@
/> />
<SmartItem <SmartItem
svg="zap" svg="zap"
:label="$t('app.keyboard_shortcuts')" :label="t('app.keyboard_shortcuts')"
:description="$t('support.shortcuts')" :description="t('support.shortcuts')"
info-icon="chevron_right" info-icon="chevron_right"
active active
@click.native="showShortcuts()" @click.native="showShortcuts()"
/> />
<SmartItem <SmartItem
svg="gift" svg="gift"
:label="$t('app.whats_new')" :label="t('app.whats_new')"
to="https://docs.hoppscotch.io/changelog" to="https://docs.hoppscotch.io/changelog"
:description="$t('support.changelog')" :description="t('support.changelog')"
info-icon="chevron_right" info-icon="chevron_right"
active active
blank blank
@@ -37,28 +37,28 @@
/> />
<SmartItem <SmartItem
svg="message-circle" svg="message-circle"
:label="$t('app.chat_with_us')" :label="t('app.chat_with_us')"
:description="$t('support.chat')" :description="t('support.chat')"
info-icon="chevron_right" info-icon="chevron_right"
active active
@click.native="chatWithUs()" @click.native="chatWithUs()"
/> />
<SmartItem <SmartItem
svg="brands/discord" svg="brands/discord"
:label="$t('app.join_discord_community')" :label="t('app.join_discord_community')"
to="https://hoppscotch.io/discord" to="https://hoppscotch.io/discord"
blank blank
:description="$t('support.community')" :description="t('support.community')"
info-icon="chevron_right" info-icon="chevron_right"
active active
@click.native="hideModal()" @click.native="hideModal()"
/> />
<SmartItem <SmartItem
svg="brands/twitter" svg="brands/twitter"
:label="$t('app.twitter')" :label="t('app.twitter')"
to="https://hoppscotch.io/twitter" to="https://hoppscotch.io/twitter"
blank blank
:description="$t('support.twitter')" :description="t('support.twitter')"
info-icon="chevron_right" info-icon="chevron_right"
active active
@click.native="hideModal()" @click.native="hideModal()"
@@ -71,6 +71,9 @@
<script setup lang="ts"> <script setup lang="ts">
import { invokeAction } from "~/helpers/actions" import { invokeAction } from "~/helpers/actions"
import { showChat } from "~/helpers/support" import { showChat } from "~/helpers/support"
import { useI18n } from "~/helpers/utils/composables"
const t = useI18n()
defineProps<{ defineProps<{
show: Boolean show: Boolean
@@ -87,6 +90,7 @@ const chatWithUs = () => {
const showShortcuts = () => { const showShortcuts = () => {
invokeAction("flyouts.keybinds.toggle") invokeAction("flyouts.keybinds.toggle")
hideModal()
} }
const hideModal = () => { const hideModal = () => {

View File

@@ -3,16 +3,7 @@
:to="`${/^\/(?!\/).*$/.test(to) ? localePath(to) : to}`" :to="`${/^\/(?!\/).*$/.test(to) ? localePath(to) : to}`"
:exact="exact" :exact="exact"
:blank="blank" :blank="blank"
class=" class="focus:outline-none focus-visible:bg-accentDark inline-flex items-center justify-center py-2 font-bold transition"
font-bold
py-2
transition
inline-flex
items-center
justify-center
focus:outline-none
focus-visible:bg-accentDark
"
:class="[ :class="[
color color
? `text-${color}-800 bg-${color}-200 hover:(text-${color}-900 bg-${color}-300) focus-visible:(text-${color}-900 bg-${color}-300)` ? `text-${color}-800 bg-${color}-200 hover:(text-${color}-900 bg-${color}-300) focus-visible:(text-${color}-900 bg-${color}-300)`
@@ -38,7 +29,7 @@
> >
<span <span
v-if="!loading" v-if="!loading"
class="inline-flex items-center justify-center whitespace-nowrap" class="whitespace-nowrap inline-flex items-center justify-center"
:class="{ 'flex-row-reverse': reverse }" :class="{ 'flex-row-reverse': reverse }"
> >
<i <i
@@ -65,7 +56,7 @@
<kbd <kbd
v-for="(key, index) in shortcut" v-for="(key, index) in shortcut"
:key="`key-${index}`" :key="`key-${index}`"
class="bg-accentLight rounded ml-1 px-1 inline-flex" class="bg-accentLight inline-flex px-1 ml-1 rounded"
> >
{{ key }} {{ key }}
</kbd> </kbd>

View File

@@ -3,18 +3,7 @@
:to="`${/^\/(?!\/).*$/.test(to) ? localePath(to) : to}`" :to="`${/^\/(?!\/).*$/.test(to) ? localePath(to) : to}`"
:exact="exact" :exact="exact"
:blank="blank" :blank="blank"
class=" class="whitespace-nowrap hover:bg-primaryDark focus:outline-none focus-visible:bg-primaryDark inline-flex items-center justify-center py-2 font-semibold transition"
font-semibold
py-2
transition
inline-flex
items-center
justify-center
whitespace-nowrap
hover:bg-primaryDark
focus:outline-none
focus-visible:bg-primaryDark
"
:class="[ :class="[
color color
? `text-${color}-500 hover:(text-${color}-600 text-${color}-600)` ? `text-${color}-500 hover:(text-${color}-600 text-${color}-600)`
@@ -28,7 +17,7 @@
'border border-divider hover:border-dividerDark focus-visible:border-dividerDark': 'border border-divider hover:border-dividerDark focus-visible:border-dividerDark':
outline, outline,
}, },
{ '!bg-primaryDark': filled }, { '!bg-primaryLight !hover:bg-primaryDark': filled },
]" ]"
:disabled="disabled" :disabled="disabled"
> >
@@ -56,14 +45,7 @@
<kbd <kbd
v-for="(key, index) in shortcut" v-for="(key, index) in shortcut"
:key="`key-${index}`" :key="`key-${index}`"
class=" class="bg-dividerLight text-secondaryLight inline-flex px-1 ml-1 rounded"
bg-dividerLight
rounded
text-secondaryLight
ml-1
px-1
inline-flex
"
> >
{{ key }} {{ key }}
</kbd> </kbd>

View File

@@ -47,9 +47,7 @@ export default defineComponent({
methods: { methods: {
addNewCollection() { addNewCollection() {
if (!this.name) { if (!this.name) {
this.$toast.error(this.$t("collection.invalid_name"), { this.$toast.error(this.$t("collection.invalid_name"))
icon: "error_outline",
})
return return
} }
this.$emit("submit", this.name) this.$emit("submit", this.name)

View File

@@ -51,9 +51,7 @@ export default defineComponent({
methods: { methods: {
addFolder() { addFolder() {
if (!this.name) { if (!this.name) {
this.$toast.error(this.$t("folder.invalid_name"), { this.$toast.error(this.$t("folder.invalid_name"))
icon: "error_outline",
})
return return
} }
this.$emit("add-folder", { this.$emit("add-folder", {

View File

@@ -18,18 +18,7 @@
type="text" type="text"
autocomplete="off" autocomplete="off"
autofocus autofocus
class=" class="border-dividerLight hover:bg-primaryDark flex w-full px-4 py-2 font-semibold bg-transparent border-t appearance-none cursor-pointer"
bg-transparent
border-t border-dividerLight
cursor-pointer
flex
font-semibold
w-full
py-2
px-4
appearance-none
hover:bg-primaryDark
"
@change="updateSelectedTeam(myTeams[$event.target.value])" @change="updateSelectedTeam(myTeams[$event.target.value])"
> >
<option <option

View File

@@ -48,9 +48,7 @@ export default defineComponent({
methods: { methods: {
saveCollection() { saveCollection() {
if (!this.name) { if (!this.name) {
this.$toast.error(this.$t("collection.invalid_name"), { this.$toast.error(this.$t("collection.invalid_name"))
icon: "error_outline",
})
return return
} }
this.$emit("submit", this.name) this.$emit("submit", this.name)

View File

@@ -48,9 +48,7 @@ export default defineComponent({
methods: { methods: {
editFolder() { editFolder() {
if (!this.name) { if (!this.name) {
this.$toast.error(this.$t("folder.invalid_name"), { this.$toast.error(this.$t("folder.invalid_name"))
icon: "error_outline",
})
return return
} }
this.$emit("submit", this.name) this.$emit("submit", this.name)

View File

@@ -47,9 +47,7 @@ export default defineComponent({
methods: { methods: {
saveRequest() { saveRequest() {
if (!this.requestUpdateData.name) { if (!this.requestUpdateData.name) {
this.$toast.error(this.$t("request.invalid_name"), { this.$toast.error(this.$t("request.invalid_name"))
icon: "error_outline",
})
return return
} }
this.$emit("submit", this.requestUpdateData) this.$emit("submit", this.requestUpdateData)

View File

@@ -229,15 +229,11 @@ export default defineComponent({
} }
) )
.then((res) => { .then((res) => {
this.$toast.success(this.$t("export.gist_created"), { this.$toast.success(this.$t("export.gist_created"))
icon: "done",
})
window.open(res.html_url) window.open(res.html_url)
}) })
.catch((e) => { .catch((e) => {
this.$toast.error(this.$t("error.something_went_wrong"), { this.$toast.error(this.$t("error.something_went_wrong"))
icon: "error_outline",
})
console.error(e) console.error(e)
}) })
}, },
@@ -415,23 +411,17 @@ export default defineComponent({
a.download = `${url.split("/").pop().split("#")[0].split("?")[0]}.json` a.download = `${url.split("/").pop().split("#")[0].split("?")[0]}.json`
document.body.appendChild(a) document.body.appendChild(a)
a.click() a.click()
this.$toast.success(this.$t("state.download_started"), { this.$toast.success(this.$t("state.download_started"))
icon: "downloading",
})
setTimeout(() => { setTimeout(() => {
document.body.removeChild(a) document.body.removeChild(a)
URL.revokeObjectURL(url) URL.revokeObjectURL(url)
}, 1000) }, 1000)
}, },
fileImported() { fileImported() {
this.$toast.success(this.$t("state.file_imported"), { this.$toast.success(this.$t("state.file_imported"))
icon: "folder_shared",
})
}, },
failedImport() { failedImport() {
this.$toast.error(this.$t("import.failed"), { this.$toast.error(this.$t("import.failed"))
icon: "error_outline",
})
}, },
parsePostmanCollection({ info, name, item }) { parsePostmanCollection({ info, name, item }) {
const hoppscotchCollection = { const hoppscotchCollection = {

View File

@@ -1,12 +1,12 @@
<template> <template>
<SmartModal <SmartModal
v-if="show" v-if="show"
:title="`${$t('collection.save_as')}`" :title="`${t('collection.save_as')}`"
@close="hideModal" @close="hideModal"
> >
<template #body> <template #body>
<div class="flex flex-col px-2"> <div class="flex flex-col px-2">
<div class="flex relative"> <div class="relative flex">
<input <input
id="selectLabelSaveReq" id="selectLabelSaveReq"
v-model="requestName" v-model="requestName"
@@ -18,11 +18,11 @@
@keyup.enter="saveRequestAs" @keyup.enter="saveRequestAs"
/> />
<label for="selectLabelSaveReq"> <label for="selectLabelSaveReq">
{{ $t("request.name") }} {{ t("request.name") }}
</label> </label>
</div> </div>
<label class="p-4"> <label class="p-4">
{{ $t("collection.select_location") }} {{ t("collection.select_location") }}
</label> </label>
<CollectionsGraphql <CollectionsGraphql
v-if="mode === 'graphql'" v-if="mode === 'graphql'"
@@ -45,11 +45,11 @@
<template #footer> <template #footer>
<span> <span>
<ButtonPrimary <ButtonPrimary
:label="`${$t('action.save')}`" :label="`${t('action.save')}`"
@click.native="saveRequestAs" @click.native="saveRequestAs"
/> />
<ButtonSecondary <ButtonSecondary
:label="`${$t('action.cancel')}`" :label="`${t('action.cancel')}`"
@click.native="hideModal" @click.native="hideModal"
/> />
</span> </span>
@@ -58,7 +58,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { reactive, ref, useContext, watch } from "@nuxtjs/composition-api" import { reactive, ref, watch } from "@nuxtjs/composition-api"
import { isHoppRESTRequest } from "~/helpers/types/HoppRESTRequest" import { isHoppRESTRequest } from "~/helpers/types/HoppRESTRequest"
import { import {
editGraphqlRequest, editGraphqlRequest,
@@ -75,6 +75,9 @@ import {
import * as teamUtils from "~/helpers/teams/utils" import * as teamUtils from "~/helpers/teams/utils"
import { apolloClient } from "~/helpers/apollo" import { apolloClient } from "~/helpers/apollo"
import { HoppGQLRequest } from "~/helpers/types/HoppGQLRequest" import { HoppGQLRequest } from "~/helpers/types/HoppGQLRequest"
import { useI18n, useToast } from "~/helpers/utils/composables"
const t = useI18n()
type CollectionType = type CollectionType =
| { | {
@@ -137,12 +140,7 @@ const emit = defineEmits<{
(e: "hide-modal"): void (e: "hide-modal"): void
}>() }>()
const { const toast = useToast()
$toast,
app: { i18n },
} = useContext()
const t = i18n.t.bind(i18n)
// TODO: Use a better implementation with computed ? // TODO: Use a better implementation with computed ?
// This implementation can't work across updates to mode prop (which won't happen tho) // This implementation can't work across updates to mode prop (which won't happen tho)
@@ -194,15 +192,11 @@ const hideModal = () => {
const saveRequestAs = async () => { const saveRequestAs = async () => {
if (!requestName.value) { if (!requestName.value) {
$toast.error(`${t("error.empty_req_name")}`, { toast.error(`${t("error.empty_req_name")}`)
icon: "error_outline",
})
return return
} }
if (picked.value === null) { if (picked.value === null) {
$toast.error(`${t("collection.select")}`, { toast.error(`${t("collection.select")}`)
icon: "error_outline",
})
return return
} }
@@ -283,9 +277,7 @@ const saveRequestAs = async () => {
requestSaved() requestSaved()
}) })
.catch((error) => { .catch((error) => {
$toast.error(t("profile.no_permission").toString(), { toast.error(`${t("profile.no_permission")}`)
icon: "error_outline",
})
throw new Error(error) throw new Error(error)
}) })
@@ -320,9 +312,7 @@ const saveRequestAs = async () => {
requestSaved() requestSaved()
} catch (error) { } catch (error) {
$toast.error(t("profile.no_permission").toString(), { toast.error(`${t("profile.no_permission")}`)
icon: "error_outline",
})
console.error(error) console.error(error)
} }
} else if (picked.value.pickedType === "teams-collection") { } else if (picked.value.pickedType === "teams-collection") {
@@ -352,9 +342,7 @@ const saveRequestAs = async () => {
requestSaved() requestSaved()
} catch (error) { } catch (error) {
$toast.error(t("profile.no_permission").toString(), { toast.error(`${t("profile.no_permission")}`)
icon: "error_outline",
})
console.error(error) console.error(error)
} }
} else if (picked.value.pickedType === "gql-my-request") { } else if (picked.value.pickedType === "gql-my-request") {
@@ -386,9 +374,7 @@ const saveRequestAs = async () => {
} }
const requestSaved = () => { const requestSaved = () => {
$toast.success(`${t("request.added")}`, { toast.success(`${t("request.added")}`)
icon: "post_add",
})
hideModal() hideModal()
} }

View File

@@ -49,9 +49,7 @@ export default defineComponent({
methods: { methods: {
addNewCollection() { addNewCollection() {
if (!this.name) { if (!this.name) {
this.$toast.error(`${this.$t("collection.invalid_name")}`, { this.$toast.error(`${this.$t("collection.invalid_name")}`)
icon: "error_outline",
})
return return
} }

View File

@@ -1,7 +1,7 @@
<template> <template>
<div class="flex flex-col" :class="[{ 'bg-primaryLight': dragging }]"> <div class="flex flex-col" :class="[{ 'bg-primaryLight': dragging }]">
<div <div
class="flex items-center group" class="group flex items-center"
@dragover.prevent @dragover.prevent
@drop.prevent="dropEvent" @drop.prevent="dropEvent"
@dragover="dragging = true" @dragover="dragging = true"
@@ -10,7 +10,7 @@
@dragend="dragging = false" @dragend="dragging = false"
> >
<span <span
class="cursor-pointer flex px-4 justify-center items-center" class="flex items-center justify-center px-4 cursor-pointer"
@click="toggleShowChildren()" @click="toggleShowChildren()"
> >
<SmartIcon <SmartIcon
@@ -20,15 +20,7 @@
/> />
</span> </span>
<span <span
class=" class="group-hover:text-secondaryDark flex flex-1 min-w-0 py-2 pr-2 transition cursor-pointer"
cursor-pointer
flex flex-1
min-w-0
py-2
pr-2
transition
group-hover:text-secondaryDark
"
@click="toggleShowChildren()" @click="toggleShowChildren()"
> >
<span class="truncate"> {{ collection.name }} </span> <span class="truncate"> {{ collection.name }} </span>
@@ -38,7 +30,7 @@
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
svg="folder-plus" svg="folder-plus"
:title="$t('folder.new')" :title="$t('folder.new')"
class="hidden group-hover:inline-flex" class="group-hover:inline-flex hidden"
@click.native=" @click.native="
$emit('add-folder', { $emit('add-folder', {
path: `${collectionIndex}`, path: `${collectionIndex}`,
@@ -99,16 +91,7 @@
</div> </div>
<div v-if="showChildren || isFiltered" class="flex"> <div v-if="showChildren || isFiltered" class="flex">
<div <div
class=" class="flex w-1 transform transition cursor-nsResize ml-5.5 bg-dividerLight hover:scale-x-125 hover:bg-dividerDark"
flex
w-1
transform
transition
cursor-nsResize
ml-5.5
bg-dividerLight
hover:scale-x-125 hover:bg-dividerDark
"
@click="toggleShowChildren()" @click="toggleShowChildren()"
></div> ></div>
<div class="flex flex-col flex-1 truncate"> <div class="flex flex-col flex-1 truncate">
@@ -149,25 +132,12 @@
v-if=" v-if="
collection.folders.length === 0 && collection.requests.length === 0 collection.folders.length === 0 && collection.requests.length === 0
" "
class=" class="text-secondaryLight flex flex-col items-center justify-center p-4"
flex flex-col
text-secondaryLight
p-4
items-center
justify-center
"
> >
<img <img
:src="`/images/states/${$colorMode.value}/pack.svg`" :src="`/images/states/${$colorMode.value}/pack.svg`"
loading="lazy" loading="lazy"
class=" class="inline-flex flex-col object-contain object-center w-16 h-16 mb-4"
flex-col
mb-4
object-contain object-center
h-16
w-16
inline-flex
"
:alt="$t('empty.collection')" :alt="$t('empty.collection')"
/> />
<span class="text-center"> <span class="text-center">
@@ -251,9 +221,7 @@ export default defineComponent({
this.$emit("select", { picked: null }) this.$emit("select", { picked: null })
} }
removeGraphqlCollection(this.collectionIndex) removeGraphqlCollection(this.collectionIndex)
this.$toast.success(`${this.$t("state.deleted")}`, { this.$toast.success(`${this.$t("state.deleted")}`)
icon: "delete",
})
}, },
dropEvent({ dataTransfer }: any) { dropEvent({ dataTransfer }: any) {
this.dragging = !this.dragging this.dragging = !this.dragging

View File

@@ -54,9 +54,7 @@ export default defineComponent({
methods: { methods: {
saveCollection() { saveCollection() {
if (!this.name) { if (!this.name) {
this.$toast.error(`${this.$t("collection.invalid_name")}`, { this.$toast.error(`${this.$t("collection.invalid_name")}`)
icon: "error_outline",
})
return return
} }
const collectionUpdated = { const collectionUpdated = {

View File

@@ -54,9 +54,7 @@ export default defineComponent({
methods: { methods: {
editFolder() { editFolder() {
if (!this.name) { if (!this.name) {
this.$toast.error(`${this.$t("collection.invalid_name")}`, { this.$toast.error(`${this.$t("collection.invalid_name")}`)
icon: "error_outline",
})
return return
} }
editGraphqlFolder(this.folderPath, { editGraphqlFolder(this.folderPath, {

View File

@@ -58,9 +58,7 @@ export default defineComponent({
methods: { methods: {
saveRequest() { saveRequest() {
if (!this.requestUpdateData.name) { if (!this.requestUpdateData.name) {
this.$toast.error(`${this.$t("collection.invalid_name")}`, { this.$toast.error(`${this.$t("collection.invalid_name")}`)
icon: "error_outline",
})
return return
} }
const requestUpdated = { const requestUpdated = {

View File

@@ -1,7 +1,7 @@
<template> <template>
<div class="flex flex-col" :class="[{ 'bg-primaryLight': dragging }]"> <div class="flex flex-col" :class="[{ 'bg-primaryLight': dragging }]">
<div <div
class="flex items-center group" class="group flex items-center"
@dragover.prevent @dragover.prevent
@drop.prevent="dropEvent" @drop.prevent="dropEvent"
@dragover="dragging = true" @dragover="dragging = true"
@@ -10,7 +10,7 @@
@dragend="dragging = false" @dragend="dragging = false"
> >
<span <span
class="cursor-pointer flex px-4 justify-center items-center" class="flex items-center justify-center px-4 cursor-pointer"
@click="toggleShowChildren()" @click="toggleShowChildren()"
> >
<SmartIcon <SmartIcon
@@ -20,15 +20,7 @@
/> />
</span> </span>
<span <span
class=" class="group-hover:text-secondaryDark flex flex-1 min-w-0 py-2 pr-2 transition cursor-pointer"
cursor-pointer
flex flex-1
min-w-0
py-2
pr-2
transition
group-hover:text-secondaryDark
"
@click="toggleShowChildren()" @click="toggleShowChildren()"
> >
<span class="truncate"> <span class="truncate">
@@ -40,7 +32,7 @@
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
svg="folder-plus" svg="folder-plus"
:title="$t('folder.new')" :title="$t('folder.new')"
class="hidden group-hover:inline-flex" class="group-hover:inline-flex hidden"
@click.native="$emit('add-folder', { folder, path: folderPath })" @click.native="$emit('add-folder', { folder, path: folderPath })"
/> />
<span> <span>
@@ -95,16 +87,7 @@
</div> </div>
<div v-if="showChildren || isFiltered" class="flex"> <div v-if="showChildren || isFiltered" class="flex">
<div <div
class=" class="flex w-1 transform transition cursor-nsResize ml-5.5 bg-dividerLight hover:scale-x-125 hover:bg-dividerDark"
flex
w-1
transform
transition
cursor-nsResize
ml-5.5
bg-dividerLight
hover:scale-x-125 hover:bg-dividerDark
"
@click="toggleShowChildren()" @click="toggleShowChildren()"
></div> ></div>
<div class="flex flex-col flex-1 truncate"> <div class="flex flex-col flex-1 truncate">
@@ -148,25 +131,12 @@
folder.requests && folder.requests &&
folder.requests.length === 0 folder.requests.length === 0
" "
class=" class="text-secondaryLight flex flex-col items-center justify-center p-4"
flex flex-col
text-secondaryLight
p-4
items-center
justify-center
"
> >
<img <img
:src="`/images/states/${$colorMode.value}/pack.svg`" :src="`/images/states/${$colorMode.value}/pack.svg`"
loading="lazy" loading="lazy"
class=" class="inline-flex flex-col object-contain object-center w-16 h-16 mb-4"
flex-col
mb-4
object-contain object-center
h-16
w-16
inline-flex
"
:alt="$t('empty.folder')" :alt="$t('empty.folder')"
/> />
<span class="text-center"> <span class="text-center">
@@ -250,9 +220,7 @@ export default defineComponent({
} }
removeGraphqlFolder(this.folderPath) removeGraphqlFolder(this.folderPath)
this.$toast.success(`${this.$t("state.deleted")}`, { this.$toast.success(`${this.$t("state.deleted")}`)
icon: "delete",
})
}, },
dropEvent({ dataTransfer }: any) { dropEvent({ dataTransfer }: any) {
this.dragging = !this.dragging this.dragging = !this.dragging

View File

@@ -140,15 +140,11 @@ export default defineComponent({
} }
) )
.then((res) => { .then((res) => {
this.$toast.success(this.$t("export.gist_created"), { this.$toast.success(this.$t("export.gist_created"))
icon: "done",
})
window.open(res.html_url) window.open(res.html_url)
}) })
.catch((e) => { .catch((e) => {
this.$toast.error(this.$t("error.something_went_wrong"), { this.$toast.error(this.$t("error.something_went_wrong"))
icon: "error_outline",
})
console.error(e) console.error(e)
}) })
}, },
@@ -252,23 +248,17 @@ export default defineComponent({
a.download = `${url.split("/").pop().split("#")[0].split("?")[0]}.json` a.download = `${url.split("/").pop().split("#")[0].split("?")[0]}.json`
document.body.appendChild(a) document.body.appendChild(a)
a.click() a.click()
this.$toast.success(this.$t("state.download_started"), { this.$toast.success(this.$t("state.download_started"))
icon: "downloading",
})
setTimeout(() => { setTimeout(() => {
document.body.removeChild(a) document.body.removeChild(a)
URL.revokeObjectURL(url) URL.revokeObjectURL(url)
}, 1000) }, 1000)
}, },
fileImported() { fileImported() {
this.$toast.success(this.$t("state.file_imported"), { this.$toast.success(this.$t("state.file_imported"))
icon: "folder_shared",
})
}, },
failedImport() { failedImport() {
this.$toast.error(this.$t("import.failed"), { this.$toast.error(this.$t("import.failed"))
icon: "error_outline",
})
}, },
parsePostmanCollection({ info, name, item }) { parsePostmanCollection({ info, name, item }) {
const hoppscotchCollection = { const hoppscotchCollection = {

View File

@@ -1,7 +1,7 @@
<template> <template>
<div class="flex flex-col" :class="[{ 'bg-primaryLight': dragging }]"> <div class="flex flex-col" :class="[{ 'bg-primaryLight': dragging }]">
<div <div
class="flex items-center group" class="group flex items-center"
draggable="true" draggable="true"
@dragstart="dragStart" @dragstart="dragStart"
@dragover.stop @dragover.stop
@@ -9,15 +9,7 @@
@dragend="dragging = false" @dragend="dragging = false"
> >
<span <span
class=" class="flex items-center justify-center w-16 px-2 truncate cursor-pointer"
cursor-pointer
flex
px-2
w-16
justify-center
items-center
truncate
"
@click="!doc ? selectRequest() : {}" @click="!doc ? selectRequest() : {}"
> >
<SmartIcon <SmartIcon
@@ -27,15 +19,7 @@
/> />
</span> </span>
<span <span
class=" class="group-hover:text-secondaryDark flex flex-1 min-w-0 py-2 pr-2 transition cursor-pointer"
cursor-pointer
flex flex-1
min-w-0
py-2
pr-2
transition
group-hover:text-secondaryDark
"
@click="!doc ? selectRequest() : {}" @click="!doc ? selectRequest() : {}"
> >
<span class="truncate"> {{ request.name }} </span> <span class="truncate"> {{ request.name }} </span>
@@ -46,7 +30,7 @@
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
svg="rotate-ccw" svg="rotate-ccw"
:title="$t('action.restore')" :title="$t('action.restore')"
class="hidden group-hover:inline-flex" class="group-hover:inline-flex hidden"
@click.native="!doc ? selectRequest() : {}" @click.native="!doc ? selectRequest() : {}"
/> />
<span> <span>
@@ -194,9 +178,7 @@ export default defineComponent({
} }
removeGraphqlRequest(this.folderPath, this.requestIndex) removeGraphqlRequest(this.folderPath, this.requestIndex)
this.$toast.success(`${this.$t("state.deleted")}`, { this.$toast.success(`${this.$t("state.deleted")}`)
icon: "delete",
})
}, },
}, },
}) })

View File

@@ -4,14 +4,7 @@
:class="{ 'rounded border border-divider': savingMode }" :class="{ 'rounded border border-divider': savingMode }"
> >
<div <div
class=" class="divide-dividerLight border-dividerLight sticky top-0 z-10 flex flex-col border-b divide-y"
divide-y divide-dividerLight
border-b border-dividerLight
flex flex-col
top-0
z-10
sticky
"
:class="{ 'bg-primary': !savingMode }" :class="{ 'bg-primary': !savingMode }"
> >
<input <input
@@ -20,9 +13,9 @@
type="search" type="search"
autocomplete="off" autocomplete="off"
:placeholder="$t('action.search')" :placeholder="$t('action.search')"
class="bg-transparent flex w-full py-2 px-4" class="flex w-full px-4 py-2 bg-transparent"
/> />
<div class="flex flex-1 justify-between"> <div class="flex justify-between flex-1">
<ButtonSecondary <ButtonSecondary
svg="plus" svg="plus"
:label="$t('action.new')" :label="$t('action.new')"
@@ -69,15 +62,15 @@
</div> </div>
<div <div
v-if="collections.length === 0" v-if="collections.length === 0"
class="flex flex-col text-secondaryLight p-4 items-center justify-center" class="text-secondaryLight flex flex-col items-center justify-center p-4"
> >
<img <img
:src="`/images/states/${$colorMode.value}/pack.svg`" :src="`/images/states/${$colorMode.value}/pack.svg`"
loading="lazy" loading="lazy"
class="flex-col my-4 object-contain object-center h-16 w-16 inline-flex" class="inline-flex flex-col object-contain object-center w-16 h-16 my-4"
:alt="$t('empty.collections')" :alt="$t('empty.collections')"
/> />
<span class="text-center pb-4"> <span class="pb-4 text-center">
{{ $t("empty.collections") }} {{ $t("empty.collections") }}
</span> </span>
<ButtonSecondary <ButtonSecondary
@@ -88,9 +81,9 @@
</div> </div>
<div <div
v-if="!(filteredCollections.length !== 0 || collections.length === 0)" v-if="!(filteredCollections.length !== 0 || collections.length === 0)"
class="flex flex-col text-secondaryLight p-4 items-center justify-center" class="text-secondaryLight flex flex-col items-center justify-center p-4"
> >
<i class="opacity-75 pb-2 material-icons">manage_search</i> <i class="material-icons pb-2 opacity-75">manage_search</i>
<span class="text-center"> <span class="text-center">
{{ $t("state.nothing_found") }} "{{ filterText }}" {{ $t("state.nothing_found") }} "{{ filterText }}"
</span> </span>

View File

@@ -4,16 +4,7 @@
:class="{ 'rounded border border-divider': saveRequest }" :class="{ 'rounded border border-divider': saveRequest }"
> >
<div <div
class=" class="divide-dividerLight bg-primary border-dividerLight sticky top-0 z-10 flex flex-col border-b divide-y rounded-t"
divide-y divide-dividerLight
bg-primary
border-b border-dividerLight
rounded-t
flex flex-col
top-0
z-10
sticky
"
> >
<div v-if="!saveRequest" class="search-wrappe"> <div v-if="!saveRequest" class="search-wrappe">
<input <input
@@ -21,7 +12,7 @@
type="search" type="search"
autocomplete="off" autocomplete="off"
:placeholder="$t('action.search')" :placeholder="$t('action.search')"
class="bg-transparent flex w-full py-2 pr-2 pl-4" class="flex w-full py-2 pl-4 pr-2 bg-transparent"
/> />
</div> </div>
<CollectionsChooseType <CollectionsChooseType
@@ -31,7 +22,7 @@
@update-collection-type="updateCollectionType" @update-collection-type="updateCollectionType"
@update-selected-team="updateSelectedTeam" @update-selected-team="updateSelectedTeam"
/> />
<div class="flex flex-1 justify-between"> <div class="flex justify-between flex-1">
<ButtonSecondary <ButtonSecondary
v-if=" v-if="
collectionsType.type == 'team-collections' && collectionsType.type == 'team-collections' &&
@@ -107,15 +98,15 @@
</div> </div>
<div <div
v-if="filteredCollections.length === 0 && filterText.length === 0" v-if="filteredCollections.length === 0 && filterText.length === 0"
class="flex flex-col text-secondaryLight p-4 items-center justify-center" class="text-secondaryLight flex flex-col items-center justify-center p-4"
> >
<img <img
:src="`/images/states/${$colorMode.value}/pack.svg`" :src="`/images/states/${$colorMode.value}/pack.svg`"
loading="lazy" loading="lazy"
class="flex-col my-4 object-contain object-center h-16 w-16 inline-flex" class="inline-flex flex-col object-contain object-center w-16 h-16 my-4"
:alt="$t('empty.collections')" :alt="$t('empty.collections')"
/> />
<span class="text-center pb-4"> <span class="pb-4 text-center">
{{ $t("empty.collections") }} {{ $t("empty.collections") }}
</span> </span>
<ButtonSecondary <ButtonSecondary
@@ -140,9 +131,9 @@
</div> </div>
<div <div
v-if="filterText.length !== 0 && filteredCollections.length === 0" v-if="filterText.length !== 0 && filteredCollections.length === 0"
class="flex flex-col text-secondaryLight p-4 items-center justify-center" class="text-secondaryLight flex flex-col items-center justify-center p-4"
> >
<i class="opacity-75 pb-2 material-icons">manage_search</i> <i class="material-icons pb-2 opacity-75">manage_search</i>
<span class="text-center"> <span class="text-center">
{{ $t("state.nothing_found") }} "{{ filterText }}" {{ $t("state.nothing_found") }} "{{ filterText }}"
</span> </span>
@@ -361,14 +352,10 @@ export default defineComponent({
this.collectionsType.selectedTeam.id this.collectionsType.selectedTeam.id
) )
.then(() => { .then(() => {
this.$toast.success(this.$t("collection.created"), { this.$toast.success(this.$t("collection.created"))
icon: "done",
})
}) })
.catch((e) => { .catch((e) => {
this.$toast.error(this.$t("error.something_went_wrong"), { this.$toast.error(this.$t("error.something_went_wrong"))
icon: "error_outline",
})
console.error(e) console.error(e)
}) })
} }
@@ -377,9 +364,7 @@ export default defineComponent({
// Intented to be called by CollectionEdit modal submit event // Intented to be called by CollectionEdit modal submit event
updateEditingCollection(newName) { updateEditingCollection(newName) {
if (!newName) { if (!newName) {
this.$toast.error(this.$t("collection.invalid_name"), { this.$toast.error(this.$t("collection.invalid_name"))
icon: "error_outline",
})
return return
} }
if (this.collectionsType.type === "my-collections") { if (this.collectionsType.type === "my-collections") {
@@ -396,14 +381,10 @@ export default defineComponent({
teamUtils teamUtils
.renameCollection(this.$apollo, newName, this.editingCollection.id) .renameCollection(this.$apollo, newName, this.editingCollection.id)
.then(() => { .then(() => {
this.$toast.success(this.$t("collection.renamed"), { this.$toast.success(this.$t("collection.renamed"))
icon: "done",
})
}) })
.catch((e) => { .catch((e) => {
this.$toast.error(this.$t("error.something_went_wrong"), { this.$toast.error(this.$t("error.something_went_wrong"))
icon: "error_outline",
})
console.error(e) console.error(e)
}) })
} }
@@ -420,14 +401,10 @@ export default defineComponent({
teamUtils teamUtils
.renameCollection(this.$apollo, name, this.editingFolder.id) .renameCollection(this.$apollo, name, this.editingFolder.id)
.then(() => { .then(() => {
this.$toast.success(this.$t("folder.renamed"), { this.$toast.success(this.$t("folder.renamed"))
icon: "done",
})
}) })
.catch((e) => { .catch((e) => {
this.$toast.error(this.$t("error.something_went_wrong"), { this.$toast.error(this.$t("error.something_went_wrong"))
icon: "error_outline",
})
console.error(e) console.error(e)
}) })
} }
@@ -460,15 +437,11 @@ export default defineComponent({
this.editingRequestIndex this.editingRequestIndex
) )
.then(() => { .then(() => {
this.$toast.success(this.$t("request.renamed"), { this.$toast.success(this.$t("request.renamed"))
icon: "done",
})
this.$emit("update-team-collections") this.$emit("update-team-collections")
}) })
.catch((e) => { .catch((e) => {
this.$toast.error(this.$t("error.something_went_wrong"), { this.$toast.error(this.$t("error.something_went_wrong"))
icon: "error_outline",
})
console.error(e) console.error(e)
}) })
} }
@@ -533,15 +506,11 @@ export default defineComponent({
}, },
}) })
.then(() => { .then(() => {
this.$toast.success(this.$t("folder.created"), { this.$toast.success(this.$t("folder.created"))
icon: "done",
})
this.$emit("update-team-collections") this.$emit("update-team-collections")
}) })
.catch((e) => { .catch((e) => {
this.$toast.error(this.$t("error.something_went_wrong"), { this.$toast.error(this.$t("error.something_went_wrong"))
icon: "error_outline",
})
console.error(e) console.error(e)
}) })
} }
@@ -605,9 +574,7 @@ export default defineComponent({
} }
removeRESTCollection(collectionIndex) removeRESTCollection(collectionIndex)
this.$toast.success(this.$t("state.deleted"), { this.$toast.success(this.$t("state.deleted"))
icon: "delete",
})
} else if (collectionsType.type === "team-collections") { } else if (collectionsType.type === "team-collections") {
// Cancel pick if picked collection is deleted // Cancel pick if picked collection is deleted
if ( if (
@@ -633,14 +600,10 @@ export default defineComponent({
}, },
}) })
.then(() => { .then(() => {
this.$toast.success(this.$t("state.deleted"), { this.$toast.success(this.$t("state.deleted"))
icon: "delete",
})
}) })
.catch((e) => { .catch((e) => {
this.$toast.error(this.$t("error.something_went_wrong"), { this.$toast.error(this.$t("error.something_went_wrong"))
icon: "error_outline",
})
console.error(e) console.error(e)
}) })
} }
@@ -658,9 +621,7 @@ export default defineComponent({
this.$emit("select", { picked: null }) this.$emit("select", { picked: null })
} }
removeRESTRequest(folderPath, requestIndex) removeRESTRequest(folderPath, requestIndex)
this.$toast.success(this.$t("state.deleted"), { this.$toast.success(this.$t("state.deleted"))
icon: "delete",
})
} else if (this.collectionsType.type === "team-collections") { } else if (this.collectionsType.type === "team-collections") {
// Cancel pick if the picked item is being deleted // Cancel pick if the picked item is being deleted
if ( if (
@@ -674,14 +635,10 @@ export default defineComponent({
teamUtils teamUtils
.deleteRequest(this.$apollo, requestIndex) .deleteRequest(this.$apollo, requestIndex)
.then(() => { .then(() => {
this.$toast.success(this.$t("state.deleted"), { this.$toast.success(this.$t("state.deleted"))
icon: "delete",
})
}) })
.catch((e) => { .catch((e) => {
this.$toast.error(this.$t("error.something_went_wrong"), { this.$toast.error(this.$t("error.something_went_wrong"))
icon: "error_outline",
})
console.error(e) console.error(e)
}) })
} }

View File

@@ -1,7 +1,7 @@
<template> <template>
<div class="flex flex-col" :class="[{ 'bg-primaryLight': dragging }]"> <div class="flex flex-col" :class="[{ 'bg-primaryLight': dragging }]">
<div <div
class="flex items-center group" class="group flex items-center"
@dragover.prevent @dragover.prevent
@drop.prevent="dropEvent" @drop.prevent="dropEvent"
@dragover="dragging = true" @dragover="dragging = true"
@@ -10,7 +10,7 @@
@dragend="dragging = false" @dragend="dragging = false"
> >
<span <span
class="cursor-pointer flex px-4 justify-center items-center" class="flex items-center justify-center px-4 cursor-pointer"
@click="toggleShowChildren()" @click="toggleShowChildren()"
> >
<SmartIcon <SmartIcon
@@ -20,15 +20,7 @@
/> />
</span> </span>
<span <span
class=" class="group-hover:text-secondaryDark flex flex-1 min-w-0 py-2 pr-2 transition cursor-pointer"
cursor-pointer
flex flex-1
min-w-0
py-2
pr-2
transition
group-hover:text-secondaryDark
"
@click="toggleShowChildren()" @click="toggleShowChildren()"
> >
<span class="truncate"> {{ collection.name }} </span> <span class="truncate"> {{ collection.name }} </span>
@@ -55,7 +47,7 @@
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
svg="folder-plus" svg="folder-plus"
:title="$t('folder.new')" :title="$t('folder.new')"
class="hidden group-hover:inline-flex" class="group-hover:inline-flex hidden"
@click.native=" @click.native="
$emit('add-folder', { $emit('add-folder', {
folder: collection, folder: collection,
@@ -118,16 +110,7 @@
</div> </div>
<div v-if="showChildren || isFiltered" class="flex"> <div v-if="showChildren || isFiltered" class="flex">
<div <div
class=" class="flex w-1 transform transition cursor-nsResize ml-5.5 bg-dividerLight hover:scale-x-125 hover:bg-dividerDark"
flex
w-1
transform
transition
cursor-nsResize
ml-5.5
bg-dividerLight
hover:scale-x-125 hover:bg-dividerDark
"
@click="toggleShowChildren()" @click="toggleShowChildren()"
></div> ></div>
<div class="flex flex-col flex-1 truncate"> <div class="flex flex-col flex-1 truncate">
@@ -175,25 +158,12 @@
(collection.requests == undefined || (collection.requests == undefined ||
collection.requests.length === 0) collection.requests.length === 0)
" "
class=" class="text-secondaryLight flex flex-col items-center justify-center p-4"
flex flex-col
text-secondaryLight
p-4
items-center
justify-center
"
> >
<img <img
:src="`/images/states/${$colorMode.value}/pack.svg`" :src="`/images/states/${$colorMode.value}/pack.svg`"
loading="lazy" loading="lazy"
class=" class="inline-flex flex-col object-contain object-center w-16 h-16 mb-4"
flex-col
mb-4
object-contain object-center
h-16
w-16
inline-flex
"
:alt="$t('empty.collection')" :alt="$t('empty.collection')"
/> />
<span class="text-center"> <span class="text-center">

View File

@@ -1,7 +1,7 @@
<template> <template>
<div class="flex flex-col" :class="[{ 'bg-primaryLight': dragging }]"> <div class="flex flex-col" :class="[{ 'bg-primaryLight': dragging }]">
<div <div
class="flex items-center group" class="group flex items-center"
@dragover.prevent @dragover.prevent
@drop.prevent="dropEvent" @drop.prevent="dropEvent"
@dragover="dragging = true" @dragover="dragging = true"
@@ -10,7 +10,7 @@
@dragend="dragging = false" @dragend="dragging = false"
> >
<span <span
class="cursor-pointer flex px-4 justify-center items-center" class="flex items-center justify-center px-4 cursor-pointer"
@click="toggleShowChildren()" @click="toggleShowChildren()"
> >
<SmartIcon <SmartIcon
@@ -20,15 +20,7 @@
/> />
</span> </span>
<span <span
class=" class="group-hover:text-secondaryDark flex flex-1 min-w-0 py-2 pr-2 transition cursor-pointer"
cursor-pointer
flex flex-1
min-w-0
py-2
pr-2
transition
group-hover:text-secondaryDark
"
@click="toggleShowChildren()" @click="toggleShowChildren()"
> >
<span class="truncate"> <span class="truncate">
@@ -40,7 +32,7 @@
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
svg="folder-plus" svg="folder-plus"
:title="$t('folder.new')" :title="$t('folder.new')"
class="hidden group-hover:inline-flex" class="group-hover:inline-flex hidden"
@click.native="$emit('add-folder', { folder, path: folderPath })" @click.native="$emit('add-folder', { folder, path: folderPath })"
/> />
<span> <span>
@@ -100,16 +92,7 @@
</div> </div>
<div v-if="showChildren || isFiltered" class="flex"> <div v-if="showChildren || isFiltered" class="flex">
<div <div
class=" class="flex w-1 transform transition cursor-nsResize ml-5.5 bg-dividerLight hover:scale-x-125 hover:bg-dividerDark"
flex
w-1
transform
transition
cursor-nsResize
ml-5.5
bg-dividerLight
hover:scale-x-125 hover:bg-dividerDark
"
@click="toggleShowChildren()" @click="toggleShowChildren()"
></div> ></div>
<div class="flex flex-col flex-1 truncate"> <div class="flex flex-col flex-1 truncate">
@@ -157,25 +140,12 @@
folder.requests && folder.requests &&
folder.requests.length === 0 folder.requests.length === 0
" "
class=" class="text-secondaryLight flex flex-col items-center justify-center p-4"
flex flex-col
text-secondaryLight
p-4
items-center
justify-center
"
> >
<img <img
:src="`/images/states/${$colorMode.value}/pack.svg`" :src="`/images/states/${$colorMode.value}/pack.svg`"
loading="lazy" loading="lazy"
class=" class="inline-flex flex-col object-contain object-center w-16 h-16 mb-4"
flex-col
mb-4
object-contain object-center
h-16
w-16
inline-flex
"
:alt="$t('empty.folder')" :alt="$t('empty.folder')"
/> />
<span class="text-center"> <span class="text-center">
@@ -262,9 +232,7 @@ export default defineComponent({
this.$emit("select", { picked: null }) this.$emit("select", { picked: null })
} }
removeRESTFolder(this.folderPath) removeRESTFolder(this.folderPath)
this.$toast.success(this.$t("state.deleted"), { this.$toast.success(this.$t("state.deleted"))
icon: "delete",
})
}, },
dropEvent({ dataTransfer }) { dropEvent({ dataTransfer }) {
this.dragging = !this.dragging this.dragging = !this.dragging

View File

@@ -1,7 +1,7 @@
<template> <template>
<div class="flex flex-col" :class="[{ 'bg-primaryLight': dragging }]"> <div class="flex flex-col" :class="[{ 'bg-primaryLight': dragging }]">
<div <div
class="flex items-center group" class="group flex items-center"
draggable="true" draggable="true"
@dragstart="dragStart" @dragstart="dragStart"
@dragover.stop @dragover.stop
@@ -9,15 +9,7 @@
@dragend="dragging = false" @dragend="dragging = false"
> >
<span <span
class=" class="flex items-center justify-center w-16 px-2 truncate cursor-pointer"
cursor-pointer
flex
px-2
w-16
justify-center
items-center
truncate
"
:class="getRequestLabelColor(request.method)" :class="getRequestLabelColor(request.method)"
@click="!doc ? selectRequest() : {}" @click="!doc ? selectRequest() : {}"
> >
@@ -32,16 +24,7 @@
</span> </span>
</span> </span>
<span <span
class=" class="group-hover:text-secondaryDark flex items-center flex-1 min-w-0 py-2 pr-2 transition cursor-pointer"
cursor-pointer
flex flex-1
min-w-0
py-2
pr-2
transition
items-center
group-hover:text-secondaryDark
"
@click="!doc ? selectRequest() : {}" @click="!doc ? selectRequest() : {}"
> >
<span class="truncate"> {{ request.name }} </span> <span class="truncate"> {{ request.name }} </span>
@@ -61,7 +44,7 @@
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
svg="rotate-ccw" svg="rotate-ccw"
:title="$t('action.restore')" :title="$t('action.restore')"
class="hidden group-hover:inline-flex" class="group-hover:inline-flex hidden"
@click.native="!doc ? selectRequest() : {}" @click.native="!doc ? selectRequest() : {}"
/> />
<span> <span>

View File

@@ -1,8 +1,8 @@
<template> <template>
<div class="flex flex-col"> <div class="flex flex-col">
<div class="flex items-center group"> <div class="group flex items-center">
<span <span
class="cursor-pointer flex px-4 justify-center items-center" class="flex items-center justify-center px-4 cursor-pointer"
@click="toggleShowChildren()" @click="toggleShowChildren()"
> >
<SmartIcon <SmartIcon
@@ -12,15 +12,7 @@
/> />
</span> </span>
<span <span
class=" class="group-hover:text-secondaryDark flex flex-1 min-w-0 py-2 pr-2 transition cursor-pointer"
cursor-pointer
flex flex-1
min-w-0
py-2
pr-2
transition
group-hover:text-secondaryDark
"
@click="toggleShowChildren()" @click="toggleShowChildren()"
> >
<span class="truncate"> {{ collection.title }} </span> <span class="truncate"> {{ collection.title }} </span>
@@ -47,7 +39,7 @@
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
svg="folder-plus" svg="folder-plus"
:title="$t('folder.new')" :title="$t('folder.new')"
class="hidden group-hover:inline-flex" class="group-hover:inline-flex hidden"
@click.native=" @click.native="
$emit('add-folder', { $emit('add-folder', {
folder: collection, folder: collection,
@@ -114,16 +106,7 @@
</div> </div>
<div v-if="showChildren || isFiltered" class="flex"> <div v-if="showChildren || isFiltered" class="flex">
<div <div
class=" class="flex w-1 transform transition cursor-nsResize ml-5.5 bg-dividerLight hover:scale-x-125 hover:bg-dividerDark"
flex
w-1
transform
transition
cursor-nsResize
ml-5.5
bg-dividerLight
hover:scale-x-125 hover:bg-dividerDark
"
@click="toggleShowChildren()" @click="toggleShowChildren()"
></div> ></div>
<div class="flex flex-col flex-1 truncate"> <div class="flex flex-col flex-1 truncate">
@@ -169,25 +152,12 @@
(collection.requests == undefined || (collection.requests == undefined ||
collection.requests.length === 0) collection.requests.length === 0)
" "
class=" class="text-secondaryLight flex flex-col items-center justify-center p-4"
flex flex-col
text-secondaryLight
p-4
items-center
justify-center
"
> >
<img <img
:src="`/images/states/${$colorMode.value}/pack.svg`" :src="`/images/states/${$colorMode.value}/pack.svg`"
loading="lazy" loading="lazy"
class=" class="inline-flex flex-col object-contain object-center w-16 h-16 mb-4"
flex-col
mb-4
object-contain object-center
h-16
w-16
inline-flex
"
:alt="$t('empty.collection')" :alt="$t('empty.collection')"
/> />
<span class="text-center"> <span class="text-center">

View File

@@ -1,8 +1,8 @@
<template> <template>
<div class="flex flex-col"> <div class="flex flex-col">
<div class="flex items-center group"> <div class="group flex items-center">
<span <span
class="cursor-pointer flex px-4 justify-center items-center" class="flex items-center justify-center px-4 cursor-pointer"
@click="toggleShowChildren()" @click="toggleShowChildren()"
> >
<SmartIcon <SmartIcon
@@ -12,15 +12,7 @@
/> />
</span> </span>
<span <span
class=" class="group-hover:text-secondaryDark flex flex-1 min-w-0 py-2 pr-2 transition cursor-pointer"
cursor-pointer
flex flex-1
min-w-0
py-2
pr-2
transition
group-hover:text-secondaryDark
"
@click="toggleShowChildren()" @click="toggleShowChildren()"
> >
<span class="truncate"> <span class="truncate">
@@ -33,7 +25,7 @@
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
svg="folder-plus" svg="folder-plus"
:title="$t('folder.new')" :title="$t('folder.new')"
class="hidden group-hover:inline-flex" class="group-hover:inline-flex hidden"
@click.native="$emit('add-folder', { folder, path: folderPath })" @click.native="$emit('add-folder', { folder, path: folderPath })"
/> />
<span> <span>
@@ -97,16 +89,7 @@
</div> </div>
<div v-if="showChildren || isFiltered" class="flex"> <div v-if="showChildren || isFiltered" class="flex">
<div <div
class=" class="flex w-1 transform transition cursor-nsResize ml-5.5 bg-dividerLight hover:scale-x-125 hover:bg-dividerDark"
flex
w-1
transform
transition
cursor-nsResize
ml-5.5
bg-dividerLight
hover:scale-x-125 hover:bg-dividerDark
"
@click="toggleShowChildren()" @click="toggleShowChildren()"
></div> ></div>
<div class="flex flex-col flex-1 truncate"> <div class="flex flex-col flex-1 truncate">
@@ -150,25 +133,12 @@
(folder.children == undefined || folder.children.length === 0) && (folder.children == undefined || folder.children.length === 0) &&
(folder.requests == undefined || folder.requests.length === 0) (folder.requests == undefined || folder.requests.length === 0)
" "
class=" class="text-secondaryLight flex flex-col items-center justify-center p-4"
flex flex-col
text-secondaryLight
p-4
items-center
justify-center
"
> >
<img <img
:src="`/images/states/${$colorMode.value}/pack.svg`" :src="`/images/states/${$colorMode.value}/pack.svg`"
loading="lazy" loading="lazy"
class=" class="inline-flex flex-col object-contain object-center w-16 h-16 mb-4"
flex-col
mb-4
object-contain object-center
h-16
w-16
inline-flex
"
:alt="$t('empty.folder')" :alt="$t('empty.folder')"
/> />
<span class="text-center"> <span class="text-center">
@@ -253,15 +223,11 @@ export default defineComponent({
teamUtils teamUtils
.deleteCollection(this.$apollo, this.folder.id) .deleteCollection(this.$apollo, this.folder.id)
.then(() => { .then(() => {
this.$toast.success(this.$t("state.deleted"), { this.$toast.success(this.$t("state.deleted"))
icon: "delete",
})
this.$emit("update-team-collections") this.$emit("update-team-collections")
}) })
.catch((e) => { .catch((e) => {
this.$toast.error(this.$t("error.something_went_wrong"), { this.$toast.error(this.$t("error.something_went_wrong"))
icon: "error_outline",
})
console.error(e) console.error(e)
}) })
this.$emit("update-team-collections") this.$emit("update-team-collections")

View File

@@ -1,16 +1,8 @@
<template> <template>
<div class="flex flex-col"> <div class="flex flex-col">
<div class="flex items-center group"> <div class="group flex items-center">
<span <span
class=" class="flex items-center justify-center w-16 px-2 truncate cursor-pointer"
cursor-pointer
flex
px-2
w-16
justify-center
items-center
truncate
"
:class="getRequestLabelColor(request.method)" :class="getRequestLabelColor(request.method)"
@click="!doc ? selectRequest() : {}" @click="!doc ? selectRequest() : {}"
> >
@@ -25,16 +17,7 @@
</span> </span>
</span> </span>
<span <span
class=" class="group-hover:text-secondaryDark flex items-center flex-1 min-w-0 py-2 pr-2 transition cursor-pointer"
cursor-pointer
flex flex-1
min-w-0
py-2
pr-2
transition
items-center
group-hover:text-secondaryDark
"
@click="!doc ? selectRequest() : {}" @click="!doc ? selectRequest() : {}"
> >
<span class="truncate"> {{ request.name }} </span> <span class="truncate"> {{ request.name }} </span>
@@ -53,7 +36,7 @@
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
svg="rotate-ccw" svg="rotate-ccw"
:title="$t('action.restore')" :title="$t('action.restore')"
class="hidden group-hover:inline-flex" class="group-hover:inline-flex hidden"
@click.native="!doc ? selectRequest() : {}" @click.native="!doc ? selectRequest() : {}"
/> />
<span> <span>

View File

@@ -52,9 +52,7 @@ export default defineComponent({
methods: { methods: {
addNewEnvironment() { addNewEnvironment() {
if (!this.name) { if (!this.name) {
this.$toast.error(`${this.$t("environment.invalid_name")}`, { this.$toast.error(`${this.$t("environment.invalid_name")}`)
icon: "error_outline",
})
return return
} }
createEnvironment(this.name) createEnvironment(this.name)

View File

@@ -6,7 +6,7 @@
> >
<template #body> <template #body>
<div class="flex flex-col px-2"> <div class="flex flex-col px-2">
<div class="flex relative"> <div class="relative flex">
<input <input
id="selectLabelEnvEdit" id="selectLabelEnvEdit"
v-model="name" v-model="name"
@@ -22,7 +22,7 @@
{{ $t("action.label") }} {{ $t("action.label") }}
</label> </label>
</div> </div>
<div class="flex flex-1 justify-between items-center"> <div class="flex items-center justify-between flex-1">
<label for="variableList" class="p-4"> <label for="variableList" class="p-4">
{{ $t("environment.variable_list") }} {{ $t("environment.variable_list") }}
</label> </label>
@@ -43,21 +43,21 @@
/> />
</div> </div>
</div> </div>
<div class="divide-y divide-dividerLight border-divider border rounded"> <div class="divide-dividerLight border-divider border divide-y rounded">
<div <div
v-for="(variable, index) in vars" v-for="(variable, index) in vars"
:key="`variable-${index}`" :key="`variable-${index}`"
class="divide-x divide-dividerLight flex" class="divide-dividerLight flex divide-x"
> >
<input <input
v-model="variable.key" v-model="variable.key"
class="bg-transparent flex flex-1 py-2 px-4" class="flex flex-1 px-4 py-2 bg-transparent"
:placeholder="`${$t('count.variable', { count: index + 1 })}`" :placeholder="`${$t('count.variable', { count: index + 1 })}`"
:name="'param' + index" :name="'param' + index"
/> />
<input <input
v-model="variable.value" v-model="variable.value"
class="bg-transparent flex flex-1 py-2 px-4" class="flex flex-1 px-4 py-2 bg-transparent"
:placeholder="`${$t('count.value', { count: index + 1 })}`" :placeholder="`${$t('count.value', { count: index + 1 })}`"
:name="'value' + index" :name="'value' + index"
/> />
@@ -74,28 +74,15 @@
</div> </div>
<div <div
v-if="vars.length === 0" v-if="vars.length === 0"
class=" class="text-secondaryLight flex flex-col items-center justify-center p-4"
flex flex-col
text-secondaryLight
p-4
items-center
justify-center
"
> >
<img <img
:src="`/images/states/${$colorMode.value}/blockchain.svg`" :src="`/images/states/${$colorMode.value}/blockchain.svg`"
loading="lazy" loading="lazy"
class=" class="inline-flex flex-col object-contain object-center w-16 h-16 my-4"
flex-col
my-4
object-contain object-center
h-16
w-16
inline-flex
"
:alt="$t('empty.environments')" :alt="$t('empty.environments')"
/> />
<span class="text-center pb-4"> <span class="pb-4 text-center">
{{ $t("empty.environments") }} {{ $t("empty.environments") }}
</span> </span>
<ButtonSecondary <ButtonSecondary
@@ -177,9 +164,7 @@ export default defineComponent({
clearContent() { clearContent() {
this.vars = [] this.vars = []
this.clearIcon = "check" this.clearIcon = "check"
this.$toast.success(`${this.$t("state.cleared")}`, { this.$toast.success(`${this.$t("state.cleared")}`)
icon: "clear_all",
})
setTimeout(() => (this.clearIcon = "trash-2"), 1000) setTimeout(() => (this.clearIcon = "trash-2"), 1000)
}, },
addEnvironmentVariable() { addEnvironmentVariable() {
@@ -193,9 +178,7 @@ export default defineComponent({
}, },
saveEnvironment() { saveEnvironment() {
if (!this.name) { if (!this.name) {
this.$toast.error(`${this.$t("environment.invalid_name")}`, { this.$toast.error(`${this.$t("environment.invalid_name")}`)
icon: "error_outline",
})
return return
} }

View File

@@ -1,21 +1,13 @@
<template> <template>
<div class="flex items-center group"> <div class="group flex items-center">
<span <span
class="cursor-pointer flex px-4 justify-center items-center" class="flex items-center justify-center px-4 cursor-pointer"
@click="$emit('edit-environment')" @click="$emit('edit-environment')"
> >
<SmartIcon class="svg-icons" name="layers" /> <SmartIcon class="svg-icons" name="layers" />
</span> </span>
<span <span
class=" class="group-hover:text-secondaryDark flex flex-1 min-w-0 py-2 pr-2 transition cursor-pointer"
cursor-pointer
flex flex-1
min-w-0
py-2
pr-2
transition
group-hover:text-secondaryDark
"
@click="$emit('edit-environment')" @click="$emit('edit-environment')"
> >
<span class="truncate"> <span class="truncate">
@@ -102,9 +94,7 @@ export default defineComponent({
removeEnvironment() { removeEnvironment() {
if (this.environmentIndex !== "Global") if (this.environmentIndex !== "Global")
deleteEnvironment(this.environmentIndex) deleteEnvironment(this.environmentIndex)
this.$toast.success(`${this.$t("state.deleted")}`, { this.$toast.success(`${this.$t("state.deleted")}`)
icon: "delete",
})
}, },
duplicateEnvironment() { duplicateEnvironment() {
if (this.environmentIndex === "Global") { if (this.environmentIndex === "Global") {

View File

@@ -140,15 +140,11 @@ export default defineComponent({
} }
) )
.then((res) => { .then((res) => {
this.$toast.success(this.$t("export.gist_created"), { this.$toast.success(this.$t("export.gist_created"))
icon: "done",
})
window.open(res.html_url) window.open(res.html_url)
}) })
.catch((e) => { .catch((e) => {
this.$toast.error(this.$t("error.something_went_wrong"), { this.$toast.error(this.$t("error.something_went_wrong"))
icon: "error_outline",
})
console.error(e) console.error(e)
}) })
}, },
@@ -230,18 +226,14 @@ export default defineComponent({
a.download = `${url.split("/").pop().split("#")[0].split("?")[0]}.json` a.download = `${url.split("/").pop().split("#")[0].split("?")[0]}.json`
document.body.appendChild(a) document.body.appendChild(a)
a.click() a.click()
this.$toast.success(this.$t("state.download_started"), { this.$toast.success(this.$t("state.download_started"))
icon: "downloading",
})
setTimeout(() => { setTimeout(() => {
document.body.removeChild(a) document.body.removeChild(a)
URL.revokeObjectURL(url) URL.revokeObjectURL(url)
}, 1000) }, 1000)
}, },
fileImported() { fileImported() {
this.$toast.success(this.$t("state.file_imported"), { this.$toast.success(this.$t("state.file_imported"))
icon: "folder_shared",
})
}, },
}, },
}) })

View File

@@ -1,27 +1,22 @@
<template> <template>
<AppSection :label="`${$t('environment.title')}`"> <AppSection :label="`${$t('environment.title')}`">
<div class="bg-primary rounded-t flex flex-col top-0 z-10 sticky"> <div class="bg-primary sticky top-0 z-10 flex flex-col rounded-t">
<tippy ref="options" interactive trigger="click" theme="popover" arrow> <tippy ref="options" interactive trigger="click" theme="popover" arrow>
<template #trigger> <template #trigger>
<span <span
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="`${$t('environment.select')}`" :title="`${$t('environment.select')}`"
class=" class="border-dividerLight select-wrapper flex-1 bg-transparent border-b"
bg-transparent
border-b border-dividerLight
flex-1
select-wrapper
"
> >
<ButtonSecondary <ButtonSecondary
v-if="selectedEnvironmentIndex !== -1" v-if="selectedEnvironmentIndex !== -1"
:label="environments[selectedEnvironmentIndex].name" :label="environments[selectedEnvironmentIndex].name"
class="rounded-none flex-1 pr-8" class="flex-1 pr-8 rounded-none"
/> />
<ButtonSecondary <ButtonSecondary
v-else v-else
:label="`${$t('environment.no_environment')}`" :label="`${$t('environment.no_environment')}`"
class="rounded-none flex-1 pr-8" class="flex-1 pr-8 rounded-none"
/> />
</span> </span>
</template> </template>
@@ -50,7 +45,7 @@
" "
/> />
</tippy> </tippy>
<div class="border-b border-dividerLight flex flex-1 justify-between"> <div class="border-dividerLight flex justify-between flex-1 border-b">
<ButtonSecondary <ButtonSecondary
svg="plus" svg="plus"
:label="`${$t('action.new')}`" :label="`${$t('action.new')}`"
@@ -91,7 +86,7 @@
<EnvironmentsEnvironment <EnvironmentsEnvironment
environment-index="Global" environment-index="Global"
:environment="globalEnvironment" :environment="globalEnvironment"
class="border-b border-dashed border-dividerLight" class="border-dividerLight border-b border-dashed"
@edit-environment="editEnvironment('Global')" @edit-environment="editEnvironment('Global')"
/> />
<EnvironmentsEnvironment <EnvironmentsEnvironment
@@ -104,15 +99,15 @@
</div> </div>
<div <div
v-if="environments.length === 0" v-if="environments.length === 0"
class="flex flex-col text-secondaryLight p-4 items-center justify-center" class="text-secondaryLight flex flex-col items-center justify-center p-4"
> >
<img <img
:src="`/images/states/${$colorMode.value}/blockchain.svg`" :src="`/images/states/${$colorMode.value}/blockchain.svg`"
loading="lazy" loading="lazy"
class="flex-col my-4 object-contain object-center h-16 w-16 inline-flex" class="inline-flex flex-col object-contain object-center w-16 h-16 my-4"
:alt="$t('empty.environments')" :alt="$t('empty.environments')"
/> />
<span class="text-center pb-4"> <span class="pb-4 text-center">
{{ $t("empty.environments") }} {{ $t("empty.environments") }}
</span> </span>
<ButtonSecondary <ButtonSecondary

View File

@@ -7,7 +7,7 @@
@close="hideModal" @close="hideModal"
> >
<template #body> <template #body>
<div v-if="mode === 'sign-in'" class="flex flex-col space-y-2 px-2"> <div v-if="mode === 'sign-in'" class="flex flex-col px-2 space-y-2">
<SmartItem <SmartItem
:loading="signingInWithGitHub" :loading="signingInWithGitHub"
svg="auth/github" svg="auth/github"
@@ -56,9 +56,9 @@
/> />
</form> </form>
<div v-if="mode === 'email-sent'" class="flex flex-col px-4"> <div v-if="mode === 'email-sent'" class="flex flex-col px-4">
<div class="flex flex-col max-w-md justify-center items-center"> <div class="flex flex-col items-center justify-center max-w-md">
<SmartIcon class="h-6 text-accent w-6" name="inbox" /> <SmartIcon class="text-accent w-6 h-6" name="inbox" />
<h3 class="my-2 text-center text-lg"> <h3 class="my-2 text-lg text-center">
{{ $t("auth.we_sent_magic_link") }} {{ $t("auth.we_sent_magic_link") }}
</h3> </h3>
<p class="text-center"> <p class="text-center">
@@ -95,7 +95,7 @@
</p> </p>
<p <p
v-if="mode === 'email-sent'" v-if="mode === 'email-sent'"
class="flex flex-1 text-secondaryLight justify-between" class="text-secondaryLight flex justify-between flex-1"
> >
<SmartAnchor <SmartAnchor
class="link" class="link"
@@ -155,9 +155,7 @@ export default defineComponent({
}, },
methods: { methods: {
showLoginSuccess() { showLoginSuccess() {
this.$toast.success(`${this.$t("auth.login_success")}`, { this.$toast.success(`${this.$t("auth.login_success")}`)
icon: "vpn_key",
})
}, },
async signInWithGoogle() { async signInWithGoogle() {
this.signingInWithGoogle = true this.signingInWithGoogle = true
@@ -174,7 +172,6 @@ export default defineComponent({
// The pending Google credential. // The pending Google credential.
const pendingCred = e.credential const pendingCred = e.credential
this.$toast.info(`${this.$t("auth.account_exists")}`, { this.$toast.info(`${this.$t("auth.account_exists")}`, {
icon: "vpn_key",
duration: 0, duration: 0,
closeOnSwipe: false, closeOnSwipe: false,
action: { action: {
@@ -190,9 +187,7 @@ export default defineComponent({
}, },
}) })
} else { } else {
this.$toast.error(`${this.$t("error.something_went_wrong")}`, { this.$toast.error(`${this.$t("error.something_went_wrong")}`)
icon: "error_outline",
})
} }
} }
@@ -218,7 +213,6 @@ export default defineComponent({
// The pending Google credential. // The pending Google credential.
const pendingCred = e.credential const pendingCred = e.credential
this.$toast.info(`${this.$t("auth.account_exists")}`, { this.$toast.info(`${this.$t("auth.account_exists")}`, {
icon: "vpn_key",
duration: 0, duration: 0,
closeOnSwipe: false, closeOnSwipe: false,
action: { action: {
@@ -234,9 +228,7 @@ export default defineComponent({
}, },
}) })
} else { } else {
this.$toast.error(`${this.$t("error.something_went_wrong")}`, { this.$toast.error(`${this.$t("error.something_went_wrong")}`)
icon: "error_outline",
})
} }
} }
@@ -256,9 +248,7 @@ export default defineComponent({
}) })
.catch((e) => { .catch((e) => {
console.error(e) console.error(e)
this.$toast.error(e.message, { this.$toast.error(e.message)
icon: "error_outline",
})
this.signingInWithEmail = false this.signingInWithEmail = false
}) })
.finally(() => { .finally(() => {

View File

@@ -40,14 +40,10 @@ export default defineComponent({
async logout() { async logout() {
try { try {
await signOutUser() await signOutUser()
this.$toast.success(`${this.$t("auth.logged_out")}`, { this.$toast.success(`${this.$t("auth.logged_out")}`)
icon: "vpn_key",
})
} catch (e) { } catch (e) {
console.error(e) console.error(e)
this.$toast.error(`${this.$t("error.something_went_wrong")}`, { this.$toast.error(`${this.$t("error.something_went_wrong")}`)
icon: "error_outline",
})
} }
}, },
}, },

View File

@@ -21,28 +21,19 @@
</div> </div>
<div <div
v-if="gqlField.description" v-if="gqlField.description"
class="text-secondaryLight py-2 field-desc" class="text-secondaryLight field-desc py-2"
> >
{{ gqlField.description }} {{ gqlField.description }}
</div> </div>
<div <div
v-if="gqlField.isDeprecated" v-if="gqlField.isDeprecated"
class=" class="field-deprecated inline-block px-2 py-1 my-1 text-black bg-yellow-200 rounded"
rounded
bg-yellow-200
my-1
text-black
py-1
px-2
inline-block
field-deprecated
"
> >
{{ $t("state.deprecated") }} {{ $t("state.deprecated") }}
</div> </div>
<div v-if="fieldArgs.length > 0"> <div v-if="fieldArgs.length > 0">
<h5 class="my-2">Arguments:</h5> <h5 class="my-2">Arguments:</h5>
<div class="border-divider border-l-2 pl-4"> <div class="border-divider pl-4 border-l-2">
<div v-for="(field, index) in fieldArgs" :key="`field-${index}`"> <div v-for="(field, index) in fieldArgs" :key="`field-${index}`">
<span> <span>
{{ field.name }}: {{ field.name }}:
@@ -53,7 +44,7 @@
</span> </span>
<div <div
v-if="field.description" v-if="field.description"
class="text-secondaryLight py-2 field-desc" class="text-secondaryLight field-desc py-2"
> >
{{ field.description }} {{ field.description }}
</div> </div>

View File

@@ -1,31 +1,21 @@
<template> <template>
<div class="bg-primary flex p-4 top-0 z-10 sticky"> <div class="bg-primary sticky top-0 z-10 flex p-4">
<div class="space-x-2 flex-1 inline-flex"> <div class="inline-flex flex-1 space-x-2">
<input <input
id="url" id="url"
v-model="url" v-model="url"
type="url" type="url"
autocomplete="off" autocomplete="off"
spellcheck="false" spellcheck="false"
class=" class="bg-primaryLight border-divider text-secondaryDark hover:border-dividerDark focus-visible:bg-transparent focus-visible:border-dividerDark w-full px-4 py-2 border rounded"
bg-primaryLight :placeholder="`${t('request.url')}`"
border border-divider
rounded
text-secondaryDark
w-full
py-2
px-4
hover:border-dividerDark
focus-visible:bg-transparent focus-visible:border-dividerDark
"
:placeholder="$t('request.url')"
:disabled="connected" :disabled="connected"
@keyup.enter="onConnectClick" @keyup.enter="onConnectClick"
/> />
<ButtonPrimary <ButtonPrimary
id="get" id="get"
name="get" name="get"
:label="!connected ? $t('action.connect') : $t('action.disconnect')" :label="!connected ? t('action.connect') : t('action.disconnect')"
class="w-32" class="w-32"
@click.native="onConnectClick" @click.native="onConnectClick"
/> />
@@ -37,9 +27,15 @@
import { logHoppRequestRunToAnalytics } from "~/helpers/fb/analytics" import { logHoppRequestRunToAnalytics } from "~/helpers/fb/analytics"
import { GQLConnection } from "~/helpers/GQLConnection" import { GQLConnection } from "~/helpers/GQLConnection"
import { getCurrentStrategyID } from "~/helpers/network" import { getCurrentStrategyID } from "~/helpers/network"
import { useReadonlyStream, useStream } from "~/helpers/utils/composables" import {
useReadonlyStream,
useStream,
useI18n,
} from "~/helpers/utils/composables"
import { gqlHeaders$, gqlURL$, setGQLURL } from "~/newstore/GQLSession" import { gqlHeaders$, gqlURL$, setGQLURL } from "~/newstore/GQLSession"
const t = useI18n()
const props = defineProps<{ const props = defineProps<{
conn: GQLConnection conn: GQLConnection
}>() }>()

View File

@@ -3,55 +3,44 @@
<SmartTabs styles="sticky bg-primary top-upperPrimaryStickyFold z-10"> <SmartTabs styles="sticky bg-primary top-upperPrimaryStickyFold z-10">
<template #actions> <template #actions>
<ButtonSecondary <ButtonSecondary
:label="`${$t('request.run')}`" :label="`${t('request.run')}`"
svg="play" svg="play"
class="rounded-none !text-accent" class="rounded-none !text-accent"
@click.native="runQuery()" @click.native="runQuery()"
/> />
<ButtonSecondary <ButtonSecondary
ref="saveRequest" ref="saveRequest"
:label="`${$t('request.save')}`" :label="`${t('request.save')}`"
class="rounded-none" class="rounded-none"
@click.native="saveRequest" @click.native="saveRequest"
/> />
</template> </template>
<SmartTab :id="'query'" :label="`${$t('tab.query')}`" :selected="true"> <SmartTab :id="'query'" :label="`${t('tab.query')}`" :selected="true">
<AppSection label="query"> <AppSection label="query">
<div <div
class=" class="bg-primary border-dividerLight top-upperSecondaryStickyFold gqlRunQuery sticky z-10 flex items-center justify-between flex-1 pl-4 border-b"
bg-primary
border-b border-dividerLight
flex flex-1
top-upperSecondaryStickyFold
pl-4
z-10
sticky
items-center
justify-between
gqlRunQuery
"
> >
<label class="font-semibold text-secondaryLight"> <label class="text-secondaryLight font-semibold">
{{ $t("request.query") }} {{ t("request.query") }}
</label> </label>
<div class="flex"> <div class="flex">
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
to="https://docs.hoppscotch.io" to="https://docs.hoppscotch.io/graphql/#queries"
blank blank
:title="$t('app.wiki')" :title="t('app.wiki')"
svg="help-circle" svg="help-circle"
/> />
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('action.prettify')" :title="t('action.prettify')"
:svg="`${prettifyQueryIcon}`" :svg="`${prettifyQueryIcon}`"
@click.native="prettifyQuery" @click.native="prettifyQuery"
/> />
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('action.copy')" :title="t('action.copy')"
:svg="`${copyQueryIcon}`" :svg="`${copyQueryIcon}`"
@click.native="copyQuery" @click.native="copyQuery"
/> />
@@ -61,35 +50,25 @@
</AppSection> </AppSection>
</SmartTab> </SmartTab>
<SmartTab :id="'variables'" :label="`${$t('tab.variables')}`"> <SmartTab :id="'variables'" :label="`${t('tab.variables')}`">
<AppSection label="variables"> <AppSection label="variables">
<div <div
class=" class="bg-primary border-dividerLight top-upperSecondaryStickyFold sticky z-10 flex items-center justify-between flex-1 pl-4 border-b"
bg-primary
border-b border-dividerLight
flex flex-1
top-upperSecondaryStickyFold
pl-4
z-10
sticky
items-center
justify-between
"
> >
<label class="font-semibold text-secondaryLight"> <label class="text-secondaryLight font-semibold">
{{ $t("request.variables") }} {{ t("request.variables") }}
</label> </label>
<div class="flex"> <div class="flex">
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
to="https://docs.hoppscotch.io" to="https://docs.hoppscotch.io/graphql/#queries"
blank blank
:title="$t('app.wiki')" :title="t('app.wiki')"
svg="help-circle" svg="help-circle"
/> />
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('action.copy')" :title="t('action.copy')"
:svg="`${copyVariablesIcon}`" :svg="`${copyVariablesIcon}`"
@click.native="copyVariables" @click.native="copyVariables"
/> />
@@ -99,48 +78,38 @@
</AppSection> </AppSection>
</SmartTab> </SmartTab>
<SmartTab :id="'headers'" :label="`${$t('tab.headers')}`"> <SmartTab :id="'headers'" :label="`${t('tab.headers')}`">
<AppSection label="headers"> <AppSection label="headers">
<div <div
class=" class="bg-primary border-dividerLight top-upperSecondaryStickyFold sticky z-10 flex items-center justify-between flex-1 pl-4 border-b"
bg-primary
border-b border-dividerLight
flex flex-1
top-upperSecondaryStickyFold
pl-4
z-10
sticky
items-center
justify-between
"
> >
<label class="font-semibold text-secondaryLight"> <label class="text-secondaryLight font-semibold">
{{ $t("tab.headers") }} {{ t("tab.headers") }}
</label> </label>
<div class="flex"> <div class="flex">
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
to="https://docs.hoppscotch.io" to="https://docs.hoppscotch.io/graphql/#headers"
blank blank
:title="$t('app.wiki')" :title="t('app.wiki')"
svg="help-circle" svg="help-circle"
/> />
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('action.clear_all')" :title="t('action.clear_all')"
svg="trash-2" svg="trash-2"
@click.native="bulkMode ? clearBulkEditor() : clearContent()" @click.native="clearContent()"
/> />
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('state.bulk_mode')" :title="t('state.bulk_mode')"
svg="edit" svg="edit"
:class="{ '!text-accent': bulkMode }" :class="{ '!text-accent': bulkMode }"
@click.native="bulkMode = !bulkMode" @click.native="bulkMode = !bulkMode"
/> />
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('add.new')" :title="t('add.new')"
svg="plus" svg="plus"
:disabled="bulkMode" :disabled="bulkMode"
@click.native="addRequestHeader" @click.native="addRequestHeader"
@@ -152,14 +121,10 @@
<div <div
v-for="(header, index) in headers" v-for="(header, index) in headers"
:key="`header-${String(index)}`" :key="`header-${String(index)}`"
class=" class="divide-dividerLight border-dividerLight flex border-b divide-x"
divide-x divide-dividerLight
border-b border-dividerLight
flex
"
> >
<SmartAutoComplete <SmartAutoComplete
:placeholder="`${$t('count.header', { count: index + 1 })}`" :placeholder="`${t('count.header', { count: index + 1 })}`"
:source="commonHeaders" :source="commonHeaders"
:spellcheck="false" :spellcheck="false"
:value="header.key" :value="header.key"
@@ -182,8 +147,8 @@
" "
/> />
<input <input
class="bg-transparent flex flex-1 py-2 px-4" class="flex flex-1 px-4 py-2 bg-transparent"
:placeholder="`${$t('count.value', { count: index + 1 })}`" :placeholder="`${t('count.value', { count: index + 1 })}`"
:name="`value ${String(index)}`" :name="`value ${String(index)}`"
:value="header.value" :value="header.value"
autofocus autofocus
@@ -201,9 +166,9 @@
:title=" :title="
header.hasOwnProperty('active') header.hasOwnProperty('active')
? header.active ? header.active
? $t('action.turn_off') ? t('action.turn_off')
: $t('action.turn_on') : t('action.turn_on')
: $t('action.turn_off') : t('action.turn_off')
" "
:svg=" :svg="
header.hasOwnProperty('active') header.hasOwnProperty('active')
@@ -225,7 +190,7 @@
<span> <span>
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('action.remove')" :title="t('action.remove')"
svg="trash" svg="trash"
color="red" color="red"
@click.native="removeRequestHeader(index)" @click.native="removeRequestHeader(index)"
@@ -234,32 +199,19 @@
</div> </div>
<div <div
v-if="headers.length === 0" v-if="headers.length === 0"
class=" class="text-secondaryLight flex flex-col items-center justify-center p-4"
flex flex-col
text-secondaryLight
p-4
items-center
justify-center
"
> >
<img <img
:src="`/images/states/${$colorMode.value}/add_category.svg`" :src="`/images/states/${$colorMode.value}/add_category.svg`"
loading="lazy" loading="lazy"
class=" class="inline-flex flex-col object-contain object-center w-16 h-16 my-4"
flex-col :alt="`${t('empty.headers')}`"
my-4
object-contain object-center
h-16
w-16
inline-flex
"
:alt="$t('empty.headers')"
/> />
<span class="text-center pb-4"> <span class="pb-4 text-center">
{{ $t("empty.headers") }} {{ t("empty.headers") }}
</span> </span>
<ButtonSecondary <ButtonSecondary
:label="`${$t('add.new')}`" :label="`${t('add.new')}`"
filled filled
svg="plus" svg="plus"
class="mb-4" class="mb-4"
@@ -280,7 +232,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, ref, useContext, watch } from "@nuxtjs/composition-api" import { onMounted, ref, watch } from "@nuxtjs/composition-api"
import clone from "lodash/clone" import clone from "lodash/clone"
import * as gql from "graphql" import * as gql from "graphql"
import { copyToClipboard } from "~/helpers/utils/clipboard" import { copyToClipboard } from "~/helpers/utils/clipboard"
@@ -288,6 +240,8 @@ import {
useNuxt, useNuxt,
useReadonlyStream, useReadonlyStream,
useStream, useStream,
useI18n,
useToast,
} from "~/helpers/utils/composables" } from "~/helpers/utils/composables"
import { import {
addGQLHeader, addGQLHeader,
@@ -314,15 +268,14 @@ import jsonLinter from "~/helpers/editor/linting/json"
import { createGQLQueryLinter } from "~/helpers/editor/linting/gqlQuery" import { createGQLQueryLinter } from "~/helpers/editor/linting/gqlQuery"
import queryCompleter from "~/helpers/editor/completion/gqlQuery" import queryCompleter from "~/helpers/editor/completion/gqlQuery"
const t = useI18n()
const props = defineProps<{ const props = defineProps<{
conn: GQLConnection conn: GQLConnection
}>() }>()
const { const toast = useToast()
$toast,
app: { i18n },
} = useContext()
const t = i18n.t.bind(i18n)
const nuxt = useNuxt() const nuxt = useNuxt()
const bulkMode = ref(false) const bulkMode = ref(false)
@@ -335,11 +288,9 @@ watch(bulkHeaders, () => {
value: item.substring(item.indexOf(":") + 1).trim(), value: item.substring(item.indexOf(":") + 1).trim(),
active: !item.trim().startsWith("//"), active: !item.trim().startsWith("//"),
})) }))
setGQLHeaders(transformation) setGQLHeaders(transformation as GQLHeader[])
} catch (e) { } catch (e) {
$toast.error(`${t("error.something_went_wrong")}`, { toast.error(`${t("error.something_went_wrong")}`)
icon: "error_outline",
})
console.error(e) console.error(e)
} }
}) })
@@ -392,12 +343,13 @@ const showSaveRequestModal = ref(false)
watch( watch(
headers, headers,
() => { () => {
if ( if (!bulkMode.value)
(headers.value[headers.value.length - 1]?.key !== "" || if (
headers.value[headers.value.length - 1]?.value !== "") && (headers.value[headers.value.length - 1]?.key !== "" ||
headers.value.length headers.value[headers.value.length - 1]?.value !== "") &&
) headers.value.length
addRequestHeader() )
addRequestHeader()
}, },
{ deep: true } { deep: true }
) )
@@ -427,6 +379,7 @@ onMounted(() => {
const copyQuery = () => { const copyQuery = () => {
copyToClipboard(gqlQueryString.value) copyToClipboard(gqlQueryString.value)
copyQueryIcon.value = "check" copyQueryIcon.value = "check"
toast.success(`${t("state.copied_to_clipboard")}`)
setTimeout(() => (copyQueryIcon.value = "copy"), 1000) setTimeout(() => (copyQueryIcon.value = "copy"), 1000)
} }
@@ -470,18 +423,14 @@ const runQuery = async () => {
}) })
) )
$toast.success(`${t("state.finished_in", { duration })}`, { toast.success(`${t("state.finished_in", { duration })}`)
icon: "done",
})
} catch (e: any) { } catch (e: any) {
response.value = `${e}` response.value = `${e}`
nuxt.value.$loading.finish() nuxt.value.$loading.finish()
$toast.error( toast.error(
`${t("error.something_went_wrong")}. ${t("error.check_console_details")}`, `${t("error.something_went_wrong")}. ${t("error.check_console_details")}`,
{ {}
icon: "error_outline",
}
) )
console.error(e) console.error(e)
} }
@@ -499,12 +448,11 @@ const hideRequestModal = () => {
const prettifyQuery = () => { const prettifyQuery = () => {
try { try {
gqlQueryString.value = gql.print(gql.parse(gqlQueryString.value)) gqlQueryString.value = gql.print(gql.parse(gqlQueryString.value))
prettifyQueryIcon.value = "check"
} catch (e) { } catch (e) {
$toast.error(`${t("error.gql_prettify_invalid_query")}`, { toast.error(`${t("error.gql_prettify_invalid_query")}`)
icon: "error_outline", prettifyQueryIcon.value = "info"
})
} }
prettifyQueryIcon.value = "check"
setTimeout(() => (prettifyQueryIcon.value = "wand"), 1000) setTimeout(() => (prettifyQueryIcon.value = "wand"), 1000)
} }
@@ -515,6 +463,7 @@ const saveRequest = () => {
const copyVariables = () => { const copyVariables = () => {
copyToClipboard(variableString.value) copyToClipboard(variableString.value)
copyVariablesIcon.value = "check" copyVariablesIcon.value = "check"
toast.success(`${t("state.copied_to_clipboard")}`)
setTimeout(() => (copyVariablesIcon.value = "copy"), 1000) setTimeout(() => (copyVariablesIcon.value = "copy"), 1000)
} }
@@ -542,11 +491,10 @@ const removeRequestHeader = (index: number) => {
const deletedItem = headersBeforeDeletion[index] const deletedItem = headersBeforeDeletion[index]
if (deletedItem.key || deletedItem.value) { if (deletedItem.key || deletedItem.value) {
$toast.success(t("state.deleted").toString(), { toast.success(`${t("state.deleted")}`, {
icon: "delete",
action: [ action: [
{ {
text: t("action.undo").toString(), text: `${t("action.undo")}`,
onClick: (_, toastObject) => { onClick: (_, toastObject) => {
setGQLHeaders(headersBeforeDeletion as GQLHeader[]) setGQLHeaders(headersBeforeDeletion as GQLHeader[])
editBulkHeadersLine(index, deletedItem) editBulkHeadersLine(index, deletedItem)

View File

@@ -2,32 +2,22 @@
<AppSection ref="response" label="response"> <AppSection ref="response" label="response">
<div <div
v-if="responseString === 'loading'" v-if="responseString === 'loading'"
class="flex flex-col p-4 items-center justify-center" class="flex flex-col items-center justify-center p-4"
> >
<SmartSpinner class="my-4" /> <SmartSpinner class="my-4" />
<span class="text-secondaryLight">{{ $t("state.loading") }}</span> <span class="text-secondaryLight">{{ t("state.loading") }}</span>
</div> </div>
<div v-else-if="responseString"> <div v-else-if="responseString">
<div <div
class=" class="bg-primary border-dividerLight sticky top-0 z-10 flex items-center justify-between flex-1 pl-4 border-b"
bg-primary
border-b border-dividerLight
flex flex-1
pl-4
top-0
z-10
sticky
items-center
justify-between
"
> >
<label class="font-semibold text-secondaryLight"> <label class="text-secondaryLight font-semibold">
{{ $t("response.title") }} {{ t("response.title") }}
</label> </label>
<div class="flex"> <div class="flex">
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('state.linewrap')" :title="t('state.linewrap')"
:class="{ '!text-accent': linewrapEnabled }" :class="{ '!text-accent': linewrapEnabled }"
svg="corner-down-left" svg="corner-down-left"
@click.native.prevent="linewrapEnabled = !linewrapEnabled" @click.native.prevent="linewrapEnabled = !linewrapEnabled"
@@ -35,14 +25,14 @@
<ButtonSecondary <ButtonSecondary
ref="downloadResponse" ref="downloadResponse"
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('action.download_file')" :title="t('action.download_file')"
:svg="downloadResponseIcon" :svg="downloadResponseIcon"
@click.native="downloadResponse" @click.native="downloadResponse"
/> />
<ButtonSecondary <ButtonSecondary
ref="copyResponseButton" ref="copyResponseButton"
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('action.copy')" :title="t('action.copy')"
:svg="copyResponseIcon" :svg="copyResponseIcon"
@click.native="copyResponse" @click.native="copyResponse"
/> />
@@ -52,21 +42,15 @@
</div> </div>
<div <div
v-else v-else
class=" class="text-secondaryLight flex flex-col items-center justify-center flex-1 p-4"
flex flex-col flex-1
text-secondaryLight
p-4
items-center
justify-center
"
> >
<div class="flex space-x-2 pb-4 my-4"> <div class="flex pb-4 my-4 space-x-2">
<div class="flex flex-col space-y-4 text-right items-end"> <div class="flex flex-col items-end space-y-4 text-right">
<span class="flex flex-1 items-center"> <span class="flex items-center flex-1">
{{ $t("shortcut.general.command_menu") }} {{ t("shortcut.general.command_menu") }}
</span> </span>
<span class="flex flex-1 items-center"> <span class="flex items-center flex-1">
{{ $t("shortcut.general.help_menu") }} {{ t("shortcut.general.help_menu") }}
</span> </span>
</div> </div>
<div class="flex flex-col space-y-4"> <div class="flex flex-col space-y-4">
@@ -79,8 +63,8 @@
</div> </div>
</div> </div>
<ButtonSecondary <ButtonSecondary
:label="`${$t('app.documentation')}`" :label="`${t('app.documentation')}`"
to="https://docs.hoppscotch.io" to="https://docs.hoppscotch.io/features/response"
svg="external-link" svg="external-link"
blank blank
outline outline
@@ -91,17 +75,19 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { reactive, ref, useContext } from "@nuxtjs/composition-api" import { reactive, ref } from "@nuxtjs/composition-api"
import { useCodemirror } from "~/helpers/editor/codemirror" import { useCodemirror } from "~/helpers/editor/codemirror"
import { copyToClipboard } from "~/helpers/utils/clipboard" import { copyToClipboard } from "~/helpers/utils/clipboard"
import { useReadonlyStream } from "~/helpers/utils/composables" import {
useReadonlyStream,
useI18n,
useToast,
} from "~/helpers/utils/composables"
import { gqlResponse$ } from "~/newstore/GQLSession" import { gqlResponse$ } from "~/newstore/GQLSession"
const { const t = useI18n()
$toast,
app: { i18n }, const toast = useToast()
} = useContext()
const t = i18n.t.bind(i18n)
const responseString = useReadonlyStream(gqlResponse$, "") const responseString = useReadonlyStream(gqlResponse$, "")
@@ -128,6 +114,7 @@ const copyResponseIcon = ref("copy")
const copyResponse = () => { const copyResponse = () => {
copyToClipboard(responseString.value!) copyToClipboard(responseString.value!)
copyResponseIcon.value = "check" copyResponseIcon.value = "check"
toast.success(`${t("state.copied_to_clipboard")}`)
setTimeout(() => (copyResponseIcon.value = "copy"), 1000) setTimeout(() => (copyResponseIcon.value = "copy"), 1000)
} }
@@ -141,9 +128,7 @@ const downloadResponse = () => {
document.body.appendChild(a) document.body.appendChild(a)
a.click() a.click()
downloadResponseIcon.value = "check" downloadResponseIcon.value = "check"
$toast.success(`${t("state.download_started")}`, { toast.success(`${t("state.download_started")}`)
icon: "downloading",
})
setTimeout(() => { setTimeout(() => {
document.body.removeChild(a) document.body.removeChild(a)
URL.revokeObjectURL(url) URL.revokeObjectURL(url)

View File

@@ -3,7 +3,7 @@
<SmartTab <SmartTab
:id="'history'" :id="'history'"
icon="clock" icon="clock"
:label="`${$t('tab.history')}`" :label="`${t('tab.history')}`"
:selected="true" :selected="true"
> >
<History <History
@@ -16,7 +16,7 @@
<SmartTab <SmartTab
:id="'collections'" :id="'collections'"
icon="folder" icon="folder"
:label="`${$t('tab.collections')}`" :label="`${t('tab.collections')}`"
> >
<CollectionsGraphql /> <CollectionsGraphql />
</SmartTab> </SmartTab>
@@ -24,7 +24,7 @@
<SmartTab <SmartTab
:id="'docs'" :id="'docs'"
icon="book-open" icon="book-open"
:label="`${$t('tab.documentation')}`" :label="`${t('tab.documentation')}`"
> >
<AppSection label="docs"> <AppSection label="docs">
<div <div
@@ -34,46 +34,33 @@
subscriptionFields.length === 0 && subscriptionFields.length === 0 &&
graphqlTypes.length === 0 graphqlTypes.length === 0
" "
class=" class="text-secondaryLight flex flex-col items-center justify-center p-4"
flex flex-col
text-secondaryLight
p-4
items-center
justify-center
"
> >
<img <img
:src="`/images/states/${$colorMode.value}/add_comment.svg`" :src="`/images/states/${$colorMode.value}/add_comment.svg`"
loading="lazy" loading="lazy"
class=" class="inline-flex flex-col object-contain object-center w-16 h-16 my-4"
flex-col :alt="`${t('empty.documentation')}`"
my-4
object-contain object-center
h-16
w-16
inline-flex
"
:alt="$t('empty.documentation')"
/> />
<span class="text-center mb-4"> <span class="mb-4 text-center">
{{ $t("empty.documentation") }} {{ t("empty.documentation") }}
</span> </span>
</div> </div>
<div v-else> <div v-else>
<div class="bg-primary flex top-0 z-10 sticky"> <div class="bg-primary sticky top-0 z-10 flex">
<input <input
v-model="graphqlFieldsFilterText" v-model="graphqlFieldsFilterText"
type="search" type="search"
autocomplete="off" autocomplete="off"
:placeholder="`${$t('action.search')}`" :placeholder="`${t('action.search')}`"
class="bg-transparent flex w-full p-4 py-2" class="flex w-full p-4 py-2 bg-transparent"
/> />
<div class="flex"> <div class="flex">
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
to="https://docs.hoppscotch.io/quickstart/graphql" to="https://docs.hoppscotch.io/quickstart/graphql"
blank blank
:title="$t('app.wiki')" :title="t('app.wiki')"
svg="help-circle" svg="help-circle"
/> />
</div> </div>
@@ -86,9 +73,9 @@
<SmartTab <SmartTab
v-if="queryFields.length > 0" v-if="queryFields.length > 0"
:id="'queries'" :id="'queries'"
:label="`${$t('tab.queries')}`" :label="`${t('tab.queries')}`"
:selected="true" :selected="true"
class="divide-y divide-dividerLight" class="divide-dividerLight divide-y"
> >
<GraphqlField <GraphqlField
v-for="(field, index) in filteredQueryFields" v-for="(field, index) in filteredQueryFields"
@@ -101,8 +88,8 @@
<SmartTab <SmartTab
v-if="mutationFields.length > 0" v-if="mutationFields.length > 0"
:id="'mutations'" :id="'mutations'"
:label="`${$t('graphql.mutations')}`" :label="`${t('graphql.mutations')}`"
class="divide-y divide-dividerLight" class="divide-dividerLight divide-y"
> >
<GraphqlField <GraphqlField
v-for="(field, index) in filteredMutationFields" v-for="(field, index) in filteredMutationFields"
@@ -115,8 +102,8 @@
<SmartTab <SmartTab
v-if="subscriptionFields.length > 0" v-if="subscriptionFields.length > 0"
:id="'subscriptions'" :id="'subscriptions'"
:label="`${$t('graphql.subscriptions')}`" :label="`${t('graphql.subscriptions')}`"
class="divide-y divide-dividerLight" class="divide-dividerLight divide-y"
> >
<GraphqlField <GraphqlField
v-for="(field, index) in filteredSubscriptionFields" v-for="(field, index) in filteredSubscriptionFields"
@@ -130,8 +117,8 @@
v-if="graphqlTypes.length > 0" v-if="graphqlTypes.length > 0"
:id="'types'" :id="'types'"
ref="typesTab" ref="typesTab"
:label="`${$t('tab.types')}`" :label="`${t('tab.types')}`"
class="divide-y divide-dividerLight" class="divide-dividerLight divide-y"
> >
<GraphqlType <GraphqlType
v-for="(type, index) in filteredGraphqlTypes" v-for="(type, index) in filteredGraphqlTypes"
@@ -149,36 +136,26 @@
</AppSection> </AppSection>
</SmartTab> </SmartTab>
<SmartTab :id="'schema'" icon="box" :label="`${$t('tab.schema')}`"> <SmartTab :id="'schema'" icon="box" :label="`${t('tab.schema')}`">
<AppSection ref="schema" label="schema"> <AppSection ref="schema" label="schema">
<div <div
v-if="schemaString" v-if="schemaString"
class=" class="bg-primary border-dividerLight sticky top-0 z-10 flex items-center justify-between flex-1 pl-4 border-b"
bg-primary
flex flex-1
top-0
pl-4
z-10
sticky
items-center
justify-between
border-b border-dividerLight
"
> >
<label class="font-semibold text-secondaryLight"> <label class="text-secondaryLight font-semibold">
{{ $t("graphql.schema") }} {{ t("graphql.schema") }}
</label> </label>
<div class="flex"> <div class="flex">
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
to="https://docs.hoppscotch.io/quickstart/graphql" to="https://docs.hoppscotch.io/quickstart/graphql"
blank blank
:title="$t('app.wiki')" :title="t('app.wiki')"
svg="help-circle" svg="help-circle"
/> />
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('state.linewrap')" :title="t('state.linewrap')"
:class="{ '!text-accent': linewrapEnabled }" :class="{ '!text-accent': linewrapEnabled }"
svg="corner-down-left" svg="corner-down-left"
@click.native.prevent="linewrapEnabled = !linewrapEnabled" @click.native.prevent="linewrapEnabled = !linewrapEnabled"
@@ -186,14 +163,14 @@
<ButtonSecondary <ButtonSecondary
ref="downloadSchema" ref="downloadSchema"
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('action.download_file')" :title="t('action.download_file')"
:svg="downloadSchemaIcon" :svg="downloadSchemaIcon"
@click.native="downloadSchema" @click.native="downloadSchema"
/> />
<ButtonSecondary <ButtonSecondary
ref="copySchemaCode" ref="copySchemaCode"
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('action.copy')" :title="t('action.copy')"
:svg="copySchemaIcon" :svg="copySchemaIcon"
@click.native="copySchema" @click.native="copySchema"
/> />
@@ -202,29 +179,16 @@
<div v-if="schemaString" ref="schemaEditor"></div> <div v-if="schemaString" ref="schemaEditor"></div>
<div <div
v-else v-else
class=" class="text-secondaryLight flex flex-col items-center justify-center p-4"
flex flex-col
text-secondaryLight
p-4
items-center
justify-center
"
> >
<img <img
:src="`/images/states/${$colorMode.value}/blockchain.svg`" :src="`/images/states/${$colorMode.value}/blockchain.svg`"
loading="lazy" loading="lazy"
class=" class="inline-flex flex-col object-contain object-center w-16 h-16 my-4"
flex-col :alt="`${t('empty.schema')}`"
my-4
object-contain object-center
h-16
w-16
inline-flex
"
:alt="$t('empty.schema')"
/> />
<span class="text-center mb-4"> <span class="mb-4 text-center">
{{ $t("empty.schema") }} {{ t("empty.schema") }}
</span> </span>
</div> </div>
</AppSection> </AppSection>
@@ -233,20 +197,18 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { import { computed, nextTick, reactive, ref } from "@nuxtjs/composition-api"
computed,
nextTick,
reactive,
ref,
useContext,
} from "@nuxtjs/composition-api"
import { GraphQLField, GraphQLType } from "graphql" import { GraphQLField, GraphQLType } from "graphql"
import { map } from "rxjs/operators" import { map } from "rxjs/operators"
import { useCodemirror } from "~/helpers/editor/codemirror" import { useCodemirror } from "~/helpers/editor/codemirror"
import { GQLConnection } from "~/helpers/GQLConnection" import { GQLConnection } from "~/helpers/GQLConnection"
import { GQLHeader } from "~/helpers/types/HoppGQLRequest" import { GQLHeader } from "~/helpers/types/HoppGQLRequest"
import { copyToClipboard } from "~/helpers/utils/clipboard" import { copyToClipboard } from "~/helpers/utils/clipboard"
import { useReadonlyStream } from "~/helpers/utils/composables" import {
useReadonlyStream,
useI18n,
useToast,
} from "~/helpers/utils/composables"
import { import {
setGQLHeaders, setGQLHeaders,
setGQLQuery, setGQLQuery,
@@ -255,6 +217,8 @@ import {
setGQLVariables, setGQLVariables,
} from "~/newstore/GQLSession" } from "~/newstore/GQLSession"
const t = useI18n()
function isTextFoundInGraphqlFieldObject( function isTextFoundInGraphqlFieldObject(
text: string, text: string,
field: GraphQLField<any, any> field: GraphQLField<any, any>
@@ -321,11 +285,7 @@ const props = defineProps<{
conn: GQLConnection conn: GQLConnection
}>() }>()
const { const toast = useToast()
$toast,
app: { i18n },
} = useContext()
const t = i18n.t.bind(i18n)
const queryFields = useReadonlyStream( const queryFields = useReadonlyStream(
props.conn.queryFields$.pipe(map((x) => x ?? [])), props.conn.queryFields$.pipe(map((x) => x ?? [])),
@@ -408,12 +368,25 @@ const handleJumpToType = async (type: GraphQLType) => {
await nextTick() await nextTick()
const rootTypeName = resolveRootType(type).name const rootTypeName = resolveRootType(type).name
const target = document.getElementById(`type_${rootTypeName}`) const target = document.getElementById(`type_${rootTypeName}`)
if (target) { if (target) {
gqlTabs.value.$el target.scrollIntoView({ block: "center", behavior: "smooth" })
.querySelector(".gqlTabs") target.classList.add(
.scrollTo({ top: target.offsetTop, behavior: "smooth" }) "transition-all",
"ring-inset",
"ring-accentLight",
"ring-4"
)
setTimeout(
() =>
target.classList.remove(
"ring-inset",
"ring-accentLight",
"ring-4",
"transition-all"
),
2000
)
} }
} }
@@ -449,9 +422,7 @@ const downloadSchema = () => {
document.body.appendChild(a) document.body.appendChild(a)
a.click() a.click()
downloadSchemaIcon.value = "check" downloadSchemaIcon.value = "check"
$toast.success(`${t("state.download_started")}`, { toast.success(`${t("state.download_started")}`)
icon: "downloading",
})
setTimeout(() => { setTimeout(() => {
document.body.removeChild(a) document.body.removeChild(a)
URL.revokeObjectURL(url) URL.revokeObjectURL(url)

View File

@@ -6,7 +6,7 @@
<span v-else-if="isEnum" class="text-accent">enum </span> <span v-else-if="isEnum" class="text-accent">enum </span>
{{ gqlType.name }} {{ gqlType.name }}
</div> </div>
<div v-if="gqlType.description" class="text-secondaryLight py-2 type-desc"> <div v-if="gqlType.description" class="py-2 text-secondaryLight type-desc">
{{ gqlType.description }} {{ gqlType.description }}
</div> </div>
<div v-if="interfaces.length > 0"> <div v-if="interfaces.length > 0">
@@ -18,7 +18,7 @@
<GraphqlTypeLink <GraphqlTypeLink
:gql-type="gqlInterface" :gql-type="gqlInterface"
:jump-type-callback="jumpTypeCallback" :jump-type-callback="jumpTypeCallback"
class="border-divider border-l-2 pl-4" class="pl-4 border-l-2 border-divider"
/> />
</div> </div>
</div> </div>
@@ -29,7 +29,7 @@
:key="`child-${index}`" :key="`child-${index}`"
:gql-type="child" :gql-type="child"
:jump-type-callback="jumpTypeCallback" :jump-type-callback="jumpTypeCallback"
class="border-divider border-l-2 pl-4" class="pl-4 border-l-2 border-divider"
/> />
</div> </div>
<div v-if="gqlType.getFields"> <div v-if="gqlType.getFields">
@@ -37,7 +37,7 @@
<GraphqlField <GraphqlField
v-for="(field, index) in gqlType.getFields()" v-for="(field, index) in gqlType.getFields()"
:key="`field-${index}`" :key="`field-${index}`"
class="border-divider border-l-2 pl-4" class="pl-4 border-l-2 border-divider"
:gql-field="field" :gql-field="field"
:is-highlighted="isFieldHighlighted({ field })" :is-highlighted="isFieldHighlighted({ field })"
:jump-type-callback="jumpTypeCallback" :jump-type-callback="jumpTypeCallback"
@@ -48,7 +48,7 @@
<div <div
v-for="(value, index) in gqlType.getValues()" v-for="(value, index) in gqlType.getValues()"
:key="`value-${index}`" :key="`value-${index}`"
class="border-divider border-l-2 pl-4" class="pl-4 border-l-2 border-divider"
v-text="value.name" v-text="value.name"
></div> ></div>
</div> </div>

View File

@@ -1,17 +1,8 @@
<template> <template>
<div class="flex flex-col group"> <div class="group flex flex-col">
<div class="flex items-center"> <div class="flex items-center">
<span <span
class=" class="group-hover:text-secondaryDark flex flex-1 min-w-0 py-2 pl-4 pr-2 transition cursor-pointer"
cursor-pointer
flex flex-1
min-w-0
py-2
pr-2
pl-4
transition
group-hover:text-secondaryDark
"
data-testid="restore_history_entry" data-testid="restore_history_entry"
@click="useEntry" @click="useEntry"
> >
@@ -24,7 +15,7 @@
svg="trash" svg="trash"
color="red" color="red"
:title="$t('action.remove')" :title="$t('action.remove')"
class="hidden group-hover:inline-flex" class="group-hover:inline-flex hidden"
data-testid="delete_history_entry" data-testid="delete_history_entry"
@click.native="$emit('delete-entry')" @click.native="$emit('delete-entry')"
/> />
@@ -32,7 +23,7 @@
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="expand ? $t('hide.more') : $t('show.more')" :title="expand ? $t('hide.more') : $t('show.more')"
:svg="expand ? 'minimize-2' : 'maximize-2'" :svg="expand ? 'minimize-2' : 'maximize-2'"
class="hidden group-hover:inline-flex" class="group-hover:inline-flex hidden"
@click.native="expand = !expand" @click.native="expand = !expand"
/> />
<ButtonSecondary <ButtonSecondary
@@ -49,7 +40,7 @@
<span <span
v-for="(line, index) in query" v-for="(line, index) in query"
:key="`line-${index}`" :key="`line-${index}`"
class="cursor-pointer text-secondaryLight px-4 whitespace-pre truncate" class="text-secondaryLight px-4 truncate whitespace-pre cursor-pointer"
data-testid="restore_history_entry" data-testid="restore_history_entry"
@click="useEntry" @click="useEntry"
>{{ line }}</span >{{ line }}</span

View File

@@ -1,11 +1,11 @@
<template> <template>
<AppSection label="history"> <AppSection label="history">
<div class="bg-primary border-b border-dividerLight flex top-0 z-10 sticky"> <div class="sticky top-0 z-10 flex border-b bg-primary border-dividerLight">
<input <input
v-model="filterText" v-model="filterText"
type="search" type="search"
autocomplete="off" autocomplete="off"
class="bg-transparent flex w-full p-4 py-2" class="flex w-full p-4 py-2 bg-transparent"
:placeholder="`${$t('action.search')}`" :placeholder="`${$t('action.search')}`"
/> />
<div class="flex"> <div class="flex">
@@ -49,24 +49,24 @@
</div> </div>
<div <div
v-if="!(filteredHistory.length !== 0 || history.length === 0)" v-if="!(filteredHistory.length !== 0 || history.length === 0)"
class="flex flex-col text-secondaryLight p-4 items-center justify-center" class="flex flex-col items-center justify-center p-4 text-secondaryLight"
> >
<i class="opacity-75 pb-2 material-icons">manage_search</i> <i class="pb-2 opacity-75 material-icons">manage_search</i>
<span class="text-center"> <span class="text-center">
{{ $t("state.nothing_found") }} "{{ filterText }}" {{ $t("state.nothing_found") }} "{{ filterText }}"
</span> </span>
</div> </div>
<div <div
v-if="history.length === 0" v-if="history.length === 0"
class="flex flex-col text-secondaryLight p-4 items-center justify-center" class="flex flex-col items-center justify-center p-4 text-secondaryLight"
> >
<img <img
:src="`/images/states/${$colorMode.value}/history.svg`" :src="`/images/states/${$colorMode.value}/history.svg`"
loading="lazy" loading="lazy"
class="flex-col my-4 object-contain object-center h-16 w-16 inline-flex" class="inline-flex flex-col object-contain object-center w-16 h-16 my-4"
:alt="$t('empty.history')" :alt="$t('empty.history')"
/> />
<span class="text-center mb-4"> <span class="mb-4 text-center">
{{ $t("empty.history") }} {{ $t("empty.history") }}
</span> </span>
</div> </div>
@@ -140,9 +140,7 @@ export default defineComponent({
clearHistory() { clearHistory() {
if (this.page === "rest") clearRESTHistory() if (this.page === "rest") clearRESTHistory()
else clearGraphqlHistory() else clearGraphqlHistory()
this.$toast.success(`${this.$t("state.history_deleted")}`, { this.$toast.success(`${this.$t("state.history_deleted")}`)
icon: "delete",
})
}, },
useHistory(entry: any) { useHistory(entry: any) {
if (this.page === "rest") setRESTRequest(entry.request) if (this.page === "rest") setRESTRequest(entry.request)
@@ -150,9 +148,7 @@ export default defineComponent({
deleteHistory(entry: any) { deleteHistory(entry: any) {
if (this.page === "rest") deleteRESTHistoryEntry(entry) if (this.page === "rest") deleteRESTHistoryEntry(entry)
else deleteGraphqlHistoryEntry(entry) else deleteGraphqlHistoryEntry(entry)
this.$toast.success(`${this.$t("state.deleted")}`, { this.$toast.success(`${this.$t("state.deleted")}`)
icon: "delete",
})
}, },
toggleStar(entry: any) { toggleStar(entry: any) {
if (this.page === "rest") toggleRESTHistoryEntryStar(entry) if (this.page === "rest") toggleRESTHistoryEntryStar(entry)

View File

@@ -1,7 +1,7 @@
<template> <template>
<div class="flex items-center group"> <div class="group flex items-center">
<span <span
class="cursor-pointer flex px-2 w-16 justify-center items-center truncate" class="flex items-center justify-center w-16 px-2 truncate cursor-pointer"
:class="entryStatus.className" :class="entryStatus.className"
data-testid="restore_history_entry" data-testid="restore_history_entry"
:title="`${duration}`" :title="`${duration}`"
@@ -10,15 +10,7 @@
{{ entry.request.method }} {{ entry.request.method }}
</span> </span>
<span <span
class=" class="group-hover:text-secondaryDark flex flex-1 min-w-0 py-2 pr-2 transition cursor-pointer"
cursor-pointer
flex flex-1
min-w-0
py-2
pr-2
transition
group-hover:text-secondaryDark
"
data-testid="restore_history_entry" data-testid="restore_history_entry"
:title="`${duration}`" :title="`${duration}`"
@click="$emit('use-entry')" @click="$emit('use-entry')"
@@ -32,7 +24,7 @@
svg="trash" svg="trash"
color="red" color="red"
:title="$t('action.remove')" :title="$t('action.remove')"
class="hidden group-hover:inline-flex" class="group-hover:inline-flex hidden"
data-testid="delete_history_entry" data-testid="delete_history_entry"
@click.native="$emit('delete-entry')" @click.native="$emit('delete-entry')"
/> />
@@ -49,13 +41,9 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { import { computed, defineComponent, PropType } from "@nuxtjs/composition-api"
computed,
defineComponent,
PropType,
useContext,
} from "@nuxtjs/composition-api"
import findStatusGroup from "~/helpers/findStatusGroup" import findStatusGroup from "~/helpers/findStatusGroup"
import { useI18n } from "~/helpers/utils/composables"
import { RESTHistoryEntry } from "~/newstore/history" import { RESTHistoryEntry } from "~/newstore/history"
export default defineComponent({ export default defineComponent({
@@ -64,10 +52,7 @@ export default defineComponent({
showMore: Boolean, showMore: Boolean,
}, },
setup(props) { setup(props) {
const { const t = useI18n()
app: { i18n },
} = useContext()
const $t = i18n.t.bind(i18n)
const duration = computed(() => { const duration = computed(() => {
if (props.entry.responseMeta.duration) { if (props.entry.responseMeta.duration) {
@@ -75,9 +60,9 @@ export default defineComponent({
if (!responseDuration) return "" if (!responseDuration) return ""
return responseDuration > 0 return responseDuration > 0
? `${$t("request.duration")}: ${responseDuration}ms` ? `${t("request.duration")}: ${responseDuration}ms`
: $t("error.no_duration") : t("error.no_duration")
} else return $t("error.no_duration") } else return t("error.no_duration")
}) })
const entryStatus = computed(() => { const entryStatus = computed(() => {

View File

@@ -1,20 +1,10 @@
<template> <template>
<div> <div>
<div <div
class=" class="bg-primary border-dividerLight top-upperSecondaryStickyFold sticky z-10 flex items-center justify-between flex-1 pl-4 border-b"
bg-primary
border-b border-dividerLight
flex flex-1
top-upperSecondaryStickyFold
pl-4
z-10
sticky
items-center
justify-between
"
> >
<span class="flex items-center"> <span class="flex items-center">
<label class="font-semibold text-secondaryLight"> <label class="text-secondaryLight font-semibold">
{{ $t("authorization.type") }} {{ $t("authorization.type") }}
</label> </label>
<tippy <tippy
@@ -27,7 +17,7 @@
<template #trigger> <template #trigger>
<span class="select-wrapper"> <span class="select-wrapper">
<ButtonSecondary <ButtonSecondary
class="rounded-none ml-2 pr-8" class="pr-8 ml-2 rounded-none"
:label="authName" :label="authName"
/> />
</span> </span>
@@ -93,37 +83,37 @@
</div> </div>
<div <div
v-if="authType === 'none'" v-if="authType === 'none'"
class="flex flex-col text-secondaryLight p-4 items-center justify-center" class="text-secondaryLight flex flex-col items-center justify-center p-4"
> >
<img <img
:src="`/images/states/${$colorMode.value}/login.svg`" :src="`/images/states/${$colorMode.value}/login.svg`"
loading="lazy" loading="lazy"
class="flex-col my-4 object-contain object-center h-16 w-16 inline-flex" class="inline-flex flex-col object-contain object-center w-16 h-16 my-4"
:alt="$t('empty.authorization')" :alt="$t('empty.authorization')"
/> />
<span class="text-center pb-4"> <span class="pb-4 text-center">
{{ $t("empty.authorization") }} {{ $t("empty.authorization") }}
</span> </span>
<ButtonSecondary <ButtonSecondary
outline outline
:label="$t('app.documentation')" :label="$t('app.documentation')"
to="https://docs.hoppscotch.io" to="https://docs.hoppscotch.io/features/authorization"
blank blank
svg="external-link" svg="external-link"
reverse reverse
class="mb-4" class="mb-4"
/> />
</div> </div>
<div v-if="authType === 'basic'" class="border-b border-dividerLight flex"> <div v-if="authType === 'basic'" class="border-dividerLight flex border-b">
<div class="border-r border-dividerLight w-2/3"> <div class="border-dividerLight w-2/3 border-r">
<div class="border-b border-dividerLight flex"> <div class="border-dividerLight flex border-b">
<SmartEnvInput <SmartEnvInput
v-model="basicUsername" v-model="basicUsername"
:placeholder="$t('authorization.username')" :placeholder="$t('authorization.username')"
styles="bg-transparent flex flex-1 py-1 px-4" styles="bg-transparent flex flex-1 py-1 px-4"
/> />
</div> </div>
<div class="border-b border-dividerLight flex"> <div class="border-dividerLight flex border-b">
<SmartEnvInput <SmartEnvInput
v-model="basicPassword" v-model="basicPassword"
:placeholder="$t('authorization.password')" :placeholder="$t('authorization.password')"
@@ -132,17 +122,7 @@
</div> </div>
</div> </div>
<div <div
class=" class="bg-primary top-upperTertiaryStickyFold min-w-46 max-w-1/3 z-9 sticky h-full p-4 overflow-auto"
bg-primary
h-full
top-upperTertiaryStickyFold
min-w-46
max-w-1/3
p-4
z-9
sticky
overflow-auto
"
> >
<div class="p-2"> <div class="p-2">
<div class="text-secondaryLight pb-2"> <div class="text-secondaryLight pb-2">
@@ -151,15 +131,15 @@
<SmartAnchor <SmartAnchor
class="link" class="link"
:label="`${$t('authorization.learn')} \xA0 →`" :label="`${$t('authorization.learn')} \xA0 →`"
to="https://docs.hoppscotch.io/" to="https://docs.hoppscotch.io/features/authorization"
blank blank
/> />
</div> </div>
</div> </div>
</div> </div>
<div v-if="authType === 'bearer'" class="border-b border-dividerLight flex"> <div v-if="authType === 'bearer'" class="border-dividerLight flex border-b">
<div class="border-r border-dividerLight w-2/3"> <div class="border-dividerLight w-2/3 border-r">
<div class="border-b border-dividerLight flex"> <div class="border-dividerLight flex border-b">
<SmartEnvInput <SmartEnvInput
v-model="bearerToken" v-model="bearerToken"
placeholder="Token" placeholder="Token"
@@ -168,17 +148,7 @@
</div> </div>
</div> </div>
<div <div
class=" class="bg-primary top-upperTertiaryStickyFold min-w-46 max-w-1/3 z-9 sticky h-full p-4 overflow-auto"
bg-primary
h-full
top-upperTertiaryStickyFold
min-w-46
max-w-1/3
p-4
z-9
sticky
overflow-auto
"
> >
<div class="p-2"> <div class="p-2">
<div class="text-secondaryLight pb-2"> <div class="text-secondaryLight pb-2">
@@ -187,7 +157,7 @@
<SmartAnchor <SmartAnchor
class="link" class="link"
:label="`${$t('authorization.learn')} \xA0 →`" :label="`${$t('authorization.learn')} \xA0 →`"
to="https://docs.hoppscotch.io/" to="https://docs.hoppscotch.io/features/authorization"
blank blank
/> />
</div> </div>
@@ -195,10 +165,10 @@
</div> </div>
<div <div
v-if="authType === 'oauth-2'" v-if="authType === 'oauth-2'"
class="border-b border-dividerLight flex" class="border-dividerLight flex border-b"
> >
<div class="border-r border-dividerLight w-2/3"> <div class="border-dividerLight w-2/3 border-r">
<div class="border-b border-dividerLight flex"> <div class="border-dividerLight flex border-b">
<SmartEnvInput <SmartEnvInput
v-model="oauth2Token" v-model="oauth2Token"
placeholder="Token" placeholder="Token"
@@ -208,17 +178,7 @@
<HttpOAuth2Authorization /> <HttpOAuth2Authorization />
</div> </div>
<div <div
class=" class="bg-primary top-upperTertiaryStickyFold min-w-46 max-w-1/3 z-9 sticky h-full p-4 overflow-auto"
bg-primary
h-full
top-upperTertiaryStickyFold
min-w-46
max-w-1/3
p-4
z-9
sticky
overflow-auto
"
> >
<div class="p-2"> <div class="p-2">
<div class="text-secondaryLight pb-2"> <div class="text-secondaryLight pb-2">
@@ -227,7 +187,7 @@
<SmartAnchor <SmartAnchor
class="link" class="link"
:label="`${$t('authorization.learn')} \xA0 →`" :label="`${$t('authorization.learn')} \xA0 →`"
to="https://docs.hoppscotch.io/" to="https://docs.hoppscotch.io/features/authorization"
blank blank
/> />
</div> </div>

View File

@@ -1,20 +1,10 @@
<template> <template>
<div> <div>
<div <div
class=" class="bg-primary border-dividerLight top-upperSecondaryStickyFold sticky z-10 flex items-center justify-between flex-1 pl-4 border-b"
bg-primary
border-b border-dividerLight
flex flex-1
top-upperSecondaryStickyFold
pl-4
z-10
sticky
items-center
justify-between
"
> >
<span class="flex items-center"> <span class="flex items-center">
<label class="font-semibold text-secondaryLight"> <label class="text-secondaryLight font-semibold">
{{ $t("request.content_type") }} {{ $t("request.content_type") }}
</label> </label>
<tippy <tippy
@@ -28,7 +18,7 @@
<span class="select-wrapper"> <span class="select-wrapper">
<ButtonSecondary <ButtonSecondary
:label="contentType || $t('state.none').toLowerCase()" :label="contentType || $t('state.none').toLowerCase()"
class="rounded-none ml-2 pr-8" class="pr-8 ml-2 rounded-none"
/> />
</span> </span>
</template> </template>
@@ -63,21 +53,21 @@
<HttpRawBody v-else-if="contentType !== null" :content-type="contentType" /> <HttpRawBody v-else-if="contentType !== null" :content-type="contentType" />
<div <div
v-if="contentType == null" v-if="contentType == null"
class="flex flex-col text-secondaryLight p-4 items-center justify-center" class="text-secondaryLight flex flex-col items-center justify-center p-4"
> >
<img <img
:src="`/images/states/${$colorMode.value}/upload_single_file.svg`" :src="`/images/states/${$colorMode.value}/upload_single_file.svg`"
loading="lazy" loading="lazy"
class="flex-col my-4 object-contain object-center h-16 w-16 inline-flex" class="inline-flex flex-col object-contain object-center w-16 h-16 my-4"
:alt="$t('empty.body')" :alt="$t('empty.body')"
/> />
<span class="text-center pb-4"> <span class="pb-4 text-center">
{{ $t("empty.body") }} {{ $t("empty.body") }}
</span> </span>
<ButtonSecondary <ButtonSecondary
outline outline
:label="`${$t('app.documentation')}`" :label="`${$t('app.documentation')}`"
to="https://docs.hoppscotch.io" to="https://docs.hoppscotch.io/features/body"
blank blank
svg="external-link" svg="external-link"
reverse reverse

View File

@@ -1,19 +1,9 @@
<template> <template>
<AppSection label="bodyParameters"> <AppSection label="bodyParameters">
<div <div
class=" class="bg-primary border-dividerLight top-upperTertiaryStickyFold sticky z-10 flex items-center justify-between flex-1 pl-4 border-b"
bg-primary
border-b border-dividerLight
flex flex-1
top-upperTertiaryStickyFold
pl-4
z-10
sticky
items-center
justify-between
"
> >
<label class="font-semibold text-secondaryLight"> <label class="text-secondaryLight font-semibold">
{{ $t("request.body") }} {{ $t("request.body") }}
</label> </label>
<div class="flex"> <div class="flex">
@@ -41,7 +31,7 @@
<div <div
v-for="(param, index) in bodyParams" v-for="(param, index) in bodyParams"
:key="`param-${index}`" :key="`param-${index}`"
class="divide-x divide-dividerLight border-b border-dividerLight flex" class="divide-dividerLight border-dividerLight flex border-b divide-x"
> >
<SmartEnvInput <SmartEnvInput
v-model="param.key" v-model="param.key"
@@ -63,7 +53,7 @@
" "
/> />
<div v-if="param.isFile" class="file-chips-container hide-scrollbar"> <div v-if="param.isFile" class="file-chips-container hide-scrollbar">
<div class="space-x-2 file-chips-wrapper"> <div class="file-chips-wrapper space-x-2">
<SmartDeletableChip <SmartDeletableChip
v-for="(file, fileIndex) in param.value" v-for="(file, fileIndex) in param.value"
:key="`param-${index}-file-${fileIndex}`" :key="`param-${index}-file-${fileIndex}`"
@@ -151,15 +141,15 @@
</div> </div>
<div <div
v-if="bodyParams.length === 0" v-if="bodyParams.length === 0"
class="flex flex-col text-secondaryLight p-4 items-center justify-center" class="text-secondaryLight flex flex-col items-center justify-center p-4"
> >
<img <img
:src="`/images/states/${$colorMode.value}/upload_single_file.svg`" :src="`/images/states/${$colorMode.value}/upload_single_file.svg`"
loading="lazy" loading="lazy"
class="flex-col my-4 object-contain object-center h-16 w-16 inline-flex" class="inline-flex flex-col object-contain object-center w-16 h-16 my-4"
:alt="$t('empty.body')" :alt="$t('empty.body')"
/> />
<span class="text-center pb-4"> <span class="pb-4 text-center">
{{ $t("empty.body") }} {{ $t("empty.body") }}
</span> </span>
<ButtonSecondary <ButtonSecondary

View File

@@ -7,7 +7,7 @@
<template #body> <template #body>
<div class="flex flex-col px-2"> <div class="flex flex-col px-2">
<label for="requestType" class="px-4 pb-4"> <label for="requestType" class="px-4 pb-4">
{{ $t("request.choose_language") }} {{ t("request.choose_language") }}
</label> </label>
<tippy ref="options" interactive trigger="click" theme="popover" arrow> <tippy ref="options" interactive trigger="click" theme="popover" arrow>
<template #trigger> <template #trigger>
@@ -33,7 +33,7 @@
" "
/> />
</tippy> </tippy>
<div class="flex flex-1 justify-between"> <div class="flex justify-between flex-1">
<label for="generatedCode" class="p-4"> <label for="generatedCode" class="p-4">
{{ t("request.generated_code") }} {{ t("request.generated_code") }}
</label> </label>
@@ -41,7 +41,7 @@
<div <div
v-if="codegenType" v-if="codegenType"
ref="generatedCode" ref="generatedCode"
class="border border-dividerLight rounded" class="border rounded border-dividerLight"
></div> ></div>
</div> </div>
</template> </template>
@@ -62,13 +62,16 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed, ref, useContext, watch } from "@nuxtjs/composition-api" import { computed, ref, watch } from "@nuxtjs/composition-api"
import { codegens, generateCodegenContext } from "~/helpers/codegen/codegen" import { codegens, generateCodegenContext } from "~/helpers/codegen/codegen"
import { useCodemirror } from "~/helpers/editor/codemirror" import { useCodemirror } from "~/helpers/editor/codemirror"
import { copyToClipboard } from "~/helpers/utils/clipboard" import { copyToClipboard } from "~/helpers/utils/clipboard"
import { getEffectiveRESTRequest } from "~/helpers/utils/EffectiveURL" import { getEffectiveRESTRequest } from "~/helpers/utils/EffectiveURL"
import { getCurrentEnvironment } from "~/newstore/environments" import { getCurrentEnvironment } from "~/newstore/environments"
import { getRESTRequest } from "~/newstore/RESTSession" import { getRESTRequest } from "~/newstore/RESTSession"
import { useI18n, useToast } from "~/helpers/utils/composables"
const t = useI18n()
const props = defineProps<{ const props = defineProps<{
show: boolean show: boolean
@@ -78,11 +81,7 @@ const emit = defineEmits<{
(e: "hide-modal"): void (e: "hide-modal"): void
}>() }>()
const { const toast = useToast()
$toast,
app: { i18n },
} = useContext()
const t = i18n.t.bind(i18n)
const options = ref<any | null>(null) const options = ref<any | null>(null)
@@ -126,9 +125,7 @@ const hideModal = () => emit("hide-modal")
const copyRequestCode = () => { const copyRequestCode = () => {
copyToClipboard(requestCode.value) copyToClipboard(requestCode.value)
copyIcon.value = "check" copyIcon.value = "check"
$toast.success(`${t("state.copied_to_clipboard")}`, { toast.success(`${t("state.copied_to_clipboard")}`)
icon: "content_paste",
})
setTimeout(() => (copyIcon.value = "copy"), 1000) setTimeout(() => (copyIcon.value = "copy"), 1000)
} }
</script> </script>

View File

@@ -1,45 +1,35 @@
<template> <template>
<AppSection label="headers"> <AppSection label="headers">
<div <div
class=" class="bg-primary border-dividerLight top-upperSecondaryStickyFold sticky z-10 flex items-center justify-between flex-1 pl-4 border-b"
bg-primary
border-b border-dividerLight
flex flex-1
top-upperSecondaryStickyFold
pl-4
z-10
sticky
items-center
justify-between
"
> >
<label class="font-semibold text-secondaryLight"> <label class="text-secondaryLight font-semibold">
{{ $t("request.header_list") }} {{ t("request.header_list") }}
</label> </label>
<div class="flex"> <div class="flex">
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
to="https://docs.hoppscotch.io/features/headers" to="https://docs.hoppscotch.io/features/headers"
blank blank
:title="$t('app.wiki')" :title="t('app.wiki')"
svg="help-circle" svg="help-circle"
/> />
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('action.clear_all')" :title="t('action.clear_all')"
svg="trash-2" svg="trash-2"
@click.native="bulkMode ? clearBulkEditor() : clearContent()" @click.native="clearContent()"
/> />
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('state.bulk_mode')" :title="t('state.bulk_mode')"
svg="edit" svg="edit"
:class="{ '!text-accent': bulkMode }" :class="{ '!text-accent': bulkMode }"
@click.native="bulkMode = !bulkMode" @click.native="bulkMode = !bulkMode"
/> />
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('add.new')" :title="t('add.new')"
svg="plus" svg="plus"
:disabled="bulkMode" :disabled="bulkMode"
@click.native="addHeader" @click.native="addHeader"
@@ -51,10 +41,10 @@
<div <div
v-for="(header, index) in headers$" v-for="(header, index) in headers$"
:key="`header-${index}`" :key="`header-${index}`"
class="divide-x divide-dividerLight border-b border-dividerLight flex" class="divide-dividerLight border-dividerLight flex border-b divide-x"
> >
<SmartAutoComplete <SmartAutoComplete
:placeholder="`${$t('count.header', { count: index + 1 })}`" :placeholder="`${t('count.header', { count: index + 1 })}`"
:source="commonHeaders" :source="commonHeaders"
:spellcheck="false" :spellcheck="false"
:value="header.key" :value="header.key"
@@ -78,7 +68,7 @@
/> />
<SmartEnvInput <SmartEnvInput
v-model="header.value" v-model="header.value"
:placeholder="`${$t('count.value', { count: index + 1 })}`" :placeholder="`${t('count.value', { count: index + 1 })}`"
styles=" styles="
bg-transparent bg-transparent
flex flex
@@ -100,9 +90,9 @@
:title=" :title="
header.hasOwnProperty('active') header.hasOwnProperty('active')
? header.active ? header.active
? $t('action.turn_off') ? t('action.turn_off')
: $t('action.turn_on') : t('action.turn_on')
: $t('action.turn_off') : t('action.turn_off')
" "
:svg=" :svg="
header.hasOwnProperty('active') header.hasOwnProperty('active')
@@ -126,7 +116,7 @@
<span> <span>
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('action.remove')" :title="t('action.remove')"
svg="trash" svg="trash"
color="red" color="red"
@click.native="deleteHeader(index)" @click.native="deleteHeader(index)"
@@ -135,33 +125,20 @@
</div> </div>
<div <div
v-if="headers$.length === 0" v-if="headers$.length === 0"
class=" class="text-secondaryLight flex flex-col items-center justify-center p-4"
flex flex-col
text-secondaryLight
p-4
items-center
justify-center
"
> >
<img <img
:src="`/images/states/${$colorMode.value}/add_category.svg`" :src="`/images/states/${$colorMode.value}/add_category.svg`"
loading="lazy" loading="lazy"
class=" class="inline-flex flex-col object-contain object-center w-16 h-16 my-4"
flex-col :alt="`${t('empty.headers')}`"
my-4
object-contain object-center
h-16
w-16
inline-flex
"
:alt="$t('empty.headers')"
/> />
<span class="text-center pb-4"> <span class="pb-4 text-center">
{{ $t("empty.headers") }} {{ t("empty.headers") }}
</span> </span>
<ButtonSecondary <ButtonSecondary
filled filled
:label="`${$t('add.new')}`" :label="`${t('add.new')}`"
svg="plus" svg="plus"
class="mb-4" class="mb-4"
@click.native="addHeader" @click.native="addHeader"
@@ -172,7 +149,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { onBeforeUpdate, ref, useContext, watch } from "@nuxtjs/composition-api" import { onBeforeUpdate, ref, watch } from "@nuxtjs/composition-api"
import { useCodemirror } from "~/helpers/editor/codemirror" import { useCodemirror } from "~/helpers/editor/codemirror"
import { import {
addRESTHeader, addRESTHeader,
@@ -183,14 +160,16 @@ import {
updateRESTHeader, updateRESTHeader,
} from "~/newstore/RESTSession" } from "~/newstore/RESTSession"
import { commonHeaders } from "~/helpers/headers" import { commonHeaders } from "~/helpers/headers"
import { useReadonlyStream } from "~/helpers/utils/composables" import {
useReadonlyStream,
useI18n,
useToast,
} from "~/helpers/utils/composables"
import { HoppRESTHeader } from "~/helpers/types/HoppRESTRequest" import { HoppRESTHeader } from "~/helpers/types/HoppRESTRequest"
const { const t = useI18n()
$toast,
app: { i18n }, const toast = useToast()
} = useContext()
const t = i18n.t.bind(i18n)
const bulkMode = ref(false) const bulkMode = ref(false)
const bulkHeaders = ref("") const bulkHeaders = ref("")
@@ -212,11 +191,9 @@ watch(bulkHeaders, () => {
value: item.substring(item.indexOf(":") + 1).trim(), value: item.substring(item.indexOf(":") + 1).trim(),
active: !item.trim().startsWith("//"), active: !item.trim().startsWith("//"),
})) }))
setRESTHeaders(transformation) setRESTHeaders(transformation as HoppRESTHeader[])
} catch (e) { } catch (e) {
$toast.error(`${t("error.something_went_wrong")}`, { toast.error(`${t("error.something_went_wrong")}`)
icon: "error_outline",
})
console.error(e) console.error(e)
} }
}) })
@@ -226,12 +203,13 @@ const headers$ = useReadonlyStream(restHeaders$, [])
watch( watch(
headers$, headers$,
(newValue) => { (newValue) => {
if ( if (!bulkMode.value)
(newValue[newValue.length - 1]?.key !== "" || if (
newValue[newValue.length - 1]?.value !== "") && (newValue[newValue.length - 1]?.key !== "" ||
newValue.length newValue[newValue.length - 1]?.value !== "") &&
) newValue.length
addHeader() )
addHeader()
}, },
{ deep: true } { deep: true }
) )
@@ -277,11 +255,10 @@ const deleteHeader = (index: number) => {
const deletedItem = headersBeforeDeletion[index] const deletedItem = headersBeforeDeletion[index]
if (deletedItem.key || deletedItem.value) { if (deletedItem.key || deletedItem.value) {
$toast.success(t("state.deleted").toString(), { toast.success(`${t("state.deleted")}`, {
icon: "delete",
action: [ action: [
{ {
text: t("action.undo").toString(), text: `${t("action.undo")}`,
onClick: (_, toastObject) => { onClick: (_, toastObject) => {
setRESTHeaders(headersBeforeDeletion as HoppRESTHeader[]) setRESTHeaders(headersBeforeDeletion as HoppRESTHeader[])
editBulkHeadersLine(index, deletedItem) editBulkHeadersLine(index, deletedItem)

View File

@@ -1,18 +1,18 @@
<template> <template>
<SmartModal v-if="show" :title="`${$t('import.curl')}`" @close="hideModal"> <SmartModal v-if="show" :title="`${t('import.curl')}`" @close="hideModal">
<template #body> <template #body>
<div class="flex flex-col px-2"> <div class="flex flex-col px-2">
<div ref="curlEditor" class="border border-dividerLight rounded"></div> <div ref="curlEditor" class="border rounded border-dividerLight"></div>
</div> </div>
</template> </template>
<template #footer> <template #footer>
<span class="flex"> <span class="flex">
<ButtonPrimary <ButtonPrimary
:label="`${$t('import.title')}`" :label="`${t('import.title')}`"
@click.native="handleImport" @click.native="handleImport"
/> />
<ButtonSecondary <ButtonSecondary
:label="`${$t('action.cancel')}`" :label="`${t('action.cancel')}`"
@click.native="hideModal" @click.native="hideModal"
/> />
</span> </span>
@@ -21,7 +21,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, useContext } from "@nuxtjs/composition-api" import { ref } from "@nuxtjs/composition-api"
import parseCurlCommand from "~/helpers/curlparser" import parseCurlCommand from "~/helpers/curlparser"
import { useCodemirror } from "~/helpers/editor/codemirror" import { useCodemirror } from "~/helpers/editor/codemirror"
import { import {
@@ -30,12 +30,11 @@ import {
makeRESTRequest, makeRESTRequest,
} from "~/helpers/types/HoppRESTRequest" } from "~/helpers/types/HoppRESTRequest"
import { setRESTRequest } from "~/newstore/RESTSession" import { setRESTRequest } from "~/newstore/RESTSession"
import { useI18n, useToast } from "~/helpers/utils/composables"
const { const t = useI18n()
$toast,
app: { i18n }, const toast = useToast()
} = useContext()
const t = i18n.t.bind(i18n)
const curl = ref("") const curl = ref("")
@@ -123,9 +122,7 @@ const handleImport = () => {
) )
} catch (e) { } catch (e) {
console.error(e) console.error(e)
$toast.error(`${t("error.curl_invalid_format")}`, { toast.error(`${t("error.curl_invalid_format")}`)
icon: "error_outline",
})
} }
hideModal() hideModal()
} }

View File

@@ -1,46 +1,46 @@
<template> <template>
<div class="flex flex-col"> <div class="flex flex-col">
<div class="border-b border-dividerLight flex"> <div class="flex border-b border-dividerLight">
<input <input
id="oidcDiscoveryURL" id="oidcDiscoveryURL"
v-model="oidcDiscoveryURL" v-model="oidcDiscoveryURL"
class="bg-transparent flex flex-1 py-2 px-4" class="flex flex-1 px-4 py-2 bg-transparent"
placeholder="OpenID Connect Discovery URL" placeholder="OpenID Connect Discovery URL"
name="oidcDiscoveryURL" name="oidcDiscoveryURL"
/> />
</div> </div>
<div class="border-b border-dividerLight flex"> <div class="flex border-b border-dividerLight">
<input <input
id="authURL" id="authURL"
v-model="authURL" v-model="authURL"
class="bg-transparent flex flex-1 py-2 px-4" class="flex flex-1 px-4 py-2 bg-transparent"
placeholder="Authentication URL" placeholder="Authentication URL"
name="authURL" name="authURL"
/> />
</div> </div>
<div class="border-b border-dividerLight flex"> <div class="flex border-b border-dividerLight">
<input <input
id="accessTokenURL" id="accessTokenURL"
v-model="accessTokenURL" v-model="accessTokenURL"
class="bg-transparent flex flex-1 py-2 px-4" class="flex flex-1 px-4 py-2 bg-transparent"
placeholder="Access Token URL" placeholder="Access Token URL"
name="accessTokenURL" name="accessTokenURL"
/> />
</div> </div>
<div class="border-b border-dividerLight flex"> <div class="flex border-b border-dividerLight">
<input <input
id="clientID" id="clientID"
v-model="clientID" v-model="clientID"
class="bg-transparent flex flex-1 py-2 px-4" class="flex flex-1 px-4 py-2 bg-transparent"
placeholder="Client ID" placeholder="Client ID"
name="clientID" name="clientID"
/> />
</div> </div>
<div class="border-b border-dividerLight flex"> <div class="flex border-b border-dividerLight">
<input <input
id="scope" id="scope"
v-model="scope" v-model="scope"
class="bg-transparent flex flex-1 py-2 px-4" class="flex flex-1 px-4 py-2 bg-transparent"
placeholder="Scope" placeholder="Scope"
name="scope" name="scope"
/> />
@@ -48,7 +48,7 @@
<div class="p-2"> <div class="p-2">
<ButtonSecondary <ButtonSecondary
filled filled
:label="`${$t('authorization.generate_token')}`" :label="`${t('authorization.generate_token')}`"
@click.native="handleAccessTokenRequest()" @click.native="handleAccessTokenRequest()"
/> />
</div> </div>
@@ -56,19 +56,21 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { Ref, useContext } from "@nuxtjs/composition-api" import { Ref } from "@nuxtjs/composition-api"
import { pluckRef, useStream } from "~/helpers/utils/composables" import {
pluckRef,
useI18n,
useStream,
useToast,
} from "~/helpers/utils/composables"
import { HoppRESTAuthOAuth2 } from "~/helpers/types/HoppRESTAuth" import { HoppRESTAuthOAuth2 } from "~/helpers/types/HoppRESTAuth"
import { restAuth$, setRESTAuth } from "~/newstore/RESTSession" import { restAuth$, setRESTAuth } from "~/newstore/RESTSession"
import { tokenRequest } from "~/helpers/oauth" import { tokenRequest } from "~/helpers/oauth"
export default { export default {
setup() { setup() {
const { const t = useI18n()
$toast, const toast = useToast()
app: { i18n },
} = useContext()
const $t = i18n.t.bind(i18n)
const auth = useStream( const auth = useStream(
restAuth$, restAuth$,
@@ -97,9 +99,7 @@ export default {
oidcDiscoveryURL.value === "" && oidcDiscoveryURL.value === "" &&
(authURL.value === "" || accessTokenURL.value === "") (authURL.value === "" || accessTokenURL.value === "")
) { ) {
$toast.error(`${$t("complete_config_urls")}`, { toast.error(`${t("complete_config_urls")}`)
icon: "error",
})
return return
} }
try { try {
@@ -113,9 +113,7 @@ export default {
} }
await tokenRequest(tokenReqParams) await tokenRequest(tokenReqParams)
} catch (e) { } catch (e) {
$toast.error(`${e}`, { toast.error(`${e}`)
icon: "code",
})
} }
} }

View File

@@ -1,45 +1,35 @@
<template> <template>
<AppSection label="parameters"> <AppSection label="parameters">
<div <div
class=" class="bg-primary border-dividerLight top-upperSecondaryStickyFold sticky z-10 flex items-center justify-between flex-1 pl-4 border-b"
bg-primary
border-b border-dividerLight
flex flex-1
top-upperSecondaryStickyFold
pl-4
z-10
sticky
items-center
justify-between
"
> >
<label class="font-semibold text-secondaryLight"> <label class="text-secondaryLight font-semibold">
{{ $t("request.parameter_list") }} {{ t("request.parameter_list") }}
</label> </label>
<div class="flex"> <div class="flex">
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
to="https://docs.hoppscotch.io/features/parameters" to="https://docs.hoppscotch.io/features/parameters"
blank blank
:title="$t('app.wiki')" :title="t('app.wiki')"
svg="help-circle" svg="help-circle"
/> />
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('action.clear_all')" :title="t('action.clear_all')"
svg="trash-2" svg="trash-2"
@click.native="bulkMode ? clearBulkEditor() : clearContent()" @click.native="clearContent()"
/> />
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('state.bulk_mode')" :title="t('state.bulk_mode')"
svg="edit" svg="edit"
:class="{ '!text-accent': bulkMode }" :class="{ '!text-accent': bulkMode }"
@click.native="bulkMode = !bulkMode" @click.native="bulkMode = !bulkMode"
/> />
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('add.new')" :title="t('add.new')"
svg="plus" svg="plus"
:disabled="bulkMode" :disabled="bulkMode"
@click.native="addParam" @click.native="addParam"
@@ -51,11 +41,11 @@
<div <div
v-for="(param, index) in params$" v-for="(param, index) in params$"
:key="`param-${index}`" :key="`param-${index}`"
class="divide-x divide-dividerLight border-b border-dividerLight flex" class="divide-dividerLight border-dividerLight flex border-b divide-x"
> >
<SmartEnvInput <SmartEnvInput
v-model="param.key" v-model="param.key"
:placeholder="`${$t('count.parameter', { count: index + 1 })}`" :placeholder="`${t('count.parameter', { count: index + 1 })}`"
styles=" styles="
bg-transparent bg-transparent
flex flex
@@ -73,7 +63,7 @@
/> />
<SmartEnvInput <SmartEnvInput
v-model="param.value" v-model="param.value"
:placeholder="`${$t('count.value', { count: index + 1 })}`" :placeholder="`${t('count.value', { count: index + 1 })}`"
styles=" styles="
bg-transparent bg-transparent
flex flex
@@ -95,9 +85,9 @@
:title=" :title="
param.hasOwnProperty('active') param.hasOwnProperty('active')
? param.active ? param.active
? $t('action.turn_off') ? t('action.turn_off')
: $t('action.turn_on') : t('action.turn_on')
: $t('action.turn_off') : t('action.turn_off')
" "
:svg=" :svg="
param.hasOwnProperty('active') param.hasOwnProperty('active')
@@ -119,7 +109,7 @@
<span> <span>
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('action.remove')" :title="t('action.remove')"
svg="trash" svg="trash"
color="red" color="red"
@click.native="deleteParam(index)" @click.native="deleteParam(index)"
@@ -128,32 +118,19 @@
</div> </div>
<div <div
v-if="params$.length === 0" v-if="params$.length === 0"
class=" class="text-secondaryLight flex flex-col items-center justify-center p-4"
flex flex-col
text-secondaryLight
p-4
items-center
justify-center
"
> >
<img <img
:src="`/images/states/${$colorMode.value}/add_files.svg`" :src="`/images/states/${$colorMode.value}/add_files.svg`"
loading="lazy" loading="lazy"
class=" class="inline-flex flex-col object-contain object-center w-16 h-16 my-4"
flex-col :alt="`${t('empty.parameters')}`"
my-4
object-contain object-center
h-16
w-16
inline-flex
"
:alt="$t('empty.parameters')"
/> />
<span class="text-center pb-4"> <span class="pb-4 text-center">
{{ $t("empty.parameters") }} {{ t("empty.parameters") }}
</span> </span>
<ButtonSecondary <ButtonSecondary
:label="`${$t('add.new')}`" :label="`${t('add.new')}`"
svg="plus" svg="plus"
filled filled
class="mb-4" class="mb-4"
@@ -165,10 +142,14 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, useContext, watch, onBeforeUpdate } from "@nuxtjs/composition-api" import { ref, watch, onBeforeUpdate } from "@nuxtjs/composition-api"
import { useCodemirror } from "~/helpers/editor/codemirror" import { useCodemirror } from "~/helpers/editor/codemirror"
import { HoppRESTParam } from "~/helpers/types/HoppRESTRequest" import { HoppRESTParam } from "~/helpers/types/HoppRESTRequest"
import { useReadonlyStream } from "~/helpers/utils/composables" import {
useReadonlyStream,
useI18n,
useToast,
} from "~/helpers/utils/composables"
import { import {
restParams$, restParams$,
addRESTParam, addRESTParam,
@@ -178,11 +159,9 @@ import {
setRESTParams, setRESTParams,
} from "~/newstore/RESTSession" } from "~/newstore/RESTSession"
const { const t = useI18n()
$toast,
app: { i18n }, const toast = useToast()
} = useContext()
const t = i18n.t.bind(i18n)
const bulkMode = ref(false) const bulkMode = ref(false)
const bulkParams = ref("") const bulkParams = ref("")
@@ -194,11 +173,9 @@ watch(bulkParams, () => {
value: item.substring(item.indexOf(":") + 1).trim(), value: item.substring(item.indexOf(":") + 1).trim(),
active: !item.trim().startsWith("//"), active: !item.trim().startsWith("//"),
})) }))
setRESTParams(transformation) setRESTParams(transformation as HoppRESTParam[])
} catch (e) { } catch (e) {
$toast.error(`${t("error.something_went_wrong")}`, { toast.error(`${t("error.something_went_wrong")}`)
icon: "error_outline",
})
console.error(e) console.error(e)
} }
}) })
@@ -219,12 +196,13 @@ const params$ = useReadonlyStream(restParams$, [])
watch( watch(
params$, params$,
(newValue) => { (newValue) => {
if ( if (!bulkMode.value)
(newValue[newValue.length - 1]?.key !== "" || if (
newValue[newValue.length - 1]?.value !== "") && (newValue[newValue.length - 1]?.key !== "" ||
newValue.length newValue[newValue.length - 1]?.value !== "") &&
) newValue.length
addParam() )
addParam()
}, },
{ deep: true } { deep: true }
) )
@@ -270,11 +248,10 @@ const deleteParam = (index: number) => {
const deletedItem = parametersBeforeDeletion[index] const deletedItem = parametersBeforeDeletion[index]
if (deletedItem.key || deletedItem.value) { if (deletedItem.key || deletedItem.value) {
$toast.success(t("state.deleted").toString(), { toast.success(`${t("state.deleted")}`, {
icon: "delete",
action: [ action: [
{ {
text: t("action.undo").toString(), text: `${t("action.undo")}`,
onClick: (_, toastObject) => { onClick: (_, toastObject) => {
setRESTParams(parametersBeforeDeletion as HoppRESTParam[]) setRESTParams(parametersBeforeDeletion as HoppRESTParam[])
editBulkParamsLine(index, deletedItem) editBulkParamsLine(index, deletedItem)

View File

@@ -1,71 +1,51 @@
<template> <template>
<AppSection id="script" :label="`${$t('preRequest.script')}`"> <AppSection id="script" :label="`${t('preRequest.script')}`">
<div <div
class=" class="bg-primary border-dividerLight top-upperSecondaryStickyFold sticky z-10 flex items-center justify-between flex-1 pl-4 border-b"
bg-primary
border-b border-dividerLight
flex flex-1
top-upperSecondaryStickyFold
pl-4
z-10
sticky
items-center
justify-between
"
> >
<label class="font-semibold text-secondaryLight"> <label class="text-secondaryLight font-semibold">
{{ $t("preRequest.javascript_code") }} {{ t("preRequest.javascript_code") }}
</label> </label>
<div class="flex"> <div class="flex">
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
to="https://docs.hoppscotch.io/features/pre-request-script" to="https://docs.hoppscotch.io/features/pre-request-script"
blank blank
:title="$t('app.wiki')" :title="t('app.wiki')"
svg="help-circle" svg="help-circle"
/> />
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('state.linewrap')" :title="t('state.linewrap')"
:class="{ '!text-accent': linewrapEnabled }" :class="{ '!text-accent': linewrapEnabled }"
svg="corner-down-left" svg="corner-down-left"
@click.native.prevent="linewrapEnabled = !linewrapEnabled" @click.native.prevent="linewrapEnabled = !linewrapEnabled"
/> />
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('action.clear')" :title="t('action.clear')"
svg="trash-2" svg="trash-2"
@click.native="clearContent" @click.native="clearContent"
/> />
</div> </div>
</div> </div>
<div class="border-b border-dividerLight flex"> <div class="border-dividerLight flex border-b">
<div class="border-r border-dividerLight w-2/3"> <div class="border-dividerLight w-2/3 border-r">
<div ref="preRrequestEditor"></div> <div ref="preRrequestEditor"></div>
</div> </div>
<div <div
class=" class="bg-primary top-upperTertiaryStickyFold min-w-46 max-w-1/3 z-9 sticky h-full p-4 overflow-auto"
bg-primary
h-full
top-upperTertiaryStickyFold
min-w-46
max-w-1/3
p-4
z-9
sticky
overflow-auto
"
> >
<div class="text-secondaryLight pb-2"> <div class="text-secondaryLight pb-2">
{{ $t("helpers.pre_request_script") }} {{ t("helpers.pre_request_script") }}
</div> </div>
<SmartAnchor <SmartAnchor
:label="`${$t('preRequest.learn')}`" :label="`${t('preRequest.learn')}`"
to="https://docs.hoppscotch.io/features/pre-request-script" to="https://docs.hoppscotch.io/features/pre-request-script"
blank blank
/> />
<h4 class="font-bold text-secondaryLight pt-6"> <h4 class="text-secondaryLight pt-6 font-bold">
{{ $t("preRequest.snippets") }} {{ t("preRequest.snippets") }}
</h4> </h4>
<div class="flex flex-col pt-4"> <div class="flex flex-col pt-4">
<TabSecondary <TabSecondary
@@ -82,17 +62,15 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { reactive, ref, useContext } from "@nuxtjs/composition-api" import { reactive, ref } from "@nuxtjs/composition-api"
import { usePreRequestScript } from "~/newstore/RESTSession" import { usePreRequestScript } from "~/newstore/RESTSession"
import snippets from "~/helpers/preRequestScriptSnippets" import snippets from "~/helpers/preRequestScriptSnippets"
import { useCodemirror } from "~/helpers/editor/codemirror" import { useCodemirror } from "~/helpers/editor/codemirror"
import linter from "~/helpers/editor/linting/preRequest" import linter from "~/helpers/editor/linting/preRequest"
import completer from "~/helpers/editor/completion/preRequest" import completer from "~/helpers/editor/completion/preRequest"
import { useI18n } from "~/helpers/utils/composables"
const { const t = useI18n()
app: { i18n },
} = useContext()
const t = i18n.t.bind(i18n)
const preRequestScript = usePreRequestScript() const preRequestScript = usePreRequestScript()

View File

@@ -1,39 +1,29 @@
<template> <template>
<div> <div>
<div <div
class=" class="bg-primary border-dividerLight top-upperTertiaryStickyFold sticky z-10 flex items-center justify-between flex-1 pl-4 border-b"
bg-primary
border-b border-dividerLight
flex flex-1
top-upperTertiaryStickyFold
pl-4
z-10
sticky
items-center
justify-between
"
> >
<label class="font-semibold text-secondaryLight"> <label class="text-secondaryLight font-semibold">
{{ $t("request.raw_body") }} {{ t("request.raw_body") }}
</label> </label>
<div class="flex"> <div class="flex">
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
to="https://docs.hoppscotch.io/features/body" to="https://docs.hoppscotch.io/features/body"
blank blank
:title="$t('app.wiki')" :title="t('app.wiki')"
svg="help-circle" svg="help-circle"
/> />
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('state.linewrap')" :title="t('state.linewrap')"
:class="{ '!text-accent': linewrapEnabled }" :class="{ '!text-accent': linewrapEnabled }"
svg="corner-down-left" svg="corner-down-left"
@click.native.prevent="linewrapEnabled = !linewrapEnabled" @click.native.prevent="linewrapEnabled = !linewrapEnabled"
/> />
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('action.clear')" :title="t('action.clear')"
svg="trash-2" svg="trash-2"
@click.native="clearContent" @click.native="clearContent"
/> />
@@ -41,14 +31,14 @@
v-if="contentType && contentType.endsWith('json')" v-if="contentType && contentType.endsWith('json')"
ref="prettifyRequest" ref="prettifyRequest"
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('action.prettify')" :title="t('action.prettify')"
:svg="prettifyIcon" :svg="prettifyIcon"
@click.native="prettifyRequestBody" @click.native="prettifyRequestBody"
/> />
<label for="payload"> <label for="payload">
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('import.json')" :title="t('import.json')"
svg="file-plus" svg="file-plus"
@click.native="$refs.payload.click()" @click.native="$refs.payload.click()"
/> />
@@ -67,21 +57,19 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed, reactive, ref, useContext } from "@nuxtjs/composition-api" import { computed, reactive, ref } from "@nuxtjs/composition-api"
import { useCodemirror } from "~/helpers/editor/codemirror" import { useCodemirror } from "~/helpers/editor/codemirror"
import { getEditorLangForMimeType } from "~/helpers/editorutils" import { getEditorLangForMimeType } from "~/helpers/editorutils"
import { pluckRef } from "~/helpers/utils/composables" import { pluckRef, useI18n, useToast } from "~/helpers/utils/composables"
import { useRESTRequestBody } from "~/newstore/RESTSession" import { useRESTRequestBody } from "~/newstore/RESTSession"
const t = useI18n()
const props = defineProps<{ const props = defineProps<{
contentType: string contentType: string
}>() }>()
const { const toast = useToast()
$toast,
app: { i18n },
} = useContext()
const t = i18n.t.bind(i18n)
const rawParamsBody = pluckRef(useRESTRequestBody(), "body") const rawParamsBody = pluckRef(useRESTRequestBody(), "body")
const prettifyIcon = ref("wand") const prettifyIcon = ref("wand")
@@ -118,13 +106,9 @@ const uploadPayload = (e: InputEvent) => {
rawParamsBody.value = target?.result rawParamsBody.value = target?.result
} }
reader.readAsText(file) reader.readAsText(file)
$toast.success(`${t("state.file_imported")}`, { toast.success(`${t("state.file_imported")}`)
icon: "attach_file",
})
} else { } else {
$toast.error(`${t("action.choose_file")}`, { toast.error(`${t("action.choose_file")}`)
icon: "attach_file",
})
} }
} }
const prettifyRequestBody = () => { const prettifyRequestBody = () => {
@@ -135,9 +119,7 @@ const prettifyRequestBody = () => {
setTimeout(() => (prettifyIcon.value = "wand"), 1000) setTimeout(() => (prettifyIcon.value = "wand"), 1000)
} catch (e) { } catch (e) {
console.error(e) console.error(e)
$toast.error(`${t("error.json_prettify_invalid_body")}`, { toast.error(`${t("error.json_prettify_invalid_body")}`)
icon: "error_outline",
})
} }
} }
</script> </script>

View File

@@ -1,19 +1,9 @@
<template> <template>
<div <div
class=" class="bg-primary hide-scrollbar sticky top-0 z-10 flex p-4 space-x-2 overflow-x-auto"
bg-primary
flex
space-x-2
p-4
top-0
z-10
sticky
overflow-x-auto
hide-scrollbar
"
> >
<div class="flex flex-1"> <div class="flex flex-1">
<div class="flex relative"> <div class="relative flex">
<label for="method"> <label for="method">
<tippy <tippy
ref="methodOptions" ref="methodOptions"
@@ -26,24 +16,10 @@
<span class="select-wrapper"> <span class="select-wrapper">
<input <input
id="method" id="method"
class=" class="bg-primaryLight border-divider text-secondaryDark w-26 hover:border-dividerDark focus-visible:bg-transparent focus-visible:border-dividerDark flex px-4 py-2 font-semibold border rounded-l cursor-pointer"
bg-primaryLight
border border-divider
rounded-l
cursor-pointer
flex
font-semibold
text-secondaryDark
py-2
px-4
w-26
hover:border-dividerDark
focus-visible:bg-transparent
focus-visible:border-dividerDark
"
:value="newMethod" :value="newMethod"
:readonly="!isCustomMethod" :readonly="!isCustomMethod"
:placeholder="`${$t('request.method')}`" :placeholder="`${t('request.method')}`"
@input="onSelectMethod($event.target.value)" @input="onSelectMethod($event.target.value)"
/> />
</span> </span>
@@ -60,7 +36,7 @@
<div class="flex flex-1"> <div class="flex flex-1">
<SmartEnvInput <SmartEnvInput
v-model="newEndpoint" v-model="newEndpoint"
:placeholder="`${$t('request.url')}`" :placeholder="`${t('request.url')}`"
styles=" styles="
bg-primaryLight bg-primaryLight
border border-divider border border-divider
@@ -82,8 +58,8 @@
<div class="flex"> <div class="flex">
<ButtonPrimary <ButtonPrimary
id="send" id="send"
class="rounded-r-none flex-1 min-w-20" class="min-w-20 flex-1 rounded-r-none"
:label="`${!loading ? $t('action.send') : $t('action.cancel')}`" :label="`${!loading ? t('action.send') : t('action.cancel')}`"
@click.native="!loading ? newSendRequest() : cancelRequest()" @click.native="!loading ? newSendRequest() : cancelRequest()"
/> />
<span class="flex"> <span class="flex">
@@ -98,7 +74,7 @@
<ButtonPrimary class="rounded-l-none" filled svg="chevron-down" /> <ButtonPrimary class="rounded-l-none" filled svg="chevron-down" />
</template> </template>
<SmartItem <SmartItem
:label="`${$t('import.curl')}`" :label="`${t('import.curl')}`"
svg="file-code" svg="file-code"
@click.native=" @click.native="
() => { () => {
@@ -108,7 +84,7 @@
" "
/> />
<SmartItem <SmartItem
:label="`${$t('show.code')}`" :label="`${t('show.code')}`"
svg="code-2" svg="code-2"
@click.native=" @click.native="
() => { () => {
@@ -119,7 +95,7 @@
/> />
<SmartItem <SmartItem
ref="clearAll" ref="clearAll"
:label="`${$t('action.clear_all')}`" :label="`${t('action.clear_all')}`"
svg="rotate-ccw" svg="rotate-ccw"
@click.native=" @click.native="
() => { () => {
@@ -131,10 +107,10 @@
</tippy> </tippy>
</span> </span>
<ButtonSecondary <ButtonSecondary
class="rounded rounded-r-none ml-2" class="ml-2 rounded rounded-r-none"
:label=" :label="
windowInnerWidth.x.value >= 768 && COLUMN_LAYOUT windowInnerWidth.x.value >= 768 && COLUMN_LAYOUT
? `${$t('request.save')}` ? `${t('request.save')}`
: '' : ''
" "
filled filled
@@ -159,27 +135,27 @@
<input <input
id="request-name" id="request-name"
v-model="requestName" v-model="requestName"
:placeholder="`${$t('request.name')}`" :placeholder="`${t('request.name')}`"
name="request-name" name="request-name"
type="text" type="text"
autocomplete="off" autocomplete="off"
class="mb-2 input" class="input mb-2"
@keyup.enter="saveOptions.tippy().hide()" @keyup.enter="saveOptions.tippy().hide()"
/> />
<SmartItem <SmartItem
ref="copyRequest" ref="copyRequest"
:label="`${$t('request.copy_link')}`" :label="shareButtonText"
:svg="hasNavigatorShare ? 'share-2' : 'copy'" :svg="copyLinkIcon"
:loading="fetchingShareLink"
@click.native=" @click.native="
() => { () => {
copyRequest() copyRequest()
saveOptions.tippy().hide()
} }
" "
/> />
<SmartItem <SmartItem
ref="saveRequest" ref="saveRequest"
:label="`${$t('request.save_as')}`" :label="`${t('request.save_as')}`"
svg="folder-plus" svg="folder-plus"
@click.native=" @click.native="
() => { () => {
@@ -208,8 +184,9 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed, ref, useContext, watch } from "@nuxtjs/composition-api" import { computed, ref, watch } from "@nuxtjs/composition-api"
import { isRight } from "fp-ts/lib/Either" import { isRight } from "fp-ts/lib/Either"
import * as E from "fp-ts/Either"
import { import {
updateRESTResponse, updateRESTResponse,
restEndpoint$, restEndpoint$,
@@ -220,6 +197,7 @@ import {
useRESTRequestName, useRESTRequestName,
getRESTSaveContext, getRESTSaveContext,
getRESTRequest, getRESTRequest,
restRequest$,
} from "~/newstore/RESTSession" } from "~/newstore/RESTSession"
import { editRESTRequest } from "~/newstore/collections" import { editRESTRequest } from "~/newstore/collections"
import { runRESTRequest$ } from "~/helpers/RequestRunner" import { runRESTRequest$ } from "~/helpers/RequestRunner"
@@ -227,6 +205,9 @@ import {
useStreamSubscriber, useStreamSubscriber,
useStream, useStream,
useNuxt, useNuxt,
useI18n,
useToast,
useReadonlyStream,
} from "~/helpers/utils/composables" } from "~/helpers/utils/composables"
import { defineActionHandler } from "~/helpers/actions" import { defineActionHandler } from "~/helpers/actions"
import { copyToClipboard } from "~/helpers/utils/clipboard" import { copyToClipboard } from "~/helpers/utils/clipboard"
@@ -234,6 +215,9 @@ import { useSetting } from "~/newstore/settings"
import { overwriteRequestTeams } from "~/helpers/teams/utils" import { overwriteRequestTeams } from "~/helpers/teams/utils"
import { apolloClient } from "~/helpers/apollo" import { apolloClient } from "~/helpers/apollo"
import useWindowSize from "~/helpers/utils/useWindowSize" import useWindowSize from "~/helpers/utils/useWindowSize"
import { createShortcode } from "~/helpers/backend/mutations/Shortcode"
const t = useI18n()
const methods = [ const methods = [
"GET", "GET",
@@ -248,12 +232,9 @@ const methods = [
"CUSTOM", "CUSTOM",
] ]
const { const toast = useToast()
$toast,
app: { i18n },
} = useContext()
const nuxt = useNuxt() const nuxt = useNuxt()
const t = i18n.t.bind(i18n)
const { subscribeToStream } = useStreamSubscriber() const { subscribeToStream } = useStreamSubscriber()
const newEndpoint = useStream(restEndpoint$, "", setRESTEndpoint) const newEndpoint = useStream(restEndpoint$, "", setRESTEndpoint)
@@ -282,6 +263,11 @@ watch(loading, () => {
}) })
const newSendRequest = async () => { const newSendRequest = async () => {
if (newEndpoint.value === "" || /^\s+$/.test(newEndpoint.value)) {
toast.error(`${t("empty.endpoint")}`)
return
}
loading.value = true loading.value = true
// Double calling is because the function returns a TaskEither than should be executed // Double calling is because the function returns a TaskEither than should be executed
@@ -327,7 +313,46 @@ const clearContent = () => {
resetRESTRequest() resetRESTRequest()
} }
const copyRequest = () => { const copyLinkIcon = hasNavigatorShare ? ref("share-2") : ref("copy")
const shareLink = ref<string | null>("")
const fetchingShareLink = ref(false)
const shareButtonText = computed(() => {
if (shareLink.value) {
return shareLink.value
} else if (fetchingShareLink.value) {
return t("state.loading")
} else {
return t("request.copy_link")
}
})
const request = useReadonlyStream(restRequest$, getRESTRequest())
watch(request, () => {
shareLink.value = null
})
const copyRequest = async () => {
if (shareLink.value) {
copyShareLink(shareLink.value)
} else {
shareLink.value = ""
fetchingShareLink.value = true
const request = getRESTRequest()
const shortcodeResult = await createShortcode(request)()
if (E.isLeft(shortcodeResult)) {
toast.error(`${shortcodeResult.left.error}`)
shareLink.value = `${t("error.something_went_wrong")}`
} else if (E.isRight(shortcodeResult)) {
shareLink.value = `/${shortcodeResult.right.createShortcode.id}`
copyShareLink(shareLink.value)
}
fetchingShareLink.value = false
}
}
const copyShareLink = (shareLink: string) => {
if (navigator.share) { if (navigator.share) {
const time = new Date().toLocaleTimeString() const time = new Date().toLocaleTimeString()
const date = new Date().toLocaleDateString() const date = new Date().toLocaleDateString()
@@ -335,15 +360,15 @@ const copyRequest = () => {
.share({ .share({
title: "Hoppscotch", title: "Hoppscotch",
text: `Hoppscotch • Open source API development ecosystem at ${time} on ${date}`, text: `Hoppscotch • Open source API development ecosystem at ${time} on ${date}`,
url: window.location.href, url: `https://hopp.sh/r${shareLink}`,
}) })
.then(() => {}) .then(() => {})
.catch(() => {}) .catch(() => {})
} else { } else {
copyToClipboard(window.location.href) copyLinkIcon.value = "check"
$toast.success(`${t("state.copied_to_clipboard")}`, { copyToClipboard(`https://hopp.sh/r${shareLink}`)
icon: "content_paste", toast.success(`${t("state.copied_to_clipboard")}`)
}) setTimeout(() => (copyLinkIcon.value = "copy"), 2000)
} }
} }
@@ -382,9 +407,7 @@ const saveRequest = () => {
if (saveCtx.originLocation === "user-collection") { if (saveCtx.originLocation === "user-collection") {
editRESTRequest(saveCtx.folderPath, saveCtx.requestIndex, getRESTRequest()) editRESTRequest(saveCtx.folderPath, saveCtx.requestIndex, getRESTRequest())
$toast.success(`${t("request.saved")}`, { toast.success(`${t("request.saved")}`)
icon: "playlist_add_check",
})
} else if (saveCtx.originLocation === "team-collection") { } else if (saveCtx.originLocation === "team-collection") {
const req = getRESTRequest() const req = getRESTRequest()
@@ -397,20 +420,14 @@ const saveRequest = () => {
saveCtx.requestID saveCtx.requestID
) )
.then(() => { .then(() => {
$toast.success(`${t("request.saved")}`, { toast.success(`${t("request.saved")}`)
icon: "playlist_add_check",
})
}) })
.catch(() => { .catch(() => {
$toast.error(t("profile.no_permission").toString(), { toast.error(`${t("profile.no_permission")}`)
icon: "error_outline",
})
}) })
} catch (error) { } catch (error) {
showSaveRequestModal.value = true showSaveRequestModal.value = true
$toast.error(t("error.something_went_wrong").toString(), { toast.error(`${t("error.something_went_wrong")}`)
icon: "error_outline",
})
console.error(error) console.error(error)
} }
} }

View File

@@ -1,27 +1,24 @@
<template> <template>
<div class="bg-primary flex p-4 top-0 z-10 sticky items-center"> <div
class="bg-primary hide-scrollbar whitespace-nowrap sticky top-0 z-10 flex items-center p-4 overflow-auto"
>
<div <div
v-if="response == null" v-if="response == null"
class=" class="text-secondaryLight flex flex-col items-center justify-center flex-1"
flex flex-col flex-1
text-secondaryLight
items-center
justify-center
"
> >
<div class="flex space-x-2 pb-4 my-4"> <div class="flex pb-4 my-4 space-x-2">
<div class="flex flex-col space-y-4 text-right items-end"> <div class="flex flex-col items-end space-y-4 text-right">
<span class="flex flex-1 items-center"> <span class="flex items-center flex-1">
{{ $t("shortcut.request.send_request") }} {{ t("shortcut.request.send_request") }}
</span> </span>
<span class="flex flex-1 items-center"> <span class="flex items-center flex-1">
{{ $t("shortcut.general.show_all") }} {{ t("shortcut.general.show_all") }}
</span> </span>
<span class="flex flex-1 items-center"> <span class="flex items-center flex-1">
{{ $t("shortcut.general.command_menu") }} {{ t("shortcut.general.command_menu") }}
</span> </span>
<span class="flex flex-1 items-center"> <span class="flex items-center flex-1">
{{ $t("shortcut.general.help_menu") }} {{ t("shortcut.general.help_menu") }}
</span> </span>
</div> </div>
<div class="flex flex-col space-y-4"> <div class="flex flex-col space-y-4">
@@ -42,8 +39,8 @@
</div> </div>
</div> </div>
<ButtonSecondary <ButtonSecondary
:label="$t('app.documentation')" :label="t('app.documentation')"
to="https://docs.hoppscotch.io" to="https://docs.hoppscotch.io/features/response"
svg="external-link" svg="external-link"
blank blank
outline outline
@@ -56,48 +53,41 @@
class="flex flex-col items-center justify-center" class="flex flex-col items-center justify-center"
> >
<SmartSpinner class="my-4" /> <SmartSpinner class="my-4" />
<span class="text-secondaryLight">{{ $t("state.loading") }}</span> <span class="text-secondaryLight">{{ t("state.loading") }}</span>
</div> </div>
<div <div
v-if="response.type === 'network_fail'" v-if="response.type === 'network_fail'"
class="flex flex-col flex-1 p-4 items-center justify-center" class="flex flex-col items-center justify-center flex-1 p-4"
> >
<img <img
:src="`/images/states/${$colorMode.value}/youre_lost.svg`" :src="`/images/states/${$colorMode.value}/youre_lost.svg`"
loading="lazy" loading="lazy"
class=" class="inline-flex flex-col object-contain object-center w-32 h-32 my-4"
flex-col :alt="`${t('error.network_fail')}`"
my-4
object-contain object-center
h-32
w-32
inline-flex
"
:alt="$t('empty.network_fail')"
/> />
<span class="text-center font-semibold mb-2"> <span class="mb-2 font-semibold text-center">
{{ $t("error.network_fail") }} {{ t("error.network_fail") }}
</span> </span>
<span class="text-center text-secondaryLight mb-4 max-w-sm"> <span class="text-secondaryLight max-w-sm mb-4 text-center">
{{ $t("helpers.network_fail") }} {{ t("helpers.network_fail") }}
</span> </span>
<AppInterceptor /> <AppInterceptor />
</div> </div>
<div <div
v-if="response.type === 'success' || 'fail'" v-if="response.type === 'success' || 'fail'"
:class="statusCategory.className" :class="statusCategory.className"
class="font-semibold space-x-4" class="space-x-4 font-semibold"
> >
<span v-if="response.statusCode"> <span v-if="response.statusCode">
<span class="text-secondary"> {{ $t("response.status") }}: </span> <span class="text-secondary"> {{ t("response.status") }}: </span>
{{ response.statusCode || $t("state.waiting_send_request") }} {{ response.statusCode || t("state.waiting_send_request") }}
</span> </span>
<span v-if="response.meta && response.meta.responseDuration"> <span v-if="response.meta && response.meta.responseDuration">
<span class="text-secondary"> {{ $t("response.time") }}: </span> <span class="text-secondary"> {{ t("response.time") }}: </span>
{{ `${response.meta.responseDuration} ms` }} {{ `${response.meta.responseDuration} ms` }}
</span> </span>
<span v-if="response.meta && response.meta.responseSize"> <span v-if="response.meta && response.meta.responseSize">
<span class="text-secondary"> {{ $t("response.size") }}: </span> <span class="text-secondary"> {{ t("response.size") }}: </span>
{{ `${response.meta.responseSize} B` }} {{ `${response.meta.responseSize} B` }}
</span> </span>
</div> </div>
@@ -110,6 +100,9 @@ import { computed } from "@nuxtjs/composition-api"
import findStatusGroup from "~/helpers/findStatusGroup" import findStatusGroup from "~/helpers/findStatusGroup"
import { HoppRESTResponse } from "~/helpers/types/HoppRESTResponse" import { HoppRESTResponse } from "~/helpers/types/HoppRESTResponse"
import { getPlatformSpecialKey as getSpecialKey } from "~/helpers/platformutils" import { getPlatformSpecialKey as getSpecialKey } from "~/helpers/platformutils"
import { useI18n } from "~/helpers/utils/composables"
const t = useI18n()
const props = defineProps<{ const props = defineProps<{
response: HoppRESTResponse response: HoppRESTResponse

View File

@@ -1,5 +1,5 @@
<template> <template>
<AppSection :label="`${$t('test.results')}`"> <AppSection :label="`${t('test.results')}`">
<div <div
v-if=" v-if="
testResults && testResults &&
@@ -7,24 +7,14 @@
" "
> >
<div <div
class=" class="bg-primary border-dividerLight top-lowerSecondaryStickyFold sticky z-10 flex items-center justify-between flex-1 pl-4 border-b"
bg-primary
border-dividerLight border-b
flex flex-1
top-lowerSecondaryStickyFold
pl-4
z-10
sticky
items-center
justify-between
"
> >
<label class="font-semibold text-secondaryLight"> <label class="text-secondaryLight font-semibold">
{{ $t("test.report") }} {{ t("test.report") }}
</label> </label>
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('action.clear')" :title="t('action.clear')"
svg="trash-2" svg="trash-2"
@click.native="clearContent()" @click.native="clearContent()"
/> />
@@ -48,10 +38,10 @@
<div <div
v-for="(result, index) in testResults.expectResults" v-for="(result, index) in testResults.expectResults"
:key="`result-${index}`" :key="`result-${index}`"
class="flex py-2 px-4 items-center" class="flex items-center px-4 py-2"
> >
<i <i
class="mr-4 material-icons" class="material-icons mr-4"
:class=" :class="
result.status === 'pass' ? 'text-green-500' : 'text-red-500' result.status === 'pass' ? 'text-green-500' : 'text-red-500'
" "
@@ -64,9 +54,7 @@
<span class="text-secondaryLight"> <span class="text-secondaryLight">
{{ {{
` \xA0 — \xA0 ${ ` \xA0 — \xA0 ${
result.status === "pass" result.status === "pass" ? t("test.passed") : t("test.failed")
? $t("test.passed")
: $t("test.failed")
}` }`
}} }}
</span> </span>
@@ -76,24 +64,24 @@
</div> </div>
<div <div
v-else v-else
class="flex flex-col text-secondaryLight p-4 items-center justify-center" class="text-secondaryLight flex flex-col items-center justify-center p-4"
> >
<img <img
:src="`/images/states/${$colorMode.value}/validation.svg`" :src="`/images/states/${$colorMode.value}/validation.svg`"
loading="lazy" loading="lazy"
class="flex-col my-4 object-contain object-center h-16 w-16 inline-flex" class="inline-flex flex-col object-contain object-center w-16 h-16 my-4"
:alt="$t('empty.tests')" :alt="`${t('empty.tests')}`"
/> />
<span class="text-center pb-2"> <span class="pb-2 text-center">
{{ $t("empty.tests") }} {{ t("empty.tests") }}
</span> </span>
<span class="text-center pb-4"> <span class="pb-4 text-center">
{{ $t("helpers.tests") }} {{ t("helpers.tests") }}
</span> </span>
<ButtonSecondary <ButtonSecondary
outline outline
:label="`${$t('action.learn_more')}`" :label="`${t('action.learn_more')}`"
to="https://docs.hoppscotch.io" to="https://docs.hoppscotch.io/features/tests"
blank blank
svg="external-link" svg="external-link"
reverse reverse
@@ -104,9 +92,11 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { useReadonlyStream } from "~/helpers/utils/composables" import { useReadonlyStream, useI18n } from "~/helpers/utils/composables"
import { restTestResults$, setRESTTestResults } from "~/newstore/RESTSession" import { restTestResults$, setRESTTestResults } from "~/newstore/RESTSession"
const t = useI18n()
const testResults = useReadonlyStream(restTestResults$, null) const testResults = useReadonlyStream(restTestResults$, null)
const clearContent = () => setRESTTestResults(null) const clearContent = () => setRESTTestResults(null)

View File

@@ -2,11 +2,11 @@
<div> <div>
<span <span
v-if="testResults.description" v-if="testResults.description"
class="flex font-bold text-secondaryDark py-2 px-4 items-center" class="flex items-center px-4 py-2 font-bold text-secondaryDark"
> >
{{ testResults.description }} {{ testResults.description }}
</span> </span>
<div v-if="testResults.expectResults" class="divide-y divide-dividerLight"> <div v-if="testResults.expectResults" class="divide-dividerLight divide-y">
<HttpTestResultReport <HttpTestResultReport
v-if="testResults.expectResults.length" v-if="testResults.expectResults.length"
:test-results="testResults" :test-results="testResults"
@@ -14,7 +14,7 @@
<div <div
v-for="(result, index) in testResults.expectResults" v-for="(result, index) in testResults.expectResults"
:key="`result-${index}`" :key="`result-${index}`"
class="flex py-2 px-4 items-center" class="flex items-center px-4 py-2"
> >
<i <i
class="mr-4 material-icons" class="mr-4 material-icons"

View File

@@ -1,5 +1,5 @@
<template> <template>
<div class="flex p-2 items-center"> <div class="flex items-center p-2">
<SmartProgressRing <SmartProgressRing
class="text-red-500" class="text-red-500"
:radius="16" :radius="16"

View File

@@ -1,71 +1,51 @@
<template> <template>
<AppSection id="script" :label="`${$t('test.script')}`"> <AppSection id="script" :label="`${t('test.script')}`">
<div <div
class=" class="bg-primary border-dividerLight top-upperSecondaryStickyFold sticky z-10 flex items-center justify-between flex-1 pl-4 border-b"
bg-primary
border-b border-dividerLight
flex flex-1
top-upperSecondaryStickyFold
pl-4
z-10
sticky
items-center
justify-between
"
> >
<label class="font-semibold text-secondaryLight"> <label class="text-secondaryLight font-semibold">
{{ $t("test.javascript_code") }} {{ t("test.javascript_code") }}
</label> </label>
<div class="flex"> <div class="flex">
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
to="https://docs.hoppscotch.io/features/tests" to="https://docs.hoppscotch.io/features/tests"
blank blank
:title="$t('app.wiki')" :title="t('app.wiki')"
svg="help-circle" svg="help-circle"
/> />
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('state.linewrap')" :title="t('state.linewrap')"
:class="{ '!text-accent': linewrapEnabled }" :class="{ '!text-accent': linewrapEnabled }"
svg="corner-down-left" svg="corner-down-left"
@click.native.prevent="linewrapEnabled = !linewrapEnabled" @click.native.prevent="linewrapEnabled = !linewrapEnabled"
/> />
<ButtonSecondary <ButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('action.clear')" :title="t('action.clear')"
svg="trash-2" svg="trash-2"
@click.native="clearContent" @click.native="clearContent"
/> />
</div> </div>
</div> </div>
<div class="border-b border-dividerLight flex"> <div class="border-dividerLight flex border-b">
<div class="border-r border-dividerLight w-2/3"> <div class="border-dividerLight w-2/3 border-r">
<div ref="testScriptEditor"></div> <div ref="testScriptEditor"></div>
</div> </div>
<div <div
class=" class="bg-primary top-upperTertiaryStickyFold min-w-46 max-w-1/3 z-9 sticky h-full p-4 overflow-auto"
bg-primary
h-full
top-upperTertiaryStickyFold
min-w-46
max-w-1/3
p-4
z-9
sticky
overflow-auto
"
> >
<div class="text-secondaryLight pb-2"> <div class="text-secondaryLight pb-2">
{{ $t("helpers.post_request_tests") }} {{ t("helpers.post_request_tests") }}
</div> </div>
<SmartAnchor <SmartAnchor
:label="`${$t('test.learn')}`" :label="`${t('test.learn')}`"
to="https://docs.hoppscotch.io/features/tests" to="https://docs.hoppscotch.io/features/tests"
blank blank
/> />
<h4 class="font-bold text-secondaryLight pt-6"> <h4 class="text-secondaryLight pt-6 font-bold">
{{ $t("test.snippets") }} {{ t("test.snippets") }}
</h4> </h4>
<div class="flex flex-col pt-4"> <div class="flex flex-col pt-4">
<TabSecondary <TabSecondary
@@ -82,17 +62,15 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { reactive, ref, useContext } from "@nuxtjs/composition-api" import { reactive, ref } from "@nuxtjs/composition-api"
import { useTestScript } from "~/newstore/RESTSession" import { useTestScript } from "~/newstore/RESTSession"
import testSnippets from "~/helpers/testSnippets" import testSnippets from "~/helpers/testSnippets"
import { useCodemirror } from "~/helpers/editor/codemirror" import { useCodemirror } from "~/helpers/editor/codemirror"
import linter from "~/helpers/editor/linting/testScript" import linter from "~/helpers/editor/linting/testScript"
import completer from "~/helpers/editor/completion/testScript" import completer from "~/helpers/editor/completion/testScript"
import { useI18n } from "~/helpers/utils/composables"
const { const t = useI18n()
app: { i18n },
} = useContext()
const t = i18n.t.bind(i18n)
const testScript = useTestScript() const testScript = useTestScript()

View File

@@ -1,27 +1,17 @@
<template> <template>
<div> <div>
<div <div
class=" class="bg-primary border-dividerLight top-lowerSecondaryStickyFold sticky z-10 flex items-center justify-between flex-1 pl-4 border-b"
bg-primary
border-b border-dividerLight
flex flex-1
top-lowerSecondaryStickyFold
pl-4
z-10
sticky
items-center
justify-between
"
> >
<label class="font-semibold text-secondaryLight"> <label class="text-secondaryLight font-semibold">
{{ $t("request.header_list") }} {{ t("request.header_list") }}
</label> </label>
<div class="flex"> <div class="flex">
<ButtonSecondary <ButtonSecondary
v-if="headers" v-if="headers"
ref="copyHeaders" ref="copyHeaders"
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('action.copy')" :title="t('action.copy')"
:svg="copyIcon" :svg="copyIcon"
@click.native="copyHeaders" @click.native="copyHeaders"
/> />
@@ -30,38 +20,19 @@
<div <div
v-for="(header, index) in headers" v-for="(header, index) in headers"
:key="`header-${index}`" :key="`header-${index}`"
class=" class="divide-dividerLight border-dividerLight group flex border-b divide-x"
divide-x divide-dividerLight
border-b border-dividerLight
flex
group
"
> >
<span <span
class=" class="group-hover:text-secondaryDark flex flex-1 min-w-0 px-4 py-2 transition"
flex flex-1
min-w-0
py-2
px-4
transition
group-hover:text-secondaryDark
"
> >
<span class="rounded-sm select-all truncate"> <span class="truncate rounded-sm select-all">
{{ header.key }} {{ header.key }}
</span> </span>
</span> </span>
<span <span
class=" class="group-hover:text-secondaryDark flex flex-1 min-w-0 px-4 py-2 transition"
flex flex-1
min-w-0
py-2
px-4
transition
group-hover:text-secondaryDark
"
> >
<span class="rounded-sm select-all truncate"> <span class="truncate rounded-sm select-all">
{{ header.value }} {{ header.value }}
</span> </span>
</span> </span>
@@ -69,28 +40,26 @@
</div> </div>
</template> </template>
<script> <script setup lang="ts">
import { defineComponent } from "@nuxtjs/composition-api" import { ref } from "@nuxtjs/composition-api"
import { HoppRESTHeader } from "~/helpers/types/HoppRESTRequest"
import { copyToClipboard } from "~/helpers/utils/clipboard" import { copyToClipboard } from "~/helpers/utils/clipboard"
import { useI18n, useToast } from "~/helpers/utils/composables"
export default defineComponent({ const t = useI18n()
props: {
headers: { type: Array, default: () => [] }, const toast = useToast()
},
data() { const props = defineProps<{
return { headers: Array<HoppRESTHeader>
copyIcon: "copy", }>()
}
}, const copyIcon = ref("copy")
methods: {
copyHeaders() { const copyHeaders = () => {
copyToClipboard(JSON.stringify(this.headers)) copyToClipboard(JSON.stringify(props.headers))
this.copyIcon = "check" copyIcon.value = "check"
this.$toast.success(this.$t("state.copied_to_clipboard"), { toast.success(`${t("state.copied_to_clipboard")}`)
icon: "content_paste", setTimeout(() => (copyIcon.value = "copy"), 1000)
}) }
setTimeout(() => (this.copyIcon = "copy"), 1000)
},
},
})
</script> </script>

View File

@@ -1,26 +1,16 @@
<template> <template>
<div class="flex flex-col flex-1"> <div class="flex flex-col flex-1">
<div <div
class=" class="bg-primary border-dividerLight top-lowerSecondaryStickyFold sticky z-10 flex items-center justify-between flex-1 pl-4 border-b"
bg-primary
border-b border-dividerLight
flex flex-1
top-lowerSecondaryStickyFold
pl-4
z-10
sticky
items-center
justify-between
"
> >
<label class="font-semibold text-secondaryLight"> <label class="text-secondaryLight font-semibold">
{{ $t("response.body") }} {{ t("response.body") }}
</label> </label>
<div class="flex"> <div class="flex">
<ButtonSecondary <ButtonSecondary
v-if="response.body" v-if="response.body"
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('state.linewrap')" :title="t('state.linewrap')"
:class="{ '!text-accent': linewrapEnabled }" :class="{ '!text-accent': linewrapEnabled }"
svg="corner-down-left" svg="corner-down-left"
@click.native.prevent="linewrapEnabled = !linewrapEnabled" @click.native.prevent="linewrapEnabled = !linewrapEnabled"
@@ -29,7 +19,7 @@
v-if="response.body" v-if="response.body"
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title=" :title="
previewEnabled ? $t('hide.preview') : $t('response.preview_html') previewEnabled ? t('hide.preview') : t('response.preview_html')
" "
:svg="!previewEnabled ? 'eye' : 'eye-off'" :svg="!previewEnabled ? 'eye' : 'eye-off'"
@click.native.prevent="togglePreview" @click.native.prevent="togglePreview"
@@ -38,7 +28,7 @@
v-if="response.body" v-if="response.body"
ref="downloadResponse" ref="downloadResponse"
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('action.download_file')" :title="t('action.download_file')"
:svg="downloadIcon" :svg="downloadIcon"
@click.native="downloadResponse" @click.native="downloadResponse"
/> />
@@ -46,7 +36,7 @@
v-if="response.body" v-if="response.body"
ref="copyResponse" ref="copyResponse"
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('action.copy')" :title="t('action.copy')"
:svg="copyIcon" :svg="copyIcon"
@click.native="copyResponse" @click.native="copyResponse"
/> />
@@ -64,20 +54,19 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed, ref, useContext, reactive } from "@nuxtjs/composition-api" import { computed, ref, reactive } from "@nuxtjs/composition-api"
import { useCodemirror } from "~/helpers/editor/codemirror" import { useCodemirror } from "~/helpers/editor/codemirror"
import { copyToClipboard } from "~/helpers/utils/clipboard" import { copyToClipboard } from "~/helpers/utils/clipboard"
import { HoppRESTResponse } from "~/helpers/types/HoppRESTResponse" import { HoppRESTResponse } from "~/helpers/types/HoppRESTResponse"
import { useI18n, useToast } from "~/helpers/utils/composables"
const t = useI18n()
const props = defineProps<{ const props = defineProps<{
response: HoppRESTResponse response: HoppRESTResponse
}>() }>()
const { const toast = useToast()
$toast,
app: { i18n },
} = useContext()
const t = i18n.t.bind(i18n)
const responseBodyText = computed(() => { const responseBodyText = computed(() => {
if ( if (
@@ -127,9 +116,7 @@ const downloadResponse = () => {
document.body.appendChild(a) document.body.appendChild(a)
a.click() a.click()
downloadIcon.value = "check" downloadIcon.value = "check"
$toast.success(`${t("state.download_started")}`, { toast.success(`${t("state.download_started")}`)
icon: "downloading",
})
setTimeout(() => { setTimeout(() => {
document.body.removeChild(a) document.body.removeChild(a)
URL.revokeObjectURL(url) URL.revokeObjectURL(url)
@@ -140,9 +127,7 @@ const downloadResponse = () => {
const copyResponse = () => { const copyResponse = () => {
copyToClipboard(responseBodyText.value) copyToClipboard(responseBodyText.value)
copyIcon.value = "check" copyIcon.value = "check"
$toast.success(`${t("state.copied_to_clipboard")}`, { toast.success(`${t("state.copied_to_clipboard")}`)
icon: "content_paste",
})
setTimeout(() => (copyIcon.value = "copy"), 1000) setTimeout(() => (copyIcon.value = "copy"), 1000)
} }

View File

@@ -1,19 +1,9 @@
<template> <template>
<div> <div>
<div <div
class=" class="bg-primary border-dividerLight top-lowerSecondaryStickyFold sticky z-10 flex items-center justify-between flex-1 pl-4 border-b"
bg-primary
border-b border-dividerLight
flex flex-1
top-lowerSecondaryStickyFold
pl-4
z-10
sticky
items-center
justify-between
"
> >
<label class="font-semibold text-secondaryLight"> <label class="text-secondaryLight font-semibold">
{{ $t("response.body") }} {{ $t("response.body") }}
</label> </label>
<div class="flex"> <div class="flex">
@@ -28,7 +18,7 @@
</div> </div>
</div> </div>
<img <img
class="border-b border-dividerLight flex max-w-full flex-1" class="border-dividerLight flex flex-1 max-w-full border-b"
:src="imageSource" :src="imageSource"
loading="lazy" loading="lazy"
:alt="imageSource" :alt="imageSource"
@@ -103,9 +93,7 @@ export default defineComponent({
document.body.appendChild(a) document.body.appendChild(a)
a.click() a.click()
this.downloadIcon = "check" this.downloadIcon = "check"
this.$toast.success(this.$t("state.download_started"), { this.$toast.success(this.$t("state.download_started"))
icon: "downloading",
})
setTimeout(() => { setTimeout(() => {
document.body.removeChild(a) document.body.removeChild(a)
URL.revokeObjectURL(url) URL.revokeObjectURL(url)

View File

@@ -1,26 +1,16 @@
<template> <template>
<div> <div>
<div <div
class=" class="bg-primary border-dividerLight top-lowerSecondaryStickyFold sticky z-10 flex items-center justify-between flex-1 pl-4 border-b"
bg-primary
border-b border-dividerLight
flex flex-1
top-lowerSecondaryStickyFold
pl-4
z-10
sticky
items-center
justify-between
"
> >
<label class="font-semibold text-secondaryLight">{{ <label class="text-secondaryLight font-semibold">{{
$t("response.body") t("response.body")
}}</label> }}</label>
<div class="flex"> <div class="flex">
<ButtonSecondary <ButtonSecondary
v-if="response.body" v-if="response.body"
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('state.linewrap')" :title="t('state.linewrap')"
:class="{ '!text-accent': linewrapEnabled }" :class="{ '!text-accent': linewrapEnabled }"
svg="corner-down-left" svg="corner-down-left"
@click.native.prevent="linewrapEnabled = !linewrapEnabled" @click.native.prevent="linewrapEnabled = !linewrapEnabled"
@@ -29,7 +19,7 @@
v-if="response.body" v-if="response.body"
ref="downloadResponse" ref="downloadResponse"
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('action.download_file')" :title="t('action.download_file')"
:svg="downloadIcon" :svg="downloadIcon"
@click.native="downloadResponse" @click.native="downloadResponse"
/> />
@@ -37,7 +27,7 @@
v-if="response.body" v-if="response.body"
ref="copyResponse" ref="copyResponse"
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('action.copy')" :title="t('action.copy')"
:svg="copyIcon" :svg="copyIcon"
@click.native="copyResponse" @click.native="copyResponse"
/> />
@@ -46,17 +36,7 @@
<div ref="jsonResponse"></div> <div ref="jsonResponse"></div>
<div <div
v-if="outlinePath" v-if="outlinePath"
class=" class="bg-primaryLight border-dividerLight flex-nowrap hide-scrollbar sticky bottom-0 z-10 flex flex-1 px-2 overflow-auto border-t"
bg-primaryLight
border-t border-dividerLight
flex flex-nowrap flex-1
px-2
bottom-0
z-10
sticky
overflow-auto
hide-scrollbar
"
> >
<div <div
v-for="(item, index) in outlinePath" v-for="(item, index) in outlinePath"
@@ -135,7 +115,7 @@
</tippy> </tippy>
<i <i
v-if="index + 1 !== outlinePath.length" v-if="index + 1 !== outlinePath.length"
class="text-secondaryLight opacity-50 material-icons" class="text-secondaryLight material-icons opacity-50"
>chevron_right</i >chevron_right</i
> >
</div> </div>
@@ -144,7 +124,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed, ref, useContext, reactive } from "@nuxtjs/composition-api" import { computed, ref, reactive } from "@nuxtjs/composition-api"
import { useCodemirror } from "~/helpers/editor/codemirror" import { useCodemirror } from "~/helpers/editor/codemirror"
import { copyToClipboard } from "~/helpers/utils/clipboard" import { copyToClipboard } from "~/helpers/utils/clipboard"
import { HoppRESTResponse } from "~/helpers/types/HoppRESTResponse" import { HoppRESTResponse } from "~/helpers/types/HoppRESTResponse"
@@ -154,16 +134,15 @@ import {
convertIndexToLineCh, convertIndexToLineCh,
convertLineChToIndex, convertLineChToIndex,
} from "~/helpers/editor/utils" } from "~/helpers/editor/utils"
import { useI18n, useToast } from "~/helpers/utils/composables"
const t = useI18n()
const props = defineProps<{ const props = defineProps<{
response: HoppRESTResponse response: HoppRESTResponse
}>() }>()
const { const toast = useToast()
$toast,
app: { i18n },
} = useContext()
const t = i18n.t.bind(i18n)
const responseBodyText = computed(() => { const responseBodyText = computed(() => {
if ( if (
@@ -234,9 +213,7 @@ const downloadResponse = () => {
document.body.appendChild(a) document.body.appendChild(a)
a.click() a.click()
downloadIcon.value = "check" downloadIcon.value = "check"
$toast.success(`${t("state.download_started")}`, { toast.success(`${t("state.download_started")}`)
icon: "downloading",
})
setTimeout(() => { setTimeout(() => {
document.body.removeChild(a) document.body.removeChild(a)
URL.revokeObjectURL(url) URL.revokeObjectURL(url)
@@ -256,9 +233,7 @@ const outlinePath = computed(() => {
const copyResponse = () => { const copyResponse = () => {
copyToClipboard(responseBodyText.value) copyToClipboard(responseBodyText.value)
copyIcon.value = "check" copyIcon.value = "check"
$toast.success(`${t("state.copied_to_clipboard")}`, { toast.success(`${t("state.copied_to_clipboard")}`)
icon: "content_paste",
})
setTimeout(() => (copyIcon.value = "copy"), 1000) setTimeout(() => (copyIcon.value = "copy"), 1000)
} }
</script> </script>

View File

@@ -1,26 +1,16 @@
<template> <template>
<div> <div>
<div <div
class=" class="bg-primary border-dividerLight top-lowerSecondaryStickyFold sticky z-10 flex items-center justify-between flex-1 pl-4 border-b"
bg-primary
border-b border-dividerLight
flex flex-1
top-lowerSecondaryStickyFold
pl-4
z-10
sticky
items-center
justify-between
"
> >
<label class="font-semibold text-secondaryLight"> <label class="text-secondaryLight font-semibold">
{{ $t("response.body") }} {{ t("response.body") }}
</label> </label>
<div class="flex"> <div class="flex">
<ButtonSecondary <ButtonSecondary
v-if="response.body" v-if="response.body"
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('state.linewrap')" :title="t('state.linewrap')"
:class="{ '!text-accent': linewrapEnabled }" :class="{ '!text-accent': linewrapEnabled }"
svg="corner-down-left" svg="corner-down-left"
@click.native.prevent="linewrapEnabled = !linewrapEnabled" @click.native.prevent="linewrapEnabled = !linewrapEnabled"
@@ -29,7 +19,7 @@
v-if="response.body" v-if="response.body"
ref="downloadResponse" ref="downloadResponse"
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('action.download_file')" :title="t('action.download_file')"
:svg="downloadIcon" :svg="downloadIcon"
@click.native="downloadResponse" @click.native="downloadResponse"
/> />
@@ -37,7 +27,7 @@
v-if="response.body" v-if="response.body"
ref="copyResponse" ref="copyResponse"
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('action.copy')" :title="t('action.copy')"
:svg="copyIcon" :svg="copyIcon"
@click.native="copyResponse" @click.native="copyResponse"
/> />
@@ -48,20 +38,19 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, useContext, computed, reactive } from "@nuxtjs/composition-api" import { ref, computed, reactive } from "@nuxtjs/composition-api"
import { useCodemirror } from "~/helpers/editor/codemirror" import { useCodemirror } from "~/helpers/editor/codemirror"
import { copyToClipboard } from "~/helpers/utils/clipboard" import { copyToClipboard } from "~/helpers/utils/clipboard"
import { HoppRESTResponse } from "~/helpers/types/HoppRESTResponse" import { HoppRESTResponse } from "~/helpers/types/HoppRESTResponse"
import { useI18n, useToast } from "~/helpers/utils/composables"
const t = useI18n()
const props = defineProps<{ const props = defineProps<{
response: HoppRESTResponse response: HoppRESTResponse
}>() }>()
const { const toast = useToast()
$toast,
app: { i18n },
} = useContext()
const t = i18n.t.bind(i18n)
const responseBodyText = computed(() => { const responseBodyText = computed(() => {
if ( if (
@@ -117,9 +106,7 @@ const downloadResponse = () => {
document.body.appendChild(a) document.body.appendChild(a)
a.click() a.click()
downloadIcon.value = "check" downloadIcon.value = "check"
$toast.success(`${t("state.download_started")}`, { toast.success(`${t("state.download_started")}`)
icon: "downloading",
})
setTimeout(() => { setTimeout(() => {
document.body.removeChild(a) document.body.removeChild(a)
URL.revokeObjectURL(url) URL.revokeObjectURL(url)
@@ -130,9 +117,7 @@ const downloadResponse = () => {
const copyResponse = () => { const copyResponse = () => {
copyToClipboard(responseBodyText.value) copyToClipboard(responseBodyText.value)
copyIcon.value = "check" copyIcon.value = "check"
$toast.success(`${t("state.copied_to_clipboard")}`, { toast.success(`${t("state.copied_to_clipboard")}`)
icon: "content_paste",
})
setTimeout(() => (copyIcon.value = "copy"), 1000) setTimeout(() => (copyIcon.value = "copy"), 1000)
} }
</script> </script>

View File

@@ -1,26 +1,16 @@
<template> <template>
<div> <div>
<div <div
class=" class="bg-primary border-dividerLight top-lowerSecondaryStickyFold sticky z-10 flex items-center justify-between flex-1 pl-4 border-b"
bg-primary
border-b border-dividerLight
flex flex-1
top-lowerSecondaryStickyFold
pl-4
z-10
sticky
items-center
justify-between
"
> >
<label class="font-semibold text-secondaryLight"> <label class="text-secondaryLight font-semibold">
{{ $t("response.body") }} {{ t("response.body") }}
</label> </label>
<div class="flex"> <div class="flex">
<ButtonSecondary <ButtonSecondary
v-if="response.body" v-if="response.body"
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('state.linewrap')" :title="t('state.linewrap')"
:class="{ '!text-accent': linewrapEnabled }" :class="{ '!text-accent': linewrapEnabled }"
svg="corner-down-left" svg="corner-down-left"
@click.native.prevent="linewrapEnabled = !linewrapEnabled" @click.native.prevent="linewrapEnabled = !linewrapEnabled"
@@ -29,7 +19,7 @@
v-if="response.body" v-if="response.body"
ref="downloadResponse" ref="downloadResponse"
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('action.download_file')" :title="t('action.download_file')"
:svg="downloadIcon" :svg="downloadIcon"
@click.native="downloadResponse" @click.native="downloadResponse"
/> />
@@ -37,7 +27,7 @@
v-if="response.body" v-if="response.body"
ref="copyResponse" ref="copyResponse"
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t('action.copy')" :title="t('action.copy')"
:svg="copyIcon" :svg="copyIcon"
@click.native="copyResponse" @click.native="copyResponse"
/> />
@@ -48,20 +38,19 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed, ref, useContext, reactive } from "@nuxtjs/composition-api" import { computed, ref, reactive } from "@nuxtjs/composition-api"
import { useCodemirror } from "~/helpers/editor/codemirror" import { useCodemirror } from "~/helpers/editor/codemirror"
import { copyToClipboard } from "~/helpers/utils/clipboard" import { copyToClipboard } from "~/helpers/utils/clipboard"
import { HoppRESTResponse } from "~/helpers/types/HoppRESTResponse" import { HoppRESTResponse } from "~/helpers/types/HoppRESTResponse"
import { useI18n, useToast } from "~/helpers/utils/composables"
const t = useI18n()
const props = defineProps<{ const props = defineProps<{
response: HoppRESTResponse response: HoppRESTResponse
}>() }>()
const { const toast = useToast()
$toast,
app: { i18n },
} = useContext()
const t = i18n.t.bind(i18n)
const responseBodyText = computed(() => { const responseBodyText = computed(() => {
if ( if (
@@ -117,9 +106,7 @@ const downloadResponse = () => {
document.body.appendChild(a) document.body.appendChild(a)
a.click() a.click()
downloadIcon.value = "check" downloadIcon.value = "check"
$toast.success(`${t("state.download_started")}`, { toast.success(`${t("state.download_started")}`)
icon: "downloading",
})
setTimeout(() => { setTimeout(() => {
document.body.removeChild(a) document.body.removeChild(a)
URL.revokeObjectURL(url) URL.revokeObjectURL(url)
@@ -130,9 +117,7 @@ const downloadResponse = () => {
const copyResponse = () => { const copyResponse = () => {
copyToClipboard(responseBodyText.value) copyToClipboard(responseBodyText.value)
copyIcon.value = "check" copyIcon.value = "check"
$toast.success(`${t("state.copied_to_clipboard")}`, { toast.success(`${t("state.copied_to_clipboard")}`)
icon: "content_paste",
})
setTimeout(() => (copyIcon.value = "copy"), 1000) setTimeout(() => (copyIcon.value = "copy"), 1000)
} }
</script> </script>

View File

@@ -1,32 +1,15 @@
<template> <template>
<div class="cursor-pointer flex h-5 w-5 relative items-center justify-center"> <div class="relative flex items-center justify-center w-5 h-5 cursor-pointer">
<img <img
class=" class="bg-primaryDark absolute object-cover object-center w-5 h-5 transition rounded-full"
bg-primaryDark bg-primaryLight
rounded-full
object-cover object-center
h-5
transition
w-5
absolute
"
:src="url" :src="url"
:alt="alt" :alt="alt"
loading="lazy" loading="lazy"
/> />
<div class="rounded-full shadow-inner inset-0 absolute"></div> <div class="absolute inset-0 rounded-full shadow-inner"></div>
<span <span
v-if="indicator" v-if="indicator"
class=" class="border-primary rounded-full border-2 h-2.5 -top-0.5 -right-0.5 w-2.5 absolute"
border-primary
rounded-full
border-2
h-2.5
-top-0.5
-right-0.5
w-2.5
absolute
"
:class="indicatorStyles" :class="indicatorStyles"
></span> ></span>
</div> </div>

View File

@@ -1,19 +1,9 @@
<template> <template>
<div class="flex flex-col"> <div class="flex flex-col">
<div <div
class=" class="bg-primary border-dividerLight sticky top-0 z-10 flex items-center justify-between flex-1 pl-4 border-b"
bg-primary
border-b border-dividerLight
flex flex-1
pl-4
top-0
z-10
sticky
items-center
justify-between
"
> >
<label for="log" class="font-semibold text-secondaryLight py-2"> <label for="log" class="text-secondaryLight py-2 font-semibold">
{{ title }} {{ title }}
</label> </label>
</div> </div>
@@ -26,7 +16,7 @@
>{{ entry.ts }}{{ source(entry.source) }}{{ entry.payload }}</span >{{ entry.ts }}{{ source(entry.source) }}{{ entry.payload }}</span
> >
</span> </span>
<span v-else>{{ $t("response.waiting_for_connection") }}</span> <span v-else>{{ t("response.waiting_for_connection") }}</span>
</div> </div>
</div> </div>
</template> </template>
@@ -34,6 +24,9 @@
<script setup lang="ts"> <script setup lang="ts">
import { nextTick, ref, watch } from "@nuxtjs/composition-api" import { nextTick, ref, watch } from "@nuxtjs/composition-api"
import { getSourcePrefix as source } from "~/helpers/utils/string" import { getSourcePrefix as source } from "~/helpers/utils/string"
import { useI18n } from "~/helpers/utils/composables"
const t = useI18n()
const props = defineProps({ const props = defineProps({
log: { type: Array, default: () => [] }, log: { type: Array, default: () => [] },

View File

@@ -9,30 +9,22 @@
> >
<Pane size="75" min-size="65" class="hide-scrollbar !overflow-auto"> <Pane size="75" min-size="65" class="hide-scrollbar !overflow-auto">
<Splitpanes class="smart-splitter" :horizontal="COLUMN_LAYOUT"> <Splitpanes class="smart-splitter" :horizontal="COLUMN_LAYOUT">
<Pane class="hide-scrollbar !overflow-auto"> <Pane
:size="COLUMN_LAYOUT ? 45 : 50"
class="hide-scrollbar !overflow-auto"
>
<AppSection label="request"> <AppSection label="request">
<div <div
class="bg-primary flex flex-col space-y-4 p-4 top-0 z-10 sticky" class="bg-primary sticky top-0 z-10 flex flex-col p-4 space-y-4"
> >
<div class="space-x-2 flex-1 inline-flex"> <div class="inline-flex flex-1 space-x-2">
<input <input
id="mqtt-url" id="mqtt-url"
v-model="url" v-model="url"
type="url" type="url"
autocomplete="off" autocomplete="off"
spellcheck="false" spellcheck="false"
class=" class="bg-primaryLight border-divider text-secondaryDark hover:border-dividerDark focus-visible:bg-transparent focus-visible:border-dividerDark w-full px-4 py-2 border rounded"
bg-primaryLight
border border-divider
rounded
text-secondaryDark
w-full
py-2
px-4
hover:border-dividerDark
focus-visible:bg-transparent
focus-visible:border-dividerDark
"
:placeholder="$t('mqtt.url')" :placeholder="$t('mqtt.url')"
:disabled="connectionState" :disabled="connectionState"
@keyup.enter="validUrl ? toggleConnection() : null" @keyup.enter="validUrl ? toggleConnection() : null"
@@ -71,7 +63,10 @@
</div> </div>
</AppSection> </AppSection>
</Pane> </Pane>
<Pane class="hide-scrollbar !overflow-auto"> <Pane
:size="COLUMN_LAYOUT ? 65 : 50"
class="hide-scrollbar !overflow-auto"
>
<AppSection label="response"> <AppSection label="response">
<RealtimeLog :title="$t('mqtt.log')" :log="log" /> <RealtimeLog :title="$t('mqtt.log')" :log="log" />
</AppSection> </AppSection>
@@ -85,8 +80,8 @@
class="hide-scrollbar !overflow-auto" class="hide-scrollbar !overflow-auto"
> >
<AppSection label="messages"> <AppSection label="messages">
<div class="flex flex-col flex-1 p-4 inline-flex"> <div class="flex inline-flex flex-col flex-1 p-4">
<label for="pub_topic" class="font-semibold text-secondaryLight"> <label for="pub_topic" class="text-secondaryLight font-semibold">
{{ $t("mqtt.topic") }} {{ $t("mqtt.topic") }}
</label> </label>
</div> </div>
@@ -101,12 +96,12 @@
spellcheck="false" spellcheck="false"
/> />
</div> </div>
<div class="flex flex-1 p-4 items-center justify-between"> <div class="flex items-center justify-between flex-1 p-4">
<label for="mqtt-message" class="font-semibold text-secondaryLight"> <label for="mqtt-message" class="text-secondaryLight font-semibold">
{{ $t("mqtt.communication") }} {{ $t("mqtt.communication") }}
</label> </label>
</div> </div>
<div class="flex space-x-2 px-4"> <div class="flex px-4 space-x-2">
<input <input
id="mqtt-message" id="mqtt-message"
v-model="msg" v-model="msg"
@@ -125,19 +120,13 @@
/> />
</div> </div>
<div <div
class=" class="border-dividerLight flex inline-flex flex-col flex-1 p-4 mt-4 border-t"
border-t border-dividerLight
flex flex-col flex-1
mt-4
p-4
inline-flex
"
> >
<label for="sub_topic" class="font-semibold text-secondaryLight"> <label for="sub_topic" class="text-secondaryLight font-semibold">
{{ $t("mqtt.topic") }} {{ $t("mqtt.topic") }}
</label> </label>
</div> </div>
<div class="flex space-x-2 px-4"> <div class="flex px-4 space-x-2">
<input <input
id="sub_topic" id="sub_topic"
v-model="sub_topic" v-model="sub_topic"
@@ -288,9 +277,7 @@ export default defineComponent({
color: "var(--accent-color)", color: "var(--accent-color)",
ts: new Date().toLocaleTimeString(), ts: new Date().toLocaleTimeString(),
}) })
this.$toast.success(this.$t("state.connected"), { this.$toast.success(this.$t("state.connected"))
icon: "sync",
})
}, },
onMessageArrived({ payloadString, destinationName }) { onMessageArrived({ payloadString, destinationName }) {
this.log.push({ this.log.push({
@@ -321,13 +308,9 @@ export default defineComponent({
this.connectingState = false this.connectingState = false
this.connectionState = false this.connectionState = false
if (this.manualDisconnect) { if (this.manualDisconnect) {
this.$toast.error(this.$t("state.disconnected"), { this.$toast.error(this.$t("state.disconnected"))
icon: "sync_disabled",
})
} else { } else {
this.$toast.error(this.$t("error.something_went_wrong"), { this.$toast.error(this.$t("error.something_went_wrong"))
icon: "error_outline",
})
} }
this.manualDisconnect = false this.manualDisconnect = false
this.subscriptionState = false this.subscriptionState = false

View File

@@ -9,10 +9,13 @@
> >
<Pane size="75" min-size="65" class="hide-scrollbar !overflow-auto"> <Pane size="75" min-size="65" class="hide-scrollbar !overflow-auto">
<Splitpanes class="smart-splitter" :horizontal="COLUMN_LAYOUT"> <Splitpanes class="smart-splitter" :horizontal="COLUMN_LAYOUT">
<Pane class="hide-scrollbar !overflow-auto"> <Pane
:size="COLUMN_LAYOUT ? 45 : 50"
class="hide-scrollbar !overflow-auto"
>
<AppSection label="request"> <AppSection label="request">
<div class="bg-primary flex p-4 top-0 z-10 sticky"> <div class="bg-primary sticky top-0 z-10 flex p-4">
<div class="space-x-2 flex-1 inline-flex"> <div class="inline-flex flex-1 space-x-2">
<div class="flex flex-1"> <div class="flex flex-1">
<label for="client-version"> <label for="client-version">
<tippy <tippy
@@ -28,21 +31,7 @@
id="client-version" id="client-version"
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
title="socket.io-client version" title="socket.io-client version"
class=" class="bg-primaryLight border-divider text-secondaryDark w-26 hover:border-dividerDark focus-visible:bg-transparent focus-visible:border-dividerDark flex px-4 py-2 font-semibold border rounded-l cursor-pointer"
bg-primaryLight
border border-divider
rounded-l
cursor-pointer
flex
font-semibold
text-secondaryDark
py-2
px-4
w-26
hover:border-dividerDark
focus-visible:bg-transparent
focus-visible:border-dividerDark
"
:value="`Client ${clientVersion}`" :value="`Client ${clientVersion}`"
readonly readonly
:disabled="connectionState" :disabled="connectionState"
@@ -64,18 +53,7 @@
autocomplete="off" autocomplete="off"
spellcheck="false" spellcheck="false"
:class="{ error: !urlValid }" :class="{ error: !urlValid }"
class=" class="bg-primaryLight border-divider text-secondaryDark hover:border-dividerDark focus-visible:bg-transparent focus-visible:border-dividerDark flex flex-1 w-full px-4 py-2 border"
bg-primaryLight
border border-divider
flex flex-1
text-secondaryDark
w-full
py-2
px-4
hover:border-dividerDark
focus-visible:bg-transparent
focus-visible:border-dividerDark
"
:placeholder="$t('socketio.url')" :placeholder="$t('socketio.url')"
:disabled="connectionState" :disabled="connectionState"
@keyup.enter="urlValid ? toggleConnection() : null" @keyup.enter="urlValid ? toggleConnection() : null"
@@ -83,19 +61,7 @@
<input <input
id="socketio-path" id="socketio-path"
v-model="path" v-model="path"
class=" class="bg-primaryLight border-divider text-secondaryDark hover:border-dividerDark focus-visible:bg-transparent focus-visible:border-dividerDark flex flex-1 w-full px-4 py-2 border rounded-r"
bg-primaryLight
border border-divider
rounded-r
flex flex-1
text-secondaryDark
w-full
py-2
px-4
hover:border-dividerDark
focus-visible:bg-transparent
focus-visible:border-dividerDark
"
spellcheck="false" spellcheck="false"
:disabled="connectionState" :disabled="connectionState"
@keyup.enter="urlValid ? toggleConnection() : null" @keyup.enter="urlValid ? toggleConnection() : null"
@@ -118,7 +84,10 @@
</div> </div>
</AppSection> </AppSection>
</Pane> </Pane>
<Pane class="hide-scrollbar !overflow-auto"> <Pane
:size="COLUMN_LAYOUT ? 65 : 50"
class="hide-scrollbar !overflow-auto"
>
<AppSection label="response"> <AppSection label="response">
<RealtimeLog :title="$t('socketio.log')" :log="communication.log" /> <RealtimeLog :title="$t('socketio.log')" :log="communication.log" />
</AppSection> </AppSection>
@@ -132,8 +101,8 @@
class="hide-scrollbar !overflow-auto" class="hide-scrollbar !overflow-auto"
> >
<AppSection label="messages"> <AppSection label="messages">
<div class="flex flex-col flex-1 p-4 inline-flex"> <div class="flex inline-flex flex-col flex-1 p-4">
<label for="events" class="font-semibold text-secondaryLight"> <label for="events" class="text-secondaryLight font-semibold">
{{ $t("socketio.events") }} {{ $t("socketio.events") }}
</label> </label>
</div> </div>
@@ -149,8 +118,8 @@
:disabled="!connectionState" :disabled="!connectionState"
/> />
</div> </div>
<div class="flex flex-1 p-4 items-center justify-between"> <div class="flex items-center justify-between flex-1 p-4">
<label class="font-semibold text-secondaryLight"> <label class="text-secondaryLight font-semibold">
{{ $t("socketio.communication") }} {{ $t("socketio.communication") }}
</label> </label>
<div class="flex"> <div class="flex">
@@ -163,7 +132,7 @@
/> />
</div> </div>
</div> </div>
<div class="flex flex-col space-y-2 px-4 pb-4"> <div class="flex flex-col px-4 pb-4 space-y-2">
<div <div
v-for="(input, index) of communication.inputs" v-for="(input, index) of communication.inputs"
:key="`input-${index}`" :key="`input-${index}`"
@@ -325,9 +294,7 @@ export default defineComponent({
ts: new Date().toLocaleTimeString(), ts: new Date().toLocaleTimeString(),
}, },
] ]
this.$toast.success(this.$t("state.connected"), { this.$toast.success(this.$t("state.connected"))
icon: "sync",
})
}) })
this.io.on("*", ({ data }) => { this.io.on("*", ({ data }) => {
const [eventName, message] = data const [eventName, message] = data
@@ -355,15 +322,11 @@ export default defineComponent({
color: "#ff5555", color: "#ff5555",
ts: new Date().toLocaleTimeString(), ts: new Date().toLocaleTimeString(),
}) })
this.$toast.error(this.$t("state.disconnected"), { this.$toast.error(this.$t("state.disconnected"))
icon: "sync_disabled",
})
}) })
} catch (e) { } catch (e) {
this.handleError(e) this.handleError(e)
this.$toast.error(this.$t("error.something_went_wrong"), { this.$toast.error(this.$t("error.something_went_wrong"))
icon: "error_outline",
})
} }
logHoppRequestRunToAnalytics({ logHoppRequestRunToAnalytics({

View File

@@ -1,8 +1,8 @@
<template> <template>
<Splitpanes class="smart-splitter" :horizontal="COLUMN_LAYOUT"> <Splitpanes class="smart-splitter" :horizontal="COLUMN_LAYOUT">
<Pane class="hide-scrollbar !overflow-auto"> <Pane :size="COLUMN_LAYOUT ? 45 : 50" class="hide-scrollbar !overflow-auto">
<div class="bg-primary flex p-4 top-0 z-10 sticky"> <div class="bg-primary sticky top-0 z-10 flex p-4">
<div class="space-x-2 flex-1 inline-flex"> <div class="inline-flex flex-1 space-x-2">
<div class="flex flex-1"> <div class="flex flex-1">
<input <input
id="server" id="server"
@@ -10,51 +10,21 @@
type="url" type="url"
autocomplete="off" autocomplete="off"
:class="{ error: !serverValid }" :class="{ error: !serverValid }"
class=" class="bg-primaryLight border-divider text-secondaryDark hover:border-dividerDark focus-visible:bg-transparent focus-visible:border-dividerDark flex flex-1 w-full px-4 py-2 border rounded-l"
bg-primaryLight
border border-divider
rounded-l
flex flex-1
text-secondaryDark
w-full
py-2
px-4
hover:border-dividerDark
focus-visible:bg-transparent focus-visible:border-dividerDark
"
:placeholder="$t('sse.url')" :placeholder="$t('sse.url')"
:disabled="connectionSSEState" :disabled="connectionSSEState"
@keyup.enter="serverValid ? toggleSSEConnection() : null" @keyup.enter="serverValid ? toggleSSEConnection() : null"
/> />
<label <label
for="event-type" for="event-type"
class=" class="bg-primaryLight border-divider text-secondaryLight px-4 py-2 font-semibold truncate border-t border-b"
bg-primaryLight
border-t border-b border-divider
font-semibold
text-secondaryLight
py-2
px-4
truncate
"
> >
{{ $t("sse.event_type") }} {{ $t("sse.event_type") }}
</label> </label>
<input <input
id="event-type" id="event-type"
v-model="eventType" v-model="eventType"
class=" class="bg-primaryLight border-divider text-secondaryDark hover:border-dividerDark focus-visible:bg-transparent focus-visible:border-dividerDark flex flex-1 w-full px-4 py-2 border rounded-r"
bg-primaryLight
border border-divider
rounded-r
flex flex-1
text-secondaryDark
w-full
py-2
px-4
hover:border-dividerDark
focus-visible:bg-transparent focus-visible:border-dividerDark
"
spellcheck="false" spellcheck="false"
:disabled="connectionSSEState" :disabled="connectionSSEState"
@keyup.enter="serverValid ? toggleSSEConnection() : null" @keyup.enter="serverValid ? toggleSSEConnection() : null"
@@ -74,7 +44,7 @@
</div> </div>
</div> </div>
</Pane> </Pane>
<Pane class="hide-scrollbar !overflow-auto"> <Pane :size="COLUMN_LAYOUT ? 65 : 50" class="hide-scrollbar !overflow-auto">
<AppSection label="response"> <AppSection label="response">
<ul> <ul>
<li> <li>
@@ -171,9 +141,7 @@ export default defineComponent({
ts: new Date().toLocaleTimeString(), ts: new Date().toLocaleTimeString(),
}, },
] ]
this.$toast.success(this.$t("state.connected"), { this.$toast.success(this.$t("state.connected"))
icon: "sync",
})
} }
this.sse.onerror = () => { this.sse.onerror = () => {
this.handleSSEError() this.handleSSEError()
@@ -188,9 +156,7 @@ export default defineComponent({
color: "#ff5555", color: "#ff5555",
ts: new Date().toLocaleTimeString(), ts: new Date().toLocaleTimeString(),
}) })
this.$toast.error(this.$t("state.disconnected"), { this.$toast.error(this.$t("state.disconnected"))
icon: "sync_disabled",
})
} }
this.sse.addEventListener(this.eventType, ({ data }) => { this.sse.addEventListener(this.eventType, ({ data }) => {
this.events.log.push({ this.events.log.push({
@@ -201,9 +167,7 @@ export default defineComponent({
}) })
} catch (e) { } catch (e) {
this.handleSSEError(e) this.handleSSEError(e)
this.$toast.error(this.$t("error.something_went_wrong"), { this.$toast.error(this.$t("error.something_went_wrong"))
icon: "error_outline",
})
} }
} else { } else {
this.events.log = [ this.events.log = [

View File

@@ -9,25 +9,17 @@
> >
<Pane size="75" min-size="65" class="hide-scrollbar !overflow-auto"> <Pane size="75" min-size="65" class="hide-scrollbar !overflow-auto">
<Splitpanes class="smart-splitter" :horizontal="COLUMN_LAYOUT"> <Splitpanes class="smart-splitter" :horizontal="COLUMN_LAYOUT">
<Pane class="hide-scrollbar !overflow-auto"> <Pane
:size="COLUMN_LAYOUT ? 45 : 50"
class="hide-scrollbar !overflow-auto"
>
<AppSection label="request"> <AppSection label="request">
<div class="bg-primary flex p-4 top-0 z-10 sticky"> <div class="bg-primary sticky top-0 z-10 flex p-4">
<div class="space-x-2 flex-1 inline-flex"> <div class="inline-flex flex-1 space-x-2">
<input <input
id="websocket-url" id="websocket-url"
v-model="url" v-model="url"
class=" class="bg-primaryLight border-divider text-secondaryDark hover:border-dividerDark focus-visible:bg-transparent focus-visible:border-dividerDark w-full px-4 py-2 border rounded"
bg-primaryLight
border border-divider
rounded
text-secondaryDark
w-full
py-2
px-4
hover:border-dividerDark
focus-visible:bg-transparent
focus-visible:border-dividerDark
"
type="url" type="url"
autocomplete="off" autocomplete="off"
spellcheck="false" spellcheck="false"
@@ -52,19 +44,9 @@
</div> </div>
</div> </div>
<div <div
class=" class="bg-primary border-dividerLight top-upperPrimaryStickyFold sticky z-10 flex items-center justify-between flex-1 pl-4 border-b"
bg-primary
border-b border-dividerLight
flex flex-1
top-upperPrimaryStickyFold
pl-4
z-10
sticky
items-center
justify-between
"
> >
<label class="font-semibold text-secondaryLight"> <label class="text-secondaryLight font-semibold">
{{ $t("websocket.protocols") }} {{ $t("websocket.protocols") }}
</label> </label>
<div class="flex"> <div class="flex">
@@ -85,15 +67,11 @@
<div <div
v-for="(protocol, index) of protocols" v-for="(protocol, index) of protocols"
:key="`protocol-${index}`" :key="`protocol-${index}`"
class=" class="divide-dividerLight border-dividerLight flex border-b divide-x"
divide-x divide-dividerLight
border-b border-dividerLight
flex
"
> >
<input <input
v-model="protocol.value" v-model="protocol.value"
class="bg-transparent flex flex-1 py-2 px-4" class="flex flex-1 px-4 py-2 bg-transparent"
:placeholder="$t('count.protocol', { count: index + 1 })" :placeholder="$t('count.protocol', { count: index + 1 })"
name="message" name="message"
type="text" type="text"
@@ -136,34 +114,24 @@
</div> </div>
<div <div
v-if="protocols.length === 0" v-if="protocols.length === 0"
class=" class="text-secondaryLight flex flex-col items-center justify-center p-4"
flex flex-col
text-secondaryLight
p-4
items-center
justify-center
"
> >
<img <img
:src="`/images/states/${$colorMode.value}/add_category.svg`" :src="`/images/states/${$colorMode.value}/add_category.svg`"
loading="lazy" loading="lazy"
class=" class="inline-flex flex-col object-contain object-center w-16 h-16 my-4"
flex-col
my-4
object-contain object-center
h-16
w-16
inline-flex
"
:alt="$t('empty.protocols')" :alt="$t('empty.protocols')"
/> />
<span class="text-center mb-4"> <span class="mb-4 text-center">
{{ $t("empty.protocols") }} {{ $t("empty.protocols") }}
</span> </span>
</div> </div>
</AppSection> </AppSection>
</Pane> </Pane>
<Pane class="hide-scrollbar !overflow-auto"> <Pane
:size="COLUMN_LAYOUT ? 65 : 50"
class="hide-scrollbar !overflow-auto"
>
<AppSection label="response"> <AppSection label="response">
<RealtimeLog <RealtimeLog
:title="$t('websocket.log')" :title="$t('websocket.log')"
@@ -180,15 +148,15 @@
class="hide-scrollbar !overflow-auto" class="hide-scrollbar !overflow-auto"
> >
<AppSection label="messages"> <AppSection label="messages">
<div class="flex flex-col flex-1 p-4 inline-flex"> <div class="flex inline-flex flex-col flex-1 p-4">
<label <label
for="websocket-message" for="websocket-message"
class="font-semibold text-secondaryLight" class="text-secondaryLight font-semibold"
> >
{{ $t("websocket.communication") }} {{ $t("websocket.communication") }}
</label> </label>
</div> </div>
<div class="flex space-x-2 px-4"> <div class="flex px-4 space-x-2">
<input <input
id="websocket-message" id="websocket-message"
v-model="communication.input" v-model="communication.input"
@@ -319,9 +287,7 @@ export default defineComponent({
ts: new Date().toLocaleTimeString(), ts: new Date().toLocaleTimeString(),
}, },
] ]
this.$toast.success(this.$t("state.connected"), { this.$toast.success(this.$t("state.connected"))
icon: "sync",
})
} }
this.socket.onerror = () => { this.socket.onerror = () => {
this.handleError() this.handleError()
@@ -334,9 +300,7 @@ export default defineComponent({
color: "#ff5555", color: "#ff5555",
ts: new Date().toLocaleTimeString(), ts: new Date().toLocaleTimeString(),
}) })
this.$toast.error(this.$t("state.disconnected"), { this.$toast.error(this.$t("state.disconnected"))
icon: "sync_disabled",
})
} }
this.socket.onmessage = ({ data }) => { this.socket.onmessage = ({ data }) => {
this.communication.log.push({ this.communication.log.push({
@@ -347,9 +311,7 @@ export default defineComponent({
} }
} catch (e) { } catch (e) {
this.handleError(e) this.handleError(e)
this.$toast.error(this.$t("error.something_went_wrong"), { this.$toast.error(this.$t("error.something_went_wrong"))
icon: "error_outline",
})
} }
logHoppRequestRunToAnalytics({ logHoppRequestRunToAnalytics({
@@ -433,7 +395,6 @@ export default defineComponent({
const oldProtocols = this.protocols.slice() const oldProtocols = this.protocols.slice()
this.$delete(this.protocols, index) this.$delete(this.protocols, index)
this.$toast.success(this.$t("state.deleted"), { this.$toast.success(this.$t("state.deleted"), {
icon: "delete",
action: { action: {
text: this.$t("action.undo"), text: this.$t("action.undo"),
duration: 4000, duration: 4000,

View File

@@ -1,15 +1,6 @@
<template> <template>
<div <div
class=" class="flex-nowrap group hover:text-secondaryDark inline-flex items-center justify-center transition cursor-pointer"
cursor-pointer
flex-nowrap
group
inline-flex
items-center
justify-center
transition
hover:text-secondaryDark
"
@click="$emit('change')" @click="$emit('change')"
> >
<input <input
@@ -21,7 +12,7 @@
/> />
<label <label
for="checkbox" for="checkbox"
class="cursor-pointer pl-0 align-middle font-semibold" class="pl-0 font-semibold align-middle cursor-pointer"
> >
<slot></slot> <slot></slot>
</label> </label>

View File

@@ -4,7 +4,7 @@
v-for="(color, index) of colors" v-for="(color, index) of colors"
:key="`color-${index}`" :key="`color-${index}`"
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
:title="$t(getColorModeName(color))" :title="t(getColorModeName(color))"
:class="{ :class="{
'bg-primaryLight !text-accent hover:text-accent': color === active, 'bg-primaryLight !text-accent hover:text-accent': color === active,
}" }"
@@ -22,6 +22,9 @@ import {
HoppBgColors, HoppBgColors,
useSetting, useSetting,
} from "~/newstore/settings" } from "~/newstore/settings"
import { useI18n } from "~/helpers/utils/composables"
const t = useI18n()
const colors = HoppBgColors const colors = HoppBgColors
const active = useSetting("BG_COLOR") const active = useSetting("BG_COLOR")

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