123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682 |
- <template>
- <AppSection
- label="collections"
- :class="{ 'rounded border border-divider': saveRequest }"
- >
- <div
- class="
- divide-y divide-dividerLight
- bg-primary
- border-b border-dividerLight
- rounded-t
- flex flex-col
- top-0
- z-10
- sticky
- "
- :class="{ '!top-sidebarPrimaryStickyFold': !saveRequest && !doc }"
- >
- <div v-if="!saveRequest" class="search-wrappe">
- <input
- v-model="filterText"
- type="search"
- autocomplete="off"
- :placeholder="$t('action.search')"
- class="bg-transparent flex w-full py-2 pr-2 pl-4"
- />
- </div>
- <CollectionsChooseType
- :collections-type="collectionsType"
- :show="showTeamCollections"
- :doc="doc"
- @update-collection-type="updateCollectionType"
- @update-selected-team="updateSelectedTeam"
- />
- <div class="flex flex-1 justify-between">
- <ButtonSecondary
- v-if="
- collectionsType.type == 'team-collections' &&
- (collectionsType.selectedTeam == undefined ||
- collectionsType.selectedTeam.myRole == 'VIEWER')
- "
- v-tippy="{ theme: 'tooltip' }"
- disabled
- class="!rounded-none"
- svg="plus"
- :title="$t('team.no_access')"
- :label="$t('action.new')"
- />
- <ButtonSecondary
- v-else
- svg="plus"
- :label="$t('action.new')"
- class="!rounded-none"
- @click.native="displayModalAdd(true)"
- />
- <span class="flex">
- <ButtonSecondary
- v-tippy="{ theme: 'tooltip' }"
- to="https://docs.hoppscotch.io/features/collections"
- blank
- :title="$t('app.wiki')"
- svg="help-circle"
- />
- <ButtonSecondary
- v-if="!saveRequest"
- v-tippy="{ theme: 'tooltip' }"
- :disabled="
- collectionsType.type == 'team-collections' &&
- collectionsType.selectedTeam == undefined
- "
- svg="archive"
- :title="$t('modal.import_export')"
- @click.native="displayModalImportExport(true)"
- />
- </span>
- </div>
- </div>
- <div class="flex flex-col">
- <component
- :is="
- collectionsType.type == 'my-collections'
- ? 'CollectionsMyCollection'
- : 'CollectionsTeamsCollection'
- "
- v-for="(collection, index) in filteredCollections"
- :key="`collection-${index}`"
- :collection-index="index"
- :collection="collection"
- :doc="doc"
- :is-filtered="filterText.length > 0"
- :selected="selected.some((coll) => coll == collection)"
- :save-request="saveRequest"
- :collections-type="collectionsType"
- :picked="picked"
- @edit-collection="editCollection(collection, index)"
- @add-folder="addFolder($event)"
- @edit-folder="editFolder($event)"
- @edit-request="editRequest($event)"
- @update-team-collections="updateTeamCollections"
- @select-collection="$emit('use-collection', collection)"
- @unselect-collection="$emit('remove-collection', collection)"
- @select="$emit('select', $event)"
- @expand-collection="expandCollection"
- @remove-collection="removeCollection"
- @remove-request="removeRequest"
- />
- </div>
- <div
- v-if="filteredCollections.length === 0 && filterText.length === 0"
- class="flex flex-col text-secondaryLight p-4 items-center justify-center"
- >
- <span class="text-center pb-4">
- {{ $t("empty.collections") }}
- </span>
- <ButtonSecondary
- v-if="
- collectionsType.type == 'team-collections' &&
- (collectionsType.selectedTeam == undefined ||
- collectionsType.selectedTeam.myRole == 'VIEWER')
- "
- v-tippy="{ theme: 'tooltip' }"
- :title="$t('team.no_access')"
- :label="$t('add.new')"
- filled
- />
- <ButtonSecondary
- v-else
- :label="$t('add.new')"
- filled
- @click.native="displayModalAdd(true)"
- />
- </div>
- <div
- v-if="filterText.length !== 0 && filteredCollections.length === 0"
- class="flex flex-col text-secondaryLight p-4 items-center justify-center"
- >
- <i class="opacity-75 pb-2 material-icons">manage_search</i>
- <span class="text-center">
- {{ $t("state.nothing_found") }} "{{ filterText }}"
- </span>
- </div>
- <CollectionsAdd
- :show="showModalAdd"
- @submit="addNewRootCollection"
- @hide-modal="displayModalAdd(false)"
- />
- <CollectionsEdit
- :show="showModalEdit"
- :editing-coll-name="editingCollection ? editingCollection.name : ''"
- :placeholder-coll-name="editingCollection ? editingCollection.name : ''"
- @hide-modal="displayModalEdit(false)"
- @submit="updateEditingCollection"
- />
- <CollectionsAddFolder
- :show="showModalAddFolder"
- :folder="editingFolder"
- :folder-path="editingFolderPath"
- @add-folder="onAddFolder($event)"
- @hide-modal="displayModalAddFolder(false)"
- />
- <CollectionsEditFolder
- :show="showModalEditFolder"
- @submit="updateEditingFolder"
- @hide-modal="displayModalEditFolder(false)"
- />
- <CollectionsEditRequest
- :show="showModalEditRequest"
- :placeholder-req-name="editingRequest ? editingRequest.name : ''"
- @submit="updateEditingRequest"
- @hide-modal="displayModalEditRequest(false)"
- />
- <CollectionsImportExport
- :show="showModalImportExport"
- :collections-type="collectionsType"
- @hide-modal="displayModalImportExport(false)"
- @update-team-collections="updateTeamCollections"
- />
- </AppSection>
- </template>
- <script>
- import gql from "graphql-tag"
- import cloneDeep from "lodash/cloneDeep"
- import { defineComponent } from "@nuxtjs/composition-api"
- import CollectionsMyCollection from "./my/Collection.vue"
- import CollectionsTeamsCollection from "./teams/Collection.vue"
- import { currentUser$ } from "~/helpers/fb/auth"
- import TeamCollectionAdapter from "~/helpers/teams/TeamCollectionAdapter"
- import * as teamUtils from "~/helpers/teams/utils"
- import {
- restCollections$,
- addRESTCollection,
- editRESTCollection,
- addRESTFolder,
- removeRESTCollection,
- editRESTFolder,
- removeRESTRequest,
- editRESTRequest,
- } from "~/newstore/collections"
- import {
- useReadonlyStream,
- useStreamSubscriber,
- } from "~/helpers/utils/composables"
- export default defineComponent({
- components: {
- CollectionsMyCollection,
- CollectionsTeamsCollection,
- },
- props: {
- doc: Boolean,
- selected: { type: Array, default: () => [] },
- saveRequest: Boolean,
- picked: { type: Object, default: () => {} },
- },
- setup() {
- const { subscribeToStream } = useStreamSubscriber()
- return {
- subscribeTo: subscribeToStream,
- collections: useReadonlyStream(restCollections$, []),
- currentUser: useReadonlyStream(currentUser$, null),
- }
- },
- data() {
- return {
- showModalAdd: false,
- showModalEdit: false,
- showModalImportExport: false,
- showModalAddFolder: false,
- showModalEditFolder: false,
- showModalEditRequest: false,
- editingCollection: undefined,
- editingCollectionIndex: undefined,
- editingFolder: undefined,
- editingFolderName: undefined,
- editingFolderIndex: undefined,
- editingFolderPath: undefined,
- editingRequest: undefined,
- editingRequestIndex: undefined,
- filterText: "",
- collectionsType: {
- type: "my-collections",
- selectedTeam: undefined,
- },
- teamCollectionAdapter: new TeamCollectionAdapter(null),
- teamCollectionsNew: [],
- }
- },
- computed: {
- showTeamCollections() {
- if (this.currentUser == null) {
- return false
- }
- return true
- },
- filteredCollections() {
- const collections =
- this.collectionsType.type === "my-collections"
- ? this.collections
- : this.teamCollectionsNew
- if (!this.filterText) {
- return collections
- }
- if (this.collectionsType.type === "team-collections") {
- return []
- }
- const filterText = this.filterText.toLowerCase()
- const filteredCollections = []
- for (const collection of collections) {
- const filteredRequests = []
- const filteredFolders = []
- for (const request of collection.requests) {
- if (request.name.toLowerCase().includes(filterText))
- filteredRequests.push(request)
- }
- for (const folder of this.collectionsType.type === "team-collections"
- ? collection.children
- : collection.folders) {
- const filteredFolderRequests = []
- for (const request of folder.requests) {
- if (request.name.toLowerCase().includes(filterText))
- filteredFolderRequests.push(request)
- }
- if (filteredFolderRequests.length > 0) {
- const filteredFolder = Object.assign({}, folder)
- filteredFolder.requests = filteredFolderRequests
- filteredFolders.push(filteredFolder)
- }
- }
- if (
- filteredRequests.length + filteredFolders.length > 0 ||
- collection.name.toLowerCase().includes(filterText)
- ) {
- const filteredCollection = Object.assign({}, collection)
- filteredCollection.requests = filteredRequests
- filteredCollection.folders = filteredFolders
- filteredCollections.push(filteredCollection)
- }
- }
- return filteredCollections
- },
- },
- watch: {
- "collectionsType.type": function emitstuff() {
- this.$emit("update-collection", this.$data.collectionsType.type)
- },
- "collectionsType.selectedTeam"(value) {
- if (value?.id) this.teamCollectionAdapter.changeTeamID(value.id)
- },
- },
- mounted() {
- this.subscribeTo(this.teamCollectionAdapter.collections$, (colls) => {
- this.teamCollectionsNew = cloneDeep(colls)
- })
- },
- methods: {
- updateTeamCollections() {
- // TODO: Remove this at some point
- },
- updateSelectedTeam(newSelectedTeam) {
- this.collectionsType.selectedTeam = newSelectedTeam
- this.$emit("update-coll-type", this.collectionsType)
- },
- updateCollectionType(newCollectionType) {
- this.collectionsType.type = newCollectionType
- this.$emit("update-coll-type", this.collectionsType)
- },
- // Intented to be called by the CollectionAdd modal submit event
- addNewRootCollection(name) {
- if (this.collectionsType.type === "my-collections") {
- addRESTCollection({
- name,
- folders: [],
- requests: [],
- })
- } else if (
- this.collectionsType.type === "team-collections" &&
- this.collectionsType.selectedTeam.myRole !== "VIEWER"
- ) {
- teamUtils
- .createNewRootCollection(
- this.$apollo,
- name,
- this.collectionsType.selectedTeam.id
- )
- .then(() => {
- this.$toast.success(this.$t("collection.created"), {
- icon: "done",
- })
- })
- .catch((e) => {
- this.$toast.error(this.$t("error.something_went_wrong"), {
- icon: "error_outline",
- })
- console.error(e)
- })
- }
- this.displayModalAdd(false)
- },
- // Intented to be called by CollectionEdit modal submit event
- updateEditingCollection(newName) {
- if (!newName) {
- this.$toast.error(this.$t("collection.invalid_name"), {
- icon: "error_outline",
- })
- return
- }
- if (this.collectionsType.type === "my-collections") {
- const collectionUpdated = {
- ...this.editingCollection,
- name: newName,
- }
- editRESTCollection(this.editingCollectionIndex, collectionUpdated)
- } else if (
- this.collectionsType.type === "team-collections" &&
- this.collectionsType.selectedTeam.myRole !== "VIEWER"
- ) {
- teamUtils
- .renameCollection(this.$apollo, newName, this.editingCollection.id)
- .then(() => {
- this.$toast.success(this.$t("collection.renamed"), {
- icon: "done",
- })
- })
- .catch((e) => {
- this.$toast.error(this.$t("error.something_went_wrong"), {
- icon: "error_outline",
- })
- console.error(e)
- })
- }
- this.displayModalEdit(false)
- },
- // Intended to be called by CollectionEditFolder modal submit event
- updateEditingFolder(name) {
- if (this.collectionsType.type === "my-collections") {
- editRESTFolder(this.editingFolderPath, { ...this.editingFolder, name })
- } else if (
- this.collectionsType.type === "team-collections" &&
- this.collectionsType.selectedTeam.myRole !== "VIEWER"
- ) {
- teamUtils
- .renameCollection(this.$apollo, name, this.editingFolder.id)
- .then(() => {
- this.$toast.success(this.$t("folder.renamed"), {
- icon: "done",
- })
- })
- .catch((e) => {
- this.$toast.error(this.$t("error.something_went_wrong"), {
- icon: "error_outline",
- })
- console.error(e)
- })
- }
- this.displayModalEditFolder(false)
- },
- // Intented to by called by CollectionsEditRequest modal submit event
- updateEditingRequest(requestUpdateData) {
- const requestUpdated = {
- ...this.editingRequest,
- name: requestUpdateData.name || this.editingRequest.name,
- }
- if (this.collectionsType.type === "my-collections") {
- editRESTRequest(
- this.editingFolderPath,
- this.editingRequestIndex,
- requestUpdated
- )
- } else if (
- this.collectionsType.type === "team-collections" &&
- this.collectionsType.selectedTeam.myRole !== "VIEWER"
- ) {
- const requestName = requestUpdateData.name || this.editingRequest.name
- teamUtils
- .updateRequest(
- this.$apollo,
- requestUpdated,
- requestName,
- this.editingRequestIndex
- )
- .then(() => {
- this.$toast.success(this.$t("request.renamed"), {
- icon: "done",
- })
- this.$emit("update-team-collections")
- })
- .catch((e) => {
- this.$toast.error(this.$t("error.something_went_wrong"), {
- icon: "error_outline",
- })
- console.error(e)
- })
- }
- this.displayModalEditRequest(false)
- },
- displayModalAdd(shouldDisplay) {
- this.showModalAdd = shouldDisplay
- },
- displayModalEdit(shouldDisplay) {
- this.showModalEdit = shouldDisplay
- if (!shouldDisplay) this.resetSelectedData()
- },
- displayModalImportExport(shouldDisplay) {
- this.showModalImportExport = shouldDisplay
- },
- displayModalAddFolder(shouldDisplay) {
- this.showModalAddFolder = shouldDisplay
- if (!shouldDisplay) this.resetSelectedData()
- },
- displayModalEditFolder(shouldDisplay) {
- this.showModalEditFolder = shouldDisplay
- if (!shouldDisplay) this.resetSelectedData()
- },
- displayModalEditRequest(shouldDisplay) {
- this.showModalEditRequest = shouldDisplay
- if (!shouldDisplay) this.resetSelectedData()
- },
- editCollection(collection, collectionIndex) {
- this.$data.editingCollection = collection
- this.$data.editingCollectionIndex = collectionIndex
- this.displayModalEdit(true)
- },
- onAddFolder({ name, folder, path }) {
- if (this.collectionsType.type === "my-collections") {
- addRESTFolder(name, path)
- } else if (this.collectionsType.type === "team-collections") {
- if (this.collectionsType.selectedTeam.myRole !== "VIEWER") {
- this.$apollo
- .mutate({
- mutation: gql`
- mutation CreateChildCollection(
- $childTitle: String!
- $collectionID: String!
- ) {
- createChildCollection(
- childTitle: $childTitle
- collectionID: $collectionID
- ) {
- id
- }
- }
- `,
- // Parameters
- variables: {
- childTitle: name,
- collectionID: folder.id,
- },
- })
- .then(() => {
- this.$toast.success(this.$t("folder.created"), {
- icon: "done",
- })
- this.$emit("update-team-collections")
- })
- .catch((e) => {
- this.$toast.error(this.$t("error.something_went_wrong"), {
- icon: "error_outline",
- })
- console.error(e)
- })
- }
- }
- this.displayModalAddFolder(false)
- },
- addFolder(payload) {
- const { folder, path } = payload
- this.$data.editingFolder = folder
- this.$data.editingFolderPath = path
- this.displayModalAddFolder(true)
- },
- editFolder(payload) {
- const { collectionIndex, folder, folderIndex, folderPath } = payload
- this.$data.editingCollectionIndex = collectionIndex
- this.$data.editingFolder = folder
- this.$data.editingFolderIndex = folderIndex
- this.$data.editingFolderPath = folderPath
- this.$data.collectionsType = this.collectionsType
- this.displayModalEditFolder(true)
- },
- editRequest(payload) {
- const {
- collectionIndex,
- folderIndex,
- folderName,
- request,
- requestIndex,
- folderPath,
- } = payload
- this.$data.editingCollectionIndex = collectionIndex
- this.$data.editingFolderIndex = folderIndex
- this.$data.editingFolderName = folderName
- this.$data.editingRequest = request
- this.$data.editingRequestIndex = requestIndex
- this.editingFolderPath = folderPath
- this.$emit("select-request", requestIndex)
- this.displayModalEditRequest(true)
- },
- resetSelectedData() {
- this.$data.editingCollection = undefined
- this.$data.editingCollectionIndex = undefined
- this.$data.editingFolder = undefined
- this.$data.editingFolderIndex = undefined
- this.$data.editingRequest = undefined
- this.$data.editingRequestIndex = undefined
- },
- expandCollection(collectionID) {
- this.teamCollectionAdapter.expandCollection(collectionID)
- },
- removeCollection({ collectionsType, collectionIndex, collectionID }) {
- if (collectionsType.type === "my-collections") {
- // Cancel pick if picked collection is deleted
- if (
- this.picked &&
- this.picked.pickedType === "my-collection" &&
- this.picked.collectionIndex === collectionIndex
- ) {
- this.$emit("select", { picked: null })
- }
- removeRESTCollection(collectionIndex)
- this.$toast.success(this.$t("state.deleted"), {
- icon: "delete",
- })
- } else if (collectionsType.type === "team-collections") {
- // Cancel pick if picked collection is deleted
- if (
- this.picked &&
- this.picked.pickedType === "teams-collection" &&
- this.picked.collectionID === collectionID
- ) {
- this.$emit("select", { picked: null })
- }
- if (collectionsType.selectedTeam.myRole !== "VIEWER") {
- this.$apollo
- .mutate({
- // Query
- mutation: gql`
- mutation ($collectionID: String!) {
- deleteCollection(collectionID: $collectionID)
- }
- `,
- // Parameters
- variables: {
- collectionID,
- },
- })
- .then(() => {
- this.$toast.success(this.$t("state.deleted"), {
- icon: "delete",
- })
- })
- .catch((e) => {
- this.$toast.error(this.$t("error.something_went_wrong"), {
- icon: "error_outline",
- })
- console.error(e)
- })
- }
- }
- },
- removeRequest({ requestIndex, folderPath }) {
- if (this.collectionsType.type === "my-collections") {
- // Cancel pick if the picked item is being deleted
- if (
- this.picked &&
- this.picked.pickedType === "my-request" &&
- this.picked.folderPath === folderPath &&
- this.picked.requestIndex === requestIndex
- ) {
- this.$emit("select", { picked: null })
- }
- removeRESTRequest(folderPath, requestIndex)
- this.$toast.success(this.$t("state.deleted"), {
- icon: "delete",
- })
- } else if (this.collectionsType.type === "team-collections") {
- // Cancel pick if the picked item is being deleted
- if (
- this.picked &&
- this.picked.pickedType === "teams-request" &&
- this.picked.requestID === requestIndex
- ) {
- this.$emit("select", { picked: null })
- }
- teamUtils
- .deleteRequest(this.$apollo, requestIndex)
- .then(() => {
- this.$toast.success(this.$t("state.deleted"), {
- icon: "delete",
- })
- })
- .catch((e) => {
- this.$toast.error(this.$t("error.something_went_wrong"), {
- icon: "error_outline",
- })
- console.error(e)
- })
- }
- },
- },
- })
- </script>
|