From 0b3fbd8d4fbd3e89b23586c577627c43e5f02e91 Mon Sep 17 00:00:00 2001 From: Ivan <8611739+IRBorisov@users.noreply.github.com> Date: Sat, 17 Aug 2024 22:31:24 +0300 Subject: [PATCH] M: Implement RSForm sorting for OSS and small UI fixes --- .../src/components/select/PickSchema.tsx | 41 ++++++++++--------- .../src/dialogs/DlgChangeInputSchema.tsx | 8 +++- .../DlgCreateOperation/TabInputOperation.tsx | 12 ++++-- .../dialogs/DlgInlineSynthesis/TabSchema.tsx | 4 +- rsconcept/frontend/src/models/ossAPI.ts | 29 ++++++++++++- .../EditorOssGraph/NodeContextMenu.tsx | 4 +- .../src/pages/OssPage/OssEditContext.tsx | 14 ++++++- rsconcept/frontend/src/utils/labels.ts | 3 +- 8 files changed, 84 insertions(+), 31 deletions(-) diff --git a/rsconcept/frontend/src/components/select/PickSchema.tsx b/rsconcept/frontend/src/components/select/PickSchema.tsx index f1d267fb..0996d6f3 100644 --- a/rsconcept/frontend/src/components/select/PickSchema.tsx +++ b/rsconcept/frontend/src/components/select/PickSchema.tsx @@ -4,9 +4,8 @@ import { useIntl } from 'react-intl'; import DataTable, { createColumnHelper, IConditionalStyle } from '@/components/ui/DataTable'; import SearchBar from '@/components/ui/SearchBar'; import { useConceptOptions } from '@/context/ConceptOptionsContext'; -import { useLibrary } from '@/context/LibraryContext'; import { ILibraryItem, LibraryItemID, LibraryItemType } from '@/models/library'; -import { ILibraryFilter } from '@/models/miscellaneous'; +import { matchLibraryItem } from '@/models/libraryAPI'; import FlexColumn from '../ui/FlexColumn'; @@ -15,6 +14,8 @@ interface PickSchemaProps { initialFilter?: string; rows?: number; + items: ILibraryItem[]; + itemType: LibraryItemType; value?: LibraryItemID; baseFilter?: (target: ILibraryItem) => boolean; onSelectValue: (newValue: LibraryItemID) => void; @@ -22,31 +23,31 @@ interface PickSchemaProps { const columnHelper = createColumnHelper(); -function PickSchema({ id, initialFilter = '', rows = 4, value, onSelectValue, baseFilter }: PickSchemaProps) { +function PickSchema({ + id, + initialFilter = '', + rows = 4, + items, + itemType, + value, + onSelectValue, + baseFilter +}: PickSchemaProps) { const intl = useIntl(); const { colors } = useConceptOptions(); - const library = useLibrary(); const [filterText, setFilterText] = useState(initialFilter); - const [filter, setFilter] = useState({}); - const [items, setItems] = useState([]); + const [filtered, setFiltered] = useState([]); + const baseFiltered = useMemo( + () => items.filter(item => item.item_type === itemType && (!baseFilter || baseFilter(item))), + [items, itemType, baseFilter] + ); useLayoutEffect(() => { - setFilter({ - query: filterText, - type: LibraryItemType.RSFORM - }); + const newFiltered = baseFiltered.filter(item => matchLibraryItem(item, filterText)); + setFiltered(newFiltered); }, [filterText]); - useLayoutEffect(() => { - const filtered = library.applyFilter(filter); - if (baseFilter) { - setItems(filtered.filter(baseFilter)); - } else { - setItems(filtered); - } - }, [library, filter, filter.query, baseFilter]); - const columns = useMemo( () => [ columnHelper.accessor('alias', { @@ -106,7 +107,7 @@ function PickSchema({ id, initialFilter = '', rows = 4, value, onSelectValue, ba noHeader noFooter className='text-sm select-none cc-scroll-y' - data={items} + data={filtered} columns={columns} conditionalRowStyles={conditionalRowStyles} noDataComponent={ diff --git a/rsconcept/frontend/src/dialogs/DlgChangeInputSchema.tsx b/rsconcept/frontend/src/dialogs/DlgChangeInputSchema.tsx index c9a4e17b..d4e7f679 100644 --- a/rsconcept/frontend/src/dialogs/DlgChangeInputSchema.tsx +++ b/rsconcept/frontend/src/dialogs/DlgChangeInputSchema.tsx @@ -8,8 +8,10 @@ import PickSchema from '@/components/select/PickSchema'; import Label from '@/components/ui/Label'; import MiniButton from '@/components/ui/MiniButton'; import Modal, { ModalProps } from '@/components/ui/Modal'; -import { ILibraryItem, LibraryItemID } from '@/models/library'; +import { useLibrary } from '@/context/LibraryContext'; +import { ILibraryItem, LibraryItemID, LibraryItemType } from '@/models/library'; import { IOperation, IOperationSchema } from '@/models/oss'; +import { sortItemsForOSS } from '@/models/ossAPI'; interface DlgChangeInputSchemaProps extends Pick { oss: IOperationSchema; @@ -19,6 +21,8 @@ interface DlgChangeInputSchemaProps extends Pick { function DlgChangeInputSchema({ oss, hideWindow, target, onSubmit }: DlgChangeInputSchemaProps) { const [selected, setSelected] = useState(target.result ?? undefined); + const library = useLibrary(); + const sortedItems = useMemo(() => sortItemsForOSS(oss, library.items), [oss, library.items]); const baseFilter = useCallback( (item: ILibraryItem) => !oss.schemas.includes(item.id) || item.id === selected || item.id === target.result, @@ -55,6 +59,8 @@ function DlgChangeInputSchema({ oss, hideWindow, target, onSubmit }: DlgChangeIn !oss.schemas.includes(item.id), [oss]); + const library = useLibrary(); + const sortedItems = useMemo(() => sortItemsForOSS(oss, library.items), [oss, library.items]); useEffect(() => { if (createSchema) { @@ -102,7 +106,9 @@ function TabInputOperation({ {!createSchema ? ( item.location === oss.location); + for (const item of items) { + if (item.visible && item.owner === oss.owner && !result.includes(item)) { + result.push(item); + } + } + for (const item of result) { + if (item.visible && !result.includes(item)) { + result.push(item); + } + } + for (const item of result) { + if (!result.includes(item)) { + result.push(item); + } + } + return result; +} diff --git a/rsconcept/frontend/src/pages/OssPage/EditorOssGraph/NodeContextMenu.tsx b/rsconcept/frontend/src/pages/OssPage/EditorOssGraph/NodeContextMenu.tsx index 9e866b26..2b38bba6 100644 --- a/rsconcept/frontend/src/pages/OssPage/EditorOssGraph/NodeContextMenu.tsx +++ b/rsconcept/frontend/src/pages/OssPage/EditorOssGraph/NodeContextMenu.tsx @@ -113,8 +113,8 @@ function NodeContextMenu({ {operation.result ? ( } disabled={controller.isProcessing} onClick={handleOpenSchema} diff --git a/rsconcept/frontend/src/pages/OssPage/OssEditContext.tsx b/rsconcept/frontend/src/pages/OssPage/OssEditContext.tsx index e81a2915..a4ae2e37 100644 --- a/rsconcept/frontend/src/pages/OssPage/OssEditContext.tsx +++ b/rsconcept/frontend/src/pages/OssPage/OssEditContext.tsx @@ -8,6 +8,7 @@ import { urls } from '@/app/urls'; import { useAccessMode } from '@/context/AccessModeContext'; import { useAuth } from '@/context/AuthContext'; import { useConceptOptions } from '@/context/ConceptOptionsContext'; +import { useLibrary } from '@/context/LibraryContext'; import { useConceptNavigation } from '@/context/NavigationContext'; import { useOSS } from '@/context/OssContext'; import DlgChangeInputSchema from '@/dialogs/DlgChangeInputSchema'; @@ -30,7 +31,7 @@ import { } from '@/models/oss'; import { UserID, UserLevel } from '@/models/user'; import { PARAMETER } from '@/utils/constants'; -import { information } from '@/utils/labels'; +import { errors, information } from '@/utils/labels'; export interface ICreateOperationPrompt { x: number; @@ -95,6 +96,7 @@ export const OssEditState = ({ selected, setSelected, children }: OssEditStatePr const { adminMode } = useConceptOptions(); const { accessLevel, setAccessLevel } = useAccessMode(); const model = useOSS(); + const library = useLibrary(); const isMutable = useMemo( () => accessLevel > UserLevel.READER && !model.schema?.read_only, @@ -307,12 +309,20 @@ export const OssEditState = ({ selected, setSelected, children }: OssEditStatePr const createInput = useCallback( (target: OperationID, positions: IOperationPosition[]) => { + const operation = model.schema?.operationByID.get(target); + if (!model.schema || !operation) { + return; + } + if (library.items.find(item => item.alias === operation.alias && item.location === model.schema!.location)) { + toast.error(errors.inputAlreadyExists); + return; + } model.createInput({ target: target, positions: positions }, new_schema => { toast.success(information.newLibraryItem); router.push(urls.schema(new_schema.id)); }); }, - [model, router] + [model, library.items, router] ); const promptEditInput = useCallback((target: OperationID, positions: IOperationPosition[]) => { diff --git a/rsconcept/frontend/src/utils/labels.ts b/rsconcept/frontend/src/utils/labels.ts index 41d9d606..be208496 100644 --- a/rsconcept/frontend/src/utils/labels.ts +++ b/rsconcept/frontend/src/utils/labels.ts @@ -953,7 +953,8 @@ export const errors = { passwordsMismatch: 'Пароли не совпадают', imageFailed: 'Ошибка при создании изображения', reuseOriginal: 'Повторное использование удаляемой конституенты при отождествлении', - substituteInherited: 'Нельзя удалять наследованные конституенты при отождествлении' + substituteInherited: 'Нельзя удалять наследованные конституенты при отождествлении', + inputAlreadyExists: 'Концептуальная схема с таким именем уже существует' }; /**