F: Add zod validation for backend responses for rsforms

This commit is contained in:
Ivan 2025-02-17 14:31:17 +03:00
parent 483fc93b58
commit 75c0a6f848
26 changed files with 318 additions and 244 deletions

View File

@ -3,8 +3,10 @@
*/ */
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import axios, { AxiosError, AxiosRequestConfig } from 'axios'; import axios, { AxiosError, AxiosRequestConfig } from 'axios';
import { z, ZodError } from 'zod';
import { buildConstants } from '@/utils/buildConstants'; import { buildConstants } from '@/utils/buildConstants';
import { errorMsg } from '@/utils/labels';
import { extractErrorMessage } from '@/utils/utils'; import { extractErrorMessage } from '@/utils/utils';
export { AxiosError } from 'axios'; export { AxiosError } from 'axios';
@ -41,23 +43,32 @@ export interface IAxiosRequest<RequestData, ResponseData> {
endpoint: string; endpoint: string;
request?: IFrontRequest<RequestData, ResponseData>; request?: IFrontRequest<RequestData, ResponseData>;
options?: AxiosRequestConfig; options?: AxiosRequestConfig;
schema?: z.ZodType;
} }
export interface IAxiosGetRequest { export interface IAxiosGetRequest {
endpoint: string; endpoint: string;
options?: AxiosRequestConfig; options?: AxiosRequestConfig;
signal?: AbortSignal; signal?: AbortSignal;
schema?: z.ZodType;
} }
// ================ Transport API calls ================ // ================ Transport API calls ================
export function axiosGet<ResponseData>({ endpoint, options }: IAxiosGetRequest) { export function axiosGet<ResponseData>({ endpoint, options, schema }: IAxiosGetRequest) {
return axiosInstance return axiosInstance
.get<ResponseData>(endpoint, options) .get<ResponseData>(endpoint, options)
.then(response => response.data) .then(response => {
schema?.parse(response.data);
return response.data;
})
.catch((error: Error | AxiosError) => { .catch((error: Error | AxiosError) => {
// Note: Ignore cancellation errors
if (error.name !== 'CanceledError') { if (error.name !== 'CanceledError') {
// Note: Ignore cancellation errors if (error instanceof ZodError) {
toast.error(extractErrorMessage(error)); toast.error(errorMsg.invalidResponse);
} else {
toast.error(extractErrorMessage(error));
}
console.error(error); console.error(error);
} }
throw error; throw error;
@ -67,11 +78,13 @@ export function axiosGet<ResponseData>({ endpoint, options }: IAxiosGetRequest)
export function axiosPost<RequestData, ResponseData = void>({ export function axiosPost<RequestData, ResponseData = void>({
endpoint, endpoint,
request, request,
options options,
schema
}: IAxiosRequest<RequestData, ResponseData>) { }: IAxiosRequest<RequestData, ResponseData>) {
return axiosInstance return axiosInstance
.post<ResponseData>(endpoint, request?.data, options) .post<ResponseData>(endpoint, request?.data, options)
.then(response => { .then(response => {
schema?.parse(response.data);
if (request?.successMessage) { if (request?.successMessage) {
if (typeof request.successMessage === 'string') { if (typeof request.successMessage === 'string') {
toast.success(request.successMessage); toast.success(request.successMessage);
@ -81,8 +94,12 @@ export function axiosPost<RequestData, ResponseData = void>({
} }
return response.data; return response.data;
}) })
.catch((error: Error | AxiosError) => { .catch((error: Error | AxiosError | ZodError) => {
toast.error(extractErrorMessage(error)); if (error instanceof ZodError) {
toast.error(errorMsg.invalidResponse);
} else {
toast.error(extractErrorMessage(error));
}
console.error(error); console.error(error);
throw error; throw error;
}); });
@ -91,11 +108,13 @@ export function axiosPost<RequestData, ResponseData = void>({
export function axiosDelete<RequestData, ResponseData = void>({ export function axiosDelete<RequestData, ResponseData = void>({
endpoint, endpoint,
request, request,
options options,
schema
}: IAxiosRequest<RequestData, ResponseData>) { }: IAxiosRequest<RequestData, ResponseData>) {
return axiosInstance return axiosInstance
.delete<ResponseData>(endpoint, options) .delete<ResponseData>(endpoint, options)
.then(response => { .then(response => {
schema?.parse(response.data);
if (request?.successMessage) { if (request?.successMessage) {
if (typeof request.successMessage === 'string') { if (typeof request.successMessage === 'string') {
toast.success(request.successMessage); toast.success(request.successMessage);
@ -105,8 +124,12 @@ export function axiosDelete<RequestData, ResponseData = void>({
} }
return response.data; return response.data;
}) })
.catch((error: Error | AxiosError) => { .catch((error: Error | AxiosError | ZodError) => {
toast.error(extractErrorMessage(error)); if (error instanceof ZodError) {
toast.error(errorMsg.invalidResponse);
} else {
toast.error(extractErrorMessage(error));
}
console.error(error); console.error(error);
throw error; throw error;
}); });
@ -115,11 +138,13 @@ export function axiosDelete<RequestData, ResponseData = void>({
export function axiosPatch<RequestData, ResponseData = void>({ export function axiosPatch<RequestData, ResponseData = void>({
endpoint, endpoint,
request, request,
options options,
schema
}: IAxiosRequest<RequestData, ResponseData>) { }: IAxiosRequest<RequestData, ResponseData>) {
return axiosInstance return axiosInstance
.patch<ResponseData>(endpoint, request?.data, options) .patch<ResponseData>(endpoint, request?.data, options)
.then(response => { .then(response => {
schema?.parse(response.data);
if (request?.successMessage) { if (request?.successMessage) {
if (typeof request.successMessage === 'string') { if (typeof request.successMessage === 'string') {
toast.success(request.successMessage); toast.success(request.successMessage);
@ -129,8 +154,12 @@ export function axiosPatch<RequestData, ResponseData = void>({
} }
return response.data; return response.data;
}) })
.catch((error: Error | AxiosError) => { .catch((error: Error | AxiosError | ZodError) => {
toast.error(extractErrorMessage(error)); if (error instanceof ZodError) {
toast.error(errorMsg.invalidResponse);
} else {
toast.error(extractErrorMessage(error));
}
console.error(error); console.error(error);
throw error; throw error;
}); });

View File

@ -1,11 +1,12 @@
import clsx from 'clsx'; import clsx from 'clsx';
import { ZodError } from 'zod';
import { AxiosError, isAxiosError } from '@/backend/apiTransport'; import { AxiosError, isAxiosError } from '@/backend/apiTransport';
import { isResponseHtml } from '@/utils/utils'; import { isResponseHtml } from '@/utils/utils';
import { PrettyJson } from './View'; import { PrettyJson } from './View';
export type ErrorData = string | Error | AxiosError | undefined | null; export type ErrorData = string | Error | AxiosError | ZodError | undefined | null;
interface InfoErrorProps { interface InfoErrorProps {
error: ErrorData; error: ErrorData;
@ -16,6 +17,13 @@ function DescribeError({ error }: { error: ErrorData }) {
return <p>Ошибки отсутствуют</p>; return <p>Ошибки отсутствуют</p>;
} else if (typeof error === 'string') { } else if (typeof error === 'string') {
return <p>{error}</p>; return <p>{error}</p>;
} else if (error instanceof ZodError) {
return (
<div className='mt-6'>
<p>Ошибка валидации данных</p>
<PrettyJson data={JSON.parse(error.toString()) as unknown} />;
</div>
);
} else if (!isAxiosError(error)) { } else if (!isAxiosError(error)) {
return ( return (
<div className='mt-6'> <div className='mt-6'>

View File

@ -138,11 +138,11 @@ export const libraryApi = {
successMessage: infoMsg.versionRestored successMessage: infoMsg.versionRestored
} }
}), }),
versionUpdate: (data: IVersionUpdateDTO) => versionUpdate: (data: { itemID: number; version: IVersionUpdateDTO }) =>
axiosPatch<IVersionUpdateDTO, IVersionInfo>({ axiosPatch<IVersionUpdateDTO, IVersionInfo>({
endpoint: `/api/versions/${data.id}`, endpoint: `/api/versions/${data.version.id}`,
request: { request: {
data: data, data: data.version,
successMessage: infoMsg.changesSaved successMessage: infoMsg.changesSaved
} }
}), }),

View File

@ -12,8 +12,8 @@ export const useVersionUpdate = () => {
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [libraryApi.baseKey, 'update-version'], mutationKey: [libraryApi.baseKey, 'update-version'],
mutationFn: libraryApi.versionUpdate, mutationFn: libraryApi.versionUpdate,
onSuccess: data => { onSuccess: (data, variables) => {
client.setQueryData(KEYS.composite.rsItem({ itemID: data.item }), (prev: IRSFormDTO | undefined) => client.setQueryData(KEYS.composite.rsItem({ itemID: variables.itemID }), (prev: IRSFormDTO | undefined) =>
!prev !prev
? undefined ? undefined
: { : {
@ -26,6 +26,6 @@ export const useVersionUpdate = () => {
} }
}); });
return { return {
versionUpdate: (data: IVersionUpdateDTO) => mutation.mutateAsync(data) versionUpdate: (data: { itemID: number; version: IVersionUpdateDTO }) => mutation.mutateAsync(data)
}; };
}; };

View File

@ -81,7 +81,7 @@ function DlgEditVersions() {
if (!isDirty || isProcessing || !isValid) { if (!isDirty || isProcessing || !isValid) {
return; return;
} }
void versionUpdate(data).then(() => reset({ ...data })); void versionUpdate({ itemID: itemID, version: data }).then(() => reset({ ...data }));
} }
return ( return (

View File

@ -2,6 +2,8 @@
* Module: Models for LibraryItem. * Module: Models for LibraryItem.
*/ */
import { z } from 'zod';
/** /**
* Represents type of library items. * Represents type of library items.
*/ */
@ -31,16 +33,17 @@ export enum LocationHead {
export const BASIC_SCHEMAS = '/L/Базовые'; export const BASIC_SCHEMAS = '/L/Базовые';
export const schemaVersionInfo = z.object({
id: z.coerce.number(),
version: z.string(),
description: z.string(),
time_create: z.string()
});
/** /**
* Represents library item version information. * Represents library item version information.
*/ */
export interface IVersionInfo { export type IVersionInfo = z.infer<typeof schemaVersionInfo>;
id: number;
item: number;
version: string;
description: string;
time_create: string;
}
/** /**
* Represents library item common data typical for all item types. * Represents library item common data typical for all item types.
@ -70,7 +73,10 @@ export interface ILibraryItemData extends ILibraryItem {
/** /**
* Represents {@link ILibraryItem} minimal reference data. * Represents {@link ILibraryItem} minimal reference data.
*/ */
export interface ILibraryItemReference extends Pick<ILibraryItem, 'id' | 'alias'> {} export interface ILibraryItemReference {
id: number;
alias: string;
}
/** /**
* Represents {@link ILibraryItem} extended data with versions. * Represents {@link ILibraryItem} extended data with versions.

View File

@ -1,6 +1,7 @@
import { queryOptions } from '@tanstack/react-query'; import { queryOptions } from '@tanstack/react-query';
import { IConstituentaReference, ITargetCst } from '@/features/rsform/models/rsform'; import { ITargetCst } from '@/features/rsform/backend/types';
import { IConstituentaReference } from '@/features/rsform/models/rsform';
import { axiosGet, axiosPatch, axiosPost } from '@/backend/apiTransport'; import { axiosGet, axiosPatch, axiosPost } from '@/backend/apiTransport';
import { DELAYS, KEYS } from '@/backend/configuration'; import { DELAYS, KEYS } from '@/backend/configuration';

View File

@ -1,7 +1,5 @@
import { useMutation } from '@tanstack/react-query'; import { useMutation } from '@tanstack/react-query';
import { ITargetCst } from '@/features/rsform/models/rsform';
import { ossApi } from './api'; import { ossApi } from './api';
export const useFindPredecessor = () => { export const useFindPredecessor = () => {
@ -10,6 +8,6 @@ export const useFindPredecessor = () => {
mutationFn: ossApi.getPredecessor mutationFn: ossApi.getPredecessor
}); });
return { return {
findPredecessor: (data: ITargetCst) => mutation.mutateAsync(data) findPredecessor: (target: number) => mutation.mutateAsync({ target: target })
}; };
}; };

View File

@ -19,13 +19,13 @@ import { IRSFormDTO } from './types';
* based on the loaded data. It also establishes dependencies between concepts in the graph. * based on the loaded data. It also establishes dependencies between concepts in the graph.
*/ */
export class RSFormLoader { export class RSFormLoader {
private schema: IRSFormDTO; private schema: IRSForm;
private graph: Graph = new Graph(); private graph: Graph = new Graph();
private cstByAlias = new Map<string, IConstituenta>(); private cstByAlias = new Map<string, IConstituenta>();
private cstByID = new Map<number, IConstituenta>(); private cstByID = new Map<number, IConstituenta>();
constructor(input: IRSFormDTO) { constructor(input: IRSFormDTO) {
this.schema = input; this.schema = input as unknown as IRSForm;
} }
produceRSForm(): IRSForm { produceRSForm(): IRSForm {
@ -33,7 +33,7 @@ export class RSFormLoader {
this.createGraph(); this.createGraph();
this.inferCstAttributes(); this.inferCstAttributes();
const result = this.schema as IRSForm; const result = this.schema;
result.stats = this.calculateStats(); result.stats = this.calculateStats();
result.graph = this.graph; result.graph = this.graph;
result.cstByAlias = this.cstByAlias; result.cstByAlias = this.cstByAlias;
@ -43,8 +43,8 @@ export class RSFormLoader {
private prepareLookups() { private prepareLookups() {
this.schema.items.forEach(cst => { this.schema.items.forEach(cst => {
this.cstByAlias.set(cst.alias, cst as IConstituenta); this.cstByAlias.set(cst.alias, cst);
this.cstByID.set(cst.id, cst as IConstituenta); this.cstByID.set(cst.id, cst);
this.graph.addNode(cst.id); this.graph.addNode(cst.id);
}); });
} }
@ -189,7 +189,7 @@ export class RSFormLoader {
sum + (cst.parse.status === ParsingStatus.VERIFIED && cst.parse.valueClass === ValueClass.INVALID ? 1 : 0), sum + (cst.parse.status === ParsingStatus.VERIFIED && cst.parse.valueClass === ValueClass.INVALID ? 1 : 0),
0 0
), ),
count_inherited: items.reduce((sum, cst) => sum + ((cst as IConstituenta).is_inherited ? 1 : 0), 0), count_inherited: items.reduce((sum, cst) => sum + (cst.is_inherited ? 1 : 0), 0),
count_text_term: items.reduce((sum, cst) => sum + (cst.term_raw ? 1 : 0), 0), count_text_term: items.reduce((sum, cst) => sum + (cst.term_raw ? 1 : 0), 0),
count_definition: items.reduce((sum, cst) => sum + (cst.definition_raw ? 1 : 0), 0), count_definition: items.reduce((sum, cst) => sum + (cst.definition_raw ? 1 : 0), 0),

View File

@ -4,21 +4,28 @@ import { axiosGet, axiosPatch, axiosPost } from '@/backend/apiTransport';
import { DELAYS, KEYS } from '@/backend/configuration'; import { DELAYS, KEYS } from '@/backend/configuration';
import { infoMsg } from '@/utils/labels'; import { infoMsg } from '@/utils/labels';
import { IConstituentaList, IConstituentaMeta, ITargetCst } from '../models/rsform'; import { IConstituentaList } from '../models/rsform';
import { IExpressionParse } from '../models/rslang';
import { import {
ICheckConstituentaDTO, ICheckConstituentaDTO,
IConstituentaBasicsDTO,
ICstCreatedResponse, ICstCreatedResponse,
ICstCreateDTO, ICstCreateDTO,
ICstMoveDTO, ICstMoveDTO,
ICstRenameDTO, ICstRenameDTO,
ICstSubstitutionsDTO, ICstSubstitutionsDTO,
ICstUpdateDTO, ICstUpdateDTO,
IExpressionParseDTO,
IInlineSynthesisDTO, IInlineSynthesisDTO,
IProduceStructureResponse, IProduceStructureResponse,
IRSFormDTO, IRSFormDTO,
IRSFormUploadDTO IRSFormUploadDTO,
ITargetCst,
schemaConstituentaBasics,
schemaCstCreatedResponse,
schemaExpressionParse,
schemaProduceStructureResponse,
schemaRSForm
} from './types'; } from './types';
export const rsformsApi = { export const rsformsApi = {
@ -32,6 +39,7 @@ export const rsformsApi = {
!itemID !itemID
? undefined ? undefined
: axiosGet<IRSFormDTO>({ : axiosGet<IRSFormDTO>({
schema: schemaRSForm,
endpoint: version ? `/api/library/${itemID}/versions/${version}` : `/api/rsforms/${itemID}/details`, endpoint: version ? `/api/library/${itemID}/versions/${version}` : `/api/rsforms/${itemID}/details`,
options: { signal: meta.signal } options: { signal: meta.signal }
}) })
@ -45,6 +53,7 @@ export const rsformsApi = {
}), }),
upload: (data: IRSFormUploadDTO) => upload: (data: IRSFormUploadDTO) =>
axiosPatch<IRSFormUploadDTO, IRSFormDTO>({ axiosPatch<IRSFormUploadDTO, IRSFormDTO>({
schema: schemaRSForm,
endpoint: `/api/rsforms/${data.itemID}/load-trs`, endpoint: `/api/rsforms/${data.itemID}/load-trs`,
request: { request: {
data: data, data: data,
@ -59,6 +68,7 @@ export const rsformsApi = {
cstCreate: ({ itemID, data }: { itemID: number; data: ICstCreateDTO }) => cstCreate: ({ itemID, data }: { itemID: number; data: ICstCreateDTO }) =>
axiosPost<ICstCreateDTO, ICstCreatedResponse>({ axiosPost<ICstCreateDTO, ICstCreatedResponse>({
schema: schemaCstCreatedResponse,
endpoint: `/api/rsforms/${itemID}/create-cst`, endpoint: `/api/rsforms/${itemID}/create-cst`,
request: { request: {
data: data, data: data,
@ -66,7 +76,8 @@ export const rsformsApi = {
} }
}), }),
cstUpdate: ({ itemID, data }: { itemID: number; data: ICstUpdateDTO }) => cstUpdate: ({ itemID, data }: { itemID: number; data: ICstUpdateDTO }) =>
axiosPatch<ICstUpdateDTO, IConstituentaMeta>({ axiosPatch<ICstUpdateDTO, IConstituentaBasicsDTO>({
schema: schemaConstituentaBasics,
endpoint: `/api/rsforms/${itemID}/update-cst`, endpoint: `/api/rsforms/${itemID}/update-cst`,
request: { request: {
data: data, data: data,
@ -75,6 +86,7 @@ export const rsformsApi = {
}), }),
cstDelete: ({ itemID, data }: { itemID: number; data: IConstituentaList }) => cstDelete: ({ itemID, data }: { itemID: number; data: IConstituentaList }) =>
axiosPatch<IConstituentaList, IRSFormDTO>({ axiosPatch<IConstituentaList, IRSFormDTO>({
schema: schemaRSForm,
endpoint: `/api/rsforms/${itemID}/delete-multiple-cst`, endpoint: `/api/rsforms/${itemID}/delete-multiple-cst`,
request: { request: {
data: data, data: data,
@ -83,6 +95,7 @@ export const rsformsApi = {
}), }),
cstRename: ({ itemID, data }: { itemID: number; data: ICstRenameDTO }) => cstRename: ({ itemID, data }: { itemID: number; data: ICstRenameDTO }) =>
axiosPatch<ICstRenameDTO, ICstCreatedResponse>({ axiosPatch<ICstRenameDTO, ICstCreatedResponse>({
schema: schemaCstCreatedResponse,
endpoint: `/api/rsforms/${itemID}/rename-cst`, endpoint: `/api/rsforms/${itemID}/rename-cst`,
request: { request: {
data: data, data: data,
@ -91,6 +104,7 @@ export const rsformsApi = {
}), }),
cstSubstitute: ({ itemID, data }: { itemID: number; data: ICstSubstitutionsDTO }) => cstSubstitute: ({ itemID, data }: { itemID: number; data: ICstSubstitutionsDTO }) =>
axiosPatch<ICstSubstitutionsDTO, IRSFormDTO>({ axiosPatch<ICstSubstitutionsDTO, IRSFormDTO>({
schema: schemaRSForm,
endpoint: `/api/rsforms/${itemID}/substitute`, endpoint: `/api/rsforms/${itemID}/substitute`,
request: { request: {
data: data, data: data,
@ -99,12 +113,14 @@ export const rsformsApi = {
}), }),
cstMove: ({ itemID, data }: { itemID: number; data: ICstMoveDTO }) => cstMove: ({ itemID, data }: { itemID: number; data: ICstMoveDTO }) =>
axiosPatch<ICstMoveDTO, IRSFormDTO>({ axiosPatch<ICstMoveDTO, IRSFormDTO>({
schema: schemaRSForm,
endpoint: `/api/rsforms/${itemID}/move-cst`, endpoint: `/api/rsforms/${itemID}/move-cst`,
request: { data: data } request: { data: data }
}), }),
produceStructure: ({ itemID, data }: { itemID: number; data: ITargetCst }) => produceStructure: ({ itemID, data }: { itemID: number; data: ITargetCst }) =>
axiosPatch<ITargetCst, IProduceStructureResponse>({ axiosPatch<ITargetCst, IProduceStructureResponse>({
schema: schemaProduceStructureResponse,
endpoint: `/api/rsforms/${itemID}/produce-structure`, endpoint: `/api/rsforms/${itemID}/produce-structure`,
request: { request: {
data: data, data: data,
@ -113,6 +129,7 @@ export const rsformsApi = {
}), }),
inlineSynthesis: (data: IInlineSynthesisDTO) => inlineSynthesis: (data: IInlineSynthesisDTO) =>
axiosPatch<IInlineSynthesisDTO, IRSFormDTO>({ axiosPatch<IInlineSynthesisDTO, IRSFormDTO>({
schema: schemaRSForm,
endpoint: `/api/rsforms/inline-synthesis`, endpoint: `/api/rsforms/inline-synthesis`,
request: { request: {
data: data, data: data,
@ -121,17 +138,20 @@ export const rsformsApi = {
}), }),
restoreOrder: ({ itemID }: { itemID: number }) => restoreOrder: ({ itemID }: { itemID: number }) =>
axiosPatch<undefined, IRSFormDTO>({ axiosPatch<undefined, IRSFormDTO>({
schema: schemaRSForm,
endpoint: `/api/rsforms/${itemID}/restore-order`, endpoint: `/api/rsforms/${itemID}/restore-order`,
request: { successMessage: infoMsg.reorderComplete } request: { successMessage: infoMsg.reorderComplete }
}), }),
resetAliases: ({ itemID }: { itemID: number }) => resetAliases: ({ itemID }: { itemID: number }) =>
axiosPatch<undefined, IRSFormDTO>({ axiosPatch<undefined, IRSFormDTO>({
schema: schemaRSForm,
endpoint: `/api/rsforms/${itemID}/reset-aliases`, endpoint: `/api/rsforms/${itemID}/reset-aliases`,
request: { successMessage: infoMsg.reindexComplete } request: { successMessage: infoMsg.reindexComplete }
}), }),
checkConstituenta: ({ itemID, data }: { itemID: number; data: ICheckConstituentaDTO }) => checkConstituenta: ({ itemID, data }: { itemID: number; data: ICheckConstituentaDTO }) =>
axiosPost<ICheckConstituentaDTO, IExpressionParse>({ axiosPost<ICheckConstituentaDTO, IExpressionParseDTO>({
schema: schemaExpressionParse,
endpoint: `/api/rsforms/${itemID}/check-constituenta`, endpoint: `/api/rsforms/${itemID}/check-constituenta`,
request: { data: data } request: { data: data }
}) })

View File

@ -1,37 +1,22 @@
import { z } from 'zod'; import { z } from 'zod';
import { ILibraryItemReference, ILibraryItemVersioned } from '@/features/library/models/library'; import { AccessPolicy, LibraryItemType, schemaVersionInfo } from '@/features/library/models/library';
import { errorMsg } from '@/utils/labels'; import { errorMsg } from '@/utils/labels';
import { CstType, IConstituentaMeta, IInheritanceInfo } from '../models/rsform'; import { CstType } from '../models/rsform';
import { IArgumentInfo, ParsingStatus, ValueClass } from '../models/rslang'; import { ParsingStatus, RSErrorType, Syntax, TokenID, ValueClass } from '../models/rslang';
/** /** Represents Constituenta basic persistent data. */
* Represents {@link IConstituenta} data from server. export type IConstituentaBasicsDTO = z.infer<typeof schemaConstituentaBasics>;
*/
export interface IConstituentaDTO extends IConstituentaMeta {
parse: {
status: ParsingStatus;
valueClass: ValueClass;
typification: string;
syntaxTree: string;
args: IArgumentInfo[];
};
}
/** /** Represents {@link IConstituenta} data from server. */
* Represents data for {@link IRSForm} provided by backend. export type IConstituentaDTO = z.infer<typeof schemaConstituenta>;
*/
export interface IRSFormDTO extends ILibraryItemVersioned {
items: IConstituentaDTO[];
inheritance: IInheritanceInfo[];
oss: ILibraryItemReference[];
}
/** /** Represents data for {@link IRSForm} provided by backend. */
* Represents data, used for uploading {@link IRSForm} as file. export type IRSFormDTO = z.infer<typeof schemaRSForm>;
*/
/** Represents data, used for uploading {@link IRSForm} as file. */
export interface IRSFormUploadDTO { export interface IRSFormUploadDTO {
itemID: number; itemID: number;
load_metadata: boolean; load_metadata: boolean;
@ -39,36 +24,128 @@ export interface IRSFormUploadDTO {
fileName: string; fileName: string;
} }
/** /** Represents target {@link IConstituenta}. */
* Represents {@link IConstituenta} data, used in creation process. export interface ITargetCst {
*/ target: number;
export const schemaCstCreate = z.object({
cst_type: z.nativeEnum(CstType),
alias: z.string().nonempty(errorMsg.requiredField),
convention: z.string(),
definition_formal: z.string(),
definition_raw: z.string(),
term_raw: z.string(),
term_forms: z.array(z.object({ text: z.string(), tags: z.string() })),
insert_after: z.number().nullable()
});
/**
* Represents {@link IConstituenta} data, used in creation process.
*/
export type ICstCreateDTO = z.infer<typeof schemaCstCreate>;
/**
* Represents data response when creating {@link IConstituenta}.
*/
export interface ICstCreatedResponse {
new_cst: IConstituentaMeta;
schema: IRSFormDTO;
} }
/** /** Represents {@link IConstituenta} data, used in creation process. */
* Represents data, used in updating persistent attributes in {@link IConstituenta}. export type ICstCreateDTO = z.infer<typeof schemaCstCreate>;
*/
/** Represents data response when creating {@link IConstituenta}. */
export type ICstCreatedResponse = z.infer<typeof schemaCstCreatedResponse>;
/** Represents data, used in updating persistent attributes in {@link IConstituenta}. */
export type ICstUpdateDTO = z.infer<typeof schemaCstUpdate>;
/** Represents data, used in renaming {@link IConstituenta}. */
export type ICstRenameDTO = z.infer<typeof schemaCstRename>;
/** 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 type IProduceStructureResponse = z.infer<typeof schemaProduceStructureResponse>;
/** Represents data, used in merging single {@link IConstituenta}. */
export type ICstSubstitute = z.infer<typeof schemaCstSubstitute>;
/** Represents input data for inline synthesis. */
export type IInlineSynthesisDTO = z.infer<typeof schemaInlineSynthesis>;
/** Represents {@link IConstituenta} data, used for checking expression. */
export interface ICheckConstituentaDTO {
alias: string;
cst_type: CstType;
definition_formal: string;
}
/** Represents data, used in merging multiple {@link IConstituenta}. */
export type ICstSubstitutionsDTO = z.infer<typeof schemaCstSubstitutions>;
/** Represents parsing error description. */
export type IRSErrorDescription = z.infer<typeof schemaRSErrorDescription>;
/** Represents results of expression parse in RSLang. */
export type IExpressionParseDTO = z.infer<typeof schemaExpressionParse>;
// ========= SCHEMAS ========
export const schemaConstituentaBasics = z.object({
id: z.coerce.number(),
alias: z.string().nonempty(errorMsg.requiredField),
convention: z.string(),
cst_type: z.nativeEnum(CstType),
definition_formal: z.string(),
definition_raw: z.string(),
definition_resolved: z.string(),
term_raw: z.string(),
term_resolved: z.string(),
term_forms: z.array(z.object({ text: z.string(), tags: z.string() }))
});
export const schemaConstituenta = schemaConstituentaBasics.extend({
parse: z.object({
status: z.nativeEnum(ParsingStatus),
valueClass: z.nativeEnum(ValueClass),
typification: z.string(),
syntaxTree: z.string(),
args: z.array(z.object({ alias: z.string(), typification: z.string() }))
})
});
export const schemaRSForm = z.object({
id: z.coerce.number(),
item_type: z.nativeEnum(LibraryItemType),
title: z.string(),
alias: z.string(),
comment: z.string(),
visible: z.boolean(),
read_only: z.boolean(),
location: z.string(),
access_policy: z.nativeEnum(AccessPolicy),
time_create: z.string(),
time_update: z.string(),
owner: z.coerce.number().nullable(),
editors: z.array(z.coerce.number()),
version: z.coerce.number().optional(),
versions: z.array(schemaVersionInfo),
items: z.array(schemaConstituenta),
inheritance: z.array(
z.object({
child: z.coerce.number(),
child_source: z.coerce.number(),
parent: z.coerce.number(),
parent_source: z.coerce.number()
})
),
oss: z.array(z.object({ id: z.coerce.number(), alias: z.string() }))
});
export const schemaCstCreate = schemaConstituentaBasics
.pick({
cst_type: true,
alias: true,
convention: true,
definition_formal: true,
definition_raw: true,
term_raw: true,
term_forms: true
})
.extend({
insert_after: z.number().nullable()
});
export const schemaCstCreatedResponse = z.object({
new_cst: schemaConstituentaBasics,
schema: schemaRSForm
});
export const schemaCstUpdate = z.object({ export const schemaCstUpdate = z.object({
target: z.number(), target: z.number(),
item_data: z.object({ item_data: z.object({
@ -80,57 +157,26 @@ export const schemaCstUpdate = z.object({
}) })
}); });
/**
* Represents data, used in updating persistent attributes in {@link IConstituenta}.
*/
export type ICstUpdateDTO = z.infer<typeof schemaCstUpdate>;
/**
* Represents data, used in renaming {@link IConstituenta}.
*/
export const schemaCstRename = z.object({ export const schemaCstRename = z.object({
target: z.number(), target: z.number(),
alias: z.string(), alias: z.string(),
cst_type: z.nativeEnum(CstType) cst_type: z.nativeEnum(CstType)
}); });
/** export const schemaProduceStructureResponse = z.object({
* Represents data, used in renaming {@link IConstituenta}. cst_list: z.array(z.number()),
*/ schema: schemaRSForm
export type ICstRenameDTO = z.infer<typeof schemaCstRename>; });
/**
* 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({ export const schemaCstSubstitute = z.object({
original: z.number(), original: z.number(),
substitution: z.number() substitution: z.number()
}); });
/** export const schemaCstSubstitutions = z.object({
* Represents data, used in merging single {@link IConstituenta}. substitutions: z.array(schemaCstSubstitute).min(1, { message: errorMsg.emptySubstitutions })
*/ });
export type ICstSubstitute = z.infer<typeof schemaCstSubstitute>;
/**
* Represents input data for inline synthesis.
*/
export const schemaInlineSynthesis = z.object({ export const schemaInlineSynthesis = z.object({
receiver: z.number(), receiver: z.number(),
source: z.number().nullable(), source: z.number().nullable(),
@ -138,28 +184,35 @@ export const schemaInlineSynthesis = z.object({
substitutions: z.array(schemaCstSubstitute) substitutions: z.array(schemaCstSubstitute)
}); });
/** export const schemaRSErrorDescription = z.object({
* Represents input data for inline synthesis. errorType: z.nativeEnum(RSErrorType),
*/ position: z.number(),
export type IInlineSynthesisDTO = z.infer<typeof schemaInlineSynthesis>; isCritical: z.boolean(),
params: z.array(z.string())
/**
* 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 })
}); });
/** export const schemaExpressionParse = z.object({
* Represents data, used in merging multiple {@link IConstituenta}. parseResult: z.boolean(),
*/ prefixLen: z.number(),
export type ICstSubstitutionsDTO = z.infer<typeof schemaCstSubstitutions>; syntax: z.nativeEnum(Syntax),
typification: z.string(),
valueClass: z.nativeEnum(ValueClass),
errors: z.array(schemaRSErrorDescription),
astText: z.string(),
ast: z.array(
z.object({
uid: z.number(),
parent: z.number(),
typeID: z.nativeEnum(TokenID),
start: z.number(),
finish: z.number(),
data: z.object({ dataType: z.string(), value: z.unknown().refine(value => value !== undefined) })
})
),
args: z.array(
z.object({
alias: z.string(),
typification: z.string()
})
)
});

View File

@ -4,9 +4,8 @@ import { useUpdateTimestamp } from '@/features/library';
import { KEYS } from '@/backend/configuration'; import { KEYS } from '@/backend/configuration';
import { ITargetCst } from '../models/rsform';
import { rsformsApi } from './api'; import { rsformsApi } from './api';
import { ITargetCst } from './types';
export const useProduceStructure = () => { export const useProduceStructure = () => {
const client = useQueryClient(); const client = useQueryClient();

View File

@ -7,9 +7,9 @@ import { ModalForm } from '@/components/Modal';
import { useDialogsStore } from '@/stores/dialogs'; import { useDialogsStore } from '@/stores/dialogs';
import { errorMsg } from '@/utils/labels'; import { errorMsg } from '@/utils/labels';
import { ICstCreateDTO, schemaCstCreate } from '../../backend/types'; import { IConstituentaBasicsDTO, ICstCreateDTO, schemaCstCreate } from '../../backend/types';
import { useCstCreate } from '../../backend/useCstCreate'; import { useCstCreate } from '../../backend/useCstCreate';
import { IConstituentaMeta, IRSForm } from '../../models/rsform'; import { IRSForm } from '../../models/rsform';
import { validateNewAlias } from '../../models/rsformAPI'; import { validateNewAlias } from '../../models/rsformAPI';
import FormCreateCst from './FormCreateCst'; import FormCreateCst from './FormCreateCst';
@ -17,7 +17,7 @@ import FormCreateCst from './FormCreateCst';
export interface DlgCreateCstProps { export interface DlgCreateCstProps {
initial: ICstCreateDTO; initial: ICstCreateDTO;
schema: IRSForm; schema: IRSForm;
onCreate: (data: IConstituentaMeta) => void; onCreate: (data: IConstituentaBasicsDTO) => void;
} }
function DlgCreateCst() { function DlgCreateCst() {
@ -30,7 +30,7 @@ function DlgCreateCst() {
}); });
const alias = useWatch({ control: methods.control, name: 'alias' }); const alias = useWatch({ control: methods.control, name: 'alias' });
const cst_type = useWatch({ control: methods.control, name: 'cst_type' }); const cst_type = useWatch({ control: methods.control, name: 'cst_type' });
const isValid = alias !== initial.alias && validateNewAlias(alias, cst_type, schema); const isValid = validateNewAlias(alias, cst_type, schema);
function onSubmit(data: ICstCreateDTO) { function onSubmit(data: ICstCreateDTO) {
return cstCreate({ itemID: schema.id, data }).then(onCreate); return cstCreate({ itemID: schema.id, data }).then(onCreate);

View File

@ -12,9 +12,9 @@ import { ModalForm } from '@/components/Modal';
import { TabLabel, TabList, TabPanel, Tabs } from '@/components/Tabs'; import { TabLabel, TabList, TabPanel, Tabs } from '@/components/Tabs';
import { useDialogsStore } from '@/stores/dialogs'; import { useDialogsStore } from '@/stores/dialogs';
import { ICstCreateDTO, schemaCstCreate } from '../../backend/types'; import { IConstituentaBasicsDTO, ICstCreateDTO, schemaCstCreate } from '../../backend/types';
import { useCstCreate } from '../../backend/useCstCreate'; import { useCstCreate } from '../../backend/useCstCreate';
import { CstType, IConstituentaMeta, IRSForm } from '../../models/rsform'; import { CstType, IRSForm } from '../../models/rsform';
import { generateAlias, validateNewAlias } from '../../models/rsformAPI'; import { generateAlias, validateNewAlias } from '../../models/rsformAPI';
import FormCreateCst from '../DlgCreateCst/FormCreateCst'; import FormCreateCst from '../DlgCreateCst/FormCreateCst';
@ -24,7 +24,7 @@ import { TemplateState } from './TemplateContext';
export interface DlgCstTemplateProps { export interface DlgCstTemplateProps {
schema: IRSForm; schema: IRSForm;
onCreate: (data: IConstituentaMeta) => void; onCreate: (data: IConstituentaBasicsDTO) => void;
insertAfter?: number; insertAfter?: number;
} }

View File

@ -5,16 +5,10 @@
import { PARAMETER } from '@/utils/constants'; import { PARAMETER } from '@/utils/constants';
import { prepareTooltip } from '@/utils/utils'; import { prepareTooltip } from '@/utils/utils';
import { IRSErrorDescription } from './backend/types';
import { GramData, Grammeme, ReferenceType } from './models/language'; import { GramData, Grammeme, ReferenceType } from './models/language';
import { CstClass, CstType, ExpressionStatus, IConstituenta, IRSForm } from './models/rsform'; import { CstClass, CstType, ExpressionStatus, IConstituenta, IRSForm } from './models/rsform';
import { import { IArgumentInfo, ISyntaxTreeNode, ParsingStatus, RSErrorType, TokenID } from './models/rslang';
IArgumentInfo,
IRSErrorDescription,
ISyntaxTreeNode,
ParsingStatus,
RSErrorType,
TokenID
} from './models/rslang';
import { CstMatchMode, DependencyMode } from './stores/cstSearch'; import { CstMatchMode, DependencyMode } from './stores/cstSearch';
import { GraphColoring } from './stores/termGraph'; import { GraphColoring } from './stores/termGraph';

View File

@ -56,9 +56,9 @@ export interface TermForm {
} }
/** /**
* Represents Constituenta basic persistent data. * Represents Constituenta.
*/ */
export interface IConstituentaMeta { export interface IConstituenta {
id: number; id: number;
alias: string; alias: string;
convention: string; convention: string;
@ -69,19 +69,7 @@ export interface IConstituentaMeta {
term_raw: string; term_raw: string;
term_resolved: string; term_resolved: string;
term_forms: TermForm[]; term_forms: TermForm[];
}
/**
* Represents target {@link IConstituenta}.
*/
export interface ITargetCst {
target: number;
}
/**
* Represents Constituenta.
*/
export interface IConstituenta extends IConstituentaMeta {
parse: { parse: {
status: ParsingStatus; status: ParsingStatus;
valueClass: ValueClass; valueClass: ValueClass;
@ -127,7 +115,10 @@ export interface IConstituenta extends IConstituentaMeta {
/** /**
* Represents {@link IConstituenta} reference. * Represents {@link IConstituenta} reference.
*/ */
export interface IConstituentaReference extends Pick<IConstituenta, 'id' | 'schema'> {} export interface IConstituentaReference {
id: number;
schema: number;
}
/** /**
* Represents Constituenta list. * Represents Constituenta list.
@ -183,12 +174,3 @@ export interface IRSForm extends ILibraryItemVersioned {
cstByAlias: Map<string, IConstituenta>; cstByAlias: Map<string, IConstituenta>;
cstByID: Map<number, IConstituenta>; cstByID: Map<number, IConstituenta>;
} }
/**
* Represents single substitution for binary synthesis table.
*/
export interface IBinarySubstitution {
leftCst: IConstituenta;
rightCst: IConstituenta;
deleteRight: boolean;
}

View File

@ -34,16 +34,6 @@ export enum ParsingStatus {
INCORRECT = 'incorrect' INCORRECT = 'incorrect'
} }
/**
* Represents parsing error description.
*/
export interface IRSErrorDescription {
errorType: RSErrorType;
position: number;
isCritical: boolean;
params: string[];
}
/** /**
* Represents AST node. * Represents AST node.
*/ */
@ -86,21 +76,6 @@ export interface IArgumentValue extends IArgumentInfo {
value?: string; value?: string;
} }
/**
* Represents results of expression parse in RSLang.
*/
export interface IExpressionParse {
parseResult: boolean;
prefixLen: number;
syntax: Syntax;
typification: string;
valueClass: ValueClass;
errors: IRSErrorDescription[];
astText: string;
ast: SyntaxTree;
args: IArgumentInfo[];
}
/** /**
* Represents RSLang token types. * Represents RSLang token types.
*/ */

View File

@ -7,8 +7,10 @@ import { Tree } from '@lezer/common';
import { cursorNode } from '@/utils/codemirror'; import { cursorNode } from '@/utils/codemirror';
import { PARAMETER } from '@/utils/constants'; import { PARAMETER } from '@/utils/constants';
import { IRSErrorDescription } from '../backend/types';
import { CstType } from './rsform'; import { CstType } from './rsform';
import { AliasMapping, IArgumentValue, IRSErrorDescription, RSErrorClass, RSErrorType, SyntaxTree } from './rslang'; import { AliasMapping, IArgumentValue, RSErrorClass, RSErrorType, SyntaxTree } from './rslang';
// cspell:disable // cspell:disable
const LOCALS_REGEXP = /[_a-zα-ω][a-zα-ω]*\d*/g; const LOCALS_REGEXP = /[_a-zα-ω][a-zα-ω]*\d*/g;

View File

@ -16,14 +16,14 @@ import { useDialogsStore } from '@/stores/dialogs';
import { useModificationStore } from '@/stores/modification'; import { useModificationStore } from '@/stores/modification';
import { errorMsg } from '@/utils/labels'; import { errorMsg } from '@/utils/labels';
import { ICstUpdateDTO, schemaCstUpdate } from '../../../backend/types'; import { ICstUpdateDTO, IExpressionParseDTO, schemaCstUpdate } from '../../../backend/types';
import { useCstUpdate } from '../../../backend/useCstUpdate'; import { useCstUpdate } from '../../../backend/useCstUpdate';
import { useMutatingRSForm } from '../../../backend/useMutatingRSForm'; import { useMutatingRSForm } from '../../../backend/useMutatingRSForm';
import { RefsInput } from '../../../components/RefsInput'; import { RefsInput } from '../../../components/RefsInput';
import { labelCstTypification, labelTypification } from '../../../labels'; import { labelCstTypification, labelTypification } from '../../../labels';
import { CstType, IConstituenta, IRSForm } from '../../../models/rsform'; import { CstType, IConstituenta, IRSForm } from '../../../models/rsform';
import { isBaseSet, isBasicConcept, isFunctional } from '../../../models/rsformAPI'; import { isBaseSet, isBasicConcept, isFunctional } from '../../../models/rsformAPI';
import { IExpressionParse, ParsingStatus } from '../../../models/rslang'; import { ParsingStatus } from '../../../models/rslang';
import EditorRSExpression from '../EditorRSExpression'; import EditorRSExpression from '../EditorRSExpression';
interface FormConstituentaProps { interface FormConstituentaProps {
@ -50,7 +50,7 @@ function FormConstituenta({ disabled, id, toggleReset, schema, activeCst, onOpen
formState: { isDirty } formState: { isDirty }
} = useForm<ICstUpdateDTO>({ resolver: zodResolver(schemaCstUpdate) }); } = useForm<ICstUpdateDTO>({ resolver: zodResolver(schemaCstUpdate) });
const [localParse, setLocalParse] = useState<IExpressionParse | undefined>(undefined); const [localParse, setLocalParse] = useState<IExpressionParseDTO | undefined>(undefined);
const typification = useMemo( const typification = useMemo(
() => () =>

View File

@ -56,7 +56,7 @@ function ToolbarConstituenta({
const isProcessing = useMutatingRSForm(); const isProcessing = useMutatingRSForm();
function viewPredecessor(target: number) { function viewPredecessor(target: number) {
void findPredecessor({ target: target }).then(reference => void findPredecessor(target).then(reference =>
router.push( router.push(
urls.schema_props({ urls.schema_props({
id: reference.schema, id: reference.schema,

View File

@ -5,6 +5,7 @@ import { toast } from 'react-toastify';
import { ReactCodeMirrorRef } from '@uiw/react-codemirror'; import { ReactCodeMirrorRef } from '@uiw/react-codemirror';
import { BadgeHelp, HelpTopic } from '@/features/help'; import { BadgeHelp, HelpTopic } from '@/features/help';
import { IExpressionParseDTO } from '@/features/rsform/backend/types';
import { DataCallback } from '@/backend/apiTransport'; import { DataCallback } from '@/backend/apiTransport';
import { Overlay } from '@/components/Container'; import { Overlay } from '@/components/Container';
@ -13,7 +14,7 @@ import { useDialogsStore } from '@/stores/dialogs';
import { usePreferencesStore } from '@/stores/preferences'; import { usePreferencesStore } from '@/stores/preferences';
import { errorMsg } from '@/utils/labels'; import { errorMsg } from '@/utils/labels';
import { ICheckConstituentaDTO } from '../../../backend/types'; import { ICheckConstituentaDTO, IRSErrorDescription } from '../../../backend/types';
import { useCheckConstituenta } from '../../../backend/useCheckConstituenta'; import { useCheckConstituenta } from '../../../backend/useCheckConstituenta';
import { useMutatingRSForm } from '../../../backend/useMutatingRSForm'; import { useMutatingRSForm } from '../../../backend/useMutatingRSForm';
import RSInput from '../../../components/RSInput'; import RSInput from '../../../components/RSInput';
@ -21,7 +22,7 @@ import { parser as rslangParser } from '../../../components/RSInput/rslang/parse
import { RSTextWrapper } from '../../../components/RSInput/textEditing'; import { RSTextWrapper } from '../../../components/RSInput/textEditing';
import { IConstituenta } from '../../../models/rsform'; import { IConstituenta } from '../../../models/rsform';
import { getDefinitionPrefix } from '../../../models/rsformAPI'; import { getDefinitionPrefix } from '../../../models/rsformAPI';
import { IExpressionParse, IRSErrorDescription, TokenID } from '../../../models/rslang'; import { TokenID } from '../../../models/rslang';
import { transformAST } from '../../../models/rslangAPI'; import { transformAST } from '../../../models/rslangAPI';
import { useRSEdit } from '../RSEditContext'; import { useRSEdit } from '../RSEditContext';
@ -42,7 +43,7 @@ interface EditorRSExpressionProps {
disabled?: boolean; disabled?: boolean;
toggleReset?: boolean; toggleReset?: boolean;
onChangeLocalParse: (typification: IExpressionParse | undefined) => void; onChangeLocalParse: (typification: IExpressionParseDTO | undefined) => void;
onOpenEdit?: (cstID: number) => void; onOpenEdit?: (cstID: number) => void;
onShowTypeGraph: (event: CProps.EventMouse) => void; onShowTypeGraph: (event: CProps.EventMouse) => void;
} }
@ -62,7 +63,7 @@ function EditorRSExpression({
const [isModified, setIsModified] = useState(false); const [isModified, setIsModified] = useState(false);
const rsInput = useRef<ReactCodeMirrorRef>(null); const rsInput = useRef<ReactCodeMirrorRef>(null);
const [parseData, setParseData] = useState<IExpressionParse | undefined>(undefined); const [parseData, setParseData] = useState<IExpressionParseDTO | undefined>(undefined);
const isProcessing = useMutatingRSForm(); const isProcessing = useMutatingRSForm();
const showControls = usePreferencesStore(state => state.showExpressionControls); const showControls = usePreferencesStore(state => state.showExpressionControls);
@ -70,7 +71,11 @@ function EditorRSExpression({
const { checkConstituenta: checkInternal, isPending } = useCheckConstituenta(); const { checkConstituenta: checkInternal, isPending } = useCheckConstituenta();
function checkConstituenta(expression: string, activeCst: IConstituenta, onSuccess?: DataCallback<IExpressionParse>) { function checkConstituenta(
expression: string,
activeCst: IConstituenta,
onSuccess?: DataCallback<IExpressionParseDTO>
) {
const data: ICheckConstituentaDTO = { const data: ICheckConstituentaDTO = {
definition_formal: expression, definition_formal: expression,
alias: activeCst.alias, alias: activeCst.alias,
@ -92,7 +97,7 @@ function EditorRSExpression({
setIsModified(newValue !== activeCst.definition_formal); setIsModified(newValue !== activeCst.definition_formal);
} }
function handleCheckExpression(callback?: (parse: IExpressionParse) => void) { function handleCheckExpression(callback?: (parse: IExpressionParseDTO) => void) {
checkConstituenta(value, activeCst, parse => { checkConstituenta(value, activeCst, parse => {
onChangeLocalParse(parse); onChangeLocalParse(parse);
if (parse.errors.length > 0) { if (parse.errors.length > 0) {

View File

@ -1,9 +1,9 @@
import { IExpressionParseDTO, IRSErrorDescription } from '../../../backend/types';
import { describeRSError } from '../../../labels'; import { describeRSError } from '../../../labels';
import { IExpressionParse, IRSErrorDescription } from '../../../models/rslang';
import { getRSErrorPrefix } from '../../../models/rslangAPI'; import { getRSErrorPrefix } from '../../../models/rslangAPI';
interface ParsingResultProps { interface ParsingResultProps {
data: IExpressionParse | undefined; data: IExpressionParseDTO | undefined;
disabled?: boolean; disabled?: boolean;
isOpen: boolean; isOpen: boolean;
onShowError: (error: IRSErrorDescription) => void; onShowError: (error: IRSErrorDescription) => void;

View File

@ -8,16 +8,17 @@ import { APP_COLORS } from '@/styling/colors';
import { globals } from '@/utils/constants'; import { globals } from '@/utils/constants';
import { prepareTooltip } from '@/utils/utils'; import { prepareTooltip } from '@/utils/utils';
import { IExpressionParseDTO } from '../../../backend/types';
import { colorStatusBar } from '../../../colors'; import { colorStatusBar } from '../../../colors';
import { labelExpressionStatus } from '../../../labels'; import { labelExpressionStatus } from '../../../labels';
import { ExpressionStatus, IConstituenta } from '../../../models/rsform'; import { ExpressionStatus, IConstituenta } from '../../../models/rsform';
import { inferStatus } from '../../../models/rsformAPI'; import { inferStatus } from '../../../models/rsformAPI';
import { IExpressionParse, ParsingStatus } from '../../../models/rslang'; import { ParsingStatus } from '../../../models/rslang';
interface StatusBarProps { interface StatusBarProps {
processing?: boolean; processing?: boolean;
isModified?: boolean; isModified?: boolean;
parseData?: IExpressionParse; parseData?: IExpressionParseDTO;
activeCst: IConstituenta; activeCst: IConstituenta;
onAnalyze: () => void; onAnalyze: () => void;
} }

View File

@ -14,11 +14,11 @@ import { PARAMETER, prefixes } from '@/utils/constants';
import { promptText } from '@/utils/labels'; import { promptText } from '@/utils/labels';
import { promptUnsaved } from '@/utils/utils'; import { promptUnsaved } from '@/utils/utils';
import { ICstCreateDTO } from '../../backend/types'; import { IConstituentaBasicsDTO, ICstCreateDTO } from '../../backend/types';
import { useCstCreate } from '../../backend/useCstCreate'; import { useCstCreate } from '../../backend/useCstCreate';
import { useCstMove } from '../../backend/useCstMove'; import { useCstMove } from '../../backend/useCstMove';
import { useRSFormSuspense } from '../../backend/useRSForm'; import { useRSFormSuspense } from '../../backend/useRSForm';
import { CstType, IConstituenta, IConstituentaMeta, IRSForm } from '../../models/rsform'; import { CstType, IConstituenta, IRSForm } from '../../models/rsform';
import { generateAlias } from '../../models/rsformAPI'; import { generateAlias } from '../../models/rsformAPI';
export enum RSTabID { export enum RSTabID {
@ -177,7 +177,7 @@ export const RSEditState = ({
}); });
} }
function onCreateCst(newCst: IConstituentaMeta) { function onCreateCst(newCst: IConstituentaBasicsDTO) {
setSelected([newCst.id]); setSelected([newCst.id]);
navigateRSForm({ tab: activeTab, activeID: newCst.id }); navigateRSForm({ tab: activeTab, activeID: newCst.id });
if (activeTab === RSTabID.CST_LIST) { if (activeTab === RSTabID.CST_LIST) {

View File

@ -141,7 +141,8 @@ export const errorMsg = {
invalidLocation: 'Некорректный формат пути', invalidLocation: 'Некорректный формат пути',
versionTaken: 'Версия с таким шифром уже существует', versionTaken: 'Версия с таким шифром уже существует',
emptySubstitutions: 'Выберите хотя бы одно отождествление', emptySubstitutions: 'Выберите хотя бы одно отождествление',
aliasInvalid: 'Введите незанятое имя, соответствующее типу' aliasInvalid: 'Введите незанятое имя, соответствующее типу',
invalidResponse: 'Некорректный ответ сервера'
}; };
/** /**