feat: duplicate REST/GraphQL collections (#4211)
Co-authored-by: Andrew Bastin <andrewbastin.k@gmail.com> Co-authored-by: nivedin <nivedinp@gmail.com>
This commit is contained in:
@@ -102,6 +102,11 @@
|
||||
@keyup.r="requestAction?.$el.click()"
|
||||
@keyup.n="folderAction?.$el.click()"
|
||||
@keyup.e="edit?.$el.click()"
|
||||
@keyup.d="
|
||||
showDuplicateCollectionAction
|
||||
? duplicateAction?.$el.click()
|
||||
: null
|
||||
"
|
||||
@keyup.delete="deleteAction?.$el.click()"
|
||||
@keyup.x="exportAction?.$el.click()"
|
||||
@keyup.p="propertiesAction?.$el.click()"
|
||||
@@ -144,6 +149,20 @@
|
||||
}
|
||||
"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
v-if="showDuplicateCollectionAction"
|
||||
ref="duplicateAction"
|
||||
:icon="IconCopy"
|
||||
:label="t('action.duplicate')"
|
||||
:loading="duplicateCollectionLoading"
|
||||
:shortcut="['D']"
|
||||
@click="
|
||||
() => {
|
||||
emit('duplicate-collection'),
|
||||
collectionsType === 'my-collections' ? hide() : null
|
||||
}
|
||||
"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
ref="exportAction"
|
||||
:icon="IconDownload"
|
||||
@@ -229,7 +248,9 @@ import {
|
||||
changeCurrentReorderStatus,
|
||||
currentReorderingStatus$,
|
||||
} from "~/newstore/reordering"
|
||||
import { platform } from "~/platform"
|
||||
import IconCheckCircle from "~icons/lucide/check-circle"
|
||||
import IconCopy from "~icons/lucide/copy"
|
||||
import IconDownload from "~icons/lucide/download"
|
||||
import IconEdit from "~icons/lucide/edit"
|
||||
import IconFilePlus from "~icons/lucide/file-plus"
|
||||
@@ -263,6 +284,7 @@ const props = withDefaults(
|
||||
hasNoTeamAccess?: boolean
|
||||
collectionMoveLoading?: string[]
|
||||
isLastItem?: boolean
|
||||
duplicateCollectionLoading?: boolean
|
||||
}>(),
|
||||
{
|
||||
id: "",
|
||||
@@ -274,6 +296,7 @@ const props = withDefaults(
|
||||
exportLoading: false,
|
||||
hasNoTeamAccess: false,
|
||||
isLastItem: false,
|
||||
duplicateLoading: false,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -283,6 +306,7 @@ const emit = defineEmits<{
|
||||
(event: "add-folder"): void
|
||||
(event: "edit-collection"): void
|
||||
(event: "edit-properties"): void
|
||||
(event: "duplicate-collection"): void
|
||||
(event: "export-data"): void
|
||||
(event: "remove-collection"): void
|
||||
(event: "drop-event", payload: DataTransfer): void
|
||||
@@ -297,6 +321,7 @@ const tippyActions = ref<HTMLDivElement | null>(null)
|
||||
const requestAction = ref<HTMLButtonElement | null>(null)
|
||||
const folderAction = ref<HTMLButtonElement | null>(null)
|
||||
const edit = ref<HTMLButtonElement | null>(null)
|
||||
const duplicateAction = ref<HTMLButtonElement | null>(null)
|
||||
const deleteAction = ref<HTMLButtonElement | null>(null)
|
||||
const exportAction = ref<HTMLButtonElement | null>(null)
|
||||
const options = ref<TippyComponent | null>(null)
|
||||
@@ -314,6 +339,11 @@ const currentReorderingStatus = useReadonlyStream(currentReorderingStatus$, {
|
||||
parentID: "",
|
||||
})
|
||||
|
||||
const currentUser = useReadonlyStream(
|
||||
platform.auth.getCurrentUserStream(),
|
||||
platform.auth.getCurrentUser()
|
||||
)
|
||||
|
||||
// Used to determine if the collection is being dragged to a different destination
|
||||
// This is used to make the highlight effect work
|
||||
watch(
|
||||
@@ -340,10 +370,25 @@ const collectionName = computed(() => {
|
||||
return (props.data as TeamCollection).title
|
||||
})
|
||||
|
||||
const showDuplicateCollectionAction = computed(() => {
|
||||
// Show if the user is not logged in
|
||||
if (!currentUser.value) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (props.collectionsType === "team-collections") {
|
||||
return true
|
||||
}
|
||||
|
||||
// Duplicate collection action is disabled on SH until the issue with syncing is resolved
|
||||
return !platform.platformFeatureFlags
|
||||
.duplicateCollectionDisabledInPersonalWorkspace
|
||||
})
|
||||
|
||||
watch(
|
||||
() => props.exportLoading,
|
||||
(val) => {
|
||||
if (!val) {
|
||||
() => [props.exportLoading, props.duplicateCollectionLoading],
|
||||
([newExportLoadingVal, newDuplicateCollectionLoadingVal]) => {
|
||||
if (!newExportLoadingVal && !newDuplicateCollectionLoadingVal) {
|
||||
options.value!.tippy?.hide()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -418,7 +418,7 @@ const HoppTeamCollectionsExporter: ImporterOrExporter = {
|
||||
metadata: {
|
||||
id: "hopp_team_collections",
|
||||
name: "export.as_json",
|
||||
title: "export.as_json_description",
|
||||
title: "export.as_json",
|
||||
icon: IconUser,
|
||||
disabled: false,
|
||||
applicableTo: ["team-workspace"],
|
||||
@@ -435,18 +435,7 @@ const HoppTeamCollectionsExporter: ImporterOrExporter = {
|
||||
)
|
||||
|
||||
if (E.isRight(res)) {
|
||||
const { exportCollectionsToJSON } = res.right
|
||||
|
||||
if (!JSON.parse(exportCollectionsToJSON).length) {
|
||||
isHoppTeamCollectionExporterInProgress.value = false
|
||||
|
||||
return toast.error(t("error.no_collections_to_export"))
|
||||
}
|
||||
|
||||
initializeDownloadCollection(
|
||||
exportCollectionsToJSON,
|
||||
"team-collections"
|
||||
)
|
||||
initializeDownloadCollection(res.right, "team-collections")
|
||||
|
||||
platform.analytics?.logEvent({
|
||||
type: "HOPP_EXPORT_COLLECTION",
|
||||
@@ -454,7 +443,7 @@ const HoppTeamCollectionsExporter: ImporterOrExporter = {
|
||||
platform: "rest",
|
||||
})
|
||||
} else {
|
||||
toast.error(res.left.error.toString())
|
||||
toast.error(res.left)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -492,11 +481,6 @@ const HoppGistCollectionsExporter: ImporterOrExporter = {
|
||||
}
|
||||
|
||||
if (E.isRight(collectionJSON)) {
|
||||
if (!JSON.parse(collectionJSON.right).length) {
|
||||
isHoppGistCollectionExporterInProgress.value = false
|
||||
return toast.error(t("error.no_collections_to_export"))
|
||||
}
|
||||
|
||||
const res = await gistExporter(collectionJSON.right, accessToken)
|
||||
|
||||
if (E.isLeft(res)) {
|
||||
@@ -513,6 +497,8 @@ const HoppGistCollectionsExporter: ImporterOrExporter = {
|
||||
})
|
||||
|
||||
platform.io.openExternalLink(res.right)
|
||||
} else {
|
||||
toast.error(collectionJSON.left)
|
||||
}
|
||||
|
||||
isHoppGistCollectionExporterInProgress.value = false
|
||||
@@ -589,9 +575,7 @@ const getCollectionJSON = async () => {
|
||||
props.collectionsType.selectedTeam?.teamID
|
||||
)
|
||||
|
||||
return E.isRight(res)
|
||||
? E.right(res.right.exportCollectionsToJSON)
|
||||
: E.left(res.left)
|
||||
return E.isRight(res) ? E.right(res.right) : E.left(res.left)
|
||||
}
|
||||
|
||||
if (props.collectionsType.type === "my-collections") {
|
||||
|
||||
@@ -71,6 +71,13 @@
|
||||
collection: node.data.data.data,
|
||||
})
|
||||
"
|
||||
@duplicate-collection="
|
||||
node.data.type === 'collections' &&
|
||||
emit('duplicate-collection', {
|
||||
pathOrID: node.id,
|
||||
collectionSyncID: node.data.data.data.id,
|
||||
})
|
||||
"
|
||||
@edit-properties="
|
||||
node.data.type === 'collections' &&
|
||||
emit('edit-properties', {
|
||||
@@ -146,6 +153,13 @@
|
||||
folder: node.data.data.data,
|
||||
})
|
||||
"
|
||||
@duplicate-collection="
|
||||
node.data.type === 'folders' &&
|
||||
emit('duplicate-collection', {
|
||||
pathOrID: node.id,
|
||||
collectionSyncID: node.data.data.data.id,
|
||||
})
|
||||
"
|
||||
@edit-properties="
|
||||
node.data.type === 'folders' &&
|
||||
emit('edit-properties', {
|
||||
@@ -447,6 +461,13 @@ const emit = defineEmits<{
|
||||
folder: HoppCollection
|
||||
}
|
||||
): void
|
||||
(
|
||||
event: "duplicate-collection",
|
||||
payload: {
|
||||
pathOrID: string
|
||||
collectionSyncID?: string
|
||||
}
|
||||
): void
|
||||
(
|
||||
event: "edit-properties",
|
||||
payload: {
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
@dragover="handleDragOver($event)"
|
||||
@dragleave="resetDragState"
|
||||
@dragend="resetDragState"
|
||||
@contextmenu.prevent="options?.tippy.show()"
|
||||
@contextmenu.prevent="options?.tippy?.show()"
|
||||
>
|
||||
<div
|
||||
class="pointer-events-auto flex min-w-0 flex-1 cursor-pointer items-center justify-center"
|
||||
@@ -112,12 +112,11 @@
|
||||
ref="duplicate"
|
||||
:icon="IconCopy"
|
||||
:label="t('action.duplicate')"
|
||||
:loading="duplicateLoading"
|
||||
:loading="duplicateRequestLoading"
|
||||
:shortcut="['D']"
|
||||
@click="
|
||||
() => {
|
||||
emit('duplicate-request'),
|
||||
collectionsType === 'my-collections' ? hide() : null
|
||||
emit('duplicate-request')
|
||||
}
|
||||
"
|
||||
/>
|
||||
@@ -211,7 +210,7 @@ const props = defineProps({
|
||||
default: "my-collections",
|
||||
required: true,
|
||||
},
|
||||
duplicateLoading: {
|
||||
duplicateRequestLoading: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
required: false,
|
||||
@@ -259,7 +258,7 @@ const emit = defineEmits<{
|
||||
(event: "update-last-request-order", payload: DataTransfer): void
|
||||
}>()
|
||||
|
||||
const tippyActions = ref<TippyComponent | null>(null)
|
||||
const tippyActions = ref<HTMLButtonElement | null>(null)
|
||||
const edit = ref<HTMLButtonElement | null>(null)
|
||||
const deleteAction = ref<HTMLButtonElement | null>(null)
|
||||
const options = ref<TippyComponent | null>(null)
|
||||
@@ -277,10 +276,10 @@ const currentReorderingStatus = useReadonlyStream(currentReorderingStatus$, {
|
||||
})
|
||||
|
||||
watch(
|
||||
() => props.duplicateLoading,
|
||||
() => props.duplicateRequestLoading,
|
||||
(val) => {
|
||||
if (!val) {
|
||||
options.value!.tippy.hide()
|
||||
options.value!.tippy?.hide()
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
@@ -61,6 +61,7 @@
|
||||
:export-loading="exportLoading"
|
||||
:has-no-team-access="hasNoTeamAccess || isShowingSearchResults"
|
||||
:collection-move-loading="collectionMoveLoading"
|
||||
:duplicate-collection-loading="duplicateCollectionLoading"
|
||||
:is-last-item="node.data.isLastItem"
|
||||
:is-selected="
|
||||
isSelected({
|
||||
@@ -89,6 +90,12 @@
|
||||
collection: node.data.data.data,
|
||||
})
|
||||
"
|
||||
@duplicate-collection="
|
||||
node.data.type === 'collections' &&
|
||||
emit('duplicate-collection', {
|
||||
pathOrID: node.data.data.data.id,
|
||||
})
|
||||
"
|
||||
@edit-properties="
|
||||
node.data.type === 'collections' &&
|
||||
emit('edit-properties', {
|
||||
@@ -149,6 +156,7 @@
|
||||
:export-loading="exportLoading"
|
||||
:has-no-team-access="hasNoTeamAccess || isShowingSearchResults"
|
||||
:collection-move-loading="collectionMoveLoading"
|
||||
:duplicate-collection-loading="duplicateCollectionLoading"
|
||||
:is-last-item="node.data.isLastItem"
|
||||
:is-selected="
|
||||
isSelected({
|
||||
@@ -176,6 +184,12 @@
|
||||
folder: node.data.data.data,
|
||||
})
|
||||
"
|
||||
@duplicate-collection="
|
||||
node.data.type === 'folders' &&
|
||||
emit('duplicate-collection', {
|
||||
pathOrID: node.data.data.data.id,
|
||||
})
|
||||
"
|
||||
@edit-properties="
|
||||
node.data.type === 'folders' &&
|
||||
emit('edit-properties', {
|
||||
@@ -236,7 +250,7 @@
|
||||
:request-i-d="node.data.data.data.id"
|
||||
:parent-i-d="node.data.data.parentIndex"
|
||||
:collections-type="collectionsType.type"
|
||||
:duplicate-loading="duplicateLoading"
|
||||
:duplicate-request-loading="duplicateRequestLoading"
|
||||
:is-active="isActiveRequest(node.data.data.data.id)"
|
||||
:has-no-team-access="hasNoTeamAccess || isShowingSearchResults"
|
||||
:request-move-loading="requestMoveLoading"
|
||||
@@ -445,7 +459,12 @@ const props = defineProps({
|
||||
default: false,
|
||||
required: false,
|
||||
},
|
||||
duplicateLoading: {
|
||||
duplicateRequestLoading: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
required: false,
|
||||
},
|
||||
duplicateCollectionLoading: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
required: false,
|
||||
@@ -497,6 +516,13 @@ const emit = defineEmits<{
|
||||
folder: TeamCollection
|
||||
}
|
||||
): void
|
||||
(
|
||||
event: "duplicate-collection",
|
||||
payload: {
|
||||
pathOrID: string
|
||||
collectionSyncID?: string
|
||||
}
|
||||
): void
|
||||
(
|
||||
event: "edit-properties",
|
||||
payload: {
|
||||
|
||||
@@ -73,7 +73,13 @@
|
||||
@keyup.r="requestAction.$el.click()"
|
||||
@keyup.n="folderAction.$el.click()"
|
||||
@keyup.e="edit.$el.click()"
|
||||
@keyup.d="
|
||||
showDuplicateCollectionAction
|
||||
? duplicateAction.$el.click()
|
||||
: null
|
||||
"
|
||||
@keyup.delete="deleteAction.$el.click()"
|
||||
@keyup.p="propertiesAction.$el.click()"
|
||||
@keyup.escape="hide()"
|
||||
>
|
||||
<HoppSmartItem
|
||||
@@ -116,6 +122,22 @@
|
||||
}
|
||||
"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
v-if="showDuplicateCollectionAction"
|
||||
ref="duplicateAction"
|
||||
:icon="IconCopy"
|
||||
:label="t('action.duplicate')"
|
||||
:shortcut="['D']"
|
||||
@click="
|
||||
() => {
|
||||
emit('duplicate-collection', {
|
||||
path: `${collectionIndex}`,
|
||||
collectionSyncID: collection.id,
|
||||
}),
|
||||
hide()
|
||||
}
|
||||
"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
ref="deleteAction"
|
||||
:icon="IconTrash2"
|
||||
@@ -168,6 +190,7 @@
|
||||
@add-request="$emit('add-request', $event)"
|
||||
@add-folder="$emit('add-folder', $event)"
|
||||
@edit-folder="$emit('edit-folder', $event)"
|
||||
@duplicate-collection="$emit('duplicate-collection', $event)"
|
||||
@edit-request="$emit('edit-request', $event)"
|
||||
@duplicate-request="$emit('duplicate-request', $event)"
|
||||
@edit-properties="
|
||||
@@ -229,24 +252,27 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from "vue"
|
||||
import IconCheckCircle from "~icons/lucide/check-circle"
|
||||
import IconFolder from "~icons/lucide/folder"
|
||||
import IconFolderOpen from "~icons/lucide/folder-open"
|
||||
import IconFilePlus from "~icons/lucide/file-plus"
|
||||
import IconFolderPlus from "~icons/lucide/folder-plus"
|
||||
import IconMoreVertical from "~icons/lucide/more-vertical"
|
||||
import IconEdit from "~icons/lucide/edit"
|
||||
import IconTrash2 from "~icons/lucide/trash-2"
|
||||
import IconSettings2 from "~icons/lucide/settings-2"
|
||||
import { useToast } from "@composables/toast"
|
||||
import { useI18n } from "@composables/i18n"
|
||||
import { useColorMode } from "@composables/theming"
|
||||
import { removeGraphqlCollection } from "~/newstore/collections"
|
||||
import { Picked } from "~/helpers/types/HoppPicked"
|
||||
import { useService } from "dioc/vue"
|
||||
import { GQLTabService } from "~/services/tab/graphql"
|
||||
import { useToast } from "@composables/toast"
|
||||
import { HoppCollection } from "@hoppscotch/data"
|
||||
import { useService } from "dioc/vue"
|
||||
import { computed, ref } from "vue"
|
||||
import { useReadonlyStream } from "~/composables/stream"
|
||||
import { Picked } from "~/helpers/types/HoppPicked"
|
||||
import { removeGraphqlCollection } from "~/newstore/collections"
|
||||
import { platform } from "~/platform"
|
||||
import { GQLTabService } from "~/services/tab/graphql"
|
||||
import IconCheckCircle from "~icons/lucide/check-circle"
|
||||
import IconCopy from "~icons/lucide/copy"
|
||||
import IconEdit from "~icons/lucide/edit"
|
||||
import IconFilePlus from "~icons/lucide/file-plus"
|
||||
import IconFolder from "~icons/lucide/folder"
|
||||
import IconFolderOpen from "~icons/lucide/folder-open"
|
||||
import IconFolderPlus from "~icons/lucide/folder-plus"
|
||||
import IconMoreVertical from "~icons/lucide/more-vertical"
|
||||
import IconSettings2 from "~icons/lucide/settings-2"
|
||||
import IconTrash2 from "~icons/lucide/trash-2"
|
||||
|
||||
const props = defineProps<{
|
||||
picked: Picked | null
|
||||
@@ -271,6 +297,13 @@ const emit = defineEmits<{
|
||||
(e: "add-request", i: any): void
|
||||
(e: "add-folder", i: any): void
|
||||
(e: "edit-folder", i: any): void
|
||||
(
|
||||
e: "duplicate-collection",
|
||||
payload: {
|
||||
path: string
|
||||
collectionSyncID?: string
|
||||
}
|
||||
): void
|
||||
(
|
||||
e: "edit-properties",
|
||||
payload: {
|
||||
@@ -296,13 +329,20 @@ const options = ref<any | null>(null)
|
||||
const requestAction = ref<any | null>(null)
|
||||
const folderAction = ref<any | null>(null)
|
||||
const edit = ref<any | null>(null)
|
||||
const duplicateAction = ref<any | null>(null)
|
||||
const deleteAction = ref<any | null>(null)
|
||||
const propertiesAction = ref<any | null>(null)
|
||||
|
||||
const showChildren = ref(false)
|
||||
const dragging = ref(false)
|
||||
|
||||
const confirmRemove = ref(false)
|
||||
|
||||
const currentUser = useReadonlyStream(
|
||||
platform.auth.getCurrentUserStream(),
|
||||
platform.auth.getCurrentUser()
|
||||
)
|
||||
|
||||
const isSelected = computed(
|
||||
() =>
|
||||
props.picked?.pickedType === "gql-my-collection" &&
|
||||
@@ -315,6 +355,17 @@ const collectionIcon = computed(() => {
|
||||
return IconFolder
|
||||
})
|
||||
|
||||
const showDuplicateCollectionAction = computed(() => {
|
||||
// Show if the user is not logged in
|
||||
if (!currentUser.value) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Duplicate collection action is disabled on SH until the issue with syncing is resolved
|
||||
return !platform.platformFeatureFlags
|
||||
.duplicateCollectionDisabledInPersonalWorkspace
|
||||
})
|
||||
|
||||
const pick = () => {
|
||||
emit("select", {
|
||||
pickedType: "gql-my-collection",
|
||||
|
||||
@@ -70,7 +70,13 @@
|
||||
@keyup.r="requestAction.$el.click()"
|
||||
@keyup.n="folderAction.$el.click()"
|
||||
@keyup.e="edit.$el.click()"
|
||||
@keyup.d="
|
||||
showDuplicateCollectionAction
|
||||
? duplicateAction.$el.click()
|
||||
: null
|
||||
"
|
||||
@keyup.delete="deleteAction.$el.click()"
|
||||
@keyup.p="propertiesAction.$el.click()"
|
||||
@keyup.escape="hide()"
|
||||
>
|
||||
<HoppSmartItem
|
||||
@@ -109,6 +115,22 @@
|
||||
}
|
||||
"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
v-if="showDuplicateCollectionAction"
|
||||
ref="duplicateAction"
|
||||
:icon="IconCopy"
|
||||
:label="t('action.duplicate')"
|
||||
:shortcut="['D']"
|
||||
@click="
|
||||
() => {
|
||||
emit('duplicate-collection', {
|
||||
path: folderPath,
|
||||
collectionSyncID: folder.id,
|
||||
}),
|
||||
hide()
|
||||
}
|
||||
"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
ref="deleteAction"
|
||||
:icon="IconTrash2"
|
||||
@@ -162,6 +184,7 @@
|
||||
@add-request="emit('add-request', $event)"
|
||||
@add-folder="emit('add-folder', $event)"
|
||||
@edit-folder="emit('edit-folder', $event)"
|
||||
@duplicate-collection="emit('duplicate-collection', $event)"
|
||||
@edit-request="emit('edit-request', $event)"
|
||||
@duplicate-request="emit('duplicate-request', $event)"
|
||||
@edit-properties="
|
||||
@@ -213,24 +236,27 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import IconEdit from "~icons/lucide/edit"
|
||||
import IconTrash2 from "~icons/lucide/trash-2"
|
||||
import IconFolderPlus from "~icons/lucide/folder-plus"
|
||||
import IconFilePlus from "~icons/lucide/file-plus"
|
||||
import IconMoreVertical from "~icons/lucide/more-vertical"
|
||||
import IconCheckCircle from "~icons/lucide/check-circle"
|
||||
import IconFolder from "~icons/lucide/folder"
|
||||
import IconFolderOpen from "~icons/lucide/folder-open"
|
||||
import IconSettings2 from "~icons/lucide/settings-2"
|
||||
import { useToast } from "@composables/toast"
|
||||
import { useI18n } from "@composables/i18n"
|
||||
import { useColorMode } from "@composables/theming"
|
||||
import { removeGraphqlFolder } from "~/newstore/collections"
|
||||
import { computed, ref } from "vue"
|
||||
import { useService } from "dioc/vue"
|
||||
import { GQLTabService } from "~/services/tab/graphql"
|
||||
import { Picked } from "~/helpers/types/HoppPicked"
|
||||
import { useToast } from "@composables/toast"
|
||||
import { HoppCollection } from "@hoppscotch/data"
|
||||
import { useService } from "dioc/vue"
|
||||
import { computed, ref } from "vue"
|
||||
import { useReadonlyStream } from "~/composables/stream"
|
||||
import { Picked } from "~/helpers/types/HoppPicked"
|
||||
import { removeGraphqlFolder } from "~/newstore/collections"
|
||||
import { platform } from "~/platform"
|
||||
import { GQLTabService } from "~/services/tab/graphql"
|
||||
import IconCheckCircle from "~icons/lucide/check-circle"
|
||||
import IconCopy from "~icons/lucide/copy"
|
||||
import IconEdit from "~icons/lucide/edit"
|
||||
import IconFilePlus from "~icons/lucide/file-plus"
|
||||
import IconFolder from "~icons/lucide/folder"
|
||||
import IconFolderOpen from "~icons/lucide/folder-open"
|
||||
import IconFolderPlus from "~icons/lucide/folder-plus"
|
||||
import IconMoreVertical from "~icons/lucide/more-vertical"
|
||||
import IconSettings2 from "~icons/lucide/settings-2"
|
||||
import IconTrash2 from "~icons/lucide/trash-2"
|
||||
|
||||
const toast = useToast()
|
||||
const t = useI18n()
|
||||
@@ -255,6 +281,7 @@ const emit = defineEmits([
|
||||
"edit-request",
|
||||
"add-folder",
|
||||
"edit-folder",
|
||||
"duplicate-collection",
|
||||
"duplicate-request",
|
||||
"edit-properties",
|
||||
"select-request",
|
||||
@@ -267,12 +294,19 @@ const options = ref<any | null>(null)
|
||||
const requestAction = ref<any | null>(null)
|
||||
const folderAction = ref<any | null>(null)
|
||||
const edit = ref<any | null>(null)
|
||||
const duplicateAction = ref<any | null>(null)
|
||||
const deleteAction = ref<any | null>(null)
|
||||
const propertiesAction = ref<any | null>(null)
|
||||
|
||||
const showChildren = ref(false)
|
||||
const dragging = ref(false)
|
||||
const confirmRemove = ref(false)
|
||||
|
||||
const currentUser = useReadonlyStream(
|
||||
platform.auth.getCurrentUserStream(),
|
||||
platform.auth.getCurrentUser()
|
||||
)
|
||||
|
||||
const isSelected = computed(
|
||||
() =>
|
||||
props.picked?.pickedType === "gql-my-folder" &&
|
||||
@@ -285,6 +319,17 @@ const collectionIcon = computed(() => {
|
||||
return IconFolder
|
||||
})
|
||||
|
||||
const showDuplicateCollectionAction = computed(() => {
|
||||
// Show if the user is not logged in
|
||||
if (!currentUser.value) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Duplicate collection action is disabled on SH until the issue with syncing is resolved
|
||||
return !platform.platformFeatureFlags
|
||||
.duplicateCollectionDisabledInPersonalWorkspace
|
||||
})
|
||||
|
||||
const pick = () => {
|
||||
emit("select", {
|
||||
pickedType: "gql-my-folder",
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
@add-request="addRequest($event)"
|
||||
@add-folder="addFolder($event)"
|
||||
@edit-folder="editFolder($event)"
|
||||
@duplicate-collection="duplicateCollection($event)"
|
||||
@edit-request="editRequest($event)"
|
||||
@duplicate-request="duplicateRequest($event)"
|
||||
@select-collection="$emit('use-collection', collection)"
|
||||
@@ -167,6 +168,7 @@ import {
|
||||
editGraphqlCollection,
|
||||
editGraphqlFolder,
|
||||
moveGraphqlRequest,
|
||||
duplicateGraphQLCollection,
|
||||
} from "~/newstore/collections"
|
||||
import IconPlus from "~icons/lucide/plus"
|
||||
import IconHelpCircle from "~icons/lucide/help-circle"
|
||||
@@ -380,6 +382,14 @@ const editCollection = (
|
||||
displayModalEdit(true)
|
||||
}
|
||||
|
||||
const duplicateCollection = ({
|
||||
path,
|
||||
collectionSyncID,
|
||||
}: {
|
||||
path: string
|
||||
collectionSyncID?: string
|
||||
}) => duplicateGraphQLCollection(path, collectionSyncID)
|
||||
|
||||
const onAddRequest = ({
|
||||
name,
|
||||
path,
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
@add-request="addRequest"
|
||||
@edit-collection="editCollection"
|
||||
@edit-folder="editFolder"
|
||||
@duplicate-collection="duplicateCollection"
|
||||
@edit-properties="editProperties"
|
||||
@export-data="exportData"
|
||||
@remove-collection="removeCollection"
|
||||
@@ -67,7 +68,8 @@
|
||||
"
|
||||
:filter-text="filterTexts"
|
||||
:export-loading="exportLoading"
|
||||
:duplicate-loading="duplicateLoading"
|
||||
:duplicate-request-loading="duplicateRequestLoading"
|
||||
:duplicate-collection-loading="duplicateCollectionLoading"
|
||||
:save-request="saveRequest"
|
||||
:picked="picked"
|
||||
:collection-move-loading="collectionMoveLoading"
|
||||
@@ -76,6 +78,7 @@
|
||||
@add-folder="addFolder"
|
||||
@edit-collection="editCollection"
|
||||
@edit-folder="editFolder"
|
||||
@duplicate-collection="duplicateCollection"
|
||||
@edit-properties="editProperties"
|
||||
@export-data="exportData"
|
||||
@remove-collection="removeCollection"
|
||||
@@ -208,6 +211,7 @@ import {
|
||||
createChildCollection,
|
||||
createNewRootCollection,
|
||||
deleteCollection,
|
||||
duplicateTeamCollection,
|
||||
moveRESTTeamCollection,
|
||||
updateOrderRESTTeamCollection,
|
||||
updateTeamCollection,
|
||||
@@ -240,6 +244,7 @@ import {
|
||||
addRESTCollection,
|
||||
addRESTFolder,
|
||||
cascadeParentCollectionForHeaderAuth,
|
||||
duplicateRESTCollection,
|
||||
editRESTCollection,
|
||||
editRESTFolder,
|
||||
editRESTRequest,
|
||||
@@ -645,7 +650,8 @@ const isSelected = ({
|
||||
|
||||
const modalLoadingState = ref(false)
|
||||
const exportLoading = ref(false)
|
||||
const duplicateLoading = ref(false)
|
||||
const duplicateRequestLoading = ref(false)
|
||||
const duplicateCollectionLoading = ref(false)
|
||||
|
||||
const showModalAdd = ref(false)
|
||||
const showModalAddRequest = ref(false)
|
||||
@@ -1044,6 +1050,34 @@ const updateEditingFolder = (newName: string) => {
|
||||
}
|
||||
}
|
||||
|
||||
const duplicateCollection = async ({
|
||||
pathOrID,
|
||||
collectionSyncID,
|
||||
}: {
|
||||
pathOrID: string
|
||||
collectionSyncID?: string
|
||||
}) => {
|
||||
if (collectionsType.value.type === "my-collections") {
|
||||
duplicateRESTCollection(pathOrID, collectionSyncID)
|
||||
} else if (hasTeamWriteAccess.value) {
|
||||
duplicateCollectionLoading.value = true
|
||||
|
||||
await pipe(
|
||||
duplicateTeamCollection(pathOrID),
|
||||
TE.match(
|
||||
(err: GQLError<string>) => {
|
||||
toast.error(`${getErrorMessage(err)}`)
|
||||
duplicateCollectionLoading.value = false
|
||||
},
|
||||
() => {
|
||||
toast.success(t("collection.duplicated"))
|
||||
duplicateCollectionLoading.value = false
|
||||
}
|
||||
)
|
||||
)()
|
||||
}
|
||||
}
|
||||
|
||||
const editRequest = (payload: {
|
||||
folderPath: string | undefined
|
||||
requestIndex: string
|
||||
@@ -1149,7 +1183,7 @@ const duplicateRequest = (payload: {
|
||||
saveRESTRequestAs(folderPath, newRequest)
|
||||
toast.success(t("request.duplicated"))
|
||||
} else if (hasTeamWriteAccess.value) {
|
||||
duplicateLoading.value = true
|
||||
duplicateRequestLoading.value = true
|
||||
|
||||
if (!collectionsType.value.selectedTeam) return
|
||||
|
||||
@@ -1164,10 +1198,10 @@ const duplicateRequest = (payload: {
|
||||
TE.match(
|
||||
(err: GQLError<string>) => {
|
||||
toast.error(`${getErrorMessage(err)}`)
|
||||
duplicateLoading.value = false
|
||||
duplicateRequestLoading.value = false
|
||||
},
|
||||
() => {
|
||||
duplicateLoading.value = false
|
||||
duplicateRequestLoading.value = false
|
||||
toast.success(t("request.duplicated"))
|
||||
displayModalAddRequest(false)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user