diff --git a/.huskyrc b/.huskyrc deleted file mode 100644 index 2543db718..000000000 --- a/.huskyrc +++ /dev/null @@ -1,5 +0,0 @@ -{ - "hooks": { - "pre-commit": "npm run pretty-quick" - } -} \ No newline at end of file diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index 8684950aa..000000000 --- a/.prettierrc +++ /dev/null @@ -1,6 +0,0 @@ -{ - "trailingComma": "es5", - "semi": false, - "singleQuote": false, - "printWidth": 100 -} diff --git a/components/ace-editor.vue b/components/ace-editor.vue index b348126cf..0ac6b2369 100644 --- a/components/ace-editor.vue +++ b/components/ace-editor.vue @@ -5,26 +5,26 @@ diff --git a/components/section.vue b/components/section.vue index 6556f1927..68f107c95 100644 --- a/components/section.vue +++ b/components/section.vue @@ -3,10 +3,10 @@ {{ label }} - {{ isCollapsed ? "expand_more" : "expand_less" }} + {{ isCollapsed(label) ? "expand_more" : "expand_less" }} -
+
@@ -24,12 +24,9 @@ export default { frameColorsEnabled() { return this.$store.state.postwoman.settings.FRAME_COLORS_ENABLED || false }, - }, - - data() { - return { - isCollapsed: false, - } + sectionString() { + return `${this.$route.path.replace(/\/+$/, "")}/${this.label}` + }, }, props: { @@ -46,7 +43,12 @@ export default { collapse({ target }) { const parent = target.parentNode.parentNode parent.querySelector(".collapsible").classList.toggle("hidden") - this.isCollapsed = !this.isCollapsed + + // Save collapsed section into the collapsedSections array + this.$store.commit("setCollapsedSection", this.sectionString) + }, + isCollapsed(label) { + return this.$store.state.theme.collapsedSections.includes(this.sectionString) || false }, }, } diff --git a/functions/jsonParse.js b/functions/jsonParse.js index 3ccfb055d..bc4b5d008 100644 --- a/functions/jsonParse.js +++ b/functions/jsonParse.js @@ -20,152 +20,152 @@ * */ export default function jsonParse(str) { - string = str; - strLen = str.length; - start = end = lastEnd = -1; - ch(); - lex(); - const ast = parseObj(); - expect('EOF'); - return ast; + string = str + strLen = str.length + start = end = lastEnd = -1 + ch() + lex() + const ast = parseObj() + expect("EOF") + return ast } -let string; -let strLen; -let start; -let end; -let lastEnd; -let code; -let kind; +let string +let strLen +let start +let end +let lastEnd +let code +let kind function parseObj() { - const nodeStart = start; - const members = []; - expect('{'); - if (!skip('}')) { + const nodeStart = start + const members = [] + expect("{") + if (!skip("}")) { do { - members.push(parseMember()); - } while (skip(',')); - expect('}'); + members.push(parseMember()) + } while (skip(",")) + expect("}") } return { - kind: 'Object', + kind: "Object", start: nodeStart, end: lastEnd, members, - }; + } } function parseMember() { - const nodeStart = start; - const key = kind === 'String' ? curToken() : null; - expect('String'); - expect(':'); - const value = parseVal(); + const nodeStart = start + const key = kind === "String" ? curToken() : null + expect("String") + expect(":") + const value = parseVal() return { - kind: 'Member', + kind: "Member", start: nodeStart, end: lastEnd, key, value, - }; + } } function parseArr() { - const nodeStart = start; - const values = []; - expect('['); - if (!skip(']')) { + const nodeStart = start + const values = [] + expect("[") + if (!skip("]")) { do { - values.push(parseVal()); - } while (skip(',')); - expect(']'); + values.push(parseVal()) + } while (skip(",")) + expect("]") } return { - kind: 'Array', + kind: "Array", start: nodeStart, end: lastEnd, values, - }; + } } function parseVal() { switch (kind) { - case '[': - return parseArr(); - case '{': - return parseObj(); - case 'String': - case 'Number': - case 'Boolean': - case 'Null': - const token = curToken(); - lex(); - return token; + case "[": + return parseArr() + case "{": + return parseObj() + case "String": + case "Number": + case "Boolean": + case "Null": + const token = curToken() + lex() + return token } - return expect('Value'); + return expect("Value") } function curToken() { - return { kind, start, end, value: JSON.parse(string.slice(start, end)) }; + return { kind, start, end, value: JSON.parse(string.slice(start, end)) } } function expect(str) { if (kind === str) { - lex(); - return; + lex() + return } - let found; - if (kind === 'EOF') { - found = '[end of file]'; + let found + if (kind === "EOF") { + found = "[end of file]" } else if (end - start > 1) { - found = '`' + string.slice(start, end) + '`'; + found = "`" + string.slice(start, end) + "`" } else { - const match = string.slice(start).match(/^.+?\b/); - found = '`' + (match ? match[0] : string[start]) + '`'; + const match = string.slice(start).match(/^.+?\b/) + found = "`" + (match ? match[0] : string[start]) + "`" } - throw syntaxError(`Expected ${str} but found ${found}.`); + throw syntaxError(`Expected ${str} but found ${found}.`) } function syntaxError(message) { - return { message, start, end }; + return { message, start, end } } function skip(k) { if (kind === k) { - lex(); - return true; + lex() + return true } } function ch() { if (end < strLen) { - end++; - code = end === strLen ? 0 : string.charCodeAt(end); + end++ + code = end === strLen ? 0 : string.charCodeAt(end) } } function lex() { - lastEnd = end; + lastEnd = end while (code === 9 || code === 10 || code === 13 || code === 32) { - ch(); + ch() } if (code === 0) { - kind = 'EOF'; - return; + kind = "EOF" + return } - start = end; + start = end switch (code) { // " case 34: - kind = 'String'; - return readString(); + kind = "String" + return readString() // -, 0-9 case 45: case 48: @@ -178,50 +178,50 @@ function lex() { case 55: case 56: case 57: - kind = 'Number'; - return readNumber(); + kind = "Number" + return readNumber() // f case 102: - if (string.slice(start, start + 5) !== 'false') { - break; + if (string.slice(start, start + 5) !== "false") { + break } - end += 4; - ch(); + end += 4 + ch() - kind = 'Boolean'; - return; + kind = "Boolean" + return // n case 110: - if (string.slice(start, start + 4) !== 'null') { - break; + if (string.slice(start, start + 4) !== "null") { + break } - end += 3; - ch(); + end += 3 + ch() - kind = 'Null'; - return; + kind = "Null" + return // t case 116: - if (string.slice(start, start + 4) !== 'true') { - break; + if (string.slice(start, start + 4) !== "true") { + break } - end += 3; - ch(); + end += 3 + ch() - kind = 'Boolean'; - return; + kind = "Boolean" + return } - kind = string[start]; - ch(); + kind = string[start] + ch() } function readString() { - ch(); + ch() while (code !== 34 && code > 31) { if (code === 92) { // \ - ch(); + ch() switch (code) { case 34: // " case 47: // / @@ -231,31 +231,31 @@ function readString() { case 110: // n case 114: // r case 116: // t - ch(); - break; + ch() + break case 117: // u - ch(); - readHex(); - readHex(); - readHex(); - readHex(); - break; + ch() + readHex() + readHex() + readHex() + readHex() + break default: - throw syntaxError('Bad character escape sequence.'); + throw syntaxError("Bad character escape sequence.") } } else if (end === strLen) { - throw syntaxError('Unterminated string.'); + throw syntaxError("Unterminated string.") } else { - ch(); + ch() } } if (code === 34) { - ch(); - return; + ch() + return } - throw syntaxError('Unterminated string.'); + throw syntaxError("Unterminated string.") } function readHex() { @@ -264,47 +264,47 @@ function readHex() { (code >= 65 && code <= 70) || // A-F (code >= 97 && code <= 102) // a-f ) { - return ch(); + return ch() } - throw syntaxError('Expected hexadecimal digit.'); + throw syntaxError("Expected hexadecimal digit.") } function readNumber() { if (code === 45) { // - - ch(); + ch() } if (code === 48) { // 0 - ch(); + ch() } else { - readDigits(); + readDigits() } if (code === 46) { // . - ch(); - readDigits(); + ch() + readDigits() } if (code === 69 || code === 101) { // E e - ch(); + ch() if (code === 43 || code === 45) { // + - - ch(); + ch() } - readDigits(); + readDigits() } } function readDigits() { if (code < 48 || code > 57) { // 0 - 9 - throw syntaxError('Expected decimal digit.'); + throw syntaxError("Expected decimal digit.") } do { - ch(); - } while (code >= 48 && code <= 57); // 0 - 9 + ch() + } while (code >= 48 && code <= 57) // 0 - 9 } diff --git a/layouts/default.vue b/layouts/default.vue index 4b299e23f..996759827 100644 --- a/layouts/default.vue +++ b/layouts/default.vue @@ -758,7 +758,11 @@ export default { }) } let showExtensionsToast = localStorage.getItem("showExtensionsToast") === "yes" - if (!this.extensionInstalled && !showExtensionsToast) { + + // Just return if showExtensionsToast is "no" + if (!showExtensionsToast) return + + if (!this.extensionInstalled) { setTimeout(() => { this.$toast.show(this.$t("extensions_info2"), { icon: "extension", @@ -776,6 +780,11 @@ export default { { text: this.$t("no"), onClick: (e, toastObject) => { + this.$store.commit("setMiscState", { + value: false, + attribute: "showExtensionsToast", + }) + localStorage.setItem("showExtensionsToast", "no") toastObject.goAway(0) }, }, diff --git a/package-lock.json b/package-lock.json index e4d7ce096..8733be693 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7344,9 +7344,9 @@ "dev": true }, "lint-staged": { - "version": "10.0.7", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-10.0.7.tgz", - "integrity": "sha512-Byj0F4l7GYUpYYHEqyFH69NiI6ICTg0CeCKbhRorL+ickbzILKUlZLiyCkljZV02wnoh7yH7PmFyYm9PRNwk9g==", + "version": "10.0.8", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-10.0.8.tgz", + "integrity": "sha512-Oa9eS4DJqvQMVdywXfEor6F4vP+21fPHF8LUXgBbVWUSWBddjqsvO6Bv1LwMChmgQZZqwUvgJSHlu8HFHAPZmA==", "dev": true, "requires": { "chalk": "^3.0.0", diff --git a/package.json b/package.json index 80f59be06..8e7e2baec 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,17 @@ "pretty-quick": "pretty-quick --pattern \"**/*.*(html|js|json|vue)\"", "test": "start-server-and-test start http-get://localhost:3000 e2e" }, + "husky": { + "hooks": { + "pre-commit": "npm run pretty-quick" + } + }, + "prettier": { + "trailingComma": "es5", + "semi": false, + "singleQuote": false, + "printWidth": 100 + }, "dependencies": { "@nuxtjs/axios": "^5.9.5", "@nuxtjs/google-analytics": "^2.2.3", @@ -42,7 +53,7 @@ "devDependencies": { "cypress": "^4.0.2", "husky": "^4.2.3", - "lint-staged": "^10.0.7", + "lint-staged": "^10.0.8", "node-sass": "^4.13.1", "prettier": "^1.19.1", "pretty-quick": "^2.0.1", diff --git a/pages/graphql.vue b/pages/graphql.vue index ddf6353f5..e2b5f7c37 100644 --- a/pages/graphql.vue +++ b/pages/graphql.vue @@ -6,7 +6,13 @@
-
+
-
file_copy', downloadButton: 'get_app', doneButton: 'done', expandResponse: false, responseBodyMaxLines: 16, + + settings: { + SCROLL_INTO_ENABLED: + typeof this.$store.state.postwoman.settings.SCROLL_INTO_ENABLED !== "undefined" + ? this.$store.state.postwoman.settings.SCROLL_INTO_ENABLED + : true, + }, } }, @@ -373,6 +388,22 @@ export default { this.$store.commit("setGQLState", { value, attribute: "query" }) }, }, + response: { + get() { + return this.$store.state.gql.response + }, + set(value) { + this.$store.commit("setGQLState", { value, attribute: "response" }) + }, + }, + schema: { + get() { + return this.$store.state.gql.schema + }, + set(value) { + this.$store.commit("setGQLState", { value, attribute: "schema" }) + }, + }, variableString: { get() { return this.$store.state.gql.variablesJSONString @@ -400,7 +431,7 @@ export default { const rootTypeName = this.resolveRootType(type).name const target = document.getElementById(`type_${rootTypeName}`) - if (target && this.$store.state.postwoman.settings.SCROLL_INTO_ENABLED) { + if (target && this.settings.SCROLL_INTO_ENABLED) { target.scrollIntoView({ behavior: "smooth", }) @@ -414,7 +445,7 @@ export default { copySchema() { this.$refs.copySchemaCode.innerHTML = this.doneButton const aux = document.createElement("textarea") - aux.innerText = this.schemaString + aux.innerText = this.schema document.body.appendChild(aux) aux.select() document.execCommand("copy") @@ -440,7 +471,7 @@ export default { copyResponse() { this.$refs.copyResponseButton.innerHTML = this.doneButton const aux = document.createElement("textarea") - aux.innerText = this.responseString + aux.innerText = this.response document.body.appendChild(aux) aux.select() document.execCommand("copy") @@ -453,8 +484,12 @@ export default { async runQuery() { const startTime = Date.now() + // Start showing the loading bar as soon as possible. + // The nuxt axios module will hide it when the request is made. this.$nuxt.$loading.start() - this.$store.state.postwoman.settings.SCROLL_INTO_ENABLED && this.scrollInto("response") + + this.response = this.$t("loading") + if (this.settings.SCROLL_INTO_ENABLED) this.scrollInto("response") try { let headers = {} @@ -477,8 +512,7 @@ export default { } const data = await sendNetworkRequest(reqOptions, this.$store) - - this.responseString = JSON.stringify(data.data, null, 2) + this.response = JSON.stringify(data.data, null, 2) this.$nuxt.$loading.finish() const duration = Date.now() - startTime @@ -486,6 +520,7 @@ export default { icon: "done", }) } catch (error) { + this.response = `${error}. ${this.$t("check_console_details")}` this.$nuxt.$loading.finish() this.$toast.error(`${error} ${this.$t("f12_details")}`, { @@ -496,13 +531,14 @@ export default { }, async getSchema() { const startTime = Date.now() - this.schemaString = this.$t("loading") - this.$store.state.postwoman.settings.SCROLL_INTO_ENABLED && this.scrollInto("schema") // Start showing the loading bar as soon as possible. // The nuxt axios module will hide it when the request is made. this.$nuxt.$loading.start() + this.schema = this.$t("loading") + if (this.settings.SCROLL_INTO_ENABLED) this.scrollInto("schema") + try { const query = JSON.stringify({ query: gql.getIntrospectionQuery(), @@ -523,8 +559,6 @@ export default { data: query, } - // console.log(reqOptions); - const reqConfig = this.$store.state.postwoman.settings.PROXY_ENABLED ? { method: "post", @@ -537,9 +571,8 @@ export default { const res = await axios(reqConfig) const data = this.$store.state.postwoman.settings.PROXY_ENABLED ? res.data : res - const schema = gql.buildClientSchema(data.data.data) - this.schemaString = gql.printSchema(schema, { + this.schema = gql.printSchema(schema, { commentDescriptions: true, }) @@ -597,7 +630,8 @@ export default { }) } catch (error) { this.$nuxt.$loading.finish() - this.schemaString = `${error}. ${this.$t("check_console_details")}` + + this.schema = `${error}. ${this.$t("check_console_details")}` this.$toast.error(`${error} ${this.$t("f12_details")}`, { icon: "error", }) @@ -609,7 +643,7 @@ export default { this.responseBodyMaxLines = this.responseBodyMaxLines == Infinity ? 16 : Infinity }, downloadResponse() { - const dataToWrite = JSON.stringify(this.schemaString, null, 2) + const dataToWrite = JSON.stringify(this.schema, null, 2) const file = new Blob([dataToWrite], { type: "application/json" }) const a = document.createElement("a") const url = URL.createObjectURL(file) @@ -650,7 +684,6 @@ export default { }, }, }) - // console.log(oldHeaders); }, scrollInto(view) { this.$refs[view].$el.scrollIntoView({ diff --git a/pages/index.vue b/pages/index.vue index 9b4d00666..a037646f0 100644 --- a/pages/index.vue +++ b/pages/index.vue @@ -185,6 +185,7 @@ name="url" type="url" v-model="uri" + spellcheck="false" />
@@ -1424,6 +1425,13 @@ export default { files: [], filenames: "", navigatorShare: navigator.share, + + settings: { + SCROLL_INTO_ENABLED: + typeof this.$store.state.postwoman.settings.SCROLL_INTO_ENABLED !== "undefined" + ? this.$store.state.postwoman.settings.SCROLL_INTO_ENABLED + : true, + }, } }, watch: { @@ -1980,7 +1988,7 @@ export default { this.path = path this.showPreRequestScript = usesScripts this.preRequestScript = preRequestScript - this.$store.state.postwoman.settings.SCROLL_INTO_ENABLED && this.scrollInto("request") + if (this.settings.SCROLL_INTO_ENABLED) this.scrollInto("request") }, getVariablesFromPreRequestScript() { if (!this.preRequestScript) { @@ -2015,7 +2023,7 @@ export default { }, async sendRequest() { this.$toast.clear() - this.$store.state.postwoman.settings.SCROLL_INTO_ENABLED && this.scrollInto("response") + if (this.settings.SCROLL_INTO_ENABLED) this.scrollInto("response") if (!this.isValidURL) { this.$toast.error(this.$t("url_invalid_format"), { icon: "error", diff --git a/pages/realtime.vue b/pages/realtime.vue index f94c63dd9..473feaad3 100644 --- a/pages/realtime.vue +++ b/pages/realtime.vue @@ -11,6 +11,7 @@ section !== value)) + : theme.collapsedSections.push(value) + }, + addGQLHeader({ gql }, object) { gql.headers.push(object) }, diff --git a/store/state.js b/store/state.js index a9a5bec15..442896f4e 100644 --- a/store/state.js +++ b/store/state.js @@ -21,8 +21,13 @@ export default () => ({ gql: { url: "https://rickandmortyapi.com/graphql", headers: [], + schema: "", variablesJSONString: "{}", query: "", + response: "", + }, + theme: { + collapsedSections: [], }, oauth2: { tokens: [],