mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-08 20:42:30 +08:00
### What problem does this PR solve? Refactor Datasets UI #3221. ### Type of change - [X] New Feature (non-breaking change which adds functionality)
This commit is contained in:
48
web/src/components/cross-language-item-ui.tsx
Normal file
48
web/src/components/cross-language-item-ui.tsx
Normal file
@ -0,0 +1,48 @@
|
||||
import { FormLabel } from '@/components/ui/form';
|
||||
import { MultiSelect } from '@/components/ui/multi-select';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const Languages = [
|
||||
'English',
|
||||
'Chinese',
|
||||
'Spanish',
|
||||
'French',
|
||||
'German',
|
||||
'Japanese',
|
||||
'Korean',
|
||||
];
|
||||
|
||||
const options = Languages.map((x) => ({ label: x, value: x }));
|
||||
|
||||
type CrossLanguageItemProps = {
|
||||
name?: string | Array<string>;
|
||||
onChange: (arg: string[]) => void;
|
||||
};
|
||||
|
||||
export const CrossLanguageItem = ({
|
||||
name = ['prompt_config', 'cross_languages'],
|
||||
onChange = () => {},
|
||||
}: CrossLanguageItemProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="pb-2">
|
||||
<FormLabel tooltip={t('chat.crossLanguageTip')}>
|
||||
{t('chat.crossLanguage')}
|
||||
</FormLabel>
|
||||
</div>
|
||||
<MultiSelect
|
||||
options={options}
|
||||
onValueChange={(val) => {
|
||||
onChange(val);
|
||||
}}
|
||||
// defaultValue={field.value}
|
||||
placeholder={t('fileManager.pleaseSelect')}
|
||||
maxCount={100}
|
||||
// {...field}
|
||||
modalPopover
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@ -43,17 +43,33 @@ export function DelimiterFormField() {
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={'parser_config.delimiter'}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel tooltip={t('knowledgeDetails.delimiterTip')}>
|
||||
{t('knowledgeDetails.delimiter')}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<DelimiterInput {...field}></DelimiterInput>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
render={({ field }) => {
|
||||
if (typeof field.value === 'undefined') {
|
||||
// default value set
|
||||
form.setValue('parser_config.delimiter', '\n');
|
||||
}
|
||||
return (
|
||||
<FormItem className=" items-center space-y-0 ">
|
||||
<div className="flex items-center">
|
||||
<FormLabel
|
||||
tooltip={t('knowledgeDetails.delimiterTip')}
|
||||
className="text-sm text-muted-foreground whitespace-nowrap w-1/4"
|
||||
>
|
||||
{t('knowledgeDetails.delimiter')}
|
||||
</FormLabel>
|
||||
<div className="w-3/4">
|
||||
<FormControl>
|
||||
<DelimiterInput {...field}></DelimiterInput>
|
||||
</FormControl>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex pt-1">
|
||||
<div className="w-1/4"></div>
|
||||
<FormMessage />
|
||||
</div>
|
||||
</FormItem>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@ -2,14 +2,15 @@
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
width: 100%;
|
||||
// width: 100%;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.tag {
|
||||
max-width: 100%;
|
||||
margin: 0;
|
||||
padding: 2px 20px 2px 4px;
|
||||
padding: 2px 20px 0px 4px;
|
||||
height: 26px;
|
||||
font-size: 14px;
|
||||
.textEllipsis();
|
||||
position: relative;
|
||||
|
||||
@ -74,7 +74,7 @@ const EditTag = ({ value = [], onChange }: EditTagsProps) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="flex gap-[8px] items-start">
|
||||
{Array.isArray(tagChild) && tagChild.length > 0 && (
|
||||
<TweenOneGroup
|
||||
className={styles.tweenGroup}
|
||||
@ -96,19 +96,23 @@ const EditTag = ({ value = [], onChange }: EditTagsProps) => {
|
||||
</TweenOneGroup>
|
||||
)}
|
||||
{inputVisible ? (
|
||||
<Input
|
||||
ref={inputRef}
|
||||
type="text"
|
||||
size="small"
|
||||
value={inputValue}
|
||||
onChange={handleInputChange}
|
||||
onBlur={handleInputConfirm}
|
||||
onPressEnter={handleInputConfirm}
|
||||
/>
|
||||
<div className="w-[180px] mb-[8px]">
|
||||
<Input
|
||||
ref={inputRef}
|
||||
type="text"
|
||||
size="small"
|
||||
value={inputValue}
|
||||
onChange={handleInputChange}
|
||||
onBlur={handleInputConfirm}
|
||||
onPressEnter={handleInputConfirm}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<Tag onClick={showInput} style={tagPlusStyle}>
|
||||
<PlusOutlined />
|
||||
</Tag>
|
||||
<div className="mb-[8px]">
|
||||
<Tag onClick={showInput} style={tagPlusStyle}>
|
||||
<PlusOutlined />
|
||||
</Tag>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -24,12 +24,21 @@ export function EntityTypesFormField({
|
||||
control={form.control}
|
||||
name={name}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t('entityTypes')}</FormLabel>
|
||||
<FormControl>
|
||||
<EditTag {...field}></EditTag>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
<FormItem className=" items-center space-y-0 ">
|
||||
<div className="flex items-center">
|
||||
<FormLabel className="text-sm text-muted-foreground whitespace-nowrap w-1/4">
|
||||
<span className="text-red-600">*</span> {t('entityTypes')}
|
||||
</FormLabel>
|
||||
<div className="w-3/4">
|
||||
<FormControl>
|
||||
<EditTag {...field}></EditTag>
|
||||
</FormControl>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex pt-1">
|
||||
<div className="w-1/4"></div>
|
||||
<FormMessage />
|
||||
</div>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
@ -17,18 +17,37 @@ export function ExcelToHtmlFormField() {
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="parser_config.html4excel"
|
||||
render={({ field }) => (
|
||||
<FormItem defaultChecked={false}>
|
||||
<FormLabel tooltip={t('html4excelTip')}>{t('html4excel')}</FormLabel>
|
||||
<FormControl>
|
||||
<Switch
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
></Switch>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
render={({ field }) => {
|
||||
if (typeof field.value === 'undefined') {
|
||||
// default value set
|
||||
form.setValue('parser_config.html4excel', false);
|
||||
}
|
||||
|
||||
return (
|
||||
<FormItem defaultChecked={false} className=" items-center space-y-0 ">
|
||||
<div className="flex items-center">
|
||||
<FormLabel
|
||||
tooltip={t('html4excelTip')}
|
||||
className="text-sm text-muted-foreground whitespace-nowrap w-1/4"
|
||||
>
|
||||
{t('html4excel')}
|
||||
</FormLabel>
|
||||
<div className="w-3/4">
|
||||
<FormControl>
|
||||
<Switch
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
></Switch>
|
||||
</FormControl>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex pt-1">
|
||||
<div className="w-1/4"></div>
|
||||
<FormMessage />
|
||||
</div>
|
||||
</FormItem>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@ -54,17 +54,37 @@ export function LayoutRecognizeFormField() {
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="parser_config.layout_recognize"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel tooltip={t('layoutRecognizeTip')}>
|
||||
{t('layoutRecognize')}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<RAGFlowSelect {...field} options={options}></RAGFlowSelect>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
render={({ field }) => {
|
||||
if (typeof field.value === 'undefined') {
|
||||
// default value set
|
||||
form.setValue(
|
||||
'parser_config.layout_recognize',
|
||||
form.formState.defaultValues?.parser_config?.layout_recognize ??
|
||||
'DeepDOC',
|
||||
);
|
||||
}
|
||||
return (
|
||||
<FormItem className=" items-center space-y-0 ">
|
||||
<div className="flex items-center">
|
||||
<FormLabel
|
||||
tooltip={t('layoutRecognizeTip')}
|
||||
className="text-sm text-muted-foreground whitespace-nowrap w-1/4"
|
||||
>
|
||||
{t('layoutRecognize')}
|
||||
</FormLabel>
|
||||
<div className="w-3/4">
|
||||
<FormControl>
|
||||
<RAGFlowSelect {...field} options={options}></RAGFlowSelect>
|
||||
</FormControl>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex pt-1">
|
||||
<div className="w-1/4"></div>
|
||||
<FormMessage />
|
||||
</div>
|
||||
</FormItem>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
25
web/src/components/originui/input.tsx
Normal file
25
web/src/components/originui/input.tsx
Normal file
@ -0,0 +1,25 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
function Input({ className, type, ...props }: React.ComponentProps<'input'>) {
|
||||
return (
|
||||
<input
|
||||
type={type}
|
||||
data-slot="input"
|
||||
className={cn(
|
||||
'border-input file:text-foreground placeholder:text-muted-foreground/70 flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-sm shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50',
|
||||
'focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]',
|
||||
'aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive',
|
||||
type === 'search' &&
|
||||
'[&::-webkit-search-cancel-button]:appearance-none [&::-webkit-search-decoration]:appearance-none [&::-webkit-search-results-button]:appearance-none [&::-webkit-search-results-decoration]:appearance-none',
|
||||
type === 'file' &&
|
||||
'text-muted-foreground/70 file:border-input file:text-foreground p-0 pr-3 italic file:me-3 file:h-full file:border-0 file:border-r file:border-solid file:bg-transparent file:px-3 file:text-sm file:font-medium file:not-italic',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export { Input };
|
||||
@ -11,7 +11,7 @@ export function PageRankFormField() {
|
||||
tooltip={t('pageRankTip')}
|
||||
defaultValue={0}
|
||||
max={100}
|
||||
min={1}
|
||||
min={0}
|
||||
></SliderInputFormField>
|
||||
);
|
||||
}
|
||||
|
||||
@ -58,17 +58,27 @@ export function UseGraphRagFormField() {
|
||||
control={form.control}
|
||||
name="parser_config.graphrag.use_graphrag"
|
||||
render={({ field }) => (
|
||||
<FormItem defaultChecked={false}>
|
||||
<FormLabel tooltip={t('useGraphRagTip')}>
|
||||
{t('useGraphRag')}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Switch
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
></Switch>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
<FormItem defaultChecked={false} className=" items-center space-y-0 ">
|
||||
<div className="flex items-center">
|
||||
<FormLabel
|
||||
tooltip={t('useGraphRagTip')}
|
||||
className="text-sm text-muted-foreground whitespace-nowrap w-1/4"
|
||||
>
|
||||
{t('useGraphRag')}
|
||||
</FormLabel>
|
||||
<div className="w-3/4">
|
||||
<FormControl>
|
||||
<Switch
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
></Switch>
|
||||
</FormControl>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex pt-1">
|
||||
<div className="w-1/4"></div>
|
||||
<FormMessage />
|
||||
</div>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
@ -112,25 +122,33 @@ const GraphRagItems = ({
|
||||
control={form.control}
|
||||
name="parser_config.graphrag.method"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel
|
||||
tooltip={renderWideTooltip(
|
||||
<div
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: t('graphRagMethodTip'),
|
||||
}}
|
||||
></div>,
|
||||
)}
|
||||
>
|
||||
{t('graphRagMethod')}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<RAGFlowSelect
|
||||
{...field}
|
||||
options={methodOptions}
|
||||
></RAGFlowSelect>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
<FormItem className=" items-center space-y-0 ">
|
||||
<div className="flex items-center">
|
||||
<FormLabel
|
||||
className="text-sm text-muted-foreground whitespace-nowrap w-1/4"
|
||||
tooltip={renderWideTooltip(
|
||||
<div
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: t('graphRagMethodTip'),
|
||||
}}
|
||||
></div>,
|
||||
)}
|
||||
>
|
||||
{t('graphRagMethod')}
|
||||
</FormLabel>
|
||||
<div className="w-3/4">
|
||||
<FormControl>
|
||||
<RAGFlowSelect
|
||||
{...field}
|
||||
options={methodOptions}
|
||||
></RAGFlowSelect>
|
||||
</FormControl>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex pt-1">
|
||||
<div className="w-1/4"></div>
|
||||
<FormMessage />
|
||||
</div>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
@ -139,17 +157,27 @@ const GraphRagItems = ({
|
||||
control={form.control}
|
||||
name="parser_config.graphrag.resolution"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel tooltip={renderWideTooltip('resolutionTip')}>
|
||||
{t('resolution')}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Switch
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
></Switch>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
<FormItem className=" items-center space-y-0 ">
|
||||
<div className="flex items-center">
|
||||
<FormLabel
|
||||
tooltip={renderWideTooltip('resolutionTip')}
|
||||
className="text-sm text-muted-foreground whitespace-nowrap w-1/4"
|
||||
>
|
||||
{t('resolution')}
|
||||
</FormLabel>
|
||||
<div className="w-3/4">
|
||||
<FormControl>
|
||||
<Switch
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
></Switch>
|
||||
</FormControl>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex pt-1">
|
||||
<div className="w-1/4"></div>
|
||||
<FormMessage />
|
||||
</div>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
@ -158,17 +186,27 @@ const GraphRagItems = ({
|
||||
control={form.control}
|
||||
name="parser_config.graphrag.community"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel tooltip={renderWideTooltip('communityTip')}>
|
||||
{t('community')}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Switch
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
></Switch>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
<FormItem className=" items-center space-y-0 ">
|
||||
<div className="flex items-center">
|
||||
<FormLabel
|
||||
tooltip={renderWideTooltip('communityTip')}
|
||||
className="text-sm text-muted-foreground whitespace-nowrap w-1/4"
|
||||
>
|
||||
{t('community')}
|
||||
</FormLabel>
|
||||
<div className="w-3/4">
|
||||
<FormControl>
|
||||
<Switch
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
></Switch>
|
||||
</FormControl>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex pt-1">
|
||||
<div className="w-1/4"></div>
|
||||
<FormMessage />
|
||||
</div>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
@ -0,0 +1,146 @@
|
||||
import { DocumentParserType } from '@/constants/knowledge';
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import random from 'lodash/random';
|
||||
import { Plus } from 'lucide-react';
|
||||
import { useCallback } from 'react';
|
||||
import { useFormContext, useWatch } from 'react-hook-form';
|
||||
import { SliderInputFormField } from '../slider-input-form-field';
|
||||
import { Button } from '../ui/button';
|
||||
import {
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '../ui/form';
|
||||
import { Input } from '../ui/input';
|
||||
import { Switch } from '../ui/switch';
|
||||
import { Textarea } from '../ui/textarea';
|
||||
|
||||
export const excludedParseMethods = [
|
||||
DocumentParserType.Table,
|
||||
DocumentParserType.Resume,
|
||||
DocumentParserType.One,
|
||||
DocumentParserType.Picture,
|
||||
DocumentParserType.KnowledgeGraph,
|
||||
DocumentParserType.Qa,
|
||||
DocumentParserType.Tag,
|
||||
];
|
||||
|
||||
export const showRaptorParseConfiguration = (
|
||||
parserId: DocumentParserType | undefined,
|
||||
) => {
|
||||
return !excludedParseMethods.some((x) => x === parserId);
|
||||
};
|
||||
|
||||
export const excludedTagParseMethods = [
|
||||
DocumentParserType.Table,
|
||||
DocumentParserType.KnowledgeGraph,
|
||||
DocumentParserType.Tag,
|
||||
];
|
||||
|
||||
export const showTagItems = (parserId: DocumentParserType) => {
|
||||
return !excludedTagParseMethods.includes(parserId);
|
||||
};
|
||||
|
||||
const UseRaptorField = 'parser_config.raptor.use_raptor';
|
||||
const RandomSeedField = 'parser_config.raptor.random_seed';
|
||||
|
||||
// The three types "table", "resume" and "one" do not display this configuration.
|
||||
|
||||
const RaptorFormFields = () => {
|
||||
const form = useFormContext();
|
||||
const { t } = useTranslate('knowledgeConfiguration');
|
||||
const useRaptor = useWatch({ name: UseRaptorField });
|
||||
|
||||
const handleGenerate = useCallback(() => {
|
||||
form.setValue(RandomSeedField, random(10000));
|
||||
}, [form]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={UseRaptorField}
|
||||
render={({ field }) => (
|
||||
<FormItem defaultChecked={false}>
|
||||
<FormLabel tooltip={t('useRaptorTip')}>{t('useRaptor')}</FormLabel>
|
||||
<FormControl>
|
||||
<Switch
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
></Switch>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
{useRaptor && (
|
||||
<div className="space-y-3">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={'parser_config.raptor.prompt'}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel tooltip={t('promptTip')}>{t('prompt')}</FormLabel>
|
||||
<FormControl>
|
||||
<Textarea {...field} rows={8} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<SliderInputFormField
|
||||
name={'parser_config.raptor.max_token'}
|
||||
label={t('maxToken')}
|
||||
tooltip={t('maxTokenTip')}
|
||||
defaultValue={256}
|
||||
max={2048}
|
||||
min={0}
|
||||
></SliderInputFormField>
|
||||
<SliderInputFormField
|
||||
name={'parser_config.raptor.threshold'}
|
||||
label={t('threshold')}
|
||||
tooltip={t('thresholdTip')}
|
||||
defaultValue={0.1}
|
||||
step={0.01}
|
||||
max={1}
|
||||
min={0}
|
||||
></SliderInputFormField>
|
||||
<SliderInputFormField
|
||||
name={'parser_config.raptor.max_cluster'}
|
||||
label={t('maxCluster')}
|
||||
tooltip={t('maxClusterTip')}
|
||||
defaultValue={64}
|
||||
max={1024}
|
||||
min={1}
|
||||
></SliderInputFormField>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={'parser_config.raptor.random_seed'}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t('randomSeed')}</FormLabel>
|
||||
<FormControl defaultValue={0}>
|
||||
<div className="flex gap-4">
|
||||
<Input {...field} />
|
||||
<Button
|
||||
size={'sm'}
|
||||
onClick={handleGenerate}
|
||||
type={'button'}
|
||||
>
|
||||
<Plus />
|
||||
</Button>
|
||||
</div>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default RaptorFormFields;
|
||||
@ -62,18 +62,39 @@ const RaptorFormFields = () => {
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={UseRaptorField}
|
||||
render={({ field }) => (
|
||||
<FormItem defaultChecked={false}>
|
||||
<FormLabel tooltip={t('useRaptorTip')}>{t('useRaptor')}</FormLabel>
|
||||
<FormControl>
|
||||
<Switch
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
></Switch>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
render={({ field }) => {
|
||||
if (typeof field.value === 'undefined') {
|
||||
// default value set
|
||||
form.setValue('parser_config.raptor.use_raptor', false);
|
||||
}
|
||||
return (
|
||||
<FormItem
|
||||
defaultChecked={false}
|
||||
className="items-center space-y-0 "
|
||||
>
|
||||
<div className="flex items-center">
|
||||
<FormLabel
|
||||
tooltip={t('useRaptorTip')}
|
||||
className="text-sm text-muted-foreground whitespace-nowrap w-1/4"
|
||||
>
|
||||
{t('useRaptor')}
|
||||
</FormLabel>
|
||||
<div className="w-3/4">
|
||||
<FormControl>
|
||||
<Switch
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
></Switch>
|
||||
</FormControl>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex pt-1">
|
||||
<div className="w-1/4"></div>
|
||||
<FormMessage />
|
||||
</div>
|
||||
</FormItem>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
{useRaptor && (
|
||||
<div className="space-y-3">
|
||||
@ -81,12 +102,24 @@ const RaptorFormFields = () => {
|
||||
control={form.control}
|
||||
name={'parser_config.raptor.prompt'}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel tooltip={t('promptTip')}>{t('prompt')}</FormLabel>
|
||||
<FormControl>
|
||||
<Textarea {...field} rows={8} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
<FormItem className=" items-center space-y-0 ">
|
||||
<div className="flex items-start">
|
||||
<FormLabel
|
||||
tooltip={t('promptTip')}
|
||||
className="text-sm text-muted-foreground whitespace-nowrap w-1/4"
|
||||
>
|
||||
{t('prompt')}
|
||||
</FormLabel>
|
||||
<div className="w-3/4">
|
||||
<FormControl>
|
||||
<Textarea {...field} rows={8} />
|
||||
</FormControl>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex pt-1">
|
||||
<div className="w-1/4"></div>
|
||||
<FormMessage />
|
||||
</div>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
@ -119,21 +152,30 @@ const RaptorFormFields = () => {
|
||||
control={form.control}
|
||||
name={'parser_config.raptor.random_seed'}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t('randomSeed')}</FormLabel>
|
||||
<FormControl defaultValue={0}>
|
||||
<div className="flex gap-4">
|
||||
<Input {...field} />
|
||||
<Button
|
||||
size={'sm'}
|
||||
onClick={handleGenerate}
|
||||
type={'button'}
|
||||
>
|
||||
<Plus />
|
||||
</Button>
|
||||
<FormItem className=" items-center space-y-0 ">
|
||||
<div className="flex items-center">
|
||||
<FormLabel className="text-sm text-muted-foreground whitespace-nowrap w-1/4">
|
||||
{t('randomSeed')}
|
||||
</FormLabel>
|
||||
<div className="w-3/4">
|
||||
<FormControl defaultValue={0}>
|
||||
<div className="flex gap-4">
|
||||
<Input {...field} />
|
||||
<Button
|
||||
size={'sm'}
|
||||
onClick={handleGenerate}
|
||||
type={'button'}
|
||||
>
|
||||
<Plus />
|
||||
</Button>
|
||||
</div>
|
||||
</FormControl>
|
||||
</div>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</div>
|
||||
<div className="flex pt-1">
|
||||
<div className="w-1/4"></div>
|
||||
<FormMessage />
|
||||
</div>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
58
web/src/components/password-input/index.tsx
Normal file
58
web/src/components/password-input/index.tsx
Normal file
@ -0,0 +1,58 @@
|
||||
import { Input } from '@/components/originui/input';
|
||||
import { useTranslate } from '@/hooks/common-hooks';
|
||||
import { EyeIcon, EyeOffIcon } from 'lucide-react';
|
||||
import { ChangeEvent, LegacyRef, forwardRef, useId, useState } from 'react';
|
||||
|
||||
type PropType = {
|
||||
name: string;
|
||||
value: string;
|
||||
onBlur: () => void;
|
||||
onChange: (event: ChangeEvent<HTMLInputElement>) => void;
|
||||
};
|
||||
|
||||
function PasswordInput(
|
||||
props: PropType,
|
||||
ref: LegacyRef<HTMLInputElement> | undefined,
|
||||
) {
|
||||
const id = useId();
|
||||
const [isVisible, setIsVisible] = useState<boolean>(false);
|
||||
|
||||
const toggleVisibility = () => setIsVisible((prevState) => !prevState);
|
||||
|
||||
const { t } = useTranslate('setting');
|
||||
|
||||
return (
|
||||
<div className="*:not-first:mt-2 w-full">
|
||||
{/* <Label htmlFor={id}>Show/hide password input</Label> */}
|
||||
<div className="relative">
|
||||
<Input
|
||||
autoComplete="off"
|
||||
inputMode="numeric"
|
||||
id={id}
|
||||
className="pe-9"
|
||||
placeholder=""
|
||||
type={isVisible ? 'text' : 'password'}
|
||||
value={props.value}
|
||||
onBlur={props.onBlur}
|
||||
onChange={(ev) => props.onChange(ev)}
|
||||
/>
|
||||
<button
|
||||
className="text-muted-foreground/80 hover:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 absolute inset-y-0 end-0 flex h-full w-9 items-center justify-center rounded-e-md transition-[color,box-shadow] outline-none focus:z-10 focus-visible:ring-[3px] disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50"
|
||||
type="button"
|
||||
onClick={toggleVisibility}
|
||||
aria-label={isVisible ? 'Hide password' : 'Show password'}
|
||||
aria-pressed={isVisible}
|
||||
aria-controls="password"
|
||||
>
|
||||
{isVisible ? (
|
||||
<EyeOffIcon size={16} aria-hidden="true" />
|
||||
) : (
|
||||
<EyeIcon size={16} aria-hidden="true" />
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default forwardRef(PasswordInput);
|
||||
@ -38,38 +38,50 @@ export function SliderInputFormField({
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={name}
|
||||
defaultValue={defaultValue}
|
||||
defaultValue={defaultValue || 0}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel tooltip={tooltip}>{label}</FormLabel>
|
||||
<div
|
||||
className={cn(
|
||||
'flex items-center gap-14 justify-between',
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<FormControl>
|
||||
<SingleFormSlider
|
||||
{...field}
|
||||
max={max}
|
||||
min={min}
|
||||
step={step}
|
||||
// defaultValue={
|
||||
// typeof defaultValue === 'number' ? [defaultValue] : undefined
|
||||
// }
|
||||
></SingleFormSlider>
|
||||
</FormControl>
|
||||
<FormControl>
|
||||
<Input
|
||||
type={'number'}
|
||||
className="h-7 w-20"
|
||||
max={max}
|
||||
min={min}
|
||||
step={step}
|
||||
{...field}
|
||||
// defaultValue={defaultValue}
|
||||
></Input>
|
||||
</FormControl>
|
||||
<FormItem className=" items-center space-y-0 ">
|
||||
<div className="flex items-center">
|
||||
<FormLabel
|
||||
tooltip={tooltip}
|
||||
className="text-sm text-muted-foreground whitespace-nowrap w-1/4"
|
||||
>
|
||||
{label}
|
||||
</FormLabel>
|
||||
<div
|
||||
className={cn(
|
||||
'flex items-center gap-14 justify-between',
|
||||
'w-3/4',
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<FormControl>
|
||||
<SingleFormSlider
|
||||
{...field}
|
||||
max={max}
|
||||
min={min}
|
||||
step={step}
|
||||
// defaultValue={
|
||||
// typeof defaultValue === 'number' ? [defaultValue] : undefined
|
||||
// }
|
||||
></SingleFormSlider>
|
||||
</FormControl>
|
||||
<FormControl>
|
||||
<Input
|
||||
type={'number'}
|
||||
className="h-7 w-20"
|
||||
max={max}
|
||||
min={min}
|
||||
step={step}
|
||||
{...field}
|
||||
onChange={(ev) => {
|
||||
const value = ev.target.value;
|
||||
field.onChange(value === '' ? 0 : Number(value)); // convert to number
|
||||
}}
|
||||
// defaultValue={defaultValue}
|
||||
></Input>
|
||||
</FormControl>
|
||||
</div>
|
||||
</div>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
|
||||
64
web/src/components/ui/tabs-underlined.tsx
Normal file
64
web/src/components/ui/tabs-underlined.tsx
Normal file
@ -0,0 +1,64 @@
|
||||
import * as TabsPrimitive from '@radix-ui/react-tabs';
|
||||
import * as React from 'react';
|
||||
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
function Tabs({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof TabsPrimitive.Root>) {
|
||||
return (
|
||||
<TabsPrimitive.Root
|
||||
data-slot="tabs"
|
||||
className={cn('flex flex-col gap-2', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function TabsList({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof TabsPrimitive.List>) {
|
||||
return (
|
||||
<TabsPrimitive.List
|
||||
data-slot="tabs-list"
|
||||
className={cn(
|
||||
'bg-muted text-muted-foreground inline-flex h-9 w-fit items-center justify-center rounded-lg p-[3px]',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function TabsTrigger({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof TabsPrimitive.Trigger>) {
|
||||
return (
|
||||
<TabsPrimitive.Trigger
|
||||
data-slot="tabs-trigger"
|
||||
className={cn(
|
||||
"data-[state=active]:bg-background dark:data-[state=active]:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 text-foreground dark:text-muted-foreground inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:shadow-sm [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function TabsContent({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof TabsPrimitive.Content>) {
|
||||
return (
|
||||
<TabsPrimitive.Content
|
||||
data-slot="tabs-content"
|
||||
className={cn('flex-1 outline-none', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export { Tabs, TabsContent, TabsList, TabsTrigger };
|
||||
Reference in New Issue
Block a user