feat(web): Ontology support import & export;
docs(web): add comments to the src/views/Ontology directory
This commit is contained in:
@@ -1,5 +1,11 @@
|
||||
/*
|
||||
* @Author: ZhaoYing
|
||||
* @Date: 2026-02-03 13:59:12
|
||||
* @Last Modified by: ZhaoYing
|
||||
* @Last Modified time: 2026-02-03 13:59:12
|
||||
*/
|
||||
import { request } from '@/utils/request'
|
||||
import type { Query, OntologyModalData, OntologyClassModalData, OntologyClassExtractModalData } from '@/views/Ontology/types'
|
||||
import type { Query, OntologyModalData, OntologyClassModalData, OntologyClassExtractModalData, OntologyExportModalData } from '@/views/Ontology/types'
|
||||
|
||||
// Scene list
|
||||
export const getOntologyScenesUrl = '/memory/ontology/scenes'
|
||||
@@ -37,3 +43,11 @@ export const createOntologyClass = (data: OntologyClassModalData) => {
|
||||
export const deleteOntologyClass = (class_id: string) => {
|
||||
return request.delete(`/memory/ontology/class/${class_id}`)
|
||||
}
|
||||
// Import scenario
|
||||
export const ontologyImport = (data: unknown) => {
|
||||
return request.uploadFile('/memory/ontology/import', data)
|
||||
}
|
||||
// Export scenario
|
||||
export const ontologyExport = (data: OntologyExportModalData, fileName: string, callback: () => void) => {
|
||||
return request.downloadFile('/memory/ontology/export', fileName, data, callback)
|
||||
}
|
||||
@@ -57,6 +57,10 @@ const ALL_FILE_TYPE: {
|
||||
htm: 'text/html',
|
||||
html: 'text/html',
|
||||
json: 'application/json',
|
||||
owl: 'application/rdf+xml',
|
||||
ttl: 'text/turtle',
|
||||
rdf: 'application/rdf+xml',
|
||||
xml: 'application/rdf+xml',
|
||||
}
|
||||
export interface UploadFilesRef {
|
||||
fileList: UploadFile[];
|
||||
@@ -122,7 +126,7 @@ const UploadFiles = forwardRef<UploadFilesRef, UploadFilesProps>(({
|
||||
if (fileSize) {
|
||||
const isLtMaxSize = (file.size / 1024 / 1024) < fileSize;
|
||||
if (!isLtMaxSize) {
|
||||
message.error(`文件大小不能超过 ${fileSize}MB`);
|
||||
message.error(t('common.fileSizeTip', { size: fileSize }));
|
||||
return Upload.LIST_IGNORE;
|
||||
}
|
||||
}
|
||||
@@ -139,7 +143,7 @@ const UploadFiles = forwardRef<UploadFilesRef, UploadFilesProps>(({
|
||||
const isValidMimeType = file.type && accept ? accept.includes(file.type) : true;
|
||||
|
||||
if (!isValidExtension && !isValidMimeType) {
|
||||
message.error(`不支持的文件类型: ${fileExtension || file.type}`);
|
||||
message.error(`${t('common.fileAcceptTip')}${fileExtension || file.type}`);
|
||||
return Upload.LIST_IGNORE;
|
||||
}
|
||||
}
|
||||
@@ -236,12 +240,12 @@ const UploadFiles = forwardRef<UploadFilesRef, UploadFilesProps>(({
|
||||
fileList,
|
||||
beforeUpload,
|
||||
headers: {
|
||||
authorization: cookieUtils.get('authToken') || '',
|
||||
authorization: `Bearer ${cookieUtils.get('authToken')}`,
|
||||
},
|
||||
onRemove: handleRemove,
|
||||
onChange: handleChange,
|
||||
accept,
|
||||
disabled,
|
||||
disabled: disabled || fileList.length >= maxCount,
|
||||
showUploadList: {
|
||||
showPreviewIcon: false,
|
||||
showRemoveIcon: true,
|
||||
@@ -249,12 +253,12 @@ const UploadFiles = forwardRef<UploadFilesRef, UploadFilesProps>(({
|
||||
},
|
||||
itemRender: (_, file, __, actions) => {
|
||||
return (
|
||||
<div key={file.uid} className="rb:relative rb:w-full rb:pt-[8px] rb:pl-[10px] rb:pr-[10px] rb-pb-[10px] rb:border-1 rb:border-[#EBEBEB] rb:rounded rb:p-2 rb:mt-2 rb:bg-white">
|
||||
<div className="rb:text-[12px] rb:flex rb:items-center rb:justify-between rb:mb-[2px]">
|
||||
<div key={file.uid} className="rb:relative rb:w-full rb:pt-2 rb:pl-2.5 rb:pr-2.5 rb-pb-[10px] rb:border rb:border-[#EBEBEB] rb:rounded rb:p-2 rb:mt-2 rb:bg-white">
|
||||
<div className="rb:text-[12px] rb:flex rb:items-center rb:justify-between rb:mb-0.5">
|
||||
{file.name}
|
||||
<span className="rb:text-[#5B6167] rb:cursor-pointer" onClick={() => actions?.remove()}>Cancel</span>
|
||||
<span className="rb:text-[#5B6167] rb:cursor-pointer" onClick={() => actions?.remove()}>{t('common.cancel')}</span>
|
||||
</div>
|
||||
<Progress percent={file.percent || 0} strokeColor={file.status === 'error' ? '#FF5D34' : '#155EEF'} size="small" showInfo={false} />
|
||||
{isAutoUpload && <Progress percent={file.percent || 0} strokeColor={file.status === 'error' ? '#FF5D34' : '#155EEF'} size="small" showInfo={false} />}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
@@ -267,20 +271,20 @@ const UploadFiles = forwardRef<UploadFilesRef, UploadFilesProps>(({
|
||||
clearFiles
|
||||
}));
|
||||
|
||||
const hasProgress = fileList.some((item) => item.percent !== 100);
|
||||
const hasProgress = isAutoUpload && fileList.some((item) => item.percent !== 100);
|
||||
|
||||
if (isCanDrag) {
|
||||
return (
|
||||
<div className="rb:mb-[24px] rb:w-full">
|
||||
<div className="rb:mb-6 rb:w-full">
|
||||
<Dragger {...uploadProps} style={{ height: '270px' }}>
|
||||
<div className="rb:flex rb:justify-center rb:flex-col rb:items-center">
|
||||
<img className="rb:w-[48px] rb:h-[48px]" src={CloudUploadOutlined} />
|
||||
{!hasProgress && (!fileList || !fileList.length) &&
|
||||
<img className="rb:w-12 rb:h-12" src={CloudUploadOutlined} />
|
||||
{(!isAutoUpload || !hasProgress && (!fileList || !fileList.length)) &&
|
||||
<>
|
||||
<div className="rb:text-base rb:text-[14px] rb:font-medium rb:flex rb:items-center rb:mt-[8px] rb:leading-[20px]">
|
||||
{t('common.dragUploadTip')}<span className="rb:ml-[4px] rb:text-[#155EEF]">{t('common.uploadClickTip')}</span>
|
||||
<div className="rb:text-base rb:text-[14px] rb:font-medium rb:flex rb:items-center rb:mt-2 rb:leading-5">
|
||||
{t('common.dragUploadTip')}<span className="rb:ml-1 rb:text-[#155EEF]">{t('common.uploadClickTip')}</span>
|
||||
</div>
|
||||
{fileType && <div className="rb:text-[12px] rb:text-[#A8A9AA] rb:leading-[14px] rb:mt-[8px] rb:cursor-pointer">{t('common.supportedFileTypes', { types: fileType.join(',') })}</div>}
|
||||
{fileType && <div className="rb:text-[12px] rb:text-[#A8A9AA] rb:leading-3.5 rb:mt-2 rb:cursor-pointer">{t('common.supportedFileTypes', { types: fileType.join(',') })}</div>}
|
||||
{(fileSize || fileType || maxCount > 1) && (
|
||||
<div className='rb:text-xs rb:mt-2 rb:text-[#A8A9AA]'>
|
||||
{t('common.uploadFileTipMax', { max: fileSize, maxCount: maxCount })}
|
||||
@@ -288,7 +292,7 @@ const UploadFiles = forwardRef<UploadFilesRef, UploadFilesProps>(({
|
||||
)}
|
||||
</>
|
||||
}
|
||||
{hasProgress && <div className="rb:text-base rb:text-[14px] rb:font-medium rb:flex rb:items-center rb:mt-[8px] rb:mb-[24px] rb:leading-[20px]">{t('common.uploading')}</div>}
|
||||
{hasProgress && <div className="rb:text-base rb:text-[14px] rb:font-medium rb:flex rb:items-center rb:mt-2 rb:mb-6 rb:leading-5">{t('common.uploading')}</div>}
|
||||
</div>
|
||||
</Dragger>
|
||||
</div>
|
||||
|
||||
@@ -426,6 +426,7 @@ export const en = {
|
||||
fileAcceptTip: 'Unsupported file type:',
|
||||
nextStep: 'Next Step',
|
||||
prevStep: 'Previous Step',
|
||||
exportSuccess: 'Export successful',
|
||||
},
|
||||
model: {
|
||||
searchPlaceholder: 'search model…',
|
||||
@@ -2471,6 +2472,11 @@ Memory Bear: After the rebellion, regional warlordism intensified for several re
|
||||
extract: 'Project Inference',
|
||||
source: 'Not Added',
|
||||
target: 'Added',
|
||||
import: 'Import Scenario',
|
||||
format: 'Export Format',
|
||||
export: 'Export Scenario',
|
||||
scene_id: 'Scenario',
|
||||
file: 'Import File',
|
||||
},
|
||||
prompt: {
|
||||
editor: 'Prompt Generator',
|
||||
|
||||
@@ -980,6 +980,7 @@ export const zh = {
|
||||
fileAcceptTip: '不支持的文件类型:',
|
||||
nextStep: '下一步',
|
||||
prevStep: '上一步',
|
||||
exportSuccess: '导出成功',
|
||||
},
|
||||
product: {
|
||||
applicationManagement: '应用管理',
|
||||
@@ -2560,6 +2561,11 @@ export const zh = {
|
||||
extract: '工程推理',
|
||||
source: '未添加项',
|
||||
target: '已添加项',
|
||||
import: '导入场景',
|
||||
format: '导出格式',
|
||||
export: '导出场景',
|
||||
scene_id: '场景',
|
||||
file: '导入文件',
|
||||
},
|
||||
prompt: {
|
||||
editor: '提示词生成器',
|
||||
|
||||
@@ -288,19 +288,20 @@ export const request = {
|
||||
...config
|
||||
});
|
||||
},
|
||||
downloadFile(url: string, fileName: string, data?: unknown) {
|
||||
downloadFile(url: string, fileName: string, data?: unknown, callback?: () => void) {
|
||||
service.post(url, data, {
|
||||
responseType: "blob",
|
||||
})
|
||||
.then(res =>{
|
||||
const link = document.createElement("a");
|
||||
const blob = new Blob([res.data], { type: "application/vnd.ms-excel" });
|
||||
const blob = new Blob([res as unknown as BlobPart]);
|
||||
link.style.display = "none";
|
||||
link.href = URL.createObjectURL(blob);
|
||||
link.setAttribute("download", decodeURI(res.headers['filename'] || fileName));
|
||||
link.setAttribute("download", decodeURI(fileName || fileName));
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
callback?.()
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
/*
|
||||
* @Author: ZhaoYing
|
||||
* @Date: 2026-02-03 14:10:42
|
||||
* @Last Modified by: ZhaoYing
|
||||
* @Last Modified time: 2026-02-03 14:10:42
|
||||
*/
|
||||
import { forwardRef, useImperativeHandle, useState } from 'react';
|
||||
import { Form, Input, App, Transfer, type TransferProps, Flex } from 'antd';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -12,24 +18,37 @@ import Tag from '@/components/Tag';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
|
||||
/**
|
||||
* Props for OntologyClassExtractModal component
|
||||
*/
|
||||
interface OntologyClassExtractModalProps {
|
||||
/** Callback function to refresh parent list after extraction */
|
||||
refresh: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modal component for extracting ontology classes using LLM
|
||||
* Two-step process: 1) Extract classes from scenario 2) Select and confirm classes to add
|
||||
*/
|
||||
const OntologyClassExtractModal = forwardRef<OntologyClassExtractModalRef, OntologyClassExtractModalProps>(({
|
||||
refresh
|
||||
}, ref) => {
|
||||
// Hooks
|
||||
const { t } = useTranslation();
|
||||
const { message } = App.useApp();
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [form] = Form.useForm<OntologyClassExtractModalData>();
|
||||
|
||||
// State
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [data, setData] = useState<OntologyClassData | null>(null)
|
||||
const [extractData, setExtractData] = useState<ExtractData | null>(null)
|
||||
const [targetKeys, setTargetKeys] = useState<TransferProps['targetKeys']>([]);
|
||||
const [selectedKeys, setSelectedKeys] = useState<TransferProps['selectedKeys']>([]);
|
||||
|
||||
// 封装取消方法,添加关闭弹窗逻辑
|
||||
/**
|
||||
* Close modal and reset all state
|
||||
*/
|
||||
const handleClose = () => {
|
||||
setVisible(false);
|
||||
form.resetFields();
|
||||
@@ -38,12 +57,19 @@ const OntologyClassExtractModal = forwardRef<OntologyClassExtractModalRef, Ontol
|
||||
setExtractData(null)
|
||||
};
|
||||
|
||||
/**
|
||||
* Open modal with scene data
|
||||
* @param vo - Ontology class data containing scene information
|
||||
*/
|
||||
const handleOpen = (vo: OntologyClassData) => {
|
||||
form.resetFields();
|
||||
setVisible(true);
|
||||
setData(vo)
|
||||
};
|
||||
// 封装保存方法,添加提交逻辑
|
||||
|
||||
/**
|
||||
* Execute LLM extraction to get class suggestions
|
||||
*/
|
||||
const handleSave = () => {
|
||||
if (!data?.scene_id) return;
|
||||
form
|
||||
@@ -69,6 +95,10 @@ const OntologyClassExtractModal = forwardRef<OntologyClassExtractModalRef, Ontol
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm and create selected classes
|
||||
* First click runs extraction, second click creates classes
|
||||
*/
|
||||
const handleConfirm = () => {
|
||||
if (!extractData) {
|
||||
handleSave()
|
||||
@@ -92,11 +122,19 @@ const OntologyClassExtractModal = forwardRef<OntologyClassExtractModalRef, Ontol
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle transfer component target keys change
|
||||
* @param nextTargetKeys - New target keys after transfer
|
||||
*/
|
||||
const onChange: TransferProps['onChange'] = (nextTargetKeys) => {
|
||||
setTargetKeys(nextTargetKeys.filter(Boolean));
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle transfer component selection change
|
||||
* @param sourceSelectedKeys - Selected keys in source list
|
||||
* @param targetSelectedKeys - Selected keys in target list
|
||||
*/
|
||||
const onSelectChange: TransferProps['onSelectChange'] = (
|
||||
sourceSelectedKeys,
|
||||
targetSelectedKeys,
|
||||
@@ -104,7 +142,9 @@ const OntologyClassExtractModal = forwardRef<OntologyClassExtractModalRef, Ontol
|
||||
setSelectedKeys([...sourceSelectedKeys, ...targetSelectedKeys].filter(Boolean));
|
||||
};
|
||||
|
||||
// 暴露给父组件的方法
|
||||
/**
|
||||
* Expose methods to parent component via ref
|
||||
*/
|
||||
useImperativeHandle(ref, () => ({
|
||||
handleOpen,
|
||||
}));
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
/*
|
||||
* @Author: ZhaoYing
|
||||
* @Date: 2026-02-03 14:10:39
|
||||
* @Last Modified by: ZhaoYing
|
||||
* @Last Modified time: 2026-02-03 14:10:39
|
||||
*/
|
||||
import { forwardRef, useImperativeHandle, useState } from 'react';
|
||||
import { Form, Input, App } from 'antd';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -8,33 +14,53 @@ import { createOntologyClass } from '@/api/ontology'
|
||||
|
||||
const FormItem = Form.Item;
|
||||
|
||||
/**
|
||||
* Props for OntologyClassModal component
|
||||
*/
|
||||
interface OntologyClassModalProps {
|
||||
/** Callback function to refresh parent list after save */
|
||||
refresh: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modal component for adding new ontology classes
|
||||
* Provides form interface for class name and description
|
||||
*/
|
||||
const OntologyClassModal = forwardRef<OntologyClassModalRef, OntologyClassModalProps>(({
|
||||
refresh
|
||||
}, ref) => {
|
||||
// Hooks
|
||||
const { t } = useTranslation();
|
||||
const { message } = App.useApp();
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [form] = Form.useForm<AddClassItem>();
|
||||
|
||||
// State
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [scene_id, setSceneId] = useState<string | null>(null)
|
||||
|
||||
// 封装取消方法,添加关闭弹窗逻辑
|
||||
/**
|
||||
* Close modal and reset form state
|
||||
*/
|
||||
const handleClose = () => {
|
||||
setVisible(false);
|
||||
form.resetFields();
|
||||
setLoading(false)
|
||||
};
|
||||
|
||||
/**
|
||||
* Open modal for adding a new class
|
||||
* @param scene_id - Target scene identifier
|
||||
*/
|
||||
const handleOpen = (scene_id: string) => {
|
||||
form.resetFields();
|
||||
setVisible(true);
|
||||
setSceneId(scene_id)
|
||||
};
|
||||
// 封装保存方法,添加提交逻辑
|
||||
|
||||
/**
|
||||
* Validate and submit form data to create new class
|
||||
*/
|
||||
const handleSave = () => {
|
||||
if (!scene_id) return;
|
||||
form
|
||||
@@ -56,7 +82,9 @@ const OntologyClassModal = forwardRef<OntologyClassModalRef, OntologyClassModalP
|
||||
});
|
||||
}
|
||||
|
||||
// 暴露给父组件的方法
|
||||
/**
|
||||
* Expose methods to parent component via ref
|
||||
*/
|
||||
useImperativeHandle(ref, () => ({
|
||||
handleOpen,
|
||||
}));
|
||||
|
||||
144
web/src/views/Ontology/components/OntologyExportModal.tsx
Normal file
144
web/src/views/Ontology/components/OntologyExportModal.tsx
Normal file
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* @Author: ZhaoYing
|
||||
* @Date: 2026-02-03 14:10:46
|
||||
* @Last Modified by: ZhaoYing
|
||||
* @Last Modified time: 2026-02-03 14:10:46
|
||||
*/
|
||||
import { forwardRef, useImperativeHandle, useState } from 'react';
|
||||
import { Form, App, Select, type SelectProps } from 'antd';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import type { OntologyExportModalData, OntologyExportModalRef } from '../types'
|
||||
import RbModal from '@/components/RbModal'
|
||||
import { ontologyExport, getOntologyScenesUrl } from '@/api/ontology'
|
||||
import CustomSelect from '@/components/CustomSelect';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
|
||||
/**
|
||||
* Props for OntologyExportModal component
|
||||
*/
|
||||
interface OntologyExportModalProps {
|
||||
/** Callback function to refresh parent list after export */
|
||||
refresh: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modal component for exporting ontology scenes
|
||||
* Supports RDF/XML (.owl) and Turtle (.ttl) formats
|
||||
*/
|
||||
const OntologyExportModal = forwardRef<OntologyExportModalRef, OntologyExportModalProps>(({
|
||||
refresh
|
||||
}, ref) => {
|
||||
// Hooks
|
||||
const { t } = useTranslation();
|
||||
const { message } = App.useApp();
|
||||
const [form] = Form.useForm<OntologyExportModalData>();
|
||||
|
||||
// State
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [fileName, setFileName] = useState('')
|
||||
|
||||
/**
|
||||
* Close modal and reset form state
|
||||
*/
|
||||
const handleClose = () => {
|
||||
setVisible(false);
|
||||
form.resetFields();
|
||||
setLoading(false)
|
||||
};
|
||||
|
||||
/**
|
||||
* Open the export modal
|
||||
*/
|
||||
const handleOpen = () => {
|
||||
form.resetFields();
|
||||
setVisible(true);
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle scene selection change to set export filename
|
||||
* @param _value - Selected scene ID
|
||||
* @param option - Selected option containing scene name
|
||||
*/
|
||||
const handleChange: SelectProps['onChange'] = (_value, option) => {
|
||||
const name = Array.isArray(option) ? option[0]?.children : option?.children;
|
||||
setFileName(String(name || ''));
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate and submit form data to export ontology
|
||||
* Downloads file with appropriate extension based on format
|
||||
*/
|
||||
const handleSave = () => {
|
||||
form
|
||||
.validateFields()
|
||||
.then((values) => {
|
||||
setLoading(true)
|
||||
ontologyExport(values, `${fileName}.${values.format === 'rdfxml' ?'owl' : 'ttl'}`, () => {
|
||||
message.success(t('common.exportSuccess'));
|
||||
handleClose();
|
||||
refresh();
|
||||
setLoading(false)
|
||||
})
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log('err', err)
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Expose methods to parent component via ref
|
||||
*/
|
||||
useImperativeHandle(ref, () => ({
|
||||
handleOpen,
|
||||
}));
|
||||
|
||||
return (
|
||||
<RbModal
|
||||
title={t('ontology.export')}
|
||||
open={visible}
|
||||
onCancel={handleClose}
|
||||
okText={t('common.export')}
|
||||
onOk={handleSave}
|
||||
confirmLoading={loading}
|
||||
>
|
||||
<Form
|
||||
form={form}
|
||||
layout="vertical"
|
||||
initialValues={{ format: 'rdfxml' }}
|
||||
>
|
||||
<FormItem
|
||||
name="scene_id"
|
||||
label={t('ontology.scene_id')}
|
||||
rules={[{ required: true, message: t('common.pleaseEnter') }]}
|
||||
>
|
||||
<CustomSelect
|
||||
url={getOntologyScenesUrl}
|
||||
params={{ page: 1, pagesize: 100 }}
|
||||
valueKey="scene_id"
|
||||
labelKey="scene_name"
|
||||
hasAll={false}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</FormItem>
|
||||
|
||||
<FormItem
|
||||
name="format"
|
||||
label={t('ontology.format')}
|
||||
>
|
||||
<Select
|
||||
placeholder={t('common.pleaseSelect')}
|
||||
options={[
|
||||
{ value: 'rdfxml', label: 'RDF/XML' },
|
||||
{ value: 'turtle', label: 'Turtle' },
|
||||
]}
|
||||
/>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</RbModal>
|
||||
);
|
||||
});
|
||||
|
||||
export default OntologyExportModal;
|
||||
139
web/src/views/Ontology/components/OntologyImportModal.tsx
Normal file
139
web/src/views/Ontology/components/OntologyImportModal.tsx
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* @Author: ZhaoYing
|
||||
* @Date: 2026-02-03 14:10:32
|
||||
* @Last Modified by: ZhaoYing
|
||||
* @Last Modified time: 2026-02-03 14:10:32
|
||||
*/
|
||||
import { forwardRef, useImperativeHandle, useState } from 'react';
|
||||
import { Form, Input, App } from 'antd';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import type { OntologyImportModalData, OntologyImportModalRef } from '../types'
|
||||
import RbModal from '@/components/RbModal'
|
||||
import { ontologyImport } from '@/api/ontology'
|
||||
import UploadFiles from '@/components/Upload/UploadFiles';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
|
||||
/**
|
||||
* Props for OntologyImportModal component
|
||||
*/
|
||||
interface OntologyImportModalProps {
|
||||
/** Callback function to refresh parent list after import */
|
||||
refresh: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modal component for importing ontology files
|
||||
* Supports OWL, TTL, RDF, XML file formats
|
||||
*/
|
||||
const OntologyImportModal = forwardRef<OntologyImportModalRef, OntologyImportModalProps>(({
|
||||
refresh
|
||||
}, ref) => {
|
||||
// Hooks
|
||||
const { t } = useTranslation();
|
||||
const { message } = App.useApp();
|
||||
const [form] = Form.useForm<OntologyImportModalData>();
|
||||
|
||||
// State
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
/**
|
||||
* Close modal and reset form state
|
||||
*/
|
||||
const handleClose = () => {
|
||||
setVisible(false);
|
||||
form.resetFields();
|
||||
setLoading(false)
|
||||
};
|
||||
|
||||
/**
|
||||
* Open the import modal
|
||||
*/
|
||||
const handleOpen = () => {
|
||||
form.resetFields();
|
||||
setVisible(true);
|
||||
};
|
||||
|
||||
/**
|
||||
* Validate and submit form data to import ontology file
|
||||
* Creates FormData with file and scene information
|
||||
*/
|
||||
const handleSave = () => {
|
||||
form
|
||||
.validateFields()
|
||||
.then((values) => {
|
||||
const { scene_name, scene_description, file } = values
|
||||
console.log('values', file);
|
||||
const formData = new FormData();
|
||||
formData.append('file', file[0]);
|
||||
formData.append('scene_name', scene_name);
|
||||
if (scene_description) {
|
||||
formData.append('scene_description', scene_description);
|
||||
}
|
||||
setLoading(true)
|
||||
ontologyImport(formData)
|
||||
.then(() => {
|
||||
message.success(t('common.saveSuccess'));
|
||||
handleClose();
|
||||
refresh();
|
||||
})
|
||||
.finally(() => setLoading(false))
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log('err', err)
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Expose methods to parent component via ref
|
||||
*/
|
||||
useImperativeHandle(ref, () => ({
|
||||
handleOpen,
|
||||
}));
|
||||
|
||||
return (
|
||||
<RbModal
|
||||
title={t('ontology.import')}
|
||||
open={visible}
|
||||
onCancel={handleClose}
|
||||
okText={t('common.create')}
|
||||
onOk={handleSave}
|
||||
confirmLoading={loading}
|
||||
>
|
||||
<Form
|
||||
form={form}
|
||||
layout="vertical"
|
||||
>
|
||||
<FormItem
|
||||
name="scene_name"
|
||||
label={t('ontology.scene_name')}
|
||||
rules={[{ required: true, message: t('common.pleaseEnter') }]}
|
||||
>
|
||||
<Input placeholder={t('common.enter')} />
|
||||
</FormItem>
|
||||
<FormItem
|
||||
name="scene_description"
|
||||
label={t('ontology.scene_description')}
|
||||
>
|
||||
<Input.TextArea placeholder={t('common.enter')} />
|
||||
</FormItem>
|
||||
|
||||
<FormItem
|
||||
name="file"
|
||||
label={t('ontology.file')}
|
||||
rules={[{ required: true, message: t('common.pleaseSelect') }]}
|
||||
>
|
||||
<UploadFiles
|
||||
isCanDrag={true}
|
||||
fileType={['owl', 'ttl', 'rdf', 'xml']}
|
||||
isAutoUpload={false}
|
||||
/>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</RbModal>
|
||||
);
|
||||
});
|
||||
|
||||
export default OntologyImportModal;
|
||||
@@ -1,3 +1,9 @@
|
||||
/*
|
||||
* @Author: ZhaoYing
|
||||
* @Date: 2026-02-03 14:10:28
|
||||
* @Last Modified by: ZhaoYing
|
||||
* @Last Modified time: 2026-02-03 14:10:28
|
||||
*/
|
||||
import { forwardRef, useImperativeHandle, useState } from 'react';
|
||||
import { Form, Input, App } from 'antd';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -8,21 +14,34 @@ import { createOntologyScene, updateOntologyScene } from '@/api/ontology'
|
||||
|
||||
const FormItem = Form.Item;
|
||||
|
||||
/**
|
||||
* Props for OntologyModal component
|
||||
*/
|
||||
interface OntologyModalProps {
|
||||
/** Callback function to refresh parent list after save */
|
||||
refresh: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modal component for creating or editing ontology scenes
|
||||
* Provides form interface for scene name and description
|
||||
*/
|
||||
const OntologyModal = forwardRef<OntologyModalRef, OntologyModalProps>(({
|
||||
refresh
|
||||
}, ref) => {
|
||||
// Hooks
|
||||
const { t } = useTranslation();
|
||||
const { message } = App.useApp();
|
||||
const [form] = Form.useForm<OntologyModalData>();
|
||||
|
||||
// State
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [editVo, setEditVo] = useState<OntologyItem | null>(null)
|
||||
const [form] = Form.useForm<OntologyModalData>();
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
// 封装取消方法,添加关闭弹窗逻辑
|
||||
/**
|
||||
* Close modal and reset form state
|
||||
*/
|
||||
const handleClose = () => {
|
||||
setVisible(false);
|
||||
form.resetFields();
|
||||
@@ -30,6 +49,10 @@ const OntologyModal = forwardRef<OntologyModalRef, OntologyModalProps>(({
|
||||
setEditVo(null)
|
||||
};
|
||||
|
||||
/**
|
||||
* Open modal for creating or editing
|
||||
* @param vo - Optional ontology item data for edit mode
|
||||
*/
|
||||
const handleOpen = (vo?: OntologyItem) => {
|
||||
if (vo) {
|
||||
setEditVo(vo);
|
||||
@@ -39,7 +62,11 @@ const OntologyModal = forwardRef<OntologyModalRef, OntologyModalProps>(({
|
||||
}
|
||||
setVisible(true);
|
||||
};
|
||||
// 封装保存方法,添加提交逻辑
|
||||
|
||||
/**
|
||||
* Validate and submit form data
|
||||
* Creates new scene or updates existing one based on editVo
|
||||
*/
|
||||
const handleSave = () => {
|
||||
form
|
||||
.validateFields()
|
||||
@@ -59,7 +86,9 @@ const OntologyModal = forwardRef<OntologyModalRef, OntologyModalProps>(({
|
||||
});
|
||||
}
|
||||
|
||||
// 暴露给父组件的方法
|
||||
/**
|
||||
* Expose methods to parent component via ref
|
||||
*/
|
||||
useImperativeHandle(ref, () => ({
|
||||
handleOpen,
|
||||
}));
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
/*
|
||||
* @Author: ZhaoYing
|
||||
* @Date: 2026-02-03 14:10:24
|
||||
* @Last Modified by: ZhaoYing
|
||||
* @Last Modified time: 2026-02-03 14:10:56
|
||||
*/
|
||||
import { type FC, type ReactNode } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { Layout, Button } from 'antd';
|
||||
@@ -6,11 +12,23 @@ import logoutIcon from '@/assets/images/logout_hover.svg'
|
||||
|
||||
const { Header } = Layout;
|
||||
|
||||
/**
|
||||
* Props for PageHeader component
|
||||
*/
|
||||
interface ConfigHeaderProps {
|
||||
/** Page title/name */
|
||||
name?: string;
|
||||
/** Subtitle content displayed below the title */
|
||||
subTitle?: ReactNode | string;
|
||||
/** Extra content displayed on the right side */
|
||||
extra?: ReactNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Page header component for ontology pages
|
||||
* Displays title, subtitle, back button and extra actions
|
||||
* @param props - Component props
|
||||
*/
|
||||
const PageHeader: FC<ConfigHeaderProps> = ({
|
||||
name,
|
||||
subTitle,
|
||||
@@ -19,6 +37,9 @@ const PageHeader: FC<ConfigHeaderProps> = ({
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
|
||||
/**
|
||||
* Navigate back to previous page
|
||||
*/
|
||||
const goBack = () => {
|
||||
navigate(-1)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
/*
|
||||
* @Author: ZhaoYing
|
||||
* @Date: 2026-02-03 14:10:15
|
||||
* @Last Modified by: ZhaoYing
|
||||
* @Last Modified time: 2026-02-03 14:10:15
|
||||
*/
|
||||
import { type FC, useState, useRef, type MouseEvent } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -5,29 +11,57 @@ import { Row, Col, Button, Flex, Divider, Space, App, Tooltip } from 'antd'
|
||||
|
||||
import SearchInput from '@/components/SearchInput';
|
||||
import OntologyModal from './components/OntologyModal'
|
||||
import type { OntologyModalRef, OntologyItem, Query } from './types'
|
||||
import type { OntologyModalRef, OntologyItem, Query, OntologyImportModalRef, OntologyExportModalRef } from './types'
|
||||
import RbCard from '@/components/RbCard/Card'
|
||||
import Tag from '@/components/Tag'
|
||||
import PageScrollList, { type PageScrollListRef } from '@/components/PageScrollList'
|
||||
import { getOntologyScenesUrl, deleteOntologyScene } from '@/api/ontology'
|
||||
import { formatDateTime } from '@/utils/format'
|
||||
import OntologyImportModal from './components/OntologyImportModal'
|
||||
import OntologyExportModal from './components/OntologyExportModal'
|
||||
|
||||
/**
|
||||
* Ontology management page component
|
||||
* Displays a list of ontology scenes with search, create, import, export functionality
|
||||
*/
|
||||
const Ontology: FC = () => {
|
||||
// Hooks
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate()
|
||||
const { modal, message } = App.useApp();
|
||||
|
||||
// State
|
||||
const [query, setQuery] = useState<Query>({});
|
||||
|
||||
// Refs
|
||||
const scrollListRef = useRef<PageScrollListRef>(null)
|
||||
const entityModalRef = useRef<OntologyModalRef>(null)
|
||||
const ontologyImportModalRef = useRef<OntologyImportModalRef>(null)
|
||||
const ontologyExportModalRef = useRef<OntologyExportModalRef>(null)
|
||||
|
||||
/**
|
||||
* Open modal to create a new ontology scene
|
||||
*/
|
||||
const handleCreate = () => {
|
||||
entityModalRef.current?.handleOpen()
|
||||
}
|
||||
|
||||
/**
|
||||
* Open modal to edit an existing ontology scene
|
||||
* @param record - The ontology item to edit
|
||||
* @param e - Mouse event to prevent propagation
|
||||
*/
|
||||
const handleEdit = (record: OntologyItem, e: MouseEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
entityModalRef.current?.handleOpen(record)
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an ontology scene with confirmation
|
||||
* @param item - The ontology item to delete
|
||||
* @param e - Mouse event to prevent propagation
|
||||
*/
|
||||
const handleDelete = (item: OntologyItem, e: MouseEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
@@ -45,9 +79,35 @@ const Ontology: FC = () => {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigate to ontology detail page
|
||||
* @param record - The ontology item to view
|
||||
*/
|
||||
const handleJump = (record: OntologyItem) => {
|
||||
navigate(`/ontology/${record.scene_id}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the ontology list
|
||||
*/
|
||||
const handleRefresh = () => {
|
||||
scrollListRef.current?.refresh()
|
||||
}
|
||||
|
||||
/**
|
||||
* Open export modal
|
||||
*/
|
||||
const handleExport = () => {
|
||||
ontologyExportModalRef.current?.handleOpen()
|
||||
}
|
||||
|
||||
/**
|
||||
* Open import modal
|
||||
*/
|
||||
const handleImport = () => {
|
||||
ontologyImportModalRef.current?.handleOpen()
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -60,9 +120,17 @@ const Ontology: FC = () => {
|
||||
/>
|
||||
</Col>
|
||||
<Col span={16} className="rb:text-right">
|
||||
<Button type="primary" onClick={handleCreate}>
|
||||
+ {t('ontology.create')}
|
||||
</Button>
|
||||
<Space size={12}>
|
||||
<Button onClick={handleExport}>
|
||||
{t('ontology.export')}
|
||||
</Button>
|
||||
<Button onClick={handleImport}>
|
||||
{t('ontology.import')}
|
||||
</Button>
|
||||
<Button type="primary" onClick={handleCreate}>
|
||||
+ {t('ontology.create')}
|
||||
</Button>
|
||||
</Space>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
@@ -124,7 +192,15 @@ const Ontology: FC = () => {
|
||||
|
||||
<OntologyModal
|
||||
ref={entityModalRef}
|
||||
refresh={() => scrollListRef.current?.refresh()}
|
||||
refresh={handleRefresh}
|
||||
/>
|
||||
<OntologyImportModal
|
||||
ref={ontologyImportModalRef}
|
||||
refresh={handleRefresh}
|
||||
/>
|
||||
<OntologyExportModal
|
||||
ref={ontologyExportModalRef}
|
||||
refresh={handleRefresh}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
/*
|
||||
* @Author: ZhaoYing
|
||||
* @Date: 2026-02-03 14:10:20
|
||||
* @Last Modified by: ZhaoYing
|
||||
* @Last Modified time: 2026-02-03 14:10:20
|
||||
*/
|
||||
import { type FC, useEffect, useState, useRef } from 'react'
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -12,22 +18,35 @@ import SearchInput from '@/components/SearchInput';
|
||||
import OntologyClassExtractModal from '../components/OntologyClassExtractModal'
|
||||
import BodyWrapper from '@/components/Empty/BodyWrapper'
|
||||
|
||||
/**
|
||||
* Ontology detail page component
|
||||
* Displays and manages classes within a specific ontology scene
|
||||
*/
|
||||
const Detail: FC = () => {
|
||||
// Hooks
|
||||
const { t } = useTranslation();
|
||||
const { id } = useParams()
|
||||
const { modal, message } = App.useApp()
|
||||
|
||||
// Refs
|
||||
const ontologyClassModalRef = useRef<OntologyClassModalRef>(null)
|
||||
const ontologyClassExtractModalRef = useRef<OntologyClassExtractModalRef>(null)
|
||||
|
||||
// State
|
||||
const [query, setQuery] = useState<{
|
||||
class_name?: string;
|
||||
}>({});
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [data, setData] = useState<OntologyClassData>({} as OntologyClassData)
|
||||
|
||||
// Fetch data when component mounts or dependencies change
|
||||
useEffect(() => {
|
||||
getData()
|
||||
}, [id, query])
|
||||
|
||||
/**
|
||||
* Fetch ontology class list data
|
||||
*/
|
||||
const getData = () => {
|
||||
if (!id) return;
|
||||
setLoading(true)
|
||||
@@ -42,6 +61,11 @@ const Detail: FC = () => {
|
||||
setLoading(false)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an ontology class with confirmation
|
||||
* @param item - The class item to delete
|
||||
*/
|
||||
const handleDelete = (item: OntologyClassItem) => {
|
||||
modal.confirm({
|
||||
title: t('common.confirmDeleteDesc', { name: item.class_name }),
|
||||
@@ -57,9 +81,17 @@ const Detail: FC = () => {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Open modal to add a new class
|
||||
*/
|
||||
const handleAdd = () => {
|
||||
ontologyClassModalRef.current?.handleOpen(data.scene_id)
|
||||
}
|
||||
|
||||
/**
|
||||
* Open modal to extract classes using LLM
|
||||
*/
|
||||
const handleExtract = () => {
|
||||
ontologyClassExtractModalRef.current?.handleOpen(data)
|
||||
}
|
||||
|
||||
@@ -1,79 +1,214 @@
|
||||
/*
|
||||
* @Author: ZhaoYing
|
||||
* @Date: 2026-02-03 14:10:10
|
||||
* @Last Modified by: ZhaoYing
|
||||
* @Last Modified time: 2026-02-03 14:10:10
|
||||
*/
|
||||
/**
|
||||
* Query parameters for ontology list pagination and filtering
|
||||
*/
|
||||
export interface Query {
|
||||
/** Number of items per page */
|
||||
pagesize?: number;
|
||||
/** Current page number */
|
||||
page?: number;
|
||||
/** Scene name for filtering */
|
||||
scene_name?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ontology scene item data structure
|
||||
*/
|
||||
export interface OntologyItem {
|
||||
/** Unique identifier for the scene */
|
||||
scene_id: string;
|
||||
/** Name of the ontology scene */
|
||||
scene_name: string;
|
||||
/** Description of the ontology scene */
|
||||
scene_description: string;
|
||||
/** Number of entity types in the scene */
|
||||
type_num: number;
|
||||
/** Array of entity type names */
|
||||
entity_type: string[];
|
||||
/** Associated workspace identifier */
|
||||
workspace_id: string;
|
||||
/** Creation timestamp */
|
||||
created_at: number;
|
||||
/** Last update timestamp */
|
||||
updated_at: number;
|
||||
/** Total count of classes in the scene */
|
||||
classes_count: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Form data for creating/editing ontology scene
|
||||
*/
|
||||
export interface OntologyModalData {
|
||||
/** Scene name */
|
||||
scene_name: string;
|
||||
/** Scene description */
|
||||
scene_description: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ref methods exposed by OntologyModal component
|
||||
*/
|
||||
export interface OntologyModalRef {
|
||||
/**
|
||||
* Open the modal for creating or editing
|
||||
* @param data - Optional ontology item data for editing mode
|
||||
*/
|
||||
handleOpen: (data?: OntologyItem) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ontology class item data structure
|
||||
*/
|
||||
export interface OntologyClassItem {
|
||||
/** Unique identifier for the class */
|
||||
class_id: string;
|
||||
/** Name of the class */
|
||||
class_name: string;
|
||||
/** Description of the class */
|
||||
class_description: string;
|
||||
/** Associated scene identifier */
|
||||
scene_id: string;
|
||||
/** Creation timestamp */
|
||||
created_at: number;
|
||||
/** Last update timestamp */
|
||||
updated_at: number;
|
||||
}
|
||||
/**
|
||||
* Response data structure for ontology class list
|
||||
*/
|
||||
export interface OntologyClassData {
|
||||
/** Total number of classes */
|
||||
total: number;
|
||||
/** Scene identifier */
|
||||
scene_id: string;
|
||||
/** Scene name */
|
||||
scene_name: string;
|
||||
/** Scene description */
|
||||
scene_description: string;
|
||||
/** Array of class items */
|
||||
items: OntologyClassItem[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Data structure for adding a new class
|
||||
*/
|
||||
export interface AddClassItem {
|
||||
/** Name of the class to add */
|
||||
class_name: string;
|
||||
/** Description of the class to add */
|
||||
class_description: string;
|
||||
}
|
||||
/**
|
||||
* Form data for creating ontology classes
|
||||
*/
|
||||
export interface OntologyClassModalData {
|
||||
/** Target scene identifier */
|
||||
scene_id: string;
|
||||
/** Array of classes to create */
|
||||
classes: AddClassItem[]
|
||||
}
|
||||
/**
|
||||
* Ref methods exposed by OntologyClassModal component
|
||||
*/
|
||||
export interface OntologyClassModalRef {
|
||||
/**
|
||||
* Open the modal for adding classes
|
||||
* @param scene_id - Target scene identifier
|
||||
*/
|
||||
handleOpen: (scene_id: string) => void;
|
||||
}
|
||||
/**
|
||||
* Form data for extracting ontology classes using LLM
|
||||
*/
|
||||
export interface OntologyClassExtractModalData {
|
||||
/** LLM model identifier */
|
||||
llm_id: string;
|
||||
/** Target scene identifier */
|
||||
scene_id: string;
|
||||
/** Scenario description for extraction */
|
||||
scenario: string;
|
||||
domain: string; // scene_name
|
||||
/** Domain name (same as scene_name) */
|
||||
domain: string;
|
||||
}
|
||||
/**
|
||||
* Ref methods exposed by OntologyClassExtractModal component
|
||||
*/
|
||||
export interface OntologyClassExtractModalRef {
|
||||
/**
|
||||
* Open the modal for extracting classes
|
||||
* @param vo - Ontology class data containing scene information
|
||||
*/
|
||||
handleOpen: (vo: OntologyClassData) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracted class item from LLM
|
||||
*/
|
||||
export interface ExtractClassItem {
|
||||
/** Unique identifier for the extracted class */
|
||||
id: string;
|
||||
/** English name of the class */
|
||||
name: string;
|
||||
/** Chinese name of the class */
|
||||
name_chinese: string;
|
||||
/** Description of the class */
|
||||
description: string;
|
||||
/** Example instances of the class */
|
||||
examples: string[];
|
||||
/** Parent class name if exists */
|
||||
parent_class: string | null;
|
||||
/** Entity type classification */
|
||||
entity_type: string;
|
||||
/** Domain the class belongs to */
|
||||
domain: string;
|
||||
}
|
||||
/**
|
||||
* Response data structure for class extraction
|
||||
*/
|
||||
export interface ExtractData {
|
||||
/** Domain name */
|
||||
domain: string;
|
||||
/** Number of classes extracted */
|
||||
extracted_count: number;
|
||||
/** Array of extracted class items */
|
||||
classes: ExtractClassItem[]
|
||||
}
|
||||
/**
|
||||
* Ref methods exposed by OntologyImportModal component
|
||||
*/
|
||||
export interface OntologyImportModalRef {
|
||||
/** Open the import modal */
|
||||
handleOpen: () => void;
|
||||
}
|
||||
/**
|
||||
* Form data for importing ontology
|
||||
*/
|
||||
export interface OntologyImportModalData {
|
||||
/** Name for the imported scene */
|
||||
scene_name: string;
|
||||
/** Optional description for the imported scene */
|
||||
scene_description?: string;
|
||||
/** File to import (OWL, TTL, RDF, XML formats) */
|
||||
file: any;
|
||||
}
|
||||
/**
|
||||
* Ref methods exposed by OntologyExportModal component
|
||||
*/
|
||||
export interface OntologyExportModalRef {
|
||||
/** Open the export modal */
|
||||
handleOpen: () => void;
|
||||
}
|
||||
/**
|
||||
* Form data for exporting ontology
|
||||
*/
|
||||
export interface OntologyExportModalData {
|
||||
/** Scene identifier to export */
|
||||
scene_id: string;
|
||||
/** Export format: 'rdfxml' (.owl) or 'turtle' (.ttl) */
|
||||
format: 'rdfxml' | 'turtle';
|
||||
}
|
||||
Reference in New Issue
Block a user