mirror of
https://github.com/tiennm99/DocsGPT.git
synced 2026-10-13 18:15:02 +00:00
(chore)react-widget: add linter
This commit is contained in:
1 parent
a3e6a5622d
commit
c4968a641e
14 files changed
+4691
-1067
No files matched your search
@@ -0,0 +1,72 @@
|
||||
import js from '@eslint/js'
|
||||
import tsParser from '@typescript-eslint/parser'
|
||||
import tsPlugin from '@typescript-eslint/eslint-plugin'
|
||||
import react from 'eslint-plugin-react'
|
||||
import unusedImports from 'eslint-plugin-unused-imports'
|
||||
import prettier from 'eslint-plugin-prettier'
|
||||
import globals from 'globals'
|
||||
|
||||
export default [
|
||||
{
|
||||
ignores: [
|
||||
'node_modules/',
|
||||
'dist/',
|
||||
'prettier.config.cjs',
|
||||
'custom.d.ts',
|
||||
'package-lock.json',
|
||||
'package.json',
|
||||
],
|
||||
},
|
||||
{
|
||||
files: ['**/*.{js,jsx,ts,tsx}'],
|
||||
languageOptions: {
|
||||
ecmaVersion: 'latest',
|
||||
sourceType: 'module',
|
||||
parser: tsParser,
|
||||
parserOptions: {
|
||||
ecmaFeatures: {
|
||||
jsx: true,
|
||||
},
|
||||
},
|
||||
globals: {
|
||||
...globals.browser,
|
||||
...globals.es2021,
|
||||
...globals.node,
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
'@typescript-eslint': tsPlugin,
|
||||
react,
|
||||
'unused-imports': unusedImports,
|
||||
prettier,
|
||||
},
|
||||
rules: {
|
||||
...js.configs.recommended.rules,
|
||||
...tsPlugin.configs.recommended.rules,
|
||||
...react.configs.recommended.rules,
|
||||
...prettier.configs.recommended.rules,
|
||||
'react/prop-types': 'off',
|
||||
'unused-imports/no-unused-imports': 'error',
|
||||
'react/react-in-jsx-scope': 'off',
|
||||
'no-undef': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'warn',
|
||||
'@typescript-eslint/no-unused-vars': [
|
||||
'warn',
|
||||
{ varsIgnorePattern: '^_', argsIgnorePattern: '^_' },
|
||||
],
|
||||
'@typescript-eslint/no-unused-expressions': 'warn',
|
||||
'prettier/prettier': [
|
||||
'error',
|
||||
{
|
||||
endOfLine: 'auto',
|
||||
},
|
||||
],
|
||||
},
|
||||
settings: {
|
||||
react: {
|
||||
version: 'detect',
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
+3317
-22
File diff suppressed because it is too large.
Load diff
@@ -35,7 +35,9 @@
|
||||
"serve": "parcel serve -p 3000",
|
||||
"dev": "parcel -p 3000",
|
||||
"test": "jest",
|
||||
"lint": "eslint",
|
||||
"lint": "eslint ./src --ext .jsx,.js,.ts,.tsx",
|
||||
"lint-fix": "eslint ./src --ext .jsx,.js,.ts,.tsx --fix",
|
||||
"format": "prettier ./src --write",
|
||||
"check": "tsc --noEmit",
|
||||
"ci": "yarn build && yarn test && yarn lint && yarn check"
|
||||
},
|
||||
@@ -60,14 +62,24 @@
|
||||
"@babel/core": "^7.24.0",
|
||||
"@babel/preset-env": "^7.24.0",
|
||||
"@babel/preset-react": "^7.23.3",
|
||||
"@eslint/js": "^9.39.4",
|
||||
"@parcel/packager-ts": "^2.16.4",
|
||||
"@parcel/transformer-typescript-types": "^2.16.4",
|
||||
"@types/dompurify": "^3.0.5",
|
||||
"@types/markdown-it": "^14.1.2",
|
||||
"@types/react": "^18.3.3",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.57.2",
|
||||
"@typescript-eslint/parser": "^8.57.2",
|
||||
"babel-loader": "^10.1.1",
|
||||
"eslint": "^9.39.4",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-prettier": "^5.5.5",
|
||||
"eslint-plugin-react": "^7.37.5",
|
||||
"eslint-plugin-unused-imports": "^4.4.1",
|
||||
"globals": "^15.15.0",
|
||||
"parcel": "^2.16.4",
|
||||
"prettier": "^3.8.1",
|
||||
"process": "^0.11.10",
|
||||
"svgo": "^3.3.3",
|
||||
"typescript": "^5.3.3"
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
module.exports = {
|
||||
trailingComma: 'all',
|
||||
tabWidth: 2,
|
||||
semi: true,
|
||||
singleQuote: true,
|
||||
printWidth: 80,
|
||||
};
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import React from "react"
|
||||
import {DocsGPTWidget} from "./components/DocsGPTWidget"
|
||||
import {SearchBar} from "./components/SearchBar"
|
||||
import React from 'react';
|
||||
import { DocsGPTWidget } from './components/DocsGPTWidget';
|
||||
import { SearchBar } from './components/SearchBar';
|
||||
export const App = () => {
|
||||
return (
|
||||
<div>
|
||||
<SearchBar/>
|
||||
<DocsGPTWidget/>
|
||||
<SearchBar />
|
||||
<DocsGPTWidget />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
@@ -1,10 +1,10 @@
|
||||
//exports browser ready methods
|
||||
|
||||
import { createRoot } from "react-dom/client";
|
||||
import { createRoot } from 'react-dom/client';
|
||||
|
||||
import { DocsGPTWidget } from './components/DocsGPTWidget';
|
||||
import { SearchBar } from './components/SearchBar';
|
||||
import React from "react";
|
||||
import React from 'react';
|
||||
if (typeof window !== 'undefined') {
|
||||
const renderWidget = (elementId: string, props = {}) => {
|
||||
const root = createRoot(document.getElementById(elementId) as HTMLElement);
|
||||
@@ -14,9 +14,11 @@ if (typeof window !== 'undefined') {
|
||||
const root = createRoot(document.getElementById(elementId) as HTMLElement);
|
||||
root.render(<SearchBar {...props} />);
|
||||
};
|
||||
(window as any).renderDocsGPTWidget = renderWidget;
|
||||
(window as unknown as Record<string, unknown>).renderDocsGPTWidget =
|
||||
renderWidget;
|
||||
|
||||
(window as any).renderSearchBar = renderSearchBar;
|
||||
(window as unknown as Record<string, unknown>).renderSearchBar =
|
||||
renderSearchBar;
|
||||
}
|
||||
|
||||
export { DocsGPTWidget, SearchBar };
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -1,3 +1,3 @@
|
||||
//exports methods for React
|
||||
export {SearchBar} from "./components/SearchBar"
|
||||
export { DocsGPTWidget } from "./components/DocsGPTWidget";
|
||||
export { SearchBar } from './components/SearchBar';
|
||||
export { DocsGPTWidget } from './components/DocsGPTWidget';
|
||||
@@ -1,8 +1,7 @@
|
||||
|
||||
//development
|
||||
import { createRoot } from "react-dom/client";
|
||||
import { App } from "./App";
|
||||
import React from "react";
|
||||
const container = document.getElementById("app") as HTMLElement;
|
||||
const root = createRoot(container)
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import { App } from './App';
|
||||
import React from 'react';
|
||||
const container = document.getElementById('app') as HTMLElement;
|
||||
const root = createRoot(container);
|
||||
root.render(<App />);
|
||||
@@ -1,20 +1,24 @@
|
||||
import { Result } from "@/types";
|
||||
|
||||
async function getSearchResults(question: string, apiKey: string, apiHost: string, signal: AbortSignal): Promise<Result[]> {
|
||||
import { Result } from '@/types';
|
||||
|
||||
async function getSearchResults(
|
||||
question: string,
|
||||
apiKey: string,
|
||||
apiHost: string,
|
||||
signal: AbortSignal,
|
||||
): Promise<Result[]> {
|
||||
const payload = {
|
||||
question,
|
||||
api_key: apiKey
|
||||
api_key: apiKey,
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await fetch(`${apiHost}/api/search`, {
|
||||
method: "POST",
|
||||
method: 'POST',
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(payload),
|
||||
signal: signal
|
||||
signal: signal,
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
@@ -23,15 +27,12 @@ async function getSearchResults(question: string, apiKey: string, apiHost: strin
|
||||
|
||||
const data: Result[] = await response.json();
|
||||
return data;
|
||||
|
||||
} catch (error) {
|
||||
if (!(error instanceof DOMException && error.name == "AbortError")) {
|
||||
console.error("Failed to fetch documents:", error);
|
||||
if (!(error instanceof DOMException && error.name == 'AbortError')) {
|
||||
console.error('Failed to fetch documents:', error);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
getSearchResults
|
||||
}
|
||||
export { getSearchResults };
|
||||
@@ -1,5 +1,3 @@
|
||||
import { FEEDBACK } from "@/types";
|
||||
|
||||
interface HistoryItem {
|
||||
prompt: string;
|
||||
response?: string;
|
||||
@@ -30,7 +28,9 @@ export function fetchAnswerStreaming({
|
||||
history = [],
|
||||
conversationId = null,
|
||||
apiHost = '',
|
||||
onEvent = () => { console.log("Event triggered, but no handler provided."); }
|
||||
onEvent = () => {
|
||||
console.log('Event triggered, but no handler provided.');
|
||||
},
|
||||
}: FetchAnswerStreamingProps): Promise<void> {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
const body = {
|
||||
@@ -38,7 +38,7 @@ export function fetchAnswerStreaming({
|
||||
history: JSON.stringify(history),
|
||||
conversation_id: conversationId,
|
||||
model: 'default',
|
||||
api_key: apiKey
|
||||
api_key: apiKey,
|
||||
};
|
||||
fetch(apiHost + '/stream', {
|
||||
method: 'POST',
|
||||
@@ -52,7 +52,7 @@ export function fetchAnswerStreaming({
|
||||
|
||||
const reader = response.body.getReader();
|
||||
const decoder = new TextDecoder('utf-8');
|
||||
let counter = 0;
|
||||
let counter = 0; // eslint-disable-line @typescript-eslint/no-unused-vars
|
||||
const processStream = ({
|
||||
done,
|
||||
value,
|
||||
@@ -95,12 +95,14 @@ export function fetchAnswerStreaming({
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export const sendFeedback = (payload: FeedbackPayload, apiHost: string): Promise<Response> => {
|
||||
export const sendFeedback = (
|
||||
payload: FeedbackPayload,
|
||||
apiHost: string,
|
||||
): Promise<Response> => {
|
||||
return fetch(`${apiHost}/api/feedback`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
question: payload.question,
|
||||
@@ -108,7 +110,7 @@ export const sendFeedback = (payload: FeedbackPayload, apiHost: string): Promis
|
||||
feedback: payload.feedback,
|
||||
api_key: payload.apikey,
|
||||
conversation_id: payload.conversation_id,
|
||||
question_index: payload.question_index
|
||||
question_index: payload.question_index,
|
||||
}),
|
||||
});
|
||||
};
|
||||
@@ -38,7 +38,7 @@ export interface Query {
|
||||
response?: string;
|
||||
feedback?: FEEDBACK;
|
||||
error?: string;
|
||||
sources?: { title: string; text: string, source:string }[];
|
||||
sources?: { title: string; text: string; source: string }[];
|
||||
conversationId?: string | null;
|
||||
title?: string | null;
|
||||
}
|
||||
@@ -51,30 +51,34 @@ export interface WidgetProps {
|
||||
description?: string;
|
||||
heroTitle?: string;
|
||||
heroDescription?: string;
|
||||
size?: 'small' | 'medium' | 'large' | {
|
||||
custom: {
|
||||
width: string;
|
||||
height: string;
|
||||
maxWidth?: string;
|
||||
maxHeight?: string;
|
||||
};
|
||||
};
|
||||
theme?:THEME,
|
||||
buttonIcon?:string;
|
||||
buttonText?:string;
|
||||
buttonBg?:string;
|
||||
collectFeedback?:boolean;
|
||||
size?:
|
||||
| 'small'
|
||||
| 'medium'
|
||||
| 'large'
|
||||
| {
|
||||
custom: {
|
||||
width: string;
|
||||
height: string;
|
||||
maxWidth?: string;
|
||||
maxHeight?: string;
|
||||
};
|
||||
};
|
||||
theme?: THEME;
|
||||
buttonIcon?: string;
|
||||
buttonText?: string;
|
||||
buttonBg?: string;
|
||||
collectFeedback?: boolean;
|
||||
showSources?: boolean;
|
||||
defaultOpen?: boolean;
|
||||
}
|
||||
export interface WidgetCoreProps extends WidgetProps {
|
||||
widgetRef?:React.RefObject<HTMLDivElement> | null;
|
||||
handleClose?:React.MouseEventHandler | undefined;
|
||||
isOpen:boolean;
|
||||
export interface WidgetCoreProps extends WidgetProps {
|
||||
widgetRef?: React.RefObject<HTMLDivElement> | null;
|
||||
handleClose?: React.MouseEventHandler | undefined;
|
||||
isOpen: boolean;
|
||||
prefilledQuery?: string;
|
||||
}
|
||||
|
||||
export interface SearchBarProps {
|
||||
export interface SearchBarProps {
|
||||
apiHost?: string;
|
||||
apiKey?: string;
|
||||
theme?: THEME;
|
||||
@@ -84,7 +88,7 @@ export interface SearchBarProps {
|
||||
}
|
||||
|
||||
export interface Result {
|
||||
text:string;
|
||||
title:string;
|
||||
source:string;
|
||||
text: string;
|
||||
title: string;
|
||||
source: string;
|
||||
}
|
||||
@@ -30,11 +30,15 @@ interface ParsedElement {
|
||||
tag: string;
|
||||
}
|
||||
|
||||
export const processMarkdownString = (markdown: string, keyword?: string): ParsedElement[] => {
|
||||
export const processMarkdownString = (
|
||||
markdown: string,
|
||||
keyword?: string,
|
||||
): ParsedElement[] => {
|
||||
const lines = markdown.trim().split('\n');
|
||||
const keywordLower = keyword?.toLowerCase();
|
||||
|
||||
const escapeRegExp = (str: string) => str.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
|
||||
const escapeRegExp = (str: string) =>
|
||||
str.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
|
||||
const escapedKeyword = keyword ? escapeRegExp(keyword) : '';
|
||||
const keywordRegex = keyword ? new RegExp(`(${escapedKeyword})`, 'gi') : null;
|
||||
|
||||
@@ -56,7 +60,7 @@ export const processMarkdownString = (markdown: string, keyword?: string): Parse
|
||||
const codeContent = codeBlockContent.join('\n');
|
||||
const parsedElement: ParsedElement = {
|
||||
content: codeContent,
|
||||
tag: 'code'
|
||||
tag: 'code',
|
||||
};
|
||||
|
||||
if (!firstLine) {
|
||||
@@ -64,7 +68,10 @@ export const processMarkdownString = (markdown: string, keyword?: string): Parse
|
||||
}
|
||||
|
||||
if (keywordLower && codeContent.toLowerCase().includes(keywordLower)) {
|
||||
parsedElement.content = parsedElement.content.replace(keywordRegex!, '<span class="highlight">$1</span>');
|
||||
parsedElement.content = parsedElement.content.replace(
|
||||
keywordRegex!,
|
||||
'<span class="highlight">$1</span>',
|
||||
);
|
||||
matchingLines.push(parsedElement);
|
||||
}
|
||||
}
|
||||
@@ -89,30 +96,30 @@ export const processMarkdownString = (markdown: string, keyword?: string): Parse
|
||||
content = headingMatch[2];
|
||||
parsedElement = {
|
||||
content: content,
|
||||
tag: 'heading'
|
||||
tag: 'heading',
|
||||
};
|
||||
} else if (bulletMatch) {
|
||||
content = bulletMatch[1];
|
||||
parsedElement = {
|
||||
content: content,
|
||||
tag: 'bulletList'
|
||||
tag: 'bulletList',
|
||||
};
|
||||
} else if (numberedMatch) {
|
||||
content = numberedMatch[1];
|
||||
parsedElement = {
|
||||
content: content,
|
||||
tag: 'numberedList'
|
||||
tag: 'numberedList',
|
||||
};
|
||||
} else if (blockquoteMatch) {
|
||||
content = blockquoteMatch[1];
|
||||
parsedElement = {
|
||||
content: content,
|
||||
tag: 'blockquote'
|
||||
tag: 'blockquote',
|
||||
};
|
||||
} else {
|
||||
parsedElement = {
|
||||
content: content,
|
||||
tag: 'text'
|
||||
tag: 'text',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -120,8 +127,14 @@ export const processMarkdownString = (markdown: string, keyword?: string): Parse
|
||||
firstLine = parsedElement;
|
||||
}
|
||||
|
||||
if (keywordLower && parsedElement.content.toLowerCase().includes(keywordLower)) {
|
||||
parsedElement.content = parsedElement.content.replace(keywordRegex!, '<span class="highlight">$1</span>');
|
||||
if (
|
||||
keywordLower &&
|
||||
parsedElement.content.toLowerCase().includes(keywordLower)
|
||||
) {
|
||||
parsedElement.content = parsedElement.content.replace(
|
||||
keywordRegex!,
|
||||
'<span class="highlight">$1</span>',
|
||||
);
|
||||
matchingLines.push(parsedElement);
|
||||
}
|
||||
}
|
||||
@@ -130,7 +143,7 @@ export const processMarkdownString = (markdown: string, keyword?: string): Parse
|
||||
const codeContent = codeBlockContent.join('\n');
|
||||
const parsedElement: ParsedElement = {
|
||||
content: codeContent,
|
||||
tag: 'code'
|
||||
tag: 'code',
|
||||
};
|
||||
|
||||
if (!firstLine) {
|
||||
@@ -138,7 +151,10 @@ export const processMarkdownString = (markdown: string, keyword?: string): Parse
|
||||
}
|
||||
|
||||
if (keywordLower && codeContent.toLowerCase().includes(keywordLower)) {
|
||||
parsedElement.content = parsedElement.content.replace(keywordRegex!, '<span class="highlight">$1</span>');
|
||||
parsedElement.content = parsedElement.content.replace(
|
||||
keywordRegex!,
|
||||
'<span class="highlight">$1</span>',
|
||||
);
|
||||
matchingLines.push(parsedElement);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user