[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="divide-y virtual-list divide-dashed divide-brdColor"
|
||||||
:class="{ filled: filteredHistory.length }"
|
:class="{ filled: filteredHistory.length }"
|
||||||
>
|
>
|
||||||
<ul v-for="(entry, index) in filteredHistory" :key="index">
|
<ul v-for="(entry, index) in filteredHistory" :key="`entry-${index}`">
|
||||||
<div class="show-on-large-screen">
|
<HistoryRestCard
|
||||||
<span
|
v-if="page == 'rest'"
|
||||||
class="p-2 m-2"
|
:entry="entry"
|
||||||
:class="findEntryStatus(entry).className"
|
:id="index"
|
||||||
:style="{ '--status-code': entry.status }"
|
:showMore="showMore"
|
||||||
>
|
@toggle-star="toggleStar(entry)"
|
||||||
{{ `${entry.method} \xA0 • \xA0 ${entry.status}` }}
|
@delete-entry="deleteHistory(entry)"
|
||||||
</span>
|
@use-entry="useHistory(entry)"
|
||||||
<li>
|
/>
|
||||||
<input
|
<HistoryGraphqlCard
|
||||||
:aria-label="$t('token_req_name')"
|
v-if="page == 'graphql'"
|
||||||
type="text"
|
:entry="entry"
|
||||||
readonly
|
:showMore="showMore"
|
||||||
:value="entry.name"
|
@toggle-star="toggleStar(entry)"
|
||||||
:placeholder="$t('empty_req_name')"
|
@delete-entry="deleteHistory(entry)"
|
||||||
class="bg-transparent"
|
@use-entry="useHistory(entry)"
|
||||||
/>
|
/>
|
||||||
</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>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<p :class="{ hidden: filteredHistory.length != 0 || history.length === 0 }" class="info">
|
<p :class="{ hidden: filteredHistory.length != 0 || history.length === 0 }" class="info">
|
||||||
@@ -144,12 +41,17 @@
|
|||||||
</p>
|
</p>
|
||||||
<div v-if="history.length !== 0" class="rounded-b-lg bg-bgDarkColor">
|
<div v-if="history.length !== 0" class="rounded-b-lg bg-bgDarkColor">
|
||||||
<div class="row-wrapper" v-if="!isClearingHistory">
|
<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>
|
<i class="material-icons">clear_all</i>
|
||||||
<span>{{ $t("clear_all") }}</span>
|
<span>{{ $t("clear_all") }}</span>
|
||||||
</button>
|
</button>
|
||||||
<v-popover>
|
<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>
|
<i class="material-icons">sort</i>
|
||||||
</button>
|
</button>
|
||||||
<template slot="popover">
|
<template slot="popover">
|
||||||
@@ -203,10 +105,20 @@
|
|||||||
<div class="row-wrapper" v-else>
|
<div class="row-wrapper" v-else>
|
||||||
<p class="info"><i class="material-icons">help_outline</i> {{ $t("are_you_sure") }}</p>
|
<p class="info"><i class="material-icons">help_outline</i> {{ $t("are_you_sure") }}</p>
|
||||||
<div>
|
<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>
|
<i class="material-icons">done</i>
|
||||||
</button>
|
</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>
|
<i class="material-icons">close</i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -218,36 +130,26 @@
|
|||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.virtual-list {
|
.virtual-list {
|
||||||
max-height: calc(100vh - 270px);
|
max-height: calc(100vh - 270px);
|
||||||
|
|
||||||
[readonly] {
|
[readonly] {
|
||||||
cursor: default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.fade-enter-active,
|
.fade-enter-active,
|
||||||
.fade-leave-active {
|
.fade-leave-active {
|
||||||
transition: all 0.2s;
|
transition: all 0.2s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fade-enter,
|
.fade-enter,
|
||||||
.fade-leave-to {
|
.fade-leave-to {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stared {
|
|
||||||
color: #f8e81c !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul,
|
ul,
|
||||||
ol {
|
ol {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 720px) {
|
@media (max-width: 720px) {
|
||||||
.virtual-list.filled {
|
.virtual-list.filled {
|
||||||
min-height: 320px;
|
min-height: 320px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.labels {
|
.labels {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
@@ -255,19 +157,23 @@ ol {
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import findStatusGroup from "~/helpers/findStatusGroup"
|
|
||||||
import { fb } from "~/helpers/fb"
|
import { fb } from "~/helpers/fb"
|
||||||
|
|
||||||
const updateOnLocalStorage = (propertyName, property) =>
|
const updateOnLocalStorage = (propertyName, property) =>
|
||||||
window.localStorage.setItem(propertyName, JSON.stringify(property))
|
window.localStorage.setItem(propertyName, JSON.stringify(property))
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
props: {
|
||||||
|
page: String,
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
history:
|
history:
|
||||||
fb.currentUser !== null
|
fb.currentUser !== null
|
||||||
? fb.currentHistory
|
? fb.currentHistory
|
||||||
: JSON.parse(window.localStorage.getItem("history")) || [],
|
: JSON.parse(
|
||||||
|
window.localStorage.getItem(this.page == "rest" ? "history" : "graphqlHistory")
|
||||||
|
) || [],
|
||||||
filterText: "",
|
filterText: "",
|
||||||
showFilter: false,
|
showFilter: false,
|
||||||
isClearingHistory: false,
|
isClearingHistory: false,
|
||||||
@@ -283,8 +189,12 @@ export default {
|
|||||||
filteredHistory() {
|
filteredHistory() {
|
||||||
this.history =
|
this.history =
|
||||||
fb.currentUser !== null
|
fb.currentUser !== null
|
||||||
? fb.currentHistory
|
? this.page == "rest"
|
||||||
: JSON.parse(window.localStorage.getItem("history")) || []
|
? fb.currentHistory
|
||||||
|
: fb.currentGraphqlHistory
|
||||||
|
: JSON.parse(
|
||||||
|
window.localStorage.getItem(this.page == "rest" ? "history" : "graphqlHistory")
|
||||||
|
) || []
|
||||||
return this.history.filter((entry) => {
|
return this.history.filter((entry) => {
|
||||||
const filterText = this.filterText.toLowerCase()
|
const filterText = this.filterText.toLowerCase()
|
||||||
return Object.keys(entry).some((key) => {
|
return Object.keys(entry).some((key) => {
|
||||||
@@ -298,12 +208,12 @@ export default {
|
|||||||
methods: {
|
methods: {
|
||||||
async clearHistory() {
|
async clearHistory() {
|
||||||
if (fb.currentUser !== null) {
|
if (fb.currentUser !== null) {
|
||||||
await fb.clearHistory()
|
this.page == "rest" ? await fb.clearHistory() : await fb.clearGraphqlHistory()
|
||||||
}
|
}
|
||||||
this.history = []
|
this.history = []
|
||||||
this.filterText = ""
|
this.filterText = ""
|
||||||
this.disableHistoryClearing()
|
this.disableHistoryClearing()
|
||||||
updateOnLocalStorage("history", this.history)
|
updateOnLocalStorage(this.page == "rest" ? "history" : "graphqlHistory", this.history)
|
||||||
this.$toast.error(this.$t("history_deleted"), {
|
this.$toast.error(this.$t("history_deleted"), {
|
||||||
icon: "delete",
|
icon: "delete",
|
||||||
})
|
})
|
||||||
@@ -311,30 +221,25 @@ export default {
|
|||||||
useHistory(entry) {
|
useHistory(entry) {
|
||||||
this.$emit("useHistory", entry)
|
this.$emit("useHistory", entry)
|
||||||
},
|
},
|
||||||
findEntryStatus({ status }) {
|
|
||||||
const foundStatusGroup = findStatusGroup(status)
|
|
||||||
return (
|
|
||||||
foundStatusGroup || {
|
|
||||||
className: "",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
},
|
|
||||||
async deleteHistory(entry) {
|
async deleteHistory(entry) {
|
||||||
if (fb.currentUser !== null) {
|
|
||||||
await fb.deleteHistory(entry)
|
|
||||||
}
|
|
||||||
this.history.splice(this.history.indexOf(entry), 1)
|
|
||||||
if (this.history.length === 0) {
|
if (this.history.length === 0) {
|
||||||
this.filterText = ""
|
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"), {
|
this.$toast.error(this.$t("deleted"), {
|
||||||
icon: "delete",
|
icon: "delete",
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
addEntry(entry) {
|
addEntry(entry) {
|
||||||
this.history.push(entry)
|
this.history.push(entry)
|
||||||
updateOnLocalStorage("history", this.history)
|
updateOnLocalStorage(this.page == "rest" ? "history" : "graphqlHistory", this.history)
|
||||||
},
|
},
|
||||||
enableHistoryClearing() {
|
enableHistoryClearing() {
|
||||||
if (!this.history || !this.history.length) return
|
if (!this.history || !this.history.length) return
|
||||||
@@ -409,10 +314,12 @@ export default {
|
|||||||
},
|
},
|
||||||
async toggleStar(entry) {
|
async toggleStar(entry) {
|
||||||
if (fb.currentUser !== null) {
|
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
|
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>
|
||||||
@@ -30,6 +30,7 @@ export class FirebaseInstance {
|
|||||||
this.currentFeeds = []
|
this.currentFeeds = []
|
||||||
this.currentSettings = []
|
this.currentSettings = []
|
||||||
this.currentHistory = []
|
this.currentHistory = []
|
||||||
|
this.currentGraphqlHistory = []
|
||||||
this.currentCollections = []
|
this.currentCollections = []
|
||||||
this.currentEnvironments = []
|
this.currentEnvironments = []
|
||||||
|
|
||||||
@@ -97,6 +98,19 @@ export class FirebaseInstance {
|
|||||||
this.currentHistory = history
|
this.currentHistory = history
|
||||||
})
|
})
|
||||||
|
|
||||||
|
this.usersCollection
|
||||||
|
.doc(this.currentUser.uid)
|
||||||
|
.collection("graphqlHistory")
|
||||||
|
.onSnapshot((historyRef) => {
|
||||||
|
const history = []
|
||||||
|
historyRef.forEach((doc) => {
|
||||||
|
const entry = doc.data()
|
||||||
|
entry.id = doc.id
|
||||||
|
history.push(entry)
|
||||||
|
})
|
||||||
|
this.currentGraphqlHistory = history
|
||||||
|
})
|
||||||
|
|
||||||
this.usersCollection
|
this.usersCollection
|
||||||
.doc(this.currentUser.uid)
|
.doc(this.currentUser.uid)
|
||||||
.collection("collections")
|
.collection("collections")
|
||||||
@@ -215,6 +229,17 @@ export class FirebaseInstance {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async writeGraphqlHistory(entry) {
|
||||||
|
const hs = entry
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.usersCollection.doc(this.currentUser.uid).collection("graphqlHistory").add(hs)
|
||||||
|
} catch (e) {
|
||||||
|
console.error("error inserting", hs, e)
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async deleteHistory(entry) {
|
async deleteHistory(entry) {
|
||||||
try {
|
try {
|
||||||
await this.usersCollection
|
await this.usersCollection
|
||||||
@@ -228,6 +253,19 @@ export class FirebaseInstance {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async deleteGraphqlHistory(entry) {
|
||||||
|
try {
|
||||||
|
await this.usersCollection
|
||||||
|
.doc(this.currentUser.uid)
|
||||||
|
.collection("graphqlHistory")
|
||||||
|
.doc(entry.id)
|
||||||
|
.delete()
|
||||||
|
} catch (e) {
|
||||||
|
console.error("error deleting", entry, e)
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async clearHistory() {
|
async clearHistory() {
|
||||||
const { docs } = await this.usersCollection
|
const { docs } = await this.usersCollection
|
||||||
.doc(this.currentUser.uid)
|
.doc(this.currentUser.uid)
|
||||||
@@ -237,6 +275,15 @@ export class FirebaseInstance {
|
|||||||
await Promise.all(docs.map((e) => this.deleteHistory(e)))
|
await Promise.all(docs.map((e) => this.deleteHistory(e)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async clearGraphqlHistory() {
|
||||||
|
const { docs } = await this.usersCollection
|
||||||
|
.doc(this.currentUser.uid)
|
||||||
|
.collection("graphqlHistory")
|
||||||
|
.get()
|
||||||
|
|
||||||
|
await Promise.all(docs.map((e) => this.deleteGraphqlHistory(e)))
|
||||||
|
}
|
||||||
|
|
||||||
async toggleStar(entry, value) {
|
async toggleStar(entry, value) {
|
||||||
try {
|
try {
|
||||||
await this.usersCollection
|
await this.usersCollection
|
||||||
@@ -251,6 +298,20 @@ export class FirebaseInstance {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async toggleGraphqlHistoryStar(entry, value) {
|
||||||
|
try {
|
||||||
|
await this.usersCollection
|
||||||
|
.doc(this.currentUser.uid)
|
||||||
|
.collection("graphqlHistory")
|
||||||
|
.doc(entry.id)
|
||||||
|
.update({ star: value })
|
||||||
|
} catch (e) {
|
||||||
|
console.error("error deleting", entry, e)
|
||||||
|
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async writeCollections(collection) {
|
async writeCollections(collection) {
|
||||||
const cl = {
|
const cl = {
|
||||||
updatedOn: new Date(),
|
updatedOn: new Date(),
|
||||||
|
|||||||
9
package-lock.json
generated
9
package-lock.json
generated
@@ -10947,6 +10947,12 @@
|
|||||||
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
|
||||||
"integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA=="
|
"integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA=="
|
||||||
},
|
},
|
||||||
|
"nan": {
|
||||||
|
"version": "2.14.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz",
|
||||||
|
"integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
"nanoid": {
|
"nanoid": {
|
||||||
"version": "3.1.20",
|
"version": "3.1.20",
|
||||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.20.tgz",
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.20.tgz",
|
||||||
@@ -16734,7 +16740,8 @@
|
|||||||
"integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
|
"integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"bindings": "^1.5.0"
|
"bindings": "^1.5.0",
|
||||||
|
"nan": "^2.12.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"glob-parent": {
|
"glob-parent": {
|
||||||
|
|||||||
@@ -318,79 +318,102 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<aside class="sticky-inner inner-right lg:max-w-md">
|
<aside class="sticky-inner inner-right lg:max-w-md">
|
||||||
<AppSection class="purple" :label="$t('docs')" ref="docs" no-legend>
|
<SmartTabs>
|
||||||
<section class="flex-col">
|
<SmartTab :id="'docs'" :label="`Docs`" :selected="true">
|
||||||
<input
|
<AppSection class="purple" :label="$t('docs')" ref="docs" no-legend>
|
||||||
type="text"
|
<section class="flex-col">
|
||||||
:placeholder="$t('search')"
|
<input
|
||||||
v-model="graphqlFieldsFilterText"
|
type="text"
|
||||||
class="rounded-t-lg"
|
:placeholder="$t('search')"
|
||||||
|
v-model="graphqlFieldsFilterText"
|
||||||
|
class="rounded-t-lg"
|
||||||
|
/>
|
||||||
|
<SmartTabs ref="gqlTabs" styles="m-4">
|
||||||
|
<div class="gqlTabs">
|
||||||
|
<SmartTab
|
||||||
|
v-if="queryFields.length > 0"
|
||||||
|
:id="'queries'"
|
||||||
|
:label="$t('queries')"
|
||||||
|
:selected="true"
|
||||||
|
>
|
||||||
|
<div v-for="field in filteredQueryFields" :key="field.name">
|
||||||
|
<GraphqlField :gqlField="field" :jumpTypeCallback="handleJumpToType" />
|
||||||
|
</div>
|
||||||
|
</SmartTab>
|
||||||
|
|
||||||
|
<SmartTab
|
||||||
|
v-if="mutationFields.length > 0"
|
||||||
|
:id="'mutations'"
|
||||||
|
:label="$t('mutations')"
|
||||||
|
>
|
||||||
|
<div v-for="field in filteredMutationFields" :key="field.name">
|
||||||
|
<GraphqlField :gqlField="field" :jumpTypeCallback="handleJumpToType" />
|
||||||
|
</div>
|
||||||
|
</SmartTab>
|
||||||
|
|
||||||
|
<SmartTab
|
||||||
|
v-if="subscriptionFields.length > 0"
|
||||||
|
:id="'subscriptions'"
|
||||||
|
:label="$t('subscriptions')"
|
||||||
|
>
|
||||||
|
<div v-for="field in filteredSubscriptionFields" :key="field.name">
|
||||||
|
<GraphqlField :gqlField="field" :jumpTypeCallback="handleJumpToType" />
|
||||||
|
</div>
|
||||||
|
</SmartTab>
|
||||||
|
|
||||||
|
<SmartTab
|
||||||
|
v-if="graphqlTypes.length > 0"
|
||||||
|
:id="'types'"
|
||||||
|
:label="$t('types')"
|
||||||
|
ref="typesTab"
|
||||||
|
>
|
||||||
|
<div v-for="type in filteredGraphqlTypes" :key="type.name">
|
||||||
|
<GraphqlType
|
||||||
|
:gqlType="type"
|
||||||
|
:gqlTypes="graphqlTypes"
|
||||||
|
:isHighlighted="isGqlTypeHighlighted({ gqlType: type })"
|
||||||
|
:highlightedFields="getGqlTypeHighlightedFields({ gqlType: type })"
|
||||||
|
:jumpTypeCallback="handleJumpToType"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</SmartTab>
|
||||||
|
</div>
|
||||||
|
</SmartTabs>
|
||||||
|
</section>
|
||||||
|
<p
|
||||||
|
v-if="
|
||||||
|
queryFields.length === 0 &&
|
||||||
|
mutationFields.length === 0 &&
|
||||||
|
subscriptionFields.length === 0 &&
|
||||||
|
graphqlTypes.length === 0
|
||||||
|
"
|
||||||
|
class="info"
|
||||||
|
>
|
||||||
|
{{ $t("send_request_first") }}
|
||||||
|
</p>
|
||||||
|
</AppSection>
|
||||||
|
</SmartTab>
|
||||||
|
|
||||||
|
<SmartTab :id="'history'" :label="$t('history')">
|
||||||
|
<History
|
||||||
|
@useHistory="handleUseHistory"
|
||||||
|
ref="graphqlHistoryComponent"
|
||||||
|
:page="'graphql'"
|
||||||
/>
|
/>
|
||||||
<SmartTabs ref="gqlTabs" styles="m-4">
|
</SmartTab>
|
||||||
<div class="gqlTabs">
|
|
||||||
<SmartTab
|
|
||||||
v-if="queryFields.length > 0"
|
|
||||||
:id="'queries'"
|
|
||||||
:label="$t('queries')"
|
|
||||||
:selected="true"
|
|
||||||
>
|
|
||||||
<div v-for="field in filteredQueryFields" :key="field.name">
|
|
||||||
<GraphqlField :gqlField="field" :jumpTypeCallback="handleJumpToType" />
|
|
||||||
</div>
|
|
||||||
</SmartTab>
|
|
||||||
|
|
||||||
<SmartTab
|
<!-- <SmartTab :id="'collections'" :label="$t('collections')">
|
||||||
v-if="mutationFields.length > 0"
|
<Collections />
|
||||||
:id="'mutations'"
|
</SmartTab>
|
||||||
:label="$t('mutations')"
|
|
||||||
>
|
|
||||||
<div v-for="field in filteredMutationFields" :key="field.name">
|
|
||||||
<GraphqlField :gqlField="field" :jumpTypeCallback="handleJumpToType" />
|
|
||||||
</div>
|
|
||||||
</SmartTab>
|
|
||||||
|
|
||||||
<SmartTab
|
<SmartTab :id="'env'" :label="$t('environments')">
|
||||||
v-if="subscriptionFields.length > 0"
|
<Environments @use-environment="useSelectedEnvironment($event)" />
|
||||||
:id="'subscriptions'"
|
</SmartTab>
|
||||||
:label="$t('subscriptions')"
|
|
||||||
>
|
|
||||||
<div v-for="field in filteredSubscriptionFields" :key="field.name">
|
|
||||||
<GraphqlField :gqlField="field" :jumpTypeCallback="handleJumpToType" />
|
|
||||||
</div>
|
|
||||||
</SmartTab>
|
|
||||||
|
|
||||||
<SmartTab
|
<SmartTab :id="'notes'" :label="$t('notes')">
|
||||||
v-if="graphqlTypes.length > 0"
|
<HttpNotes />
|
||||||
:id="'types'"
|
</SmartTab> -->
|
||||||
:label="$t('types')"
|
</SmartTabs>
|
||||||
ref="typesTab"
|
|
||||||
>
|
|
||||||
<div v-for="type in filteredGraphqlTypes" :key="type.name">
|
|
||||||
<GraphqlType
|
|
||||||
:gqlType="type"
|
|
||||||
:gqlTypes="graphqlTypes"
|
|
||||||
:isHighlighted="isGqlTypeHighlighted({ gqlType: type })"
|
|
||||||
:highlightedFields="getGqlTypeHighlightedFields({ gqlType: type })"
|
|
||||||
:jumpTypeCallback="handleJumpToType"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</SmartTab>
|
|
||||||
</div>
|
|
||||||
</SmartTabs>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<p
|
|
||||||
v-if="
|
|
||||||
queryFields.length === 0 &&
|
|
||||||
mutationFields.length === 0 &&
|
|
||||||
subscriptionFields.length === 0 &&
|
|
||||||
graphqlTypes.length === 0
|
|
||||||
"
|
|
||||||
class="info"
|
|
||||||
>
|
|
||||||
{{ $t("send_request_first") }}
|
|
||||||
</p>
|
|
||||||
</AppSection>
|
|
||||||
</aside>
|
</aside>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -412,6 +435,7 @@ import * as gql from "graphql"
|
|||||||
import { commonHeaders } from "~/helpers/headers"
|
import { commonHeaders } from "~/helpers/headers"
|
||||||
import { getPlatformSpecialKey } from "~/helpers/platformutils"
|
import { getPlatformSpecialKey } from "~/helpers/platformutils"
|
||||||
import { sendNetworkRequest } from "~/helpers/network"
|
import { sendNetworkRequest } from "~/helpers/network"
|
||||||
|
import { fb } from "~/helpers/fb"
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
@@ -429,6 +453,7 @@ export default {
|
|||||||
graphqlFieldsFilterText: undefined,
|
graphqlFieldsFilterText: undefined,
|
||||||
isPollingSchema: false,
|
isPollingSchema: false,
|
||||||
timeoutSubscription: null,
|
timeoutSubscription: null,
|
||||||
|
activeSidebar: true,
|
||||||
|
|
||||||
settings: {
|
settings: {
|
||||||
SCROLL_INTO_ENABLED:
|
SCROLL_INTO_ENABLED:
|
||||||
@@ -528,6 +553,17 @@ export default {
|
|||||||
next()
|
next()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
useSelectedEnvironment(event) {
|
||||||
|
console.log("use selected environment")
|
||||||
|
},
|
||||||
|
handleUseHistory(entry) {
|
||||||
|
this.url = entry.url
|
||||||
|
this.headers = entry.headers
|
||||||
|
this.gqlQueryString = entry.query
|
||||||
|
this.response = entry.responseText
|
||||||
|
this.variableString = entry.variables
|
||||||
|
this.schema = ""
|
||||||
|
},
|
||||||
isGqlTypeHighlighted({ gqlType }) {
|
isGqlTypeHighlighted({ gqlType }) {
|
||||||
if (!this.graphqlFieldsFilterText) return false
|
if (!this.graphqlFieldsFilterText) return false
|
||||||
|
|
||||||
@@ -683,7 +719,13 @@ export default {
|
|||||||
},
|
},
|
||||||
data: JSON.stringify({ query: gqlQueryString, variables }),
|
data: JSON.stringify({ query: gqlQueryString, variables }),
|
||||||
}
|
}
|
||||||
|
let entry = {
|
||||||
|
url: this.url,
|
||||||
|
query: gqlQueryString,
|
||||||
|
variables: this.variableString,
|
||||||
|
star: false,
|
||||||
|
headers: this.headers,
|
||||||
|
}
|
||||||
const res = await sendNetworkRequest(reqOptions, this.$store)
|
const res = await sendNetworkRequest(reqOptions, this.$store)
|
||||||
|
|
||||||
// HACK: Temporary trailing null character issue from the extension fix
|
// HACK: Temporary trailing null character issue from the extension fix
|
||||||
@@ -696,6 +738,20 @@ export default {
|
|||||||
this.$toast.info(this.$t("finished_in", { duration }), {
|
this.$toast.info(this.$t("finished_in", { duration }), {
|
||||||
icon: "done",
|
icon: "done",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
entry = {
|
||||||
|
...entry,
|
||||||
|
response: this.response,
|
||||||
|
date: new Date().toLocaleDateString(),
|
||||||
|
time: new Date().toLocaleTimeString(),
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$refs.graphqlHistoryComponent.addEntry(entry)
|
||||||
|
if (fb.currentUser !== null && fb.currentSettings[2]) {
|
||||||
|
if (fb.currentSettings[2].value) {
|
||||||
|
fb.writeGraphqlHistory(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.response = `${error}. ${this.$t("check_console_details")}`
|
this.response = `${error}. ${this.$t("check_console_details")}`
|
||||||
this.$nuxt.$loading.finish()
|
this.$nuxt.$loading.finish()
|
||||||
|
|||||||
@@ -532,7 +532,7 @@
|
|||||||
<section>
|
<section>
|
||||||
<SmartTabs>
|
<SmartTabs>
|
||||||
<SmartTab :id="'history'" :label="$t('history')" :selected="true">
|
<SmartTab :id="'history'" :label="$t('history')" :selected="true">
|
||||||
<HttpHistory @useHistory="handleUseHistory" ref="historyComponent" />
|
<History :page="'rest'" @useHistory="handleUseHistory" ref="historyComponent" />
|
||||||
</SmartTab>
|
</SmartTab>
|
||||||
|
|
||||||
<SmartTab :id="'collections'" :label="$t('collections')">
|
<SmartTab :id="'collections'" :label="$t('collections')">
|
||||||
|
|||||||
Reference in New Issue
Block a user