From 0c60d190aff290a8adac9b02adb06166fc09182b Mon Sep 17 00:00:00 2001 From: Gregory Schier Date: Mon, 14 Jul 2025 14:52:16 -0700 Subject: [PATCH] Fix lint errors and show docs explorer on Cmd click --- package-lock.json | 133 ++++++++++++++++++ plugins/action-copy-curl/package.json | 2 +- plugins/action-copy-grpcurl/package.json | 2 +- plugins/auth-basic/package.json | 2 +- plugins/auth-basic/src/index.ts | 2 +- plugins/auth-bearer/package.json | 2 +- plugins/auth-bearer/src/index.ts | 2 +- plugins/auth-jwt/package.json | 2 +- plugins/auth-jwt/src/index.ts | 92 ++++++------ plugins/auth-oauth2/package.json | 2 +- plugins/auth-oauth2/src/store.ts | 2 +- plugins/filter-jsonpath/package.json | 2 +- plugins/filter-xpath/package.json | 2 +- plugins/importer-curl/package.json | 2 +- plugins/importer-insomnia/package.json | 2 +- plugins/importer-insomnia/src/common.ts | 4 +- plugins/importer-insomnia/src/index.ts | 10 +- plugins/importer-insomnia/src/v4.ts | 36 +++-- plugins/importer-insomnia/src/v5.ts | 44 +++--- plugins/importer-openapi/package.json | 2 +- plugins/importer-postman/package.json | 2 +- plugins/importer-yaak/package.json | 2 +- plugins/importer-yaak/src/index.ts | 8 +- plugins/template-function-cookie/package.json | 2 +- plugins/template-function-cookie/src/index.ts | 2 +- plugins/template-function-encode/package.json | 2 +- plugins/template-function-fs/package.json | 2 +- plugins/template-function-hash/package.json | 2 +- plugins/template-function-hash/src/index.ts | 2 +- plugins/template-function-json/package.json | 2 +- plugins/template-function-prompt/package.json | 2 +- plugins/template-function-regex/package.json | 2 +- .../template-function-request/package.json | 2 +- .../template-function-response/package.json | 2 +- plugins/template-function-uuid/package.json | 2 +- plugins/template-function-uuid/src/index.ts | 6 +- plugins/template-function-xml/package.json | 2 +- plugins/themes-yaak/package.json | 2 +- src-web/components/HttpRequestLayout.tsx | 9 +- src-web/components/HttpRequestPane.tsx | 2 +- src-web/components/core/Editor/extensions.ts | 26 +++- src-web/components/core/SplitLayout.tsx | 32 ++--- .../{ => graphql}/GraphQLDocsExplorer.tsx | 69 +++++---- .../{ => graphql}/GraphQLEditor.tsx | 26 ++-- .../graphql/graphqlAtoms.ts} | 2 +- .../graphql/useGraphQLDocsExplorer.ts | 63 +++++++++ src-web/lib/markdown.ts | 27 ++++ src-web/package.json | 4 +- 48 files changed, 454 insertions(+), 199 deletions(-) rename src-web/components/{ => graphql}/GraphQLDocsExplorer.tsx (94%) rename src-web/components/{ => graphql}/GraphQLEditor.tsx (92%) rename src-web/{atoms/graphqlSchemaAtom.ts => components/graphql/graphqlAtoms.ts} (58%) create mode 100644 src-web/components/graphql/useGraphQLDocsExplorer.ts create mode 100644 src-web/lib/markdown.ts diff --git a/package-lock.json b/package-lock.json index f66ee51b..5da8300b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7839,6 +7839,19 @@ "reusify": "^1.0.4" } }, + "node_modules/fault": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fault/-/fault-2.0.1.tgz", + "integrity": "sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ==", + "license": "MIT", + "dependencies": { + "format": "^0.2.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/fd-slicer": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", @@ -8030,6 +8043,14 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/format": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", + "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==", + "engines": { + "node": ">=0.4.x" + } + }, "node_modules/format-graphql": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/format-graphql/-/format-graphql-1.5.0.tgz", @@ -8987,6 +9008,29 @@ "node": ">= 0.4" } }, + "node_modules/hast-util-to-html": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.5.tgz", + "integrity": "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^3.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "stringify-entities": "^4.0.0", + "zwitch": "^2.0.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/hast-util-to-jsx-runtime": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", @@ -9074,6 +9118,16 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/http-reasons": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/http-reasons/-/http-reasons-0.1.0.tgz", @@ -10885,6 +10939,36 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/mdast-util-frontmatter": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-frontmatter/-/mdast-util-frontmatter-2.0.1.tgz", + "integrity": "sha512-LRqI9+wdgC25P0URIJY9vwocIzCcksduHQ9OF2joxQoyTNVduwLAFUzjoopuRJbJAReaKrNQKAZKL3uCMugWJA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "escape-string-regexp": "^5.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-extension-frontmatter": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-frontmatter/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/mdast-util-gfm": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", @@ -11259,6 +11343,22 @@ "micromark-util-types": "^2.0.0" } }, + "node_modules/micromark-extension-frontmatter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-frontmatter/-/micromark-extension-frontmatter-2.0.0.tgz", + "integrity": "sha512-C4AkuM3dA58cgZha7zVnuVxBhDsbttIMiytjgsM2XbHAB2faRVaHRle40558FBN+DJcrLNCoqG5mlrpdU4cRtg==", + "license": "MIT", + "dependencies": { + "fault": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/micromark-extension-gfm": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", @@ -14587,6 +14687,37 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/rehype-stringify": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/rehype-stringify/-/rehype-stringify-10.0.1.tgz", + "integrity": "sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-to-html": "^9.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-frontmatter": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/remark-frontmatter/-/remark-frontmatter-5.0.0.tgz", + "integrity": "sha512-XTFYvNASMe5iPN0719nPrdItC9aU0ssC4v14mH1BCi1u0n1gAocqcujWUrByftZTbLhRtiKRyjYTSIOcr69UVQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-frontmatter": "^2.0.0", + "micromark-extension-frontmatter": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/remark-gfm": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz", @@ -18626,6 +18757,8 @@ "react-markdown": "^10.1.0", "react-pdf": "^10.0.1", "react-use": "^17.6.0", + "rehype-stringify": "^10.0.1", + "remark-frontmatter": "^5.0.0", "remark-gfm": "^4.0.1", "slugify": "^1.6.6", "uuid": "^11.1.0", diff --git a/plugins/action-copy-curl/package.json b/plugins/action-copy-curl/package.json index 056f86b6..44c87c54 100644 --- a/plugins/action-copy-curl/package.json +++ b/plugins/action-copy-curl/package.json @@ -7,6 +7,6 @@ "scripts": { "build": "yaakcli build", "dev": "yaakcli dev", - "lint": "tsc --noEmit" + "lint": "eslint . --ext .ts,.tsx" } } diff --git a/plugins/action-copy-grpcurl/package.json b/plugins/action-copy-grpcurl/package.json index ee4a0747..6dd56b80 100644 --- a/plugins/action-copy-grpcurl/package.json +++ b/plugins/action-copy-grpcurl/package.json @@ -7,6 +7,6 @@ "scripts": { "build": "yaakcli build", "dev": "yaakcli dev", - "lint": "tsc --noEmit" + "lint": "eslint . --ext .ts,.tsx" } } diff --git a/plugins/auth-basic/package.json b/plugins/auth-basic/package.json index 45d8d81a..18ec32bf 100644 --- a/plugins/auth-basic/package.json +++ b/plugins/auth-basic/package.json @@ -7,6 +7,6 @@ "scripts": { "build": "yaakcli build", "dev": "yaakcli dev", - "lint": "tsc --noEmit" + "lint": "eslint . --ext .ts,.tsx" } } diff --git a/plugins/auth-basic/src/index.ts b/plugins/auth-basic/src/index.ts index 12f99a36..26712c07 100644 --- a/plugins/auth-basic/src/index.ts +++ b/plugins/auth-basic/src/index.ts @@ -1,4 +1,4 @@ -import { PluginDefinition } from '@yaakapp/api'; +import type { PluginDefinition } from '@yaakapp/api'; export const plugin: PluginDefinition = { authentication: { diff --git a/plugins/auth-bearer/package.json b/plugins/auth-bearer/package.json index 3c50a698..d0bd131b 100644 --- a/plugins/auth-bearer/package.json +++ b/plugins/auth-bearer/package.json @@ -7,6 +7,6 @@ "scripts": { "build": "yaakcli build", "dev": "yaakcli dev", - "lint": "tsc --noEmit" + "lint": "eslint . --ext .ts,.tsx" } } diff --git a/plugins/auth-bearer/src/index.ts b/plugins/auth-bearer/src/index.ts index 6c6ec6b4..b753d012 100644 --- a/plugins/auth-bearer/src/index.ts +++ b/plugins/auth-bearer/src/index.ts @@ -1,4 +1,4 @@ -import { PluginDefinition } from '@yaakapp/api'; +import type { PluginDefinition } from '@yaakapp/api'; export const plugin: PluginDefinition = { authentication: { diff --git a/plugins/auth-jwt/package.json b/plugins/auth-jwt/package.json index c3064374..584637d7 100644 --- a/plugins/auth-jwt/package.json +++ b/plugins/auth-jwt/package.json @@ -7,7 +7,7 @@ "scripts": { "build": "yaakcli build", "dev": "yaakcli dev", - "lint": "tsc --noEmit" + "lint": "eslint . --ext .ts,.tsx" }, "dependencies": { "jsonwebtoken": "^9.0.2" diff --git a/plugins/auth-jwt/src/index.ts b/plugins/auth-jwt/src/index.ts index 45b20a53..9c2dba22 100644 --- a/plugins/auth-jwt/src/index.ts +++ b/plugins/auth-jwt/src/index.ts @@ -1,4 +1,4 @@ -import { PluginDefinition } from '@yaakapp/api'; +import type { PluginDefinition } from '@yaakapp/api'; import jwt from 'jsonwebtoken'; const algorithms = [ @@ -20,49 +20,49 @@ const algorithms = [ const defaultAlgorithm = algorithms[0]; export const plugin: PluginDefinition = { - authentication: { - name: 'jwt', - label: 'JWT Bearer', - shortLabel: 'JWT', - args: [ - { - type: 'select', - name: 'algorithm', - label: 'Algorithm', - hideLabel: true, - defaultValue: defaultAlgorithm, - options: algorithms.map(value => ({ label: value === 'none' ? 'None' : value, value })), - }, - { - type: 'text', - name: 'secret', - label: 'Secret or Private Key', - password: true, - optional: true, - multiLine: true, - }, - { - type: 'checkbox', - name: 'secretBase64', - label: 'Secret is base64 encoded', - }, - { - type: 'editor', - name: 'payload', - label: 'Payload', - language: 'json', - defaultValue: '{\n "foo": "bar"\n}', - placeholder: '{ }', - }, - ], - async onApply(_ctx, { values }) { - const { algorithm, secret: _secret, secretBase64, payload } = values; - const secret = secretBase64 ? Buffer.from(`${_secret}`, 'base64') : `${_secret}`; - const token = jwt.sign(`${payload}`, secret, { algorithm: algorithm as any }); - const value = `Bearer ${token}`; - return { setHeaders: [{ name: 'Authorization', value }] }; - } - , + authentication: { + name: 'jwt', + label: 'JWT Bearer', + shortLabel: 'JWT', + args: [ + { + type: 'select', + name: 'algorithm', + label: 'Algorithm', + hideLabel: true, + defaultValue: defaultAlgorithm, + options: algorithms.map((value) => ({ label: value === 'none' ? 'None' : value, value })), + }, + { + type: 'text', + name: 'secret', + label: 'Secret or Private Key', + password: true, + optional: true, + multiLine: true, + }, + { + type: 'checkbox', + name: 'secretBase64', + label: 'Secret is base64 encoded', + }, + { + type: 'editor', + name: 'payload', + label: 'Payload', + language: 'json', + defaultValue: '{\n "foo": "bar"\n}', + placeholder: '{ }', + }, + ], + async onApply(_ctx, { values }) { + const { algorithm, secret: _secret, secretBase64, payload } = values; + const secret = secretBase64 ? Buffer.from(`${_secret}`, 'base64') : `${_secret}`; + const token = jwt.sign(`${payload}`, secret, { + algorithm: algorithm as (typeof algorithms)[number], + }); + const value = `Bearer ${token}`; + return { setHeaders: [{ name: 'Authorization', value }] }; }, - } -; + }, +}; diff --git a/plugins/auth-oauth2/package.json b/plugins/auth-oauth2/package.json index 36de36e6..336a11d6 100644 --- a/plugins/auth-oauth2/package.json +++ b/plugins/auth-oauth2/package.json @@ -7,6 +7,6 @@ "scripts": { "build": "yaakcli build", "dev": "yaakcli dev", - "lint": "tsc --noEmit" + "lint": "eslint . --ext .ts,.tsx" } } diff --git a/plugins/auth-oauth2/src/store.ts b/plugins/auth-oauth2/src/store.ts index f0d06837..a49edb1a 100644 --- a/plugins/auth-oauth2/src/store.ts +++ b/plugins/auth-oauth2/src/store.ts @@ -1,4 +1,4 @@ -import { Context } from '@yaakapp/api'; +import type { Context } from '@yaakapp/api'; export async function storeToken( ctx: Context, diff --git a/plugins/filter-jsonpath/package.json b/plugins/filter-jsonpath/package.json index f7cd8b9b..f7000124 100644 --- a/plugins/filter-jsonpath/package.json +++ b/plugins/filter-jsonpath/package.json @@ -7,7 +7,7 @@ "scripts": { "build": "yaakcli build", "dev": "yaakcli dev", - "lint": "tsc --noEmit" + "lint": "eslint . --ext .ts,.tsx" }, "dependencies": { "jsonpath-plus": "^10.3.0" diff --git a/plugins/filter-xpath/package.json b/plugins/filter-xpath/package.json index 12a93fff..d0366235 100644 --- a/plugins/filter-xpath/package.json +++ b/plugins/filter-xpath/package.json @@ -7,7 +7,7 @@ "scripts": { "build": "yaakcli build", "dev": "yaakcli dev", - "lint": "tsc --noEmit" + "lint": "eslint . --ext .ts,.tsx" }, "dependencies": { "@xmldom/xmldom": "^0.9.8", diff --git a/plugins/importer-curl/package.json b/plugins/importer-curl/package.json index 3f0fc162..0a126ac0 100644 --- a/plugins/importer-curl/package.json +++ b/plugins/importer-curl/package.json @@ -7,7 +7,7 @@ "scripts": { "build": "yaakcli build", "dev": "yaakcli dev", - "lint": "tsc --noEmit" + "lint": "eslint . --ext .ts,.tsx" }, "dependencies": { "shell-quote": "^1.8.1" diff --git a/plugins/importer-insomnia/package.json b/plugins/importer-insomnia/package.json index 91113d5c..1a328bfa 100644 --- a/plugins/importer-insomnia/package.json +++ b/plugins/importer-insomnia/package.json @@ -7,7 +7,7 @@ "scripts": { "build": "yaakcli build", "dev": "yaakcli dev", - "lint": "tsc --noEmit" + "lint": "eslint . --ext .ts,.tsx" }, "dependencies": { "yaml": "^2.4.2" diff --git a/plugins/importer-insomnia/src/common.ts b/plugins/importer-insomnia/src/common.ts index 253924f0..262a1d64 100644 --- a/plugins/importer-insomnia/src/common.ts +++ b/plugins/importer-insomnia/src/common.ts @@ -4,11 +4,11 @@ export function convertSyntax(variable: string): string { return variable.replaceAll(/{{\s*(_\.)?([^}]+)\s*}}/g, '${[$2]}'); } -export function isJSObject(obj: any) { +export function isJSObject(obj: unknown) { return Object.prototype.toString.call(obj) === '[object Object]'; } -export function isJSString(obj: any) { +export function isJSString(obj: unknown) { return Object.prototype.toString.call(obj) === '[object String]'; } diff --git a/plugins/importer-insomnia/src/index.ts b/plugins/importer-insomnia/src/index.ts index 4d95ac2b..d357faf7 100644 --- a/plugins/importer-insomnia/src/index.ts +++ b/plugins/importer-insomnia/src/index.ts @@ -1,4 +1,4 @@ -import { Context, PluginDefinition } from '@yaakapp/api'; +import type { Context, PluginDefinition } from '@yaakapp/api'; import YAML from 'yaml'; import { deleteUndefinedAttrs, isJSObject } from './common'; import { convertInsomniaV4 } from './v4'; @@ -15,16 +15,18 @@ export const plugin: PluginDefinition = { }; export function convertInsomnia(contents: string) { - let parsed: any; + let parsed: unknown; try { parsed = JSON.parse(contents); - } catch (e) { + } catch { + // Fall through } try { parsed = parsed ?? YAML.parse(contents); - } catch (e) { + } catch { + // Fall through } if (!isJSObject(parsed)) return null; diff --git a/plugins/importer-insomnia/src/v4.ts b/plugins/importer-insomnia/src/v4.ts index 8fcb6173..de2bd65d 100644 --- a/plugins/importer-insomnia/src/v4.ts +++ b/plugins/importer-insomnia/src/v4.ts @@ -1,7 +1,8 @@ -import { PartialImportResources } from '@yaakapp/api'; +/* eslint-disable @typescript-eslint/no-explicit-any */ +import type { PartialImportResources } from '@yaakapp/api'; import { convertId, convertSyntax, isJSObject } from './common'; -export function convertInsomniaV4(parsed: Record) { +export function convertInsomniaV4(parsed: any) { if (!Array.isArray(parsed.resources)) return null; const resources: PartialImportResources = { @@ -14,7 +15,9 @@ export function convertInsomniaV4(parsed: Record) { }; // Import workspaces - const workspacesToImport = parsed.resources.filter(r => isJSObject(r) && r._type === 'workspace'); + const workspacesToImport = parsed.resources.filter( + (r: any) => isJSObject(r) && r._type === 'workspace', + ); for (const w of workspacesToImport) { resources.workspaces.push({ id: convertId(w._id), @@ -40,13 +43,9 @@ export function convertInsomniaV4(parsed: Record) { resources.folders.push(importFolder(child, w._id)); nextFolder(child._id); } else if (child._type === 'request') { - resources.httpRequests.push( - importHttpRequest(child, w._id), - ); + resources.httpRequests.push(importHttpRequest(child, w._id)); } else if (child._type === 'grpc_request') { - resources.grpcRequests.push( - importGrpcRequest(child, w._id), - ); + resources.grpcRequests.push(importGrpcRequest(child, w._id)); } } }; @@ -64,10 +63,7 @@ export function convertInsomniaV4(parsed: Record) { return { resources }; } -function importHttpRequest( - r: any, - workspaceId: string, -): PartialImportResources['httpRequests'][0] { +function importHttpRequest(r: any, workspaceId: string): PartialImportResources['httpRequests'][0] { let bodyType: string | null = null; let body = {}; if (r.body.mimeType === 'application/octet-stream') { @@ -141,10 +137,7 @@ function importHttpRequest( }; } -function importGrpcRequest( - r: any, - workspaceId: string, -): PartialImportResources['grpcRequests'][0] { +function importGrpcRequest(r: any, workspaceId: string): PartialImportResources['grpcRequests'][0] { const parts = r.protoMethodName.split('/').filter((p: any) => p !== ''); const service = parts[0] ?? null; const method = parts[1] ?? null; @@ -186,13 +179,18 @@ function importFolder(f: any, workspaceId: string): PartialImportResources['fold }; } -function importEnvironment(e: any, workspaceId: string, isParent?: boolean): PartialImportResources['environments'][0] { +function importEnvironment( + e: any, + workspaceId: string, + isParent?: boolean, +): PartialImportResources['environments'][0] { return { id: convertId(e._id), createdAt: e.created ? new Date(e.created).toISOString().replace('Z', '') : undefined, updatedAt: e.modified ? new Date(e.modified).toISOString().replace('Z', '') : undefined, workspaceId: convertId(workspaceId), - // @ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error sortPriority: e.metaSortKey, // Will be added to Yaak later base: isParent ?? e.parentId === workspaceId, model: 'environment', diff --git a/plugins/importer-insomnia/src/v5.ts b/plugins/importer-insomnia/src/v5.ts index 523d5abe..feb63219 100644 --- a/plugins/importer-insomnia/src/v5.ts +++ b/plugins/importer-insomnia/src/v5.ts @@ -1,8 +1,16 @@ -import { PartialImportResources } from '@yaakapp/api'; +/* eslint-disable @typescript-eslint/no-explicit-any */ +import type { PartialImportResources } from '@yaakapp/api'; import { convertId, convertSyntax, isJSObject } from './common'; -export function convertInsomniaV5(parsed: Record) { - if (!Array.isArray(parsed.collection)) return null; +export function convertInsomniaV5(parsed: any) { + // Assert parsed is object + if (parsed == null || typeof parsed !== 'object') { + return null; + } + + if (!('collection' in parsed) || !Array.isArray(parsed.collection)) { + return null; + } const resources: PartialImportResources = { environments: [], @@ -14,7 +22,7 @@ export function convertInsomniaV5(parsed: Record) { }; // Import workspaces - const meta: Record = parsed.meta ?? {}; + const meta = ('meta' in parsed ? parsed.meta : {}) as Record; resources.workspaces.push({ id: convertId(meta.id ?? 'collection'), createdAt: meta.created ? new Date(meta.created).toISOString().replace('Z', '') : undefined, @@ -36,17 +44,11 @@ export function convertInsomniaV5(parsed: Record) { resources.folders.push(importFolder(child, meta.id, parentId)); nextFolder(child.children, child.meta.id); } else if (child.method) { - resources.httpRequests.push( - importHttpRequest(child, meta.id, parentId), - ); + resources.httpRequests.push(importHttpRequest(child, meta.id, parentId)); } else if (child.protoFileId) { - resources.grpcRequests.push( - importGrpcRequest(child, meta.id, parentId), - ); + resources.grpcRequests.push(importGrpcRequest(child, meta.id, parentId)); } else if (child.url) { - resources.websocketRequests.push( - importWebsocketRequest(child, meta.id, parentId), - ); + resources.websocketRequests.push(importWebsocketRequest(child, meta.id, parentId)); } } }; @@ -219,7 +221,11 @@ function importAuthentication(r: any) { return { authenticationType, authentication } as const; } -function importFolder(f: any, workspaceId: string, parentId: string): PartialImportResources['folders'][0] { +function importFolder( + f: any, + workspaceId: string, + parentId: string, +): PartialImportResources['folders'][0] { const id = f.meta?.id ?? f._id; const created = f.meta?.created ?? f.created; const updated = f.meta?.modified ?? f.updated; @@ -238,8 +244,11 @@ function importFolder(f: any, workspaceId: string, parentId: string): PartialImp }; } - -function importEnvironment(e: any, workspaceId: string, isParent?: boolean): PartialImportResources['environments'][0] { +function importEnvironment( + e: any, + workspaceId: string, + isParent?: boolean, +): PartialImportResources['environments'][0] { const id = e.meta?.id ?? e._id; const created = e.meta?.created ?? e.created; const updated = e.meta?.modified ?? e.updated; @@ -251,7 +260,8 @@ function importEnvironment(e: any, workspaceId: string, isParent?: boolean): Par updatedAt: updated ? new Date(updated).toISOString().replace('Z', '') : undefined, workspaceId: convertId(workspaceId), public: !e.isPrivate, - // @ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error sortPriority: sortKey, // Will be added to Yaak later base: isParent ?? e.parentId === workspaceId, model: 'environment', diff --git a/plugins/importer-openapi/package.json b/plugins/importer-openapi/package.json index 3d904481..906031f4 100644 --- a/plugins/importer-openapi/package.json +++ b/plugins/importer-openapi/package.json @@ -7,7 +7,7 @@ "scripts": { "build": "yaakcli build", "dev": "yaakcli dev", - "lint": "tsc --noEmit" + "lint": "eslint . --ext .ts,.tsx" }, "dependencies": { "openapi-to-postmanv2": "^5.0.0", diff --git a/plugins/importer-postman/package.json b/plugins/importer-postman/package.json index 7b88053b..e1f0c0e5 100644 --- a/plugins/importer-postman/package.json +++ b/plugins/importer-postman/package.json @@ -8,6 +8,6 @@ "scripts": { "build": "yaakcli build", "dev": "yaakcli dev", - "lint": "tsc --noEmit" + "lint": "eslint . --ext .ts,.tsx" } } diff --git a/plugins/importer-yaak/package.json b/plugins/importer-yaak/package.json index 1fc143ce..a894ca5b 100644 --- a/plugins/importer-yaak/package.json +++ b/plugins/importer-yaak/package.json @@ -7,6 +7,6 @@ "scripts": { "build": "yaakcli build", "dev": "yaakcli dev", - "lint": "tsc --noEmit" + "lint": "eslint . --ext .ts,.tsx" } } diff --git a/plugins/importer-yaak/src/index.ts b/plugins/importer-yaak/src/index.ts index 1a71cfbb..66b0333b 100644 --- a/plugins/importer-yaak/src/index.ts +++ b/plugins/importer-yaak/src/index.ts @@ -1,11 +1,11 @@ -import { Environment, PluginDefinition } from '@yaakapp/api'; +import type { Environment, PluginDefinition } from '@yaakapp/api'; export const plugin: PluginDefinition = { importer: { name: 'Yaak', description: 'Yaak official format', onImport(_ctx, args) { - return migrateImport(args.text) as any; + return migrateImport(args.text); }, }, }; @@ -14,7 +14,7 @@ export function migrateImport(contents: string) { let parsed; try { parsed = JSON.parse(contents); - } catch (err) { + } catch { return undefined; } @@ -69,6 +69,6 @@ export function migrateImport(contents: string) { return { resources: parsed.resources }; // Should already be in the correct format } -function isJSObject(obj: any) { +function isJSObject(obj: unknown) { return Object.prototype.toString.call(obj) === '[object Object]'; } diff --git a/plugins/template-function-cookie/package.json b/plugins/template-function-cookie/package.json index 516de06a..6b68c4ba 100644 --- a/plugins/template-function-cookie/package.json +++ b/plugins/template-function-cookie/package.json @@ -7,6 +7,6 @@ "scripts": { "build": "yaakcli build", "dev": "yaakcli dev", - "lint": "tsc --noEmit" + "lint": "eslint . --ext .ts,.tsx" } } diff --git a/plugins/template-function-cookie/src/index.ts b/plugins/template-function-cookie/src/index.ts index 3d39d74c..0415b533 100644 --- a/plugins/template-function-cookie/src/index.ts +++ b/plugins/template-function-cookie/src/index.ts @@ -1,4 +1,4 @@ -import { CallTemplateFunctionArgs, Context, PluginDefinition } from '@yaakapp/api'; +import type { CallTemplateFunctionArgs, Context, PluginDefinition } from '@yaakapp/api'; export const plugin: PluginDefinition = { templateFunctions: [ diff --git a/plugins/template-function-encode/package.json b/plugins/template-function-encode/package.json index a5fe5b5c..749a507c 100644 --- a/plugins/template-function-encode/package.json +++ b/plugins/template-function-encode/package.json @@ -7,6 +7,6 @@ "scripts": { "build": "yaakcli build", "dev": "yaakcli dev", - "lint": "tsc --noEmit" + "lint": "eslint . --ext .ts,.tsx" } } diff --git a/plugins/template-function-fs/package.json b/plugins/template-function-fs/package.json index 3201e120..cb1781c3 100644 --- a/plugins/template-function-fs/package.json +++ b/plugins/template-function-fs/package.json @@ -7,6 +7,6 @@ "scripts": { "build": "yaakcli build", "dev": "yaakcli dev", - "lint": "tsc --noEmit" + "lint": "eslint . --ext .ts,.tsx" } } diff --git a/plugins/template-function-hash/package.json b/plugins/template-function-hash/package.json index f63ad7af..fe7e00e7 100755 --- a/plugins/template-function-hash/package.json +++ b/plugins/template-function-hash/package.json @@ -7,6 +7,6 @@ "scripts": { "build": "yaakcli build", "dev": "yaakcli dev", - "lint": "tsc --noEmit" + "lint": "eslint . --ext .ts,.tsx" } } diff --git a/plugins/template-function-hash/src/index.ts b/plugins/template-function-hash/src/index.ts index 308cb0aa..8121cc7b 100755 --- a/plugins/template-function-hash/src/index.ts +++ b/plugins/template-function-hash/src/index.ts @@ -1,4 +1,4 @@ -import { CallTemplateFunctionArgs, Context, PluginDefinition } from '@yaakapp/api'; +import type { CallTemplateFunctionArgs, Context, PluginDefinition } from '@yaakapp/api'; import { createHash, createHmac } from 'node:crypto'; const algorithms = ['md5', 'sha1', 'sha256', 'sha512'] as const; diff --git a/plugins/template-function-json/package.json b/plugins/template-function-json/package.json index 3ff9d3fd..4ca9f9a0 100755 --- a/plugins/template-function-json/package.json +++ b/plugins/template-function-json/package.json @@ -7,7 +7,7 @@ "scripts": { "build": "yaakcli build", "dev": "yaakcli dev", - "lint": "tsc --noEmit" + "lint": "eslint . --ext .ts,.tsx" }, "dependencies": { "jsonpath-plus": "^10.3.0" diff --git a/plugins/template-function-prompt/package.json b/plugins/template-function-prompt/package.json index 16b0a30d..8f8a177a 100644 --- a/plugins/template-function-prompt/package.json +++ b/plugins/template-function-prompt/package.json @@ -7,6 +7,6 @@ "scripts": { "build": "yaakcli build", "dev": "yaakcli dev", - "lint": "tsc --noEmit" + "lint": "eslint . --ext .ts,.tsx" } } diff --git a/plugins/template-function-regex/package.json b/plugins/template-function-regex/package.json index 89f955d4..1050db21 100644 --- a/plugins/template-function-regex/package.json +++ b/plugins/template-function-regex/package.json @@ -7,6 +7,6 @@ "scripts": { "build": "yaakcli build", "dev": "yaakcli dev", - "lint": "tsc --noEmit" + "lint": "eslint . --ext .ts,.tsx" } } diff --git a/plugins/template-function-request/package.json b/plugins/template-function-request/package.json index a6d59e19..9bc71759 100755 --- a/plugins/template-function-request/package.json +++ b/plugins/template-function-request/package.json @@ -7,6 +7,6 @@ "scripts": { "build": "yaakcli build", "dev": "yaakcli dev", - "lint": "tsc --noEmit" + "lint": "eslint . --ext .ts,.tsx" } } diff --git a/plugins/template-function-response/package.json b/plugins/template-function-response/package.json index ff59f929..fa97b8a9 100644 --- a/plugins/template-function-response/package.json +++ b/plugins/template-function-response/package.json @@ -7,7 +7,7 @@ "scripts": { "build": "yaakcli build", "dev": "yaakcli dev", - "lint": "tsc --noEmit" + "lint": "eslint . --ext .ts,.tsx" }, "dependencies": { "jsonpath-plus": "^10.3.0", diff --git a/plugins/template-function-uuid/package.json b/plugins/template-function-uuid/package.json index db85ab40..24974675 100644 --- a/plugins/template-function-uuid/package.json +++ b/plugins/template-function-uuid/package.json @@ -7,7 +7,7 @@ "scripts": { "build": "yaakcli build", "dev": "yaakcli dev", - "lint": "tsc --noEmit" + "lint": "eslint . --ext .ts,.tsx" }, "dependencies": { "uuid": "^11.1.0" diff --git a/plugins/template-function-uuid/src/index.ts b/plugins/template-function-uuid/src/index.ts index 49bb4cb6..3d79f80b 100644 --- a/plugins/template-function-uuid/src/index.ts +++ b/plugins/template-function-uuid/src/index.ts @@ -7,7 +7,7 @@ export const plugin: PluginDefinition = { name: 'uuid.v1', description: 'Generate a UUID V1', args: [], - async onRender(_ctx: Context, _args: CallTemplateFunctionArgs): Promise { + async onRender(): Promise { return v1(); }, }, @@ -32,7 +32,7 @@ export const plugin: PluginDefinition = { name: 'uuid.v4', description: 'Generate a UUID V4', args: [], - async onRender(_ctx: Context, _args: CallTemplateFunctionArgs): Promise { + async onRender(): Promise { return v4(); }, }, @@ -68,7 +68,7 @@ export const plugin: PluginDefinition = { name: 'uuid.v7', description: 'Generate a UUID V7', args: [], - async onRender(_ctx: Context, _args: CallTemplateFunctionArgs): Promise { + async onRender(): Promise { return v7(); }, }, diff --git a/plugins/template-function-xml/package.json b/plugins/template-function-xml/package.json index 2f776eac..b077b669 100755 --- a/plugins/template-function-xml/package.json +++ b/plugins/template-function-xml/package.json @@ -7,7 +7,7 @@ "scripts": { "build": "yaakcli build", "dev": "yaakcli dev", - "lint": "tsc --noEmit" + "lint": "eslint . --ext .ts,.tsx" }, "dependencies": { "@xmldom/xmldom": "^0.9.8", diff --git a/plugins/themes-yaak/package.json b/plugins/themes-yaak/package.json index 632e667d..758df6cc 100644 --- a/plugins/themes-yaak/package.json +++ b/plugins/themes-yaak/package.json @@ -7,6 +7,6 @@ "scripts": { "build": "yaakcli build", "dev": "yaakcli dev", - "lint": "tsc --noEmit" + "lint": "eslint . --ext .ts,.tsx" } } diff --git a/src-web/components/HttpRequestLayout.tsx b/src-web/components/HttpRequestLayout.tsx index 5e28a9ab..bbbd172b 100644 --- a/src-web/components/HttpRequestLayout.tsx +++ b/src-web/components/HttpRequestLayout.tsx @@ -3,11 +3,11 @@ import classNames from 'classnames'; import { useAtomValue } from 'jotai'; import type { CSSProperties } from 'react'; import React from 'react'; -import { showGraphQLDocExplorerAtom } from '../atoms/graphqlSchemaAtom'; import { useCurrentGraphQLSchema } from '../hooks/useIntrospectGraphQL'; import type { SlotProps } from './core/SplitLayout'; import { SplitLayout } from './core/SplitLayout'; -import { GraphQLDocsExplorer } from './GraphQLDocsExplorer'; +import { GraphQLDocsExplorer } from './graphql/GraphQLDocsExplorer'; +import { showGraphQLDocExplorerAtom } from './graphql/graphqlAtoms'; import { HttpRequestPane } from './HttpRequestPane'; import { HttpResponsePane } from './HttpResponsePane'; @@ -17,7 +17,6 @@ interface Props { } export function HttpRequestLayout({ activeRequest, style }: Props) { - const { bodyType } = activeRequest; const showGraphQLDocExplorer = useAtomValue(showGraphQLDocExplorerAtom); const graphQLSchema = useCurrentGraphQLSchema(activeRequest); @@ -39,11 +38,11 @@ export function HttpRequestLayout({ activeRequest, style }: Props) { /> ); - if (bodyType === 'graphql' && showGraphQLDocExplorer && graphQLSchema != null) { + if (activeRequest.bodyType === 'graphql' && showGraphQLDocExplorer && graphQLSchema != null) { return ( ( { + if (!gqlCompletionItem.documentation) return null; + const innerHTML = await renderMarkdown(gqlCompletionItem.documentation); + const span = document.createElement('span'); + span.innerHTML = innerHTML; + return span; + }, + onShowInDocs(field, type, parentType) { + console.log("SHOW IN DOCS", field); + showInGraphQLDocsExplorer(field, type, parentType).catch(console.error); + }, + }), + extraExtensions, + ]; } const base_ = syntaxExtensions[language ?? 'text'] ?? text(); @@ -229,7 +246,6 @@ export const multiLineExtensions = ({ hideGutter }: { hideGutter?: boolean }) => } }, }), - EditorState.allowMultipleSelections.of(true), indentOnInput(), rectangularSelection(), crosshairCursor(), diff --git a/src-web/components/core/SplitLayout.tsx b/src-web/components/core/SplitLayout.tsx index fb7ee2ba..2efc355b 100644 --- a/src-web/components/core/SplitLayout.tsx +++ b/src-web/components/core/SplitLayout.tsx @@ -64,7 +64,7 @@ export function SplitLayout({ } const size = useContainerSize(containerRef); - const verticalBasedOnSize = size.width < STACK_VERTICAL_WIDTH; + const verticalBasedOnSize = size.width !== 0 && size.width < STACK_VERTICAL_WIDTH; const vertical = layout !== 'horizontal' && (layout === 'vertical' || verticalBasedOnSize); const styles = useMemo(() => { @@ -142,31 +142,25 @@ export function SplitLayout({ [width, height, vertical, minHeightPx, setHeight, minWidthPx, setWidth], ); - const containerQueryReady = size.width > 0 || size.height > 0; - return (
- {containerQueryReady && ( + {firstSlot({ style: areaL, orientation: vertical ? 'vertical' : 'horizontal' })} + {secondSlot && ( <> - {firstSlot({ style: areaL, orientation: vertical ? 'vertical' : 'horizontal' })} - {secondSlot && ( - <> - - {secondSlot({ style: areaR, orientation: vertical ? 'vertical' : 'horizontal' })} - - )} + + {secondSlot({ style: areaR, orientation: vertical ? 'vertical' : 'horizontal' })} )}
diff --git a/src-web/components/GraphQLDocsExplorer.tsx b/src-web/components/graphql/GraphQLDocsExplorer.tsx similarity index 94% rename from src-web/components/GraphQLDocsExplorer.tsx rename to src-web/components/graphql/GraphQLDocsExplorer.tsx index 90c56875..5504ef8b 100644 --- a/src-web/components/GraphQLDocsExplorer.tsx +++ b/src-web/components/graphql/GraphQLDocsExplorer.tsx @@ -23,17 +23,18 @@ import { } from 'graphql'; import type { CSSProperties, HTMLAttributes, KeyboardEvent, ReactNode } from 'react'; import { Fragment, memo, useCallback, useMemo, useRef, useState } from 'react'; -import { showGraphQLDocExplorerAtom } from '../atoms/graphqlSchemaAtom'; -import { useClickOutside } from '../hooks/useClickOutside'; -import { useContainerSize } from '../hooks/useContainerQuery'; -import { useDebouncedValue } from '../hooks/useDebouncedValue'; -import { useStateWithDeps } from '../hooks/useStateWithDeps'; -import { jotaiStore } from '../lib/jotai'; -import { CountBadge } from './core/CountBadge'; -import { Icon } from './core/Icon'; -import { IconButton } from './core/IconButton'; -import { PlainInput } from './core/PlainInput'; -import { Markdown } from './Markdown'; +import { useClickOutside } from '../../hooks/useClickOutside'; +import { useContainerSize } from '../../hooks/useContainerQuery'; +import { useDebouncedValue } from '../../hooks/useDebouncedValue'; +import { useStateWithDeps } from '../../hooks/useStateWithDeps'; +import { jotaiStore } from '../../lib/jotai'; +import { CountBadge } from '../core/CountBadge'; +import { Icon } from '../core/Icon'; +import { IconButton } from '../core/IconButton'; +import { PlainInput } from '../core/PlainInput'; +import { Markdown } from '../Markdown'; +import { showGraphQLDocExplorerAtom } from './graphqlAtoms'; +import { useGraphQLDocsExplorerEvent } from './useGraphQLDocsExplorer'; interface Props { style?: CSSProperties; @@ -58,6 +59,17 @@ export const GraphQLDocsExplorer = memo(function GraphQLDocsExplorer({ const mutType = schema.getMutationType(); const subType = schema.getSubscriptionType(); + useGraphQLDocsExplorerEvent('gql_docs_explorer.show_in_docs', ({ field }) => { + walkTypeGraph(schema, null, (t) => { + if (t.name === field) { + setActiveItem(toExplorerItem(t, null)); + return false; + } else { + return true; + } + }); + }); + const qryItem: ExplorerItem = qryType ? { kind: 'type', type: qryType, from: null } : null; const mutItem: ExplorerItem = mutType ? { kind: 'type', type: mutType, from: null } : null; const subItem: ExplorerItem = subType ? { kind: 'type', type: subType, from: null } : null; @@ -642,22 +654,20 @@ function GqlSchemaSearch({ const results = useMemo(() => { const results: SearchResult[] = []; - walkTypeGraph( - currentItem?.type ?? null, - (type, from, depth) => { - if (type === currentItem?.type) { - return null; // Remove the current type from results - } + walkTypeGraph(schema, currentItem?.type ?? null, (type, from, depth) => { + if (type === currentItem?.type) { + return true; // Skip the current type and continue + } - const match = fuzzyMatch(type.name, debouncedValue); - if (match == null) { - // Do nothing - } else { - results.push({ name: type.name, type, score: match.score, from, depth }); - } - }, - schema, - ); + const match = fuzzyMatch(type.name, debouncedValue); + if (match == null) { + // Do nothing + } else { + results.push({ name: type.name, type, score: match.score, from, depth }); + } + + return true; // Continue searching + }); results.sort((a, b) => { if (value == '') { if (a.name.startsWith('_') && !b.name.startsWith('_')) { @@ -831,13 +841,13 @@ function DocMarkdown({ children, className }: { children: string | null; classNa } function walkTypeGraph( + schema: GraphQLSchema, start: GraphQLType | GraphQLField | GraphQLInputField | null, cb: ( type: GraphQLNamedType | GraphQLField | GraphQLInputField, from: GraphQLNamedType | null, path: string[], - ) => void, - schema: GraphQLSchema, + ) => boolean, ) { const visited = new Set(); const queue: Array<{ @@ -867,7 +877,8 @@ function walkTypeGraph( if (visited.has(name)) continue; visited.add(name); - cb(current, from, path); + const cont = cb(current, from, path); + if (!cont) break; if (isObjectType(current) || isInterfaceType(current)) { for (const field of Object.values(current.getFields())) { diff --git a/src-web/components/GraphQLEditor.tsx b/src-web/components/graphql/GraphQLEditor.tsx similarity index 92% rename from src-web/components/GraphQLEditor.tsx rename to src-web/components/graphql/GraphQLEditor.tsx index 83e9a536..0e16128c 100644 --- a/src-web/components/GraphQLEditor.tsx +++ b/src-web/components/graphql/GraphQLEditor.tsx @@ -6,19 +6,19 @@ import { formatSdl } from 'format-graphql'; import { useAtom } from 'jotai'; import { useEffect, useMemo, useRef } from 'react'; import { useLocalStorage } from 'react-use'; -import { showGraphQLDocExplorerAtom } from '../atoms/graphqlSchemaAtom'; -import { useIntrospectGraphQL } from '../hooks/useIntrospectGraphQL'; -import { useStateWithDeps } from '../hooks/useStateWithDeps'; -import { showDialog } from '../lib/dialog'; -import { Banner } from './core/Banner'; -import { Button } from './core/Button'; -import type { DropdownItem } from './core/Dropdown'; -import { Dropdown } from './core/Dropdown'; -import type { EditorProps } from './core/Editor/Editor'; -import { Editor } from './core/Editor/Editor'; -import { FormattedError } from './core/FormattedError'; -import { Icon } from './core/Icon'; -import { Separator } from './core/Separator'; +import { useIntrospectGraphQL } from '../../hooks/useIntrospectGraphQL'; +import { useStateWithDeps } from '../../hooks/useStateWithDeps'; +import { showDialog } from '../../lib/dialog'; +import { Banner } from '../core/Banner'; +import { Button } from '../core/Button'; +import type { DropdownItem } from '../core/Dropdown'; +import { Dropdown } from '../core/Dropdown'; +import type { EditorProps } from '../core/Editor/Editor'; +import { Editor } from '../core/Editor/Editor'; +import { FormattedError } from '../core/FormattedError'; +import { Icon } from '../core/Icon'; +import { Separator } from '../core/Separator'; +import { showGraphQLDocExplorerAtom } from './graphqlAtoms'; type Props = Pick & { baseRequest: HttpRequest; diff --git a/src-web/atoms/graphqlSchemaAtom.ts b/src-web/components/graphql/graphqlAtoms.ts similarity index 58% rename from src-web/atoms/graphqlSchemaAtom.ts rename to src-web/components/graphql/graphqlAtoms.ts index acdae2d2..feadbe56 100644 --- a/src-web/atoms/graphqlSchemaAtom.ts +++ b/src-web/components/graphql/graphqlAtoms.ts @@ -1,3 +1,3 @@ -import { atomWithKVStorage } from '../lib/atoms/atomWithKVStorage'; +import { atomWithKVStorage } from '../../lib/atoms/atomWithKVStorage'; export const showGraphQLDocExplorerAtom = atomWithKVStorage('show_graphql_docs', false); diff --git a/src-web/components/graphql/useGraphQLDocsExplorer.ts b/src-web/components/graphql/useGraphQLDocsExplorer.ts new file mode 100644 index 00000000..f1e5117e --- /dev/null +++ b/src-web/components/graphql/useGraphQLDocsExplorer.ts @@ -0,0 +1,63 @@ +import EventEmitter from 'eventemitter3'; +import type { DependencyList } from 'react'; +import { useEffect } from 'react'; +import { jotaiStore } from '../../lib/jotai'; +import { sleep } from '../../lib/sleep'; +import { showGraphQLDocExplorerAtom } from './graphqlAtoms'; + +type EventDataMap = { + 'gql_docs_explorer.show_in_docs': { field?: string; type?: string; parentType?: string }; + 'gql_docs_explorer.focus_tab': undefined; +}; + +export function useGraphQLDocsExplorerEvent< + Event extends keyof EventDataMap, + Data extends EventDataMap[Event], +>(event: Event, fn: (data: Data) => void, deps?: DependencyList) { + useEffect(() => { + emitter.on(event, fn); + return () => { + emitter.off(event, fn); + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, deps); +} + +export async function showInGraphQLDocsExplorer( + field: string | undefined, + type: string | undefined, + parentType: string | undefined, +) { + const isVisible = jotaiStore.get(showGraphQLDocExplorerAtom); + if (!isVisible) { + // Show and give some time for the explorer to start listening for events + jotaiStore.set(showGraphQLDocExplorerAtom, true); + await sleep(100); + } + emitter.emit('gql_docs_explorer.show_in_docs', { field, type, parentType }); +} + +const emitter = new (class GraphQLDocsExplorerEventEmitter { + #emitter: EventEmitter = new EventEmitter(); + + emit( + event: Event, + data: Data, + ) { + this.#emitter.emit(event, data); + } + + on( + event: Event, + fn: (data: Data) => void, + ) { + this.#emitter.on(event, fn); + } + + off( + event: Event, + fn: (data: Data) => void, + ) { + this.#emitter.off(event, fn); + } +})(); diff --git a/src-web/lib/markdown.ts b/src-web/lib/markdown.ts new file mode 100644 index 00000000..0c7f531e --- /dev/null +++ b/src-web/lib/markdown.ts @@ -0,0 +1,27 @@ +import rehypeStringify from 'rehype-stringify'; +import remarkGfm from 'remark-gfm'; +import remarkParse from 'remark-parse'; +import remarkRehype from 'remark-rehype'; +import { unified } from 'unified'; + +const renderer = unified() + .use(remarkParse) + .use(remarkGfm) + .use(remarkRehype, { + // handlers: { + // link: (state, node, parent) => { + // return node; + // }, + // }, + }) + .use(rehypeStringify); + +export async function renderMarkdown(md: string): Promise { + try { + const r = await renderer.process(md); + return r.toString(); + } catch (err) { + console.log('FAILED TO RENDER MARKDOWN', err); + return 'error'; + } +} diff --git a/src-web/package.json b/src-web/package.json index f89ee486..06d9c530 100644 --- a/src-web/package.json +++ b/src-web/package.json @@ -6,7 +6,7 @@ "scripts": { "dev": "vite dev --force", "build": "vite build", - "lint": "tsc --noEmit && eslint . --ext .ts,.tsx" + "lint": "eslint . --ext .ts,.tsx" }, "dependencies": { "@codemirror/commands": "^6.8.1", @@ -61,6 +61,8 @@ "react-markdown": "^10.1.0", "react-pdf": "^10.0.1", "react-use": "^17.6.0", + "rehype-stringify": "^10.0.1", + "remark-frontmatter": "^5.0.0", "remark-gfm": "^4.0.1", "slugify": "^1.6.6", "uuid": "^11.1.0",