[Feat: GraphQL sidebar] GraphQL History (#1528)
* Create REQUIREMENTS.md * graphql history UI * rest history emit * removed requirements file * add, delete, clear, star history and sync with firstore * use history * empty schema * remove other tabs * computed query, setting headers * binding props Co-authored-by: Liyas Thomas <liyascthomas@gmail.com> * remove print Co-authored-by: Liyas Thomas <liyascthomas@gmail.com> * remove dummy data Co-authored-by: Liyas Thomas <liyascthomas@gmail.com> * add docs tab * date, time attribute --> updatedOn * Removed margin from sidebar Tab * removed v-bind Co-authored-by: Liyas Thomas <liyascthomas@gmail.com> * use shortcut for v-bind * use shortcut for v-bind * use unfold icons * use template literals in :key * history clear bug * delete history bug * minor translation * remove console logs * remove unused css * add stared style * remove absolute styles * tests for graphql card * tests for rest card * tests for clear history added * mount, clear, use, delete history tests added * Rename card.vue to Card.vue * Rename card.vue to Card.vue * use computed Co-authored-by: Isha Gupta <40794215+IshaGupta18@users.noreply.github.com> Co-authored-by: Liyas Thomas <liyascthomas@gmail.com>
This commit is contained in:
109
components/history/__tests__/GraphqlCard.spec.js
Normal file
109
components/history/__tests__/GraphqlCard.spec.js
Normal file
@@ -0,0 +1,109 @@
|
||||
import GraphqlCard from "../graphql/Card"
|
||||
import { mount } from "@vue/test-utils"
|
||||
|
||||
const factory = (props) => {
|
||||
return mount(GraphqlCard, {
|
||||
propsData: props,
|
||||
stubs: {
|
||||
"v-popover": {
|
||||
template: "<div><slot /><slot name='popover' :is-open=true /></div>",
|
||||
},
|
||||
},
|
||||
mocks: {
|
||||
$t: (text) => text,
|
||||
},
|
||||
directives: {
|
||||
tooltip() {
|
||||
/* stub */
|
||||
},
|
||||
closePopover() {
|
||||
/* stub */
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const url = "https://dummydata.com"
|
||||
const query = `query getUser($uid: String!) {
|
||||
user(uid: $uid) {
|
||||
name
|
||||
}
|
||||
}`
|
||||
|
||||
describe("GraphqlCard", () => {
|
||||
test("Mounts properly if props are given", () => {
|
||||
const wrapper = factory({
|
||||
entry: {
|
||||
type: "graphql",
|
||||
url: url,
|
||||
query: query,
|
||||
star: false,
|
||||
},
|
||||
})
|
||||
expect(wrapper).toBeTruthy()
|
||||
})
|
||||
|
||||
test("toggle-star emitted on clicking on star button", async () => {
|
||||
const wrapper = factory({
|
||||
entry: {
|
||||
type: "graphql",
|
||||
url: url,
|
||||
query: query,
|
||||
star: true,
|
||||
},
|
||||
})
|
||||
|
||||
wrapper.find("button[data-testid='star_button']").trigger("click")
|
||||
expect(wrapper.emitted("toggle-star")).toBeTruthy()
|
||||
})
|
||||
|
||||
test("query expands on clicking the show more button", async () => {
|
||||
const wrapper = factory({
|
||||
entry: {
|
||||
type: "graphql",
|
||||
url: url,
|
||||
query: query,
|
||||
star: true,
|
||||
},
|
||||
})
|
||||
expect(wrapper.vm.query).toStrictEqual([
|
||||
`query getUser($uid: String!) {`,
|
||||
` user(uid: $uid) {`,
|
||||
`...`,
|
||||
])
|
||||
await wrapper.find("button[data-testid='query_expand']").trigger("click")
|
||||
expect(wrapper.vm.query).toStrictEqual([
|
||||
`query getUser($uid: String!) {`,
|
||||
` user(uid: $uid) {`,
|
||||
` name`,
|
||||
` }`,
|
||||
`}`,
|
||||
])
|
||||
})
|
||||
|
||||
test("use-entry emit on clicking the restore button", async () => {
|
||||
const wrapper = factory({
|
||||
entry: {
|
||||
type: "graphql",
|
||||
url: url,
|
||||
query: query,
|
||||
star: true,
|
||||
},
|
||||
})
|
||||
await wrapper.find("button[data-testid='restore_history_entry']").trigger("click")
|
||||
expect(wrapper.emitted("use-entry")).toBeTruthy()
|
||||
})
|
||||
|
||||
test("delete-entry emit on clicking the delete button", async () => {
|
||||
const wrapper = factory({
|
||||
entry: {
|
||||
type: "graphql",
|
||||
url: url,
|
||||
query: query,
|
||||
star: true,
|
||||
},
|
||||
})
|
||||
await wrapper.find("button[data-testid=delete_history_entry]").trigger("click")
|
||||
expect(wrapper.emitted("delete-entry")).toBeTruthy()
|
||||
})
|
||||
})
|
||||
285
components/history/__tests__/History.spec.js
Normal file
285
components/history/__tests__/History.spec.js
Normal file
@@ -0,0 +1,285 @@
|
||||
import History from "../"
|
||||
import { fb } from "~/helpers/fb"
|
||||
import { shallowMount } from "@vue/test-utils"
|
||||
import HistoryRestCard from "../rest/Card"
|
||||
|
||||
const restHistory = [
|
||||
{
|
||||
id: "0",
|
||||
type: "rest",
|
||||
},
|
||||
{
|
||||
id: "1",
|
||||
type: "rest",
|
||||
},
|
||||
{
|
||||
id: "2",
|
||||
type: "rest",
|
||||
},
|
||||
]
|
||||
|
||||
const graphqlHistory = [
|
||||
{
|
||||
id: "0",
|
||||
type: "graphql",
|
||||
},
|
||||
{
|
||||
id: "1",
|
||||
type: "graphql",
|
||||
},
|
||||
{
|
||||
id: "2",
|
||||
type: "graphql",
|
||||
},
|
||||
]
|
||||
|
||||
var localStorageMock = (function () {
|
||||
var store = {
|
||||
history: JSON.stringify(restHistory),
|
||||
graphqlHistory: JSON.stringify(graphqlHistory),
|
||||
}
|
||||
return {
|
||||
getItem: function (key) {
|
||||
return store[key]
|
||||
},
|
||||
setItem: jest.fn(),
|
||||
clear: jest.fn(),
|
||||
removeItem: jest.fn(),
|
||||
}
|
||||
})()
|
||||
Object.defineProperty(window, "localStorage", { value: localStorageMock })
|
||||
|
||||
jest.mock("~/helpers/fb", () => ({
|
||||
__esModule: true,
|
||||
|
||||
fb: {
|
||||
currentUser: null,
|
||||
currentHistory: restHistory,
|
||||
currentGraphqlHistory: graphqlHistory,
|
||||
clearHistory: jest.fn(),
|
||||
clearGraphqlHistory: jest.fn(),
|
||||
deleteHistory: jest.fn(),
|
||||
deleteGraphqlHistory: jest.fn(),
|
||||
},
|
||||
}))
|
||||
|
||||
const factory = (props) => {
|
||||
return shallowMount(History, {
|
||||
propsData: props,
|
||||
stubs: {
|
||||
"v-popover": {
|
||||
template: "<div><slot /><slot name='popover' :is-open=true /></div>",
|
||||
},
|
||||
HistoryRestCard: {
|
||||
template: "<div data-testid='rest_card' />",
|
||||
},
|
||||
HistoryGraphqlCard: {
|
||||
template: "<div data-testid='graphql_card' />",
|
||||
},
|
||||
AppSection: {
|
||||
template: "<div><slot /></div>",
|
||||
},
|
||||
},
|
||||
mocks: {
|
||||
$t: (text) => text,
|
||||
$toast: {
|
||||
error() {},
|
||||
},
|
||||
},
|
||||
directives: {
|
||||
tooltip() {
|
||||
/* stub */
|
||||
},
|
||||
closePopover() {
|
||||
/* stub */
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
fb.clearHistory.mockClear()
|
||||
fb.clearGraphqlHistory.mockClear()
|
||||
fb.deleteHistory.mockClear()
|
||||
fb.deleteGraphqlHistory.mockClear()
|
||||
window.localStorage.setItem.mockClear()
|
||||
})
|
||||
|
||||
describe("Mount History", () => {
|
||||
test("Mounts rest history without login", async () => {
|
||||
const wrapper = factory({
|
||||
page: "rest",
|
||||
})
|
||||
expect(wrapper).toBeTruthy()
|
||||
})
|
||||
test("Mounts rest history with login", async () => {
|
||||
fb.currentUser = "user"
|
||||
const wrapper = factory({
|
||||
page: "rest",
|
||||
})
|
||||
expect(wrapper).toBeTruthy()
|
||||
})
|
||||
|
||||
test("Mounts graphql history without login", async () => {
|
||||
const wrapper = factory({
|
||||
page: "rest",
|
||||
})
|
||||
expect(wrapper).toBeTruthy()
|
||||
})
|
||||
test("Mounts graphql history with login", async () => {
|
||||
fb.currentUser = "user"
|
||||
const wrapper = factory({
|
||||
page: "rest",
|
||||
})
|
||||
expect(wrapper).toBeTruthy()
|
||||
})
|
||||
})
|
||||
|
||||
describe("Clear History", () => {
|
||||
test("Clear rest history without login", async () => {
|
||||
fb.currentUser = null
|
||||
const wrapper = factory({
|
||||
page: "rest",
|
||||
})
|
||||
expect(wrapper.vm.filteredHistory).toStrictEqual(restHistory)
|
||||
await wrapper.find("button[data-testid='clear_history']").trigger("click")
|
||||
await wrapper.find("button[data-testid='confirm_clear_history']").trigger("click")
|
||||
expect(fb.clearHistory).not.toHaveBeenCalled()
|
||||
expect(window.localStorage.setItem).toHaveBeenCalledWith("history", JSON.stringify([]))
|
||||
})
|
||||
test("Clear rest history with login", async () => {
|
||||
fb.currentUser = "user"
|
||||
const wrapper = factory({
|
||||
page: "rest",
|
||||
})
|
||||
expect(wrapper.vm.filteredHistory).toStrictEqual(restHistory)
|
||||
await wrapper.find("button[data-testid='clear_history']").trigger("click")
|
||||
await wrapper.find("button[data-testid='confirm_clear_history']").trigger("click")
|
||||
expect(fb.clearHistory).toHaveBeenCalledTimes(1)
|
||||
expect(window.localStorage.setItem).toHaveBeenCalledWith("history", JSON.stringify([]))
|
||||
})
|
||||
test("Dont confirm Clear rest history", async () => {
|
||||
fb.currentUser = "user"
|
||||
const wrapper = factory({
|
||||
page: "rest",
|
||||
})
|
||||
expect(wrapper.vm.filteredHistory).toStrictEqual(restHistory)
|
||||
await wrapper.find("button[data-testid='clear_history']").trigger("click")
|
||||
await wrapper.find("button[data-testid='reject_clear_history']").trigger("click")
|
||||
expect(fb.clearHistory).not.toHaveBeenCalled()
|
||||
expect(window.localStorage.setItem).not.toHaveBeenCalledWith("history", JSON.stringify([]))
|
||||
})
|
||||
|
||||
test("Clear graphql history without login", async () => {
|
||||
fb.currentUser = null
|
||||
const wrapper = factory({
|
||||
page: "graphql",
|
||||
})
|
||||
expect(wrapper.vm.filteredHistory).toStrictEqual(graphqlHistory)
|
||||
await wrapper.find("button[data-testid='clear_history']").trigger("click")
|
||||
await wrapper.find("button[data-testid='confirm_clear_history']").trigger("click")
|
||||
expect(fb.clearGraphqlHistory).not.toHaveBeenCalled()
|
||||
expect(window.localStorage.setItem).toHaveBeenCalledWith("graphqlHistory", JSON.stringify([]))
|
||||
})
|
||||
test("Clear graphql history with login", async () => {
|
||||
fb.currentUser = "user"
|
||||
const wrapper = factory({
|
||||
page: "graphql",
|
||||
})
|
||||
expect(wrapper.vm.filteredHistory).toStrictEqual(graphqlHistory)
|
||||
await wrapper.find("button[data-testid='clear_history']").trigger("click")
|
||||
await wrapper.find("button[data-testid='confirm_clear_history']").trigger("click")
|
||||
expect(fb.clearGraphqlHistory).toHaveBeenCalledTimes(1)
|
||||
expect(window.localStorage.setItem).toHaveBeenCalledWith("graphqlHistory", JSON.stringify([]))
|
||||
})
|
||||
test("Dont confirm Clear graphql history", async () => {
|
||||
fb.currentUser = "user"
|
||||
const wrapper = factory({
|
||||
page: "graphql",
|
||||
})
|
||||
expect(wrapper.vm.filteredHistory).toStrictEqual(graphqlHistory)
|
||||
await wrapper.find("button[data-testid='clear_history']").trigger("click")
|
||||
await wrapper.find("button[data-testid='reject_clear_history']").trigger("click")
|
||||
expect(window.localStorage.setItem).not.toHaveBeenCalledWith(
|
||||
"graphqlHistory",
|
||||
JSON.stringify([])
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe("Use History", () => {
|
||||
test("use rest history", async () => {
|
||||
fb.currentUser = "user"
|
||||
const wrapper = factory({
|
||||
page: "rest",
|
||||
})
|
||||
expect(wrapper.findAll("div[data-testid='rest_card']").length).toEqual(restHistory.length)
|
||||
var index = restHistory.length - 1
|
||||
wrapper.findAll("div[data-testid='rest_card']").at(index).vm.$emit("use-entry")
|
||||
expect(wrapper.emitted("useHistory")).toBeTruthy()
|
||||
expect(wrapper.emitted("useHistory")[0]).toStrictEqual([restHistory[index]])
|
||||
})
|
||||
|
||||
test("use graphql history", async () => {
|
||||
fb.currentUser = "user"
|
||||
const wrapper = factory({
|
||||
page: "graphql",
|
||||
})
|
||||
expect(wrapper.findAll("div[data-testid='graphql_card']").length).toEqual(graphqlHistory.length)
|
||||
var index = restHistory.length - 1
|
||||
wrapper.findAll("div[data-testid='graphql_card']").at(index).vm.$emit("use-entry")
|
||||
expect(wrapper.emitted("useHistory")).toBeTruthy()
|
||||
expect(wrapper.emitted("useHistory")[0]).toStrictEqual([graphqlHistory[index]])
|
||||
})
|
||||
})
|
||||
|
||||
describe("Delete History", () => {
|
||||
test("delete rest history with login", async () => {
|
||||
fb.currentUser = "user"
|
||||
const wrapper = factory({
|
||||
page: "rest",
|
||||
})
|
||||
expect(wrapper.findAll("div[data-testid='rest_card']").length).toEqual(restHistory.length)
|
||||
var index = 1
|
||||
wrapper.findAll("div[data-testid='rest_card']").at(index).vm.$emit("delete-entry")
|
||||
expect(fb.deleteHistory).toBeCalledWith(restHistory[index])
|
||||
})
|
||||
|
||||
test("delete rest history without login", async () => {
|
||||
fb.currentUser = null
|
||||
const wrapper = factory({
|
||||
page: "rest",
|
||||
})
|
||||
expect(wrapper.findAll("div[data-testid='rest_card']").length).toEqual(restHistory.length)
|
||||
var index = 1
|
||||
wrapper.findAll("div[data-testid='rest_card']").at(index).vm.$emit("delete-entry")
|
||||
expect(window.localStorage.setItem).toBeCalledWith(
|
||||
"history",
|
||||
JSON.stringify(restHistory.filter((entry) => entry.id != index))
|
||||
)
|
||||
})
|
||||
test("delete graphql history with login", async () => {
|
||||
fb.currentUser = "user"
|
||||
const wrapper = factory({
|
||||
page: "graphql",
|
||||
})
|
||||
expect(wrapper.findAll("div[data-testid='graphql_card']").length).toEqual(graphqlHistory.length)
|
||||
var index = 1
|
||||
wrapper.findAll("div[data-testid='graphql_card']").at(index).vm.$emit("delete-entry")
|
||||
expect(fb.deleteGraphqlHistory).toBeCalledWith(graphqlHistory[index])
|
||||
})
|
||||
|
||||
test("delete graphql history without login", async () => {
|
||||
fb.currentUser = null
|
||||
const wrapper = factory({
|
||||
page: "graphql",
|
||||
})
|
||||
expect(wrapper.findAll("div[data-testid='graphql_card']").length).toEqual(graphqlHistory.length)
|
||||
var index = 1
|
||||
wrapper.findAll("div[data-testid='graphql_card']").at(index).vm.$emit("delete-entry")
|
||||
expect(window.localStorage.setItem).toBeCalledWith(
|
||||
"graphqlHistory",
|
||||
JSON.stringify(graphqlHistory.filter((entry) => entry.id != index))
|
||||
)
|
||||
})
|
||||
})
|
||||
58
components/history/__tests__/RestCard.spec.js
Normal file
58
components/history/__tests__/RestCard.spec.js
Normal file
@@ -0,0 +1,58 @@
|
||||
import RestCard from "../rest/Card"
|
||||
import { mount } from "@vue/test-utils"
|
||||
|
||||
const factory = (props) => {
|
||||
return mount(RestCard, {
|
||||
propsData: props,
|
||||
stubs: {
|
||||
"v-popover": {
|
||||
template: "<div><slot /><slot name='popover' :is-open=true /></div>",
|
||||
},
|
||||
},
|
||||
mocks: {
|
||||
$t: (text) => text,
|
||||
},
|
||||
directives: {
|
||||
tooltip() {
|
||||
/* stub */
|
||||
},
|
||||
closePopover() {
|
||||
/* stub */
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const url = "https://dummydata.com/get"
|
||||
const entry = {
|
||||
type: "rest",
|
||||
url: url,
|
||||
method: "GET",
|
||||
status: 200,
|
||||
star: false,
|
||||
}
|
||||
describe("RestCard", () => {
|
||||
test("Mounts properly if props are given", () => {
|
||||
const wrapper = factory({ entry })
|
||||
expect(wrapper).toBeTruthy()
|
||||
})
|
||||
|
||||
test("toggle-star emitted on clicking on star button", async () => {
|
||||
const wrapper = factory({ entry })
|
||||
|
||||
wrapper.find("button[data-testid='star_button']").trigger("click")
|
||||
expect(wrapper.emitted("toggle-star")).toBeTruthy()
|
||||
})
|
||||
|
||||
test("use-entry emit on clicking the restore button", async () => {
|
||||
const wrapper = factory({ entry })
|
||||
await wrapper.find("button[data-testid='restore_history_entry']").trigger("click")
|
||||
expect(wrapper.emitted("use-entry")).toBeTruthy()
|
||||
})
|
||||
|
||||
test("delete-entry emit on clicking the delete button", async () => {
|
||||
const wrapper = factory({ entry })
|
||||
await wrapper.find("button[data-testid=delete_history_entry]").trigger("click")
|
||||
expect(wrapper.emitted("delete-entry")).toBeTruthy()
|
||||
})
|
||||
})
|
||||
147
components/history/graphql/Card.vue
Normal file
147
components/history/graphql/Card.vue
Normal file
@@ -0,0 +1,147 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="show-on-large-screen">
|
||||
<li>
|
||||
<input
|
||||
data-testid="'url'"
|
||||
:aria-label="$t('url')"
|
||||
type="text"
|
||||
readonly
|
||||
:value="entry.url"
|
||||
:placeholder="$t('empty_req_name')"
|
||||
class="bg-transparent"
|
||||
/>
|
||||
</li>
|
||||
<button
|
||||
data-testid="star_button"
|
||||
class="icon"
|
||||
:class="{ stared: entry.star }"
|
||||
@click="$emit('toggle-star')"
|
||||
v-tooltip="{
|
||||
content: !entry.star ? $t('add_star') : $t('remove_star'),
|
||||
}"
|
||||
>
|
||||
<i class="material-icons">
|
||||
{{ entry.star ? "star" : "star_border" }}
|
||||
</i>
|
||||
</button>
|
||||
<button
|
||||
data-testid="query_expand"
|
||||
class="icon"
|
||||
@click="expand = !expand"
|
||||
v-tooltip="{
|
||||
content: expand ? $t('hide_more') : $t('show_more'),
|
||||
}"
|
||||
>
|
||||
<i class="material-icons">
|
||||
{{ expand ? "unfold_less" : "unfold_more" }}
|
||||
</i>
|
||||
</button>
|
||||
<v-popover>
|
||||
<button data-testid="options" class="tooltip-target icon" v-tooltip="$t('options')">
|
||||
<i class="material-icons">more_vert</i>
|
||||
</button>
|
||||
<template slot="popover">
|
||||
<div>
|
||||
<button
|
||||
data-testid="restore_history_entry"
|
||||
class="icon"
|
||||
@click="$emit('use-entry')"
|
||||
:aria-label="$t('restore')"
|
||||
v-close-popover
|
||||
>
|
||||
<i class="material-icons">restore</i>
|
||||
<span>{{ $t("restore") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
data-testid="delete_history_entry"
|
||||
class="icon"
|
||||
@click="$emit('delete-entry')"
|
||||
:aria-label="$t('delete')"
|
||||
v-close-popover
|
||||
>
|
||||
<i class="material-icons">delete</i>
|
||||
<span>{{ $t("delete") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</v-popover>
|
||||
</div>
|
||||
<div class="show-on-large-screen">
|
||||
<li data-testid="'query'">
|
||||
<input
|
||||
v-for="(line, index) in query"
|
||||
:key="`line-${index}`"
|
||||
:aria-label="$t('query')"
|
||||
type="text"
|
||||
readonly
|
||||
:value="`${line}`"
|
||||
class="pt-0 mt-0 text-sm bg-transparent text-fgLightColor"
|
||||
/>
|
||||
</li>
|
||||
</div>
|
||||
<transition name="fade">
|
||||
<div v-if="showMore" class="show-on-large-screen">
|
||||
<li>
|
||||
<input
|
||||
:aria-label="$t('time')"
|
||||
type="text"
|
||||
readonly
|
||||
:value="entry.time"
|
||||
v-tooltip="entry.date"
|
||||
class="pt-0 mt-0 text-sm bg-transparent text-fgLightColor"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<input
|
||||
:aria-label="$t('duration')"
|
||||
type="text"
|
||||
readonly
|
||||
:value="entry.duration"
|
||||
:placeholder="$t('no_duration')"
|
||||
class="pt-0 mt-0 text-sm bg-transparent text-fgLightColor"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<input
|
||||
:aria-label="$t('prerequest_script')"
|
||||
type="text"
|
||||
readonly
|
||||
:value="entry.preRequestScript"
|
||||
:placeholder="$t('no_prerequest_script')"
|
||||
class="pt-0 mt-0 text-sm bg-transparent text-fgLightColor"
|
||||
/>
|
||||
</li>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.stared {
|
||||
color: #f8e81c !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
entry: Object,
|
||||
showMore: Boolean,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
expand: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
query() {
|
||||
return this.expand
|
||||
? this.entry.query.split("\n")
|
||||
: this.entry.query.split("\n").slice(0, 2).concat(["..."])
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -13,127 +13,24 @@
|
||||
class="divide-y virtual-list divide-dashed divide-brdColor"
|
||||
:class="{ filled: filteredHistory.length }"
|
||||
>
|
||||
<ul v-for="(entry, index) in filteredHistory" :key="index">
|
||||
<div class="show-on-large-screen">
|
||||
<span
|
||||
class="p-2 m-2"
|
||||
:class="findEntryStatus(entry).className"
|
||||
:style="{ '--status-code': entry.status }"
|
||||
>
|
||||
{{ `${entry.method} \xA0 • \xA0 ${entry.status}` }}
|
||||
</span>
|
||||
<li>
|
||||
<input
|
||||
:aria-label="$t('token_req_name')"
|
||||
type="text"
|
||||
readonly
|
||||
:value="entry.name"
|
||||
:placeholder="$t('empty_req_name')"
|
||||
class="bg-transparent"
|
||||
/>
|
||||
</li>
|
||||
<button
|
||||
class="icon"
|
||||
:class="{ stared: entry.star }"
|
||||
@click="toggleStar(entry)"
|
||||
v-tooltip="{
|
||||
content: !entry.star ? $t('add_star') : $t('remove_star'),
|
||||
}"
|
||||
>
|
||||
<i class="material-icons">
|
||||
{{ entry.star ? "star" : "star_border" }}
|
||||
</i>
|
||||
</button>
|
||||
<!-- <li>
|
||||
<button
|
||||
class="icon"
|
||||
v-tooltip="{
|
||||
content: !entry.usesScripts
|
||||
? 'No pre-request script'
|
||||
: 'Used pre-request script'
|
||||
}"
|
||||
>
|
||||
<i class="material-icons">
|
||||
{{ !entry.usesScripts ? "http" : "code" }}
|
||||
</i>
|
||||
</button>
|
||||
</li> -->
|
||||
<v-popover>
|
||||
<button class="tooltip-target icon" v-tooltip="$t('options')">
|
||||
<i class="material-icons">more_vert</i>
|
||||
</button>
|
||||
<template slot="popover">
|
||||
<div>
|
||||
<button
|
||||
class="icon"
|
||||
@click="useHistory(entry)"
|
||||
:aria-label="$t('edit')"
|
||||
v-close-popover
|
||||
>
|
||||
<i class="material-icons">restore</i>
|
||||
<span>{{ $t("restore") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
class="icon"
|
||||
@click="deleteHistory(entry)"
|
||||
:aria-label="$t('delete')"
|
||||
v-close-popover
|
||||
>
|
||||
<i class="material-icons">delete</i>
|
||||
<span>{{ $t("delete") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</v-popover>
|
||||
</div>
|
||||
<div class="show-on-large-screen">
|
||||
<li>
|
||||
<input
|
||||
:aria-label="$t('url')"
|
||||
type="text"
|
||||
readonly
|
||||
:value="`${entry.url}${entry.path}`"
|
||||
:placeholder="$t('no_url')"
|
||||
class="pt-0 mt-0 text-sm bg-transparent text-fgLightColor"
|
||||
/>
|
||||
</li>
|
||||
</div>
|
||||
<transition name="fade">
|
||||
<div v-if="showMore" class="show-on-large-screen">
|
||||
<li>
|
||||
<input
|
||||
:aria-label="$t('time')"
|
||||
type="text"
|
||||
readonly
|
||||
:value="entry.time"
|
||||
v-tooltip="entry.date"
|
||||
class="pt-0 mt-0 text-sm bg-transparent text-fgLightColor"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<input
|
||||
:aria-label="$t('duration')"
|
||||
type="text"
|
||||
readonly
|
||||
:value="entry.duration"
|
||||
:placeholder="$t('no_duration')"
|
||||
class="pt-0 mt-0 text-sm bg-transparent text-fgLightColor"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<input
|
||||
:aria-label="$t('prerequest_script')"
|
||||
type="text"
|
||||
readonly
|
||||
:value="entry.preRequestScript"
|
||||
:placeholder="$t('no_prerequest_script')"
|
||||
class="pt-0 mt-0 text-sm bg-transparent text-fgLightColor"
|
||||
/>
|
||||
</li>
|
||||
</div>
|
||||
</transition>
|
||||
<ul v-for="(entry, index) in filteredHistory" :key="`entry-${index}`">
|
||||
<HistoryRestCard
|
||||
v-if="page == 'rest'"
|
||||
:entry="entry"
|
||||
:id="index"
|
||||
:showMore="showMore"
|
||||
@toggle-star="toggleStar(entry)"
|
||||
@delete-entry="deleteHistory(entry)"
|
||||
@use-entry="useHistory(entry)"
|
||||
/>
|
||||
<HistoryGraphqlCard
|
||||
v-if="page == 'graphql'"
|
||||
:entry="entry"
|
||||
:showMore="showMore"
|
||||
@toggle-star="toggleStar(entry)"
|
||||
@delete-entry="deleteHistory(entry)"
|
||||
@use-entry="useHistory(entry)"
|
||||
/>
|
||||
</ul>
|
||||
</div>
|
||||
<p :class="{ hidden: filteredHistory.length != 0 || history.length === 0 }" class="info">
|
||||
@@ -144,12 +41,17 @@
|
||||
</p>
|
||||
<div v-if="history.length !== 0" class="rounded-b-lg bg-bgDarkColor">
|
||||
<div class="row-wrapper" v-if="!isClearingHistory">
|
||||
<button class="icon" :disabled="history.length === 0" @click="enableHistoryClearing">
|
||||
<button
|
||||
data-testid="clear_history"
|
||||
class="icon"
|
||||
:disabled="history.length === 0"
|
||||
@click="enableHistoryClearing"
|
||||
>
|
||||
<i class="material-icons">clear_all</i>
|
||||
<span>{{ $t("clear_all") }}</span>
|
||||
</button>
|
||||
<v-popover>
|
||||
<button class="tooltip-target icon" v-tooltip="$t('sort')">
|
||||
<button v-if="this.page == 'rest'" class="tooltip-target icon" v-tooltip="$t('sort')">
|
||||
<i class="material-icons">sort</i>
|
||||
</button>
|
||||
<template slot="popover">
|
||||
@@ -203,10 +105,20 @@
|
||||
<div class="row-wrapper" v-else>
|
||||
<p class="info"><i class="material-icons">help_outline</i> {{ $t("are_you_sure") }}</p>
|
||||
<div>
|
||||
<button class="icon" @click="clearHistory" v-tooltip="$t('yes')">
|
||||
<button
|
||||
data-testid="confirm_clear_history"
|
||||
class="icon"
|
||||
@click="clearHistory"
|
||||
v-tooltip="$t('yes')"
|
||||
>
|
||||
<i class="material-icons">done</i>
|
||||
</button>
|
||||
<button class="icon" @click="disableHistoryClearing" v-tooltip="$t('no')">
|
||||
<button
|
||||
data-testid="reject_clear_history"
|
||||
class="icon"
|
||||
@click="disableHistoryClearing"
|
||||
v-tooltip="$t('no')"
|
||||
>
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
</div>
|
||||
@@ -218,36 +130,26 @@
|
||||
<style scoped lang="scss">
|
||||
.virtual-list {
|
||||
max-height: calc(100vh - 270px);
|
||||
|
||||
[readonly] {
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.fade-enter,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.stared {
|
||||
color: #f8e81c !important;
|
||||
}
|
||||
|
||||
ul,
|
||||
ol {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
@media (max-width: 720px) {
|
||||
.virtual-list.filled {
|
||||
min-height: 320px;
|
||||
}
|
||||
|
||||
.labels {
|
||||
display: none;
|
||||
}
|
||||
@@ -255,19 +157,23 @@ ol {
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import findStatusGroup from "~/helpers/findStatusGroup"
|
||||
import { fb } from "~/helpers/fb"
|
||||
|
||||
const updateOnLocalStorage = (propertyName, property) =>
|
||||
window.localStorage.setItem(propertyName, JSON.stringify(property))
|
||||
|
||||
export default {
|
||||
props: {
|
||||
page: String,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
history:
|
||||
fb.currentUser !== null
|
||||
? fb.currentHistory
|
||||
: JSON.parse(window.localStorage.getItem("history")) || [],
|
||||
: JSON.parse(
|
||||
window.localStorage.getItem(this.page == "rest" ? "history" : "graphqlHistory")
|
||||
) || [],
|
||||
filterText: "",
|
||||
showFilter: false,
|
||||
isClearingHistory: false,
|
||||
@@ -283,8 +189,12 @@ export default {
|
||||
filteredHistory() {
|
||||
this.history =
|
||||
fb.currentUser !== null
|
||||
? fb.currentHistory
|
||||
: JSON.parse(window.localStorage.getItem("history")) || []
|
||||
? this.page == "rest"
|
||||
? fb.currentHistory
|
||||
: fb.currentGraphqlHistory
|
||||
: JSON.parse(
|
||||
window.localStorage.getItem(this.page == "rest" ? "history" : "graphqlHistory")
|
||||
) || []
|
||||
return this.history.filter((entry) => {
|
||||
const filterText = this.filterText.toLowerCase()
|
||||
return Object.keys(entry).some((key) => {
|
||||
@@ -298,12 +208,12 @@ export default {
|
||||
methods: {
|
||||
async clearHistory() {
|
||||
if (fb.currentUser !== null) {
|
||||
await fb.clearHistory()
|
||||
this.page == "rest" ? await fb.clearHistory() : await fb.clearGraphqlHistory()
|
||||
}
|
||||
this.history = []
|
||||
this.filterText = ""
|
||||
this.disableHistoryClearing()
|
||||
updateOnLocalStorage("history", this.history)
|
||||
updateOnLocalStorage(this.page == "rest" ? "history" : "graphqlHistory", this.history)
|
||||
this.$toast.error(this.$t("history_deleted"), {
|
||||
icon: "delete",
|
||||
})
|
||||
@@ -311,30 +221,25 @@ export default {
|
||||
useHistory(entry) {
|
||||
this.$emit("useHistory", entry)
|
||||
},
|
||||
findEntryStatus({ status }) {
|
||||
const foundStatusGroup = findStatusGroup(status)
|
||||
return (
|
||||
foundStatusGroup || {
|
||||
className: "",
|
||||
}
|
||||
)
|
||||
},
|
||||
async deleteHistory(entry) {
|
||||
if (fb.currentUser !== null) {
|
||||
await fb.deleteHistory(entry)
|
||||
}
|
||||
this.history.splice(this.history.indexOf(entry), 1)
|
||||
if (this.history.length === 0) {
|
||||
this.filterText = ""
|
||||
}
|
||||
updateOnLocalStorage("history", this.history)
|
||||
if (fb.currentUser !== null) {
|
||||
await (this.page == "rest" ? fb.deleteHistory(entry) : fb.deleteGraphqlHistory(entry))
|
||||
this.history = fb.currentHistory
|
||||
updateOnLocalStorage(this.page == "rest" ? "history" : "graphqlHistory", this.history)
|
||||
} else {
|
||||
this.history.splice(this.history.indexOf(entry), 1)
|
||||
updateOnLocalStorage(this.page == "rest" ? "history" : "graphqlHistory", this.history)
|
||||
}
|
||||
this.$toast.error(this.$t("deleted"), {
|
||||
icon: "delete",
|
||||
})
|
||||
},
|
||||
addEntry(entry) {
|
||||
this.history.push(entry)
|
||||
updateOnLocalStorage("history", this.history)
|
||||
updateOnLocalStorage(this.page == "rest" ? "history" : "graphqlHistory", this.history)
|
||||
},
|
||||
enableHistoryClearing() {
|
||||
if (!this.history || !this.history.length) return
|
||||
@@ -409,10 +314,12 @@ export default {
|
||||
},
|
||||
async toggleStar(entry) {
|
||||
if (fb.currentUser !== null) {
|
||||
await fb.toggleStar(entry, !entry.star)
|
||||
this.page == "rest"
|
||||
? await fb.toggleStar(entry, !entry.star)
|
||||
: await fb.toggleGraphqlHistoryStar(entry, !entry.star)
|
||||
}
|
||||
entry.star = !entry.star
|
||||
updateOnLocalStorage("history", this.history)
|
||||
updateOnLocalStorage(this.page == "rest" ? "history" : "graphqlHistory", this.history)
|
||||
},
|
||||
},
|
||||
}
|
||||
160
components/history/rest/Card.vue
Normal file
160
components/history/rest/Card.vue
Normal file
@@ -0,0 +1,160 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="show-on-large-screen">
|
||||
<span
|
||||
class="p-2 m-2"
|
||||
:class="entryStatus.className"
|
||||
:style="{ '--status-code': entry.status }"
|
||||
>
|
||||
{{ `${entry.method} \xA0 • \xA0 ${entry.status}` }}
|
||||
</span>
|
||||
<li>
|
||||
<input
|
||||
:aria-label="$t('token_req_name')"
|
||||
type="text"
|
||||
readonly
|
||||
:value="entry.name"
|
||||
:placeholder="$t('empty_req_name')"
|
||||
class="bg-transparent"
|
||||
/>
|
||||
</li>
|
||||
<button
|
||||
data-testid="star_button"
|
||||
class="icon"
|
||||
:class="{ stared: entry.star }"
|
||||
@click="$emit('toggle-star')"
|
||||
v-tooltip="{
|
||||
content: !entry.star ? $t('add_star') : $t('remove_star'),
|
||||
}"
|
||||
>
|
||||
<i class="material-icons">
|
||||
{{ entry.star ? "star" : "star_border" }}
|
||||
</i>
|
||||
</button>
|
||||
<!-- <li>
|
||||
<button
|
||||
class="icon"
|
||||
v-tooltip="{
|
||||
content: !entry.usesScripts
|
||||
? 'No pre-request script'
|
||||
: 'Used pre-request script'
|
||||
}"
|
||||
>
|
||||
<i class="material-icons">
|
||||
{{ !entry.usesScripts ? "http" : "code" }}
|
||||
</i>
|
||||
</button>
|
||||
</li> -->
|
||||
<v-popover>
|
||||
<button class="tooltip-target icon" v-tooltip="$t('options')">
|
||||
<i class="material-icons">more_vert</i>
|
||||
</button>
|
||||
<template slot="popover">
|
||||
<div>
|
||||
<button
|
||||
data-testid="restore_history_entry"
|
||||
class="icon"
|
||||
@click="$emit('use-entry')"
|
||||
:aria-label="$t('edit')"
|
||||
v-close-popover
|
||||
>
|
||||
<i class="material-icons">restore</i>
|
||||
<span>{{ $t("restore") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
data-testid="delete_history_entry"
|
||||
class="icon"
|
||||
@click="$emit('delete-entry')"
|
||||
:aria-label="$t('delete')"
|
||||
v-close-popover
|
||||
>
|
||||
<i class="material-icons">delete</i>
|
||||
<span>{{ $t("delete") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</v-popover>
|
||||
</div>
|
||||
<div class="show-on-large-screen">
|
||||
<li>
|
||||
<input
|
||||
:aria-label="$t('url')"
|
||||
type="text"
|
||||
readonly
|
||||
:value="`${entry.url}${entry.path}`"
|
||||
:placeholder="$t('no_url')"
|
||||
class="pt-0 mt-0 text-sm bg-transparent text-fgLightColor"
|
||||
/>
|
||||
</li>
|
||||
</div>
|
||||
<transition name="fade">
|
||||
<div v-if="showMore" class="show-on-large-screen">
|
||||
<li>
|
||||
<input
|
||||
:aria-label="$t('time')"
|
||||
type="text"
|
||||
readonly
|
||||
:value="entry.time"
|
||||
v-tooltip="entry.date"
|
||||
class="pt-0 mt-0 text-sm bg-transparent text-fgLightColor"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<input
|
||||
:aria-label="$t('duration')"
|
||||
type="text"
|
||||
readonly
|
||||
:value="entry.duration"
|
||||
:placeholder="$t('no_duration')"
|
||||
class="pt-0 mt-0 text-sm bg-transparent text-fgLightColor"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<input
|
||||
:aria-label="$t('prerequest_script')"
|
||||
type="text"
|
||||
readonly
|
||||
:value="entry.preRequestScript"
|
||||
:placeholder="$t('no_prerequest_script')"
|
||||
class="pt-0 mt-0 text-sm bg-transparent text-fgLightColor"
|
||||
/>
|
||||
</li>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.stared {
|
||||
color: #f8e81c !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import findStatusGroup from "~/helpers/findStatusGroup"
|
||||
|
||||
export default {
|
||||
props: {
|
||||
entry: Object,
|
||||
showMore: Boolean,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
expand: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
entryStatus() {
|
||||
const foundStatusGroup = findStatusGroup(this.entry.status)
|
||||
console.log(foundStatusGroup)
|
||||
return (
|
||||
foundStatusGroup || {
|
||||
className: "",
|
||||
}
|
||||
)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user