F: Implement schema checks for backend + small fixes

This commit is contained in:
Ivan 2025-02-18 23:38:33 +03:00
parent a34af217eb
commit cf3db3aa72
32 changed files with 311 additions and 305 deletions

View File

@ -27,7 +27,6 @@ function LoginPage() {
register, register,
handleSubmit, handleSubmit,
clearErrors, clearErrors,
resetField,
formState: { errors } formState: { errors }
} = useForm({ } = useForm({
resolver: zodResolver(schemaUserLogin), resolver: zodResolver(schemaUserLogin),
@ -39,7 +38,6 @@ function LoginPage() {
function onSubmit(data: IUserLoginDTO) { function onSubmit(data: IUserLoginDTO) {
return login(data).then(() => { return login(data).then(() => {
resetField('password');
if (router.canBack()) { if (router.canBack()) {
router.back(); router.back();
} else { } else {

View File

@ -1,6 +1,11 @@
import { queryOptions } from '@tanstack/react-query'; import { queryOptions } from '@tanstack/react-query';
import { IRSFormDTO } from '@/features/rsform/backend/types'; import {
IRSFormDTO,
IVersionCreatedResponse,
schemaRSForm,
schemaVersionCreatedResponse
} from '@/features/rsform/backend/types';
import { axiosDelete, axiosGet, axiosPatch, axiosPost } from '@/backend/apiTransport'; import { axiosDelete, axiosGet, axiosPatch, axiosPost } from '@/backend/apiTransport';
import { DELAYS, KEYS } from '@/backend/configuration'; import { DELAYS, KEYS } from '@/backend/configuration';
@ -13,10 +18,12 @@ import {
ILibraryItem, ILibraryItem,
IRenameLocationDTO, IRenameLocationDTO,
IUpdateLibraryItemDTO, IUpdateLibraryItemDTO,
IVersionCreatedResponse,
IVersionCreateDTO, IVersionCreateDTO,
IVersionInfo, IVersionInfo,
IVersionUpdateDTO IVersionUpdateDTO,
schemaLibraryItem,
schemaLibraryItemArray,
schemaVersionInfo
} from './types'; } from './types';
export const libraryApi = { export const libraryApi = {
@ -29,6 +36,7 @@ export const libraryApi = {
staleTime: DELAYS.staleMedium, staleTime: DELAYS.staleMedium,
queryFn: meta => queryFn: meta =>
axiosGet<ILibraryItem[]>({ axiosGet<ILibraryItem[]>({
schema: schemaLibraryItemArray,
endpoint: isAdmin ? '/api/library/all' : '/api/library/active', endpoint: isAdmin ? '/api/library/all' : '/api/library/active',
options: { signal: meta.signal } options: { signal: meta.signal }
}) })
@ -39,6 +47,7 @@ export const libraryApi = {
staleTime: DELAYS.staleMedium, staleTime: DELAYS.staleMedium,
queryFn: meta => queryFn: meta =>
axiosGet<ILibraryItem[]>({ axiosGet<ILibraryItem[]>({
schema: schemaLibraryItemArray,
endpoint: '/api/library/templates', endpoint: '/api/library/templates',
options: { signal: meta.signal } options: { signal: meta.signal }
}) })
@ -46,6 +55,7 @@ export const libraryApi = {
createItem: (data: ICreateLibraryItemDTO) => createItem: (data: ICreateLibraryItemDTO) =>
axiosPost<ICreateLibraryItemDTO, ILibraryItem>({ axiosPost<ICreateLibraryItemDTO, ILibraryItem>({
schema: schemaLibraryItem,
endpoint: !data.file ? '/api/library' : '/api/rsforms/create-detailed', endpoint: !data.file ? '/api/library' : '/api/rsforms/create-detailed',
request: { request: {
data: data, data: data,
@ -61,6 +71,7 @@ export const libraryApi = {
}), }),
updateItem: (data: IUpdateLibraryItemDTO) => updateItem: (data: IUpdateLibraryItemDTO) =>
axiosPatch<IUpdateLibraryItemDTO, ILibraryItem>({ axiosPatch<IUpdateLibraryItemDTO, ILibraryItem>({
schema: schemaLibraryItem,
endpoint: `/api/library/${data.id}`, endpoint: `/api/library/${data.id}`,
request: { request: {
data: data, data: data,
@ -109,6 +120,7 @@ export const libraryApi = {
}), }),
cloneItem: (data: ICloneLibraryItemDTO) => cloneItem: (data: ICloneLibraryItemDTO) =>
axiosPost<ICloneLibraryItemDTO, IRSFormDTO>({ axiosPost<ICloneLibraryItemDTO, IRSFormDTO>({
schema: schemaRSForm,
endpoint: `/api/library/${data.id}/clone`, endpoint: `/api/library/${data.id}/clone`,
request: { request: {
data: data, data: data,
@ -126,6 +138,7 @@ export const libraryApi = {
versionCreate: ({ itemID, data }: { itemID: number; data: IVersionCreateDTO }) => versionCreate: ({ itemID, data }: { itemID: number; data: IVersionCreateDTO }) =>
axiosPost<IVersionCreateDTO, IVersionCreatedResponse>({ axiosPost<IVersionCreateDTO, IVersionCreatedResponse>({
schema: schemaVersionCreatedResponse,
endpoint: `/api/library/${itemID}/create-version`, endpoint: `/api/library/${itemID}/create-version`,
request: { request: {
data: data, data: data,
@ -134,6 +147,7 @@ export const libraryApi = {
}), }),
versionRestore: ({ versionID }: { versionID: number }) => versionRestore: ({ versionID }: { versionID: number }) =>
axiosPatch<undefined, IRSFormDTO>({ axiosPatch<undefined, IRSFormDTO>({
schema: schemaRSForm,
endpoint: `/api/versions/${versionID}/restore`, endpoint: `/api/versions/${versionID}/restore`,
request: { request: {
successMessage: infoMsg.versionRestored successMessage: infoMsg.versionRestored
@ -141,6 +155,7 @@ export const libraryApi = {
}), }),
versionUpdate: (data: { itemID: number; version: IVersionUpdateDTO }) => versionUpdate: (data: { itemID: number; version: IVersionUpdateDTO }) =>
axiosPatch<IVersionUpdateDTO, IVersionInfo>({ axiosPatch<IVersionUpdateDTO, IVersionInfo>({
schema: schemaVersionInfo,
endpoint: `/api/versions/${data.version.id}`, endpoint: `/api/versions/${data.version.id}`,
request: { request: {
data: data.version, data: data.version,

View File

@ -1,7 +1,5 @@
import { z } from 'zod'; import { z } from 'zod';
import { IRSFormDTO } from '@/features/rsform/backend/types';
import { errorMsg } from '@/utils/labels'; import { errorMsg } from '@/utils/labels';
import { validateLocation } from '../models/libraryAPI'; import { validateLocation } from '../models/libraryAPI';
@ -19,34 +17,15 @@ export enum AccessPolicy {
PRIVATE = 'private' PRIVATE = 'private'
} }
/** /** Represents library item common data typical for all item types. */
* Represents library item common data typical for all item types. export type ILibraryItem = z.infer<typeof schemaLibraryItem>;
*/
export interface ILibraryItem {
id: number;
item_type: LibraryItemType;
title: string;
alias: string;
comment: string;
visible: boolean;
read_only: boolean;
location: string;
access_policy: AccessPolicy;
time_create: string;
time_update: string;
owner: number | null;
}
/** /** Represents {@link ILibraryItem} data loaded for both OSS and RSForm. */
* Represents {@link ILibraryItem} constant data loaded for both OSS and RSForm.
*/
export interface ILibraryItemData extends ILibraryItem { export interface ILibraryItemData extends ILibraryItem {
editors: number[]; editors: number[];
} }
/** /** Represents update data for renaming Location. */
* Represents update data for renaming Location.
*/
export interface IRenameLocationDTO { export interface IRenameLocationDTO {
target: string; target: string;
new_location: string; new_location: string;
@ -61,62 +40,52 @@ export type ICloneLibraryItemDTO = z.infer<typeof schemaCloneLibraryItem>;
/** Represents data, used for creating {@link IRSForm}. */ /** Represents data, used for creating {@link IRSForm}. */
export type ICreateLibraryItemDTO = z.infer<typeof schemaCreateLibraryItem>; export type ICreateLibraryItemDTO = z.infer<typeof schemaCreateLibraryItem>;
/** /** Represents update data for editing {@link ILibraryItem}. */
* 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<typeof schemaUpdateLibraryItem>; export type IUpdateLibraryItemDTO = z.infer<typeof schemaUpdateLibraryItem>;
/** /** Create version metadata in persistent storage. */
* 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<typeof schemaVersionCreate>; export type IVersionCreateDTO = z.infer<typeof schemaVersionCreate>;
/**
* 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. */ /** Represents version data, intended to update version metadata in persistent storage. */
export type IVersionUpdateDTO = z.infer<typeof schemaVersionUpdate>; export type IVersionUpdateDTO = z.infer<typeof schemaVersionUpdate>;
// ======= SCHEMAS ========= // ======= SCHEMAS =========
/** Represents data, used for cloning {@link IRSForm}. */
export const schemaCloneLibraryItem = z.object({ export const schemaLibraryItem = z.object({
id: z.number(), id: z.coerce.number(),
item_type: z.nativeEnum(LibraryItemType), item_type: z.nativeEnum(LibraryItemType),
title: z.string().nonempty(errorMsg.requiredField), title: z.string(),
alias: z.string().nonempty(errorMsg.requiredField), alias: z.string().nonempty(),
comment: z.string(), comment: z.string(),
visible: z.boolean(), visible: z.boolean(),
read_only: z.boolean(), read_only: z.boolean(),
location: z.string().refine(data => validateLocation(data), { message: errorMsg.invalidLocation }), location: z.string(),
access_policy: z.nativeEnum(AccessPolicy), access_policy: z.nativeEnum(AccessPolicy),
time_create: z.string(),
time_update: z.string(),
owner: z.coerce.number().nullable()
});
export const schemaLibraryItemArray = z.array(schemaLibraryItem);
export const schemaCloneLibraryItem = schemaLibraryItem
.pick({
id: true,
item_type: true,
title: true,
alias: true,
comment: true,
visible: true,
read_only: true,
location: true,
access_policy: true
})
.extend({
title: z.string().nonempty(errorMsg.requiredField),
alias: z.string().nonempty(errorMsg.requiredField),
location: z.string().refine(data => validateLocation(data), { message: errorMsg.invalidLocation }),
items: z.array(z.number()).optional() items: z.array(z.number()).optional()
}); });
@ -143,6 +112,16 @@ export const schemaCreateLibraryItem = z
message: errorMsg.requiredField message: errorMsg.requiredField
}); });
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()
});
export const schemaVersionInfo = z.object({ export const schemaVersionInfo = z.object({
id: z.coerce.number(), id: z.coerce.number(),
version: z.string(), version: z.string(),
@ -155,3 +134,9 @@ export const schemaVersionUpdate = z.object({
version: z.string().nonempty(errorMsg.requiredField), version: z.string().nonempty(errorMsg.requiredField),
description: z.string() description: z.string()
}); });
export const schemaVersionCreate = z.object({
version: z.string(),
description: z.string(),
items: z.array(z.number()).optional()
});

View File

@ -6,9 +6,9 @@ import { Dropdown, DropdownButton, useDropdown } from '@/components/Dropdown';
import { IconPrivate, IconProtected, IconPublic } from '@/components/Icons'; import { IconPrivate, IconProtected, IconPublic } from '@/components/Icons';
import { CProps } from '@/components/props'; import { CProps } from '@/components/props';
import { prefixes } from '@/utils/constants'; import { prefixes } from '@/utils/constants';
import { describeAccessPolicy, labelAccessPolicy } from '@/utils/labels';
import { AccessPolicy } from '../backend/types'; import { AccessPolicy } from '../backend/types';
import { describeAccessPolicy, labelAccessPolicy } from '../labels';
interface SelectAccessPolicyProps extends CProps.Styling { interface SelectAccessPolicyProps extends CProps.Styling {
value: AccessPolicy; value: AccessPolicy;

View File

@ -6,9 +6,9 @@ import { Dropdown, DropdownButton, useDropdown } from '@/components/Dropdown';
import { IconOSS, IconRSForm } from '@/components/Icons'; import { IconOSS, IconRSForm } from '@/components/Icons';
import { CProps } from '@/components/props'; import { CProps } from '@/components/props';
import { prefixes } from '@/utils/constants'; import { prefixes } from '@/utils/constants';
import { describeLibraryItemType, labelLibraryItemType } from '@/utils/labels';
import { LibraryItemType } from '../backend/types'; import { LibraryItemType } from '../backend/types';
import { describeLibraryItemType, labelLibraryItemType } from '../labels';
interface SelectItemTypeProps extends CProps.Styling { interface SelectItemTypeProps extends CProps.Styling {
value: LibraryItemType; value: LibraryItemType;

View File

@ -94,7 +94,7 @@ function DlgEditVersions() {
selected={versionID} selected={versionID}
/> />
<form className='flex' onSubmit={event => void handleSubmit(onUpdate)(event)}> <form className='flex items-center ' onSubmit={event => void handleSubmit(onUpdate)(event)}>
<TextInput <TextInput
id='dlg_version' id='dlg_version'
{...register('version')} {...register('version')}
@ -103,7 +103,7 @@ function DlgEditVersions() {
className='w-[16rem] mr-3' className='w-[16rem] mr-3'
error={formErrors.version} error={formErrors.version}
/> />
<div className='cc-icons'> <div className='cc-icons h-fit'>
<MiniButton <MiniButton
type='submit' type='submit'
title={isValid ? 'Сохранить изменения' : errorMsg.versionTaken} title={isValid ? 'Сохранить изменения' : errorMsg.versionTaken}

View File

@ -1,3 +1,4 @@
import { AccessPolicy, LibraryItemType } from './backend/types';
import { FolderNode } from './models/FolderTree'; import { FolderNode } from './models/FolderTree';
import { LocationHead } from './models/library'; import { LocationHead } from './models/library';
import { validateLocation } from './models/libraryAPI'; import { validateLocation } from './models/libraryAPI';
@ -45,3 +46,52 @@ export function labelFolderNode(node: FolderNode): string {
export function describeFolderNode(node: FolderNode): string { export function describeFolderNode(node: FolderNode): string {
return `${node.filesInside} | ${node.filesTotal}`; return `${node.filesInside} | ${node.filesTotal}`;
} }
/**
* Retrieves label for {@link AccessPolicy}.
*/
export function labelAccessPolicy(policy: AccessPolicy): string {
// prettier-ignore
switch (policy) {
case AccessPolicy.PRIVATE: return 'Личный';
case AccessPolicy.PROTECTED: return 'Защищенный';
case AccessPolicy.PUBLIC: return 'Открытый';
}
}
/**
* Retrieves description for {@link AccessPolicy}.
*/
export function describeAccessPolicy(policy: AccessPolicy): string {
// prettier-ignore
switch (policy) {
case AccessPolicy.PRIVATE:
return 'Доступ только для владельца';
case AccessPolicy.PROTECTED:
return 'Доступ для владельца и редакторов';
case AccessPolicy.PUBLIC:
return 'Открытый доступ';
}
}
/**
* Retrieves label for {@link LibraryItemType}.
*/
export function labelLibraryItemType(itemType: LibraryItemType): string {
// prettier-ignore
switch (itemType) {
case LibraryItemType.RSFORM: return 'КС';
case LibraryItemType.OSS: return 'ОСС';
}
}
/**
* Retrieves description for {@link LibraryItemType}.
*/
export function describeLibraryItemType(itemType: LibraryItemType): string {
// prettier-ignore
switch (itemType) {
case LibraryItemType.RSFORM: return 'Концептуальная схема';
case LibraryItemType.OSS: return 'Операционная схема синтеза';
}
}

View File

@ -2,7 +2,7 @@
* Module: Models for LibraryItem. * Module: Models for LibraryItem.
*/ */
import { ILibraryItemData, IVersionInfo, LibraryItemType } from '../backend/types'; import { LibraryItemType } from '../backend/types';
/** /**
* Represents valid location headers. * Represents valid location headers.
@ -24,14 +24,6 @@ export interface ILibraryItemReference {
alias: string; alias: string;
} }
/**
* Represents {@link ILibraryItem} extended data with versions.
*/
export interface ILibraryItemVersioned extends ILibraryItemData {
version?: number;
versions: IVersionInfo[];
}
/** /**
* Represents Library filter parameters. * Represents Library filter parameters.
*/ */

View File

@ -6,28 +6,28 @@ import { ILibraryItem } from '@/features/library/backend/types';
import { Graph } from '@/models/Graph'; import { Graph } from '@/models/Graph';
import { IOperationSchema, IOperationSchemaStats } from '../models/oss'; import { IOperation, IOperationSchema, IOperationSchemaStats } from '../models/oss';
import { IOperation, IOperationSchemaDTO, OperationType } from './types'; import { IOperationSchemaDTO, OperationType } from './types';
/** /**
* Loads data into an {@link IOperationSchema} based on {@link IOperationSchemaDTO}. * Loads data into an {@link IOperationSchema} based on {@link IOperationSchemaDTO}.
* *
*/ */
export class OssLoader { export class OssLoader {
private oss: IOperationSchemaDTO; private oss: IOperationSchema;
private graph: Graph = new Graph(); private graph: Graph = new Graph();
private operationByID = new Map<number, IOperation>(); private operationByID = new Map<number, IOperation>();
private schemaIDs: number[] = []; private schemaIDs: number[] = [];
private items: ILibraryItem[]; private items: ILibraryItem[];
constructor(input: IOperationSchemaDTO, items: ILibraryItem[]) { constructor(input: IOperationSchemaDTO, items: ILibraryItem[]) {
this.oss = input; this.oss = input as unknown as IOperationSchema;
this.items = items; this.items = items;
} }
produceOSS(): IOperationSchema { produceOSS(): IOperationSchema {
const result = this.oss as IOperationSchema; const result = this.oss;
this.prepareLookups(); this.prepareLookups();
this.createGraph(); this.createGraph();
this.extractSchemas(); this.extractSchemas();
@ -42,7 +42,7 @@ export class OssLoader {
private prepareLookups() { private prepareLookups() {
this.oss.items.forEach(operation => { this.oss.items.forEach(operation => {
this.operationByID.set(operation.id, operation as IOperation); this.operationByID.set(operation.id, operation);
this.graph.addNode(operation.id); this.graph.addNode(operation.id);
}); });
} }

View File

@ -17,7 +17,10 @@ import {
IOperationPosition, IOperationPosition,
IOperationSchemaDTO, IOperationSchemaDTO,
IOperationUpdateDTO, IOperationUpdateDTO,
ITargetOperation ITargetOperation,
schemaConstituentaReference,
schemaOperationCreatedResponse,
schemaOperationSchema
} from './types'; } from './types';
export const ossApi = { export const ossApi = {
@ -31,6 +34,7 @@ export const ossApi = {
!itemID !itemID
? undefined ? undefined
: axiosGet<IOperationSchemaDTO>({ : axiosGet<IOperationSchemaDTO>({
schema: schemaOperationSchema,
endpoint: `/api/oss/${itemID}/details`, endpoint: `/api/oss/${itemID}/details`,
options: { signal: meta.signal } options: { signal: meta.signal }
}) })
@ -56,6 +60,7 @@ export const ossApi = {
operationCreate: ({ itemID, data }: { itemID: number; data: IOperationCreateDTO }) => operationCreate: ({ itemID, data }: { itemID: number; data: IOperationCreateDTO }) =>
axiosPost<IOperationCreateDTO, IOperationCreatedResponse>({ axiosPost<IOperationCreateDTO, IOperationCreatedResponse>({
schema: schemaOperationCreatedResponse,
endpoint: `/api/oss/${itemID}/create-operation`, endpoint: `/api/oss/${itemID}/create-operation`,
request: { request: {
data: data, data: data,
@ -64,6 +69,7 @@ export const ossApi = {
}), }),
operationDelete: ({ itemID, data }: { itemID: number; data: IOperationDeleteDTO }) => operationDelete: ({ itemID, data }: { itemID: number; data: IOperationDeleteDTO }) =>
axiosPatch<IOperationDeleteDTO, IOperationSchemaDTO>({ axiosPatch<IOperationDeleteDTO, IOperationSchemaDTO>({
schema: schemaOperationSchema,
endpoint: `/api/oss/${itemID}/delete-operation`, endpoint: `/api/oss/${itemID}/delete-operation`,
request: { request: {
data: data, data: data,
@ -80,6 +86,7 @@ export const ossApi = {
}), }),
inputUpdate: ({ itemID, data }: { itemID: number; data: IInputUpdateDTO }) => inputUpdate: ({ itemID, data }: { itemID: number; data: IInputUpdateDTO }) =>
axiosPatch<IInputUpdateDTO, IOperationSchemaDTO>({ axiosPatch<IInputUpdateDTO, IOperationSchemaDTO>({
schema: schemaOperationSchema,
endpoint: `/api/oss/${itemID}/set-input`, endpoint: `/api/oss/${itemID}/set-input`,
request: { request: {
data: data, data: data,
@ -88,6 +95,7 @@ export const ossApi = {
}), }),
operationUpdate: ({ itemID, data }: { itemID: number; data: IOperationUpdateDTO }) => operationUpdate: ({ itemID, data }: { itemID: number; data: IOperationUpdateDTO }) =>
axiosPatch<IOperationUpdateDTO, IOperationSchemaDTO>({ axiosPatch<IOperationUpdateDTO, IOperationSchemaDTO>({
schema: schemaOperationSchema,
endpoint: `/api/oss/${itemID}/update-operation`, endpoint: `/api/oss/${itemID}/update-operation`,
request: { request: {
data: data, data: data,
@ -96,6 +104,7 @@ export const ossApi = {
}), }),
operationExecute: ({ itemID, data }: { itemID: number; data: ITargetOperation }) => operationExecute: ({ itemID, data }: { itemID: number; data: ITargetOperation }) =>
axiosPost<ITargetOperation, IOperationSchemaDTO>({ axiosPost<ITargetOperation, IOperationSchemaDTO>({
schema: schemaOperationSchema,
endpoint: `/api/oss/${itemID}/execute-operation`, endpoint: `/api/oss/${itemID}/execute-operation`,
request: { request: {
data: data, data: data,
@ -105,6 +114,7 @@ export const ossApi = {
relocateConstituents: (data: ICstRelocateDTO) => relocateConstituents: (data: ICstRelocateDTO) =>
axiosPost<ICstRelocateDTO, IOperationSchemaDTO>({ axiosPost<ICstRelocateDTO, IOperationSchemaDTO>({
schema: schemaOperationSchema,
endpoint: `/api/oss/relocate-constituents`, endpoint: `/api/oss/relocate-constituents`,
request: { request: {
data: data, data: data,
@ -113,6 +123,7 @@ export const ossApi = {
}), }),
getPredecessor: (data: ITargetCst) => getPredecessor: (data: ITargetCst) =>
axiosPost<ITargetCst, IConstituentaReference>({ axiosPost<ITargetCst, IConstituentaReference>({
schema: schemaConstituentaReference,
endpoint: '/api/oss/get-predecessor', endpoint: '/api/oss/get-predecessor',
request: { data: data } request: { data: data }
}) })

View File

@ -1,7 +1,9 @@
import { z } from 'zod'; import { z } from 'zod';
import { ILibraryItem, ILibraryItemData } from '@/features/library/backend/types'; import { schemaLibraryItem } from '@/features/library/backend/types';
import { ICstSubstitute, schemaCstSubstitute } from '@/features/rsform/backend/types'; import { schemaCstSubstitute } from '@/features/rsform/backend/types';
import { errorMsg } from '@/utils/labels';
/** /**
* Represents {@link IOperation} type. * Represents {@link IOperation} type.
@ -11,61 +13,14 @@ export enum OperationType {
SYNTHESIS = 'synthesis' SYNTHESIS = 'synthesis'
} }
/** /** Represents {@link ICstSubstitute} extended data. */
* Represents {@link ICstSubstitute} extended data. export type ICstSubstituteInfo = z.infer<typeof schemaCstSubstituteInfo>;
*/
export interface ICstSubstituteEx extends ICstSubstitute {
operation: number;
original_alias: string;
original_term: string;
substitution_alias: string;
substitution_term: string;
}
/** /** Represents {@link IOperation} data from server. */
* Represents Operation. export type IOperationDTO = z.infer<typeof schemaOperation>;
*/
export interface IOperation {
id: number;
operation_type: OperationType;
oss: number;
alias: string; /** Represents backend data for {@link IOperationSchema}. */
title: string; export type IOperationSchemaDTO = z.infer<typeof schemaOperationSchema>;
comment: string;
position_x: number;
position_y: number;
result: number | null;
is_owned: boolean;
is_consolidation: boolean; // aka 'diamond synthesis'
substitutions: ICstSubstituteEx[];
arguments: number[];
}
/**
* Represents {@link IOperation} Argument.
*/
export interface IArgument {
operation: number;
argument: number;
}
/**
* Represents {@link IOperation} data from server.
*/
export interface IOperationDTO extends Omit<IOperation, 'substitutions' | 'arguments'> {}
/**
* Represents backend data for {@link IOperationSchema}.
*/
export interface IOperationSchemaDTO extends ILibraryItemData {
items: IOperationDTO[];
arguments: IArgument[];
substitutions: ICstSubstituteEx[];
}
/** Represents {@link IOperation} position. */ /** Represents {@link IOperation} position. */
export type IOperationPosition = z.infer<typeof schemaOperationPosition>; export type IOperationPosition = z.infer<typeof schemaOperationPosition>;
@ -73,14 +28,8 @@ export type IOperationPosition = z.infer<typeof schemaOperationPosition>;
/** Represents {@link IOperation} data, used in creation process. */ /** Represents {@link IOperation} data, used in creation process. */
export type IOperationCreateDTO = z.infer<typeof schemaOperationCreate>; export type IOperationCreateDTO = z.infer<typeof schemaOperationCreate>;
/** /** Represents data response when creating {@link IOperation}. */
* Represents data response when creating {@link IOperation}. export type IOperationCreatedResponse = z.infer<typeof schemaOperationCreatedResponse>;
*/
export interface IOperationCreatedResponse {
new_operation: IOperationDTO;
oss: IOperationSchemaDTO;
}
/** /**
* Represents target {@link IOperation}. * Represents target {@link IOperation}.
*/ */
@ -92,13 +41,8 @@ export interface ITargetOperation {
/** Represents {@link IOperation} data, used in destruction process. */ /** Represents {@link IOperation} data, used in destruction process. */
export type IOperationDeleteDTO = z.infer<typeof schemaOperationDelete>; export type IOperationDeleteDTO = z.infer<typeof schemaOperationDelete>;
/** /** Represents data response when creating {@link IRSForm} for Input {@link IOperation}. */
* Represents data response when creating {@link IRSForm} for Input {@link IOperation}. export type IInputCreatedResponse = z.infer<typeof schemaInputCreatedResponse>;
*/
export interface IInputCreatedResponse {
new_schema: ILibraryItem;
oss: IOperationSchemaDTO;
}
/** Represents {@link IOperation} data, used in setInput process. */ /** Represents {@link IOperation} data, used in setInput process. */
export type IInputUpdateDTO = z.infer<typeof schemaInputUpdate>; export type IInputUpdateDTO = z.infer<typeof schemaInputUpdate>;
@ -106,29 +50,49 @@ export type IInputUpdateDTO = z.infer<typeof schemaInputUpdate>;
/** Represents {@link IOperation} data, used in update process. */ /** Represents {@link IOperation} data, used in update process. */
export type IOperationUpdateDTO = z.infer<typeof schemaOperationUpdate>; export type IOperationUpdateDTO = z.infer<typeof schemaOperationUpdate>;
/** /** Represents data, used relocating {@link IConstituenta}s between {@link ILibraryItem}s. */
* 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<typeof schemaCstRelocate>; export type ICstRelocateDTO = z.infer<typeof schemaCstRelocate>;
/** /** Represents {@link IConstituenta} reference. */
* Represents {@link IConstituenta} reference. export type IConstituentaReference = z.infer<typeof schemaConstituentaReference>;
*/
export interface IConstituentaReference {
id: number;
schema: number;
}
// ====== Schemas ====== // ====== Schemas ======
export const schemaOperation = z.object({
id: z.number(),
operation_type: z.nativeEnum(OperationType),
oss: z.number(),
alias: z.string(),
title: z.string(),
comment: z.string(),
position_x: z.number(),
position_y: z.number(),
result: z.number().nullable()
});
export const schemaCstSubstituteInfo = schemaCstSubstitute.extend({
operation: z.number(),
original_alias: z.string(),
original_term: z.string(),
substitution_alias: z.string(),
substitution_term: z.string()
});
export const schemaOperationSchema = schemaLibraryItem.extend({
editors: z.number().array(),
items: z.array(schemaOperation),
arguments: z
.object({
operation: z.number(),
argument: z.number()
})
.array(),
substitutions: z.array(schemaCstSubstituteInfo)
});
export const schemaOperationPosition = z.object({ export const schemaOperationPosition = z.object({
id: z.number(), id: z.number(),
position_x: z.number(), position_x: z.number(),
@ -150,6 +114,11 @@ export const schemaOperationCreate = z.object({
create_schema: z.boolean() create_schema: z.boolean()
}); });
export const schemaOperationCreatedResponse = z.object({
new_operation: schemaOperation,
oss: schemaOperationSchema
});
export const schemaOperationDelete = z.object({ export const schemaOperationDelete = z.object({
target: z.number(), target: z.number(),
positions: z.array(schemaOperationPosition), positions: z.array(schemaOperationPosition),
@ -163,14 +132,29 @@ export const schemaInputUpdate = z.object({
input: z.number().nullable() input: z.number().nullable()
}); });
export const schemaInputCreatedResponse = z.object({
new_schema: schemaLibraryItem,
oss: schemaOperationSchema
});
export const schemaOperationUpdate = z.object({ export const schemaOperationUpdate = z.object({
target: z.number(), target: z.number(),
positions: z.array(schemaOperationPosition), positions: z.array(schemaOperationPosition),
item_data: z.object({ item_data: z.object({
alias: z.string().nonempty(), alias: z.string().nonempty(errorMsg.requiredField),
title: z.string(), title: z.string(),
comment: z.string() comment: z.string()
}), }),
arguments: z.array(z.number()), arguments: z.array(z.number()),
substitutions: z.array(schemaCstSubstitute) substitutions: z.array(schemaCstSubstitute)
}); });
export const schemaCstRelocate = z.object({
destination: z.number().nullable(),
items: z.array(z.number()).refine(data => data.length > 0)
});
export const schemaConstituentaReference = z.object({
id: z.number(),
schema: z.number()
});

View File

@ -9,7 +9,7 @@ import { IconMoveDown, IconMoveUp, IconRemove } from '@/components/Icons';
import { CProps } from '@/components/props'; import { CProps } from '@/components/props';
import { NoData } from '@/components/View'; import { NoData } from '@/components/View';
import { IOperation } from '../backend/types'; import { IOperation } from '../models/oss';
import SelectOperation from './SelectOperation'; import SelectOperation from './SelectOperation';

View File

@ -5,7 +5,7 @@ import clsx from 'clsx';
import { SelectSingle } from '@/components/Input'; import { SelectSingle } from '@/components/Input';
import { CProps } from '@/components/props'; import { CProps } from '@/components/props';
import { IOperation } from '../backend/types'; import { IOperation } from '../models/oss';
import { matchOperation } from '../models/ossAPI'; import { matchOperation } from '../models/ossAPI';
interface SelectOperationProps extends CProps.Styling { interface SelectOperationProps extends CProps.Styling {

View File

@ -6,7 +6,7 @@ import { Tooltip } from '@/components/Container';
import DataTable from '@/components/DataTable'; import DataTable from '@/components/DataTable';
import { IconPageRight } from '@/components/Icons'; import { IconPageRight } from '@/components/Icons';
import { ICstSubstituteEx, OperationType } from '../backend/types'; import { ICstSubstituteInfo, OperationType } from '../backend/types';
import { labelOperationType } from '../labels'; import { labelOperationType } from '../labels';
import { OssNodeInternal } from '../models/ossLayout'; import { OssNodeInternal } from '../models/ossLayout';
@ -15,7 +15,7 @@ interface TooltipOperationProps {
anchor: string; anchor: string;
} }
const columnHelper = createColumnHelper<ICstSubstituteEx>(); const columnHelper = createColumnHelper<ICstSubstituteInfo>();
function TooltipOperation({ node, anchor }: TooltipOperationProps) { function TooltipOperation({ node, anchor }: TooltipOperationProps) {
const columns = [ const columns = [

View File

@ -12,9 +12,9 @@ import { Label } from '@/components/Input';
import { ModalForm } from '@/components/Modal'; import { ModalForm } from '@/components/Modal';
import { useDialogsStore } from '@/stores/dialogs'; import { useDialogsStore } from '@/stores/dialogs';
import { IInputUpdateDTO, IOperation, IOperationPosition, schemaInputUpdate } from '../backend/types'; import { IInputUpdateDTO, IOperationPosition, schemaInputUpdate } from '../backend/types';
import { useInputUpdate } from '../backend/useInputUpdate'; import { useInputUpdate } from '../backend/useInputUpdate';
import { IOperationSchema } from '../models/oss'; import { IOperation, IOperationSchema } from '../models/oss';
import { sortItemsForOSS } from '../models/ossAPI'; import { sortItemsForOSS } from '../models/ossAPI';
export interface DlgChangeInputSchemaProps { export interface DlgChangeInputSchemaProps {

View File

@ -10,9 +10,9 @@ import { Checkbox, TextInput } from '@/components/Input';
import { ModalForm } from '@/components/Modal'; import { ModalForm } from '@/components/Modal';
import { useDialogsStore } from '@/stores/dialogs'; import { useDialogsStore } from '@/stores/dialogs';
import { IOperation, IOperationDeleteDTO, IOperationPosition, schemaOperationDelete } from '../backend/types'; import { IOperationDeleteDTO, IOperationPosition, schemaOperationDelete } from '../backend/types';
import { useOperationDelete } from '../backend/useOperationDelete'; import { useOperationDelete } from '../backend/useOperationDelete';
import { IOperationSchema } from '../models/oss'; import { IOperation, IOperationSchema } from '../models/oss';
export interface DlgDeleteOperationProps { export interface DlgDeleteOperationProps {
oss: IOperationSchema; oss: IOperationSchema;

View File

@ -1,7 +1,7 @@
'use client'; 'use client';
import { Suspense, useState } from 'react'; import { Suspense, useState } from 'react';
import { FormProvider, useForm, useWatch } from 'react-hook-form'; import { FormProvider, useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod'; import { zodResolver } from '@hookform/resolvers/zod';
import clsx from 'clsx'; import clsx from 'clsx';
@ -12,15 +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 { import { IOperationPosition, IOperationUpdateDTO, OperationType, schemaOperationUpdate } from '../../backend/types';
IOperation,
IOperationPosition,
IOperationUpdateDTO,
OperationType,
schemaOperationUpdate
} from '../../backend/types';
import { useOperationUpdate } from '../../backend/useOperationUpdate'; import { useOperationUpdate } from '../../backend/useOperationUpdate';
import { IOperationSchema } from '../../models/oss'; import { IOperation, IOperationSchema } from '../../models/oss';
import TabArguments from './TabArguments'; import TabArguments from './TabArguments';
import TabOperation from './TabOperation'; import TabOperation from './TabOperation';
@ -45,6 +39,7 @@ function DlgEditOperation() {
const methods = useForm<IOperationUpdateDTO>({ const methods = useForm<IOperationUpdateDTO>({
resolver: zodResolver(schemaOperationUpdate), resolver: zodResolver(schemaOperationUpdate),
defaultValues: { defaultValues: {
target: target.id,
item_data: { item_data: {
alias: target.alias, alias: target.alias,
title: target.alias, title: target.alias,
@ -56,10 +51,9 @@ function DlgEditOperation() {
substitution: sub.substitution substitution: sub.substitution
})), })),
positions: positions positions: positions
} },
mode: 'onChange'
}); });
const alias = useWatch({ control: methods.control, name: 'item_data.alias' });
const canSubmit = alias !== '';
const [activeTab, setActiveTab] = useState(TabID.CARD); const [activeTab, setActiveTab] = useState(TabID.CARD);
@ -71,7 +65,7 @@ function DlgEditOperation() {
<ModalForm <ModalForm
header='Редактирование операции' header='Редактирование операции'
submitText='Сохранить' submitText='Сохранить'
canSubmit={canSubmit} canSubmit={methods.formState.isValid}
onSubmit={event => void methods.handleSubmit(onSubmit)(event)} onSubmit={event => void methods.handleSubmit(onSubmit)(event)}
className='w-[40rem] px-6 h-[32rem]' className='w-[40rem] px-6 h-[32rem]'
helpTopic={HelpTopic.UI_SUBSTITUTIONS} helpTopic={HelpTopic.UI_SUBSTITUTIONS}

View File

@ -15,10 +15,10 @@ import { Loader } from '@/components/Loader';
import { ModalForm } from '@/components/Modal'; import { ModalForm } from '@/components/Modal';
import { useDialogsStore } from '@/stores/dialogs'; import { useDialogsStore } from '@/stores/dialogs';
import { ICstRelocateDTO, IOperation, IOperationPosition, schemaCstRelocate } from '../backend/types'; import { ICstRelocateDTO, IOperationPosition, schemaCstRelocate } from '../backend/types';
import { useRelocateConstituents } from '../backend/useRelocateConstituents'; import { useRelocateConstituents } from '../backend/useRelocateConstituents';
import { useUpdatePositions } from '../backend/useUpdatePositions'; import { useUpdatePositions } from '../backend/useUpdatePositions';
import { IOperationSchema } from '../models/oss'; import { IOperation, IOperationSchema } from '../models/oss';
import { getRelocateCandidates } from '../models/ossAPI'; import { getRelocateCandidates } from '../models/ossAPI';
export interface DlgRelocateConstituentsProps { export interface DlgRelocateConstituentsProps {
@ -37,7 +37,6 @@ function DlgRelocateConstituents() {
handleSubmit, handleSubmit,
control, control,
setValue, setValue,
resetField,
formState: { isValid } formState: { isValid }
} = useForm<ICstRelocateDTO>({ } = useForm<ICstRelocateDTO>({
resolver: zodResolver(schemaCstRelocate), resolver: zodResolver(schemaCstRelocate),
@ -78,22 +77,22 @@ function DlgRelocateConstituents() {
function toggleDirection() { function toggleDirection() {
setDirectionUp(prev => !prev); setDirectionUp(prev => !prev);
resetField('destination'); setValue('destination', null);
} }
function handleSelectSource(newValue: ILibraryItem | undefined) { function handleSelectSource(newValue: ILibraryItem | undefined) {
setSource(newValue); setSource(newValue);
resetField('destination'); setValue('destination', null);
resetField('items'); setValue('items', []);
} }
function handleSelectDestination(newValue: ILibraryItem | undefined) { function handleSelectDestination(newValue: ILibraryItem | undefined) {
if (newValue) { if (newValue) {
setValue('destination', newValue.id); setValue('destination', newValue.id);
} else { } else {
resetField('destination'); setValue('destination', null);
} }
resetField('items'); setValue('items', []);
} }
function onSubmit(data: ICstRelocateDTO) { function onSubmit(data: ICstRelocateDTO) {
@ -116,7 +115,7 @@ function DlgRelocateConstituents() {
<ModalForm <ModalForm
header='Перенос конституент' header='Перенос конституент'
submitText='Переместить' submitText='Переместить'
canSubmit={isValid} canSubmit={isValid && destinationItem !== undefined}
onSubmit={event => void handleSubmit(onSubmit)(event)} onSubmit={event => void handleSubmit(onSubmit)(event)}
className={clsx('w-[40rem] h-[33rem]', 'py-3 px-6')} className={clsx('w-[40rem] h-[33rem]', 'py-3 px-6')}
helpTopic={HelpTopic.UI_RELOCATE_CST} helpTopic={HelpTopic.UI_RELOCATE_CST}

View File

@ -2,11 +2,19 @@
* Module: Schema of Synthesis Operations. * Module: Schema of Synthesis Operations.
*/ */
import { ILibraryItemData } from '@/features/library/backend/types';
import { Graph } from '@/models/Graph'; import { Graph } from '@/models/Graph';
import { IArgument, ICstSubstituteEx, IOperation } from '../backend/types'; import { ICstSubstituteInfo, IOperationDTO, IOperationSchemaDTO } from '../backend/types';
/**
* Represents Operation.
*/
export interface IOperation extends IOperationDTO {
is_owned: boolean;
is_consolidation: boolean; // aka 'diamond synthesis'
substitutions: ICstSubstituteInfo[];
arguments: number[];
}
/** /**
* Represents {@link IOperationSchema} statistics. * Represents {@link IOperationSchema} statistics.
@ -22,10 +30,8 @@ export interface IOperationSchemaStats {
/** /**
* Represents OperationSchema. * Represents OperationSchema.
*/ */
export interface IOperationSchema extends ILibraryItemData { export interface IOperationSchema extends IOperationSchemaDTO {
items: IOperation[]; items: IOperation[];
arguments: IArgument[];
substitutions: ICstSubstituteEx[];
graph: Graph; graph: Graph;
schemas: number[]; schemas: number[];

View File

@ -18,10 +18,10 @@ import { infoMsg } from '@/utils/labels';
import { TextMatcher } from '@/utils/utils'; import { TextMatcher } from '@/utils/utils';
import { Graph } from '../../../models/Graph'; import { Graph } from '../../../models/Graph';
import { IOperation, IOperationPosition, OperationType } from '../backend/types'; import { IOperationPosition, OperationType } from '../backend/types';
import { describeSubstitutionError } from '../labels'; import { describeSubstitutionError } from '../labels';
import { IOperationSchema, SubstitutionErrorType } from './oss'; import { IOperation, IOperationSchema, SubstitutionErrorType } from './oss';
import { Position2D } from './ossLayout'; import { Position2D } from './ossLayout';
/** /**

View File

@ -3,7 +3,8 @@
*/ */
import { Node } from 'reactflow'; import { Node } from 'reactflow';
import { IOperation } from '../backend/types'; import { IOperation } from './oss';
/** /**
* Represents XY Position. * Represents XY Position.
*/ */

View File

@ -16,8 +16,9 @@ import useClickedOutside from '@/hooks/useClickedOutside';
import { PARAMETER } from '@/utils/constants'; import { PARAMETER } from '@/utils/constants';
import { prepareTooltip } from '@/utils/utils'; import { prepareTooltip } from '@/utils/utils';
import { IOperation, OperationType } from '../../../backend/types'; import { OperationType } from '../../../backend/types';
import { useMutatingOss } from '../../../backend/useMutatingOss'; import { useMutatingOss } from '../../../backend/useMutatingOss';
import { IOperation } from '../../../models/oss';
import { useOssEdit } from '../OssEditContext'; import { useOssEdit } from '../OssEditContext';
export interface ContextMenuData { export interface ContextMenuData {

View File

@ -1,43 +1,26 @@
import { axiosPost } from '@/backend/apiTransport'; import { axiosPost } from '@/backend/apiTransport';
import { KEYS } from '@/backend/configuration'; import { KEYS } from '@/backend/configuration';
/** import { ILexemeResponse, ITextResult, IWordFormDTO, schemaLexemeResponse, schemaTextResult } from './types';
* Represents API result for text output.
*/
export interface ITextResult {
result: string;
}
/**
* Represents wordform data used for backend communication.
*/
export interface IWordFormDTO {
text: string;
grams: string;
}
/**
* Represents lexeme response containing multiple {@link Wordform}s.
*/
export interface ILexemeResponse {
items: IWordFormDTO[];
}
export const cctextApi = { export const cctextApi = {
baseKey: KEYS.cctext, baseKey: KEYS.cctext,
inflectText: (data: IWordFormDTO) => inflectText: (data: IWordFormDTO) =>
axiosPost<IWordFormDTO, ITextResult>({ axiosPost<IWordFormDTO, ITextResult>({
schema: schemaTextResult,
endpoint: '/api/cctext/inflect', endpoint: '/api/cctext/inflect',
request: { data: data } request: { data: data }
}), }),
parseText: (data: { text: string }) => parseText: (data: { text: string }) =>
axiosPost<{ text: string }, ITextResult>({ axiosPost<{ text: string }, ITextResult>({
schema: schemaTextResult,
endpoint: '/api/cctext/parse', endpoint: '/api/cctext/parse',
request: { data: data } request: { data: data }
}), }),
generateLexeme: (data: { text: string }) => generateLexeme: (data: { text: string }) =>
axiosPost<{ text: string }, ILexemeResponse>({ axiosPost<{ text: string }, ILexemeResponse>({
schema: schemaLexemeResponse,
endpoint: '/api/cctext/generate-lexeme', endpoint: '/api/cctext/generate-lexeme',
request: { data: data } request: { data: data }
}) })

View File

@ -0,0 +1,25 @@
import { z } from 'zod';
/** Represents API result for text output. */
export type ITextResult = z.infer<typeof schemaTextResult>;
/** Represents wordform data used for backend communication. */
export type IWordFormDTO = z.infer<typeof schemaWordForm>;
/** Represents lexeme response containing multiple {@link Wordform}s. */
export type ILexemeResponse = z.infer<typeof schemaLexemeResponse>;
// ====== Schemas =========
export const schemaTextResult = z.object({
result: z.string()
});
export const schemaWordForm = z.object({
text: z.string(),
grams: z.string()
});
export const schemaLexemeResponse = z.object({
items: z.array(schemaWordForm)
});

View File

@ -1,6 +1,7 @@
import { useMutation } from '@tanstack/react-query'; import { useMutation } from '@tanstack/react-query';
import { cctextApi, IWordFormDTO } from './api'; import { cctextApi } from './api';
import { IWordFormDTO } from './types';
export const useInflectText = () => { export const useInflectText = () => {
const mutation = useMutation({ const mutation = useMutation({

View File

@ -109,6 +109,9 @@ export type IRSErrorDescription = z.infer<typeof schemaRSErrorDescription>;
/** Represents results of expression parse in RSLang. */ /** Represents results of expression parse in RSLang. */
export type IExpressionParseDTO = z.infer<typeof schemaExpressionParse>; export type IExpressionParseDTO = z.infer<typeof schemaExpressionParse>;
/** Represents data response when creating {@link IVersionInfo}. */
export type IVersionCreatedResponse = z.infer<typeof schemaVersionCreatedResponse>;
/** Represents RSLang token types. */ /** Represents RSLang token types. */
export enum TokenID { export enum TokenID {
// Global, local IDs and literals // Global, local IDs and literals
@ -322,6 +325,11 @@ export const schemaRSForm = z.object({
oss: z.array(z.object({ id: z.coerce.number(), alias: z.string() })) oss: z.array(z.object({ id: z.coerce.number(), alias: z.string() }))
}); });
export const schemaVersionCreatedResponse = z.object({
version: z.number(),
schema: schemaRSForm
});
export const schemaCstCreate = schemaConstituentaBasics export const schemaCstCreate = schemaConstituentaBasics
.pick({ .pick({
cst_type: true, cst_type: true,

View File

@ -62,7 +62,7 @@ export function ToolbarRSFormCard({ controller, onSubmit }: ToolbarRSFormCardPro
/> />
) : null} ) : null}
<MiniButton <MiniButton
titleHtml={tooltipText.shareItem(controller.schema.access_policy)} titleHtml={tooltipText.shareItem(controller.schema.access_policy === AccessPolicy.PUBLIC)}
icon={<IconShare size='1.25rem' className='icon-primary' />} icon={<IconShare size='1.25rem' className='icon-primary' />}
onClick={sharePage} onClick={sharePage}
disabled={controller.schema.access_policy !== AccessPolicy.PUBLIC} disabled={controller.schema.access_policy !== AccessPolicy.PUBLIC}

View File

@ -2,7 +2,8 @@
* Module: Models for formal representation for systems of concepts. * Module: Models for formal representation for systems of concepts.
*/ */
import { ILibraryItemReference, ILibraryItemVersioned } from '@/features/library/models/library'; import { ILibraryItemData, IVersionInfo } from '@/features/library/backend/types';
import { ILibraryItemReference } from '@/features/library/models/library';
import { Graph } from '@/models/Graph'; import { Graph } from '@/models/Graph';
@ -137,7 +138,10 @@ export interface IInheritanceInfo {
/** /**
* Represents formal explication for set of concepts. * Represents formal explication for set of concepts.
*/ */
export interface IRSForm extends ILibraryItemVersioned { export interface IRSForm extends ILibraryItemData {
version?: number;
versions: IVersionInfo[];
items: IConstituenta[]; items: IConstituenta[];
inheritance: IInheritanceInfo[]; inheritance: IInheritanceInfo[];
oss: ILibraryItemReference[]; oss: ILibraryItemReference[];

View File

@ -227,7 +227,7 @@ function MenuRSTabs() {
<Dropdown isOpen={schemaMenu.isOpen}> <Dropdown isOpen={schemaMenu.isOpen}>
<DropdownButton <DropdownButton
text='Поделиться' text='Поделиться'
titleHtml={tooltipText.shareItem(controller.schema.access_policy)} titleHtml={tooltipText.shareItem(controller.schema.access_policy === AccessPolicy.PUBLIC)}
icon={<IconShare size='1rem' className='icon-primary' />} icon={<IconShare size='1rem' className='icon-primary' />}
onClick={handleShare} onClick={handleShare}
disabled={controller.schema.access_policy !== AccessPolicy.PUBLIC} disabled={controller.schema.access_policy !== AccessPolicy.PUBLIC}

View File

@ -14,6 +14,11 @@ export const PARAMETER = {
navigationDuration: 300, // milliseconds navigation duration navigationDuration: 300, // milliseconds navigation duration
navigationPopupDelay: 300, // milliseconds delay for navigation popup navigationPopupDelay: 300, // milliseconds delay for navigation popup
fastAnimation: 200, // milliseconds - duration of fast animation
fadeDuration: 300, // milliseconds - duration of fade animation
dropdownDuration: 200, // milliseconds - duration of dropdown animation
moveDuration: 500, // milliseconds - duration of move animation
ossImageWidth: 1280, // pixels - size of OSS image ossImageWidth: 1280, // pixels - size of OSS image
ossImageHeight: 960, // pixels - size of OSS image ossImageHeight: 960, // pixels - size of OSS image
ossContextMenuWidth: 200, // pixels - width of OSS context menu ossContextMenuWidth: 200, // pixels - width of OSS context menu
@ -23,11 +28,6 @@ export const PARAMETER = {
ossDistanceX: 180, // pixels - insert x-distance between node centers ossDistanceX: 180, // pixels - insert x-distance between node centers
ossDistanceY: 100, // pixels - insert y-distance between node centers ossDistanceY: 100, // pixels - insert y-distance between node centers
fastAnimation: 200, // milliseconds - duration of fast animation
fadeDuration: 300, // milliseconds - duration of fade animation
dropdownDuration: 300, // milliseconds - duration of dropdown animation
moveDuration: 500, // milliseconds - duration of move animation
graphHandleSize: 3, // pixels - size of graph connection handle graphHandleSize: 3, // pixels - size of graph connection handle
graphNodeRadius: 20, // pixels - radius of graph node graphNodeRadius: 20, // pixels - radius of graph node
graphNodePadding: 5, // pixels - padding of graph node graphNodePadding: 5, // pixels - padding of graph node

View File

@ -4,7 +4,6 @@
* Label is a short text used to represent an entity. * Label is a short text used to represent an entity.
* Description is a long description used in tooltips. * Description is a long description used in tooltips.
*/ */
import { AccessPolicy, LibraryItemType } from '@/features/library/backend/types';
import { UserRole } from '@/features/users/stores/role'; import { UserRole } from '@/features/users/stores/role';
/** /**
@ -37,55 +36,6 @@ export function describeAccessMode(mode: UserRole): string {
} }
} }
/**
* Retrieves label for {@link AccessPolicy}.
*/
export function labelAccessPolicy(policy: AccessPolicy): string {
// prettier-ignore
switch (policy) {
case AccessPolicy.PRIVATE: return 'Личный';
case AccessPolicy.PROTECTED: return 'Защищенный';
case AccessPolicy.PUBLIC: return 'Открытый';
}
}
/**
* Retrieves description for {@link AccessPolicy}.
*/
export function describeAccessPolicy(policy: AccessPolicy): string {
// prettier-ignore
switch (policy) {
case AccessPolicy.PRIVATE:
return 'Доступ только для владельца';
case AccessPolicy.PROTECTED:
return 'Доступ для владельца и редакторов';
case AccessPolicy.PUBLIC:
return 'Открытый доступ';
}
}
/**
* Retrieves label for {@link LibraryItemType}.
*/
export function labelLibraryItemType(itemType: LibraryItemType): string {
// prettier-ignore
switch (itemType) {
case LibraryItemType.RSFORM: return 'КС';
case LibraryItemType.OSS: return 'ОСС';
}
}
/**
* Retrieves description for {@link LibraryItemType}.
*/
export function describeLibraryItemType(itemType: LibraryItemType): string {
// prettier-ignore
switch (itemType) {
case LibraryItemType.RSFORM: return 'Концептуальная схема';
case LibraryItemType.OSS: return 'Операционная схема синтеза';
}
}
/** /**
* UI info descriptors. * UI info descriptors.
*/ */
@ -150,8 +100,7 @@ export const errorMsg = {
*/ */
export const tooltipText = { export const tooltipText = {
unsaved: 'Сохраните или отмените изменения', unsaved: 'Сохраните или отмените изменения',
shareItem: (policy?: AccessPolicy) => shareItem: (isPublic: boolean) => (isPublic ? 'Поделиться схемой' : 'Поделиться можно только <br/>открытой схемой')
policy === AccessPolicy.PUBLIC ? 'Поделиться схемой' : 'Поделиться можно только <br/>открытой схемой'
}; };
/** /**