Implementing Synthesis frontend pt1
Some checks failed
Backend CI / build (3.12) (push) Waiting to run
Frontend CI / build (18.x) (push) Has been cancelled

This commit is contained in:
Ivan 2024-07-14 14:41:05 +03:00
parent 5b0321b9d1
commit 6f3d3c830e
17 changed files with 1346 additions and 1442 deletions

View File

@ -124,6 +124,7 @@
"pymorphy",
"Quantor",
"razdel",
"reactflow",
"reagraph",
"redef",
"REDOC",

View File

@ -1,22 +1,4 @@
[
{
"model": "auth.user",
"pk": 1,
"fields": {
"password": "pbkdf2_sha256$720000$gFZkaBswurtL0naQKiUnW7$3b6SUN3fY2Xl1H7erAszVpQl2LpoKusan+yJP7Bp3JA=",
"last_login": "2024-06-03T20:57:02.522Z",
"is_superuser": true,
"username": "admin",
"first_name": "Администратор",
"last_name": "",
"email": "admin@mail.ru",
"is_staff": true,
"is_active": true,
"date_joined": "2024-05-27T18:31:48.913Z",
"groups": [],
"user_permissions": []
}
},
{
"model": "auth.user",
"pk": 3,

View File

@ -7,7 +7,7 @@ drf-spectacular==0.27.2
drf-spectacular-sidecar==2024.6.1
coreapi==2.3.3
django-rest-passwordreset==1.4.1
cctext==0.1.3
cctext==0.1.4
pyconcept==0.1.6
psycopg2-binary==2.9.9

File diff suppressed because it is too large Load Diff

View File

@ -13,12 +13,12 @@
},
"dependencies": {
"@lezer/lr": "^1.4.1",
"@tanstack/react-table": "^8.17.3",
"@uiw/codemirror-themes": "^4.22.2",
"@uiw/react-codemirror": "^4.22.2",
"@tanstack/react-table": "^8.19.3",
"@uiw/codemirror-themes": "^4.23.0",
"@uiw/react-codemirror": "^4.23.0",
"axios": "^1.7.2",
"clsx": "^2.1.1",
"framer-motion": "^11.0.10",
"framer-motion": "^11.3.2",
"js-file-download": "^0.4.12",
"react": "^18.3.1",
"react-dom": "^18.3.1",
@ -26,36 +26,37 @@
"react-icons": "^5.2.1",
"react-intl": "^6.6.8",
"react-loader-spinner": "^6.1.6",
"react-pdf": "^9.0.0",
"react-router-dom": "^6.24.0",
"react-pdf": "^9.1.0",
"react-router-dom": "^6.24.1",
"react-select": "^5.8.0",
"react-tabs": "^6.0.2",
"react-toastify": "^10.0.5",
"react-tooltip": "^5.27.0",
"react-tooltip": "^5.27.1",
"reactflow": "^11.11.4",
"reagraph": "^4.19.2",
"use-debounce": "^10.0.1"
},
"devDependencies": {
"@lezer/generator": "^1.7.1",
"@types/jest": "^29.5.12",
"@types/node": "^20.14.9",
"@types/node": "^20.14.10",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@typescript-eslint/eslint-plugin": "^7.14.1",
"@typescript-eslint/parser": "^7.14.1",
"@typescript-eslint/eslint-plugin": "^7.16.0",
"@typescript-eslint/parser": "^7.16.0",
"@vitejs/plugin-react": "^4.3.1",
"autoprefixer": "^10.4.19",
"eslint": "^8.57.0",
"eslint-plugin-react-hooks": "^4.6.2",
"eslint-plugin-react-refresh": "^0.4.7",
"eslint-plugin-simple-import-sort": "^12.1.0",
"eslint-plugin-react-refresh": "^0.4.8",
"eslint-plugin-simple-import-sort": "^12.1.1",
"eslint-plugin-tsdoc": "^0.3.0",
"jest": "^29.7.0",
"postcss": "^8.4.38",
"postcss": "^8.4.39",
"tailwindcss": "^3.4.4",
"ts-jest": "^29.1.5",
"typescript": "^5.5.2",
"vite": "^5.3.1"
"ts-jest": "^29.2.2",
"typescript": "^5.5.3",
"vite": "^5.3.3"
},
"jest": {
"preset": "ts-jest",

View File

@ -234,6 +234,7 @@ export function postCloneLibraryItem(target: string, request: FrontExchange<IRSF
}
export function getOssDetails(target: string, request: FrontPull<IOperationSchemaData>) {
request.setLoading!(false);
request.onSuccess({
id: Number(target),
comment: '123',

View File

@ -48,6 +48,7 @@ function EditorOssCard({ isModified, onDestroy, setIsModified }: EditorOssCardPr
anonymous={!user}
onSubmit={initiateSubmit}
onDestroy={onDestroy}
controller={controller}
/>
<AnimateFade onKeyDown={handleInput} className={clsx('sm:w-fit mx-auto', 'flex flex-col sm:flex-row')}>
<FlexColumn className='px-3'>

View File

@ -1,14 +1,21 @@
'use client';
import { ReactFlowProvider } from 'reactflow';
import AnimateFade from '@/components/wrap/AnimateFade';
import { useOssEdit } from '../OssEditContext';
import OssFlow from './OssFlow';
function EditorOssGraph() {
// TODO: Implement OSS editing UI here
const controller = useOssEdit();
return (
<AnimateFade>
<div className='py-3'>Реализация графического интерфейса</div>
</AnimateFade>
<ReactFlowProvider>
<AnimateFade>
<OssFlow controller={controller} />
</AnimateFade>
</ReactFlowProvider>
);
}

View File

@ -0,0 +1,58 @@
import { CiSquareRemove } from 'react-icons/ci';
import { PiPlugsConnected } from 'react-icons/pi';
import { Handle, Position } from 'reactflow';
import MiniButton from '@/components/ui/MiniButton.tsx';
import { useOssEdit } from '../OssEditContext';
interface InputNodeProps {
id: string;
}
function InputNode({ id }: InputNodeProps) {
const controller = useOssEdit();
console.log(controller.isMutable);
const handleDelete = () => {
console.log('delete node ' + id);
};
const handleClick = () => {
// controller.selectNode(id);
// controller.showSelectInput();
};
return (
<>
<Handle type='target' position={Position.Bottom} />
<div>
<MiniButton
className='float-right'
icon={<CiSquareRemove className='icon-red' />}
title='Удалить'
onClick={handleDelete}
color={'red'}
/>
<div>
Тип: <strong>Ввод</strong>
</div>
<div>
{/* Схема:{controller.getBind(id) === undefined ? '' : controller.getBind(id)} */}
<strong>
<MiniButton
className='float-right'
icon={<PiPlugsConnected className='icon-green' />}
title='Привязать схему'
onClick={() => {
handleClick();
}}
/>
</strong>
</div>
</div>
</>
);
}
export default InputNode;

View File

@ -0,0 +1,70 @@
import { CiSquareRemove } from 'react-icons/ci';
import { IoGitNetworkSharp } from 'react-icons/io5';
import { VscDebugStart } from 'react-icons/vsc';
import { Handle, Position } from 'reactflow';
import MiniButton from '@/components/ui/MiniButton.tsx';
import { useOssEdit } from '../OssEditContext';
interface OperationNodeProps {
id: string;
}
function OperationNode({ id }: OperationNodeProps) {
const controller = useOssEdit();
console.log(controller.isMutable);
const handleDelete = () => {
console.log('delete node ' + id);
// onDelete(id);
};
const handleEditOperation = () => {
console.log('edit operation ' + id);
//controller.selectNode(id);
//controller.showSynthesis();
};
const handleRunOperation = () => {
console.log('run operation');
// controller.singleSynthesis(id);
};
return (
<>
<Handle type='target' position={Position.Bottom} />
<div>
<MiniButton
className='float-right'
icon={<CiSquareRemove className='icon-red' />}
title='Удалить'
onClick={handleDelete}
color={'red'}
/>
<div>
Тип: <strong>Отождествление</strong>
</div>
<div>
Схема: <strong></strong>
<MiniButton
className='float-right'
icon={<VscDebugStart className='icon-green' />}
title='Синтез'
onClick={() => handleRunOperation()}
/>
<MiniButton
className='float-right'
icon={<IoGitNetworkSharp className='icon-green' />}
title='Отождествления'
onClick={() => handleEditOperation()}
/>
</div>
</div>
<Handle type='source' position={Position.Top} id='a' style={{ left: 50 }} />
<Handle type='source' position={Position.Top} id='b' style={{ right: 50, left: 'auto' }} />
</>
);
}
export default OperationNode;

View File

@ -0,0 +1,50 @@
'use client';
import { useMemo } from 'react';
import { NodeTypes, ProOptions, ReactFlow } from 'reactflow';
import { useConceptOptions } from '@/context/ConceptOptionsContext';
import { useOSS } from '@/context/OssContext';
import { IOssEditContext } from '../OssEditContext';
import InputNode from './InputNode';
import OperationNode from './OperationNode';
const OssNodeTypes: NodeTypes = {
synthesis: OperationNode,
input: InputNode
};
interface OssFlowProps {
controller: IOssEditContext;
}
function OssFlow({ controller }: OssFlowProps) {
const { calculateHeight } = useConceptOptions();
const model = useOSS();
console.log(model.loading);
console.log(controller.isMutable);
const initialNodes = [
{ id: '1', position: { x: 0, y: 0 }, data: { label: '1' }, type: 'input' },
{ id: '2', position: { x: 0, y: 100 }, data: { label: '2' }, type: 'synthesis' }
];
const initialEdges = [{ id: 'e1-2', source: '1', target: '2' }];
const proOptions: ProOptions = { hideAttribution: true };
const canvasWidth = useMemo(() => {
return 'calc(100vw - 1rem)';
}, []);
const canvasHeight = useMemo(() => calculateHeight('1.75rem + 4px'), [calculateHeight]);
return (
<div className='relative' style={{ height: canvasHeight, width: canvasWidth }}>
<ReactFlow nodes={initialNodes} edges={initialEdges} fitView proOptions={proOptions} nodeTypes={OssNodeTypes} />
</div>
);
}
export default OssFlow;

View File

@ -15,7 +15,7 @@ import { IOperationSchema } from '@/models/oss';
import { UserID, UserLevel } from '@/models/user';
import { information } from '@/utils/labels';
interface IOssEditContext {
export interface IOssEditContext {
schema?: IOperationSchema;
isMutable: boolean;

View File

@ -49,6 +49,7 @@ function EditorRSFormCard({ isModified, onDestroy, setIsModified }: EditorRSForm
anonymous={!user}
onSubmit={initiateSubmit}
onDestroy={onDestroy}
controller={controller}
/>
<AnimateFade
onKeyDown={handleInput}

View File

@ -8,29 +8,34 @@ import BadgeHelp from '@/components/info/BadgeHelp';
import MiniButton from '@/components/ui/MiniButton';
import Overlay from '@/components/ui/Overlay';
import { useAccessMode } from '@/context/AccessModeContext';
import { AccessPolicy } from '@/models/library';
import { AccessPolicy, ILibraryItemEditor } from '@/models/library';
import { HelpTopic } from '@/models/miscellaneous';
import { UserLevel } from '@/models/user';
import { PARAMETER } from '@/utils/constants';
import { prepareTooltip, tooltips } from '@/utils/labels';
import { useRSEdit } from '../RSEditContext';
interface ToolbarRSFormCardProps {
modified: boolean;
subscribed: boolean;
anonymous: boolean;
onSubmit: () => void;
onDestroy: () => void;
controller: ILibraryItemEditor;
}
function ToolbarRSFormCard({ modified, anonymous, subscribed, onSubmit, onDestroy }: ToolbarRSFormCardProps) {
const controller = useRSEdit();
function ToolbarRSFormCard({
modified,
anonymous,
controller,
subscribed,
onSubmit,
onDestroy
}: ToolbarRSFormCardProps) {
const { accessLevel } = useAccessMode();
const canSave = useMemo(() => modified && !controller.isProcessing, [modified, controller.isProcessing]);
return (
<Overlay position='top-1 right-1/2 translate-x-1/2' className='cc-icons'>
{controller.isContentEditable || modified ? (
{controller.isMutable || modified ? (
<MiniButton
titleHtml={prepareTooltip('Сохранить изменения', 'Ctrl + S')}
disabled={!canSave}
@ -56,7 +61,7 @@ function ToolbarRSFormCard({ modified, anonymous, subscribed, onSubmit, onDestro
<MiniButton
title='Удалить схему'
icon={<IconDestroy size='1.25rem' className='icon-red' />}
disabled={!controller.isContentEditable || controller.isProcessing || accessLevel < UserLevel.OWNER}
disabled={!controller.isMutable || controller.isProcessing || accessLevel < UserLevel.OWNER}
onClick={onDestroy}
/>
) : null}

View File

@ -8,8 +8,8 @@ import { toast } from 'react-toastify';
import { urls } from '@/app/urls';
import { useAccessMode } from '@/context/AccessModeContext';
import { useAuth } from '@/context/AuthContext';
import { useConceptNavigation } from '@/context/NavigationContext';
import { useConceptOptions } from '@/context/ConceptOptionsContext';
import { useConceptNavigation } from '@/context/NavigationContext';
import { useRSForm } from '@/context/RSFormContext';
import DlgChangeLocation from '@/dialogs/DlgChangeLocation';
import DlgCloneLibraryItem from '@/dialogs/DlgCloneLibraryItem';
@ -46,7 +46,7 @@ import { EXTEOR_TRS_FILE } from '@/utils/constants';
import { information, prompts } from '@/utils/labels';
import { promptUnsaved } from '@/utils/utils';
interface IRSEditContext {
export interface IRSEditContext {
schema?: IRSForm;
selected: ConstituentaID[];

View File

@ -3,3 +3,4 @@
*/
@import 'react-toastify/dist/ReactToastify.css';
@import 'reactflow/dist/style.css';

View File

@ -33,3 +33,22 @@
color: var(--cd-fg-60);
}
}
.Flow {
flex-grow: 1;
font-size: 12px;
}
.react-flow__node-input {
border: 1px solid #555;
padding: 10px;
width: 150px;
border-radius: 5px;
}
.react-flow__node-synthesis {
border: 1px solid #555;
padding: 10px;
width: 250px;
border-radius: 5px;
}