index.vue 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. <template>
  2. <div :class="{ 'rounded border border-divider': savingMode }">
  3. <div
  4. class="sticky top-0 z-10 flex flex-col border-b divide-dividerLight divide-y border-dividerLight"
  5. :class="{ 'bg-primary': !savingMode }"
  6. >
  7. <input
  8. v-if="showCollActions"
  9. v-model="filterText"
  10. type="search"
  11. autocomplete="off"
  12. :placeholder="$t('action.search')"
  13. class="flex px-4 py-2 bg-transparent"
  14. />
  15. <div class="flex justify-between flex-1">
  16. <ButtonSecondary
  17. svg="plus"
  18. :label="$t('action.new')"
  19. class="!rounded-none"
  20. @click.native="displayModalAdd(true)"
  21. />
  22. <div class="flex">
  23. <ButtonSecondary
  24. v-tippy="{ theme: 'tooltip' }"
  25. to="https://docs.hoppscotch.io/features/collections"
  26. blank
  27. :title="$t('app.wiki')"
  28. svg="help-circle"
  29. />
  30. <ButtonSecondary
  31. v-if="showCollActions"
  32. v-tippy="{ theme: 'tooltip' }"
  33. :title="$t('modal.import_export')"
  34. svg="archive"
  35. @click.native="displayModalImportExport(true)"
  36. />
  37. </div>
  38. </div>
  39. </div>
  40. <div class="flex-col">
  41. <CollectionsGraphqlCollection
  42. v-for="(collection, index) in filteredCollections"
  43. :key="`collection-${index}`"
  44. :picked="picked"
  45. :name="collection.name"
  46. :collection-index="index"
  47. :collection="collection"
  48. :doc="doc"
  49. :is-filtered="filterText.length > 0"
  50. :saving-mode="savingMode"
  51. @edit-collection="editCollection(collection, index)"
  52. @add-folder="addFolder($event)"
  53. @edit-folder="editFolder($event)"
  54. @edit-request="editRequest($event)"
  55. @duplicate-request="duplicateRequest($event)"
  56. @select-collection="$emit('use-collection', collection)"
  57. @select="$emit('select', $event)"
  58. />
  59. </div>
  60. <div
  61. v-if="collections.length === 0"
  62. class="flex flex-col items-center justify-center p-4 text-secondaryLight"
  63. >
  64. <img
  65. :src="`/images/states/${$colorMode.value}/pack.svg`"
  66. loading="lazy"
  67. class="inline-flex flex-col object-contain object-center w-16 h-16 my-4"
  68. :alt="$t('empty.collections')"
  69. />
  70. <span class="pb-4 text-center">
  71. {{ $t("empty.collections") }}
  72. </span>
  73. <ButtonSecondary
  74. :label="$t('add.new')"
  75. filled
  76. @click.native="displayModalAdd(true)"
  77. />
  78. </div>
  79. <div
  80. v-if="!(filteredCollections.length !== 0 || collections.length === 0)"
  81. class="flex flex-col items-center justify-center p-4 text-secondaryLight"
  82. >
  83. <i class="pb-2 opacity-75 material-icons">manage_search</i>
  84. <span class="my-2 text-center">
  85. {{ $t("state.nothing_found") }} "{{ filterText }}"
  86. </span>
  87. </div>
  88. <CollectionsGraphqlAdd
  89. :show="showModalAdd"
  90. @hide-modal="displayModalAdd(false)"
  91. />
  92. <CollectionsGraphqlEdit
  93. :show="showModalEdit"
  94. :editing-collection="editingCollection"
  95. :editing-collection-index="editingCollectionIndex"
  96. :editing-collection-name="editingCollection ? editingCollection.name : ''"
  97. @hide-modal="displayModalEdit(false)"
  98. />
  99. <CollectionsGraphqlAddFolder
  100. :show="showModalAddFolder"
  101. :folder-path="editingFolderPath"
  102. @add-folder="onAddFolder($event)"
  103. @hide-modal="displayModalAddFolder(false)"
  104. />
  105. <CollectionsGraphqlEditFolder
  106. :show="showModalEditFolder"
  107. :collection-index="editingCollectionIndex"
  108. :folder="editingFolder"
  109. :folder-index="editingFolderIndex"
  110. :folder-path="editingFolderPath"
  111. :editing-folder-name="editingFolder ? editingFolder.name : ''"
  112. @hide-modal="displayModalEditFolder(false)"
  113. />
  114. <CollectionsGraphqlEditRequest
  115. :show="showModalEditRequest"
  116. :folder-path="editingFolderPath"
  117. :request="editingRequest"
  118. :request-index="editingRequestIndex"
  119. :editing-request-name="editingRequest ? editingRequest.name : ''"
  120. @hide-modal="displayModalEditRequest(false)"
  121. />
  122. <CollectionsGraphqlImportExport
  123. :show="showModalImportExport"
  124. @hide-modal="displayModalImportExport(false)"
  125. />
  126. </div>
  127. </template>
  128. <script>
  129. import { defineComponent } from "@nuxtjs/composition-api"
  130. import cloneDeep from "lodash/cloneDeep"
  131. import clone from "lodash/clone"
  132. import { useReadonlyStream } from "~/helpers/utils/composables"
  133. import {
  134. graphqlCollections$,
  135. addGraphqlFolder,
  136. saveGraphqlRequestAs,
  137. } from "~/newstore/collections"
  138. export default defineComponent({
  139. props: {
  140. // Whether to activate the ability to pick items (activates 'select' events)
  141. savingMode: { type: Boolean, default: false },
  142. doc: { type: Boolean, default: false },
  143. picked: { type: Object, default: null },
  144. // Whether to show the 'New' and 'Import/Export' actions
  145. showCollActions: { type: Boolean, default: true },
  146. },
  147. setup() {
  148. return {
  149. collections: useReadonlyStream(graphqlCollections$, []),
  150. }
  151. },
  152. data() {
  153. return {
  154. showModalAdd: false,
  155. showModalEdit: false,
  156. showModalImportExport: false,
  157. showModalAddFolder: false,
  158. showModalEditFolder: false,
  159. showModalEditRequest: false,
  160. editingCollection: undefined,
  161. editingCollectionIndex: undefined,
  162. editingFolder: undefined,
  163. editingFolderName: undefined,
  164. editingFolderIndex: undefined,
  165. editingFolderPath: undefined,
  166. editingRequest: undefined,
  167. editingRequestIndex: undefined,
  168. filterText: "",
  169. }
  170. },
  171. computed: {
  172. filteredCollections() {
  173. const collections = clone(this.collections)
  174. if (!this.filterText) return collections
  175. const filterText = this.filterText.toLowerCase()
  176. const filteredCollections = []
  177. for (const collection of collections) {
  178. const filteredRequests = []
  179. const filteredFolders = []
  180. for (const request of collection.requests) {
  181. if (request.name.toLowerCase().includes(filterText))
  182. filteredRequests.push(request)
  183. }
  184. for (const folder of collection.folders) {
  185. const filteredFolderRequests = []
  186. for (const request of folder.requests) {
  187. if (request.name.toLowerCase().includes(filterText))
  188. filteredFolderRequests.push(request)
  189. }
  190. if (filteredFolderRequests.length > 0) {
  191. const filteredFolder = Object.assign({}, folder)
  192. filteredFolder.requests = filteredFolderRequests
  193. filteredFolders.push(filteredFolder)
  194. }
  195. }
  196. if (filteredRequests.length + filteredFolders.length > 0) {
  197. const filteredCollection = Object.assign({}, collection)
  198. filteredCollection.requests = filteredRequests
  199. filteredCollection.folders = filteredFolders
  200. filteredCollections.push(filteredCollection)
  201. }
  202. }
  203. return filteredCollections
  204. },
  205. },
  206. methods: {
  207. displayModalAdd(shouldDisplay) {
  208. this.showModalAdd = shouldDisplay
  209. },
  210. displayModalEdit(shouldDisplay) {
  211. this.showModalEdit = shouldDisplay
  212. if (!shouldDisplay) this.resetSelectedData()
  213. },
  214. displayModalImportExport(shouldDisplay) {
  215. this.showModalImportExport = shouldDisplay
  216. },
  217. displayModalAddFolder(shouldDisplay) {
  218. this.showModalAddFolder = shouldDisplay
  219. if (!shouldDisplay) this.resetSelectedData()
  220. },
  221. displayModalEditFolder(shouldDisplay) {
  222. this.showModalEditFolder = shouldDisplay
  223. if (!shouldDisplay) this.resetSelectedData()
  224. },
  225. displayModalEditRequest(shouldDisplay) {
  226. this.showModalEditRequest = shouldDisplay
  227. if (!shouldDisplay) this.resetSelectedData()
  228. },
  229. editCollection(collection, collectionIndex) {
  230. this.$data.editingCollection = collection
  231. this.$data.editingCollectionIndex = collectionIndex
  232. this.displayModalEdit(true)
  233. },
  234. onAddFolder({ name, path }) {
  235. addGraphqlFolder(name, path)
  236. this.displayModalAddFolder(false)
  237. },
  238. addFolder(payload) {
  239. const { path } = payload
  240. this.$data.editingFolderPath = path
  241. this.displayModalAddFolder(true)
  242. },
  243. editFolder(payload) {
  244. const { folder, folderPath } = payload
  245. this.editingFolder = folder
  246. this.editingFolderPath = folderPath
  247. this.displayModalEditFolder(true)
  248. },
  249. editRequest(payload) {
  250. const {
  251. collectionIndex,
  252. folderIndex,
  253. folderName,
  254. request,
  255. requestIndex,
  256. folderPath,
  257. } = payload
  258. this.$data.editingFolderPath = folderPath
  259. this.$data.editingCollectionIndex = collectionIndex
  260. this.$data.editingFolderIndex = folderIndex
  261. this.$data.editingFolderName = folderName
  262. this.$data.editingRequest = request
  263. this.$data.editingRequestIndex = requestIndex
  264. this.displayModalEditRequest(true)
  265. },
  266. resetSelectedData() {
  267. this.$data.editingCollection = undefined
  268. this.$data.editingCollectionIndex = undefined
  269. this.$data.editingFolder = undefined
  270. this.$data.editingFolderIndex = undefined
  271. this.$data.editingRequest = undefined
  272. this.$data.editingRequestIndex = undefined
  273. },
  274. duplicateRequest({ folderPath, request }) {
  275. saveGraphqlRequestAs(folderPath, {
  276. ...cloneDeep(request),
  277. name: `${request.name} - ${this.$t("action.duplicate")}`,
  278. })
  279. },
  280. },
  281. })
  282. </script>