index.vue 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. <template>
  2. <AppSection label="history">
  3. <div
  4. class="
  5. bg-primary
  6. border-b border-dividerLight
  7. flex
  8. top-sidebarPrimaryStickyFold
  9. z-10
  10. sticky
  11. "
  12. >
  13. <input
  14. v-model="filterText"
  15. type="search"
  16. autocomplete="off"
  17. class="bg-transparent flex w-full p-4 py-2"
  18. :placeholder="$t('action.search')"
  19. />
  20. <div class="flex">
  21. <ButtonSecondary
  22. v-tippy="{ theme: 'tooltip' }"
  23. to="https://docs.hoppscotch.io/features/history"
  24. blank
  25. :title="$t('app.wiki')"
  26. svg="help-circle"
  27. />
  28. <ButtonSecondary
  29. v-tippy="{ theme: 'tooltip' }"
  30. data-testid="clear_history"
  31. :disabled="history.length === 0"
  32. svg="trash-2"
  33. :title="$t('action.clear_all')"
  34. @click.native="confirmRemove = true"
  35. />
  36. </div>
  37. </div>
  38. <div class="flex flex-col">
  39. <div v-for="(entry, index) in filteredHistory" :key="`entry-${index}`">
  40. <HistoryRestCard
  41. v-if="page == 'rest'"
  42. :id="index"
  43. :entry="entry"
  44. :show-more="showMore"
  45. @toggle-star="toggleStar(entry)"
  46. @delete-entry="deleteHistory(entry)"
  47. @use-entry="useHistory(entry)"
  48. />
  49. <HistoryGraphqlCard
  50. v-if="page == 'graphql'"
  51. :entry="entry"
  52. :show-more="showMore"
  53. @toggle-star="toggleStar(entry)"
  54. @delete-entry="deleteHistory(entry)"
  55. @use-entry="useHistory(entry)"
  56. />
  57. </div>
  58. </div>
  59. <div
  60. v-if="!(filteredHistory.length !== 0 || history.length === 0)"
  61. class="flex flex-col text-secondaryLight p-4 items-center justify-center"
  62. >
  63. <i class="opacity-75 pb-2 material-icons">manage_search</i>
  64. <span class="text-center">
  65. {{ $t("state.nothing_found") }} "{{ filterText }}"
  66. </span>
  67. </div>
  68. <div
  69. v-if="history.length === 0"
  70. class="flex flex-col text-secondaryLight p-4 items-center justify-center"
  71. >
  72. <i class="opacity-75 pb-2 material-icons">schedule</i>
  73. <span class="text-center">
  74. {{ $t("empty.history") }}
  75. </span>
  76. </div>
  77. <SmartConfirmModal
  78. :show="confirmRemove"
  79. :title="$t('confirm.remove_history')"
  80. @hide-modal="confirmRemove = false"
  81. @resolve="clearHistory"
  82. />
  83. </AppSection>
  84. </template>
  85. <script lang="ts">
  86. import { defineComponent, PropType } from "@nuxtjs/composition-api"
  87. import { useReadonlyStream } from "~/helpers/utils/composables"
  88. import {
  89. restHistory$,
  90. graphqlHistory$,
  91. clearRESTHistory,
  92. clearGraphqlHistory,
  93. toggleGraphqlHistoryEntryStar,
  94. toggleRESTHistoryEntryStar,
  95. deleteGraphqlHistoryEntry,
  96. deleteRESTHistoryEntry,
  97. RESTHistoryEntry,
  98. GQLHistoryEntry,
  99. } from "~/newstore/history"
  100. import { setRESTRequest } from "~/newstore/RESTSession"
  101. export default defineComponent({
  102. props: {
  103. page: { type: String as PropType<"rest" | "graphql">, default: null },
  104. },
  105. setup(props) {
  106. return {
  107. history: useReadonlyStream<RESTHistoryEntry[] | GQLHistoryEntry[]>(
  108. props.page === "rest" ? restHistory$ : graphqlHistory$,
  109. []
  110. ),
  111. }
  112. },
  113. data() {
  114. return {
  115. filterText: "",
  116. showMore: false,
  117. confirmRemove: false,
  118. }
  119. },
  120. computed: {
  121. filteredHistory(): any[] {
  122. const filteringHistory = this.history as Array<
  123. RESTHistoryEntry | GQLHistoryEntry
  124. >
  125. return filteringHistory.filter(
  126. (entry: RESTHistoryEntry | GQLHistoryEntry) => {
  127. const filterText = this.filterText.toLowerCase()
  128. return Object.keys(entry).some((key) => {
  129. let value = entry[key as keyof typeof entry]
  130. if (value) {
  131. value = typeof value !== "string" ? value.toString() : value
  132. return value.toLowerCase().includes(filterText)
  133. }
  134. return false
  135. })
  136. }
  137. )
  138. },
  139. },
  140. methods: {
  141. clearHistory() {
  142. if (this.page === "rest") clearRESTHistory()
  143. else clearGraphqlHistory()
  144. this.$toast.success(this.$t("state.history_deleted").toString(), {
  145. icon: "delete",
  146. })
  147. },
  148. useHistory(entry: any) {
  149. if (this.page === "rest") setRESTRequest(entry.request)
  150. },
  151. deleteHistory(entry: any) {
  152. if (this.page === "rest") deleteRESTHistoryEntry(entry)
  153. else deleteGraphqlHistoryEntry(entry)
  154. this.$toast.success(this.$t("state.deleted").toString(), {
  155. icon: "delete",
  156. })
  157. },
  158. toggleStar(entry: any) {
  159. if (this.page === "rest") toggleRESTHistoryEntryStar(entry)
  160. else toggleGraphqlHistoryEntryStar(entry)
  161. },
  162. },
  163. })
  164. </script>