Implement UI for ProduceStructure

This commit is contained in:
IRBorisov 2024-03-15 12:34:41 +03:00
parent 7d7016cc67
commit 156c58568e
7 changed files with 116 additions and 10 deletions

View File

@ -1,11 +1,12 @@
# Frontend Developer guidelines
Styling conventions
- static > conditional static > props. All dynamic styling should go in styles props
- dimensions = rectangle + outer layout
<details>
<summary>clsx className groupind and order</summary>
<summary>clsx className grouping and order</summary>
<pre>
- layer: z-position
- outer layout: fixed bottom-1/2 left-0 -translate-x-1/2
@ -18,4 +19,4 @@ Styling conventions
- behavior modifiers: select-none disabled:cursor-not-allowed
- transitions:
</pre>
</details>
</details>

View File

@ -1,9 +1,12 @@
import axios, { type AxiosError } from 'axios';
import clsx from 'clsx';
import { urls } from '@/utils/constants';
import { isResponseHtml } from '@/utils/utils';
import AnimateFade from './AnimateFade';
import PrettyJson from './ui/PrettyJSON';
import TextURL from './ui/TextURL';
export type ErrorData = string | Error | AxiosError | undefined;
@ -50,7 +53,21 @@ function DescribeError({ error }: { error: ErrorData }) {
function InfoError({ error }: InfoErrorProps) {
return (
<AnimateFade className='px-3 py-2 min-w-[25rem] w-full text-sm font-semibold select-text clr-text-red'>
<AnimateFade
className={clsx(
'min-w-[25rem] w-full',
'px-3 py-2 flex flex-col',
'clr-text-red',
'text-sm font-semibold',
'select-text'
)}
>
<p className='clr-text-default font-normal'>
Пожалуйста сделайте скриншот и отправьте вместе с описанием ситуации на почту{' '}
<TextURL href={urls.mail_portal} text='portal@acconcept.ru' />
<br />
Для продолжения работы перезагрузите страницу
</p>
<DescribeError error={error} />
</AnimateFade>
);

View File

@ -7,9 +7,11 @@ import useRSFormDetails from '@/hooks/useRSFormDetails';
import { ILibraryItem, IVersionData } from '@/models/library';
import { ILibraryUpdateData } from '@/models/library';
import {
EntityID,
IConstituentaList,
IConstituentaMeta,
ICstCreateData,
ICstID,
ICstMovetoData,
ICstRenameData,
ICstSubstituteData,
@ -26,6 +28,7 @@ import {
patchDeleteConstituenta,
patchLibraryItem,
patchMoveConstituenta,
patchProduceStructure,
patchRenameConstituenta,
patchResetAliases,
patchSubstituteConstituenta,
@ -61,6 +64,7 @@ interface IRSFormContext {
upload: (data: IRSFormUploadData, callback: () => void) => void;
resetAliases: (callback: () => void) => void;
produceStructure: (data: ICstID, callback?: DataCallback<EntityID[]>) => void;
cstCreate: (data: ICstCreateData, callback?: DataCallback<IConstituentaMeta>) => void;
cstRename: (data: ICstRenameData, callback?: DataCallback<IConstituentaMeta>) => void;
@ -260,6 +264,24 @@ export const RSFormState = ({ schemaID, versionID, children }: RSFormStateProps)
[schemaID, setError, schema, library, user, setSchema]
);
const produceStructure = useCallback(
(data: ICstID, callback?: DataCallback<EntityID[]>) => {
setError(undefined);
patchProduceStructure(schemaID, {
data: data,
showError: true,
setLoading: setProcessing,
onError: setError,
onSuccess: newData => {
setSchema(newData.schema);
library.localUpdateTimestamp(newData.schema.id);
if (callback) callback(newData.cst_list);
}
});
},
[setError, setSchema, library, schemaID]
);
const download = useCallback(
(callback: DataCallback<Blob>) => {
setError(undefined);
@ -459,6 +481,7 @@ export const RSFormState = ({ schemaID, versionID, children }: RSFormStateProps)
upload,
claim,
resetAliases,
produceStructure,
subscribe,
unsubscribe,
cstUpdate,

View File

@ -77,6 +77,11 @@ export interface IConstituentaMeta {
term_forms: TermForm[];
}
/**
* Represents id for {@link IConstituenta}.
*/
export interface ICstID extends Pick<IConstituentaMeta, 'id'> {}
/**
* Represents Constituenta.
*/
@ -97,7 +102,7 @@ export interface IConstituenta extends IConstituentaMeta {
* Represents Constituenta list.
*/
export interface IConstituentaList {
items: number[];
items: EntityID[];
}
/**
@ -152,6 +157,14 @@ export interface ICstCreatedResponse {
schema: IRSFormData;
}
/**
* Represents data response when creating producing structure of {@link IConstituenta}.
*/
export interface IProduceStructureResponse {
cst_list: EntityID[];
schema: IRSFormData;
}
/**
* Represents {@link IRSForm} statistics.
*/

View File

@ -28,9 +28,11 @@ import { IVersionData } from '@/models/library';
import { UserAccessMode } from '@/models/miscellaneous';
import {
CstType,
EntityID,
IConstituenta,
IConstituentaMeta,
ICstCreateData,
ICstID,
ICstMovetoData,
ICstRenameData,
ICstSubstituteData,
@ -46,6 +48,7 @@ interface IRSEditContext {
isMutable: boolean;
isContentEditable: boolean;
isProcessing: boolean;
canProduceStructure: boolean;
viewVersion: (version?: number) => void;
@ -65,6 +68,7 @@ interface IRSEditContext {
toggleSubscribe: () => void;
download: () => void;
reindex: () => void;
produceStructure: () => void;
substitute: () => void;
createVersion: () => void;
@ -81,13 +85,13 @@ export const useRSEdit = () => {
};
interface RSEditStateProps {
selected: number[];
selected: EntityID[];
isModified: boolean;
setSelected: React.Dispatch<React.SetStateAction<number[]>>;
setSelected: React.Dispatch<React.SetStateAction<EntityID[]>>;
activeCst?: IConstituenta;
onCreateCst?: (newCst: IConstituentaMeta) => void;
onDeleteCst?: (newActive?: number) => void;
onDeleteCst?: (newActive?: EntityID) => void;
children: React.ReactNode;
}
@ -130,7 +134,7 @@ export const RSEditState = ({
const [renameInitialData, setRenameInitialData] = useState<ICstRenameData>();
const [showRenameCst, setShowRenameCst] = useState(false);
const [insertCstID, setInsertCstID] = useState<number | undefined>(undefined);
const [insertCstID, setInsertCstID] = useState<EntityID | undefined>(undefined);
const [showTemplates, setShowTemplates] = useState(false);
useLayoutEffect(
@ -188,7 +192,7 @@ export const RSEditState = ({
);
const handleDeleteCst = useCallback(
(deleted: number[]) => {
(deleted: EntityID[]) => {
if (!model.schema) {
return;
}
@ -370,6 +374,30 @@ export const RSEditState = ({
const reindex = useCallback(() => model.resetAliases(() => toast.success('Имена конституент обновлены')), [model]);
const canProduceStructure = useMemo(() => {
return (
!!activeCst &&
!!activeCst.parse.typification &&
activeCst.cst_type !== CstType.BASE &&
activeCst.cst_type !== CstType.CONSTANT
);
}, [activeCst]);
const produceStructure = useCallback(() => {
if (!activeCst) {
return;
}
const data: ICstID = {
id: activeCst.id
};
model.produceStructure(data, cstList => {
toast.success(`Добавлены конституенты: ${cstList.length}`);
if (cstList.length !== 0) {
setSelected(cstList);
}
});
}, [activeCst, setSelected, model]);
const promptTemplate = useCallback(() => {
setInsertCstID(activeCst?.id);
setShowTemplates(true);
@ -431,6 +459,7 @@ export const RSEditState = ({
isMutable,
isContentEditable,
isProcessing: model.processing,
canProduceStructure,
viewVersion,
@ -450,6 +479,7 @@ export const RSEditState = ({
share,
toggleSubscribe,
reindex,
produceStructure,
substitute,
createVersion: () => setShowCreateVersion(true),

View File

@ -13,7 +13,7 @@ import {
BiUpload
} from 'react-icons/bi';
import { FiEdit } from 'react-icons/fi';
import { LuAlertTriangle, LuArchive, LuCrown, LuGlasses, LuReplace } from 'react-icons/lu';
import { LuAlertTriangle, LuArchive, LuCrown, LuGlasses, LuNetwork, LuReplace } from 'react-icons/lu';
import { VscLibrary } from 'react-icons/vsc';
import Button from '@/components/ui/Button';
@ -90,6 +90,11 @@ function RSTabsMenu({ onDestroy }: RSTabsMenuProps) {
controller.promptTemplate();
}
function handleProduceStructure() {
editMenu.hide();
controller.produceStructure();
}
function handleChangeMode(newMode: UserAccessMode) {
accessMenu.hide();
setMode(newMode);
@ -203,6 +208,13 @@ function RSTabsMenu({ onDestroy }: RSTabsMenuProps) {
icon={<BiDiamond size='1rem' className='icon-green' />}
onClick={handleTemplates}
/>
<DropdownButton
disabled={!controller.isContentEditable || !controller.canProduceStructure}
text='Порождение структуры'
title='Раскрыть структуру типизации выделенной конституенты'
icon={<LuNetwork size='1rem' className='icon-primary' />}
onClick={handleProduceStructure}
/>
<DropdownButton
disabled={!controller.isContentEditable}
text='Отождествление'

View File

@ -27,10 +27,12 @@ import {
IConstituentaMeta,
ICstCreateData,
ICstCreatedResponse,
ICstID,
ICstMovetoData,
ICstRenameData,
ICstSubstituteData,
ICstUpdateData,
IProduceStructureResponse,
IRSFormCreateData,
IRSFormData,
IRSFormUploadData,
@ -323,6 +325,14 @@ export function patchRenameConstituenta(schema: string, request: FrontExchange<I
});
}
export function patchProduceStructure(schema: string, request: FrontExchange<ICstID, IProduceStructureResponse>) {
AxiosPatch({
title: `Producing structure constituenta id=${request.data.id} for schema id=${schema}`,
endpoint: `/api/rsforms/${schema}/cst-produce-structure`,
request: request
});
}
export function patchSubstituteConstituenta(schema: string, request: FrontExchange<ICstSubstituteData, IRSFormData>) {
AxiosPatch({
title: `Substitution for constituenta id=${request.data.original} for schema id=${schema}`,