refactor: file prefix replace utils & add unit test (#1676)

* refactor: file prefix replace utils

* chore: add unit tests for core module
This commit is contained in:
Louis 2024-01-22 10:05:47 +07:00 committed by GitHub
parent fc3a5c9e01
commit 99d083d84a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 204 additions and 386 deletions

View File

@ -39,6 +39,7 @@ lint: check-file-counts
# Testing
test: lint
yarn build:test
yarn test:unit
yarn test
# Builds and publishes the app

3
core/.gitignore vendored
View File

@ -6,7 +6,4 @@ coverage
.vscode
.idea
dist
compiled
.awcache
.rpt2_cache
docs

7
core/jest.config.js Normal file
View File

@ -0,0 +1,7 @@
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
moduleNameMapper: {
'@/(.*)': '<rootDir>/src/$1',
},
}

View File

@ -12,7 +12,8 @@
"module": "dist/core.es5.js",
"typings": "dist/types/index.d.ts",
"files": [
"dist"
"dist",
"types"
],
"author": "Jan <service@jan.ai>",
"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"
}

View File

@ -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();
});
};

View File

@ -6,3 +6,4 @@ export * from './download'
export * from './module'
export * from './api'
export * from './log'
export * from './path'

9
core/src/node/path.ts Normal file
View File

@ -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");
}

View File

@ -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");
});
});

View File

@ -13,7 +13,7 @@
"declarationDir": "dist/types",
"outDir": "dist/lib",
"importHelpers": true,
"typeRoots": ["node_modules/@types"]
"types": ["@types/jest"]
},
"include": ["src"]
}

View File

@ -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))
}
)
}

View File

@ -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<FileStat | undefined> => {
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)

View File

@ -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
)
)

View File

@ -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",

View File

@ -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<boolean>(false)
const [experimentalFeature, directSetExperimentalFeature] =
useState<boolean>(false)
const [ignoreSSL, directSetIgnoreSSL] = useState<boolean>(false)
const [proxy, directSetProxy] = useState<string>('')
@ -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) => {

View File

@ -104,8 +104,8 @@ export const useCreateNewThread = () => {
}
extensionManager
.get<ConversationalExtension>(ExtensionType.Conversational)
?.saveThread(thread)
.get<ConversationalExtension>(ExtensionType.Conversational)
?.saveThread(thread)
}
return {

View File

@ -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)

View File

@ -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"
},

View File

@ -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<string>(proxy)
const [gpuEnabled, setGpuEnabled] = useState<boolean>(false)
const { readSettings, saveSettings, validateSettings, setShowNotification } =
useSettings()
const onProxyChange = useCallback((event: ChangeEvent<HTMLInputElement>) => {
const value = event.target.value || ''
setPartialProxy(value)
if (value.trim().startsWith('http')) {
setProxy(value.trim())
}
else {
setProxy('')
}
}, [setPartialProxy, setProxy])
const onProxyChange = useCallback(
(event: ChangeEvent<HTMLInputElement>) => {
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 = () => {
<div className="flex w-full items-start justify-between border-b border-border py-4 first:pt-0 last:border-none">
<div className="w-4/5 flex-shrink-0 space-y-1.5">
<div className="flex gap-x-2">
<h6 className="text-sm font-semibold capitalize">
HTTPS Proxy
</h6>
<h6 className="text-sm font-semibold capitalize">HTTPS Proxy</h6>
</div>
<p className="whitespace-pre-wrap leading-relaxed">
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).
</p>
<Input
placeholder={"http://<user>:<password>@<domain or IP>:<port>"}
placeholder={'http://<user>:<password>@<domain or IP>:<port>'}
value={partialProxy}
onChange={onProxyChange}
/>
@ -138,7 +142,8 @@ const Advanced = () => {
</h6>
</div>
<p className="whitespace-pre-wrap leading-relaxed">
Allow self-signed or unverified certificates - may be required for certain proxies.
Allow self-signed or unverified certificates - may be required for
certain proxies.
</p>
</div>
<Switch

View File

@ -1,101 +0,0 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
type Props = {
extensionName: string
preferenceValues: any
preferenceItems: any
}
import { useForm } from 'react-hook-form'
import { zodResolver } from '@hookform/resolvers/zod'
import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
Input,
FormLabel,
FormMessage,
Button,
} from '@janhq/uikit'
import * as z from 'zod'
import { toaster } from '@/containers/Toast'
import { formatExtensionsName } from '@/utils/converter'
const PreferenceExtensions = (props: Props) => {
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<z.infer<typeof FormSchema>>({
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<typeof FormSchema>) => {
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 (
<div className="mx-auto w-full lg:mt-10 lg:w-1/2">
<h6 className="mb-6 text-lg font-semibold capitalize">
{formatExtensionsName(extensionName)}
</h6>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
{preferenceItems
.filter((x: any) => x.extensionName === extensionName)
?.map((e: any) => (
<FormField
key={e.preferenceKey}
control={form.control}
name={e.preferenceKey}
render={({ field }) => (
<FormItem>
<FormLabel>{e.preferenceName}</FormLabel>
<FormDescription className="mb-2">
{e.preferenceDescription}
</FormDescription>
<FormControl>
<Input
placeholder={`Enter your ${e.preferenceName}`}
{...field}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
))}
<div className="pt-4">
<Button type="submit" block>
Submit
</Button>
</div>
</form>
</Form>
</div>
)
}
export default PreferenceExtensions

View File

@ -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<any[]>([])
const [extensionCatalog, setExtensionCatalog] = useState<any[]>([])
const [activeExtensions, setActiveExtensions] = useState<Extension[]>([])
const fileInputRef = useRef<HTMLInputElement | null>(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 (
<div className="block w-full">
{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 (
<div
key={i}
className="flex w-full items-start justify-between border-b border-border py-4 first:pt-0 last:border-none"
>
<div className="w-4/5 flex-shrink-0 space-y-1.5">
<div className="flex gap-x-2">
<h6 className="text-sm font-semibold capitalize">
{formatExtensionsName(item.name)}
</h6>
<p className="whitespace-pre-wrap font-semibold leading-relaxed ">
v{item.version}
</p>
</div>
<p className="whitespace-pre-wrap leading-relaxed ">
{item.description}
{activeExtensions.map((item, i) => {
return (
<div
key={i}
className="flex w-full items-start justify-between border-b border-border py-4 first:pt-0 last:border-none"
>
<div className="w-4/5 flex-shrink-0 space-y-1.5">
<div className="flex gap-x-2">
<h6 className="text-sm font-semibold capitalize">
{formatExtensionsName(item.name ?? item.description ?? '')}
</h6>
<p className="whitespace-pre-wrap font-semibold leading-relaxed ">
v{item.version}
</p>
{isActiveExtension && (
<div className="flex items-center gap-x-2">
<p className="whitespace-pre-wrap leading-relaxed ">
Installed{' '}
{hasUpdateVersionExtensions
? `v${installedExtension.version}`
: 'the latest version'}
</p>
</div>
)}
</div>
<p className="whitespace-pre-wrap leading-relaxed ">
{item.description}
</p>
</div>
)
})}
</div>
)
})}
{/* Manual Installation */}
<div className="flex w-full items-start justify-between border-b border-border py-4 first:pt-0 last:border-none">
<div className="w-4/5 flex-shrink-0 space-y-1.5">

View File

@ -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<any[]>([])
const [preferenceItems, setPreferenceItems] = useState<any[]>([])
const [preferenceValues, setPreferenceValues] = useState<any[]>([])
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 <Models />
default:
return (
<PreferenceExtensions
extensionName={menu}
preferenceItems={preferenceItems}
preferenceValues={preferenceValues}
/>
)
}
}
@ -97,45 +79,6 @@ const SettingsScreen = () => {
})}
</div>
</div>
<div className="mt-5 flex-shrink-0">
{preferenceExtensions.length > 0 && (
<label className="font-bold uppercase text-muted-foreground">
Core Extensions
</label>
)}
<div className="mt-2 font-medium">
{preferenceExtensions.map((menu, i) => {
const isActive = activePreferenceExtension === menu
return (
<div key={i} className="relative my-0.5 block py-1.5">
<div
onClick={() => {
setActivePreferenceExtension(menu)
setActiveStaticMenu('')
}}
className="block w-full cursor-pointer"
>
<span
className={twMerge(
'capitalize',
isActive && 'relative z-10'
)}
>
{formatExtensionsName(String(menu))}
</span>
</div>
{isActive ? (
<m.div
className="absolute inset-0 -left-3 h-full w-[calc(100%+24px)] rounded-md bg-primary/50"
layoutId="active-static-menu"
/>
) : null}
</div>
)
})}
</div>
</div>
</div>
</ScrollArea>
</div>