mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-26 13:00:39 +03:00
Implement UI for ProduceStructure
This commit is contained in:
parent
7d7016cc67
commit
156c58568e
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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='Отождествление'
|
||||
|
|
|
@ -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}`,
|
||||
|
|
Loading…
Reference in New Issue
Block a user