From 6bb02c646271f935fbe9ddd20754a1504b66849d Mon Sep 17 00:00:00 2001 From: Ivan <8611739+IRBorisov@users.noreply.github.com> Date: Wed, 12 Feb 2025 20:53:01 +0300 Subject: [PATCH] R: Refine feature boundaries and dependencies --- .../frontend/src/backend/configuration.ts | 15 ++ .../frontend/src/features/auth/backend/api.ts | 78 +------- .../src/features/auth/backend/types.ts | 71 +++++++ .../auth/backend/useChangePassword.tsx | 3 +- .../src/features/auth/backend/useLogin.tsx | 3 +- .../auth/backend/useRequestPasswordReset.tsx | 3 +- .../auth/backend/useResetPassword.tsx | 3 +- .../src/features/auth/pages/LoginPage.tsx | 2 +- .../src/features/library/backend/api.ts | 160 +++------------ .../src/features/library/backend/types.ts | 122 ++++++++++++ .../features/library/backend/useCloneItem.tsx | 3 +- .../library/backend/useCreateItem.tsx | 3 +- .../library/backend/useDeleteItem.tsx | 12 +- .../library/backend/useMutatingLibrary.tsx | 11 +- .../library/backend/useRenameLocation.tsx | 12 +- .../library/backend/useSetAccessPolicy.tsx | 21 +- .../library/backend/useSetEditors.tsx | 17 +- .../library/backend/useSetLocation.tsx | 19 +- .../features/library/backend/useSetOwner.tsx | 15 +- .../library/backend/useUpdateItem.tsx | 17 +- .../library/backend/useVersionCreate.tsx | 10 +- .../library/backend/useVersionDelete.tsx | 22 +-- .../library/backend/useVersionRestore.tsx | 7 +- .../library/backend/useVersionUpdate.tsx | 28 ++- .../library/dialogs/DlgCloneLibraryItem.tsx | 2 +- .../library/dialogs/DlgCreateVersion.tsx | 2 +- .../DlgEditVersions/DlgEditVersions.tsx | 4 +- .../frontend/src/features/library/index.ts | 1 - .../src/features/library/models/library.ts | 18 +- .../pages/CreateItemPage/FormCreateItem.tsx | 2 +- .../src/features/oss/backend/OssLoader.ts | 14 +- .../frontend/src/features/oss/backend/api.ts | 158 ++------------- .../src/features/oss/backend/types.ts | 143 ++++++++++++++ .../features/oss/backend/useInputCreate.tsx | 10 +- .../features/oss/backend/useInputUpdate.tsx | 10 +- .../features/oss/backend/useMutatingOss.tsx | 8 +- .../src/features/oss/backend/useOSS.tsx | 2 +- .../oss/backend/useOperationCreate.tsx | 3 +- .../oss/backend/useOperationDelete.tsx | 10 +- .../oss/backend/useOperationExecute.tsx | 10 +- .../oss/backend/useOperationUpdate.tsx | 12 +- .../oss/backend/useRelocateConstituents.tsx | 10 +- .../oss/backend/useUpdatePositions.tsx | 3 +- .../oss/dialogs/DlgChangeInputSchema.tsx | 2 +- .../DlgCreateOperation/DlgCreateOperation.tsx | 2 +- .../DlgCreateOperation/TabInputOperation.tsx | 2 +- .../TabSynthesisOperation.tsx | 2 +- .../oss/dialogs/DlgDeleteOperation.tsx | 4 +- .../DlgEditOperation/DlgEditOperation.tsx | 2 +- .../dialogs/DlgEditOperation/TabArguments.tsx | 2 +- .../dialogs/DlgEditOperation/TabOperation.tsx | 2 +- .../dialogs/DlgEditOperation/TabSynthesis.tsx | 5 +- .../oss/dialogs/DlgRelocateConstituents.tsx | 5 +- rsconcept/frontend/src/features/oss/index.ts | 1 + .../frontend/src/features/oss/models/oss.ts | 19 +- .../src/features/oss/models/ossAPI.ts | 22 +-- .../OssPage/EditorOssCard/EditorOssCard.tsx | 2 +- .../pages/OssPage/EditorOssCard/FormOSS.tsx | 2 +- .../EditorOssGraph/NodeContextMenu.tsx | 16 +- .../oss/pages/OssPage/MenuOssTabs.tsx | 2 +- .../oss/pages/OssPage/OssEditContext.tsx | 2 +- .../features/oss/pages/OssPage/OssPage.tsx | 2 +- .../features/rsform/backend/RSFormLoader.ts | 14 +- .../src/features/rsform/backend/api.ts | 186 ++---------------- .../src/features/rsform/backend/cctext/api.ts | 3 +- .../backend/cctext/useIsProcessingCctext.tsx | 4 +- .../src/features/rsform/backend/types.ts | 160 +++++++++++++++ .../rsform/backend/useCheckConstituenta.tsx | 3 +- .../features/rsform/backend/useCstCreate.tsx | 7 +- .../features/rsform/backend/useCstDelete.tsx | 4 +- .../features/rsform/backend/useCstMove.tsx | 3 +- .../features/rsform/backend/useCstRename.tsx | 7 +- .../rsform/backend/useCstSubstitute.tsx | 7 +- .../features/rsform/backend/useCstUpdate.tsx | 7 +- .../rsform/backend/useInlineSynthesis.tsx | 7 +- .../rsform/backend/useMutatingRSForm.tsx | 8 +- .../rsform/backend/useProduceStructure.tsx | 4 +- .../src/features/rsform/backend/useRSForm.tsx | 3 +- .../rsform/backend/useResetAliases.tsx | 4 +- .../features/rsform/backend/useUploadTRS.tsx | 12 +- .../rsform/components/PickConstituenta.tsx | 4 +- .../components/PickMultiConstituenta.tsx | 12 +- .../rsform/components/PickSubstitutions.tsx | 21 +- .../rsform/components/RSInput/RSInput.tsx | 4 +- .../components/RSInput/clickNavigation.ts | 9 +- .../rsform/components/RSInput/tooltip.ts | 3 +- .../rsform/components/RSInput/utils.ts | 25 +++ .../rsform/components/RefsInput/RefsInput.tsx | 4 +- .../components/RefsInput/clickNavigation.ts | 9 +- .../rsform/components/RefsInput/tooltip.ts | 3 +- .../rsform/components/RefsInput/utils.ts | 26 +++ .../rsform/components/SelectConstituenta.tsx | 4 +- .../ToolbarRSFormCard.tsx | 17 +- .../dialogs/DlgCreateCst/DlgCreateCst.tsx | 2 +- .../dialogs/DlgCreateCst/FormCreateCst.tsx | 2 +- .../dialogs/DlgCstTemplate/DlgCstTemplate.tsx | 2 +- .../dialogs/DlgCstTemplate/TabArguments.tsx | 2 +- .../dialogs/DlgCstTemplate/TabTemplate.tsx | 2 +- .../dialogs/DlgDeleteCst/DlgDeleteCst.tsx | 8 +- .../dialogs/DlgDeleteCst/ListConstituents.tsx | 4 +- .../DlgEditReference/TabEntityReference.tsx | 2 +- .../DlgInlineSynthesis/DlgInlineSynthesis.tsx | 2 +- .../DlgInlineSynthesis/TabConstituents.tsx | 7 +- .../dialogs/DlgInlineSynthesis/TabSource.tsx | 2 +- .../DlgInlineSynthesis/TabSubstitutions.tsx | 4 +- .../features/rsform/dialogs/DlgRenameCst.tsx | 2 +- .../DlgShowTypeGraph/graph/MGraphLayout.ts | 2 +- .../rsform/dialogs/DlgSubstituteCst.tsx | 4 +- .../rsform/dialogs/DlgUploadRSForm.tsx | 3 +- .../frontend/src/features/rsform/index.ts | 7 + .../src/features/rsform/models/rsform.ts | 21 +- .../src/features/rsform/models/rslangAPI.ts | 57 +++++- .../EditorConstituenta/FormConstituenta.tsx | 6 +- .../ToolbarConstituenta.tsx | 6 +- .../EditorRSExpression/EditorRSExpression.tsx | 8 +- .../EditorRSFormCard/EditorRSFormCard.tsx | 2 +- .../EditorRSFormCard/FormRSForm.tsx | 2 +- .../RSFormPage/EditorRSList/EditorRSList.tsx | 4 +- .../RSFormPage/EditorRSList/TableRSList.tsx | 4 +- .../RSFormPage/EditorTermGraph/TGFlow.tsx | 18 +- .../RSFormPage/EditorTermGraph/ViewHidden.tsx | 12 +- .../rsform/pages/RSFormPage/MenuRSTabs.tsx | 3 +- .../rsform/pages/RSFormPage/RSEditContext.tsx | 39 ++-- .../rsform/pages/RSFormPage/RSTabs.tsx | 3 +- .../ViewConstituents/ConstituentsSearch.tsx | 4 +- .../TableSideConstituents.tsx | 4 +- .../src/features/users/backend/api.ts | 43 +--- .../src/features/users/backend/types.ts | 38 ++++ .../src/features/users/backend/useSignup.tsx | 3 +- .../users/backend/useUpdateProfile.tsx | 3 +- .../users/pages/RegisterPage/FormSignup.tsx | 2 +- .../pages/UserProfilePage/EditorPassword.tsx | 2 +- .../pages/UserProfilePage/EditorProfile.tsx | 2 +- rsconcept/frontend/src/utils/codemirror.ts | 99 +--------- 134 files changed, 1132 insertions(+), 1069 deletions(-) create mode 100644 rsconcept/frontend/src/features/auth/backend/types.ts create mode 100644 rsconcept/frontend/src/features/library/backend/types.ts create mode 100644 rsconcept/frontend/src/features/oss/backend/types.ts create mode 100644 rsconcept/frontend/src/features/oss/index.ts create mode 100644 rsconcept/frontend/src/features/rsform/backend/types.ts create mode 100644 rsconcept/frontend/src/features/rsform/components/RSInput/utils.ts create mode 100644 rsconcept/frontend/src/features/rsform/components/RefsInput/utils.ts rename rsconcept/frontend/src/features/rsform/{pages/RSFormPage/EditorRSFormCard => components}/ToolbarRSFormCard.tsx (86%) create mode 100644 rsconcept/frontend/src/features/rsform/index.ts create mode 100644 rsconcept/frontend/src/features/users/backend/types.ts diff --git a/rsconcept/frontend/src/backend/configuration.ts b/rsconcept/frontend/src/backend/configuration.ts index fdb5d8a9..65ac44c8 100644 --- a/rsconcept/frontend/src/backend/configuration.ts +++ b/rsconcept/frontend/src/backend/configuration.ts @@ -7,3 +7,18 @@ export const DELAYS = { staleMedium: 1 * 60 * 60 * 1000, staleLong: 24 * 60 * 60 * 1000 }; + +/** API keys for local cache. */ +export const KEYS = { + oss: 'oss', + rsform: 'rsform', + library: 'library', + users: 'users', + cctext: 'cctext', + + composite: { + libraryList: ['library', 'list'], + ossItem: ({ itemID }: { itemID?: number }) => [KEYS.oss, 'item', itemID], + rsItem: ({ itemID, version }: { itemID?: number; version?: number }) => [KEYS.rsform, 'item', itemID, version ?? ''] + } +}; diff --git a/rsconcept/frontend/src/features/auth/backend/api.ts b/rsconcept/frontend/src/features/auth/backend/api.ts index 4fca65cc..09600fa2 100644 --- a/rsconcept/frontend/src/features/auth/backend/api.ts +++ b/rsconcept/frontend/src/features/auth/backend/api.ts @@ -1,77 +1,17 @@ import { queryOptions } from '@tanstack/react-query'; -import { z } from 'zod'; import { axiosGet, axiosPatch, axiosPost } from '@/backend/apiTransport'; import { DELAYS } from '@/backend/configuration'; -import { errorMsg, infoMsg } from '@/utils/labels'; +import { infoMsg } from '@/utils/labels'; -/** - * Represents CurrentUser information. - */ -export interface ICurrentUser { - id: number | null; - username: string; - is_staff: boolean; - editor: number[]; -} - -/** - * Represents login data, used to authenticate users. - */ -export const schemaUserLogin = z.object({ - username: z.string().nonempty(errorMsg.requiredField), - password: z.string().nonempty(errorMsg.requiredField) -}); - -/** - * Represents login data, used to authenticate users. - */ -export type IUserLoginDTO = z.infer; - -/** - * Represents data needed to update password for current user. - */ -export const schemaChangePassword = z - .object({ - old_password: z.string().nonempty(errorMsg.requiredField), - new_password: z.string().nonempty(errorMsg.requiredField), - new_password2: z.string().nonempty(errorMsg.requiredField) - }) - .refine(schema => schema.new_password === schema.new_password2, { - path: ['new_password2'], - message: errorMsg.passwordsMismatch - }) - .refine(schema => schema.old_password !== schema.new_password, { - path: ['new_password'], - message: errorMsg.passwordsSame - }); - -/** - * Represents data needed to update password for current user. - */ -export type IChangePasswordDTO = z.infer; - -/** - * Represents password reset request data. - */ -export interface IRequestPasswordDTO { - email: string; -} - -/** - * Represents password reset data. - */ -export interface IResetPasswordDTO { - password: string; - token: string; -} - -/** - * Represents password token data. - */ -export interface IPasswordTokenDTO { - token: string; -} +import { + IChangePasswordDTO, + ICurrentUser, + IPasswordTokenDTO, + IRequestPasswordDTO, + IResetPasswordDTO, + IUserLoginDTO +} from './types'; /** * Authentication API. diff --git a/rsconcept/frontend/src/features/auth/backend/types.ts b/rsconcept/frontend/src/features/auth/backend/types.ts new file mode 100644 index 00000000..0d760a15 --- /dev/null +++ b/rsconcept/frontend/src/features/auth/backend/types.ts @@ -0,0 +1,71 @@ +import { z } from 'zod'; + +import { errorMsg } from '@/utils/labels'; + +/** + * Represents CurrentUser information. + */ +export interface ICurrentUser { + id: number | null; + username: string; + is_staff: boolean; + editor: number[]; +} + +/** + * Represents login data, used to authenticate users. + */ +export const schemaUserLogin = z.object({ + username: z.string().nonempty(errorMsg.requiredField), + password: z.string().nonempty(errorMsg.requiredField) +}); + +/** + * Represents login data, used to authenticate users. + */ +export type IUserLoginDTO = z.infer; + +/** + * Represents data needed to update password for current user. + */ +export const schemaChangePassword = z + .object({ + old_password: z.string().nonempty(errorMsg.requiredField), + new_password: z.string().nonempty(errorMsg.requiredField), + new_password2: z.string().nonempty(errorMsg.requiredField) + }) + .refine(schema => schema.new_password === schema.new_password2, { + path: ['new_password2'], + message: errorMsg.passwordsMismatch + }) + .refine(schema => schema.old_password !== schema.new_password, { + path: ['new_password'], + message: errorMsg.passwordsSame + }); + +/** + * Represents data needed to update password for current user. + */ +export type IChangePasswordDTO = z.infer; + +/** + * Represents password reset request data. + */ +export interface IRequestPasswordDTO { + email: string; +} + +/** + * Represents password reset data. + */ +export interface IResetPasswordDTO { + password: string; + token: string; +} + +/** + * Represents password token data. + */ +export interface IPasswordTokenDTO { + token: string; +} diff --git a/rsconcept/frontend/src/features/auth/backend/useChangePassword.tsx b/rsconcept/frontend/src/features/auth/backend/useChangePassword.tsx index 860b9ad1..0262d421 100644 --- a/rsconcept/frontend/src/features/auth/backend/useChangePassword.tsx +++ b/rsconcept/frontend/src/features/auth/backend/useChangePassword.tsx @@ -1,6 +1,7 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { authApi, IChangePasswordDTO } from './api'; +import { authApi } from './api'; +import { IChangePasswordDTO } from './types'; export const useChangePassword = () => { const client = useQueryClient(); diff --git a/rsconcept/frontend/src/features/auth/backend/useLogin.tsx b/rsconcept/frontend/src/features/auth/backend/useLogin.tsx index 86bab7a6..2c57716c 100644 --- a/rsconcept/frontend/src/features/auth/backend/useLogin.tsx +++ b/rsconcept/frontend/src/features/auth/backend/useLogin.tsx @@ -1,6 +1,7 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { authApi, IUserLoginDTO } from './api'; +import { authApi } from './api'; +import { IUserLoginDTO } from './types'; export const useLogin = () => { const client = useQueryClient(); diff --git a/rsconcept/frontend/src/features/auth/backend/useRequestPasswordReset.tsx b/rsconcept/frontend/src/features/auth/backend/useRequestPasswordReset.tsx index 47c285f4..d945b88d 100644 --- a/rsconcept/frontend/src/features/auth/backend/useRequestPasswordReset.tsx +++ b/rsconcept/frontend/src/features/auth/backend/useRequestPasswordReset.tsx @@ -1,6 +1,7 @@ import { useMutation } from '@tanstack/react-query'; -import { authApi, IRequestPasswordDTO } from './api'; +import { authApi } from './api'; +import { IRequestPasswordDTO } from './types'; export const useRequestPasswordReset = () => { const mutation = useMutation({ diff --git a/rsconcept/frontend/src/features/auth/backend/useResetPassword.tsx b/rsconcept/frontend/src/features/auth/backend/useResetPassword.tsx index 15f69357..4e0779cb 100644 --- a/rsconcept/frontend/src/features/auth/backend/useResetPassword.tsx +++ b/rsconcept/frontend/src/features/auth/backend/useResetPassword.tsx @@ -1,6 +1,7 @@ import { useMutation } from '@tanstack/react-query'; -import { authApi, IPasswordTokenDTO, IResetPasswordDTO } from './api'; +import { authApi } from './api'; +import { IPasswordTokenDTO, IResetPasswordDTO } from './types'; export const useResetPassword = () => { const validateMutation = useMutation({ diff --git a/rsconcept/frontend/src/features/auth/pages/LoginPage.tsx b/rsconcept/frontend/src/features/auth/pages/LoginPage.tsx index 61ff588c..3690e1b5 100644 --- a/rsconcept/frontend/src/features/auth/pages/LoginPage.tsx +++ b/rsconcept/frontend/src/features/auth/pages/LoginPage.tsx @@ -12,7 +12,7 @@ import { TextInput } from '@/components/Input'; import useQueryStrings from '@/hooks/useQueryStrings'; import { resources } from '@/utils/constants'; -import { IUserLoginDTO, schemaUserLogin } from '../backend/api'; +import { IUserLoginDTO, schemaUserLogin } from '../backend/types'; import { useAuthSuspense } from '../backend/useAuth'; import { useLogin } from '../backend/useLogin'; import { ExpectedAnonymous } from '../components/ExpectedAnonymous'; diff --git a/rsconcept/frontend/src/features/library/backend/api.ts b/rsconcept/frontend/src/features/library/backend/api.ts index c7136f41..76ec6f80 100644 --- a/rsconcept/frontend/src/features/library/backend/api.ts +++ b/rsconcept/frontend/src/features/library/backend/api.ts @@ -1,139 +1,25 @@ import { queryOptions } from '@tanstack/react-query'; -import { z } from 'zod'; import { axiosDelete, axiosGet, axiosPatch, axiosPost } from '@/backend/apiTransport'; -import { DELAYS } from '@/backend/configuration'; -import { ossApi } from '@/features/oss/backend/api'; -import { IRSFormDTO, rsformsApi } from '@/features/rsform/backend/api'; -import { errorMsg, infoMsg } from '@/utils/labels'; +import { DELAYS, KEYS } from '@/backend/configuration'; +import { IRSFormDTO } from '@/features/rsform/backend/types'; +import { infoMsg } from '@/utils/labels'; -import { AccessPolicy, ILibraryItem, IVersionInfo, LibraryItemID, LibraryItemType, VersionID } from '../models/library'; -import { validateLocation } from '../models/libraryAPI'; - -/** - * Represents update data for renaming Location. - */ -export interface IRenameLocationDTO { - target: string; - new_location: string; -} - -/** - * Represents data, used for cloning {@link IRSForm}. - */ -export const schemaCloneLibraryItem = z.object({ - id: z.number(), - item_type: z.nativeEnum(LibraryItemType), - title: z.string().nonempty(errorMsg.requiredField), - alias: z.string().nonempty(errorMsg.requiredField), - comment: z.string(), - visible: z.boolean(), - read_only: z.boolean(), - location: z.string().refine(data => validateLocation(data), { message: errorMsg.invalidLocation }), - access_policy: z.nativeEnum(AccessPolicy), - - items: z.array(z.number()).optional() -}); - -/** - * Represents data, used for cloning {@link IRSForm}. - */ -export type ICloneLibraryItemDTO = z.infer; - -/** - * Represents data, used for creating {@link IRSForm}. - */ -export const schemaCreateLibraryItem = z - .object({ - item_type: z.nativeEnum(LibraryItemType), - title: z.string().optional(), - alias: z.string().optional(), - comment: z.string(), - visible: z.boolean(), - read_only: z.boolean(), - location: z.string().refine(data => validateLocation(data), { message: errorMsg.invalidLocation }), - access_policy: z.nativeEnum(AccessPolicy), - - file: z.instanceof(File).optional(), - fileName: z.string().optional() - }) - .refine(data => !!data.file || !!data.title, { - path: ['title'], - message: errorMsg.requiredField - }) - .refine(data => !!data.file || !!data.alias, { - path: ['alias'], - message: errorMsg.requiredField - }); - -/** - * Represents data, used for creating {@link IRSForm}. - */ -export type ICreateLibraryItemDTO = z.infer; - -/** - * Represents update data for editing {@link ILibraryItem}. - */ -export const schemaUpdateLibraryItem = z.object({ - id: z.number(), - item_type: z.nativeEnum(LibraryItemType), - title: z.string().nonempty(errorMsg.requiredField), - alias: z.string().nonempty(errorMsg.requiredField), - comment: z.string(), - visible: z.boolean(), - read_only: z.boolean() -}); - -/** - * Represents update data for editing {@link ILibraryItem}. - */ -export type IUpdateLibraryItemDTO = z.infer; - -/** - * Create version metadata in persistent storage. - */ -export const schemaVersionCreate = z.object({ - version: z.string(), - description: z.string(), - items: z.array(z.number()).optional() -}); - -/** - * Create version metadata in persistent storage. - */ -export type IVersionCreateDTO = z.infer; - -/** - * Represents data response when creating {@link IVersionInfo}. - */ -export interface IVersionCreatedResponse { - version: number; - schema: IRSFormDTO; -} - -/** - * Represents version data, intended to update version metadata in persistent storage. - */ -export const schemaVersionUpdate = z.object({ - id: z.number(), - version: z.string().nonempty(errorMsg.requiredField), - description: z.string() -}); - -/** - * Represents version data, intended to update version metadata in persistent storage. - */ -export type IVersionUpdateDTO = z.infer; +import { AccessPolicy, ILibraryItem, IVersionInfo } from '../models/library'; +import { + ICloneLibraryItemDTO, + ICreateLibraryItemDTO, + IRenameLocationDTO, + IUpdateLibraryItemDTO, + IVersionCreatedResponse, + IVersionCreateDTO, + IVersionUpdateDTO +} from './types'; export const libraryApi = { - baseKey: 'library', - libraryListKey: ['library', 'list'], + baseKey: KEYS.library, + libraryListKey: KEYS.composite.libraryList, - getItemQueryOptions: ({ itemID, itemType }: { itemID: LibraryItemID; itemType: LibraryItemType }) => { - return itemType === LibraryItemType.RSFORM - ? rsformsApi.getRSFormQueryOptions({ itemID }) - : ossApi.getOssQueryOptions({ itemID }); - }, getLibraryQueryOptions: ({ isAdmin }: { isAdmin: boolean }) => queryOptions({ queryKey: [...libraryApi.libraryListKey, isAdmin ? 'admin' : 'user'], @@ -178,7 +64,7 @@ export const libraryApi = { successMessage: infoMsg.changesSaved } }), - setOwner: ({ itemID, owner }: { itemID: LibraryItemID; owner: number }) => + setOwner: ({ itemID, owner }: { itemID: number; owner: number }) => axiosPatch({ endpoint: `/api/library/${itemID}/set-owner`, request: { @@ -186,7 +72,7 @@ export const libraryApi = { successMessage: infoMsg.changesSaved } }), - setLocation: ({ itemID, location }: { itemID: LibraryItemID; location: string }) => + setLocation: ({ itemID, location }: { itemID: number; location: string }) => axiosPatch({ endpoint: `/api/library/${itemID}/set-location`, request: { @@ -194,7 +80,7 @@ export const libraryApi = { successMessage: infoMsg.moveComplete } }), - setAccessPolicy: ({ itemID, policy }: { itemID: LibraryItemID; policy: AccessPolicy }) => + setAccessPolicy: ({ itemID, policy }: { itemID: number; policy: AccessPolicy }) => axiosPatch({ endpoint: `/api/library/${itemID}/set-access-policy`, request: { @@ -202,7 +88,7 @@ export const libraryApi = { successMessage: infoMsg.changesSaved } }), - setEditors: ({ itemID, editors }: { itemID: LibraryItemID; editors: number[] }) => + setEditors: ({ itemID, editors }: { itemID: number; editors: number[] }) => axiosPatch({ endpoint: `/api/library/${itemID}/set-editors`, request: { @@ -211,7 +97,7 @@ export const libraryApi = { } }), - deleteItem: (target: LibraryItemID) => + deleteItem: (target: number) => axiosDelete({ endpoint: `/api/library/${target}`, request: { @@ -235,7 +121,7 @@ export const libraryApi = { } }), - versionCreate: ({ itemID, data }: { itemID: LibraryItemID; data: IVersionCreateDTO }) => + versionCreate: ({ itemID, data }: { itemID: number; data: IVersionCreateDTO }) => axiosPost({ endpoint: `/api/library/${itemID}/create-version`, request: { @@ -243,7 +129,7 @@ export const libraryApi = { successMessage: infoMsg.newVersion(data.version) } }), - versionRestore: ({ versionID }: { versionID: VersionID }) => + versionRestore: ({ versionID }: { versionID: number }) => axiosPatch({ endpoint: `/api/versions/${versionID}/restore`, request: { @@ -258,7 +144,7 @@ export const libraryApi = { successMessage: infoMsg.changesSaved } }), - versionDelete: (data: { itemID: LibraryItemID; versionID: VersionID }) => + versionDelete: (data: { itemID: number; versionID: number }) => axiosDelete({ endpoint: `/api/versions/${data.versionID}`, request: { diff --git a/rsconcept/frontend/src/features/library/backend/types.ts b/rsconcept/frontend/src/features/library/backend/types.ts new file mode 100644 index 00000000..983e2f45 --- /dev/null +++ b/rsconcept/frontend/src/features/library/backend/types.ts @@ -0,0 +1,122 @@ +import { z } from 'zod'; + +import { IRSFormDTO } from '@/features/rsform/backend/types'; +import { errorMsg } from '@/utils/labels'; + +import { AccessPolicy, LibraryItemType } from '../models/library'; +import { validateLocation } from '../models/libraryAPI'; + +/** + * Represents update data for renaming Location. + */ +export interface IRenameLocationDTO { + target: string; + new_location: string; +} + +/** + * Represents data, used for cloning {@link IRSForm}. + */ +export const schemaCloneLibraryItem = z.object({ + id: z.number(), + item_type: z.nativeEnum(LibraryItemType), + title: z.string().nonempty(errorMsg.requiredField), + alias: z.string().nonempty(errorMsg.requiredField), + comment: z.string(), + visible: z.boolean(), + read_only: z.boolean(), + location: z.string().refine(data => validateLocation(data), { message: errorMsg.invalidLocation }), + access_policy: z.nativeEnum(AccessPolicy), + + items: z.array(z.number()).optional() +}); + +/** + * Represents data, used for cloning {@link IRSForm}. + */ +export type ICloneLibraryItemDTO = z.infer; + +/** + * Represents data, used for creating {@link IRSForm}. + */ +export const schemaCreateLibraryItem = z + .object({ + item_type: z.nativeEnum(LibraryItemType), + title: z.string().optional(), + alias: z.string().optional(), + comment: z.string(), + visible: z.boolean(), + read_only: z.boolean(), + location: z.string().refine(data => validateLocation(data), { message: errorMsg.invalidLocation }), + access_policy: z.nativeEnum(AccessPolicy), + + file: z.instanceof(File).optional(), + fileName: z.string().optional() + }) + .refine(data => !!data.file || !!data.title, { + path: ['title'], + message: errorMsg.requiredField + }) + .refine(data => !!data.file || !!data.alias, { + path: ['alias'], + message: errorMsg.requiredField + }); + +/** + * Represents data, used for creating {@link IRSForm}. + */ +export type ICreateLibraryItemDTO = z.infer; + +/** + * Represents update data for editing {@link ILibraryItem}. + */ +export const schemaUpdateLibraryItem = z.object({ + id: z.number(), + item_type: z.nativeEnum(LibraryItemType), + title: z.string().nonempty(errorMsg.requiredField), + alias: z.string().nonempty(errorMsg.requiredField), + comment: z.string(), + visible: z.boolean(), + read_only: z.boolean() +}); + +/** + * Represents update data for editing {@link ILibraryItem}. + */ +export type IUpdateLibraryItemDTO = z.infer; + +/** + * Create version metadata in persistent storage. + */ +export const schemaVersionCreate = z.object({ + version: z.string(), + description: z.string(), + items: z.array(z.number()).optional() +}); + +/** + * Create version metadata in persistent storage. + */ +export type IVersionCreateDTO = z.infer; + +/** + * Represents data response when creating {@link IVersionInfo}. + */ +export interface IVersionCreatedResponse { + version: number; + schema: IRSFormDTO; +} + +/** + * Represents version data, intended to update version metadata in persistent storage. + */ +export const schemaVersionUpdate = z.object({ + id: z.number(), + version: z.string().nonempty(errorMsg.requiredField), + description: z.string() +}); + +/** + * Represents version data, intended to update version metadata in persistent storage. + */ +export type IVersionUpdateDTO = z.infer; diff --git a/rsconcept/frontend/src/features/library/backend/useCloneItem.tsx b/rsconcept/frontend/src/features/library/backend/useCloneItem.tsx index fd4f05b0..40368589 100644 --- a/rsconcept/frontend/src/features/library/backend/useCloneItem.tsx +++ b/rsconcept/frontend/src/features/library/backend/useCloneItem.tsx @@ -1,6 +1,7 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { ICloneLibraryItemDTO, libraryApi } from './api'; +import { libraryApi } from './api'; +import { ICloneLibraryItemDTO } from './types'; export const useCloneItem = () => { const client = useQueryClient(); diff --git a/rsconcept/frontend/src/features/library/backend/useCreateItem.tsx b/rsconcept/frontend/src/features/library/backend/useCreateItem.tsx index b06a7b7e..2e048870 100644 --- a/rsconcept/frontend/src/features/library/backend/useCreateItem.tsx +++ b/rsconcept/frontend/src/features/library/backend/useCreateItem.tsx @@ -1,6 +1,7 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { ICreateLibraryItemDTO, libraryApi } from './api'; +import { libraryApi } from './api'; +import { ICreateLibraryItemDTO } from './types'; export const useCreateItem = () => { const client = useQueryClient(); diff --git a/rsconcept/frontend/src/features/library/backend/useDeleteItem.tsx b/rsconcept/frontend/src/features/library/backend/useDeleteItem.tsx index dd9df896..8437349c 100644 --- a/rsconcept/frontend/src/features/library/backend/useDeleteItem.tsx +++ b/rsconcept/frontend/src/features/library/backend/useDeleteItem.tsx @@ -1,10 +1,8 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { ossApi } from '@/features/oss/backend/api'; -import { rsformsApi } from '@/features/rsform/backend/api'; +import { KEYS } from '@/backend/configuration'; import { PARAMETER } from '@/utils/constants'; -import { LibraryItemID } from '../models/library'; import { libraryApi } from './api'; export const useDeleteItem = () => { @@ -17,16 +15,16 @@ export const useDeleteItem = () => { setTimeout( () => void Promise.allSettled([ - client.invalidateQueries({ queryKey: [ossApi.baseKey] }), - client.resetQueries({ queryKey: rsformsApi.getRSFormQueryOptions({ itemID: variables }).queryKey }), - client.resetQueries({ queryKey: ossApi.getOssQueryOptions({ itemID: variables }).queryKey }) + client.invalidateQueries({ queryKey: [KEYS.oss] }), + client.resetQueries({ queryKey: KEYS.composite.rsItem({ itemID: variables }) }), + client.resetQueries({ queryKey: KEYS.composite.ossItem({ itemID: variables }) }) ]).catch(console.error), PARAMETER.navigationDuration ); } }); return { - deleteItem: (target: LibraryItemID) => mutation.mutateAsync(target), + deleteItem: (target: number) => mutation.mutateAsync(target), isPending: mutation.isPending }; }; diff --git a/rsconcept/frontend/src/features/library/backend/useMutatingLibrary.tsx b/rsconcept/frontend/src/features/library/backend/useMutatingLibrary.tsx index 4ca57cd3..44989b66 100644 --- a/rsconcept/frontend/src/features/library/backend/useMutatingLibrary.tsx +++ b/rsconcept/frontend/src/features/library/backend/useMutatingLibrary.tsx @@ -1,13 +1,10 @@ import { useIsMutating } from '@tanstack/react-query'; -import { ossApi } from '@/features/oss/backend/api'; -import { rsformsApi } from '@/features/rsform/backend/api'; - -import { libraryApi } from './api'; +import { KEYS } from '@/backend/configuration'; export const useMutatingLibrary = () => { - const countMutations = useIsMutating({ mutationKey: [libraryApi.baseKey] }); - const countOss = useIsMutating({ mutationKey: [ossApi.baseKey] }); - const countRSForm = useIsMutating({ mutationKey: [rsformsApi.baseKey] }); + const countMutations = useIsMutating({ mutationKey: [KEYS.library] }); + const countOss = useIsMutating({ mutationKey: [KEYS.oss] }); + const countRSForm = useIsMutating({ mutationKey: [KEYS.rsform] }); return countMutations + countOss + countRSForm !== 0; }; diff --git a/rsconcept/frontend/src/features/library/backend/useRenameLocation.tsx b/rsconcept/frontend/src/features/library/backend/useRenameLocation.tsx index c9c48dc1..2c515bbf 100644 --- a/rsconcept/frontend/src/features/library/backend/useRenameLocation.tsx +++ b/rsconcept/frontend/src/features/library/backend/useRenameLocation.tsx @@ -1,9 +1,9 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { ossApi } from '@/features/oss/backend/api'; -import { rsformsApi } from '@/features/rsform/backend/api'; +import { KEYS } from '@/backend/configuration'; -import { IRenameLocationDTO, libraryApi } from './api'; +import { libraryApi } from './api'; +import { IRenameLocationDTO } from './types'; export const useRenameLocation = () => { const client = useQueryClient(); @@ -12,9 +12,9 @@ export const useRenameLocation = () => { mutationFn: libraryApi.renameLocation, onSuccess: () => Promise.allSettled([ - client.invalidateQueries({ queryKey: [libraryApi.baseKey] }), - client.invalidateQueries({ queryKey: [rsformsApi.baseKey] }), - client.invalidateQueries({ queryKey: [ossApi.baseKey] }) + client.invalidateQueries({ queryKey: [KEYS.library] }), + client.invalidateQueries({ queryKey: [KEYS.rsform] }), + client.invalidateQueries({ queryKey: [KEYS.oss] }) ]) }); return { diff --git a/rsconcept/frontend/src/features/library/backend/useSetAccessPolicy.tsx b/rsconcept/frontend/src/features/library/backend/useSetAccessPolicy.tsx index d9744dcf..65eda3bd 100644 --- a/rsconcept/frontend/src/features/library/backend/useSetAccessPolicy.tsx +++ b/rsconcept/frontend/src/features/library/backend/useSetAccessPolicy.tsx @@ -1,9 +1,10 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { IOperationSchemaDTO, ossApi } from '@/features/oss/backend/api'; -import { rsformsApi } from '@/features/rsform/backend/api'; +import { KEYS } from '@/backend/configuration'; +import { IOperationSchemaDTO } from '@/features/oss/backend/types'; +import { IRSFormDTO } from '@/features/rsform/backend/types'; -import { AccessPolicy, ILibraryItem, LibraryItemID } from '../models/library'; +import { AccessPolicy, ILibraryItem } from '../models/library'; import { libraryApi } from './api'; export const useSetAccessPolicy = () => { @@ -12,26 +13,28 @@ export const useSetAccessPolicy = () => { mutationKey: [libraryApi.baseKey, 'set-location'], mutationFn: libraryApi.setAccessPolicy, onSuccess: (_, variables) => { - const ossKey = ossApi.getOssQueryOptions({ itemID: variables.itemID }).queryKey; + const ossKey = KEYS.composite.ossItem({ itemID: variables.itemID }); const ossData: IOperationSchemaDTO | undefined = client.getQueryData(ossKey); if (ossData) { client.setQueryData(ossKey, { ...ossData, access_policy: variables.policy }); return Promise.allSettled([ - client.invalidateQueries({ queryKey: libraryApi.libraryListKey }), + client.invalidateQueries({ queryKey: KEYS.composite.libraryList }), ...ossData.items .map(item => { if (!item.result) { return; } - const itemKey = rsformsApi.getRSFormQueryOptions({ itemID: item.result }).queryKey; + const itemKey = KEYS.composite.rsItem({ itemID: item.result }); return client.invalidateQueries({ queryKey: itemKey }); }) .filter(item => !!item) ]); } - const rsKey = rsformsApi.getRSFormQueryOptions({ itemID: variables.itemID }).queryKey; - client.setQueryData(rsKey, prev => (!prev ? undefined : { ...prev, access_policy: variables.policy })); + const rsKey = KEYS.composite.rsItem({ itemID: variables.itemID }); + client.setQueryData(rsKey, (prev: IRSFormDTO | undefined) => + !prev ? undefined : { ...prev, access_policy: variables.policy } + ); client.setQueryData(libraryApi.libraryListKey, (prev: ILibraryItem[] | undefined) => prev?.map(item => (item.id === variables.itemID ? { ...item, access_policy: variables.policy } : item)) ); @@ -39,6 +42,6 @@ export const useSetAccessPolicy = () => { }); return { - setAccessPolicy: (data: { itemID: LibraryItemID; policy: AccessPolicy }) => mutation.mutateAsync(data) + setAccessPolicy: (data: { itemID: number; policy: AccessPolicy }) => mutation.mutateAsync(data) }; }; diff --git a/rsconcept/frontend/src/features/library/backend/useSetEditors.tsx b/rsconcept/frontend/src/features/library/backend/useSetEditors.tsx index 3addb83f..944994b5 100644 --- a/rsconcept/frontend/src/features/library/backend/useSetEditors.tsx +++ b/rsconcept/frontend/src/features/library/backend/useSetEditors.tsx @@ -1,7 +1,8 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { ossApi } from '@/features/oss/backend/api'; -import { rsformsApi } from '@/features/rsform/backend/api'; +import { KEYS } from '@/backend/configuration'; +import { IOperationSchemaDTO } from '@/features/oss/backend/types'; +import { IRSFormDTO } from '@/features/rsform/backend/types'; import { libraryApi } from './api'; @@ -11,8 +12,8 @@ export const useSetEditors = () => { mutationKey: [libraryApi.baseKey, 'set-location'], mutationFn: libraryApi.setEditors, onSuccess: (_, variables) => { - const ossKey = ossApi.getOssQueryOptions({ itemID: variables.itemID }).queryKey; - const ossData = client.getQueryData(ossKey); + const ossKey = KEYS.composite.ossItem({ itemID: variables.itemID }); + const ossData: IOperationSchemaDTO | undefined = client.getQueryData(ossKey); if (ossData) { client.setQueryData(ossKey, { ...ossData, editors: variables.editors }); return Promise.allSettled( @@ -21,15 +22,17 @@ export const useSetEditors = () => { if (!item.result) { return; } - const itemKey = rsformsApi.getRSFormQueryOptions({ itemID: item.result }).queryKey; + const itemKey = KEYS.composite.rsItem({ itemID: item.result }); return client.invalidateQueries({ queryKey: itemKey }); }) .filter(item => !!item) ); } - const rsKey = rsformsApi.getRSFormQueryOptions({ itemID: variables.itemID }).queryKey; - client.setQueryData(rsKey, prev => (!prev ? undefined : { ...prev, editors: variables.editors })); + const rsKey = KEYS.composite.rsItem({ itemID: variables.itemID }); + client.setQueryData(rsKey, (prev: IRSFormDTO | undefined) => + !prev ? undefined : { ...prev, editors: variables.editors } + ); } }); diff --git a/rsconcept/frontend/src/features/library/backend/useSetLocation.tsx b/rsconcept/frontend/src/features/library/backend/useSetLocation.tsx index 5f81fc2f..aef9760c 100644 --- a/rsconcept/frontend/src/features/library/backend/useSetLocation.tsx +++ b/rsconcept/frontend/src/features/library/backend/useSetLocation.tsx @@ -1,9 +1,10 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { IOperationSchemaDTO, ossApi } from '@/features/oss/backend/api'; -import { rsformsApi } from '@/features/rsform/backend/api'; +import { KEYS } from '@/backend/configuration'; +import { IOperationSchemaDTO } from '@/features/oss/backend/types'; +import { IRSFormDTO } from '@/features/rsform/backend/types'; -import { ILibraryItem, LibraryItemID } from '../models/library'; +import { ILibraryItem } from '../models/library'; import { libraryApi } from './api'; export const useSetLocation = () => { @@ -12,7 +13,7 @@ export const useSetLocation = () => { mutationKey: [libraryApi.baseKey, 'set-location'], mutationFn: libraryApi.setLocation, onSuccess: (_, variables) => { - const ossKey = ossApi.getOssQueryOptions({ itemID: variables.itemID }).queryKey; + const ossKey = KEYS.composite.ossItem({ itemID: variables.itemID }); const ossData: IOperationSchemaDTO | undefined = client.getQueryData(ossKey); if (ossData) { client.setQueryData(ossKey, { ...ossData, location: variables.location }); @@ -23,15 +24,17 @@ export const useSetLocation = () => { if (!item.result) { return; } - const itemKey = rsformsApi.getRSFormQueryOptions({ itemID: item.result }).queryKey; + const itemKey = KEYS.composite.rsItem({ itemID: item.result }); return client.invalidateQueries({ queryKey: itemKey }); }) .filter(item => !!item) ]); } - const rsKey = rsformsApi.getRSFormQueryOptions({ itemID: variables.itemID }).queryKey; - client.setQueryData(rsKey, prev => (!prev ? undefined : { ...prev, location: variables.location })); + const rsKey = KEYS.composite.rsItem({ itemID: variables.itemID }); + client.setQueryData(rsKey, (prev: IRSFormDTO | undefined) => + !prev ? undefined : { ...prev, location: variables.location } + ); client.setQueryData(libraryApi.libraryListKey, (prev: ILibraryItem[] | undefined) => prev?.map(item => (item.id === variables.itemID ? { ...item, location: variables.location } : item)) ); @@ -39,6 +42,6 @@ export const useSetLocation = () => { }); return { - setLocation: (data: { itemID: LibraryItemID; location: string }) => mutation.mutateAsync(data) + setLocation: (data: { itemID: number; location: string }) => mutation.mutateAsync(data) }; }; diff --git a/rsconcept/frontend/src/features/library/backend/useSetOwner.tsx b/rsconcept/frontend/src/features/library/backend/useSetOwner.tsx index 4eda022b..184fffed 100644 --- a/rsconcept/frontend/src/features/library/backend/useSetOwner.tsx +++ b/rsconcept/frontend/src/features/library/backend/useSetOwner.tsx @@ -1,7 +1,8 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { IOperationSchemaDTO, ossApi } from '@/features/oss/backend/api'; -import { rsformsApi } from '@/features/rsform/backend/api'; +import { KEYS } from '@/backend/configuration'; +import { IOperationSchemaDTO } from '@/features/oss/backend/types'; +import { IRSFormDTO } from '@/features/rsform/backend/types'; import { ILibraryItem } from '../models/library'; import { libraryApi } from './api'; @@ -12,7 +13,7 @@ export const useSetOwner = () => { mutationKey: [libraryApi.baseKey, 'set-owner'], mutationFn: libraryApi.setOwner, onSuccess: (_, variables) => { - const ossKey = ossApi.getOssQueryOptions({ itemID: variables.itemID }).queryKey; + const ossKey = KEYS.composite.ossItem({ itemID: variables.itemID }); const ossData: IOperationSchemaDTO | undefined = client.getQueryData(ossKey); if (ossData) { client.setQueryData(ossKey, { ...ossData, owner: variables.owner }); @@ -23,15 +24,17 @@ export const useSetOwner = () => { if (!item.result) { return; } - const itemKey = rsformsApi.getRSFormQueryOptions({ itemID: item.result }).queryKey; + const itemKey = KEYS.composite.rsItem({ itemID: item.result }); return client.invalidateQueries({ queryKey: itemKey }); }) .filter(item => !!item) ]); } - const rsKey = rsformsApi.getRSFormQueryOptions({ itemID: variables.itemID }).queryKey; - client.setQueryData(rsKey, prev => (!prev ? undefined : { ...prev, owner: variables.owner })); + const rsKey = KEYS.composite.rsItem({ itemID: variables.itemID }); + client.setQueryData(rsKey, (prev: IRSFormDTO | undefined) => + !prev ? undefined : { ...prev, owner: variables.owner } + ); client.setQueryData(libraryApi.libraryListKey, (prev: ILibraryItem[] | undefined) => prev?.map(item => (item.id === variables.itemID ? { ...item, owner: variables.owner } : item)) ); diff --git a/rsconcept/frontend/src/features/library/backend/useUpdateItem.tsx b/rsconcept/frontend/src/features/library/backend/useUpdateItem.tsx index c17e43c2..ccc9300d 100644 --- a/rsconcept/frontend/src/features/library/backend/useUpdateItem.tsx +++ b/rsconcept/frontend/src/features/library/backend/useUpdateItem.tsx @@ -1,10 +1,12 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { IOperationSchemaDTO, ossApi } from '@/features/oss/backend/api'; -import { IRSFormDTO } from '@/features/rsform/backend/api'; +import { KEYS } from '@/backend/configuration'; +import { IOperationSchemaDTO } from '@/features/oss/backend/types'; +import { IRSFormDTO } from '@/features/rsform/backend/types'; import { ILibraryItem, LibraryItemType } from '../models/library'; -import { IUpdateLibraryItemDTO, libraryApi } from './api'; +import { libraryApi } from './api'; +import { IUpdateLibraryItemDTO } from './types'; export const useUpdateItem = () => { const client = useQueryClient(); @@ -12,7 +14,10 @@ export const useUpdateItem = () => { mutationKey: [libraryApi.baseKey, 'update-item'], mutationFn: libraryApi.updateItem, onSuccess: (data: ILibraryItem) => { - const itemKey = libraryApi.getItemQueryOptions({ itemID: data.id, itemType: data.item_type }).queryKey; + const itemKey = + data.item_type === LibraryItemType.RSFORM + ? KEYS.composite.rsItem({ itemID: data.id }) + : KEYS.composite.ossItem({ itemID: data.id }); client.setQueryData(libraryApi.libraryListKey, (prev: ILibraryItem[] | undefined) => prev?.map(item => (item.id === data.id ? data : item)) ); @@ -23,9 +28,7 @@ export const useUpdateItem = () => { const schema: IRSFormDTO | undefined = client.getQueryData(itemKey); if (schema) { return Promise.allSettled( - schema.oss.map(item => - client.invalidateQueries({ queryKey: ossApi.getOssQueryOptions({ itemID: item.id }).queryKey }) - ) + schema.oss.map(item => client.invalidateQueries({ queryKey: KEYS.composite.ossItem({ itemID: item.id }) })) ); } } diff --git a/rsconcept/frontend/src/features/library/backend/useVersionCreate.tsx b/rsconcept/frontend/src/features/library/backend/useVersionCreate.tsx index 51ef40ac..d887dd83 100644 --- a/rsconcept/frontend/src/features/library/backend/useVersionCreate.tsx +++ b/rsconcept/frontend/src/features/library/backend/useVersionCreate.tsx @@ -1,9 +1,9 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { rsformsApi } from '@/features/rsform/backend/api'; +import { KEYS } from '@/backend/configuration'; -import { LibraryItemID } from '../models/library'; -import { IVersionCreateDTO, libraryApi } from './api'; +import { libraryApi } from './api'; +import { IVersionCreateDTO } from './types'; import { useUpdateTimestamp } from './useUpdateTimestamp'; export const useVersionCreate = () => { @@ -13,12 +13,12 @@ export const useVersionCreate = () => { mutationKey: [libraryApi.baseKey, 'create-version'], mutationFn: libraryApi.versionCreate, onSuccess: data => { - client.setQueryData(rsformsApi.getRSFormQueryOptions({ itemID: data.schema.id }).queryKey, data.schema); + client.setQueryData(KEYS.composite.rsItem({ itemID: data.schema.id }), data.schema); updateTimestamp(data.schema.id); } }); return { - versionCreate: (data: { itemID: LibraryItemID; data: IVersionCreateDTO }) => + versionCreate: (data: { itemID: number; data: IVersionCreateDTO }) => mutation.mutateAsync(data).then(response => response.version) }; }; diff --git a/rsconcept/frontend/src/features/library/backend/useVersionDelete.tsx b/rsconcept/frontend/src/features/library/backend/useVersionDelete.tsx index 68ad6a67..8e99e194 100644 --- a/rsconcept/frontend/src/features/library/backend/useVersionDelete.tsx +++ b/rsconcept/frontend/src/features/library/backend/useVersionDelete.tsx @@ -1,8 +1,8 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { IRSFormDTO, rsformsApi } from '@/features/rsform/backend/api'; +import { KEYS } from '@/backend/configuration'; +import { IRSFormDTO } from '@/features/rsform/backend/types'; -import { LibraryItemID, VersionID } from '../models/library'; import { libraryApi } from './api'; export const useVersionDelete = () => { @@ -11,19 +11,17 @@ export const useVersionDelete = () => { mutationKey: [libraryApi.baseKey, 'delete-version'], mutationFn: libraryApi.versionDelete, onSuccess: (_, variables) => { - client.setQueryData( - rsformsApi.getRSFormQueryOptions({ itemID: variables.itemID }).queryKey, - (prev: IRSFormDTO | undefined) => - !prev - ? undefined - : { - ...prev, - versions: prev.versions.filter(version => version.id !== variables.versionID) - } + client.setQueryData(KEYS.composite.rsItem({ itemID: variables.itemID }), (prev: IRSFormDTO | undefined) => + !prev + ? undefined + : { + ...prev, + versions: prev.versions.filter(version => version.id !== variables.versionID) + } ); } }); return { - versionDelete: (data: { itemID: LibraryItemID; versionID: VersionID }) => mutation.mutateAsync(data) + versionDelete: (data: { itemID: number; versionID: number }) => mutation.mutateAsync(data) }; }; diff --git a/rsconcept/frontend/src/features/library/backend/useVersionRestore.tsx b/rsconcept/frontend/src/features/library/backend/useVersionRestore.tsx index 23f2b4ab..2a0888e0 100644 --- a/rsconcept/frontend/src/features/library/backend/useVersionRestore.tsx +++ b/rsconcept/frontend/src/features/library/backend/useVersionRestore.tsx @@ -1,8 +1,7 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { rsformsApi } from '@/features/rsform/backend/api'; +import { KEYS } from '@/backend/configuration'; -import { VersionID } from '../models/library'; import { libraryApi } from './api'; export const useVersionRestore = () => { @@ -11,11 +10,11 @@ export const useVersionRestore = () => { mutationKey: [libraryApi.baseKey, 'restore-version'], mutationFn: libraryApi.versionRestore, onSuccess: data => { - client.setQueryData(rsformsApi.getRSFormQueryOptions({ itemID: data.id }).queryKey, data); + client.setQueryData(KEYS.composite.rsItem({ itemID: data.id }), data); return client.invalidateQueries({ queryKey: [libraryApi.baseKey] }); } }); return { - versionRestore: (data: { versionID: VersionID }) => mutation.mutateAsync(data) + versionRestore: (data: { versionID: number }) => mutation.mutateAsync(data) }; }; diff --git a/rsconcept/frontend/src/features/library/backend/useVersionUpdate.tsx b/rsconcept/frontend/src/features/library/backend/useVersionUpdate.tsx index df58ee90..53e04e68 100644 --- a/rsconcept/frontend/src/features/library/backend/useVersionUpdate.tsx +++ b/rsconcept/frontend/src/features/library/backend/useVersionUpdate.tsx @@ -1,8 +1,10 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { IRSFormDTO, rsformsApi } from '@/features/rsform/backend/api'; +import { KEYS } from '@/backend/configuration'; +import { IRSFormDTO } from '@/features/rsform/backend/types'; -import { IVersionUpdateDTO, libraryApi } from './api'; +import { libraryApi } from './api'; +import { IVersionUpdateDTO } from './types'; export const useVersionUpdate = () => { const client = useQueryClient(); @@ -10,19 +12,15 @@ export const useVersionUpdate = () => { mutationKey: [libraryApi.baseKey, 'update-version'], mutationFn: libraryApi.versionUpdate, onSuccess: data => { - client.setQueryData( - rsformsApi.getRSFormQueryOptions({ itemID: data.item }).queryKey, - (prev: IRSFormDTO | undefined) => - !prev - ? undefined - : { - ...prev, - versions: prev.versions.map(version => - version.id === data.id - ? { ...version, description: data.description, version: data.version } - : version - ) - } + client.setQueryData(KEYS.composite.rsItem({ itemID: data.item }), (prev: IRSFormDTO | undefined) => + !prev + ? undefined + : { + ...prev, + versions: prev.versions.map(version => + version.id === data.id ? { ...version, description: data.description, version: data.version } : version + ) + } ); } }); diff --git a/rsconcept/frontend/src/features/library/dialogs/DlgCloneLibraryItem.tsx b/rsconcept/frontend/src/features/library/dialogs/DlgCloneLibraryItem.tsx index beddf13e..6a90ba28 100644 --- a/rsconcept/frontend/src/features/library/dialogs/DlgCloneLibraryItem.tsx +++ b/rsconcept/frontend/src/features/library/dialogs/DlgCloneLibraryItem.tsx @@ -12,7 +12,7 @@ import { ModalForm } from '@/components/Modal'; import { useAuthSuspense } from '@/features/auth'; import { useDialogsStore } from '@/stores/dialogs'; -import { ICloneLibraryItemDTO, schemaCloneLibraryItem } from '../backend/api'; +import { ICloneLibraryItemDTO, schemaCloneLibraryItem } from '../backend/types'; import { useCloneItem } from '../backend/useCloneItem'; import { SelectAccessPolicy } from '../components/SelectAccessPolicy'; import { SelectLocationContext } from '../components/SelectLocationContext'; diff --git a/rsconcept/frontend/src/features/library/dialogs/DlgCreateVersion.tsx b/rsconcept/frontend/src/features/library/dialogs/DlgCreateVersion.tsx index f165298c..3c4054bd 100644 --- a/rsconcept/frontend/src/features/library/dialogs/DlgCreateVersion.tsx +++ b/rsconcept/frontend/src/features/library/dialogs/DlgCreateVersion.tsx @@ -9,7 +9,7 @@ import { ModalForm } from '@/components/Modal'; import { useDialogsStore } from '@/stores/dialogs'; import { errorMsg } from '@/utils/labels'; -import { IVersionCreateDTO, schemaVersionCreate } from '../backend/api'; +import { IVersionCreateDTO, schemaVersionCreate } from '../backend/types'; import { useVersionCreate } from '../backend/useVersionCreate'; import { IVersionInfo } from '../models/library'; import { nextVersion } from '../models/libraryAPI'; diff --git a/rsconcept/frontend/src/features/library/dialogs/DlgEditVersions/DlgEditVersions.tsx b/rsconcept/frontend/src/features/library/dialogs/DlgEditVersions/DlgEditVersions.tsx index 4a91c2a9..8461bc66 100644 --- a/rsconcept/frontend/src/features/library/dialogs/DlgEditVersions/DlgEditVersions.tsx +++ b/rsconcept/frontend/src/features/library/dialogs/DlgEditVersions/DlgEditVersions.tsx @@ -9,11 +9,11 @@ import { MiniButton } from '@/components/Control'; import { IconReset, IconSave } from '@/components/Icons'; import { TextArea, TextInput } from '@/components/Input'; import { ModalView } from '@/components/Modal'; -import { useRSFormSuspense } from '@/features/rsform/backend/useRSForm'; +import { useRSFormSuspense } from '@/features/rsform'; import { useDialogsStore } from '@/stores/dialogs'; import { errorMsg } from '@/utils/labels'; -import { IVersionUpdateDTO, schemaVersionUpdate } from '../../backend/api'; +import { IVersionUpdateDTO, schemaVersionUpdate } from '../../backend/types'; import { useMutatingLibrary } from '../../backend/useMutatingLibrary'; import { useVersionDelete } from '../../backend/useVersionDelete'; import { useVersionUpdate } from '../../backend/useVersionUpdate'; diff --git a/rsconcept/frontend/src/features/library/index.ts b/rsconcept/frontend/src/features/library/index.ts index ff387c0b..11b3a967 100644 --- a/rsconcept/frontend/src/features/library/index.ts +++ b/rsconcept/frontend/src/features/library/index.ts @@ -1,4 +1,3 @@ -export { libraryApi } from './backend/api'; export { useDeleteItem } from './backend/useDeleteItem'; export { useLibrary, useLibrarySuspense } from './backend/useLibrary'; export { useMutatingLibrary } from './backend/useMutatingLibrary'; diff --git a/rsconcept/frontend/src/features/library/models/library.ts b/rsconcept/frontend/src/features/library/models/library.ts index bd15ef55..418080c5 100644 --- a/rsconcept/frontend/src/features/library/models/library.ts +++ b/rsconcept/frontend/src/features/library/models/library.ts @@ -31,22 +31,12 @@ export enum LocationHead { export const BASIC_SCHEMAS = '/L/Базовые'; -/** - * Represents {@link LibraryItem} identifier type. - */ -export type LibraryItemID = number; - -/** - * Represents {@link Version} identifier type. - */ -export type VersionID = number; - /** * Represents library item version information. */ export interface IVersionInfo { - id: VersionID; - item: LibraryItemID; + id: number; + item: number; version: string; description: string; time_create: string; @@ -56,7 +46,7 @@ export interface IVersionInfo { * Represents library item common data typical for all item types. */ export interface ILibraryItem { - id: LibraryItemID; + id: number; item_type: LibraryItemType; title: string; alias: string; @@ -86,7 +76,7 @@ export interface ILibraryItemReference extends Pick(); + private operationByID = new Map(); private schemaIDs: number[] = []; private items: ILibraryItem[]; @@ -72,7 +66,7 @@ export class OssLoader { }); } - private inferConsolidation(operationID: OperationID): boolean { + private inferConsolidation(operationID: number): boolean { const inputs = this.graph.expandInputs([operationID]); if (inputs.length === 0) { return false; diff --git a/rsconcept/frontend/src/features/oss/backend/api.ts b/rsconcept/frontend/src/features/oss/backend/api.ts index 3b8a0e87..f96f1f05 100644 --- a/rsconcept/frontend/src/features/oss/backend/api.ts +++ b/rsconcept/frontend/src/features/oss/backend/api.ts @@ -1,157 +1,29 @@ import { queryOptions } from '@tanstack/react-query'; -import { z } from 'zod'; import { axiosGet, axiosPatch, axiosPost } from '@/backend/apiTransport'; -import { DELAYS } from '@/backend/configuration'; -import { ILibraryItem, ILibraryItemData } from '@/features/library/models/library'; -import { IArgument, ICstSubstituteEx, IOperation, OperationID, OperationType } from '@/features/oss/models/oss'; -import { schemaCstSubstitute } from '@/features/rsform/backend/api'; +import { DELAYS, KEYS } from '@/backend/configuration'; import { IConstituentaReference, ITargetCst } from '@/features/rsform/models/rsform'; import { infoMsg } from '@/utils/labels'; -/** - * Represents {@link IOperation} data from server. - */ -export interface IOperationDTO extends Omit {} - -/** - * Represents backend data for {@link IOperationSchema}. - */ -export interface IOperationSchemaDTO extends ILibraryItemData { - items: IOperationDTO[]; - arguments: IArgument[]; - substitutions: ICstSubstituteEx[]; -} - -/** - * Represents {@link IOperation} position. - */ -export const schemaOperationPosition = z.object({ - id: z.number(), - position_x: z.number(), - position_y: z.number() -}); - -/** - * Represents {@link IOperation} position. - */ -export type IOperationPosition = z.infer; - -/** - * Represents {@link IOperation} data, used in creation process. - */ -export const schemaOperationCreate = z.object({ - positions: z.array(schemaOperationPosition), - item_data: z.object({ - alias: z.string().nonempty(), - operation_type: z.nativeEnum(OperationType), - title: z.string(), - comment: z.string(), - position_x: z.number(), - position_y: z.number(), - result: z.number().nullable() - }), - arguments: z.array(z.number()), - create_schema: z.boolean() -}); - -/** - * Represents {@link IOperation} data, used in creation process. - */ -export type IOperationCreateDTO = z.infer; - -/** - * Represents data response when creating {@link IOperation}. - */ -export interface IOperationCreatedResponse { - new_operation: IOperationDTO; - oss: IOperationSchemaDTO; -} - -/** - * Represents target {@link IOperation}. - */ -export interface ITargetOperation { - positions: IOperationPosition[]; - target: OperationID; -} - -/** - * Represents {@link IOperation} data, used in destruction process. - */ -export const schemaOperationDelete = z.object({ - target: z.number(), - positions: z.array(schemaOperationPosition), - keep_constituents: z.boolean(), - delete_schema: z.boolean() -}); - -/** - * Represents {@link IOperation} data, used in destruction process. - */ -export type IOperationDeleteDTO = z.infer; - -/** - * Represents data response when creating {@link IRSForm} for Input {@link IOperation}. - */ -export interface IInputCreatedResponse { - new_schema: ILibraryItem; - oss: IOperationSchemaDTO; -} - -/** - * Represents {@link IOperation} data, used in setInput process. - */ -export const schemaInputUpdate = z.object({ - target: z.number(), - positions: z.array(schemaOperationPosition), - input: z.number().nullable() -}); - -/** - * Represents {@link IOperation} data, used in setInput process. - */ -export type IInputUpdateDTO = z.infer; - -/** - * Represents {@link IOperation} data, used in update process. - */ -export const schemaOperationUpdate = z.object({ - target: z.number(), - positions: z.array(schemaOperationPosition), - item_data: z.object({ - alias: z.string().nonempty(), - title: z.string(), - comment: z.string() - }), - arguments: z.array(z.number()), - substitutions: z.array(schemaCstSubstitute) -}); - -/** - * Represents {@link IOperation} data, used in update process. - */ -export type IOperationUpdateDTO = z.infer; - -/** - * Represents data, used relocating {@link IConstituenta}s between {@link ILibraryItem}s. - */ -export const schemaCstRelocate = z.object({ - destination: z.number(), - items: z.array(z.number()).refine(data => data.length > 0) -}); - -/** - * Represents data, used relocating {@link IConstituenta}s between {@link ILibraryItem}s. - */ -export type ICstRelocateDTO = z.infer; +import { + ICstRelocateDTO, + IInputCreatedResponse, + IInputUpdateDTO, + IOperationCreatedResponse, + IOperationCreateDTO, + IOperationDeleteDTO, + IOperationPosition, + IOperationSchemaDTO, + IOperationUpdateDTO, + ITargetOperation +} from './types'; export const ossApi = { - baseKey: 'oss', + baseKey: KEYS.oss, getOssQueryOptions: ({ itemID }: { itemID?: number }) => { return queryOptions({ - queryKey: [ossApi.baseKey, 'item', itemID], + queryKey: KEYS.composite.ossItem({ itemID }), staleTime: DELAYS.staleShort, queryFn: meta => !itemID diff --git a/rsconcept/frontend/src/features/oss/backend/types.ts b/rsconcept/frontend/src/features/oss/backend/types.ts new file mode 100644 index 00000000..d248fe9c --- /dev/null +++ b/rsconcept/frontend/src/features/oss/backend/types.ts @@ -0,0 +1,143 @@ +import { z } from 'zod'; + +import { ILibraryItem, ILibraryItemData } from '@/features/library/models/library'; +import { schemaCstSubstitute } from '@/features/rsform/backend/types'; + +import { IArgument, ICstSubstituteEx, IOperation, OperationType } from '../models/oss'; + +/** + * Represents {@link IOperation} data from server. + */ +export interface IOperationDTO extends Omit {} + +/** + * Represents backend data for {@link IOperationSchema}. + */ +export interface IOperationSchemaDTO extends ILibraryItemData { + items: IOperationDTO[]; + arguments: IArgument[]; + substitutions: ICstSubstituteEx[]; +} + +/** + * Represents {@link IOperation} position. + */ +export const schemaOperationPosition = z.object({ + id: z.number(), + position_x: z.number(), + position_y: z.number() +}); + +/** + * Represents {@link IOperation} position. + */ +export type IOperationPosition = z.infer; + +/** + * Represents {@link IOperation} data, used in creation process. + */ +export const schemaOperationCreate = z.object({ + positions: z.array(schemaOperationPosition), + item_data: z.object({ + alias: z.string().nonempty(), + operation_type: z.nativeEnum(OperationType), + title: z.string(), + comment: z.string(), + position_x: z.number(), + position_y: z.number(), + result: z.number().nullable() + }), + arguments: z.array(z.number()), + create_schema: z.boolean() +}); + +/** + * Represents {@link IOperation} data, used in creation process. + */ +export type IOperationCreateDTO = z.infer; + +/** + * Represents data response when creating {@link IOperation}. + */ +export interface IOperationCreatedResponse { + new_operation: IOperationDTO; + oss: IOperationSchemaDTO; +} + +/** + * Represents target {@link IOperation}. + */ +export interface ITargetOperation { + positions: IOperationPosition[]; + target: number; +} + +/** + * Represents {@link IOperation} data, used in destruction process. + */ +export const schemaOperationDelete = z.object({ + target: z.number(), + positions: z.array(schemaOperationPosition), + keep_constituents: z.boolean(), + delete_schema: z.boolean() +}); + +/** + * Represents {@link IOperation} data, used in destruction process. + */ +export type IOperationDeleteDTO = z.infer; + +/** + * Represents data response when creating {@link IRSForm} for Input {@link IOperation}. + */ +export interface IInputCreatedResponse { + new_schema: ILibraryItem; + oss: IOperationSchemaDTO; +} + +/** + * Represents {@link IOperation} data, used in setInput process. + */ +export const schemaInputUpdate = z.object({ + target: z.number(), + positions: z.array(schemaOperationPosition), + input: z.number().nullable() +}); + +/** + * Represents {@link IOperation} data, used in setInput process. + */ +export type IInputUpdateDTO = z.infer; + +/** + * Represents {@link IOperation} data, used in update process. + */ +export const schemaOperationUpdate = z.object({ + target: z.number(), + positions: z.array(schemaOperationPosition), + item_data: z.object({ + alias: z.string().nonempty(), + title: z.string(), + comment: z.string() + }), + arguments: z.array(z.number()), + substitutions: z.array(schemaCstSubstitute) +}); + +/** + * Represents {@link IOperation} data, used in update process. + */ +export type IOperationUpdateDTO = z.infer; + +/** + * Represents data, used relocating {@link IConstituenta}s between {@link ILibraryItem}s. + */ +export const schemaCstRelocate = z.object({ + destination: z.number(), + items: z.array(z.number()).refine(data => data.length > 0) +}); + +/** + * Represents data, used relocating {@link IConstituenta}s between {@link ILibraryItem}s. + */ +export type ICstRelocateDTO = z.infer; diff --git a/rsconcept/frontend/src/features/oss/backend/useInputCreate.tsx b/rsconcept/frontend/src/features/oss/backend/useInputCreate.tsx index 3df53467..0cb73664 100644 --- a/rsconcept/frontend/src/features/oss/backend/useInputCreate.tsx +++ b/rsconcept/frontend/src/features/oss/backend/useInputCreate.tsx @@ -1,9 +1,9 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { libraryApi } from '@/features/library'; -import { rsformsApi } from '@/features/rsform/backend/api'; +import { KEYS } from '@/backend/configuration'; -import { ITargetOperation, ossApi } from './api'; +import { ossApi } from './api'; +import { ITargetOperation } from './types'; export const useInputCreate = () => { const client = useQueryClient(); @@ -13,8 +13,8 @@ export const useInputCreate = () => { onSuccess: data => { client.setQueryData(ossApi.getOssQueryOptions({ itemID: data.oss.id }).queryKey, data.oss); return Promise.allSettled([ - client.invalidateQueries({ queryKey: libraryApi.libraryListKey }), - client.invalidateQueries({ queryKey: [rsformsApi.baseKey] }) + client.invalidateQueries({ queryKey: KEYS.composite.libraryList }), + client.invalidateQueries({ queryKey: [KEYS.rsform] }) ]); } }); diff --git a/rsconcept/frontend/src/features/oss/backend/useInputUpdate.tsx b/rsconcept/frontend/src/features/oss/backend/useInputUpdate.tsx index e65580b5..3250f176 100644 --- a/rsconcept/frontend/src/features/oss/backend/useInputUpdate.tsx +++ b/rsconcept/frontend/src/features/oss/backend/useInputUpdate.tsx @@ -1,9 +1,9 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { libraryApi } from '@/features/library'; -import { rsformsApi } from '@/features/rsform/backend/api'; +import { KEYS } from '@/backend/configuration'; -import { IInputUpdateDTO, ossApi } from './api'; +import { ossApi } from './api'; +import { IInputUpdateDTO } from './types'; export const useInputUpdate = () => { const client = useQueryClient(); @@ -13,8 +13,8 @@ export const useInputUpdate = () => { onSuccess: data => { client.setQueryData(ossApi.getOssQueryOptions({ itemID: data.id }).queryKey, data); return Promise.allSettled([ - client.invalidateQueries({ queryKey: libraryApi.libraryListKey }), - client.invalidateQueries({ queryKey: [rsformsApi.baseKey] }) + client.invalidateQueries({ queryKey: KEYS.composite.libraryList }), + client.invalidateQueries({ queryKey: [KEYS.rsform] }) ]); } }); diff --git a/rsconcept/frontend/src/features/oss/backend/useMutatingOss.tsx b/rsconcept/frontend/src/features/oss/backend/useMutatingOss.tsx index 37e449fa..f34a5686 100644 --- a/rsconcept/frontend/src/features/oss/backend/useMutatingOss.tsx +++ b/rsconcept/frontend/src/features/oss/backend/useMutatingOss.tsx @@ -1,11 +1,9 @@ import { useIsMutating } from '@tanstack/react-query'; -import { libraryApi } from '@/features/library'; - -import { ossApi } from './api'; +import { KEYS } from '@/backend/configuration'; export const useMutatingOss = () => { - const countLibrary = useIsMutating({ mutationKey: [libraryApi.baseKey] }); - const countOss = useIsMutating({ mutationKey: [ossApi.baseKey] }); + const countLibrary = useIsMutating({ mutationKey: [KEYS.library] }); + const countOss = useIsMutating({ mutationKey: [KEYS.oss] }); return countLibrary + countOss !== 0; }; diff --git a/rsconcept/frontend/src/features/oss/backend/useOSS.tsx b/rsconcept/frontend/src/features/oss/backend/useOSS.tsx index dd70c6a8..abddd515 100644 --- a/rsconcept/frontend/src/features/oss/backend/useOSS.tsx +++ b/rsconcept/frontend/src/features/oss/backend/useOSS.tsx @@ -1,8 +1,8 @@ import { useQuery, useSuspenseQuery } from '@tanstack/react-query'; +import { queryClient } from '@/backend/queryClient'; import { useLibrary, useLibrarySuspense } from '@/features/library/backend/useLibrary'; -import { queryClient } from '../../../backend/queryClient'; import { ossApi } from './api'; import { OssLoader } from './OssLoader'; diff --git a/rsconcept/frontend/src/features/oss/backend/useOperationCreate.tsx b/rsconcept/frontend/src/features/oss/backend/useOperationCreate.tsx index 86b87eae..6d4f4ce7 100644 --- a/rsconcept/frontend/src/features/oss/backend/useOperationCreate.tsx +++ b/rsconcept/frontend/src/features/oss/backend/useOperationCreate.tsx @@ -2,7 +2,8 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useUpdateTimestamp } from '@/features/library'; -import { IOperationCreateDTO, ossApi } from './api'; +import { ossApi } from './api'; +import { IOperationCreateDTO } from './types'; export const useOperationCreate = () => { const client = useQueryClient(); diff --git a/rsconcept/frontend/src/features/oss/backend/useOperationDelete.tsx b/rsconcept/frontend/src/features/oss/backend/useOperationDelete.tsx index ae3de11b..2b386593 100644 --- a/rsconcept/frontend/src/features/oss/backend/useOperationDelete.tsx +++ b/rsconcept/frontend/src/features/oss/backend/useOperationDelete.tsx @@ -1,9 +1,9 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { libraryApi } from '@/features/library'; -import { rsformsApi } from '@/features/rsform/backend/api'; +import { KEYS } from '@/backend/configuration'; -import { IOperationDeleteDTO, ossApi } from './api'; +import { ossApi } from './api'; +import { IOperationDeleteDTO } from './types'; export const useOperationDelete = () => { const client = useQueryClient(); @@ -13,8 +13,8 @@ export const useOperationDelete = () => { onSuccess: data => { client.setQueryData(ossApi.getOssQueryOptions({ itemID: data.id }).queryKey, data); return Promise.allSettled([ - client.invalidateQueries({ queryKey: libraryApi.libraryListKey }), - client.invalidateQueries({ queryKey: [rsformsApi.baseKey] }) + client.invalidateQueries({ queryKey: KEYS.composite.libraryList }), + client.invalidateQueries({ queryKey: [KEYS.rsform] }) ]); } }); diff --git a/rsconcept/frontend/src/features/oss/backend/useOperationExecute.tsx b/rsconcept/frontend/src/features/oss/backend/useOperationExecute.tsx index 8b3788ae..eed40874 100644 --- a/rsconcept/frontend/src/features/oss/backend/useOperationExecute.tsx +++ b/rsconcept/frontend/src/features/oss/backend/useOperationExecute.tsx @@ -1,9 +1,9 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { libraryApi } from '@/features/library'; -import { rsformsApi } from '@/features/rsform/backend/api'; +import { KEYS } from '@/backend/configuration'; -import { ITargetOperation, ossApi } from './api'; +import { ossApi } from './api'; +import { ITargetOperation } from './types'; export const useOperationExecute = () => { const client = useQueryClient(); @@ -13,8 +13,8 @@ export const useOperationExecute = () => { onSuccess: data => { client.setQueryData(ossApi.getOssQueryOptions({ itemID: data.id }).queryKey, data); return Promise.allSettled([ - client.invalidateQueries({ queryKey: libraryApi.libraryListKey }), - client.invalidateQueries({ queryKey: [rsformsApi.baseKey] }) + client.invalidateQueries({ queryKey: KEYS.composite.libraryList }), + client.invalidateQueries({ queryKey: [KEYS.rsform] }) ]); } }); diff --git a/rsconcept/frontend/src/features/oss/backend/useOperationUpdate.tsx b/rsconcept/frontend/src/features/oss/backend/useOperationUpdate.tsx index 3b981d6e..34d8626a 100644 --- a/rsconcept/frontend/src/features/oss/backend/useOperationUpdate.tsx +++ b/rsconcept/frontend/src/features/oss/backend/useOperationUpdate.tsx @@ -1,10 +1,10 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { libraryApi } from '@/features/library'; +import { KEYS } from '@/backend/configuration'; import { ILibraryItem } from '@/features/library/models/library'; -import { rsformsApi } from '@/features/rsform/backend/api'; -import { IOperationUpdateDTO, ossApi } from './api'; +import { ossApi } from './api'; +import { IOperationUpdateDTO } from './types'; export const useOperationUpdate = () => { const client = useQueryClient(); @@ -12,12 +12,12 @@ export const useOperationUpdate = () => { mutationKey: [ossApi.baseKey, 'operation-update'], mutationFn: ossApi.operationUpdate, onSuccess: (data, variables) => { - client.setQueryData(ossApi.getOssQueryOptions({ itemID: data.id }).queryKey, data); + client.setQueryData(KEYS.composite.ossItem({ itemID: data.id }), data); const schemaID = data.items.find(item => item.id === variables.data.target)?.result; if (!schemaID) { return; } - client.setQueryData(libraryApi.libraryListKey, (prev: ILibraryItem[] | undefined) => + client.setQueryData(KEYS.composite.libraryList, (prev: ILibraryItem[] | undefined) => !prev ? undefined : prev.map(item => @@ -25,7 +25,7 @@ export const useOperationUpdate = () => { ) ); return client.invalidateQueries({ - queryKey: rsformsApi.getRSFormQueryOptions({ itemID: schemaID }).queryKey + queryKey: KEYS.composite.rsItem({ itemID: schemaID }) }); } }); diff --git a/rsconcept/frontend/src/features/oss/backend/useRelocateConstituents.tsx b/rsconcept/frontend/src/features/oss/backend/useRelocateConstituents.tsx index 465df171..960f5997 100644 --- a/rsconcept/frontend/src/features/oss/backend/useRelocateConstituents.tsx +++ b/rsconcept/frontend/src/features/oss/backend/useRelocateConstituents.tsx @@ -1,9 +1,9 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { libraryApi } from '@/features/library'; -import { rsformsApi } from '@/features/rsform/backend/api'; +import { KEYS } from '@/backend/configuration'; -import { ICstRelocateDTO, ossApi } from './api'; +import { ossApi } from './api'; +import { ICstRelocateDTO } from './types'; export const useRelocateConstituents = () => { const client = useQueryClient(); @@ -13,8 +13,8 @@ export const useRelocateConstituents = () => { onSuccess: data => { client.setQueryData(ossApi.getOssQueryOptions({ itemID: data.id }).queryKey, data); return Promise.allSettled([ - client.invalidateQueries({ queryKey: libraryApi.libraryListKey }), - client.invalidateQueries({ queryKey: [rsformsApi.baseKey] }) + client.invalidateQueries({ queryKey: KEYS.composite.libraryList }), + client.invalidateQueries({ queryKey: [KEYS.rsform] }) ]); } }); diff --git a/rsconcept/frontend/src/features/oss/backend/useUpdatePositions.tsx b/rsconcept/frontend/src/features/oss/backend/useUpdatePositions.tsx index fbda7ca6..8d6613e6 100644 --- a/rsconcept/frontend/src/features/oss/backend/useUpdatePositions.tsx +++ b/rsconcept/frontend/src/features/oss/backend/useUpdatePositions.tsx @@ -2,7 +2,8 @@ import { useMutation } from '@tanstack/react-query'; import { useUpdateTimestamp } from '@/features/library'; -import { IOperationPosition, ossApi } from './api'; +import { ossApi } from './api'; +import { IOperationPosition } from './types'; export const useUpdatePositions = () => { const { updateTimestamp } = useUpdateTimestamp(); diff --git a/rsconcept/frontend/src/features/oss/dialogs/DlgChangeInputSchema.tsx b/rsconcept/frontend/src/features/oss/dialogs/DlgChangeInputSchema.tsx index 7e5cb4b9..23157382 100644 --- a/rsconcept/frontend/src/features/oss/dialogs/DlgChangeInputSchema.tsx +++ b/rsconcept/frontend/src/features/oss/dialogs/DlgChangeInputSchema.tsx @@ -11,7 +11,7 @@ import { ModalForm } from '@/components/Modal'; import { ILibraryItem, LibraryItemType, PickSchema, useLibrary } from '@/features/library'; import { useDialogsStore } from '@/stores/dialogs'; -import { IInputUpdateDTO, IOperationPosition, schemaInputUpdate } from '../backend/api'; +import { IInputUpdateDTO, IOperationPosition, schemaInputUpdate } from '../backend/types'; import { useInputUpdate } from '../backend/useInputUpdate'; import { IOperation, IOperationSchema } from '../models/oss'; import { sortItemsForOSS } from '../models/ossAPI'; diff --git a/rsconcept/frontend/src/features/oss/dialogs/DlgCreateOperation/DlgCreateOperation.tsx b/rsconcept/frontend/src/features/oss/dialogs/DlgCreateOperation/DlgCreateOperation.tsx index 8b924db0..388f53b5 100644 --- a/rsconcept/frontend/src/features/oss/dialogs/DlgCreateOperation/DlgCreateOperation.tsx +++ b/rsconcept/frontend/src/features/oss/dialogs/DlgCreateOperation/DlgCreateOperation.tsx @@ -10,7 +10,7 @@ import { TabLabel, TabList, TabPanel, Tabs } from '@/components/Tabs'; import { HelpTopic } from '@/features/help'; import { useDialogsStore } from '@/stores/dialogs'; -import { IOperationCreateDTO, IOperationPosition, schemaOperationCreate } from '../../backend/api'; +import { IOperationCreateDTO, IOperationPosition, schemaOperationCreate } from '../../backend/types'; import { useOperationCreate } from '../../backend/useOperationCreate'; import { describeOperationType, labelOperationType } from '../../labels'; import { IOperationSchema, OperationID, OperationType } from '../../models/oss'; diff --git a/rsconcept/frontend/src/features/oss/dialogs/DlgCreateOperation/TabInputOperation.tsx b/rsconcept/frontend/src/features/oss/dialogs/DlgCreateOperation/TabInputOperation.tsx index c9f51cf5..96b53f06 100644 --- a/rsconcept/frontend/src/features/oss/dialogs/DlgCreateOperation/TabInputOperation.tsx +++ b/rsconcept/frontend/src/features/oss/dialogs/DlgCreateOperation/TabInputOperation.tsx @@ -8,7 +8,7 @@ import { Checkbox, Label, TextArea, TextInput } from '@/components/Input'; import { ILibraryItem, LibraryItemType, PickSchema, useLibrary } from '@/features/library'; import { useDialogsStore } from '@/stores/dialogs'; -import { IOperationCreateDTO } from '../../backend/api'; +import { IOperationCreateDTO } from '../../backend/types'; import { sortItemsForOSS } from '../../models/ossAPI'; import { DlgCreateOperationProps } from './DlgCreateOperation'; diff --git a/rsconcept/frontend/src/features/oss/dialogs/DlgCreateOperation/TabSynthesisOperation.tsx b/rsconcept/frontend/src/features/oss/dialogs/DlgCreateOperation/TabSynthesisOperation.tsx index 1f364710..ab89c4b2 100644 --- a/rsconcept/frontend/src/features/oss/dialogs/DlgCreateOperation/TabSynthesisOperation.tsx +++ b/rsconcept/frontend/src/features/oss/dialogs/DlgCreateOperation/TabSynthesisOperation.tsx @@ -4,7 +4,7 @@ import { FlexColumn } from '@/components/Container'; import { Label, TextArea, TextInput } from '@/components/Input'; import { useDialogsStore } from '@/stores/dialogs'; -import { IOperationCreateDTO } from '../../backend/api'; +import { IOperationCreateDTO } from '../../backend/types'; import { PickMultiOperation } from '../../components/PickMultiOperation'; import { DlgCreateOperationProps } from './DlgCreateOperation'; diff --git a/rsconcept/frontend/src/features/oss/dialogs/DlgDeleteOperation.tsx b/rsconcept/frontend/src/features/oss/dialogs/DlgDeleteOperation.tsx index e5abab80..a5ade07a 100644 --- a/rsconcept/frontend/src/features/oss/dialogs/DlgDeleteOperation.tsx +++ b/rsconcept/frontend/src/features/oss/dialogs/DlgDeleteOperation.tsx @@ -7,11 +7,11 @@ import { Controller, useForm } from 'react-hook-form'; import { Checkbox, TextInput } from '@/components/Input'; import { ModalForm } from '@/components/Modal'; import { HelpTopic } from '@/features/help'; -import { IOperation, IOperationSchema } from '@/features/oss/models/oss'; import { useDialogsStore } from '@/stores/dialogs'; -import { IOperationDeleteDTO, IOperationPosition, schemaOperationDelete } from '../backend/api'; +import { IOperationDeleteDTO, IOperationPosition, schemaOperationDelete } from '../backend/types'; import { useOperationDelete } from '../backend/useOperationDelete'; +import { IOperation, IOperationSchema } from '../models/oss'; export interface DlgDeleteOperationProps { oss: IOperationSchema; diff --git a/rsconcept/frontend/src/features/oss/dialogs/DlgEditOperation/DlgEditOperation.tsx b/rsconcept/frontend/src/features/oss/dialogs/DlgEditOperation/DlgEditOperation.tsx index 00660699..4da15929 100644 --- a/rsconcept/frontend/src/features/oss/dialogs/DlgEditOperation/DlgEditOperation.tsx +++ b/rsconcept/frontend/src/features/oss/dialogs/DlgEditOperation/DlgEditOperation.tsx @@ -11,7 +11,7 @@ import { TabLabel, TabList, TabPanel, Tabs } from '@/components/Tabs'; import { HelpTopic } from '@/features/help'; import { useDialogsStore } from '@/stores/dialogs'; -import { IOperationPosition, IOperationUpdateDTO, schemaOperationUpdate } from '../../backend/api'; +import { IOperationPosition, IOperationUpdateDTO, schemaOperationUpdate } from '../../backend/types'; import { useOperationUpdate } from '../../backend/useOperationUpdate'; import { IOperation, IOperationSchema, OperationType } from '../../models/oss'; import TabArguments from './TabArguments'; diff --git a/rsconcept/frontend/src/features/oss/dialogs/DlgEditOperation/TabArguments.tsx b/rsconcept/frontend/src/features/oss/dialogs/DlgEditOperation/TabArguments.tsx index ef08b449..0828924d 100644 --- a/rsconcept/frontend/src/features/oss/dialogs/DlgEditOperation/TabArguments.tsx +++ b/rsconcept/frontend/src/features/oss/dialogs/DlgEditOperation/TabArguments.tsx @@ -5,7 +5,7 @@ import { FlexColumn } from '@/components/Container'; import { Label } from '@/components/Input'; import { useDialogsStore } from '@/stores/dialogs'; -import { IOperationUpdateDTO } from '../../backend/api'; +import { IOperationUpdateDTO } from '../../backend/types'; import { PickMultiOperation } from '../../components/PickMultiOperation'; import { DlgEditOperationProps } from './DlgEditOperation'; diff --git a/rsconcept/frontend/src/features/oss/dialogs/DlgEditOperation/TabOperation.tsx b/rsconcept/frontend/src/features/oss/dialogs/DlgEditOperation/TabOperation.tsx index 3f0a156f..e2ee4d31 100644 --- a/rsconcept/frontend/src/features/oss/dialogs/DlgEditOperation/TabOperation.tsx +++ b/rsconcept/frontend/src/features/oss/dialogs/DlgEditOperation/TabOperation.tsx @@ -2,7 +2,7 @@ import { useFormContext } from 'react-hook-form'; import { TextArea, TextInput } from '@/components/Input'; -import { IOperationUpdateDTO } from '../../backend/api'; +import { IOperationUpdateDTO } from '../../backend/types'; function TabOperation() { const { diff --git a/rsconcept/frontend/src/features/oss/dialogs/DlgEditOperation/TabSynthesis.tsx b/rsconcept/frontend/src/features/oss/dialogs/DlgEditOperation/TabSynthesis.tsx index eacff546..450e0394 100644 --- a/rsconcept/frontend/src/features/oss/dialogs/DlgEditOperation/TabSynthesis.tsx +++ b/rsconcept/frontend/src/features/oss/dialogs/DlgEditOperation/TabSynthesis.tsx @@ -3,12 +3,11 @@ import { Controller, useFormContext, useWatch } from 'react-hook-form'; import { TextArea } from '@/components/Input'; -import { useRSForms } from '@/features/rsform/backend/useRSForms'; -import PickSubstitutions from '@/features/rsform/components/PickSubstitutions'; +import { PickSubstitutions, useRSForms } from '@/features/rsform'; import { useDialogsStore } from '@/stores/dialogs'; import { APP_COLORS } from '@/styling/colors'; -import { IOperationUpdateDTO } from '../../backend/api'; +import { IOperationUpdateDTO } from '../../backend/types'; import { SubstitutionValidator } from '../../models/ossAPI'; import { DlgEditOperationProps } from './DlgEditOperation'; diff --git a/rsconcept/frontend/src/features/oss/dialogs/DlgRelocateConstituents.tsx b/rsconcept/frontend/src/features/oss/dialogs/DlgRelocateConstituents.tsx index 353ecf4a..adb65b36 100644 --- a/rsconcept/frontend/src/features/oss/dialogs/DlgRelocateConstituents.tsx +++ b/rsconcept/frontend/src/features/oss/dialogs/DlgRelocateConstituents.tsx @@ -11,11 +11,10 @@ import { Loader } from '@/components/Loader'; import { ModalForm } from '@/components/Modal'; import { HelpTopic } from '@/features/help'; import { ILibraryItem, SelectLibraryItem, useLibrary } from '@/features/library'; -import { useRSForm } from '@/features/rsform/backend/useRSForm'; -import PickMultiConstituenta from '@/features/rsform/components/PickMultiConstituenta'; +import { PickMultiConstituenta, useRSForm } from '@/features/rsform'; import { useDialogsStore } from '@/stores/dialogs'; -import { ICstRelocateDTO, IOperationPosition, schemaCstRelocate } from '../backend/api'; +import { ICstRelocateDTO, IOperationPosition, schemaCstRelocate } from '../backend/types'; import { useRelocateConstituents } from '../backend/useRelocateConstituents'; import { useUpdatePositions } from '../backend/useUpdatePositions'; import { IOperation, IOperationSchema } from '../models/oss'; diff --git a/rsconcept/frontend/src/features/oss/index.ts b/rsconcept/frontend/src/features/oss/index.ts new file mode 100644 index 00000000..d2dfee66 --- /dev/null +++ b/rsconcept/frontend/src/features/oss/index.ts @@ -0,0 +1 @@ +export { useFindPredecessor } from './backend/useFindPredecessor'; diff --git a/rsconcept/frontend/src/features/oss/models/oss.ts b/rsconcept/frontend/src/features/oss/models/oss.ts index 88088093..36b2512e 100644 --- a/rsconcept/frontend/src/features/oss/models/oss.ts +++ b/rsconcept/frontend/src/features/oss/models/oss.ts @@ -1,11 +1,9 @@ /** * Module: Schema of Synthesis Operations. */ -import { ILibraryItem, ILibraryItemData } from '@/features/library/models/library'; -import { ICstSubstitute } from '@/features/rsform/backend/api'; -import { IConstituenta } from '@/features/rsform/models/rsform'; - -import { Graph } from '../../../models/Graph'; +import { ILibraryItemData } from '@/features/library/models/library'; +import { ICstSubstitute } from '@/features/rsform'; +import { Graph } from '@/models/Graph'; /** * Represents {@link IOperation} identifier type. @@ -51,17 +49,6 @@ export interface IArgument { argument: OperationID; } -/** - * Represents substitution for multi synthesis table. - */ -export interface IMultiSubstitution { - original_source: ILibraryItem; - original: IConstituenta; - substitution: IConstituenta; - substitution_source: ILibraryItem; - is_suggestion: boolean; -} - /** * Represents {@link ICstSubstitute} extended data. */ diff --git a/rsconcept/frontend/src/features/oss/models/ossAPI.ts b/rsconcept/frontend/src/features/oss/models/ossAPI.ts index 40c76c52..b043215e 100644 --- a/rsconcept/frontend/src/features/oss/models/ossAPI.ts +++ b/rsconcept/frontend/src/features/oss/models/ossAPI.ts @@ -3,8 +3,8 @@ */ import { ILibraryItem } from '@/features/library/models/library'; -import { ICstSubstitute } from '@/features/rsform/backend/api'; -import { ConstituentaID, CstClass, CstType, IConstituenta, IRSForm } from '@/features/rsform/models/rsform'; +import { CstClass, CstType, IConstituenta, IRSForm } from '@/features/rsform'; +import { ICstSubstitute } from '@/features/rsform/backend/types'; import { AliasMapping, ParsingStatus } from '@/features/rsform/models/rslang'; import { applyAliasMapping, @@ -17,7 +17,7 @@ import { infoMsg } from '@/utils/labels'; import { TextMatcher } from '@/utils/utils'; import { Graph } from '../../../models/Graph'; -import { IOperationPosition } from '../backend/api'; +import { IOperationPosition } from '../backend/types'; import { describeSubstitutionError } from '../labels'; import { IOperation, IOperationSchema, OperationID, OperationType, SubstitutionErrorType } from './oss'; import { Position2D } from './ossLayout'; @@ -67,13 +67,13 @@ export class SubstitutionValidator { private schemas: IRSForm[]; private substitutions: ICstSubstitute[]; - private constituents = new Set(); - private originals = new Set(); + private constituents = new Set(); + private originals = new Set(); private mapping: CrossMapping = new Map(); - private cstByID = new Map(); + private cstByID = new Map(); private schemaByID = new Map(); - private schemaByCst = new Map(); + private schemaByCst = new Map(); constructor(schemas: IRSForm[], substitutions: ICstSubstitute[]) { this.schemas = schemas; @@ -125,9 +125,9 @@ export class SubstitutionValidator { } private calculateSuggestions(): void { - const candidates = new Map(); - const minors = new Set(); - const schemaByCst = new Map(); + const candidates = new Map(); + const minors = new Set(); + const schemaByCst = new Map(); for (const schema of this.schemas) { for (const cst of schema.items) { if (this.originals.has(cst.id)) { @@ -456,7 +456,7 @@ export function getRelocateCandidates( return addedCst; } - const unreachableBases: ConstituentaID[] = []; + const unreachableBases: number[] = []; for (const cst of schema.items.filter(item => item.is_inherited)) { if (cst.parent_schema == destinationSchema) { continue; diff --git a/rsconcept/frontend/src/features/oss/pages/OssPage/EditorOssCard/EditorOssCard.tsx b/rsconcept/frontend/src/features/oss/pages/OssPage/EditorOssCard/EditorOssCard.tsx index 2c92fee8..4cd4f9aa 100644 --- a/rsconcept/frontend/src/features/oss/pages/OssPage/EditorOssCard/EditorOssCard.tsx +++ b/rsconcept/frontend/src/features/oss/pages/OssPage/EditorOssCard/EditorOssCard.tsx @@ -4,7 +4,7 @@ import clsx from 'clsx'; import { FlexColumn } from '@/components/Container'; import { EditorLibraryItem } from '@/features/library'; -import ToolbarRSFormCard from '@/features/rsform/pages/RSFormPage/EditorRSFormCard/ToolbarRSFormCard'; +import { ToolbarRSFormCard } from '@/features/rsform'; import { useModificationStore } from '@/stores/modification'; import { globals } from '@/utils/constants'; diff --git a/rsconcept/frontend/src/features/oss/pages/OssPage/EditorOssCard/FormOSS.tsx b/rsconcept/frontend/src/features/oss/pages/OssPage/EditorOssCard/FormOSS.tsx index 2a3ad332..cc2f90a1 100644 --- a/rsconcept/frontend/src/features/oss/pages/OssPage/EditorOssCard/FormOSS.tsx +++ b/rsconcept/frontend/src/features/oss/pages/OssPage/EditorOssCard/FormOSS.tsx @@ -10,7 +10,7 @@ import { SubmitButton } from '@/components/Control'; import { IconSave } from '@/components/Icons'; import { TextArea, TextInput } from '@/components/Input'; import { LibraryItemType, ToolbarItemAccess, useUpdateItem } from '@/features/library'; -import { IUpdateLibraryItemDTO, schemaUpdateLibraryItem } from '@/features/library/backend/api'; +import { IUpdateLibraryItemDTO, schemaUpdateLibraryItem } from '@/features/library/backend/types'; import { useModificationStore } from '@/stores/modification'; import { globals } from '@/utils/constants'; diff --git a/rsconcept/frontend/src/features/oss/pages/OssPage/EditorOssGraph/NodeContextMenu.tsx b/rsconcept/frontend/src/features/oss/pages/OssPage/EditorOssGraph/NodeContextMenu.tsx index d340b704..82f2b162 100644 --- a/rsconcept/frontend/src/features/oss/pages/OssPage/EditorOssGraph/NodeContextMenu.tsx +++ b/rsconcept/frontend/src/features/oss/pages/OssPage/EditorOssGraph/NodeContextMenu.tsx @@ -12,12 +12,12 @@ import { IconNewRSForm, IconRSForm } from '@/components/Icons'; -import { useMutatingOss } from '@/features/oss/backend/useMutatingOss'; -import { IOperation, OperationID, OperationType } from '@/features/oss/models/oss'; import useClickedOutside from '@/hooks/useClickedOutside'; import { PARAMETER } from '@/utils/constants'; import { prepareTooltip } from '@/utils/utils'; +import { useMutatingOss } from '../../../backend/useMutatingOss'; +import { IOperation, OperationType } from '../../../models/oss'; import { useOssEdit } from '../OssEditContext'; export interface ContextMenuData { @@ -29,12 +29,12 @@ export interface ContextMenuData { interface NodeContextMenuProps extends ContextMenuData { isOpen: boolean; onHide: () => void; - onDelete: (target: OperationID) => void; - onCreateInput: (target: OperationID) => void; - onEditSchema: (target: OperationID) => void; - onEditOperation: (target: OperationID) => void; - onExecuteOperation: (target: OperationID) => void; - onRelocateConstituents: (target: OperationID) => void; + onDelete: (target: number) => void; + onCreateInput: (target: number) => void; + onEditSchema: (target: number) => void; + onEditOperation: (target: number) => void; + onExecuteOperation: (target: number) => void; + onRelocateConstituents: (target: number) => void; } function NodeContextMenu({ diff --git a/rsconcept/frontend/src/features/oss/pages/OssPage/MenuOssTabs.tsx b/rsconcept/frontend/src/features/oss/pages/OssPage/MenuOssTabs.tsx index f3d089e4..6496524e 100644 --- a/rsconcept/frontend/src/features/oss/pages/OssPage/MenuOssTabs.tsx +++ b/rsconcept/frontend/src/features/oss/pages/OssPage/MenuOssTabs.tsx @@ -19,11 +19,11 @@ import { IconShare } from '@/components/Icons'; import { useAuthSuspense } from '@/features/auth'; -import { useMutatingOss } from '@/features/oss/backend/useMutatingOss'; import { useRoleStore, UserRole } from '@/features/users'; import { describeAccessMode as describeUserRole, labelAccessMode as labelUserRole } from '@/utils/labels'; import { sharePage } from '@/utils/utils'; +import { useMutatingOss } from '../../backend/useMutatingOss'; import { useOssEdit } from './OssEditContext'; function MenuOssTabs() { diff --git a/rsconcept/frontend/src/features/oss/pages/OssPage/OssEditContext.tsx b/rsconcept/frontend/src/features/oss/pages/OssPage/OssEditContext.tsx index 10987b63..cd7bcd3d 100644 --- a/rsconcept/frontend/src/features/oss/pages/OssPage/OssEditContext.tsx +++ b/rsconcept/frontend/src/features/oss/pages/OssPage/OssEditContext.tsx @@ -11,7 +11,7 @@ import { useDialogsStore } from '@/stores/dialogs'; import { usePreferencesStore } from '@/stores/preferences'; import { promptText } from '@/utils/labels'; -import { IOperationPosition } from '../../backend/api'; +import { IOperationPosition } from '../../backend/types'; import { useOssSuspense } from '../../backend/useOSS'; import { IOperationSchema, OperationID, OperationType } from '../../models/oss'; diff --git a/rsconcept/frontend/src/features/oss/pages/OssPage/OssPage.tsx b/rsconcept/frontend/src/features/oss/pages/OssPage/OssPage.tsx index 4d494de2..9ca45a8d 100644 --- a/rsconcept/frontend/src/features/oss/pages/OssPage/OssPage.tsx +++ b/rsconcept/frontend/src/features/oss/pages/OssPage/OssPage.tsx @@ -17,7 +17,7 @@ import OssTabs from './OssTabs'; const paramsSchema = z.object({ id: z.coerce.number(), - tab: z.preprocess(v => (v ? Number(v) : undefined), z.nativeEnum(OssTabID).default(OssTabID.CARD)) + tab: z.preprocess(v => (v ? Number(v) : undefined), z.nativeEnum(OssTabID).default(OssTabID.GRAPH)) }); export function OssPage() { diff --git a/rsconcept/frontend/src/features/rsform/backend/RSFormLoader.ts b/rsconcept/frontend/src/features/rsform/backend/RSFormLoader.ts index ccaeb65c..e024ce52 100644 --- a/rsconcept/frontend/src/features/rsform/backend/RSFormLoader.ts +++ b/rsconcept/frontend/src/features/rsform/backend/RSFormLoader.ts @@ -4,11 +4,11 @@ import { Graph } from '@/models/Graph'; -import { ConstituentaID, CstType, IConstituenta, IRSForm, IRSFormStats } from '../models/rsform'; +import { CstType, IConstituenta, IRSForm, IRSFormStats } from '../models/rsform'; import { inferClass, inferStatus, inferTemplate, isBaseSet, isFunctional } from '../models/rsformAPI'; import { ParsingStatus, ValueClass } from '../models/rslang'; import { extractGlobals, isSimpleExpression, splitTemplateDefinition } from '../models/rslangAPI'; -import { IRSFormDTO } from './api'; +import { IRSFormDTO } from './types'; /** * Loads data into an {@link IRSForm} based on {@link IRSFormDTO}. @@ -21,7 +21,7 @@ export class RSFormLoader { private schema: IRSFormDTO; private graph: Graph = new Graph(); private cstByAlias = new Map(); - private cstByID = new Map(); + private cstByID = new Map(); constructor(input: IRSFormDTO) { this.schema = input; @@ -61,7 +61,7 @@ export class RSFormLoader { } private inferCstAttributes() { - const schemaByCst = new Map(); + const schemaByCst = new Map(); const parents: number[] = []; this.schema.inheritance.forEach(item => { if (item.child_source === this.schema.id) { @@ -120,7 +120,7 @@ export class RSFormLoader { return isSimpleExpression(expression); } - private inferParent(target: IConstituenta): ConstituentaID | undefined { + private inferParent(target: IConstituenta): number | undefined { const sources = this.extractSources(target); if (sources.size !== 1 || sources.has(target.id)) { return undefined; @@ -133,8 +133,8 @@ export class RSFormLoader { return parent_id; } - private extractSources(target: IConstituenta): Set { - const sources = new Set(); + private extractSources(target: IConstituenta): Set { + const sources = new Set(); if (!isFunctional(target.cst_type)) { const node = this.graph.at(target.id)!; node.inputs.forEach(id => { diff --git a/rsconcept/frontend/src/features/rsform/backend/api.ts b/rsconcept/frontend/src/features/rsform/backend/api.ts index cfa470e5..5da3cf1c 100644 --- a/rsconcept/frontend/src/features/rsform/backend/api.ts +++ b/rsconcept/frontend/src/features/rsform/backend/api.ts @@ -1,181 +1,31 @@ import { queryOptions } from '@tanstack/react-query'; -import { z } from 'zod'; import { axiosGet, axiosPatch, axiosPost } from '@/backend/apiTransport'; -import { DELAYS } from '@/backend/configuration'; -import { ILibraryItemReference, ILibraryItemVersioned } from '@/features/library/models/library'; -import { errorMsg, infoMsg } from '@/utils/labels'; +import { DELAYS, KEYS } from '@/backend/configuration'; +import { infoMsg } from '@/utils/labels'; +import { IConstituentaList, IConstituentaMeta, ITargetCst } from '../models/rsform'; +import { IExpressionParse } from '../models/rslang'; import { - ConstituentaID, - CstType, - IConstituentaList, - IConstituentaMeta, - IInheritanceInfo, - ITargetCst, - TermForm -} from '../models/rsform'; -import { IArgumentInfo, IExpressionParse, ParsingStatus, ValueClass } from '../models/rslang'; - -/** - * Represents {@link IConstituenta} data from server. - */ -export interface IConstituentaDTO extends IConstituentaMeta { - parse: { - status: ParsingStatus; - valueClass: ValueClass; - typification: string; - syntaxTree: string; - args: IArgumentInfo[]; - }; -} - -/** - * Represents data for {@link IRSForm} provided by backend. - */ -export interface IRSFormDTO extends ILibraryItemVersioned { - items: IConstituentaDTO[]; - inheritance: IInheritanceInfo[]; - oss: ILibraryItemReference[]; -} - -/** - * Represents data, used for uploading {@link IRSForm} as file. - */ -export interface IRSFormUploadDTO { - itemID: number; - load_metadata: boolean; - file: File; - fileName: string; -} - -/** - * Represents {@link IConstituenta} data, used in creation process. - */ -export interface ICstCreateDTO { - alias: string; - cst_type: CstType; - definition_raw: string; - term_raw: string; - convention: string; - definition_formal: string; - term_forms: TermForm[]; - - insert_after: ConstituentaID | null; -} - -/** - * Represents data response when creating {@link IConstituenta}. - */ -export interface ICstCreatedResponse { - new_cst: IConstituentaMeta; - schema: IRSFormDTO; -} - -/** - * Represents data, used in updating persistent attributes in {@link IConstituenta}. - */ -export const schemaCstUpdate = z.object({ - target: z.number(), - item_data: z.object({ - convention: z.string().optional(), - definition_formal: z.string().optional(), - definition_raw: z.string().optional(), - term_raw: z.string().optional(), - term_forms: z.array(z.object({ text: z.string(), tags: z.string() })).optional() - }) -}); - -/** - * Represents data, used in updating persistent attributes in {@link IConstituenta}. - */ -export type ICstUpdateDTO = z.infer; - -/** - * Represents data, used in renaming {@link IConstituenta}. - */ -export const schemaCstRename = z.object({ - target: z.number(), - alias: z.string(), - cst_type: z.nativeEnum(CstType) -}); - -/** - * Represents data, used in renaming {@link IConstituenta}. - */ -export type ICstRenameDTO = z.infer; - -/** - * Represents data, used in ordering a list of {@link IConstituenta}. - */ -export interface ICstMoveDTO { - items: ConstituentaID[]; - move_to: number; // Note: 0-base index -} - -/** - * Represents data response when creating producing structure of {@link IConstituenta}. - */ -export interface IProduceStructureResponse { - cst_list: ConstituentaID[]; - schema: IRSFormDTO; -} - -/** - * Represents data, used in merging single {@link IConstituenta}. - */ -export const schemaCstSubstitute = z.object({ - original: z.number(), - substitution: z.number() -}); - -/** - * Represents data, used in merging single {@link IConstituenta}. - */ -export type ICstSubstitute = z.infer; - -/** - * Represents input data for inline synthesis. - */ -export const schemaInlineSynthesis = z.object({ - receiver: z.number(), - source: z.number().nullable(), - items: z.array(z.number()), - substitutions: z.array(schemaCstSubstitute) -}); - -/** - * Represents input data for inline synthesis. - */ -export type IInlineSynthesisDTO = z.infer; - -/** - * Represents {@link IConstituenta} data, used for checking expression. - */ -export interface ICheckConstituentaDTO { - alias: string; - cst_type: CstType; - definition_formal: string; -} - -/** - * Represents data, used in renaming {@link IConstituenta}. - */ -export const schemaCstSubstitutions = z.object({ - substitutions: z.array(schemaCstSubstitute).min(1, { message: errorMsg.emptySubstitutions }) -}); - -/** - * Represents data, used in merging multiple {@link IConstituenta}. - */ -export type ICstSubstitutionsDTO = z.infer; + ICheckConstituentaDTO, + ICstCreatedResponse, + ICstCreateDTO, + ICstMoveDTO, + ICstRenameDTO, + ICstSubstitutionsDTO, + ICstUpdateDTO, + IInlineSynthesisDTO, + IProduceStructureResponse, + IRSFormDTO, + IRSFormUploadDTO +} from './types'; export const rsformsApi = { - baseKey: 'rsform', + baseKey: KEYS.rsform, getRSFormQueryOptions: ({ itemID, version }: { itemID?: number; version?: number }) => { return queryOptions({ - queryKey: [rsformsApi.baseKey, 'item', itemID, version ?? ''], + queryKey: KEYS.composite.rsItem({ itemID, version }), staleTime: DELAYS.staleShort, queryFn: meta => !itemID diff --git a/rsconcept/frontend/src/features/rsform/backend/cctext/api.ts b/rsconcept/frontend/src/features/rsform/backend/cctext/api.ts index c89e2311..2439d644 100644 --- a/rsconcept/frontend/src/features/rsform/backend/cctext/api.ts +++ b/rsconcept/frontend/src/features/rsform/backend/cctext/api.ts @@ -1,4 +1,5 @@ import { axiosPost } from '@/backend/apiTransport'; +import { KEYS } from '@/backend/configuration'; /** * Represents API result for text output. @@ -23,7 +24,7 @@ export interface ILexemeResponse { } export const cctextApi = { - baseKey: 'cctext', + baseKey: KEYS.cctext, inflectText: (data: IWordFormDTO) => axiosPost({ diff --git a/rsconcept/frontend/src/features/rsform/backend/cctext/useIsProcessingCctext.tsx b/rsconcept/frontend/src/features/rsform/backend/cctext/useIsProcessingCctext.tsx index 401a032e..6a8336d0 100644 --- a/rsconcept/frontend/src/features/rsform/backend/cctext/useIsProcessingCctext.tsx +++ b/rsconcept/frontend/src/features/rsform/backend/cctext/useIsProcessingCctext.tsx @@ -1,8 +1,8 @@ import { useIsMutating } from '@tanstack/react-query'; -import { cctextApi } from './api'; +import { KEYS } from '@/backend/configuration'; export const useIsProcessingCctext = () => { - const countMutations = useIsMutating({ mutationKey: [cctextApi.baseKey] }); + const countMutations = useIsMutating({ mutationKey: [KEYS.cctext] }); return countMutations !== 0; }; diff --git a/rsconcept/frontend/src/features/rsform/backend/types.ts b/rsconcept/frontend/src/features/rsform/backend/types.ts new file mode 100644 index 00000000..aa179f7e --- /dev/null +++ b/rsconcept/frontend/src/features/rsform/backend/types.ts @@ -0,0 +1,160 @@ +import { z } from 'zod'; + +import { ILibraryItemReference, ILibraryItemVersioned } from '@/features/library/models/library'; +import { errorMsg } from '@/utils/labels'; + +import { CstType, IConstituentaMeta, IInheritanceInfo, TermForm } from '../models/rsform'; +import { IArgumentInfo, ParsingStatus, ValueClass } from '../models/rslang'; + +/** + * Represents {@link IConstituenta} data from server. + */ +export interface IConstituentaDTO extends IConstituentaMeta { + parse: { + status: ParsingStatus; + valueClass: ValueClass; + typification: string; + syntaxTree: string; + args: IArgumentInfo[]; + }; +} + +/** + * Represents data for {@link IRSForm} provided by backend. + */ +export interface IRSFormDTO extends ILibraryItemVersioned { + items: IConstituentaDTO[]; + inheritance: IInheritanceInfo[]; + oss: ILibraryItemReference[]; +} + +/** + * Represents data, used for uploading {@link IRSForm} as file. + */ +export interface IRSFormUploadDTO { + itemID: number; + load_metadata: boolean; + file: File; + fileName: string; +} + +/** + * Represents {@link IConstituenta} data, used in creation process. + */ +export interface ICstCreateDTO { + alias: string; + cst_type: CstType; + definition_raw: string; + term_raw: string; + convention: string; + definition_formal: string; + term_forms: TermForm[]; + + insert_after: number | null; +} + +/** + * Represents data response when creating {@link IConstituenta}. + */ +export interface ICstCreatedResponse { + new_cst: IConstituentaMeta; + schema: IRSFormDTO; +} + +/** + * Represents data, used in updating persistent attributes in {@link IConstituenta}. + */ +export const schemaCstUpdate = z.object({ + target: z.number(), + item_data: z.object({ + convention: z.string().optional(), + definition_formal: z.string().optional(), + definition_raw: z.string().optional(), + term_raw: z.string().optional(), + term_forms: z.array(z.object({ text: z.string(), tags: z.string() })).optional() + }) +}); + +/** + * Represents data, used in updating persistent attributes in {@link IConstituenta}. + */ +export type ICstUpdateDTO = z.infer; + +/** + * Represents data, used in renaming {@link IConstituenta}. + */ +export const schemaCstRename = z.object({ + target: z.number(), + alias: z.string(), + cst_type: z.nativeEnum(CstType) +}); + +/** + * Represents data, used in renaming {@link IConstituenta}. + */ +export type ICstRenameDTO = z.infer; + +/** + * Represents data, used in ordering a list of {@link IConstituenta}. + */ +export interface ICstMoveDTO { + items: number[]; + move_to: number; // Note: 0-base index +} + +/** + * Represents data response when creating producing structure of {@link IConstituenta}. + */ +export interface IProduceStructureResponse { + cst_list: number[]; + schema: IRSFormDTO; +} + +/** + * Represents data, used in merging single {@link IConstituenta}. + */ +export const schemaCstSubstitute = z.object({ + original: z.number(), + substitution: z.number() +}); + +/** + * Represents data, used in merging single {@link IConstituenta}. + */ +export type ICstSubstitute = z.infer; + +/** + * Represents input data for inline synthesis. + */ +export const schemaInlineSynthesis = z.object({ + receiver: z.number(), + source: z.number().nullable(), + items: z.array(z.number()), + substitutions: z.array(schemaCstSubstitute) +}); + +/** + * Represents input data for inline synthesis. + */ +export type IInlineSynthesisDTO = z.infer; + +/** + * Represents {@link IConstituenta} data, used for checking expression. + */ +export interface ICheckConstituentaDTO { + alias: string; + cst_type: CstType; + definition_formal: string; +} + +/** + * Represents data, used in renaming {@link IConstituenta}. + */ +export const schemaCstSubstitutions = z.object({ + substitutions: z.array(schemaCstSubstitute).min(1, { message: errorMsg.emptySubstitutions }) +}); + +/** + * Represents data, used in merging multiple {@link IConstituenta}. + */ +export type ICstSubstitutionsDTO = z.infer; diff --git a/rsconcept/frontend/src/features/rsform/backend/useCheckConstituenta.tsx b/rsconcept/frontend/src/features/rsform/backend/useCheckConstituenta.tsx index 5ed414b6..8b24266e 100644 --- a/rsconcept/frontend/src/features/rsform/backend/useCheckConstituenta.tsx +++ b/rsconcept/frontend/src/features/rsform/backend/useCheckConstituenta.tsx @@ -1,6 +1,7 @@ import { useMutation } from '@tanstack/react-query'; -import { ICheckConstituentaDTO, rsformsApi } from './api'; +import { rsformsApi } from './api'; +import { ICheckConstituentaDTO } from './types'; export const useCheckConstituenta = () => { const mutation = useMutation({ diff --git a/rsconcept/frontend/src/features/rsform/backend/useCstCreate.tsx b/rsconcept/frontend/src/features/rsform/backend/useCstCreate.tsx index 30f935b5..cf43623a 100644 --- a/rsconcept/frontend/src/features/rsform/backend/useCstCreate.tsx +++ b/rsconcept/frontend/src/features/rsform/backend/useCstCreate.tsx @@ -1,9 +1,10 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; +import { KEYS } from '@/backend/configuration'; import { useUpdateTimestamp } from '@/features/library'; -import { ossApi } from '@/features/oss/backend/api'; -import { ICstCreateDTO, rsformsApi } from './api'; +import { rsformsApi } from './api'; +import { ICstCreateDTO } from './types'; export const useCstCreate = () => { const client = useQueryClient(); @@ -16,7 +17,7 @@ export const useCstCreate = () => { updateTimestamp(data.schema.id); return Promise.allSettled([ - client.invalidateQueries({ queryKey: [ossApi.baseKey] }), + client.invalidateQueries({ queryKey: [KEYS.oss] }), client.invalidateQueries({ queryKey: [rsformsApi.baseKey], predicate: query => query.queryKey.length > 2 && query.queryKey[2] !== data.schema.id diff --git a/rsconcept/frontend/src/features/rsform/backend/useCstDelete.tsx b/rsconcept/frontend/src/features/rsform/backend/useCstDelete.tsx index b436f591..04e99594 100644 --- a/rsconcept/frontend/src/features/rsform/backend/useCstDelete.tsx +++ b/rsconcept/frontend/src/features/rsform/backend/useCstDelete.tsx @@ -1,7 +1,7 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; +import { KEYS } from '@/backend/configuration'; import { useUpdateTimestamp } from '@/features/library'; -import { ossApi } from '@/features/oss/backend/api'; import { IConstituentaList } from '../models/rsform'; import { rsformsApi } from './api'; @@ -17,7 +17,7 @@ export const useCstDelete = () => { updateTimestamp(data.id); return Promise.allSettled([ - client.invalidateQueries({ queryKey: [ossApi.baseKey] }), + client.invalidateQueries({ queryKey: [KEYS.oss] }), client.invalidateQueries({ queryKey: [rsformsApi.baseKey], predicate: query => query.queryKey.length > 2 && query.queryKey[2] !== data.id diff --git a/rsconcept/frontend/src/features/rsform/backend/useCstMove.tsx b/rsconcept/frontend/src/features/rsform/backend/useCstMove.tsx index 35450d8d..f2bc4aff 100644 --- a/rsconcept/frontend/src/features/rsform/backend/useCstMove.tsx +++ b/rsconcept/frontend/src/features/rsform/backend/useCstMove.tsx @@ -2,7 +2,8 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useUpdateTimestamp } from '@/features/library'; -import { ICstMoveDTO, rsformsApi } from './api'; +import { rsformsApi } from './api'; +import { ICstMoveDTO } from './types'; export const useCstMove = () => { const client = useQueryClient(); diff --git a/rsconcept/frontend/src/features/rsform/backend/useCstRename.tsx b/rsconcept/frontend/src/features/rsform/backend/useCstRename.tsx index 1d2f3503..6193efa1 100644 --- a/rsconcept/frontend/src/features/rsform/backend/useCstRename.tsx +++ b/rsconcept/frontend/src/features/rsform/backend/useCstRename.tsx @@ -1,9 +1,10 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; +import { KEYS } from '@/backend/configuration'; import { useUpdateTimestamp } from '@/features/library'; -import { ossApi } from '@/features/oss/backend/api'; -import { ICstRenameDTO, rsformsApi } from './api'; +import { rsformsApi } from './api'; +import { ICstRenameDTO } from './types'; export const useCstRename = () => { const client = useQueryClient(); @@ -16,7 +17,7 @@ export const useCstRename = () => { updateTimestamp(data.schema.id); return Promise.allSettled([ - client.invalidateQueries({ queryKey: [ossApi.baseKey] }), + client.invalidateQueries({ queryKey: [KEYS.oss] }), client.invalidateQueries({ queryKey: [rsformsApi.baseKey], predicate: query => query.queryKey.length > 2 && query.queryKey[2] !== data.schema.id diff --git a/rsconcept/frontend/src/features/rsform/backend/useCstSubstitute.tsx b/rsconcept/frontend/src/features/rsform/backend/useCstSubstitute.tsx index a9f37b93..a55af2a9 100644 --- a/rsconcept/frontend/src/features/rsform/backend/useCstSubstitute.tsx +++ b/rsconcept/frontend/src/features/rsform/backend/useCstSubstitute.tsx @@ -1,9 +1,10 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; +import { KEYS } from '@/backend/configuration'; import { useUpdateTimestamp } from '@/features/library'; -import { ossApi } from '@/features/oss/backend/api'; -import { ICstSubstitutionsDTO, rsformsApi } from './api'; +import { rsformsApi } from './api'; +import { ICstSubstitutionsDTO } from './types'; export const useCstSubstitute = () => { const client = useQueryClient(); @@ -16,7 +17,7 @@ export const useCstSubstitute = () => { updateTimestamp(data.id); return Promise.allSettled([ - client.invalidateQueries({ queryKey: [ossApi.baseKey] }), + client.invalidateQueries({ queryKey: [KEYS.oss] }), client.invalidateQueries({ queryKey: [rsformsApi.baseKey], predicate: query => query.queryKey.length > 2 && query.queryKey[2] !== data.id diff --git a/rsconcept/frontend/src/features/rsform/backend/useCstUpdate.tsx b/rsconcept/frontend/src/features/rsform/backend/useCstUpdate.tsx index ab0ffd6a..31dc7bb0 100644 --- a/rsconcept/frontend/src/features/rsform/backend/useCstUpdate.tsx +++ b/rsconcept/frontend/src/features/rsform/backend/useCstUpdate.tsx @@ -1,9 +1,10 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; +import { KEYS } from '@/backend/configuration'; import { useUpdateTimestamp } from '@/features/library'; -import { ossApi } from '@/features/oss/backend/api'; -import { ICstUpdateDTO, rsformsApi } from './api'; +import { rsformsApi } from './api'; +import { ICstUpdateDTO } from './types'; export const useCstUpdate = () => { const client = useQueryClient(); @@ -15,7 +16,7 @@ export const useCstUpdate = () => { updateTimestamp(variables.itemID); return Promise.allSettled([ - client.invalidateQueries({ queryKey: [ossApi.baseKey] }), + client.invalidateQueries({ queryKey: [KEYS.oss] }), client.invalidateQueries({ queryKey: [rsformsApi.baseKey] }) ]); } diff --git a/rsconcept/frontend/src/features/rsform/backend/useInlineSynthesis.tsx b/rsconcept/frontend/src/features/rsform/backend/useInlineSynthesis.tsx index 7d7a1ad4..3befa891 100644 --- a/rsconcept/frontend/src/features/rsform/backend/useInlineSynthesis.tsx +++ b/rsconcept/frontend/src/features/rsform/backend/useInlineSynthesis.tsx @@ -1,9 +1,10 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; +import { KEYS } from '@/backend/configuration'; import { useUpdateTimestamp } from '@/features/library'; -import { ossApi } from '@/features/oss/backend/api'; -import { IInlineSynthesisDTO, rsformsApi } from './api'; +import { rsformsApi } from './api'; +import { IInlineSynthesisDTO } from './types'; export const useInlineSynthesis = () => { const client = useQueryClient(); @@ -16,7 +17,7 @@ export const useInlineSynthesis = () => { updateTimestamp(data.id); return Promise.allSettled([ - client.invalidateQueries({ queryKey: [ossApi.baseKey] }), + client.invalidateQueries({ queryKey: [KEYS.oss] }), client.invalidateQueries({ queryKey: [rsformsApi.baseKey], predicate: query => query.queryKey.length > 2 && query.queryKey[2] !== data.id diff --git a/rsconcept/frontend/src/features/rsform/backend/useMutatingRSForm.tsx b/rsconcept/frontend/src/features/rsform/backend/useMutatingRSForm.tsx index 325fb58f..577e250c 100644 --- a/rsconcept/frontend/src/features/rsform/backend/useMutatingRSForm.tsx +++ b/rsconcept/frontend/src/features/rsform/backend/useMutatingRSForm.tsx @@ -1,11 +1,9 @@ import { useIsMutating } from '@tanstack/react-query'; -import { libraryApi } from '@/features/library'; - -import { rsformsApi } from './api'; +import { KEYS } from '@/backend/configuration'; export const useMutatingRSForm = () => { - const countLibrary = useIsMutating({ mutationKey: [libraryApi.baseKey] }); - const countRsform = useIsMutating({ mutationKey: [rsformsApi.baseKey] }); + const countLibrary = useIsMutating({ mutationKey: [KEYS.library] }); + const countRsform = useIsMutating({ mutationKey: [KEYS.rsform] }); return countLibrary + countRsform !== 0; }; diff --git a/rsconcept/frontend/src/features/rsform/backend/useProduceStructure.tsx b/rsconcept/frontend/src/features/rsform/backend/useProduceStructure.tsx index 07a865d3..05fe8a78 100644 --- a/rsconcept/frontend/src/features/rsform/backend/useProduceStructure.tsx +++ b/rsconcept/frontend/src/features/rsform/backend/useProduceStructure.tsx @@ -1,7 +1,7 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; +import { KEYS } from '@/backend/configuration'; import { useUpdateTimestamp } from '@/features/library'; -import { ossApi } from '@/features/oss/backend/api'; import { ITargetCst } from '../models/rsform'; import { rsformsApi } from './api'; @@ -17,7 +17,7 @@ export const useProduceStructure = () => { updateTimestamp(data.schema.id); return Promise.allSettled([ - client.invalidateQueries({ queryKey: [ossApi.baseKey] }), + client.invalidateQueries({ queryKey: [KEYS.oss] }), client.invalidateQueries({ queryKey: [rsformsApi.baseKey], predicate: query => query.queryKey.length > 2 && query.queryKey[2] !== data.schema.id diff --git a/rsconcept/frontend/src/features/rsform/backend/useRSForm.tsx b/rsconcept/frontend/src/features/rsform/backend/useRSForm.tsx index 023ee667..3174bad3 100644 --- a/rsconcept/frontend/src/features/rsform/backend/useRSForm.tsx +++ b/rsconcept/frontend/src/features/rsform/backend/useRSForm.tsx @@ -1,6 +1,7 @@ import { useQuery, useSuspenseQuery } from '@tanstack/react-query'; -import { queryClient } from '../../../backend/queryClient'; +import { queryClient } from '@/backend/queryClient'; + import { rsformsApi } from './api'; import { RSFormLoader } from './RSFormLoader'; diff --git a/rsconcept/frontend/src/features/rsform/backend/useResetAliases.tsx b/rsconcept/frontend/src/features/rsform/backend/useResetAliases.tsx index 238facdd..bfac8ac0 100644 --- a/rsconcept/frontend/src/features/rsform/backend/useResetAliases.tsx +++ b/rsconcept/frontend/src/features/rsform/backend/useResetAliases.tsx @@ -1,7 +1,7 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; +import { KEYS } from '@/backend/configuration'; import { useUpdateTimestamp } from '@/features/library'; -import { ossApi } from '@/features/oss/backend/api'; import { rsformsApi } from './api'; @@ -16,7 +16,7 @@ export const useResetAliases = () => { updateTimestamp(data.id); return Promise.allSettled([ - client.invalidateQueries({ queryKey: [ossApi.baseKey] }), + client.invalidateQueries({ queryKey: [KEYS.oss] }), client.invalidateQueries({ queryKey: [rsformsApi.baseKey], predicate: query => query.queryKey.length > 2 && query.queryKey[2] !== data.id diff --git a/rsconcept/frontend/src/features/rsform/backend/useUploadTRS.tsx b/rsconcept/frontend/src/features/rsform/backend/useUploadTRS.tsx index 87834b37..49a68a93 100644 --- a/rsconcept/frontend/src/features/rsform/backend/useUploadTRS.tsx +++ b/rsconcept/frontend/src/features/rsform/backend/useUploadTRS.tsx @@ -1,10 +1,10 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { libraryApi } from '@/features/library'; +import { KEYS } from '@/backend/configuration'; import { ILibraryItem } from '@/features/library/models/library'; -import { ossApi } from '@/features/oss/backend/api'; -import { IRSFormUploadDTO, rsformsApi } from './api'; +import { rsformsApi } from './api'; +import { IRSFormUploadDTO } from './types'; export const useUploadTRS = () => { const client = useQueryClient(); @@ -12,13 +12,13 @@ export const useUploadTRS = () => { mutationKey: [rsformsApi.baseKey, 'load-trs'], mutationFn: rsformsApi.upload, onSuccess: data => { - client.setQueryData(rsformsApi.getRSFormQueryOptions({ itemID: data.id }).queryKey, data); - client.setQueryData(libraryApi.libraryListKey, (prev: ILibraryItem[] | undefined) => + client.setQueryData(KEYS.composite.rsItem({ itemID: data.id }), data); + client.setQueryData(KEYS.composite.libraryList, (prev: ILibraryItem[] | undefined) => prev?.map(item => (item.id === data.id ? data : item)) ); return Promise.allSettled([ - client.invalidateQueries({ queryKey: [ossApi.baseKey] }), + client.invalidateQueries({ queryKey: [KEYS.oss] }), client.invalidateQueries({ queryKey: [rsformsApi.baseKey], predicate: query => query.queryKey.length > 2 && query.queryKey[2] !== data.id diff --git a/rsconcept/frontend/src/features/rsform/components/PickConstituenta.tsx b/rsconcept/frontend/src/features/rsform/components/PickConstituenta.tsx index c9ed448d..cae024c8 100644 --- a/rsconcept/frontend/src/features/rsform/components/PickConstituenta.tsx +++ b/rsconcept/frontend/src/features/rsform/components/PickConstituenta.tsx @@ -31,7 +31,7 @@ interface PickConstituentaProps extends CProps.Styling { const columnHelper = createColumnHelper(); -function PickConstituenta({ +export function PickConstituenta({ id, items, value, @@ -102,5 +102,3 @@ function PickConstituenta({ ); } - -export default PickConstituenta; diff --git a/rsconcept/frontend/src/features/rsform/components/PickMultiConstituenta.tsx b/rsconcept/frontend/src/features/rsform/components/PickMultiConstituenta.tsx index 7165ae65..191e5dbc 100644 --- a/rsconcept/frontend/src/features/rsform/components/PickMultiConstituenta.tsx +++ b/rsconcept/frontend/src/features/rsform/components/PickMultiConstituenta.tsx @@ -10,7 +10,7 @@ import { NoData } from '@/components/View'; import { Graph } from '@/models/Graph'; import { describeConstituenta } from '../labels'; -import { ConstituentaID, IConstituenta, IRSForm } from '../models/rsform'; +import { IConstituenta, IRSForm } from '../models/rsform'; import { isBasicConcept, matchConstituenta } from '../models/rsformAPI'; import { CstMatchMode } from '../stores/cstSearch'; import BadgeConstituenta from './BadgeConstituenta'; @@ -18,8 +18,8 @@ import ToolbarGraphSelection from './ToolbarGraphSelection'; interface PickMultiConstituentaProps extends CProps.Styling { id?: string; - value: ConstituentaID[]; - onChange: (newValue: ConstituentaID[]) => void; + value: number[]; + onChange: (newValue: number[]) => void; schema: IRSForm; items: IConstituenta[]; @@ -30,7 +30,7 @@ interface PickMultiConstituentaProps extends CProps.Styling { const columnHelper = createColumnHelper(); -function PickMultiConstituenta({ +export function PickMultiConstituenta({ id, schema, items, @@ -72,7 +72,7 @@ function PickMultiConstituenta({ onChange([]); } else { const newRowSelection = typeof updater === 'function' ? updater(rowSelection) : updater; - const newSelection: ConstituentaID[] = []; + const newSelection: number[] = []; filtered.forEach((cst, index) => { if (newRowSelection[String(index)] === true) { newSelection.push(cst.id); @@ -141,5 +141,3 @@ function PickMultiConstituenta({ ); } - -export default PickMultiConstituenta; diff --git a/rsconcept/frontend/src/features/rsform/components/PickSubstitutions.tsx b/rsconcept/frontend/src/features/rsform/components/PickSubstitutions.tsx index d10c1ac7..9c0e6d7b 100644 --- a/rsconcept/frontend/src/features/rsform/components/PickSubstitutions.tsx +++ b/rsconcept/frontend/src/features/rsform/components/PickSubstitutions.tsx @@ -10,15 +10,22 @@ import { IconAccept, IconPageLeft, IconPageRight, IconRemove, IconReplace } from import { CProps } from '@/components/props'; import { NoData } from '@/components/View'; import { ILibraryItem, SelectLibraryItem } from '@/features/library'; -import { IMultiSubstitution } from '@/features/oss/models/oss'; import { APP_COLORS } from '@/styling/colors'; import { errorMsg } from '@/utils/labels'; -import { ICstSubstitute } from '../backend/api'; -import { ConstituentaID, IConstituenta, IRSForm } from '../models/rsform'; +import { ICstSubstitute } from '../backend/types'; +import { IConstituenta, IRSForm } from '../models/rsform'; import BadgeConstituenta from './BadgeConstituenta'; import SelectConstituenta from './SelectConstituenta'; +interface IMultiSubstitution { + original_source: ILibraryItem; + original: IConstituenta; + substitution: IConstituenta; + substitution_source: ILibraryItem; + is_suggestion: boolean; +} + interface PickSubstitutionsProps extends CProps.Styling { value: ICstSubstitute[]; onChange: (newValue: ICstSubstitute[]) => void; @@ -34,7 +41,7 @@ interface PickSubstitutionsProps extends CProps.Styling { const columnHelper = createColumnHelper(); -function PickSubstitutions({ +export function PickSubstitutions({ value, onChange, suggestions, @@ -81,7 +88,7 @@ function PickSubstitutions({ })) ]; - function getSchemaByCst(id: ConstituentaID): IRSForm | undefined { + function getSchemaByCst(id: number): IRSForm | undefined { for (const schema of schemas) { const cst = schema.cstByID.get(id); if (cst) { @@ -91,7 +98,7 @@ function PickSubstitutions({ return undefined; } - function getConstituenta(id: ConstituentaID): IConstituenta | undefined { + function getConstituenta(id: number): IConstituenta | undefined { for (const schema of schemas) { const cst = schema.cstByID.get(id); if (cst) { @@ -291,5 +298,3 @@ function PickSubstitutions({ ); } - -export default PickSubstitutions; diff --git a/rsconcept/frontend/src/features/rsform/components/RSInput/RSInput.tsx b/rsconcept/frontend/src/features/rsform/components/RSInput/RSInput.tsx index 599684ab..28860716 100644 --- a/rsconcept/frontend/src/features/rsform/components/RSInput/RSInput.tsx +++ b/rsconcept/frontend/src/features/rsform/components/RSInput/RSInput.tsx @@ -12,7 +12,7 @@ import { Label } from '@/components/Input'; import { usePreferencesStore } from '@/stores/preferences'; import { APP_COLORS } from '@/styling/colors'; -import { ConstituentaID, IRSForm } from '../../models/rsform'; +import { IRSForm } from '../../models/rsform'; import { generateAlias, getCstTypePrefix, guessCstType } from '../../models/rsformAPI'; import { extractGlobals } from '../../models/rslangAPI'; import { ccBracketMatching } from './bracketMatching'; @@ -41,7 +41,7 @@ interface RSInputProps onChange?: (newValue: string) => void; onAnalyze?: () => void; schema?: IRSForm; - onOpenEdit?: (cstID: ConstituentaID) => void; + onOpenEdit?: (cstID: number) => void; } const RSInput = forwardRef( diff --git a/rsconcept/frontend/src/features/rsform/components/RSInput/clickNavigation.ts b/rsconcept/frontend/src/features/rsform/components/RSInput/clickNavigation.ts index 3e798266..a9890c04 100644 --- a/rsconcept/frontend/src/features/rsform/components/RSInput/clickNavigation.ts +++ b/rsconcept/frontend/src/features/rsform/components/RSInput/clickNavigation.ts @@ -1,11 +1,10 @@ import { Extension } from '@codemirror/state'; import { EditorView } from '@uiw/react-codemirror'; -import { findAliasAt } from '@/utils/codemirror'; +import { IRSForm } from '../../models/rsform'; +import { findAliasAt } from './utils'; -import { ConstituentaID, IRSForm } from '../../models/rsform'; - -const navigationProducer = (schema: IRSForm, onOpenEdit: (cstID: ConstituentaID) => void) => { +const navigationProducer = (schema: IRSForm, onOpenEdit: (cstID: number) => void) => { return EditorView.domEventHandlers({ click: (event: MouseEvent, view: EditorView) => { if (!event.ctrlKey && !event.metaKey) { @@ -34,6 +33,6 @@ const navigationProducer = (schema: IRSForm, onOpenEdit: (cstID: ConstituentaID) }); }; -export function rsNavigation(schema: IRSForm, onOpenEdit: (cstID: ConstituentaID) => void): Extension { +export function rsNavigation(schema: IRSForm, onOpenEdit: (cstID: number) => void): Extension { return [navigationProducer(schema, onOpenEdit)]; } diff --git a/rsconcept/frontend/src/features/rsform/components/RSInput/tooltip.ts b/rsconcept/frontend/src/features/rsform/components/RSInput/tooltip.ts index ca7b5943..e20fb858 100644 --- a/rsconcept/frontend/src/features/rsform/components/RSInput/tooltip.ts +++ b/rsconcept/frontend/src/features/rsform/components/RSInput/tooltip.ts @@ -2,11 +2,10 @@ import { Extension } from '@codemirror/state'; import { hoverTooltip, TooltipView } from '@codemirror/view'; import clsx from 'clsx'; -import { findAliasAt } from '@/utils/codemirror'; - import { labelCstTypification } from '../../labels'; import { IConstituenta, IRSForm } from '../../models/rsform'; import { isBasicConcept } from '../../models/rsformAPI'; +import { findAliasAt } from './utils'; const tooltipProducer = (schema: IRSForm, canClick?: boolean) => { return hoverTooltip((view, pos) => { diff --git a/rsconcept/frontend/src/features/rsform/components/RSInput/utils.ts b/rsconcept/frontend/src/features/rsform/components/RSInput/utils.ts new file mode 100644 index 00000000..ba41e4a4 --- /dev/null +++ b/rsconcept/frontend/src/features/rsform/components/RSInput/utils.ts @@ -0,0 +1,25 @@ +import { syntaxTree } from '@codemirror/language'; +import { EditorState } from '@uiw/react-codemirror'; + +import { findEnvelopingNodes } from '@/utils/codemirror'; + +import { GlobalTokens } from './rslang'; + +/** + * Retrieves globalID from position in Editor. + */ +export function findAliasAt(pos: number, state: EditorState) { + const { from: lineStart, to: lineEnd, text } = state.doc.lineAt(pos); + const nodes = findEnvelopingNodes(pos, pos, syntaxTree(state), GlobalTokens); + let alias = ''; + let start = 0; + let end = 0; + nodes.forEach(node => { + if (node.to <= lineEnd && node.from >= lineStart) { + alias = text.slice(node.from - lineStart, node.to - lineStart); + start = node.from; + end = node.to; + } + }); + return { alias, start, end }; +} diff --git a/rsconcept/frontend/src/features/rsform/components/RefsInput/RefsInput.tsx b/rsconcept/frontend/src/features/rsform/components/RefsInput/RefsInput.tsx index ebf4fa50..30004d3c 100644 --- a/rsconcept/frontend/src/features/rsform/components/RefsInput/RefsInput.tsx +++ b/rsconcept/frontend/src/features/rsform/components/RefsInput/RefsInput.tsx @@ -15,7 +15,7 @@ import { APP_COLORS } from '@/styling/colors'; import { CodeMirrorWrapper } from '@/utils/codemirror'; import { ReferenceType } from '../../models/language'; -import { ConstituentaID, IRSForm } from '../../models/rsform'; +import { IRSForm } from '../../models/rsform'; import { refsNavigation } from './clickNavigation'; import { NaturalLanguage, ReferenceTokens } from './parse'; import { RefEntity } from './parse/parser.terms'; @@ -67,7 +67,7 @@ interface RefsInputInputProps onChange?: (newValue: string) => void; schema: IRSForm; - onOpenEdit?: (cstID: ConstituentaID) => void; + onOpenEdit?: (cstID: number) => void; label?: string; disabled?: boolean; diff --git a/rsconcept/frontend/src/features/rsform/components/RefsInput/clickNavigation.ts b/rsconcept/frontend/src/features/rsform/components/RefsInput/clickNavigation.ts index c556c6ad..96db452e 100644 --- a/rsconcept/frontend/src/features/rsform/components/RefsInput/clickNavigation.ts +++ b/rsconcept/frontend/src/features/rsform/components/RefsInput/clickNavigation.ts @@ -1,11 +1,10 @@ import { Extension } from '@codemirror/state'; import { EditorView } from '@uiw/react-codemirror'; -import { findReferenceAt } from '@/utils/codemirror'; +import { IRSForm } from '../../models/rsform'; +import { findReferenceAt } from './utils'; -import { ConstituentaID, IRSForm } from '../../models/rsform'; - -const navigationProducer = (schema: IRSForm, onOpenEdit: (cstID: ConstituentaID) => void) => { +const navigationProducer = (schema: IRSForm, onOpenEdit: (cstID: number) => void) => { return EditorView.domEventHandlers({ click: (event: MouseEvent, view: EditorView) => { if (!event.ctrlKey && !event.metaKey) { @@ -34,6 +33,6 @@ const navigationProducer = (schema: IRSForm, onOpenEdit: (cstID: ConstituentaID) }); }; -export function refsNavigation(schema: IRSForm, onOpenEdit: (cstID: ConstituentaID) => void): Extension { +export function refsNavigation(schema: IRSForm, onOpenEdit: (cstID: number) => void): Extension { return [navigationProducer(schema, onOpenEdit)]; } diff --git a/rsconcept/frontend/src/features/rsform/components/RefsInput/tooltip.ts b/rsconcept/frontend/src/features/rsform/components/RefsInput/tooltip.ts index 31df8536..ada46b38 100644 --- a/rsconcept/frontend/src/features/rsform/components/RefsInput/tooltip.ts +++ b/rsconcept/frontend/src/features/rsform/components/RefsInput/tooltip.ts @@ -4,7 +4,7 @@ import { hoverTooltip, TooltipView } from '@codemirror/view'; import clsx from 'clsx'; import { APP_COLORS } from '@/styling/colors'; -import { findContainedNodes, findReferenceAt } from '@/utils/codemirror'; +import { findContainedNodes } from '@/utils/codemirror'; import { colorFgGrammeme } from '../../colors'; import { labelGrammeme } from '../../labels'; @@ -13,6 +13,7 @@ import { IEntityReference, ISyntacticReference } from '../../models/language'; import { parseGrammemes } from '../../models/languageAPI'; import { IConstituenta, IRSForm } from '../../models/rsform'; import { RefEntity } from './parse/parser.terms'; +import { findReferenceAt } from './utils'; export const tooltipProducer = (schema: IRSForm, canClick?: boolean) => { return hoverTooltip((view, pos) => { diff --git a/rsconcept/frontend/src/features/rsform/components/RefsInput/utils.ts b/rsconcept/frontend/src/features/rsform/components/RefsInput/utils.ts new file mode 100644 index 00000000..d2907ff3 --- /dev/null +++ b/rsconcept/frontend/src/features/rsform/components/RefsInput/utils.ts @@ -0,0 +1,26 @@ +import { syntaxTree } from '@codemirror/language'; +import { EditorState } from '@uiw/react-codemirror'; + +import { findEnvelopingNodes } from '@/utils/codemirror'; + +import { parseEntityReference, parseSyntacticReference } from '../../models/languageAPI'; +import { ReferenceTokens } from './parse'; +import { RefEntity } from './parse/parser.terms'; + +/** + * Retrieves reference from position in Editor. + */ +export function findReferenceAt(pos: number, state: EditorState) { + const nodes = findEnvelopingNodes(pos, pos, syntaxTree(state), ReferenceTokens); + if (nodes.length !== 1) { + return undefined; + } + const start = nodes[0].from; + const end = nodes[0].to; + const text = state.doc.sliceString(start, end); + if (nodes[0].type.id === RefEntity) { + return { ref: parseEntityReference(text), start, end }; + } else { + return { ref: parseSyntacticReference(text), start, end }; + } +} diff --git a/rsconcept/frontend/src/features/rsform/components/SelectConstituenta.tsx b/rsconcept/frontend/src/features/rsform/components/SelectConstituenta.tsx index 53d27c0d..f5ecd521 100644 --- a/rsconcept/frontend/src/features/rsform/components/SelectConstituenta.tsx +++ b/rsconcept/frontend/src/features/rsform/components/SelectConstituenta.tsx @@ -7,7 +7,7 @@ import { CProps } from '@/components/props'; import { describeConstituentaTerm } from '../labels'; import { describeConstituenta } from '../labels'; -import { ConstituentaID, IConstituenta } from '../models/rsform'; +import { IConstituenta } from '../models/rsform'; import { matchConstituenta } from '../models/rsformAPI'; import { CstMatchMode } from '../stores/cstSearch'; @@ -34,7 +34,7 @@ function SelectConstituenta({ label: `${cst.alias}${cst.is_inherited ? '*' : ''}: ${describeConstituenta(cst)}` })) ?? []; - function filter(option: { value: ConstituentaID | undefined; label: string }, inputValue: string) { + function filter(option: { value: number | undefined; label: string }, inputValue: string) { const cst = items?.find(item => item.id === option.value); return !cst ? false : matchConstituenta(cst, inputValue, CstMatchMode.ALL); } diff --git a/rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorRSFormCard/ToolbarRSFormCard.tsx b/rsconcept/frontend/src/features/rsform/components/ToolbarRSFormCard.tsx similarity index 86% rename from rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorRSFormCard/ToolbarRSFormCard.tsx rename to rsconcept/frontend/src/features/rsform/components/ToolbarRSFormCard.tsx index b75034e1..b2f0b933 100644 --- a/rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorRSFormCard/ToolbarRSFormCard.tsx +++ b/rsconcept/frontend/src/features/rsform/components/ToolbarRSFormCard.tsx @@ -4,23 +4,28 @@ import { Overlay } from '@/components/Container'; import { MiniButton } from '@/components/Control'; import { IconDestroy, IconSave, IconShare } from '@/components/Icons'; import { BadgeHelp, HelpTopic } from '@/features/help'; -import { ILibraryItemEditor, MiniSelectorOSS, useMutatingLibrary } from '@/features/library'; -import { AccessPolicy, LibraryItemType } from '@/features/library'; +import { + AccessPolicy, + ILibraryItemEditor, + LibraryItemType, + MiniSelectorOSS, + useMutatingLibrary +} from '@/features/library'; import { useRoleStore, UserRole } from '@/features/users'; import { useModificationStore } from '@/stores/modification'; import { PARAMETER } from '@/utils/constants'; import { tooltipText } from '@/utils/labels'; import { prepareTooltip, sharePage } from '@/utils/utils'; -import { IRSForm } from '../../../models/rsform'; -import { IRSEditContext } from '../RSEditContext'; +import { IRSForm } from '../models/rsform'; +import { IRSEditContext } from '../pages/RSFormPage/RSEditContext'; interface ToolbarRSFormCardProps { onSubmit: () => void; controller: ILibraryItemEditor; } -function ToolbarRSFormCard({ controller, onSubmit }: ToolbarRSFormCardProps) { +export function ToolbarRSFormCard({ controller, onSubmit }: ToolbarRSFormCardProps) { const role = useRoleStore(state => state.role); const { isModified } = useModificationStore(); const isProcessing = useMutatingLibrary(); @@ -73,5 +78,3 @@ function ToolbarRSFormCard({ controller, onSubmit }: ToolbarRSFormCardProps) { ); } - -export default ToolbarRSFormCard; diff --git a/rsconcept/frontend/src/features/rsform/dialogs/DlgCreateCst/DlgCreateCst.tsx b/rsconcept/frontend/src/features/rsform/dialogs/DlgCreateCst/DlgCreateCst.tsx index 9c766c30..3e6fc6ee 100644 --- a/rsconcept/frontend/src/features/rsform/dialogs/DlgCreateCst/DlgCreateCst.tsx +++ b/rsconcept/frontend/src/features/rsform/dialogs/DlgCreateCst/DlgCreateCst.tsx @@ -6,7 +6,7 @@ import { ModalForm } from '@/components/Modal'; import usePartialUpdate from '@/hooks/usePartialUpdate'; import { useDialogsStore } from '@/stores/dialogs'; -import { ICstCreateDTO } from '../../backend/api'; +import { ICstCreateDTO } from '../../backend/types'; import { CstType, IRSForm } from '../../models/rsform'; import { generateAlias } from '../../models/rsformAPI'; import FormCreateCst from './FormCreateCst'; diff --git a/rsconcept/frontend/src/features/rsform/dialogs/DlgCreateCst/FormCreateCst.tsx b/rsconcept/frontend/src/features/rsform/dialogs/DlgCreateCst/FormCreateCst.tsx index 9dcc70c9..1a8a13b3 100644 --- a/rsconcept/frontend/src/features/rsform/dialogs/DlgCreateCst/FormCreateCst.tsx +++ b/rsconcept/frontend/src/features/rsform/dialogs/DlgCreateCst/FormCreateCst.tsx @@ -7,7 +7,7 @@ import { TextArea, TextInput } from '@/components/Input'; import { BadgeHelp, HelpTopic } from '@/features/help'; import { PARAMETER } from '@/utils/constants'; -import { ICstCreateDTO } from '../../backend/api'; +import { ICstCreateDTO } from '../../backend/types'; import RSInput from '../../components/RSInput'; import { SelectCstType } from '../../components/SelectCstType'; import { CstType, IRSForm } from '../../models/rsform'; diff --git a/rsconcept/frontend/src/features/rsform/dialogs/DlgCstTemplate/DlgCstTemplate.tsx b/rsconcept/frontend/src/features/rsform/dialogs/DlgCstTemplate/DlgCstTemplate.tsx index 42b027ed..170b18b9 100644 --- a/rsconcept/frontend/src/features/rsform/dialogs/DlgCstTemplate/DlgCstTemplate.tsx +++ b/rsconcept/frontend/src/features/rsform/dialogs/DlgCstTemplate/DlgCstTemplate.tsx @@ -11,7 +11,7 @@ import usePartialUpdate from '@/hooks/usePartialUpdate'; import { useDialogsStore } from '@/stores/dialogs'; import { promptText } from '@/utils/labels'; -import { ICstCreateDTO } from '../../backend/api'; +import { ICstCreateDTO } from '../../backend/types'; import { useRSForm } from '../../backend/useRSForm'; import { CstType, IRSForm } from '../../models/rsform'; import { generateAlias, validateNewAlias } from '../../models/rsformAPI'; diff --git a/rsconcept/frontend/src/features/rsform/dialogs/DlgCstTemplate/TabArguments.tsx b/rsconcept/frontend/src/features/rsform/dialogs/DlgCstTemplate/TabArguments.tsx index 00d4a613..022ebd31 100644 --- a/rsconcept/frontend/src/features/rsform/dialogs/DlgCstTemplate/TabArguments.tsx +++ b/rsconcept/frontend/src/features/rsform/dialogs/DlgCstTemplate/TabArguments.tsx @@ -10,7 +10,7 @@ import { IconAccept, IconRemove, IconReset } from '@/components/Icons'; import { NoData } from '@/components/View'; import { APP_COLORS } from '@/styling/colors'; -import PickConstituenta from '../../components/PickConstituenta'; +import { PickConstituenta } from '../../components/PickConstituenta'; import RSInput from '../../components/RSInput'; import { IConstituenta, IRSForm } from '../../models/rsform'; import { IArgumentValue } from '../../models/rslang'; diff --git a/rsconcept/frontend/src/features/rsform/dialogs/DlgCstTemplate/TabTemplate.tsx b/rsconcept/frontend/src/features/rsform/dialogs/DlgCstTemplate/TabTemplate.tsx index c8231e24..6954e064 100644 --- a/rsconcept/frontend/src/features/rsform/dialogs/DlgCstTemplate/TabTemplate.tsx +++ b/rsconcept/frontend/src/features/rsform/dialogs/DlgCstTemplate/TabTemplate.tsx @@ -4,8 +4,8 @@ import { Dispatch, useEffect, useState } from 'react'; import { SelectSingle, TextArea } from '@/components/Input'; import { useTemplatesSuspense } from '@/features/library'; -import PickConstituenta from '@/features/rsform/components/PickConstituenta'; +import { PickConstituenta } from '../../components/PickConstituenta'; import RSInput from '../../components/RSInput'; import { CATEGORY_CST_TYPE, IConstituenta, IRSForm } from '../../models/rsform'; import { applyFilterCategory } from '../../models/rsformAPI'; diff --git a/rsconcept/frontend/src/features/rsform/dialogs/DlgDeleteCst/DlgDeleteCst.tsx b/rsconcept/frontend/src/features/rsform/dialogs/DlgDeleteCst/DlgDeleteCst.tsx index a58c072f..f6ac484f 100644 --- a/rsconcept/frontend/src/features/rsform/dialogs/DlgDeleteCst/DlgDeleteCst.tsx +++ b/rsconcept/frontend/src/features/rsform/dialogs/DlgDeleteCst/DlgDeleteCst.tsx @@ -9,13 +9,13 @@ import { useDialogsStore } from '@/stores/dialogs'; import { prefixes } from '@/utils/constants'; import { useCstDelete } from '../../backend/useCstDelete'; -import { ConstituentaID, IRSForm } from '../../models/rsform'; +import { IRSForm } from '../../models/rsform'; import ListConstituents from './ListConstituents'; export interface DlgDeleteCstProps { schema: IRSForm; - selected: ConstituentaID[]; - afterDelete: (initialSchema: IRSForm, deleted: ConstituentaID[]) => void; + selected: number[]; + afterDelete: (initialSchema: IRSForm, deleted: number[]) => void; } function DlgDeleteCst() { @@ -23,7 +23,7 @@ function DlgDeleteCst() { const { cstDelete } = useCstDelete(); const [expandOut, setExpandOut] = useState(false); - const expansion: ConstituentaID[] = schema.graph.expandAllOutputs(selected); + const expansion: number[] = schema.graph.expandAllOutputs(selected); const hasInherited = selected.some( id => schema.inheritance.find(item => item.parent === id), [selected, schema.inheritance] diff --git a/rsconcept/frontend/src/features/rsform/dialogs/DlgDeleteCst/ListConstituents.tsx b/rsconcept/frontend/src/features/rsform/dialogs/DlgDeleteCst/ListConstituents.tsx index 7bbccd29..dc7e494f 100644 --- a/rsconcept/frontend/src/features/rsform/dialogs/DlgDeleteCst/ListConstituents.tsx +++ b/rsconcept/frontend/src/features/rsform/dialogs/DlgDeleteCst/ListConstituents.tsx @@ -1,10 +1,10 @@ import clsx from 'clsx'; import { labelConstituenta } from '../../labels'; -import { ConstituentaID, IRSForm } from '../../models/rsform'; +import { IRSForm } from '../../models/rsform'; interface ListConstituentsProps { - list: ConstituentaID[]; + list: number[]; schema: IRSForm; prefix: string; title?: string; diff --git a/rsconcept/frontend/src/features/rsform/dialogs/DlgEditReference/TabEntityReference.tsx b/rsconcept/frontend/src/features/rsform/dialogs/DlgEditReference/TabEntityReference.tsx index 03b33401..ab8ed3ce 100644 --- a/rsconcept/frontend/src/features/rsform/dialogs/DlgEditReference/TabEntityReference.tsx +++ b/rsconcept/frontend/src/features/rsform/dialogs/DlgEditReference/TabEntityReference.tsx @@ -4,7 +4,7 @@ import { useEffect, useState } from 'react'; import { Label, TextInput } from '@/components/Input'; -import PickConstituenta from '../../components/PickConstituenta'; +import { PickConstituenta } from '../../components/PickConstituenta'; import SelectMultiGrammeme from '../../components/SelectMultiGrammeme'; import SelectWordForm from '../../components/SelectWordForm'; import { IGrammemeOption, ReferenceType } from '../../models/language'; diff --git a/rsconcept/frontend/src/features/rsform/dialogs/DlgInlineSynthesis/DlgInlineSynthesis.tsx b/rsconcept/frontend/src/features/rsform/dialogs/DlgInlineSynthesis/DlgInlineSynthesis.tsx index 314d0026..b0b5fb8c 100644 --- a/rsconcept/frontend/src/features/rsform/dialogs/DlgInlineSynthesis/DlgInlineSynthesis.tsx +++ b/rsconcept/frontend/src/features/rsform/dialogs/DlgInlineSynthesis/DlgInlineSynthesis.tsx @@ -10,7 +10,7 @@ import { ModalForm } from '@/components/Modal'; import { TabLabel, TabList, TabPanel, Tabs } from '@/components/Tabs'; import { useDialogsStore } from '@/stores/dialogs'; -import { IInlineSynthesisDTO, schemaInlineSynthesis } from '../../backend/api'; +import { IInlineSynthesisDTO, schemaInlineSynthesis } from '../../backend/types'; import { useInlineSynthesis } from '../../backend/useInlineSynthesis'; import { IRSForm } from '../../models/rsform'; import TabConstituents from './TabConstituents'; diff --git a/rsconcept/frontend/src/features/rsform/dialogs/DlgInlineSynthesis/TabConstituents.tsx b/rsconcept/frontend/src/features/rsform/dialogs/DlgInlineSynthesis/TabConstituents.tsx index 66f98b48..37d05043 100644 --- a/rsconcept/frontend/src/features/rsform/dialogs/DlgInlineSynthesis/TabConstituents.tsx +++ b/rsconcept/frontend/src/features/rsform/dialogs/DlgInlineSynthesis/TabConstituents.tsx @@ -2,10 +2,9 @@ import { Controller, useFormContext, useWatch } from 'react-hook-form'; -import { IInlineSynthesisDTO } from '../../backend/api'; +import { IInlineSynthesisDTO } from '../../backend/types'; import { useRSFormSuspense } from '../../backend/useRSForm'; -import PickMultiConstituenta from '../../components/PickMultiConstituenta'; -import { ConstituentaID } from '../../models/rsform'; +import { PickMultiConstituenta } from '../../components/PickMultiConstituenta'; function TabConstituents() { const { setValue, control } = useFormContext(); @@ -14,7 +13,7 @@ function TabConstituents() { const { schema } = useRSFormSuspense({ itemID: sourceID! }); - function handleSelectItems(newValue: ConstituentaID[]) { + function handleSelectItems(newValue: number[]) { setValue('items', newValue); const newSubstitutions = substitutions.filter( sub => newValue.includes(sub.original) || newValue.includes(sub.substitution) diff --git a/rsconcept/frontend/src/features/rsform/dialogs/DlgInlineSynthesis/TabSource.tsx b/rsconcept/frontend/src/features/rsform/dialogs/DlgInlineSynthesis/TabSource.tsx index 38822d0a..a0af6a25 100644 --- a/rsconcept/frontend/src/features/rsform/dialogs/DlgInlineSynthesis/TabSource.tsx +++ b/rsconcept/frontend/src/features/rsform/dialogs/DlgInlineSynthesis/TabSource.tsx @@ -6,7 +6,7 @@ import { TextInput } from '@/components/Input'; import { LibraryItemType, PickSchema, useLibrary } from '@/features/library'; import { useDialogsStore } from '@/stores/dialogs'; -import { IInlineSynthesisDTO } from '../../backend/api'; +import { IInlineSynthesisDTO } from '../../backend/types'; import { sortItemsForInlineSynthesis } from '../../models/rsformAPI'; import { DlgInlineSynthesisProps } from './DlgInlineSynthesis'; diff --git a/rsconcept/frontend/src/features/rsform/dialogs/DlgInlineSynthesis/TabSubstitutions.tsx b/rsconcept/frontend/src/features/rsform/dialogs/DlgInlineSynthesis/TabSubstitutions.tsx index 74484237..1dda0b53 100644 --- a/rsconcept/frontend/src/features/rsform/dialogs/DlgInlineSynthesis/TabSubstitutions.tsx +++ b/rsconcept/frontend/src/features/rsform/dialogs/DlgInlineSynthesis/TabSubstitutions.tsx @@ -4,9 +4,9 @@ import { Controller, useFormContext, useWatch } from 'react-hook-form'; import { useDialogsStore } from '@/stores/dialogs'; -import { IInlineSynthesisDTO } from '../../backend/api'; +import { IInlineSynthesisDTO } from '../../backend/types'; import { useRSFormSuspense } from '../../backend/useRSForm'; -import PickSubstitutions from '../../components/PickSubstitutions'; +import { PickSubstitutions } from '../../components/PickSubstitutions'; import { DlgInlineSynthesisProps } from './DlgInlineSynthesis'; function TabSubstitutions() { diff --git a/rsconcept/frontend/src/features/rsform/dialogs/DlgRenameCst.tsx b/rsconcept/frontend/src/features/rsform/dialogs/DlgRenameCst.tsx index 66f0322b..4fabec1a 100644 --- a/rsconcept/frontend/src/features/rsform/dialogs/DlgRenameCst.tsx +++ b/rsconcept/frontend/src/features/rsform/dialogs/DlgRenameCst.tsx @@ -9,7 +9,7 @@ import { ModalForm } from '@/components/Modal'; import { HelpTopic } from '@/features/help'; import { useDialogsStore } from '@/stores/dialogs'; -import { ICstRenameDTO, schemaCstRename } from '../backend/api'; +import { ICstRenameDTO, schemaCstRename } from '../backend/types'; import { useCstRename } from '../backend/useCstRename'; import { SelectCstType } from '../components/SelectCstType'; import { CstType, IConstituenta, IRSForm } from '../models/rsform'; diff --git a/rsconcept/frontend/src/features/rsform/dialogs/DlgShowTypeGraph/graph/MGraphLayout.ts b/rsconcept/frontend/src/features/rsform/dialogs/DlgShowTypeGraph/graph/MGraphLayout.ts index 038de3d9..636d1ab0 100644 --- a/rsconcept/frontend/src/features/rsform/dialogs/DlgShowTypeGraph/graph/MGraphLayout.ts +++ b/rsconcept/frontend/src/features/rsform/dialogs/DlgShowTypeGraph/graph/MGraphLayout.ts @@ -1,7 +1,7 @@ import dagre from '@dagrejs/dagre'; import { Edge, Node } from 'reactflow'; -import { TMGraphNode } from '@/features/rsform/models/TMGraph'; +import { TMGraphNode } from '../../../models/TMGraph'; const NODE_WIDTH = 44; const NODE_HEIGHT = 44; diff --git a/rsconcept/frontend/src/features/rsform/dialogs/DlgSubstituteCst.tsx b/rsconcept/frontend/src/features/rsform/dialogs/DlgSubstituteCst.tsx index a9186c97..7f9f5936 100644 --- a/rsconcept/frontend/src/features/rsform/dialogs/DlgSubstituteCst.tsx +++ b/rsconcept/frontend/src/features/rsform/dialogs/DlgSubstituteCst.tsx @@ -9,9 +9,9 @@ import { ModalForm } from '@/components/Modal'; import { HelpTopic } from '@/features/help'; import { useDialogsStore } from '@/stores/dialogs'; -import { ICstSubstitutionsDTO, schemaCstSubstitutions } from '../backend/api'; +import { ICstSubstitutionsDTO, schemaCstSubstitutions } from '../backend/types'; import { useCstSubstitute } from '../backend/useCstSubstitute'; -import PickSubstitutions from '../components/PickSubstitutions'; +import { PickSubstitutions } from '../components/PickSubstitutions'; import { IRSForm } from '../models/rsform'; export interface DlgSubstituteCstProps { diff --git a/rsconcept/frontend/src/features/rsform/dialogs/DlgUploadRSForm.tsx b/rsconcept/frontend/src/features/rsform/dialogs/DlgUploadRSForm.tsx index afde84fd..8d8a6ff7 100644 --- a/rsconcept/frontend/src/features/rsform/dialogs/DlgUploadRSForm.tsx +++ b/rsconcept/frontend/src/features/rsform/dialogs/DlgUploadRSForm.tsx @@ -4,10 +4,11 @@ import { useState } from 'react'; import { Checkbox, FileInput } from '@/components/Input'; import { ModalForm } from '@/components/Modal'; -import { useUploadTRS } from '@/features/rsform/backend/useUploadTRS'; import { useDialogsStore } from '@/stores/dialogs'; import { EXTEOR_TRS_FILE } from '@/utils/constants'; +import { useUploadTRS } from '../backend/useUploadTRS'; + export interface DlgUploadRSFormProps { itemID: number; } diff --git a/rsconcept/frontend/src/features/rsform/index.ts b/rsconcept/frontend/src/features/rsform/index.ts new file mode 100644 index 00000000..e0770ac0 --- /dev/null +++ b/rsconcept/frontend/src/features/rsform/index.ts @@ -0,0 +1,7 @@ +export { type ICstSubstitute } from './backend/types'; +export { useRSForm, useRSFormSuspense } from './backend/useRSForm'; +export { useRSForms } from './backend/useRSForms'; +export { PickMultiConstituenta } from './components/PickMultiConstituenta'; +export { PickSubstitutions } from './components/PickSubstitutions'; +export { ToolbarRSFormCard } from './components/ToolbarRSFormCard'; +export { CstClass, CstType, type IConstituenta, type IRSForm } from './models/rsform'; diff --git a/rsconcept/frontend/src/features/rsform/models/rsform.ts b/rsconcept/frontend/src/features/rsform/models/rsform.ts index ca94c58c..e50ba10b 100644 --- a/rsconcept/frontend/src/features/rsform/models/rsform.ts +++ b/rsconcept/frontend/src/features/rsform/models/rsform.ts @@ -24,11 +24,6 @@ export enum CstType { // CstType constant for category dividers in TemplateSchemas export const CATEGORY_CST_TYPE = CstType.THEOREM; -/** - * Represents {@link IConstituenta} identifier type. - */ -export type ConstituentaID = number; - /** * Represents Constituenta classification in terms of system of concepts. */ @@ -63,7 +58,7 @@ export interface TermForm { * Represents Constituenta basic persistent data. */ export interface IConstituentaMeta { - id: ConstituentaID; + id: number; alias: string; convention: string; cst_type: CstType; @@ -79,7 +74,7 @@ export interface IConstituentaMeta { * Represents target {@link IConstituenta}. */ export interface ITargetCst { - target: ConstituentaID; + target: number; } /** @@ -107,7 +102,7 @@ export interface IConstituenta extends IConstituentaMeta { /** Indicates if this {@link IConstituenta} has a simple expression. */ is_simple_expression: boolean; - /** Index of {@link LibraryItemID} that contains this cst (or inheritance parent). + /** Index of {@link LibraryItem} that contains this cst (or inheritance parent). * 0 - not inherited, 1 - inherited by 1st schema, 2 - inherited by 2nd schema, etc. */ parent_schema_index: number; @@ -119,7 +114,7 @@ export interface IConstituenta extends IConstituentaMeta { has_inherited_children: boolean; /** {@link IConstituenta} that spawned this one. */ - spawner?: ConstituentaID; + spawner?: number; /** Alias of {@link IConstituenta} that spawned this one. */ spawner_alias?: string; /** List of {@link IConstituenta} that are spawned by this one. */ @@ -137,7 +132,7 @@ export interface IConstituentaReference extends Pick; - cstByID: Map; + cstByID: Map; } /** diff --git a/rsconcept/frontend/src/features/rsform/models/rslangAPI.ts b/rsconcept/frontend/src/features/rsform/models/rslangAPI.ts index a046b216..c9bf944f 100644 --- a/rsconcept/frontend/src/features/rsform/models/rslangAPI.ts +++ b/rsconcept/frontend/src/features/rsform/models/rslangAPI.ts @@ -2,8 +2,13 @@ * Module: API for RSLanguage. */ +import { Tree } from '@lezer/common'; + +import { cursorNode } from '@/utils/codemirror'; +import { PARAMETER } from '@/utils/constants'; + import { CstType } from './rsform'; -import { AliasMapping, IArgumentValue, IRSErrorDescription, RSErrorClass, RSErrorType } from './rslang'; +import { AliasMapping, IArgumentValue, IRSErrorDescription, RSErrorClass, RSErrorType, SyntaxTree } from './rslang'; // cspell:disable const LOCALS_REGEXP = /[_a-zα-ω][a-zα-ω]*\d*/g; @@ -237,3 +242,53 @@ export function applyTypificationMapping(target: string, mapping: AliasMapping): return result; } + +/** + * Transform Tree to {@link SyntaxTree}. + */ +export function transformAST(tree: Tree): SyntaxTree { + const result: SyntaxTree = []; + const parents: number[] = []; + const cursor = tree.cursor(); + let finished = false; + let leave = true; + while (!finished) { + let node = cursorNode(cursor); + node.isLeaf = !cursor.firstChild(); + + leave = true; + result.push({ + uid: result.length, + parent: parents.length > 0 ? parents[parents.length - 1] : result.length, + typeID: node.type.id, + start: node.from, + finish: node.to, + data: { + dataType: 'string', + value: node.type.name == '⚠' ? PARAMETER.errorNodeLabel : node.type.name + } + }); + parents.push(result.length - 1); + + if (!node.isLeaf) continue; + + for (;;) { + node = cursorNode(cursor, node.isLeaf); + if (leave) { + parents.pop(); + } + + leave = cursor.type.isAnonymous; + node.isLeaf = false; + if (cursor.nextSibling()) { + break; + } + if (!cursor.parent()) { + finished = true; + break; + } + leave = true; + } + } + return result; +} diff --git a/rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorConstituenta/FormConstituenta.tsx b/rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorConstituenta/FormConstituenta.tsx index abacd98b..056c2528 100644 --- a/rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorConstituenta/FormConstituenta.tsx +++ b/rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorConstituenta/FormConstituenta.tsx @@ -16,12 +16,12 @@ import { useDialogsStore } from '@/stores/dialogs'; import { useModificationStore } from '@/stores/modification'; import { errorMsg } from '@/utils/labels'; -import { ICstUpdateDTO, schemaCstUpdate } from '../../../backend/api'; +import { ICstUpdateDTO, schemaCstUpdate } from '../../../backend/types'; import { useCstUpdate } from '../../../backend/useCstUpdate'; import { useMutatingRSForm } from '../../../backend/useMutatingRSForm'; import RefsInput from '../../../components/RefsInput'; import { labelCstTypification, labelTypification } from '../../../labels'; -import { ConstituentaID, CstType, IConstituenta, IRSForm } from '../../../models/rsform'; +import { CstType, IConstituenta, IRSForm } from '../../../models/rsform'; import { isBaseSet, isBasicConcept, isFunctional } from '../../../models/rsformAPI'; import { IExpressionParse, ParsingStatus } from '../../../models/rslang'; import EditorRSExpression from '../EditorRSExpression'; @@ -33,7 +33,7 @@ interface FormConstituentaProps { activeCst: IConstituenta; schema: IRSForm; - onOpenEdit?: (cstID: ConstituentaID) => void; + onOpenEdit?: (cstID: number) => void; } function FormConstituenta({ disabled, id, toggleReset, schema, activeCst, onOpenEdit }: FormConstituentaProps) { diff --git a/rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorConstituenta/ToolbarConstituenta.tsx b/rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorConstituenta/ToolbarConstituenta.tsx index 343cb0f8..69c62d9b 100644 --- a/rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorConstituenta/ToolbarConstituenta.tsx +++ b/rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorConstituenta/ToolbarConstituenta.tsx @@ -19,7 +19,7 @@ import { } from '@/components/Icons'; import { BadgeHelp, HelpTopic } from '@/features/help'; import { MiniSelectorOSS } from '@/features/library'; -import { useFindPredecessor } from '@/features/oss/backend/useFindPredecessor'; +import { useFindPredecessor } from '@/features/oss'; import { useModificationStore } from '@/stores/modification'; import { usePreferencesStore } from '@/stores/preferences'; import { PARAMETER } from '@/utils/constants'; @@ -27,7 +27,7 @@ import { tooltipText } from '@/utils/labels'; import { prepareTooltip } from '@/utils/utils'; import { useMutatingRSForm } from '../../../backend/useMutatingRSForm'; -import { ConstituentaID, IConstituenta } from '../../../models/rsform'; +import { IConstituenta } from '../../../models/rsform'; import { RSTabID, useRSEdit } from '../RSEditContext'; interface ToolbarConstituentaProps { @@ -54,7 +54,7 @@ function ToolbarConstituenta({ const { isModified } = useModificationStore(); const isProcessing = useMutatingRSForm(); - function viewPredecessor(target: ConstituentaID) { + function viewPredecessor(target: number) { void findPredecessor({ target: target }).then(reference => router.push( urls.schema_props({ diff --git a/rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorRSExpression/EditorRSExpression.tsx b/rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorRSExpression/EditorRSExpression.tsx index b1f94f84..1f574395 100644 --- a/rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorRSExpression/EditorRSExpression.tsx +++ b/rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorRSExpression/EditorRSExpression.tsx @@ -10,18 +10,18 @@ import { CProps } from '@/components/props'; import { BadgeHelp, HelpTopic } from '@/features/help'; import { useDialogsStore } from '@/stores/dialogs'; import { usePreferencesStore } from '@/stores/preferences'; -import { transformAST } from '@/utils/codemirror'; import { errorMsg } from '@/utils/labels'; -import { ICheckConstituentaDTO } from '../../../backend/api'; +import { ICheckConstituentaDTO } from '../../../backend/types'; import { useCheckConstituenta } from '../../../backend/useCheckConstituenta'; import { useMutatingRSForm } from '../../../backend/useMutatingRSForm'; import RSInput from '../../../components/RSInput'; import { parser as rslangParser } from '../../../components/RSInput/rslang/parserAST'; import { RSTextWrapper } from '../../../components/RSInput/textEditing'; -import { ConstituentaID, IConstituenta } from '../../../models/rsform'; +import { IConstituenta } from '../../../models/rsform'; import { getDefinitionPrefix } from '../../../models/rsformAPI'; import { IExpressionParse, IRSErrorDescription, TokenID } from '../../../models/rslang'; +import { transformAST } from '../../../models/rslangAPI'; import { useRSEdit } from '../RSEditContext'; import ParsingResult from './ParsingResult'; import RSEditorControls from './RSEditControls'; @@ -41,7 +41,7 @@ interface EditorRSExpressionProps { toggleReset?: boolean; onChangeLocalParse: (typification: IExpressionParse | undefined) => void; - onOpenEdit?: (cstID: ConstituentaID) => void; + onOpenEdit?: (cstID: number) => void; onShowTypeGraph: (event: CProps.EventMouse) => void; } diff --git a/rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorRSFormCard/EditorRSFormCard.tsx b/rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorRSFormCard/EditorRSFormCard.tsx index b35adc81..223cd6ce 100644 --- a/rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorRSFormCard/EditorRSFormCard.tsx +++ b/rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorRSFormCard/EditorRSFormCard.tsx @@ -7,10 +7,10 @@ import { EditorLibraryItem } from '@/features/library'; import { useModificationStore } from '@/stores/modification'; import { globals } from '@/utils/constants'; +import { ToolbarRSFormCard } from '../../../components/ToolbarRSFormCard'; import { useRSEdit } from '../RSEditContext'; import FormRSForm from './FormRSForm'; import RSFormStats from './RSFormStats'; -import ToolbarRSFormCard from './ToolbarRSFormCard'; function EditorRSFormCard() { const controller = useRSEdit(); diff --git a/rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorRSFormCard/FormRSForm.tsx b/rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorRSFormCard/FormRSForm.tsx index 38928cf5..c8b1cf9b 100644 --- a/rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorRSFormCard/FormRSForm.tsx +++ b/rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorRSFormCard/FormRSForm.tsx @@ -11,7 +11,7 @@ import { SubmitButton } from '@/components/Control'; import { IconSave } from '@/components/Icons'; import { Label, TextArea, TextInput } from '@/components/Input'; import { LibraryItemType, SelectVersion, ToolbarItemAccess, useUpdateItem } from '@/features/library'; -import { IUpdateLibraryItemDTO, schemaUpdateLibraryItem } from '@/features/library/backend/api'; +import { IUpdateLibraryItemDTO, schemaUpdateLibraryItem } from '@/features/library/backend/types'; import { useModificationStore } from '@/stores/modification'; import { globals } from '@/utils/constants'; diff --git a/rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorRSList/EditorRSList.tsx b/rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorRSList/EditorRSList.tsx index 4c1b49ee..b33c9ef8 100644 --- a/rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorRSList/EditorRSList.tsx +++ b/rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorRSList/EditorRSList.tsx @@ -14,7 +14,7 @@ import { infoMsg } from '@/utils/labels'; import { convertToCSV } from '@/utils/utils'; import { useMutatingRSForm } from '../../../backend/useMutatingRSForm'; -import { ConstituentaID, CstType } from '../../../models/rsform'; +import { CstType } from '../../../models/rsform'; import { matchConstituenta } from '../../../models/rsformAPI'; import { CstMatchMode } from '../../../stores/cstSearch'; import { useRSEdit } from '../RSEditContext'; @@ -50,7 +50,7 @@ function EditorRSList() { function handleRowSelection(updater: React.SetStateAction) { const newRowSelection = typeof updater === 'function' ? updater(rowSelection) : updater; - const newSelection: ConstituentaID[] = []; + const newSelection: number[] = []; filtered.forEach((cst, index) => { if (newRowSelection[String(index)] === true) { newSelection.push(cst.id); diff --git a/rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorRSList/TableRSList.tsx b/rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorRSList/TableRSList.tsx index cc88a306..2c3ad888 100644 --- a/rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorRSList/TableRSList.tsx +++ b/rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorRSList/TableRSList.tsx @@ -13,7 +13,7 @@ import { truncateToSymbol } from '@/utils/utils'; import BadgeConstituenta from '../../../components/BadgeConstituenta'; import { labelCstTypification } from '../../../labels'; -import { ConstituentaID, IConstituenta } from '../../../models/rsform'; +import { IConstituenta } from '../../../models/rsform'; interface TableRSListProps { items?: IConstituenta[]; @@ -22,7 +22,7 @@ interface TableRSListProps { selected: RowSelectionState; setSelected: React.Dispatch>; - onEdit: (cstID: ConstituentaID) => void; + onEdit: (cstID: number) => void; onCreateNew: () => void; } diff --git a/rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorTermGraph/TGFlow.tsx b/rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorTermGraph/TGFlow.tsx index 4d15c479..9c7db162 100644 --- a/rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorTermGraph/TGFlow.tsx +++ b/rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorTermGraph/TGFlow.tsx @@ -31,7 +31,7 @@ import { useMutatingRSForm } from '../../../backend/useMutatingRSForm'; import { colorBgGraphNode } from '../../../colors'; import InfoConstituenta from '../../../components/InfoConstituenta'; import ToolbarGraphSelection from '../../../components/ToolbarGraphSelection'; -import { ConstituentaID, CstType, IConstituenta, IRSForm } from '../../../models/rsform'; +import { CstType, IConstituenta, IRSForm } from '../../../models/rsform'; import { isBasicConcept } from '../../../models/rsformAPI'; import { GraphFilterParams, useTermGraphStore } from '../../../stores/termGraph'; import { useRSEdit } from '../RSEditContext'; @@ -68,10 +68,10 @@ function TGFlow() { const [focusCst, setFocusCst] = useState(undefined); const filteredGraph = produceFilteredGraph(controller.schema, filter, focusCst); - const [hidden, setHidden] = useState([]); + const [hidden, setHidden] = useState([]); const [isDragging, setIsDragging] = useState(false); - const [hoverID, setHoverID] = useState(undefined); + const [hoverID, setHoverID] = useState(undefined); const hoverCst = hoverID && controller.schema.cstByID.get(hoverID); const [hoverCstDebounced] = useDebounce(hoverCst, PARAMETER.graphPopupDelay); const [hoverLeft, setHoverLeft] = useState(true); @@ -93,7 +93,7 @@ function TGFlow() { }); useEffect(() => { - const newDismissed: ConstituentaID[] = []; + const newDismissed: number[] = []; controller.schema.items.forEach(cst => { if (!filteredGraph.nodes.has(cst.id)) { newDismissed.push(cst.id); @@ -250,7 +250,7 @@ function TGFlow() { }, PARAMETER.graphRefreshDelay); } - function handleSetFocus(cstID: ConstituentaID | undefined) { + function handleSetFocus(cstID: number | undefined) { const target = cstID !== undefined ? controller.schema.cstByID.get(cstID) : cstID; setFocusCst(prev => (prev === target ? undefined : target)); if (target) { @@ -258,7 +258,7 @@ function TGFlow() { } } - function handleNodeClick(event: CProps.EventMouse, cstID: ConstituentaID) { + function handleNodeClick(event: CProps.EventMouse, cstID: number) { if (event.altKey) { event.preventDefault(); event.stopPropagation(); @@ -266,13 +266,13 @@ function TGFlow() { } } - function handleNodeDoubleClick(event: CProps.EventMouse, cstID: ConstituentaID) { + function handleNodeDoubleClick(event: CProps.EventMouse, cstID: number) { event.preventDefault(); event.stopPropagation(); controller.navigateCst(cstID); } - function handleNodeEnter(event: CProps.EventMouse, cstID: ConstituentaID) { + function handleNodeEnter(event: CProps.EventMouse, cstID: number) { setHoverID(cstID); setHoverLeft( event.clientX / window.innerWidth >= PARAMETER.graphHoverXLimit || @@ -446,7 +446,7 @@ function produceFilteredGraph(schema: IRSForm, params: GraphFilterParams, focusC }); } if (focusCst) { - const includes: ConstituentaID[] = [ + const includes: number[] = [ focusCst.id, ...focusCst.spawn, ...(params.focusShowInputs ? schema.graph.expandInputs([focusCst.id]) : []), diff --git a/rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorTermGraph/ViewHidden.tsx b/rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorTermGraph/ViewHidden.tsx index e5bfa89a..107484e1 100644 --- a/rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorTermGraph/ViewHidden.tsx +++ b/rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorTermGraph/ViewHidden.tsx @@ -13,18 +13,18 @@ import { APP_COLORS } from '@/styling/colors'; import { globals, PARAMETER, prefixes } from '@/utils/constants'; import { colorBgGraphNode } from '../../../colors'; -import { ConstituentaID, IRSForm } from '../../../models/rsform'; +import { IRSForm } from '../../../models/rsform'; import { GraphColoring, useTermGraphStore } from '../../../stores/termGraph'; import { useRSEdit } from '../RSEditContext'; interface ViewHiddenProps { schema: IRSForm; - items: ConstituentaID[]; - selected: ConstituentaID[]; + items: number[]; + selected: number[]; coloringScheme: GraphColoring; - toggleSelection: (cstID: ConstituentaID) => void; - setFocus: (cstID: ConstituentaID) => void; + toggleSelection: (cstID: number) => void; + setFocus: (cstID: number) => void; } function ViewHidden({ items, selected, toggleSelection, setFocus, schema, coloringScheme }: ViewHiddenProps) { @@ -37,7 +37,7 @@ function ViewHidden({ items, selected, toggleSelection, setFocus, schema, colori const setActiveCst = useTooltipsStore(state => state.setActiveCst); const hiddenHeight = useFitHeight(windowSize.isSmall ? '10.4rem + 2px' : '12.5rem + 2px'); - function handleClick(cstID: ConstituentaID, event: CProps.EventMouse) { + function handleClick(cstID: number, event: CProps.EventMouse) { if (event.ctrlKey || event.metaKey) { setFocus(cstID); } else { diff --git a/rsconcept/frontend/src/features/rsform/pages/RSFormPage/MenuRSTabs.tsx b/rsconcept/frontend/src/features/rsform/pages/RSFormPage/MenuRSTabs.tsx index a8b6f989..147d1b4a 100644 --- a/rsconcept/frontend/src/features/rsform/pages/RSFormPage/MenuRSTabs.tsx +++ b/rsconcept/frontend/src/features/rsform/pages/RSFormPage/MenuRSTabs.tsx @@ -33,7 +33,6 @@ import { } from '@/components/Icons'; import { useAuthSuspense } from '@/features/auth'; import { AccessPolicy, LocationHead } from '@/features/library/models/library'; -import { OssTabID } from '@/features/oss/pages/OssPage/OssEditContext'; import { useRoleStore, UserRole } from '@/features/users'; import { useDialogsStore } from '@/stores/dialogs'; import { useModificationStore } from '@/stores/modification'; @@ -284,7 +283,7 @@ function MenuRSTabs() { } - onClick={() => router.push(urls.oss(controller.schema.oss[0].id, OssTabID.GRAPH))} + onClick={() => router.push(urls.oss(controller.schema.oss[0].id))} /> ) : null} void; - navigateRSForm: ({ tab, activeID }: { tab: RSTabID; activeID?: ConstituentaID }) => void; - navigateCst: (cstID: ConstituentaID) => void; + navigateRSForm: ({ tab, activeID }: { tab: RSTabID; activeID?: number }) => void; + navigateCst: (cstID: number) => void; navigateOss: (ossID: number, newTab?: boolean) => void; deleteSchema: () => void; - setSelected: React.Dispatch>; - select: (target: ConstituentaID) => void; - deselect: (target: ConstituentaID) => void; - toggleSelect: (target: ConstituentaID) => void; + setSelected: React.Dispatch>; + select: (target: number) => void; + deselect: (target: number) => void; + toggleSelect: (target: number) => void; deselectAll: () => void; moveUp: () => void; @@ -100,7 +99,7 @@ export const RSEditState = ({ const isContentEditable = isMutable && !isArchive; const isAttachedToOSS = schema.oss.length > 0; - const [selected, setSelected] = useState([]); + const [selected, setSelected] = useState([]); const canDeleteSelected = selected.length > 0 && selected.every(id => !schema.cstByID.get(id)?.is_inherited); const activeCst = selected.length === 0 ? undefined : schema.cstByID.get(selected[selected.length - 1]); @@ -132,7 +131,7 @@ export const RSEditState = ({ router.push(urls.oss(ossID), newTab); } - function navigateRSForm({ tab, activeID }: { tab: RSTabID; activeID?: ConstituentaID }) { + function navigateRSForm({ tab, activeID }: { tab: RSTabID; activeID?: number }) { const data = { id: schema.id, tab: tab, @@ -154,7 +153,7 @@ export const RSEditState = ({ } } - function navigateCst(cstID: ConstituentaID) { + function navigateCst(cstID: number) { if (cstID !== activeCst?.id || activeTab !== RSTabID.CST_EDIT) { navigateRSForm({ tab: RSTabID.CST_EDIT, activeID: cstID }); } @@ -167,7 +166,7 @@ export const RSEditState = ({ const ossID = schema.oss.length > 0 ? schema.oss[0].id : undefined; void deleteItem(schema.id).then(() => { if (ossID) { - router.push(urls.oss(ossID, OssTabID.GRAPH)); + router.push(urls.oss(ossID)); } else { if (searchLocation === schema.location) { setSearchLocation(''); @@ -329,9 +328,9 @@ export const RSEditState = ({ deleteSchema, setSelected, - select: (target: ConstituentaID) => setSelected(prev => [...prev, target]), - deselect: (target: ConstituentaID) => setSelected(prev => prev.filter(id => id !== target)), - toggleSelect: (target: ConstituentaID) => + select: (target: number) => setSelected(prev => [...prev, target]), + deselect: (target: number) => setSelected(prev => prev.filter(id => id !== target)), + toggleSelect: (target: number) => setSelected(prev => (prev.includes(target) ? prev.filter(id => id !== target) : [...prev, target])), deselectAll: () => setSelected([]), @@ -351,10 +350,10 @@ export const RSEditState = ({ // ====== Internals ========= function getNextActiveOnDelete( - activeID: ConstituentaID | undefined, + activeID: number | undefined, items: IConstituenta[], - deleted: ConstituentaID[] -): ConstituentaID | undefined { + deleted: number[] +): number | undefined { if (items.length === deleted.length) { return undefined; } diff --git a/rsconcept/frontend/src/features/rsform/pages/RSFormPage/RSTabs.tsx b/rsconcept/frontend/src/features/rsform/pages/RSFormPage/RSTabs.tsx index 01438d6b..7ea3eabe 100644 --- a/rsconcept/frontend/src/features/rsform/pages/RSFormPage/RSTabs.tsx +++ b/rsconcept/frontend/src/features/rsform/pages/RSFormPage/RSTabs.tsx @@ -10,7 +10,6 @@ import { useAppLayoutStore } from '@/stores/appLayout'; import { useModificationStore } from '@/stores/modification'; import { labelVersion } from '../../labels'; -import { ConstituentaID } from '../../models/rsform'; import EditorConstituenta from './EditorConstituenta'; import EditorRSForm from './EditorRSFormCard'; import EditorRSList from './EditorRSList'; @@ -19,7 +18,7 @@ import MenuRSTabs from './MenuRSTabs'; import { RSTabID, useRSEdit } from './RSEditContext'; interface RSTabsProps { - activeID?: ConstituentaID; + activeID?: number; activeTab: RSTabID; } diff --git a/rsconcept/frontend/src/features/rsform/pages/RSFormPage/ViewConstituents/ConstituentsSearch.tsx b/rsconcept/frontend/src/features/rsform/pages/RSFormPage/ViewConstituents/ConstituentsSearch.tsx index 4ba4afbd..f907cdfb 100644 --- a/rsconcept/frontend/src/features/rsform/pages/RSFormPage/ViewConstituents/ConstituentsSearch.tsx +++ b/rsconcept/frontend/src/features/rsform/pages/RSFormPage/ViewConstituents/ConstituentsSearch.tsx @@ -6,7 +6,7 @@ import { MiniButton } from '@/components/Control'; import { IconChild } from '@/components/Icons'; import { SearchBar } from '@/components/Input'; -import { ConstituentaID, IConstituenta, IRSForm } from '../../../models/rsform'; +import { IConstituenta, IRSForm } from '../../../models/rsform'; import { matchConstituenta } from '../../../models/rsformAPI'; import SelectMatchMode from '../../../pages/RSFormPage/ViewConstituents/SelectMatchMode'; import { DependencyMode, useCstSearchStore } from '../../../stores/cstSearch'; @@ -15,7 +15,7 @@ import SelectGraphFilter from './SelectGraphFilter'; interface ConstituentsSearchProps { schema: IRSForm; dense?: boolean; - activeID?: ConstituentaID; + activeID?: number; activeExpression: string; onChange: React.Dispatch>; diff --git a/rsconcept/frontend/src/features/rsform/pages/RSFormPage/ViewConstituents/TableSideConstituents.tsx b/rsconcept/frontend/src/features/rsform/pages/RSFormPage/ViewConstituents/TableSideConstituents.tsx index 53ae58aa..5f237433 100644 --- a/rsconcept/frontend/src/features/rsform/pages/RSFormPage/ViewConstituents/TableSideConstituents.tsx +++ b/rsconcept/frontend/src/features/rsform/pages/RSFormPage/ViewConstituents/TableSideConstituents.tsx @@ -9,14 +9,14 @@ import { PARAMETER, prefixes } from '@/utils/constants'; import BadgeConstituenta from '../../../components/BadgeConstituenta'; import { describeConstituenta } from '../../../labels'; -import { ConstituentaID, IConstituenta } from '../../../models/rsform'; +import { IConstituenta } from '../../../models/rsform'; const DESCRIPTION_MAX_SYMBOLS = 280; interface TableSideConstituentsProps { items: IConstituenta[]; activeCst?: IConstituenta; - onOpenEdit: (cstID: ConstituentaID) => void; + onOpenEdit: (cstID: number) => void; autoScroll?: boolean; maxHeight: string; } diff --git a/rsconcept/frontend/src/features/users/backend/api.ts b/rsconcept/frontend/src/features/users/backend/api.ts index 50cd3c53..e56f616a 100644 --- a/rsconcept/frontend/src/features/users/backend/api.ts +++ b/rsconcept/frontend/src/features/users/backend/api.ts @@ -1,49 +1,14 @@ import { queryOptions } from '@tanstack/react-query'; -import { z } from 'zod'; import { axiosGet, axiosPatch, axiosPost } from '@/backend/apiTransport'; -import { DELAYS } from '@/backend/configuration'; -import { patterns } from '@/utils/constants'; -import { errorMsg, infoMsg } from '@/utils/labels'; +import { DELAYS, KEYS } from '@/backend/configuration'; +import { infoMsg } from '@/utils/labels'; import { IUserInfo, IUserProfile } from '../models/user'; - -/** - * Represents signup data, used to create new users. - */ -export const schemaUserSignup = z - .object({ - username: z.string().nonempty(errorMsg.requiredField).regex(RegExp(patterns.login), errorMsg.loginFormat), - email: z.string().email(errorMsg.emailField), - first_name: z.string(), - last_name: z.string(), - - password: z.string().nonempty(errorMsg.requiredField), - password2: z.string().nonempty(errorMsg.requiredField) - }) - .refine(schema => schema.password === schema.password2, { path: ['password2'], message: errorMsg.passwordsMismatch }); - -/** - * Represents signup data, used to create new users. - */ -export type IUserSignupDTO = z.infer; - -/** - * Represents user data, intended to update user profile in persistent storage. - */ -export const schemaUpdateProfile = z.object({ - email: z.string().email(errorMsg.emailField), - first_name: z.string(), - last_name: z.string() -}); - -/** - * Represents user data, intended to update user profile in persistent storage. - */ -export type IUpdateProfileDTO = z.infer; +import { IUpdateProfileDTO, IUserSignupDTO } from './types'; export const usersApi = { - baseKey: 'users', + baseKey: KEYS.users, getUsersQueryOptions: () => queryOptions({ queryKey: [usersApi.baseKey, 'list'], diff --git a/rsconcept/frontend/src/features/users/backend/types.ts b/rsconcept/frontend/src/features/users/backend/types.ts new file mode 100644 index 00000000..2943daaa --- /dev/null +++ b/rsconcept/frontend/src/features/users/backend/types.ts @@ -0,0 +1,38 @@ +import { z } from 'zod'; + +import { patterns } from '@/utils/constants'; +import { errorMsg } from '@/utils/labels'; + +/** + * Represents signup data, used to create new users. + */ +export const schemaUserSignup = z + .object({ + username: z.string().nonempty(errorMsg.requiredField).regex(RegExp(patterns.login), errorMsg.loginFormat), + email: z.string().email(errorMsg.emailField), + first_name: z.string(), + last_name: z.string(), + + password: z.string().nonempty(errorMsg.requiredField), + password2: z.string().nonempty(errorMsg.requiredField) + }) + .refine(schema => schema.password === schema.password2, { path: ['password2'], message: errorMsg.passwordsMismatch }); + +/** + * Represents signup data, used to create new users. + */ +export type IUserSignupDTO = z.infer; +/** + * Represents user data, intended to update user profile in persistent storage. + */ + +export const schemaUpdateProfile = z.object({ + email: z.string().email(errorMsg.emailField), + first_name: z.string(), + last_name: z.string() +}); + +/** + * Represents user data, intended to update user profile in persistent storage. + */ +export type IUpdateProfileDTO = z.infer; diff --git a/rsconcept/frontend/src/features/users/backend/useSignup.tsx b/rsconcept/frontend/src/features/users/backend/useSignup.tsx index db3a5a6a..c45ec21d 100644 --- a/rsconcept/frontend/src/features/users/backend/useSignup.tsx +++ b/rsconcept/frontend/src/features/users/backend/useSignup.tsx @@ -1,6 +1,7 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { IUserSignupDTO, usersApi } from './api'; +import { usersApi } from './api'; +import { IUserSignupDTO } from './types'; export const useSignup = () => { const client = useQueryClient(); diff --git a/rsconcept/frontend/src/features/users/backend/useUpdateProfile.tsx b/rsconcept/frontend/src/features/users/backend/useUpdateProfile.tsx index 88d3d45b..b95496af 100644 --- a/rsconcept/frontend/src/features/users/backend/useUpdateProfile.tsx +++ b/rsconcept/frontend/src/features/users/backend/useUpdateProfile.tsx @@ -1,6 +1,7 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { IUpdateProfileDTO, usersApi } from './api'; +import { usersApi } from './api'; +import { IUpdateProfileDTO } from './types'; export const useUpdateProfile = () => { const client = useQueryClient(); diff --git a/rsconcept/frontend/src/features/users/pages/RegisterPage/FormSignup.tsx b/rsconcept/frontend/src/features/users/pages/RegisterPage/FormSignup.tsx index 6d06fa3a..46afa71f 100644 --- a/rsconcept/frontend/src/features/users/pages/RegisterPage/FormSignup.tsx +++ b/rsconcept/frontend/src/features/users/pages/RegisterPage/FormSignup.tsx @@ -16,7 +16,7 @@ import { PrettyJson } from '@/components/View'; import { HelpTopic } from '@/features/help'; import { globals, patterns } from '@/utils/constants'; -import { IUserSignupDTO, schemaUserSignup } from '../../backend/api'; +import { IUserSignupDTO, schemaUserSignup } from '../../backend/types'; import { useSignup } from '../../backend/useSignup'; function FormSignup() { diff --git a/rsconcept/frontend/src/features/users/pages/UserProfilePage/EditorPassword.tsx b/rsconcept/frontend/src/features/users/pages/UserProfilePage/EditorPassword.tsx index d073738d..27427ae1 100644 --- a/rsconcept/frontend/src/features/users/pages/UserProfilePage/EditorPassword.tsx +++ b/rsconcept/frontend/src/features/users/pages/UserProfilePage/EditorPassword.tsx @@ -11,7 +11,7 @@ import { SubmitButton } from '@/components/Control'; import { ErrorData } from '@/components/InfoError'; import { TextInput } from '@/components/Input'; import { useChangePassword } from '@/features/auth'; -import { IChangePasswordDTO, schemaChangePassword } from '@/features/auth/backend/api'; +import { IChangePasswordDTO, schemaChangePassword } from '@/features/auth/backend/types'; function EditorPassword() { const router = useConceptNavigation(); diff --git a/rsconcept/frontend/src/features/users/pages/UserProfilePage/EditorProfile.tsx b/rsconcept/frontend/src/features/users/pages/UserProfilePage/EditorProfile.tsx index a842ab14..40903517 100644 --- a/rsconcept/frontend/src/features/users/pages/UserProfilePage/EditorProfile.tsx +++ b/rsconcept/frontend/src/features/users/pages/UserProfilePage/EditorProfile.tsx @@ -9,7 +9,7 @@ import { SubmitButton } from '@/components/Control'; import { ErrorData } from '@/components/InfoError'; import { TextInput } from '@/components/Input'; -import { IUpdateProfileDTO, schemaUpdateProfile } from '../../backend/api'; +import { IUpdateProfileDTO, schemaUpdateProfile } from '../../backend/types'; import { useProfileSuspense } from '../../backend/useProfile'; import { useUpdateProfile } from '../../backend/useUpdateProfile'; diff --git a/rsconcept/frontend/src/utils/codemirror.ts b/rsconcept/frontend/src/utils/codemirror.ts index 5d6e6521..f48efc17 100644 --- a/rsconcept/frontend/src/utils/codemirror.ts +++ b/rsconcept/frontend/src/utils/codemirror.ts @@ -3,15 +3,7 @@ */ import { syntaxTree } from '@codemirror/language'; import { NodeType, Tree, TreeCursor } from '@lezer/common'; -import { EditorState, ReactCodeMirrorRef, SelectionRange } from '@uiw/react-codemirror'; - -import { ReferenceTokens } from '@/features/rsform/components/RefsInput/parse'; -import { RefEntity } from '@/features/rsform/components/RefsInput/parse/parser.terms'; -import { GlobalTokens } from '@/features/rsform/components/RSInput/rslang'; -import { parseEntityReference, parseSyntacticReference } from '@/features/rsform/models/languageAPI'; -import { SyntaxTree } from '@/features/rsform/models/rslang'; - -import { PARAMETER } from './constants'; +import { ReactCodeMirrorRef, SelectionRange } from '@uiw/react-codemirror'; /** * Represents syntax tree node data. @@ -29,7 +21,7 @@ interface CursorNode extends SyntaxNode { isLeaf: boolean; } -function cursorNode({ type, from, to }: TreeCursor, isLeaf = false): CursorNode { +export function cursorNode({ type, from, to }: TreeCursor, isLeaf = false): CursorNode { return { type, from, to, isLeaf }; } @@ -87,56 +79,6 @@ export function printTree(tree: Tree): string { return state.output; } -/** - * Transform Tree to {@link SyntaxTree}. - */ -export function transformAST(tree: Tree): SyntaxTree { - const result: SyntaxTree = []; - const parents: number[] = []; - const cursor = tree.cursor(); - let finished = false; - let leave = true; - while (!finished) { - let node = cursorNode(cursor); - node.isLeaf = !cursor.firstChild(); - - leave = true; - result.push({ - uid: result.length, - parent: parents.length > 0 ? parents[parents.length - 1] : result.length, - typeID: node.type.id, - start: node.from, - finish: node.to, - data: { - dataType: 'string', - value: node.type.name == '⚠' ? PARAMETER.errorNodeLabel : node.type.name - } - }); - parents.push(result.length - 1); - - if (!node.isLeaf) continue; - - for (;;) { - node = cursorNode(cursor, node.isLeaf); - if (leave) { - parents.pop(); - } - - leave = cursor.type.isAnonymous; - node.isLeaf = false; - if (cursor.nextSibling()) { - break; - } - if (!cursor.parent()) { - finished = true; - break; - } - leave = true; - } - } - return result; -} - /** * Retrieves a list of all nodes, containing given range and corresponding to a filter. */ @@ -171,43 +113,6 @@ export function findContainedNodes(start: number, finish: number, tree: Tree, fi return result; } -/** - * Retrieves globalID from position in Editor. - */ -export function findAliasAt(pos: number, state: EditorState) { - const { from: lineStart, to: lineEnd, text } = state.doc.lineAt(pos); - const nodes = findEnvelopingNodes(pos, pos, syntaxTree(state), GlobalTokens); - let alias = ''; - let start = 0; - let end = 0; - nodes.forEach(node => { - if (node.to <= lineEnd && node.from >= lineStart) { - alias = text.slice(node.from - lineStart, node.to - lineStart); - start = node.from; - end = node.to; - } - }); - return { alias, start, end }; -} - -/** - * Retrieves reference from position in Editor. - */ -export function findReferenceAt(pos: number, state: EditorState) { - const nodes = findEnvelopingNodes(pos, pos, syntaxTree(state), ReferenceTokens); - if (nodes.length !== 1) { - return undefined; - } - const start = nodes[0].from; - const end = nodes[0].to; - const text = state.doc.sliceString(start, end); - if (nodes[0].type.id === RefEntity) { - return { ref: parseEntityReference(text), start, end }; - } else { - return { ref: parseSyntacticReference(text), start, end }; - } -} - /** * Wrapper class for CodeMirror editor. *