refactor: types and functional improvements
Co-authored-by: Andrew Bastin <andrewbastin.k@gmail.com>
This commit is contained in:
parent
ebc536b835
commit
d634828eca
2 changed files with 70 additions and 39 deletions
|
|
@ -36,7 +36,7 @@
|
||||||
open
|
open
|
||||||
>
|
>
|
||||||
<summary
|
<summary
|
||||||
class="flex items-center justify-between flex-1 min-w-0 cursor-pointer transition focus:outline-none text-secondaryLight text-tiny group"
|
class="flex items-center justify-between flex-1 min-w-0 transition cursor-pointer focus:outline-none text-secondaryLight text-tiny group"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
class="px-4 py-2 truncate transition group-hover:text-secondary capitalize-first"
|
class="px-4 py-2 truncate transition group-hover:text-secondary capitalize-first"
|
||||||
|
|
@ -49,7 +49,7 @@
|
||||||
color="red"
|
color="red"
|
||||||
:title="$t('action.remove')"
|
:title="$t('action.remove')"
|
||||||
class="hidden group-hover:inline-flex"
|
class="hidden group-hover:inline-flex"
|
||||||
@click.native="deleteBattleHistoryEntry(filteredHistoryGroup)"
|
@click.native="deleteBatchHistoryEntry(filteredHistoryGroup)"
|
||||||
/>
|
/>
|
||||||
</summary>
|
</summary>
|
||||||
<div
|
<div
|
||||||
|
|
@ -59,11 +59,11 @@
|
||||||
<component
|
<component
|
||||||
:is="page == 'rest' ? 'HistoryRestCard' : 'HistoryGraphqlCard'"
|
:is="page == 'rest' ? 'HistoryRestCard' : 'HistoryGraphqlCard'"
|
||||||
:id="index"
|
:id="index"
|
||||||
:entry="entry"
|
:entry="entry.entry"
|
||||||
:show-more="showMore"
|
:show-more="showMore"
|
||||||
@toggle-star="toggleStar(entry)"
|
@toggle-star="toggleStar(entry.entry)"
|
||||||
@delete-entry="deleteHistory(entry)"
|
@delete-entry="deleteHistory(entry.entry)"
|
||||||
@use-entry="useHistory(entry)"
|
@use-entry="useHistory(entry.entry)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</details>
|
</details>
|
||||||
|
|
@ -101,9 +101,12 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, ref } from "@nuxtjs/composition-api"
|
import { computed, ref, Ref } from "@nuxtjs/composition-api"
|
||||||
import { useTimeAgo } from "@vueuse/core"
|
|
||||||
import { safelyExtractRESTRequest } from "@hoppscotch/data"
|
import { safelyExtractRESTRequest } from "@hoppscotch/data"
|
||||||
|
import groupBy from "lodash/groupBy"
|
||||||
|
import { useTimeAgo } from "@vueuse/core"
|
||||||
|
import { pipe } from "fp-ts/function"
|
||||||
|
import * as A from "fp-ts/Array"
|
||||||
import {
|
import {
|
||||||
useI18n,
|
useI18n,
|
||||||
useReadonlyStream,
|
useReadonlyStream,
|
||||||
|
|
@ -133,11 +136,11 @@ const confirmRemove = ref(false)
|
||||||
const toast = useToast()
|
const toast = useToast()
|
||||||
const t = useI18n()
|
const t = useI18n()
|
||||||
|
|
||||||
const groupByDate = (array: any[], key: string) => {
|
type HistoryEntry = GQLHistoryEntry | RESTHistoryEntry
|
||||||
return array.reduce((rv: any, x: any) => {
|
|
||||||
;(rv[useTimeAgo(x[key]).value] = rv[useTimeAgo(x[key]).value] || []).push(x)
|
type TimedHistoryEntry = {
|
||||||
return rv
|
entry: HistoryEntry
|
||||||
}, {})
|
timeAgo: Ref<string>
|
||||||
}
|
}
|
||||||
|
|
||||||
const history = useReadonlyStream<RESTHistoryEntry[] | GQLHistoryEntry[]>(
|
const history = useReadonlyStream<RESTHistoryEntry[] | GQLHistoryEntry[]>(
|
||||||
|
|
@ -145,27 +148,49 @@ const history = useReadonlyStream<RESTHistoryEntry[] | GQLHistoryEntry[]>(
|
||||||
[]
|
[]
|
||||||
)
|
)
|
||||||
|
|
||||||
const filteredHistory = computed(() => {
|
const deepCheckForRegex = (value: unknown, regExp: RegExp): boolean => {
|
||||||
const regExp = new RegExp(filterText.value, "gi")
|
if (value === null || value === undefined) return false
|
||||||
const check = (obj: any) => {
|
|
||||||
if (obj !== null && typeof obj === "object") {
|
if (typeof value === "string") return regExp.test(value)
|
||||||
return Object.values(obj).some(check)
|
if (typeof value === "number") return regExp.test(value.toString())
|
||||||
}
|
|
||||||
if (Array.isArray(obj)) {
|
if (typeof value === "object")
|
||||||
return obj.some(check)
|
return Object.values(value).some((input) =>
|
||||||
}
|
deepCheckForRegex(input, regExp)
|
||||||
return (
|
)
|
||||||
(typeof obj === "string" || typeof obj === "number") &&
|
if (Array.isArray(value))
|
||||||
regExp.test(obj as string)
|
return value.some((input) => deepCheckForRegex(input, regExp))
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const filteredHistory = computed(() =>
|
||||||
|
pipe(
|
||||||
|
history.value as HistoryEntry[],
|
||||||
|
A.filter(
|
||||||
|
(
|
||||||
|
input
|
||||||
|
): input is HistoryEntry & {
|
||||||
|
updatedOn: NonNullable<HistoryEntry["updatedOn"]>
|
||||||
|
} => {
|
||||||
|
return (
|
||||||
|
!!input.updatedOn &&
|
||||||
|
(filterText.value.length === 0 ||
|
||||||
|
deepCheckForRegex(input, new RegExp(filterText.value, "gi")))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
),
|
||||||
|
A.map(
|
||||||
|
(entry): TimedHistoryEntry => ({
|
||||||
|
entry,
|
||||||
|
timeAgo: useTimeAgo(entry.updatedOn),
|
||||||
|
})
|
||||||
)
|
)
|
||||||
}
|
|
||||||
return (history.value as Array<RESTHistoryEntry | GQLHistoryEntry>).filter(
|
|
||||||
check
|
|
||||||
)
|
)
|
||||||
})
|
)
|
||||||
|
|
||||||
const filteredHistoryGroups = computed(() =>
|
const filteredHistoryGroups = computed(() =>
|
||||||
groupByDate(filteredHistory.value, "updatedOn")
|
groupBy(filteredHistory.value, (entry) => entry.timeAgo.value)
|
||||||
)
|
)
|
||||||
|
|
||||||
const clearHistory = () => {
|
const clearHistory = () => {
|
||||||
|
|
@ -181,14 +206,20 @@ const useHistory = (entry: any) => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const deleteBattleHistoryEntry = (entries: number[]) => {
|
const isRESTHistoryEntry = (
|
||||||
if (props.page === "rest") {
|
entries: TimedHistoryEntry[]
|
||||||
entries.forEach((entry: any) => {
|
): entries is Array<TimedHistoryEntry & { entry: RESTHistoryEntry }> =>
|
||||||
deleteRESTHistoryEntry(entry)
|
// If the page is rest, then we can guarantee what we have is a RESTHistoryEnry
|
||||||
|
props.page === "rest"
|
||||||
|
|
||||||
|
const deleteBatchHistoryEntry = (entries: TimedHistoryEntry[]) => {
|
||||||
|
if (isRESTHistoryEntry(entries)) {
|
||||||
|
entries.forEach((entry) => {
|
||||||
|
deleteRESTHistoryEntry(entry.entry)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
entries.forEach((entry: any) => {
|
entries.forEach((entry) => {
|
||||||
deleteGraphqlHistoryEntry(entry)
|
deleteGraphqlHistoryEntry(entry.entry as GQLHistoryEntry)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
toast.success(`${t("state.deleted")}`)
|
toast.success(`${t("state.deleted")}`)
|
||||||
|
|
|
||||||
|
|
@ -68,14 +68,14 @@ type TypeFromPrimitiveArray<P extends JSPrimitive | undefined> =
|
||||||
: unknown[]
|
: unknown[]
|
||||||
|
|
||||||
export const objHasProperty =
|
export const objHasProperty =
|
||||||
<O extends object, K extends string, P extends JSPrimitive>(
|
<O extends object, K extends string, P extends JSPrimitive | undefined>(
|
||||||
prop: K,
|
prop: K,
|
||||||
type: P
|
type?: P
|
||||||
) =>
|
) =>
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
(obj: O): obj is O & { [_ in K]: TypeFromPrimitive<P> } =>
|
(obj: O): obj is O & { [_ in K]: TypeFromPrimitive<P> } =>
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
prop in obj && typeof (obj as any)[prop] === type
|
prop in obj && (type === undefined || typeof (obj as any)[prop] === type)
|
||||||
|
|
||||||
export const objHasArrayProperty =
|
export const objHasArrayProperty =
|
||||||
<O extends object, K extends string, P extends JSPrimitive>(
|
<O extends object, K extends string, P extends JSPrimitive>(
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue