From 99d083d84a7d02843d00072b4ebecc0951cba3cd Mon Sep 17 00:00:00 2001 From: Louis Date: Mon, 22 Jan 2024 10:05:47 +0700 Subject: [PATCH] refactor: file prefix replace utils & add unit test (#1676) * refactor: file prefix replace utils * chore: add unit tests for core module --- Makefile | 1 + core/.gitignore | 3 - core/jest.config.js | 7 ++ core/package.json | 8 +- core/src/node/api/routes/download.ts | 82 +++++++------- core/src/node/index.ts | 1 + core/src/node/path.ts | 9 ++ core/tests/node/path.test.ts | 12 +++ core/tsconfig.json | 2 +- electron/handlers/download.ts | 100 ++++++++--------- electron/handlers/fileManager.ts | 7 +- electron/handlers/fs.ts | 10 +- package.json | 8 +- web/context/FeatureToggle.tsx | 11 +- web/hooks/useCreateNewThread.ts | 4 +- web/hooks/useDownloadModel.ts | 6 +- web/package.json | 2 +- web/screens/Settings/Advanced/index.tsx | 63 ++++++----- .../PreferenceExtensions/index.tsx | 101 ------------------ .../{ExtensionsCatalog => }/index.tsx | 94 ++++------------ web/screens/Settings/index.tsx | 59 +--------- 21 files changed, 204 insertions(+), 386 deletions(-) create mode 100644 core/jest.config.js create mode 100644 core/src/node/path.ts create mode 100644 core/tests/node/path.test.ts delete mode 100644 web/screens/Settings/CoreExtensions/PreferenceExtensions/index.tsx rename web/screens/Settings/CoreExtensions/{ExtensionsCatalog => }/index.tsx (57%) diff --git a/Makefile b/Makefile index 65e21897d..905a68321 100644 --- a/Makefile +++ b/Makefile @@ -39,6 +39,7 @@ lint: check-file-counts # Testing test: lint yarn build:test + yarn test:unit yarn test # Builds and publishes the app diff --git a/core/.gitignore b/core/.gitignore index d626d098e..2227931f3 100644 --- a/core/.gitignore +++ b/core/.gitignore @@ -6,7 +6,4 @@ coverage .vscode .idea dist -compiled -.awcache -.rpt2_cache docs diff --git a/core/jest.config.js b/core/jest.config.js new file mode 100644 index 000000000..fb03768fe --- /dev/null +++ b/core/jest.config.js @@ -0,0 +1,7 @@ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', + moduleNameMapper: { + '@/(.*)': '/src/$1', + }, +} \ No newline at end of file diff --git a/core/package.json b/core/package.json index 1244f0ce9..437e6d0a6 100644 --- a/core/package.json +++ b/core/package.json @@ -12,7 +12,8 @@ "module": "dist/core.es5.js", "typings": "dist/types/index.d.ts", "files": [ - "dist" + "dist", + "types" ], "author": "Jan ", "exports": { @@ -38,18 +39,23 @@ }, "scripts": { "lint": "tslint --project tsconfig.json -t codeFrame 'src/**/*.ts' 'test/**/*.ts'", + "test": "jest", "prebuild": "rimraf dist", "build": "tsc --module commonjs && rollup -c rollup.config.ts", "start": "rollup -c rollup.config.ts -w" }, "devDependencies": { + "jest": "^25.4.0", + "@types/jest": "^29.5.11", "@types/node": "^12.0.2", + "eslint-plugin-jest": "^23.8.2", "rollup": "^2.38.5", "rollup-plugin-commonjs": "^9.1.8", "rollup-plugin-json": "^3.1.0", "rollup-plugin-node-resolve": "^5.2.0", "rollup-plugin-sourcemaps": "^0.6.3", "rollup-plugin-typescript2": "^0.36.0", + "ts-jest": "^26.1.1", "tslib": "^2.6.2", "typescript": "^5.2.2" } diff --git a/core/src/node/api/routes/download.ts b/core/src/node/api/routes/download.ts index 99c990f76..f78a9acc9 100644 --- a/core/src/node/api/routes/download.ts +++ b/core/src/node/api/routes/download.ts @@ -1,58 +1,58 @@ -import { DownloadRoute } from '../../../api' -import { join } from 'path' -import { userSpacePath } from '../../extension/manager' -import { DownloadManager } from '../../download' -import { HttpServer } from '../HttpServer' -import { createWriteStream } from 'fs' +import { DownloadRoute } from "../../../api"; +import { join } from "path"; +import { userSpacePath } from "../../extension/manager"; +import { DownloadManager } from "../../download"; +import { HttpServer } from "../HttpServer"; +import { createWriteStream } from "fs"; +import { normalizeFilePath } from "../../path"; export const downloadRouter = async (app: HttpServer) => { app.post(`/${DownloadRoute.downloadFile}`, async (req, res) => { - const strictSSL = !(req.query.ignoreSSL === 'true'); - const proxy = req.query.proxy?.startsWith('http') ? req.query.proxy : undefined; - const body = JSON.parse(req.body as any) + const strictSSL = !(req.query.ignoreSSL === "true"); + const proxy = req.query.proxy?.startsWith("http") ? req.query.proxy : undefined; + const body = JSON.parse(req.body as any); const normalizedArgs = body.map((arg: any) => { - if (typeof arg === 'string' && arg.includes('file:/')) { - return join(userSpacePath, arg.replace('file:/', '')) + if (typeof arg === "string") { + return join(userSpacePath, normalizeFilePath(arg)); } - return arg - }) + return arg; + }); - const localPath = normalizedArgs[1] - const fileName = localPath.split('/').pop() ?? '' + const localPath = normalizedArgs[1]; + const fileName = localPath.split("/").pop() ?? ""; - const request = require('request') - const progress = require('request-progress') - - const rq = request({ url: normalizedArgs[0], strictSSL, proxy }) + const request = require("request"); + const progress = require("request-progress"); + + const rq = request({ url: normalizedArgs[0], strictSSL, proxy }); progress(rq, {}) - .on('progress', function (state: any) { - console.log('download onProgress', state) + .on("progress", function (state: any) { + console.log("download onProgress", state); }) - .on('error', function (err: Error) { - console.log('download onError', err) + .on("error", function (err: Error) { + console.log("download onError", err); }) - .on('end', function () { - console.log('download onEnd') + .on("end", function () { + console.log("download onEnd"); }) - .pipe(createWriteStream(normalizedArgs[1])) + .pipe(createWriteStream(normalizedArgs[1])); - DownloadManager.instance.setRequest(fileName, rq) - }) + DownloadManager.instance.setRequest(fileName, rq); + }); app.post(`/${DownloadRoute.abortDownload}`, async (req, res) => { - const body = JSON.parse(req.body as any) + const body = JSON.parse(req.body as any); const normalizedArgs = body.map((arg: any) => { - if (typeof arg === 'string' && arg.includes('file:/')) { - return join(userSpacePath, arg.replace('file:/', '')) + if (typeof arg === "string") { + return join(userSpacePath, normalizeFilePath(arg)); } - return arg - }) + return arg; + }); - const localPath = normalizedArgs[0] - const fileName = localPath.split('/').pop() ?? '' - console.debug('fileName', fileName) - const rq = DownloadManager.instance.networkRequests[fileName] - DownloadManager.instance.networkRequests[fileName] = undefined - rq?.abort() - }) -} + const localPath = normalizedArgs[0]; + const fileName = localPath.split("/").pop() ?? ""; + const rq = DownloadManager.instance.networkRequests[fileName]; + DownloadManager.instance.networkRequests[fileName] = undefined; + rq?.abort(); + }); +}; diff --git a/core/src/node/index.ts b/core/src/node/index.ts index 50651d1fd..ff50fa0fc 100644 --- a/core/src/node/index.ts +++ b/core/src/node/index.ts @@ -6,3 +6,4 @@ export * from './download' export * from './module' export * from './api' export * from './log' +export * from './path' diff --git a/core/src/node/path.ts b/core/src/node/path.ts new file mode 100644 index 000000000..adbc38c6c --- /dev/null +++ b/core/src/node/path.ts @@ -0,0 +1,9 @@ +/** + * Normalize file path + * Remove all file protocol prefix + * @param path + * @returns + */ +export function normalizeFilePath(path: string): string { + return path.replace(/^(file:[\\/]+)([^:\s]+)$/, "$2"); +} diff --git a/core/tests/node/path.test.ts b/core/tests/node/path.test.ts new file mode 100644 index 000000000..9f8a557bb --- /dev/null +++ b/core/tests/node/path.test.ts @@ -0,0 +1,12 @@ +import { normalizeFilePath } from "../../src/node/path"; + +describe("Test file normalize", () => { + test("returns no file protocol prefix on Unix", async () => { + expect(normalizeFilePath("file://test.txt")).toBe("test.txt"); + expect(normalizeFilePath("file:/test.txt")).toBe("test.txt"); + }); + test("returns no file protocol prefix on Windows", async () => { + expect(normalizeFilePath("file:\\\\test.txt")).toBe("test.txt"); + expect(normalizeFilePath("file:\\test.txt")).toBe("test.txt"); + }); +}); diff --git a/core/tsconfig.json b/core/tsconfig.json index 81991f46a..b112079d2 100644 --- a/core/tsconfig.json +++ b/core/tsconfig.json @@ -13,7 +13,7 @@ "declarationDir": "dist/types", "outDir": "dist/lib", "importHelpers": true, - "typeRoots": ["node_modules/@types"] + "types": ["@types/jest"] }, "include": ["src"] } diff --git a/electron/handlers/download.ts b/electron/handlers/download.ts index 832c46892..4174593ad 100644 --- a/electron/handlers/download.ts +++ b/electron/handlers/download.ts @@ -5,7 +5,7 @@ import request from 'request' import { createWriteStream, renameSync } from 'fs' import { DownloadEvent, DownloadRoute } from '@janhq/core' const progress = require('request-progress') -import { DownloadManager } from '@janhq/core/node' +import { DownloadManager, normalizeFilePath } from '@janhq/core/node' export function handleDownloaderIPCs() { /** @@ -54,66 +54,68 @@ export function handleDownloaderIPCs() { * @param url - The URL to download the file from. * @param fileName - The name to give the downloaded file. */ - ipcMain.handle(DownloadRoute.downloadFile, async (_event, url, fileName, network) => { - const strictSSL = !network?.ignoreSSL; - const proxy = network?.proxy?.startsWith('http') ? network.proxy : undefined; - const userDataPath = join(app.getPath('home'), 'jan') - if ( - typeof fileName === 'string' && - (fileName.includes('file:/') || fileName.includes('file:\\')) - ) { - fileName = fileName.replace('file:/', '').replace('file:\\', '') - } - const destination = resolve(userDataPath, fileName) - const rq = request({ url, strictSSL, proxy }) + ipcMain.handle( + DownloadRoute.downloadFile, + async (_event, url, fileName, network) => { + const strictSSL = !network?.ignoreSSL + const proxy = network?.proxy?.startsWith('http') + ? network.proxy + : undefined + const userDataPath = join(app.getPath('home'), 'jan') + if (typeof fileName === 'string') { + fileName = normalizeFilePath(fileName) + } + const destination = resolve(userDataPath, fileName) + const rq = request({ url, strictSSL, proxy }) - // Put request to download manager instance - DownloadManager.instance.setRequest(fileName, rq) + // Put request to download manager instance + DownloadManager.instance.setRequest(fileName, rq) - // Downloading file to a temp file first - const downloadingTempFile = `${destination}.download` - - progress(rq, {}) - .on('progress', function (state: any) { - WindowManager?.instance.currentWindow?.webContents.send( - DownloadEvent.onFileDownloadUpdate, - { - ...state, - fileName, - } - ) - }) - .on('error', function (err: Error) { - WindowManager?.instance.currentWindow?.webContents.send( - DownloadEvent.onFileDownloadError, - { - fileName, - err, - } - ) - }) - .on('end', function () { - if (DownloadManager.instance.networkRequests[fileName]) { - // Finished downloading, rename temp file to actual file - renameSync(downloadingTempFile, destination) + // Downloading file to a temp file first + const downloadingTempFile = `${destination}.download` + progress(rq, {}) + .on('progress', function (state: any) { WindowManager?.instance.currentWindow?.webContents.send( - DownloadEvent.onFileDownloadSuccess, + DownloadEvent.onFileDownloadUpdate, { + ...state, fileName, } ) - DownloadManager.instance.setRequest(fileName, undefined) - } else { + }) + .on('error', function (err: Error) { WindowManager?.instance.currentWindow?.webContents.send( DownloadEvent.onFileDownloadError, { fileName, - err: { message: 'aborted' }, + err, } ) - } - }) - .pipe(createWriteStream(downloadingTempFile)) - }) + }) + .on('end', function () { + if (DownloadManager.instance.networkRequests[fileName]) { + // Finished downloading, rename temp file to actual file + renameSync(downloadingTempFile, destination) + + WindowManager?.instance.currentWindow?.webContents.send( + DownloadEvent.onFileDownloadSuccess, + { + fileName, + } + ) + DownloadManager.instance.setRequest(fileName, undefined) + } else { + WindowManager?.instance.currentWindow?.webContents.send( + DownloadEvent.onFileDownloadError, + { + fileName, + err: { message: 'aborted' }, + } + ) + } + }) + .pipe(createWriteStream(downloadingTempFile)) + } + ) } diff --git a/electron/handlers/fileManager.ts b/electron/handlers/fileManager.ts index bfbd9af45..01043dd26 100644 --- a/electron/handlers/fileManager.ts +++ b/electron/handlers/fileManager.ts @@ -7,6 +7,7 @@ import { userSpacePath, getResourcePath } from './../utils/path' import fs from 'fs' import { join } from 'path' import { FileStat } from '@janhq/core' +import { normalizeFilePath } from '@janhq/core/node' /** * Handles file system extensions operations. @@ -42,11 +43,7 @@ export function handleFileMangerIPCs() { ipcMain.handle( FileManagerRoute.fileStat, async (_event, path: string): Promise => { - const normalizedPath = path - .replace(`file://`, '') - .replace(`file:/`, '') - .replace(`file:\\\\`, '') - .replace(`file:\\`, '') + const normalizedPath = normalizeFilePath(path) const fullPath = join(userSpacePath, normalizedPath) const isExist = fs.existsSync(fullPath) diff --git a/electron/handlers/fs.ts b/electron/handlers/fs.ts index 8f7e434cc..2da81c381 100644 --- a/electron/handlers/fs.ts +++ b/electron/handlers/fs.ts @@ -3,6 +3,7 @@ import { ipcMain } from 'electron' import { FileSystemRoute } from '@janhq/core' import { userSpacePath } from '../utils/path' import { join } from 'path' +import { normalizeFilePath } from '@janhq/core/node' /** * Handles file system operations. */ @@ -15,14 +16,7 @@ export function handleFsIPCs() { ...args.map((arg) => typeof arg === 'string' && (arg.includes(`file:/`) || arg.includes(`file:\\`)) - ? join( - userSpacePath, - arg - .replace(`file://`, '') - .replace(`file:/`, '') - .replace(`file:\\\\`, '') - .replace(`file:\\`, '') - ) + ? join(userSpacePath, normalizeFilePath(arg)) : arg ) ) diff --git a/package.json b/package.json index 955bbbd5c..4b8bc4af0 100644 --- a/package.json +++ b/package.json @@ -11,19 +11,15 @@ ], "nohoist": [ "uikit", - "uikit/*", "core", - "core/*", "electron", - "electron/**", "web", - "web/**", - "server", - "server/**" + "server" ] }, "scripts": { "lint": "yarn workspace jan lint && yarn workspace jan-web lint", + "test:unit": "yarn workspace @janhq/core test", "test": "yarn workspace jan test:e2e", "copy:assets": "cpx \"models/**\" \"electron/models/\" && cpx \"docs/openapi/**\" \"electron/docs/openapi\"", "dev:electron": "yarn copy:assets && yarn workspace jan dev", diff --git a/web/context/FeatureToggle.tsx b/web/context/FeatureToggle.tsx index 54dd6a943..6444359b0 100644 --- a/web/context/FeatureToggle.tsx +++ b/web/context/FeatureToggle.tsx @@ -29,7 +29,8 @@ export default function FeatureToggleWrapper({ const EXPERIMENTAL_FEATURE = 'experimentalFeature' const IGNORE_SSL = 'ignoreSSLFeature' const HTTPS_PROXY_FEATURE = 'httpsProxyFeature' - const [experimentalFeature, directSetExperimentalFeature] = useState(false) + const [experimentalFeature, directSetExperimentalFeature] = + useState(false) const [ignoreSSL, directSetIgnoreSSL] = useState(false) const [proxy, directSetProxy] = useState('') @@ -37,12 +38,8 @@ export default function FeatureToggleWrapper({ directSetExperimentalFeature( localStorage.getItem(EXPERIMENTAL_FEATURE) === 'true' ) - directSetIgnoreSSL( - localStorage.getItem(IGNORE_SSL) === 'true' - ) - directSetProxy( - localStorage.getItem(HTTPS_PROXY_FEATURE) ?? "" - ) + directSetIgnoreSSL(localStorage.getItem(IGNORE_SSL) === 'true') + directSetProxy(localStorage.getItem(HTTPS_PROXY_FEATURE) ?? '') }, []) const setExperimentalFeature = (on: boolean) => { diff --git a/web/hooks/useCreateNewThread.ts b/web/hooks/useCreateNewThread.ts index 81114333a..08b7a7430 100644 --- a/web/hooks/useCreateNewThread.ts +++ b/web/hooks/useCreateNewThread.ts @@ -104,8 +104,8 @@ export const useCreateNewThread = () => { } extensionManager - .get(ExtensionType.Conversational) - ?.saveThread(thread) + .get(ExtensionType.Conversational) + ?.saveThread(thread) } return { diff --git a/web/hooks/useDownloadModel.ts b/web/hooks/useDownloadModel.ts index ee32ff606..14051fa63 100644 --- a/web/hooks/useDownloadModel.ts +++ b/web/hooks/useDownloadModel.ts @@ -1,3 +1,5 @@ +import { useContext } from 'react' + import { Model, ExtensionType, @@ -8,14 +10,14 @@ import { import { useSetAtom } from 'jotai' +import { FeatureToggleContext } from '@/context/FeatureToggle' + import { modelBinFileName } from '@/utils/model' import { useDownloadState } from './useDownloadState' import { extensionManager } from '@/extension/ExtensionManager' import { addNewDownloadingModelAtom } from '@/helpers/atoms/Model.atom' -import { useContext } from 'react' -import { FeatureToggleContext } from '@/context/FeatureToggle' export default function useDownloadModel() { const { ignoreSSL, proxy } = useContext(FeatureToggleContext) diff --git a/web/package.json b/web/package.json index 1300cbf6b..bba3dd48b 100644 --- a/web/package.json +++ b/web/package.json @@ -7,7 +7,7 @@ "dev": "next dev", "build": "next build", "start": "next start", - "lint": "next lint", + "lint": "eslint .", "format": "prettier --write \"**/*.{js,jsx,ts,tsx}\"", "compile": "tsc --noEmit -p . --pretty" }, diff --git a/web/screens/Settings/Advanced/index.tsx b/web/screens/Settings/Advanced/index.tsx index f07d34d6d..0782614d5 100644 --- a/web/screens/Settings/Advanced/index.tsx +++ b/web/screens/Settings/Advanced/index.tsx @@ -1,19 +1,16 @@ /* eslint-disable react-hooks/exhaustive-deps */ 'use client' -import { useContext, useEffect, useState, useCallback, ChangeEvent } from 'react' +import { + useContext, + useEffect, + useState, + useCallback, + ChangeEvent, +} from 'react' import { fs } from '@janhq/core' -import { - Switch, - Button, - Input, - Modal, - ModalContent, - ModalHeader, - ModalTitle, - ModalTrigger, -} from '@janhq/uikit' +import { Switch, Button, Input } from '@janhq/uikit' import ShortcutModal from '@/containers/ShortcutModal' @@ -24,22 +21,30 @@ import { FeatureToggleContext } from '@/context/FeatureToggle' import { useSettings } from '@/hooks/useSettings' const Advanced = () => { - const { experimentalFeature, setExperimentalFeature, ignoreSSL, setIgnoreSSL, proxy, setProxy } = - useContext(FeatureToggleContext) + const { + experimentalFeature, + setExperimentalFeature, + ignoreSSL, + setIgnoreSSL, + proxy, + setProxy, + } = useContext(FeatureToggleContext) const [partialProxy, setPartialProxy] = useState(proxy) const [gpuEnabled, setGpuEnabled] = useState(false) const { readSettings, saveSettings, validateSettings, setShowNotification } = useSettings() - const onProxyChange = useCallback((event: ChangeEvent) => { - const value = event.target.value || '' - setPartialProxy(value) - if (value.trim().startsWith('http')) { - setProxy(value.trim()) - } - else { - setProxy('') - } - }, [setPartialProxy, setProxy]) + const onProxyChange = useCallback( + (event: ChangeEvent) => { + const value = event.target.value || '' + setPartialProxy(value) + if (value.trim().startsWith('http')) { + setProxy(value.trim()) + } else { + setProxy('') + } + }, + [setPartialProxy, setProxy] + ) useEffect(() => { readSettings().then((settings) => { @@ -115,15 +120,14 @@ const Advanced = () => {
-
- HTTPS Proxy -
+
HTTPS Proxy

- Specify the HTTPS proxy or leave blank (proxy auto-configuration and SOCKS not supported). + Specify the HTTPS proxy or leave blank (proxy auto-configuration and + SOCKS not supported).

:@:"} + placeholder={'http://:@:'} value={partialProxy} onChange={onProxyChange} /> @@ -138,7 +142,8 @@ const Advanced = () => {

- Allow self-signed or unverified certificates - may be required for certain proxies. + Allow self-signed or unverified certificates - may be required for + certain proxies.

{ - const { extensionName, preferenceValues, preferenceItems } = props - - const FormSchema = z.record( - z - .string({ required_error: 'Field is Required' }) - .min(1, { message: 'Field is Required' }) - ) - - const form = useForm>({ - resolver: zodResolver(FormSchema), - defaultValues: preferenceValues.reduce( - (obj: any, item: { key: any; value: any }) => - Object.assign(obj, { [item.key]: item.value }), - {} - ), - }) - - const onSubmit = async (values: z.infer) => { - for (const [key, value] of Object.entries(values)) { - // await preferences.set(extensionName, key, value) - // await execute(ExtensionService.OnPreferencesUpdate, {}) - } - toaster({ - title: formatExtensionsName(extensionName), - description: 'Successfully updated preferences', - }) - } - - return ( -
-
- {formatExtensionsName(extensionName)} -
-
- - {preferenceItems - .filter((x: any) => x.extensionName === extensionName) - ?.map((e: any) => ( - ( - - {e.preferenceName} - - {e.preferenceDescription} - - - - - - - )} - /> - ))} -
- -
- - -
- ) -} - -export default PreferenceExtensions diff --git a/web/screens/Settings/CoreExtensions/ExtensionsCatalog/index.tsx b/web/screens/Settings/CoreExtensions/index.tsx similarity index 57% rename from web/screens/Settings/CoreExtensions/ExtensionsCatalog/index.tsx rename to web/screens/Settings/CoreExtensions/index.tsx index 85d5ab5e8..81772c3ce 100644 --- a/web/screens/Settings/CoreExtensions/ExtensionsCatalog/index.tsx +++ b/web/screens/Settings/CoreExtensions/index.tsx @@ -1,38 +1,17 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -/* eslint-disable @typescript-eslint/ban-ts-comment */ -import React, { useState, useEffect, useRef, useContext } from 'react' +import React, { useState, useEffect, useRef } from 'react' import { Button } from '@janhq/uikit' -import { FeatureToggleContext } from '@/context/FeatureToggle' - import { formatExtensionsName } from '@/utils/converter' import { extensionManager } from '@/extension' +import Extension from '@/extension/Extension' const ExtensionCatalog = () => { - const [activeExtensions, setActiveExtensions] = useState([]) - const [extensionCatalog, setExtensionCatalog] = useState([]) + const [activeExtensions, setActiveExtensions] = useState([]) const fileInputRef = useRef(null) - const { experimentalFeature } = useContext(FeatureToggleContext) - /** - * Loads the extension catalog module from a CDN and sets it as the extension catalog state. - */ - useEffect(() => { - if (!window.electronAPI) { - return - } - - // Get extension manifest - import(/* webpackIgnore: true */ PLUGIN_CATALOG + `?t=${Date.now()}`).then( - (data) => { - if (Array.isArray(data.default) && experimentalFeature) - setExtensionCatalog(data.default) - } - ) - }, [experimentalFeature]) - /** * Fetches the active extensions and their preferences from the `extensions` and `preferences` modules. * If the `experimentComponent` extension point is available, it executes the extension point and @@ -90,57 +69,28 @@ const ExtensionCatalog = () => { return (
- {extensionCatalog - .concat( - activeExtensions.filter( - (e) => !(extensionCatalog ?? []).some((p) => p.name === e.name) - ) ?? [] - ) - .map((item, i) => { - const isActiveExtension = activeExtensions.some( - (x) => x.name === item.name - ) - const installedExtension = activeExtensions.filter( - (p) => p.name === item.name - )[0] - const updateVersionExtensions = Number( - installedExtension?.version.replaceAll('.', '') - ) - - const hasUpdateVersionExtensions = - item.version.replaceAll('.', '') > updateVersionExtensions - - return ( -
-
-
-
- {formatExtensionsName(item.name)} -
-

- v{item.version} -

-
-

- {item.description} + {activeExtensions.map((item, i) => { + return ( +

+
+
+
+ {formatExtensionsName(item.name ?? item.description ?? '')} +
+

+ v{item.version}

- {isActiveExtension && ( -
-

- Installed{' '} - {hasUpdateVersionExtensions - ? `v${installedExtension.version}` - : 'the latest version'} -

-
- )}
+

+ {item.description} +

- ) - })} +
+ ) + })} {/* Manual Installation */}
diff --git a/web/screens/Settings/index.tsx b/web/screens/Settings/index.tsx index 7e914b8b8..53d4e1779 100644 --- a/web/screens/Settings/index.tsx +++ b/web/screens/Settings/index.tsx @@ -9,8 +9,7 @@ import { twMerge } from 'tailwind-merge' import Advanced from '@/screens/Settings/Advanced' import AppearanceOptions from '@/screens/Settings/Appearance' -import ExtensionCatalog from '@/screens/Settings/CoreExtensions/ExtensionsCatalog' -import PreferenceExtensions from '@/screens/Settings/CoreExtensions/PreferenceExtensions' +import ExtensionCatalog from '@/screens/Settings/CoreExtensions' import Models from '@/screens/Settings/Models' @@ -19,8 +18,6 @@ import { formatExtensionsName } from '@/utils/converter' const SettingsScreen = () => { const [activeStaticMenu, setActiveStaticMenu] = useState('My Models') const [menus, setMenus] = useState([]) - const [preferenceItems, setPreferenceItems] = useState([]) - const [preferenceValues, setPreferenceValues] = useState([]) useEffect(() => { const menu = ['My Models', 'My Settings', 'Advanced Settings'] @@ -31,12 +28,6 @@ const SettingsScreen = () => { setMenus(menu) }, []) - const preferenceExtensions = preferenceItems - .map((x) => x.extensionnName) - .filter((x, i) => { - // return prefere/nceItems.map((x) => x.extensionName).indexOf(x) === i - }) - const [activePreferenceExtension, setActivePreferenceExtension] = useState('') const handleShowOptions = (menu: string) => { @@ -52,15 +43,6 @@ const SettingsScreen = () => { case 'My Models': return - - default: - return ( - - ) } } @@ -97,45 +79,6 @@ const SettingsScreen = () => { })}
- -
- {preferenceExtensions.length > 0 && ( - - )} -
- {preferenceExtensions.map((menu, i) => { - const isActive = activePreferenceExtension === menu - return ( -
-
{ - setActivePreferenceExtension(menu) - setActiveStaticMenu('') - }} - className="block w-full cursor-pointer" - > - - {formatExtensionsName(String(menu))} - -
- {isActive ? ( - - ) : null} -
- ) - })} -
-