refactor: implement updated equality heuristics for hopprestrequest struct

This commit is contained in:
Andrew Bastin
2022-04-14 20:23:29 +05:30
committed by liyasthomas
parent 99148a0a0e
commit ede27e0600
11 changed files with 132 additions and 296 deletions

View File

@@ -162,8 +162,8 @@ import {
HoppRESTRequest,
safelyExtractRESTRequest,
translateToNewRequest,
isEqualHoppRESTRequest,
} from "@hoppscotch/data"
import isEqual from "lodash/isEqual"
import * as E from "fp-ts/Either"
import {
useI18n,
@@ -349,9 +349,9 @@ const selectRequest = () => {
const currentFullReq = getRESTRequest()
// Check if whether user clicked the same request or not
if (!isActive.value) {
if (!isActive.value && currentReqWithNoChange !== undefined) {
// Check if there is any changes done on the current request
if (isEqual(currentReqWithNoChange, currentFullReq)) {
if (isEqualHoppRESTRequest(currentReqWithNoChange, currentFullReq)) {
setRestReq(props.request)
if (props.saveRequest)
emit("select", {

View File

@@ -157,11 +157,11 @@
import { ref, computed } from "@nuxtjs/composition-api"
import {
HoppRESTRequest,
isEqualHoppRESTRequest,
safelyExtractRESTRequest,
translateToNewRequest,
} from "@hoppscotch/data"
import * as E from "fp-ts/Either"
import isEqual from "lodash/isEqual"
import {
useI18n,
useToast,
@@ -277,8 +277,7 @@ const isActive = computed(
() =>
active.value &&
active.value.originLocation === "team-collection" &&
active.value.requestID === props.requestIndex &&
isEqual(active.value.req, props.request)
active.value.requestID === props.requestIndex
)
const dragStart = ({ dataTransfer }: DragEvent) => {
@@ -333,9 +332,9 @@ const selectRequest = () => {
const currentFullReq = getRESTRequest()
// Check if whether user clicked the same request or not
if (!isActive.value) {
if (!isActive.value && currentReqWithNoChange) {
// Check if there is any changes done on the current request
if (isEqual(currentReqWithNoChange, currentFullReq)) {
if (isEqualHoppRESTRequest(currentReqWithNoChange, currentFullReq)) {
setRestReq(props.request)
if (props.saveRequest)
emit("select", {

View File

@@ -113,13 +113,16 @@
<script setup lang="ts">
import { computed, ref, Ref } from "@nuxtjs/composition-api"
import { HoppRESTRequest, safelyExtractRESTRequest } from "@hoppscotch/data"
import {
HoppRESTRequest,
isEqualHoppRESTRequest,
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 * as E from "fp-ts/Either"
import isEqual from "lodash/isEqual"
import {
useI18n,
useReadonlyStream,
@@ -231,7 +234,9 @@ const setRestReq = (request: HoppRESTRequest | null | undefined) => {
setRESTRequest(safelyExtractRESTRequest(request, getDefaultRESTRequest()))
}
const useHistory = (entry: HistoryEntry) => {
// NOTE: For GQL, the HistoryGraphqlCard component already implements useEntry
// (That is not a really good behaviour tho ¯\_(ツ)_/¯)
const useHistory = (entry: RESTHistoryEntry) => {
const currentFullReq = getRESTRequest()
// Initial state trigers a popup
if (!clickedHistory.value) {
@@ -240,7 +245,12 @@ const useHistory = (entry: HistoryEntry) => {
return
}
// Checks if there are any change done in current request and the history request
if (!isEqual(currentFullReq, clickedHistory.value.request)) {
if (
!isEqualHoppRESTRequest(
currentFullReq,
clickedHistory.value.request as HoppRESTRequest
)
) {
clickedHistory.value = entry
confirmChange.value = true
} else {
@@ -342,7 +352,7 @@ const deleteHistory = (entry: HistoryEntry) => {
}
const toggleStar = (entry: HistoryEntry) => {
//History entry type specified because function does not know the type
// History entry type specified because function does not know the type
if (props.page === "rest")
toggleRESTHistoryEntryStar(entry as RESTHistoryEntry)
else toggleGraphqlHistoryEntryStar(entry as GQLHistoryEntry)

View File

@@ -58,7 +58,7 @@
"@codemirror/tooltip": "^0.19.16",
"@codemirror/view": "^0.19.48",
"@hoppscotch/codemirror-lang-graphql": "workspace:^0.1.0",
"@hoppscotch/data": "workspace:^0.4.0",
"@hoppscotch/data": "workspace:^0.4.2",
"@hoppscotch/js-sandbox": "workspace:^2.0.0",
"@nuxtjs/axios": "^5.13.6",
"@nuxtjs/composition-api": "^0.32.0",

View File

@@ -25,11 +25,11 @@ import {
watch,
} from "@nuxtjs/composition-api"
import { Subscription } from "rxjs"
import isEqual from "lodash/isEqual"
import {
HoppRESTRequest,
HoppRESTAuthOAuth2,
safelyExtractRESTRequest,
isEqualHoppRESTRequest,
} from "@hoppscotch/data"
import {
getRESTRequest,
@@ -102,8 +102,7 @@ function setupRequestSync(
) {
const request = await loadRequestFromSync()
if (request) {
// setRESTRequest(request)
if (!isEqual(request, getRESTRequest())) {
if (!isEqualHoppRESTRequest(request, getRESTRequest())) {
requestForSync.value = request
confirmSync.value = true
}

View File

@@ -35,7 +35,7 @@
"license": "MIT",
"private": false,
"devDependencies": {
"@hoppscotch/data": "workspace:^0.4.1",
"@hoppscotch/data": "workspace:^0.4.2",
"@hoppscotch/js-sandbox": "workspace:^2.0.0",
"@swc/core": "^1.2.163",
"@types/axios": "^0.14.0",

View File

@@ -1,6 +1,6 @@
{
"name": "@hoppscotch/data",
"version": "0.4.1",
"version": "0.4.2",
"description": "Data Types, Validations and Migrations for Hoppscotch Public Data Structures",
"main": "dist/index.js",
"module": "true",

View File

@@ -1,6 +1,9 @@
import cloneDeep from "lodash/cloneDeep"
import * as Eq from "fp-ts/Eq"
import * as S from "fp-ts/string"
import { ValidContentTypes } from "./content-types"
import { HoppRESTAuth } from "./HoppRESTAuth"
import { lodashIsEqualEq, mapThenEq, undefinedEq } from "../utils/eq"
export * from "./content-types"
export * from "./HoppRESTAuth"
@@ -57,6 +60,28 @@ export interface HoppRESTRequest {
body: HoppRESTReqBody
}
export const HoppRESTRequestEq = Eq.struct<HoppRESTRequest>({
id: undefinedEq(S.Eq),
v: S.Eq,
auth: lodashIsEqualEq,
body: lodashIsEqualEq,
endpoint: S.Eq,
headers: mapThenEq(
(arr) => arr.filter((h) => h.key !== "" && h.value !== ""),
lodashIsEqualEq
),
params: mapThenEq(
(arr) => arr.filter((p) => p.key !== "" && p.value !== ""),
lodashIsEqualEq
),
method: S.Eq,
name: S.Eq,
preRequestScript: S.Eq,
testScript: S.Eq,
})
export const isEqualHoppRESTRequest = HoppRESTRequestEq.equals
/**
* Safely tries to extract REST Request data from an unknown value.
* If we fail to detect certain bits, we just resolve it to the default value

View File

@@ -0,0 +1,50 @@
import * as Eq from "fp-ts/Eq"
import * as S from "fp-ts/string"
import isEqual from "lodash/isEqual"
/*
* Eq-s are fp-ts an interface (type class) that defines how the equality
* of 2 values of a certain type are matched as equal
*/
/**
* Create an Eq from a non-undefinable value and makes it accept undefined
* @param eq The non nullable Eq to add to
* @returns The updated Eq which accepts undefined
*/
export const undefinedEq = <T>(eq: Eq.Eq<T>): Eq.Eq<T | undefined> => ({
equals(x: T | undefined, y: T | undefined) {
if (x !== undefined && y !== undefined) {
return eq.equals(x, y)
}
return x === undefined && y === undefined
}
})
/**
* An Eq which compares by transforming based on a mapping function and then applying the Eq to it
* @param map The mapping function to map values to
* @param eq The Eq which takes the value which the map returns
* @returns An Eq which takes the input of the mapping function
*/
export const mapThenEq = <A, B>(map: (x: A) => B, eq: Eq.Eq<B>): Eq.Eq<A> => ({
equals(x: A, y: A) {
return eq.equals(map(x), map(y))
}
})
/**
* An Eq which checks equality of 2 string in a case insensitive way
*/
export const stringCaseInsensitiveEq: Eq.Eq<string> = mapThenEq(S.toLowerCase, S.Eq)
/**
* An Eq that does equality check with Lodash's isEqual function
*/
export const lodashIsEqualEq: Eq.Eq<any> = {
equals(x: any, y: any) {
return isEqual(x, y)
}
}

View File

@@ -40,7 +40,7 @@
"author": "Hoppscotch (support@hoppscotch.io)",
"license": "MIT",
"dependencies": {
"@hoppscotch/data": "workspace:^0.4.0",
"@hoppscotch/data": "workspace:^0.4.2",
"fp-ts": "^2.11.9",
"lodash": "^4.17.21",
"quickjs-emscripten": "^0.15.0",