feat: reorder key-value entries (#2189)
This commit is contained in:
committed by
Andrew Bastin
parent
0edfe7b8e3
commit
29d3f3cbe3
18
packages/hoppscotch-app/assets/icons/grip-vertical.svg
Normal file
18
packages/hoppscotch-app/assets/icons/grip-vertical.svg
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<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"
|
||||||
|
>
|
||||||
|
<circle cx="9" cy="12" r="1" />
|
||||||
|
<circle cx="9" cy="5" r="1" />
|
||||||
|
<circle cx="9" cy="19" r="1" />
|
||||||
|
<circle cx="15" cy="12" r="1" />
|
||||||
|
<circle cx="15" cy="5" r="1" />
|
||||||
|
<circle cx="15" cy="19" r="1" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 413 B |
@@ -155,18 +155,38 @@
|
|||||||
class="flex flex-col flex-1"
|
class="flex flex-col flex-1"
|
||||||
></div>
|
></div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<div
|
<draggable
|
||||||
v-for="(header, index) in workingHeaders"
|
v-model="workingHeaders"
|
||||||
:key="`header-${header.id}-${index}`"
|
animation="250"
|
||||||
class="flex border-b divide-x divide-dividerLight border-dividerLight"
|
handle=".draggable-handle"
|
||||||
|
draggable=".draggable-content"
|
||||||
|
ghost-class="cursor-move"
|
||||||
|
chosen-class="bg-primaryLight"
|
||||||
|
drag-class="cursor-grabbing"
|
||||||
>
|
>
|
||||||
<SmartAutoComplete
|
<div
|
||||||
:placeholder="`${t('count.header', { count: index + 1 })}`"
|
v-for="(header, index) in workingHeaders"
|
||||||
:source="commonHeaders"
|
:key="`header-${header.id}-${index}`"
|
||||||
:spellcheck="false"
|
class="flex border-b divide-x divide-dividerLight border-dividerLight draggable-content group"
|
||||||
:value="header.key"
|
>
|
||||||
autofocus
|
<span>
|
||||||
styles="
|
<ButtonSecondary
|
||||||
|
svg="grip-vertical"
|
||||||
|
class="cursor-auto text-primary hover:text-primary"
|
||||||
|
:class="{
|
||||||
|
'draggable-handle group-hover:text-secondaryLight !cursor-grab':
|
||||||
|
index !== workingHeaders?.length - 1,
|
||||||
|
}"
|
||||||
|
tabindex="-1"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<SmartAutoComplete
|
||||||
|
:placeholder="`${t('count.header', { count: index + 1 })}`"
|
||||||
|
:source="commonHeaders"
|
||||||
|
:spellcheck="false"
|
||||||
|
:value="header.key"
|
||||||
|
autofocus
|
||||||
|
styles="
|
||||||
bg-transparent
|
bg-transparent
|
||||||
flex
|
flex
|
||||||
flex-1
|
flex-1
|
||||||
@@ -174,69 +194,70 @@
|
|||||||
px-4
|
px-4
|
||||||
truncate
|
truncate
|
||||||
"
|
"
|
||||||
class="flex-1 !flex"
|
class="flex-1 !flex"
|
||||||
@input="
|
@input="
|
||||||
updateHeader(index, {
|
|
||||||
id: header.id,
|
|
||||||
key: $event,
|
|
||||||
value: header.value,
|
|
||||||
active: header.active,
|
|
||||||
})
|
|
||||||
"
|
|
||||||
/>
|
|
||||||
<input
|
|
||||||
class="flex flex-1 px-4 py-2 bg-transparent"
|
|
||||||
:placeholder="`${t('count.value', { count: index + 1 })}`"
|
|
||||||
:name="`value ${String(index)}`"
|
|
||||||
:value="header.value"
|
|
||||||
autofocus
|
|
||||||
@change="
|
|
||||||
updateHeader(index, {
|
|
||||||
id: header.id,
|
|
||||||
key: header.key,
|
|
||||||
value: $event.target.value,
|
|
||||||
active: header.active,
|
|
||||||
})
|
|
||||||
"
|
|
||||||
/>
|
|
||||||
<span>
|
|
||||||
<ButtonSecondary
|
|
||||||
v-tippy="{ theme: 'tooltip' }"
|
|
||||||
:title="
|
|
||||||
header.hasOwnProperty('active')
|
|
||||||
? header.active
|
|
||||||
? t('action.turn_off')
|
|
||||||
: t('action.turn_on')
|
|
||||||
: t('action.turn_off')
|
|
||||||
"
|
|
||||||
:svg="
|
|
||||||
header.hasOwnProperty('active')
|
|
||||||
? header.active
|
|
||||||
? 'check-circle'
|
|
||||||
: 'circle'
|
|
||||||
: 'check-circle'
|
|
||||||
"
|
|
||||||
color="green"
|
|
||||||
@click.native="
|
|
||||||
updateHeader(index, {
|
updateHeader(index, {
|
||||||
id: header.id,
|
id: header.id,
|
||||||
key: header.key,
|
key: $event,
|
||||||
value: header.value,
|
value: header.value,
|
||||||
active: !header.active,
|
active: header.active,
|
||||||
})
|
})
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
</span>
|
<input
|
||||||
<span>
|
class="flex flex-1 px-4 py-2 bg-transparent"
|
||||||
<ButtonSecondary
|
:placeholder="`${t('count.value', { count: index + 1 })}`"
|
||||||
v-tippy="{ theme: 'tooltip' }"
|
:name="`value ${String(index)}`"
|
||||||
:title="t('action.remove')"
|
:value="header.value"
|
||||||
svg="trash"
|
autofocus
|
||||||
color="red"
|
@change="
|
||||||
@click.native="deleteHeader(index)"
|
updateHeader(index, {
|
||||||
|
id: header.id,
|
||||||
|
key: header.key,
|
||||||
|
value: $event.target.value,
|
||||||
|
active: header.active,
|
||||||
|
})
|
||||||
|
"
|
||||||
/>
|
/>
|
||||||
</span>
|
<span>
|
||||||
</div>
|
<ButtonSecondary
|
||||||
|
v-tippy="{ theme: 'tooltip' }"
|
||||||
|
:title="
|
||||||
|
header.hasOwnProperty('active')
|
||||||
|
? header.active
|
||||||
|
? t('action.turn_off')
|
||||||
|
: t('action.turn_on')
|
||||||
|
: t('action.turn_off')
|
||||||
|
"
|
||||||
|
:svg="
|
||||||
|
header.hasOwnProperty('active')
|
||||||
|
? header.active
|
||||||
|
? 'check-circle'
|
||||||
|
: 'circle'
|
||||||
|
: 'check-circle'
|
||||||
|
"
|
||||||
|
color="green"
|
||||||
|
@click.native="
|
||||||
|
updateHeader(index, {
|
||||||
|
id: header.id,
|
||||||
|
key: header.key,
|
||||||
|
value: header.value,
|
||||||
|
active: !header.active,
|
||||||
|
})
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
<ButtonSecondary
|
||||||
|
v-tippy="{ theme: 'tooltip' }"
|
||||||
|
:title="t('action.remove')"
|
||||||
|
svg="trash"
|
||||||
|
color="red"
|
||||||
|
@click.native="deleteHeader(index)"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</draggable>
|
||||||
<div
|
<div
|
||||||
v-if="workingHeaders.length === 0"
|
v-if="workingHeaders.length === 0"
|
||||||
class="flex flex-col items-center justify-center p-4 text-secondaryLight"
|
class="flex flex-col items-center justify-center p-4 text-secondaryLight"
|
||||||
@@ -288,6 +309,7 @@ import {
|
|||||||
parseRawKeyValueEntriesE,
|
parseRawKeyValueEntriesE,
|
||||||
RawKeyValueEntry,
|
RawKeyValueEntry,
|
||||||
} from "@hoppscotch/data"
|
} from "@hoppscotch/data"
|
||||||
|
import draggable from "vuedraggable"
|
||||||
import isEqual from "lodash/isEqual"
|
import isEqual from "lodash/isEqual"
|
||||||
import cloneDeep from "lodash/cloneDeep"
|
import cloneDeep from "lodash/cloneDeep"
|
||||||
import { copyToClipboard } from "~/helpers/utils/clipboard"
|
import { copyToClipboard } from "~/helpers/utils/clipboard"
|
||||||
|
|||||||
@@ -28,97 +28,118 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<draggable
|
||||||
v-for="(param, index) in workingParams"
|
v-model="workingParams"
|
||||||
:key="`param-${index}`"
|
animation="250"
|
||||||
class="flex border-b divide-x divide-dividerLight border-dividerLight"
|
handle=".draggable-handle"
|
||||||
|
draggable=".draggable-content"
|
||||||
|
ghost-class="cursor-move"
|
||||||
|
chosen-class="bg-primaryLight"
|
||||||
|
drag-class="cursor-grabbing"
|
||||||
>
|
>
|
||||||
<SmartEnvInput
|
<div
|
||||||
v-model="param.key"
|
v-for="(param, index) in workingParams"
|
||||||
:placeholder="`${$t('count.parameter', { count: index + 1 })}`"
|
:key="`param-${index}`"
|
||||||
@change="
|
class="flex border-b divide-x divide-dividerLight border-dividerLight draggable-content group"
|
||||||
updateBodyParam(index, {
|
>
|
||||||
key: $event,
|
<span>
|
||||||
value: param.value,
|
<ButtonSecondary
|
||||||
active: param.active,
|
svg="grip-vertical"
|
||||||
isFile: param.isFile,
|
class="cursor-auto text-primary hover:text-primary"
|
||||||
})
|
:class="{
|
||||||
"
|
'draggable-handle group-hover:text-secondaryLight !cursor-grab':
|
||||||
/>
|
index !== workingParams?.length - 1,
|
||||||
<div v-if="param.isFile" class="file-chips-container hide-scrollbar">
|
}"
|
||||||
<div class="space-x-2 file-chips-wrapper">
|
tabindex="-1"
|
||||||
<SmartFileChip
|
/>
|
||||||
v-for="(file, fileIndex) in param.value"
|
</span>
|
||||||
:key="`param-${index}-file-${fileIndex}`"
|
|
||||||
>{{ file.name }}</SmartFileChip
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<span v-else class="flex flex-1">
|
|
||||||
<SmartEnvInput
|
<SmartEnvInput
|
||||||
v-model="param.value"
|
v-model="param.key"
|
||||||
:placeholder="`${$t('count.value', { count: index + 1 })}`"
|
:placeholder="`${$t('count.parameter', { count: index + 1 })}`"
|
||||||
@change="
|
@change="
|
||||||
updateBodyParam(index, {
|
updateBodyParam(index, {
|
||||||
key: param.key,
|
key: $event,
|
||||||
value: $event,
|
value: param.value,
|
||||||
active: param.active,
|
active: param.active,
|
||||||
isFile: param.isFile,
|
isFile: param.isFile,
|
||||||
})
|
})
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
</span>
|
<div v-if="param.isFile" class="file-chips-container hide-scrollbar">
|
||||||
<span>
|
<div class="space-x-2 file-chips-wrapper">
|
||||||
<label :for="`attachment${index}`" class="p-0">
|
<SmartFileChip
|
||||||
<input
|
v-for="(file, fileIndex) in param.value"
|
||||||
:id="`attachment${index}`"
|
:key="`param-${index}-file-${fileIndex}`"
|
||||||
:ref="`attachment${index}`"
|
>{{ file.name }}</SmartFileChip
|
||||||
:name="`attachment${index}`"
|
>
|
||||||
type="file"
|
</div>
|
||||||
multiple
|
</div>
|
||||||
class="p-1 cursor-pointer transition file:transition file:cursor-pointer text-secondaryLight hover:text-secondaryDark file:mr-2 file:py-1 file:px-4 file:rounded file:border-0 file:text-tiny text-tiny file:text-secondary hover:file:text-secondaryDark file:bg-primaryLight hover:file:bg-primaryDark"
|
<span v-else class="flex flex-1">
|
||||||
@change="setRequestAttachment(index, param, $event)"
|
<SmartEnvInput
|
||||||
|
v-model="param.value"
|
||||||
|
:placeholder="`${$t('count.value', { count: index + 1 })}`"
|
||||||
|
@change="
|
||||||
|
updateBodyParam(index, {
|
||||||
|
key: param.key,
|
||||||
|
value: $event,
|
||||||
|
active: param.active,
|
||||||
|
isFile: param.isFile,
|
||||||
|
})
|
||||||
|
"
|
||||||
/>
|
/>
|
||||||
</label>
|
</span>
|
||||||
</span>
|
<span>
|
||||||
<span>
|
<label :for="`attachment${index}`" class="p-0">
|
||||||
<ButtonSecondary
|
<input
|
||||||
v-tippy="{ theme: 'tooltip' }"
|
:id="`attachment${index}`"
|
||||||
:title="
|
:ref="`attachment${index}`"
|
||||||
param.hasOwnProperty('active')
|
:name="`attachment${index}`"
|
||||||
? param.active
|
type="file"
|
||||||
? $t('action.turn_off')
|
multiple
|
||||||
: $t('action.turn_on')
|
class="p-1 cursor-pointer transition file:transition file:cursor-pointer text-secondaryLight hover:text-secondaryDark file:mr-2 file:py-1 file:px-4 file:rounded file:border-0 file:text-tiny text-tiny file:text-secondary hover:file:text-secondaryDark file:bg-primaryLight hover:file:bg-primaryDark"
|
||||||
: $t('action.turn_off')
|
@change="setRequestAttachment(index, param, $event)"
|
||||||
"
|
/>
|
||||||
:svg="
|
</label>
|
||||||
param.hasOwnProperty('active')
|
</span>
|
||||||
? param.active
|
<span>
|
||||||
? 'check-circle'
|
<ButtonSecondary
|
||||||
: 'circle'
|
v-tippy="{ theme: 'tooltip' }"
|
||||||
: 'check-circle'
|
:title="
|
||||||
"
|
param.hasOwnProperty('active')
|
||||||
color="green"
|
? param.active
|
||||||
@click.native="
|
? $t('action.turn_off')
|
||||||
updateBodyParam(index, {
|
: $t('action.turn_on')
|
||||||
key: param.key,
|
: $t('action.turn_off')
|
||||||
value: param.value,
|
"
|
||||||
active: param.hasOwnProperty('active') ? !param.active : false,
|
:svg="
|
||||||
isFile: param.isFile,
|
param.hasOwnProperty('active')
|
||||||
})
|
? param.active
|
||||||
"
|
? 'check-circle'
|
||||||
/>
|
: 'circle'
|
||||||
</span>
|
: 'check-circle'
|
||||||
<span>
|
"
|
||||||
<ButtonSecondary
|
color="green"
|
||||||
v-tippy="{ theme: 'tooltip' }"
|
@click.native="
|
||||||
:title="$t('action.remove')"
|
updateBodyParam(index, {
|
||||||
svg="trash"
|
key: param.key,
|
||||||
color="red"
|
value: param.value,
|
||||||
@click.native="deleteBodyParam(index)"
|
active: param.hasOwnProperty('active') ? !param.active : false,
|
||||||
/>
|
isFile: param.isFile,
|
||||||
</span>
|
})
|
||||||
</div>
|
"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
<ButtonSecondary
|
||||||
|
v-tippy="{ theme: 'tooltip' }"
|
||||||
|
:title="$t('action.remove')"
|
||||||
|
svg="trash"
|
||||||
|
color="red"
|
||||||
|
@click.native="deleteBodyParam(index)"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</draggable>
|
||||||
<div
|
<div
|
||||||
v-if="workingParams.length === 0"
|
v-if="workingParams.length === 0"
|
||||||
class="flex flex-col items-center justify-center p-4 text-secondaryLight"
|
class="flex flex-col items-center justify-center p-4 text-secondaryLight"
|
||||||
@@ -146,6 +167,7 @@ import { ref, Ref, watch } from "@nuxtjs/composition-api"
|
|||||||
import { FormDataKeyValue } from "@hoppscotch/data"
|
import { FormDataKeyValue } from "@hoppscotch/data"
|
||||||
import isEqual from "lodash/isEqual"
|
import isEqual from "lodash/isEqual"
|
||||||
import { clone } from "lodash"
|
import { clone } from "lodash"
|
||||||
|
import draggable from "vuedraggable"
|
||||||
import { pluckRef, useI18n, useToast } from "~/helpers/utils/composables"
|
import { pluckRef, useI18n, useToast } from "~/helpers/utils/composables"
|
||||||
import { useRESTRequestBody } from "~/newstore/RESTSession"
|
import { useRESTRequestBody } from "~/newstore/RESTSession"
|
||||||
|
|
||||||
|
|||||||
@@ -38,18 +38,38 @@
|
|||||||
</div>
|
</div>
|
||||||
<div v-if="bulkMode" ref="bulkEditor" class="flex flex-col flex-1"></div>
|
<div v-if="bulkMode" ref="bulkEditor" class="flex flex-col flex-1"></div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<div
|
<draggable
|
||||||
v-for="(header, index) in workingHeaders"
|
v-model="workingHeaders"
|
||||||
:key="`header-${header.id}-${index}`"
|
animation="250"
|
||||||
class="flex border-b divide-x divide-dividerLight border-dividerLight"
|
handle=".draggable-handle"
|
||||||
|
draggable=".draggable-content"
|
||||||
|
ghost-class="cursor-move"
|
||||||
|
chosen-class="bg-primaryLight"
|
||||||
|
drag-class="cursor-grabbing"
|
||||||
>
|
>
|
||||||
<SmartAutoComplete
|
<div
|
||||||
:placeholder="`${t('count.header', { count: index + 1 })}`"
|
v-for="(header, index) in workingHeaders"
|
||||||
:source="commonHeaders"
|
:key="`header-${header.id}-${index}`"
|
||||||
:spellcheck="false"
|
class="flex border-b divide-x divide-dividerLight border-dividerLight draggable-content group"
|
||||||
:value="header.key"
|
>
|
||||||
autofocus
|
<span>
|
||||||
styles="
|
<ButtonSecondary
|
||||||
|
svg="grip-vertical"
|
||||||
|
class="cursor-auto text-primary hover:text-primary"
|
||||||
|
:class="{
|
||||||
|
'draggable-handle group-hover:text-secondaryLight !cursor-grab':
|
||||||
|
index !== workingHeaders?.length - 1,
|
||||||
|
}"
|
||||||
|
tabindex="-1"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<SmartAutoComplete
|
||||||
|
:placeholder="`${t('count.header', { count: index + 1 })}`"
|
||||||
|
:source="commonHeaders"
|
||||||
|
:spellcheck="false"
|
||||||
|
:value="header.key"
|
||||||
|
autofocus
|
||||||
|
styles="
|
||||||
bg-transparent
|
bg-transparent
|
||||||
flex
|
flex
|
||||||
flex-1
|
flex-1
|
||||||
@@ -57,66 +77,67 @@
|
|||||||
px-4
|
px-4
|
||||||
truncate
|
truncate
|
||||||
"
|
"
|
||||||
class="flex-1 !flex"
|
class="flex-1 !flex"
|
||||||
@input="
|
@input="
|
||||||
updateHeader(index, {
|
|
||||||
id: header.id,
|
|
||||||
key: $event,
|
|
||||||
value: header.value,
|
|
||||||
active: header.active,
|
|
||||||
})
|
|
||||||
"
|
|
||||||
/>
|
|
||||||
<SmartEnvInput
|
|
||||||
v-model="header.value"
|
|
||||||
:placeholder="`${t('count.value', { count: index + 1 })}`"
|
|
||||||
@change="
|
|
||||||
updateHeader(index, {
|
|
||||||
id: header.id,
|
|
||||||
key: header.key,
|
|
||||||
value: $event,
|
|
||||||
active: header.active,
|
|
||||||
})
|
|
||||||
"
|
|
||||||
/>
|
|
||||||
<span>
|
|
||||||
<ButtonSecondary
|
|
||||||
v-tippy="{ theme: 'tooltip' }"
|
|
||||||
:title="
|
|
||||||
header.hasOwnProperty('active')
|
|
||||||
? header.active
|
|
||||||
? t('action.turn_off')
|
|
||||||
: t('action.turn_on')
|
|
||||||
: t('action.turn_off')
|
|
||||||
"
|
|
||||||
:svg="
|
|
||||||
header.hasOwnProperty('active')
|
|
||||||
? header.active
|
|
||||||
? 'check-circle'
|
|
||||||
: 'circle'
|
|
||||||
: 'check-circle'
|
|
||||||
"
|
|
||||||
color="green"
|
|
||||||
@click.native="
|
|
||||||
updateHeader(index, {
|
updateHeader(index, {
|
||||||
id: header.id,
|
id: header.id,
|
||||||
key: header.key,
|
key: $event,
|
||||||
value: header.value,
|
value: header.value,
|
||||||
active: !header.active,
|
active: header.active,
|
||||||
})
|
})
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
</span>
|
<SmartEnvInput
|
||||||
<span>
|
v-model="header.value"
|
||||||
<ButtonSecondary
|
:placeholder="`${t('count.value', { count: index + 1 })}`"
|
||||||
v-tippy="{ theme: 'tooltip' }"
|
@change="
|
||||||
:title="t('action.remove')"
|
updateHeader(index, {
|
||||||
svg="trash"
|
id: header.id,
|
||||||
color="red"
|
key: header.key,
|
||||||
@click.native="deleteHeader(index)"
|
value: $event,
|
||||||
|
active: header.active,
|
||||||
|
})
|
||||||
|
"
|
||||||
/>
|
/>
|
||||||
</span>
|
<span>
|
||||||
</div>
|
<ButtonSecondary
|
||||||
|
v-tippy="{ theme: 'tooltip' }"
|
||||||
|
:title="
|
||||||
|
header.hasOwnProperty('active')
|
||||||
|
? header.active
|
||||||
|
? t('action.turn_off')
|
||||||
|
: t('action.turn_on')
|
||||||
|
: t('action.turn_off')
|
||||||
|
"
|
||||||
|
:svg="
|
||||||
|
header.hasOwnProperty('active')
|
||||||
|
? header.active
|
||||||
|
? 'check-circle'
|
||||||
|
: 'circle'
|
||||||
|
: 'check-circle'
|
||||||
|
"
|
||||||
|
color="green"
|
||||||
|
@click.native="
|
||||||
|
updateHeader(index, {
|
||||||
|
id: header.id,
|
||||||
|
key: header.key,
|
||||||
|
value: header.value,
|
||||||
|
active: !header.active,
|
||||||
|
})
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
<ButtonSecondary
|
||||||
|
v-tippy="{ theme: 'tooltip' }"
|
||||||
|
:title="t('action.remove')"
|
||||||
|
svg="trash"
|
||||||
|
color="red"
|
||||||
|
@click.native="deleteHeader(index)"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</draggable>
|
||||||
<div
|
<div
|
||||||
v-if="workingHeaders.length === 0"
|
v-if="workingHeaders.length === 0"
|
||||||
class="flex flex-col items-center justify-center p-4 text-secondaryLight"
|
class="flex flex-col items-center justify-center p-4 text-secondaryLight"
|
||||||
@@ -155,6 +176,7 @@ import * as E from "fp-ts/Either"
|
|||||||
import * as O from "fp-ts/Option"
|
import * as O from "fp-ts/Option"
|
||||||
import * as A from "fp-ts/Array"
|
import * as A from "fp-ts/Array"
|
||||||
import cloneDeep from "lodash/cloneDeep"
|
import cloneDeep from "lodash/cloneDeep"
|
||||||
|
import draggable from "vuedraggable"
|
||||||
import { useCodemirror } from "~/helpers/editor/codemirror"
|
import { useCodemirror } from "~/helpers/editor/codemirror"
|
||||||
import { restHeaders$, setRESTHeaders } from "~/newstore/RESTSession"
|
import { restHeaders$, setRESTHeaders } from "~/newstore/RESTSession"
|
||||||
import { commonHeaders } from "~/helpers/headers"
|
import { commonHeaders } from "~/helpers/headers"
|
||||||
|
|||||||
@@ -38,73 +38,96 @@
|
|||||||
</div>
|
</div>
|
||||||
<div v-if="bulkMode" ref="bulkEditor" class="flex flex-col flex-1"></div>
|
<div v-if="bulkMode" ref="bulkEditor" class="flex flex-col flex-1"></div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<div
|
<draggable
|
||||||
v-for="(param, index) in workingParams"
|
v-model="workingParams"
|
||||||
:key="`param-${param.id}-${index}`"
|
animation="250"
|
||||||
class="flex border-b divide-x divide-dividerLight border-dividerLight"
|
handle=".draggable-handle"
|
||||||
|
draggable=".draggable-content"
|
||||||
|
ghost-class="cursor-move"
|
||||||
|
chosen-class="bg-primaryLight"
|
||||||
|
drag-class="cursor-grabbing"
|
||||||
>
|
>
|
||||||
<SmartEnvInput
|
<div
|
||||||
v-model="param.key"
|
v-for="(param, index) in workingParams"
|
||||||
:placeholder="`${t('count.parameter', { count: index + 1 })}`"
|
:key="`param-${param.id}-${index}`"
|
||||||
@change="
|
class="flex border-b divide-x divide-dividerLight border-dividerLight draggable-content group"
|
||||||
updateParam(index, {
|
>
|
||||||
id: param.id,
|
<span>
|
||||||
key: $event,
|
<ButtonSecondary
|
||||||
value: param.value,
|
svg="grip-vertical"
|
||||||
active: param.active,
|
class="cursor-auto text-primary hover:text-primary"
|
||||||
})
|
:class="{
|
||||||
"
|
'draggable-handle group-hover:text-secondaryLight !cursor-grab':
|
||||||
/>
|
index !== workingParams?.length - 1,
|
||||||
<SmartEnvInput
|
}"
|
||||||
v-model="param.value"
|
tabindex="-1"
|
||||||
:placeholder="`${t('count.value', { count: index + 1 })}`"
|
/>
|
||||||
@change="
|
</span>
|
||||||
updateParam(index, {
|
<SmartEnvInput
|
||||||
id: param.id,
|
v-model="param.key"
|
||||||
key: param.key,
|
:placeholder="`${t('count.parameter', { count: index + 1 })}`"
|
||||||
value: $event,
|
@change="
|
||||||
active: param.active,
|
|
||||||
})
|
|
||||||
"
|
|
||||||
/>
|
|
||||||
<span>
|
|
||||||
<ButtonSecondary
|
|
||||||
v-tippy="{ theme: 'tooltip' }"
|
|
||||||
:title="
|
|
||||||
param.hasOwnProperty('active')
|
|
||||||
? param.active
|
|
||||||
? t('action.turn_off')
|
|
||||||
: t('action.turn_on')
|
|
||||||
: t('action.turn_off')
|
|
||||||
"
|
|
||||||
:svg="
|
|
||||||
param.hasOwnProperty('active')
|
|
||||||
? param.active
|
|
||||||
? 'check-circle'
|
|
||||||
: 'circle'
|
|
||||||
: 'check-circle'
|
|
||||||
"
|
|
||||||
color="green"
|
|
||||||
@click.native="
|
|
||||||
updateParam(index, {
|
updateParam(index, {
|
||||||
id: param.id,
|
id: param.id,
|
||||||
key: param.key,
|
key: $event,
|
||||||
value: param.value,
|
value: param.value,
|
||||||
active: param.hasOwnProperty('active') ? !param.active : false,
|
active: param.active,
|
||||||
})
|
})
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
</span>
|
<SmartEnvInput
|
||||||
<span>
|
v-model="param.value"
|
||||||
<ButtonSecondary
|
:placeholder="`${t('count.value', { count: index + 1 })}`"
|
||||||
v-tippy="{ theme: 'tooltip' }"
|
@change="
|
||||||
:title="t('action.remove')"
|
updateParam(index, {
|
||||||
svg="trash"
|
id: param.id,
|
||||||
color="red"
|
key: param.key,
|
||||||
@click.native="deleteParam(index)"
|
value: $event,
|
||||||
|
active: param.active,
|
||||||
|
})
|
||||||
|
"
|
||||||
/>
|
/>
|
||||||
</span>
|
<span>
|
||||||
</div>
|
<ButtonSecondary
|
||||||
|
v-tippy="{ theme: 'tooltip' }"
|
||||||
|
:title="
|
||||||
|
param.hasOwnProperty('active')
|
||||||
|
? param.active
|
||||||
|
? t('action.turn_off')
|
||||||
|
: t('action.turn_on')
|
||||||
|
: t('action.turn_off')
|
||||||
|
"
|
||||||
|
:svg="
|
||||||
|
param.hasOwnProperty('active')
|
||||||
|
? param.active
|
||||||
|
? 'check-circle'
|
||||||
|
: 'circle'
|
||||||
|
: 'check-circle'
|
||||||
|
"
|
||||||
|
color="green"
|
||||||
|
@click.native="
|
||||||
|
updateParam(index, {
|
||||||
|
id: param.id,
|
||||||
|
key: param.key,
|
||||||
|
value: param.value,
|
||||||
|
active: param.hasOwnProperty('active')
|
||||||
|
? !param.active
|
||||||
|
: false,
|
||||||
|
})
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
<ButtonSecondary
|
||||||
|
v-tippy="{ theme: 'tooltip' }"
|
||||||
|
:title="t('action.remove')"
|
||||||
|
svg="trash"
|
||||||
|
color="red"
|
||||||
|
@click.native="deleteParam(index)"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</draggable>
|
||||||
<div
|
<div
|
||||||
v-if="workingParams.length === 0"
|
v-if="workingParams.length === 0"
|
||||||
class="flex flex-col items-center justify-center p-4 text-secondaryLight"
|
class="flex flex-col items-center justify-center p-4 text-secondaryLight"
|
||||||
@@ -143,6 +166,7 @@ import {
|
|||||||
} from "@hoppscotch/data"
|
} from "@hoppscotch/data"
|
||||||
import isEqual from "lodash/isEqual"
|
import isEqual from "lodash/isEqual"
|
||||||
import cloneDeep from "lodash/cloneDeep"
|
import cloneDeep from "lodash/cloneDeep"
|
||||||
|
import draggable from "vuedraggable"
|
||||||
import linter from "~/helpers/editor/linting/rawKeyValue"
|
import linter from "~/helpers/editor/linting/rawKeyValue"
|
||||||
import { useCodemirror } from "~/helpers/editor/codemirror"
|
import { useCodemirror } from "~/helpers/editor/codemirror"
|
||||||
import { useI18n, useToast, useStream } from "~/helpers/utils/composables"
|
import { useI18n, useToast, useStream } from "~/helpers/utils/composables"
|
||||||
|
|||||||
@@ -38,73 +38,94 @@
|
|||||||
</div>
|
</div>
|
||||||
<div v-if="bulkMode" ref="bulkEditor" class="flex flex-col flex-1"></div>
|
<div v-if="bulkMode" ref="bulkEditor" class="flex flex-col flex-1"></div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<div
|
<draggable
|
||||||
v-for="(param, index) in workingUrlEncodedParams"
|
v-model="workingUrlEncodedParams"
|
||||||
:key="`param-${param.id}-${index}`"
|
animation="250"
|
||||||
class="flex border-b divide-x divide-dividerLight border-dividerLight"
|
handle=".draggable-handle"
|
||||||
|
draggable=".draggable-content"
|
||||||
|
ghost-class="cursor-move"
|
||||||
|
chosen-class="bg-primaryLight"
|
||||||
|
drag-class="cursor-grabbing"
|
||||||
>
|
>
|
||||||
<SmartEnvInput
|
<div
|
||||||
v-model="param.key"
|
v-for="(param, index) in workingUrlEncodedParams"
|
||||||
:placeholder="`${t('count.parameter', { count: index + 1 })}`"
|
:key="`param-${param.id}-${index}`"
|
||||||
@change="
|
class="flex border-b divide-x divide-dividerLight border-dividerLight draggable-content group"
|
||||||
updateUrlEncodedParam(index, {
|
>
|
||||||
id: param.id,
|
<span>
|
||||||
key: $event,
|
<ButtonSecondary
|
||||||
value: param.value,
|
svg="grip-vertical"
|
||||||
active: param.active,
|
class="cursor-auto text-primary hover:text-primary"
|
||||||
})
|
:class="{
|
||||||
"
|
'draggable-handle group-hover:text-secondaryLight !cursor-grab':
|
||||||
/>
|
index !== workingUrlEncodedParams?.length - 1,
|
||||||
<SmartEnvInput
|
}"
|
||||||
v-model="param.value"
|
tabindex="-1"
|
||||||
:placeholder="`${t('count.value', { count: index + 1 })}`"
|
/>
|
||||||
@change="
|
</span>
|
||||||
updateUrlEncodedParam(index, {
|
<SmartEnvInput
|
||||||
id: param.id,
|
v-model="param.key"
|
||||||
key: param.key,
|
:placeholder="`${t('count.parameter', { count: index + 1 })}`"
|
||||||
value: $event,
|
@change="
|
||||||
active: param.active,
|
|
||||||
})
|
|
||||||
"
|
|
||||||
/>
|
|
||||||
<span>
|
|
||||||
<ButtonSecondary
|
|
||||||
v-tippy="{ theme: 'tooltip' }"
|
|
||||||
:title="
|
|
||||||
param.hasOwnProperty('active')
|
|
||||||
? param.active
|
|
||||||
? t('action.turn_off')
|
|
||||||
: t('action.turn_on')
|
|
||||||
: t('action.turn_off')
|
|
||||||
"
|
|
||||||
:svg="
|
|
||||||
param.hasOwnProperty('active')
|
|
||||||
? param.active
|
|
||||||
? 'check-circle'
|
|
||||||
: 'circle'
|
|
||||||
: 'check-circle'
|
|
||||||
"
|
|
||||||
color="green"
|
|
||||||
@click.native="
|
|
||||||
updateUrlEncodedParam(index, {
|
updateUrlEncodedParam(index, {
|
||||||
id: param.id,
|
id: param.id,
|
||||||
key: param.key,
|
key: $event,
|
||||||
value: param.value,
|
value: param.value,
|
||||||
active: !param.active,
|
active: param.active,
|
||||||
})
|
})
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
</span>
|
<SmartEnvInput
|
||||||
<span>
|
v-model="param.value"
|
||||||
<ButtonSecondary
|
:placeholder="`${t('count.value', { count: index + 1 })}`"
|
||||||
v-tippy="{ theme: 'tooltip' }"
|
@change="
|
||||||
:title="t('action.remove')"
|
updateUrlEncodedParam(index, {
|
||||||
svg="trash"
|
id: param.id,
|
||||||
color="red"
|
key: param.key,
|
||||||
@click.native="deleteUrlEncodedParam(index)"
|
value: $event,
|
||||||
|
active: param.active,
|
||||||
|
})
|
||||||
|
"
|
||||||
/>
|
/>
|
||||||
</span>
|
<span>
|
||||||
</div>
|
<ButtonSecondary
|
||||||
|
v-tippy="{ theme: 'tooltip' }"
|
||||||
|
:title="
|
||||||
|
param.hasOwnProperty('active')
|
||||||
|
? param.active
|
||||||
|
? t('action.turn_off')
|
||||||
|
: t('action.turn_on')
|
||||||
|
: t('action.turn_off')
|
||||||
|
"
|
||||||
|
:svg="
|
||||||
|
param.hasOwnProperty('active')
|
||||||
|
? param.active
|
||||||
|
? 'check-circle'
|
||||||
|
: 'circle'
|
||||||
|
: 'check-circle'
|
||||||
|
"
|
||||||
|
color="green"
|
||||||
|
@click.native="
|
||||||
|
updateUrlEncodedParam(index, {
|
||||||
|
id: param.id,
|
||||||
|
key: param.key,
|
||||||
|
value: param.value,
|
||||||
|
active: !param.active,
|
||||||
|
})
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
<ButtonSecondary
|
||||||
|
v-tippy="{ theme: 'tooltip' }"
|
||||||
|
:title="t('action.remove')"
|
||||||
|
svg="trash"
|
||||||
|
color="red"
|
||||||
|
@click.native="deleteUrlEncodedParam(index)"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</draggable>
|
||||||
<div
|
<div
|
||||||
v-if="workingUrlEncodedParams.length === 0"
|
v-if="workingUrlEncodedParams.length === 0"
|
||||||
class="flex flex-col items-center justify-center p-4 text-secondaryLight"
|
class="flex flex-col items-center justify-center p-4 text-secondaryLight"
|
||||||
@@ -146,6 +167,7 @@ import * as O from "fp-ts/Option"
|
|||||||
import * as RA from "fp-ts/ReadonlyArray"
|
import * as RA from "fp-ts/ReadonlyArray"
|
||||||
import * as E from "fp-ts/Either"
|
import * as E from "fp-ts/Either"
|
||||||
import { cloneDeep } from "lodash"
|
import { cloneDeep } from "lodash"
|
||||||
|
import draggable from "vuedraggable"
|
||||||
import { useCodemirror } from "~/helpers/editor/codemirror"
|
import { useCodemirror } from "~/helpers/editor/codemirror"
|
||||||
import linter from "~/helpers/editor/linting/rawKeyValue"
|
import linter from "~/helpers/editor/linting/rawKeyValue"
|
||||||
import { useRESTRequestBody } from "~/newstore/RESTSession"
|
import { useRESTRequestBody } from "~/newstore/RESTSession"
|
||||||
|
|||||||
@@ -51,61 +51,82 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<draggable
|
||||||
v-for="(protocol, index) of protocols"
|
v-model="protocols"
|
||||||
:key="`protocol-${index}`"
|
animation="250"
|
||||||
class="flex border-b divide-x divide-dividerLight border-dividerLight"
|
handle=".draggable-handle"
|
||||||
|
draggable=".draggable-content"
|
||||||
|
ghost-class="cursor-move"
|
||||||
|
chosen-class="bg-primaryLight"
|
||||||
|
drag-class="cursor-grabbing"
|
||||||
>
|
>
|
||||||
<input
|
<div
|
||||||
v-model="protocol.value"
|
v-for="(protocol, index) of protocols"
|
||||||
class="flex flex-1 px-4 py-2 bg-transparent"
|
:key="`protocol-${index}`"
|
||||||
:placeholder="$t('count.protocol', { count: index + 1 })"
|
class="flex border-b divide-x divide-dividerLight border-dividerLight draggable-content group"
|
||||||
name="message"
|
>
|
||||||
type="text"
|
<span>
|
||||||
autocomplete="off"
|
<ButtonSecondary
|
||||||
@change="
|
svg="grip-vertical"
|
||||||
updateProtocol(index, {
|
class="cursor-auto text-primary hover:text-primary"
|
||||||
value: $event.target.value,
|
:class="{
|
||||||
active: protocol.active,
|
'draggable-handle group-hover:text-secondaryLight !cursor-grab':
|
||||||
})
|
index !== protocols?.length - 1,
|
||||||
"
|
}"
|
||||||
/>
|
tabindex="-1"
|
||||||
<span>
|
/>
|
||||||
<ButtonSecondary
|
</span>
|
||||||
v-tippy="{ theme: 'tooltip' }"
|
<input
|
||||||
:title="
|
v-model="protocol.value"
|
||||||
protocol.hasOwnProperty('active')
|
class="flex flex-1 px-4 py-2 bg-transparent"
|
||||||
? protocol.active
|
:placeholder="$t('count.protocol', { count: index + 1 })"
|
||||||
? $t('action.turn_off')
|
name="message"
|
||||||
: $t('action.turn_on')
|
type="text"
|
||||||
: $t('action.turn_off')
|
autocomplete="off"
|
||||||
"
|
@change="
|
||||||
:svg="
|
|
||||||
protocol.hasOwnProperty('active')
|
|
||||||
? protocol.active
|
|
||||||
? 'check-circle'
|
|
||||||
: 'circle'
|
|
||||||
: 'check-circle'
|
|
||||||
"
|
|
||||||
color="green"
|
|
||||||
@click.native="
|
|
||||||
updateProtocol(index, {
|
updateProtocol(index, {
|
||||||
value: protocol.value,
|
value: $event.target.value,
|
||||||
active: !protocol.active,
|
active: protocol.active,
|
||||||
})
|
})
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
</span>
|
<span>
|
||||||
<span>
|
<ButtonSecondary
|
||||||
<ButtonSecondary
|
v-tippy="{ theme: 'tooltip' }"
|
||||||
v-tippy="{ theme: 'tooltip' }"
|
:title="
|
||||||
:title="$t('action.remove')"
|
protocol.hasOwnProperty('active')
|
||||||
svg="trash"
|
? protocol.active
|
||||||
color="red"
|
? $t('action.turn_off')
|
||||||
@click.native="deleteProtocol({ index })"
|
: $t('action.turn_on')
|
||||||
/>
|
: $t('action.turn_off')
|
||||||
</span>
|
"
|
||||||
</div>
|
:svg="
|
||||||
|
protocol.hasOwnProperty('active')
|
||||||
|
? protocol.active
|
||||||
|
? 'check-circle'
|
||||||
|
: 'circle'
|
||||||
|
: 'check-circle'
|
||||||
|
"
|
||||||
|
color="green"
|
||||||
|
@click.native="
|
||||||
|
updateProtocol(index, {
|
||||||
|
value: protocol.value,
|
||||||
|
active: !protocol.active,
|
||||||
|
})
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
<ButtonSecondary
|
||||||
|
v-tippy="{ theme: 'tooltip' }"
|
||||||
|
:title="$t('action.remove')"
|
||||||
|
svg="trash"
|
||||||
|
color="red"
|
||||||
|
@click.native="deleteProtocol({ index })"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</draggable>
|
||||||
<div
|
<div
|
||||||
v-if="protocols.length === 0"
|
v-if="protocols.length === 0"
|
||||||
class="flex flex-col items-center justify-center p-4 text-secondaryLight"
|
class="flex flex-col items-center justify-center p-4 text-secondaryLight"
|
||||||
@@ -162,6 +183,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import { defineComponent } from "@nuxtjs/composition-api"
|
import { defineComponent } from "@nuxtjs/composition-api"
|
||||||
import debounce from "lodash/debounce"
|
import debounce from "lodash/debounce"
|
||||||
|
import draggable from "vuedraggable"
|
||||||
import { logHoppRequestRunToAnalytics } from "~/helpers/fb/analytics"
|
import { logHoppRequestRunToAnalytics } from "~/helpers/fb/analytics"
|
||||||
import {
|
import {
|
||||||
setWSEndpoint,
|
setWSEndpoint,
|
||||||
@@ -185,6 +207,9 @@ import {
|
|||||||
import { useStream } from "~/helpers/utils/composables"
|
import { useStream } from "~/helpers/utils/composables"
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
|
components: {
|
||||||
|
draggable,
|
||||||
|
},
|
||||||
setup() {
|
setup() {
|
||||||
return {
|
return {
|
||||||
url: useStream(WSEndpoint$, "", setWSEndpoint),
|
url: useStream(WSEndpoint$, "", setWSEndpoint),
|
||||||
|
|||||||
@@ -129,6 +129,9 @@ const initView = (el: any) => {
|
|||||||
clipboardEv = ev
|
clipboardEv = ev
|
||||||
pastedValue = ev.clipboardData?.getData("text") ?? ""
|
pastedValue = ev.clipboardData?.getData("text") ?? ""
|
||||||
},
|
},
|
||||||
|
drop(ev) {
|
||||||
|
ev.preventDefault()
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
ViewPlugin.fromClass(
|
ViewPlugin.fromClass(
|
||||||
class {
|
class {
|
||||||
|
|||||||
@@ -111,6 +111,7 @@
|
|||||||
"vue-pdf-embed": "^1.1.0",
|
"vue-pdf-embed": "^1.1.0",
|
||||||
"vue-textarea-autosize": "^1.1.1",
|
"vue-textarea-autosize": "^1.1.1",
|
||||||
"vue-tippy": "^4.13.0",
|
"vue-tippy": "^4.13.0",
|
||||||
|
"vuedraggable": "^2.24.3",
|
||||||
"vuejs-auto-complete": "^0.9.0",
|
"vuejs-auto-complete": "^0.9.0",
|
||||||
"wonka": "^4.0.15",
|
"wonka": "^4.0.15",
|
||||||
"yargs-parser": "^21.0.1"
|
"yargs-parser": "^21.0.1"
|
||||||
|
|||||||
@@ -55,6 +55,8 @@ export default defineConfig({
|
|||||||
},
|
},
|
||||||
cursor: {
|
cursor: {
|
||||||
nsResize: "ns-resize",
|
nsResize: "ns-resize",
|
||||||
|
grab: "grab",
|
||||||
|
grabbing: "grabbing",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
735
pnpm-lock.yaml
generated
735
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user