feat: reorder key-value entries (#2189)

This commit is contained in:
Liyas Thomas
2022-03-24 19:47:20 +05:30
committed by Andrew Bastin
parent 0edfe7b8e3
commit 29d3f3cbe3
11 changed files with 989 additions and 667 deletions

View 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

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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),

View File

@@ -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 {

View File

@@ -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"

View File

@@ -55,6 +55,8 @@ export default defineConfig({
}, },
cursor: { cursor: {
nsResize: "ns-resize", nsResize: "ns-resize",
grab: "grab",
grabbing: "grabbing",
}, },
}, },
}, },

735
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff