F: Rework DeleteCst and InlineSynthesis dialogs
This commit is contained in:
parent
acf0f4e9f6
commit
ea349c7ecc
|
@ -620,6 +620,8 @@ def inline_synthesis(request: Request) -> HttpResponse:
|
||||||
|
|
||||||
receiver = m.RSForm(serializer.validated_data['receiver'])
|
receiver = m.RSForm(serializer.validated_data['receiver'])
|
||||||
items = cast(list[m.Constituenta], serializer.validated_data['items'])
|
items = cast(list[m.Constituenta], serializer.validated_data['items'])
|
||||||
|
if len(items) == 0:
|
||||||
|
items = list(m.RSForm(serializer.validated_data['source']).constituents().order_by('order'))
|
||||||
|
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
new_items = receiver.insert_copy(items)
|
new_items = receiver.insert_copy(items)
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { Label } from '@/components/Input';
|
||||||
import { ModalForm } from '@/components/Modal';
|
import { ModalForm } from '@/components/Modal';
|
||||||
import { useLibrary } from '@/features/library/backend/useLibrary';
|
import { useLibrary } from '@/features/library/backend/useLibrary';
|
||||||
import { ILibraryItem, LibraryItemType } from '@/features/library/models/library';
|
import { ILibraryItem, LibraryItemType } from '@/features/library/models/library';
|
||||||
import PickSchema from '@/features/rsform/components/PickSchema';
|
import { PickSchema } from '@/features/rsform/components/PickSchema';
|
||||||
import { useDialogsStore } from '@/stores/dialogs';
|
import { useDialogsStore } from '@/stores/dialogs';
|
||||||
|
|
||||||
import { IInputUpdateDTO, IOperationPosition, schemaInputUpdate } from '../backend/api';
|
import { IInputUpdateDTO, IOperationPosition, schemaInputUpdate } from '../backend/api';
|
||||||
|
|
|
@ -8,7 +8,7 @@ import { Checkbox, Label, TextArea, TextInput } from '@/components/Input';
|
||||||
import { useLibrary } from '@/features/library/backend/useLibrary';
|
import { useLibrary } from '@/features/library/backend/useLibrary';
|
||||||
import { ILibraryItem, LibraryItemID, LibraryItemType } from '@/features/library/models/library';
|
import { ILibraryItem, LibraryItemID, LibraryItemType } from '@/features/library/models/library';
|
||||||
import { sortItemsForOSS } from '@/features/oss/models/ossAPI';
|
import { sortItemsForOSS } from '@/features/oss/models/ossAPI';
|
||||||
import PickSchema from '@/features/rsform/components/PickSchema';
|
import { PickSchema } from '@/features/rsform/components/PickSchema';
|
||||||
import { useDialogsStore } from '@/stores/dialogs';
|
import { useDialogsStore } from '@/stores/dialogs';
|
||||||
|
|
||||||
import { IOperationCreateDTO } from '../../backend/api';
|
import { IOperationCreateDTO } from '../../backend/api';
|
||||||
|
|
|
@ -49,7 +49,6 @@ function TabSynthesisOperation() {
|
||||||
<Controller
|
<Controller
|
||||||
name='arguments'
|
name='arguments'
|
||||||
control={control}
|
control={control}
|
||||||
defaultValue={[]}
|
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<PickMultiOperation items={oss.items} value={field.value} onChange={field.onChange} rows={6} />
|
<PickMultiOperation items={oss.items} value={field.value} onChange={field.onChange} rows={6} />
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -29,7 +29,6 @@ function TabArguments() {
|
||||||
<Controller
|
<Controller
|
||||||
name='arguments'
|
name='arguments'
|
||||||
control={control}
|
control={control}
|
||||||
defaultValue={[]}
|
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<>
|
<>
|
||||||
<Label text={`Выбор аргументов: [ ${field.value.length} ]`} />
|
<Label text={`Выбор аргументов: [ ${field.value.length} ]`} />
|
||||||
|
|
|
@ -32,7 +32,6 @@ function TabSynthesis() {
|
||||||
<Controller
|
<Controller
|
||||||
name='substitutions'
|
name='substitutions'
|
||||||
control={control}
|
control={control}
|
||||||
defaultValue={[]}
|
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<PickSubstitutions
|
<PickSubstitutions
|
||||||
schemas={schemas}
|
schemas={schemas}
|
||||||
|
|
|
@ -142,12 +142,17 @@ export type ICstSubstitute = z.infer<typeof schemaCstSubstitute>;
|
||||||
/**
|
/**
|
||||||
* Represents input data for inline synthesis.
|
* Represents input data for inline synthesis.
|
||||||
*/
|
*/
|
||||||
export interface IInlineSynthesisDTO {
|
export const schemaInlineSynthesis = z.object({
|
||||||
receiver: LibraryItemID;
|
receiver: z.number(),
|
||||||
source: LibraryItemID;
|
source: z.number().nullable(),
|
||||||
items: ConstituentaID[];
|
items: z.array(z.number()),
|
||||||
substitutions: ICstSubstitute[];
|
substitutions: z.array(schemaCstSubstitute)
|
||||||
}
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents input data for inline synthesis.
|
||||||
|
*/
|
||||||
|
export type IInlineSynthesisDTO = z.infer<typeof schemaInlineSynthesis>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents {@link IConstituenta} data, used for checking expression.
|
* Represents {@link IConstituenta} data, used for checking expression.
|
||||||
|
@ -260,9 +265,9 @@ export const rsformsApi = {
|
||||||
successMessage: response => infoMsg.addedConstituents(response.cst_list.length)
|
successMessage: response => infoMsg.addedConstituents(response.cst_list.length)
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
inlineSynthesis: ({ itemID, data }: { itemID: LibraryItemID; data: IInlineSynthesisDTO }) =>
|
inlineSynthesis: (data: IInlineSynthesisDTO) =>
|
||||||
axiosPost<IInlineSynthesisDTO, IRSFormDTO>({
|
axiosPatch<IInlineSynthesisDTO, IRSFormDTO>({
|
||||||
endpoint: `/api/rsforms/${itemID}/inline-synthesis`,
|
endpoint: `/api/rsforms/inline-synthesis`,
|
||||||
request: {
|
request: {
|
||||||
data: data,
|
data: data,
|
||||||
successMessage: infoMsg.inlineSynthesisComplete
|
successMessage: infoMsg.inlineSynthesisComplete
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||||
|
|
||||||
import { useUpdateTimestamp } from '@/features/library/backend/useUpdateTimestamp';
|
import { useUpdateTimestamp } from '@/features/library/backend/useUpdateTimestamp';
|
||||||
import { LibraryItemID } from '@/features/library/models/library';
|
|
||||||
import { ossApi } from '@/features/oss/backend/api';
|
import { ossApi } from '@/features/oss/backend/api';
|
||||||
|
|
||||||
import { IInlineSynthesisDTO, rsformsApi } from './api';
|
import { IInlineSynthesisDTO, rsformsApi } from './api';
|
||||||
|
@ -26,6 +25,6 @@ export const useInlineSynthesis = () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
inlineSynthesis: (data: { itemID: LibraryItemID; data: IInlineSynthesisDTO }) => mutation.mutateAsync(data)
|
inlineSynthesis: (data: IInlineSynthesisDTO) => mutation.mutateAsync(data)
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -31,7 +31,7 @@ interface PickSchemaProps extends CProps.Styling {
|
||||||
|
|
||||||
const columnHelper = createColumnHelper<ILibraryItem>();
|
const columnHelper = createColumnHelper<ILibraryItem>();
|
||||||
|
|
||||||
function PickSchema({
|
export function PickSchema({
|
||||||
id,
|
id,
|
||||||
initialFilter = '',
|
initialFilter = '',
|
||||||
rows = 4,
|
rows = 4,
|
||||||
|
@ -157,5 +157,3 @@ function PickSchema({
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default PickSchema;
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ interface PickSubstitutionsProps extends CProps.Styling {
|
||||||
allowSelfSubstitution?: boolean;
|
allowSelfSubstitution?: boolean;
|
||||||
|
|
||||||
schemas: IRSForm[];
|
schemas: IRSForm[];
|
||||||
filter?: (cst: IConstituenta) => boolean;
|
filterCst?: (cst: IConstituenta) => boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const columnHelper = createColumnHelper<IMultiSubstitution>();
|
const columnHelper = createColumnHelper<IMultiSubstitution>();
|
||||||
|
@ -41,7 +41,7 @@ function PickSubstitutions({
|
||||||
suggestions,
|
suggestions,
|
||||||
rows,
|
rows,
|
||||||
schemas,
|
schemas,
|
||||||
filter,
|
filterCst,
|
||||||
allowSelfSubstitution,
|
allowSelfSubstitution,
|
||||||
className,
|
className,
|
||||||
...restProps
|
...restProps
|
||||||
|
@ -225,7 +225,7 @@ function PickSubstitutions({
|
||||||
<SelectConstituenta
|
<SelectConstituenta
|
||||||
noBorder
|
noBorder
|
||||||
items={(leftArgument as IRSForm)?.items.filter(
|
items={(leftArgument as IRSForm)?.items.filter(
|
||||||
cst => !value.find(item => item.original === cst.id) && (!filter || filter(cst))
|
cst => !value.find(item => item.original === cst.id) && (!filterCst || filterCst(cst))
|
||||||
)}
|
)}
|
||||||
value={leftCst}
|
value={leftCst}
|
||||||
onChange={setLeftCst}
|
onChange={setLeftCst}
|
||||||
|
@ -247,7 +247,7 @@ function PickSubstitutions({
|
||||||
title='Добавить в таблицу отождествлений'
|
title='Добавить в таблицу отождествлений'
|
||||||
className='mb-[0.375rem] grow-0'
|
className='mb-[0.375rem] grow-0'
|
||||||
icon={<IconReplace size='1.5rem' className='icon-primary' />}
|
icon={<IconReplace size='1.5rem' className='icon-primary' />}
|
||||||
disabled={!leftCst || !rightCst || leftCst === rightCst}
|
disabled={!leftCst || !rightCst || (leftCst === rightCst && !allowSelfSubstitution)}
|
||||||
onClick={addSubstitution}
|
onClick={addSubstitution}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -263,7 +263,7 @@ function PickSubstitutions({
|
||||||
<SelectConstituenta
|
<SelectConstituenta
|
||||||
noBorder
|
noBorder
|
||||||
items={(rightArgument as IRSForm)?.items.filter(
|
items={(rightArgument as IRSForm)?.items.filter(
|
||||||
cst => !value.find(item => item.original === cst.id) && (!filter || filter(cst))
|
cst => !value.find(item => item.original === cst.id) && (!filterCst || filterCst(cst))
|
||||||
)}
|
)}
|
||||||
value={rightCst}
|
value={rightCst}
|
||||||
onChange={setRightCst}
|
onChange={setRightCst}
|
||||||
|
|
|
@ -8,17 +8,20 @@ import { ModalForm } from '@/components/Modal';
|
||||||
import { useDialogsStore } from '@/stores/dialogs';
|
import { useDialogsStore } from '@/stores/dialogs';
|
||||||
import { prefixes } from '@/utils/constants';
|
import { prefixes } from '@/utils/constants';
|
||||||
|
|
||||||
|
import { useCstDelete } from '../../backend/useCstDelete';
|
||||||
import { ConstituentaID, IRSForm } from '../../models/rsform';
|
import { ConstituentaID, IRSForm } from '../../models/rsform';
|
||||||
import ListConstituents from './ListConstituents';
|
import ListConstituents from './ListConstituents';
|
||||||
|
|
||||||
export interface DlgDeleteCstProps {
|
export interface DlgDeleteCstProps {
|
||||||
schema: IRSForm;
|
schema: IRSForm;
|
||||||
selected: ConstituentaID[];
|
selected: ConstituentaID[];
|
||||||
onDelete: (items: ConstituentaID[]) => void;
|
afterDelete: (initialSchema: IRSForm, deleted: ConstituentaID[]) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
function DlgDeleteCst() {
|
function DlgDeleteCst() {
|
||||||
const { selected, schema, onDelete } = useDialogsStore(state => state.props as DlgDeleteCstProps);
|
const { selected, schema, afterDelete } = useDialogsStore(state => state.props as DlgDeleteCstProps);
|
||||||
|
const { cstDelete } = useCstDelete();
|
||||||
|
|
||||||
const [expandOut, setExpandOut] = useState(false);
|
const [expandOut, setExpandOut] = useState(false);
|
||||||
const expansion: ConstituentaID[] = schema.graph.expandAllOutputs(selected);
|
const expansion: ConstituentaID[] = schema.graph.expandAllOutputs(selected);
|
||||||
const hasInherited = selected.some(
|
const hasInherited = selected.some(
|
||||||
|
@ -27,12 +30,8 @@ function DlgDeleteCst() {
|
||||||
);
|
);
|
||||||
|
|
||||||
function handleSubmit() {
|
function handleSubmit() {
|
||||||
if (expandOut) {
|
const deleted = expandOut ? selected.concat(expansion) : selected;
|
||||||
onDelete(selected.concat(expansion));
|
void cstDelete({ itemID: schema.id, data: { items: deleted } }).then(() => afterDelete(schema, deleted));
|
||||||
} else {
|
|
||||||
onDelete(selected);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,24 +1,25 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { Suspense, useEffect, useState } from 'react';
|
import { Suspense, useState } from 'react';
|
||||||
|
import { FormProvider, useForm, useWatch } from 'react-hook-form';
|
||||||
|
|
||||||
import { Loader } from '@/components/Loader';
|
import { Loader } from '@/components/Loader';
|
||||||
import { ModalForm } from '@/components/Modal';
|
import { ModalForm } from '@/components/Modal';
|
||||||
import { TabLabel, TabList, TabPanel, Tabs } from '@/components/Tabs';
|
import { TabLabel, TabList, TabPanel, Tabs } from '@/components/Tabs';
|
||||||
import { LibraryItemID } from '@/features/library/models/library';
|
|
||||||
import { useRSForm } from '@/features/rsform/backend/useRSForm';
|
|
||||||
import { useDialogsStore } from '@/stores/dialogs';
|
import { useDialogsStore } from '@/stores/dialogs';
|
||||||
|
|
||||||
import { ICstSubstitute, IInlineSynthesisDTO } from '../../backend/api';
|
import { IInlineSynthesisDTO, schemaInlineSynthesis } from '../../backend/api';
|
||||||
import { ConstituentaID, IRSForm } from '../../models/rsform';
|
import { useInlineSynthesis } from '../../backend/useInlineSynthesis';
|
||||||
|
import { IRSForm } from '../../models/rsform';
|
||||||
import TabConstituents from './TabConstituents';
|
import TabConstituents from './TabConstituents';
|
||||||
import TabSource from './TabSource';
|
import TabSource from './TabSource';
|
||||||
import TabSubstitutions from './TabSubstitutions';
|
import TabSubstitutions from './TabSubstitutions';
|
||||||
|
|
||||||
export interface DlgInlineSynthesisProps {
|
export interface DlgInlineSynthesisProps {
|
||||||
receiver: IRSForm;
|
receiver: IRSForm;
|
||||||
onInlineSynthesis: (data: IInlineSynthesisDTO) => void;
|
onSynthesis: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum TabID {
|
export enum TabID {
|
||||||
|
@ -28,40 +29,24 @@ export enum TabID {
|
||||||
}
|
}
|
||||||
|
|
||||||
function DlgInlineSynthesis() {
|
function DlgInlineSynthesis() {
|
||||||
const { receiver, onInlineSynthesis } = useDialogsStore(state => state.props as DlgInlineSynthesisProps);
|
const { receiver, onSynthesis } = useDialogsStore(state => state.props as DlgInlineSynthesisProps);
|
||||||
const [activeTab, setActiveTab] = useState(TabID.SCHEMA);
|
const [activeTab, setActiveTab] = useState(TabID.SCHEMA);
|
||||||
|
const { inlineSynthesis } = useInlineSynthesis();
|
||||||
|
|
||||||
const [sourceID, setSourceID] = useState<LibraryItemID | undefined>(undefined);
|
const methods = useForm<IInlineSynthesisDTO>({
|
||||||
const [selected, setSelected] = useState<ConstituentaID[]>([]);
|
resolver: zodResolver(schemaInlineSynthesis),
|
||||||
const [substitutions, setSubstitutions] = useState<ICstSubstitute[]>([]);
|
defaultValues: {
|
||||||
|
|
||||||
const { schema } = useRSForm({ itemID: sourceID });
|
|
||||||
|
|
||||||
const validated = selected.length > 0;
|
|
||||||
|
|
||||||
function handleSubmit() {
|
|
||||||
if (!sourceID || selected.length === 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
onInlineSynthesis({
|
|
||||||
source: sourceID,
|
|
||||||
receiver: receiver.id,
|
receiver: receiver.id,
|
||||||
items: selected,
|
source: null,
|
||||||
substitutions: substitutions
|
items: [],
|
||||||
|
substitutions: []
|
||||||
|
},
|
||||||
|
mode: 'onChange'
|
||||||
});
|
});
|
||||||
return true;
|
const sourceID = useWatch({ control: methods.control, name: 'source' });
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
function onSubmit(data: IInlineSynthesisDTO) {
|
||||||
if (schema) {
|
return inlineSynthesis(data).then(onSynthesis);
|
||||||
setSelected(schema.items.map(cst => cst.id));
|
|
||||||
}
|
|
||||||
}, [schema, setSelected]);
|
|
||||||
|
|
||||||
function handleSetSource(schemaID: LibraryItemID) {
|
|
||||||
setSourceID(schemaID);
|
|
||||||
setSelected([]);
|
|
||||||
setSubstitutions([]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -69,8 +54,8 @@ function DlgInlineSynthesis() {
|
||||||
header='Импорт концептуальной схем'
|
header='Импорт концептуальной схем'
|
||||||
submitText='Добавить конституенты'
|
submitText='Добавить конституенты'
|
||||||
className='w-[40rem] h-[33rem] px-6'
|
className='w-[40rem] h-[33rem] px-6'
|
||||||
canSubmit={validated}
|
canSubmit={methods.formState.isValid && sourceID !== null}
|
||||||
onSubmit={handleSubmit}
|
onSubmit={event => void methods.handleSubmit(onSubmit)(event)}
|
||||||
>
|
>
|
||||||
<Tabs
|
<Tabs
|
||||||
selectedTabClassName='clr-selected'
|
selectedTabClassName='clr-selected'
|
||||||
|
@ -94,14 +79,15 @@ function DlgInlineSynthesis() {
|
||||||
/>
|
/>
|
||||||
</TabList>
|
</TabList>
|
||||||
|
|
||||||
|
<FormProvider {...methods}>
|
||||||
<TabPanel>
|
<TabPanel>
|
||||||
<TabSource selected={sourceID} setSelected={handleSetSource} receiver={receiver} />
|
<TabSource />
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
|
|
||||||
<TabPanel>
|
<TabPanel>
|
||||||
{!!sourceID ? (
|
{!!sourceID ? (
|
||||||
<Suspense fallback={<Loader />}>
|
<Suspense fallback={<Loader />}>
|
||||||
<TabConstituents itemID={sourceID} selected={selected} setSelected={setSelected} />
|
<TabConstituents />
|
||||||
</Suspense>
|
</Suspense>
|
||||||
) : null}
|
) : null}
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
|
@ -109,16 +95,11 @@ function DlgInlineSynthesis() {
|
||||||
<TabPanel>
|
<TabPanel>
|
||||||
{!!sourceID ? (
|
{!!sourceID ? (
|
||||||
<Suspense fallback={<Loader />}>
|
<Suspense fallback={<Loader />}>
|
||||||
<TabSubstitutions
|
<TabSubstitutions />
|
||||||
sourceID={sourceID}
|
|
||||||
receiver={receiver}
|
|
||||||
selected={selected}
|
|
||||||
substitutions={substitutions}
|
|
||||||
setSubstitutions={setSubstitutions}
|
|
||||||
/>
|
|
||||||
</Suspense>
|
</Suspense>
|
||||||
) : null}
|
) : null}
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
|
</FormProvider>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</ModalForm>
|
</ModalForm>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,22 +1,43 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { LibraryItemID } from '@/features/library/models/library';
|
import { Controller, useFormContext, useWatch } from 'react-hook-form';
|
||||||
|
|
||||||
|
import { IInlineSynthesisDTO } from '../../backend/api';
|
||||||
import { useRSFormSuspense } from '../../backend/useRSForm';
|
import { useRSFormSuspense } from '../../backend/useRSForm';
|
||||||
import PickMultiConstituenta from '../../components/PickMultiConstituenta';
|
import PickMultiConstituenta from '../../components/PickMultiConstituenta';
|
||||||
import { ConstituentaID } from '../../models/rsform';
|
import { ConstituentaID } from '../../models/rsform';
|
||||||
|
|
||||||
interface TabConstituentsProps {
|
function TabConstituents() {
|
||||||
itemID: LibraryItemID;
|
const { setValue, control } = useFormContext<IInlineSynthesisDTO>();
|
||||||
selected: ConstituentaID[];
|
const sourceID = useWatch({ control, name: 'source' });
|
||||||
setSelected: React.Dispatch<React.SetStateAction<ConstituentaID[]>>;
|
const substitutions = useWatch({ control, name: 'substitutions' });
|
||||||
|
|
||||||
|
const { schema } = useRSFormSuspense({ itemID: sourceID! });
|
||||||
|
|
||||||
|
function handleSelectItems(newValue: ConstituentaID[]) {
|
||||||
|
setValue('items', newValue);
|
||||||
|
const newSubstitutions = substitutions.filter(
|
||||||
|
sub => newValue.includes(sub.original) || newValue.includes(sub.substitution)
|
||||||
|
);
|
||||||
|
if (newSubstitutions.length !== substitutions.length) {
|
||||||
|
setValue('substitutions', newSubstitutions);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function TabConstituents({ itemID, selected, setSelected }: TabConstituentsProps) {
|
|
||||||
const { schema } = useRSFormSuspense({ itemID });
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PickMultiConstituenta schema={schema} items={schema.items} rows={13} value={selected} onChange={setSelected} />
|
<Controller
|
||||||
|
name='items'
|
||||||
|
control={control}
|
||||||
|
render={({ field }) => (
|
||||||
|
<PickMultiConstituenta
|
||||||
|
schema={schema}
|
||||||
|
items={schema.items}
|
||||||
|
rows={13}
|
||||||
|
value={field.value}
|
||||||
|
onChange={handleSelectItems}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,33 +1,46 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
|
import { useFormContext, useWatch } from 'react-hook-form';
|
||||||
|
|
||||||
import { TextInput } from '@/components/Input';
|
import { TextInput } from '@/components/Input';
|
||||||
import { useLibrary } from '@/features/library/backend/useLibrary';
|
import { useLibrary } from '@/features/library/backend/useLibrary';
|
||||||
import { LibraryItemID, LibraryItemType } from '@/features/library/models/library';
|
import { LibraryItemID, LibraryItemType } from '@/features/library/models/library';
|
||||||
|
import { useDialogsStore } from '@/stores/dialogs';
|
||||||
|
|
||||||
import PickSchema from '../../components/PickSchema';
|
import { IInlineSynthesisDTO } from '../../backend/api';
|
||||||
import { IRSForm } from '../../models/rsform';
|
import { PickSchema } from '../../components/PickSchema';
|
||||||
import { sortItemsForInlineSynthesis } from '../../models/rsformAPI';
|
import { sortItemsForInlineSynthesis } from '../../models/rsformAPI';
|
||||||
|
import { DlgInlineSynthesisProps } from './DlgInlineSynthesis';
|
||||||
|
|
||||||
interface TabSourceProps {
|
function TabSource() {
|
||||||
selected?: LibraryItemID;
|
const { items: libraryItems } = useLibrary();
|
||||||
setSelected: (newValue: LibraryItemID) => void;
|
const { receiver } = useDialogsStore(state => state.props as DlgInlineSynthesisProps);
|
||||||
receiver: IRSForm;
|
const { setValue, control } = useFormContext<IInlineSynthesisDTO>();
|
||||||
|
const sourceID = useWatch({ control, name: 'source' });
|
||||||
|
|
||||||
|
const selectedInfo = libraryItems.find(item => item.id === sourceID);
|
||||||
|
const sortedItems = sortItemsForInlineSynthesis(receiver, libraryItems);
|
||||||
|
|
||||||
|
function handleSelectSource(newValue: LibraryItemID) {
|
||||||
|
if (newValue === sourceID) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setValue('source', newValue);
|
||||||
|
setValue('items', []);
|
||||||
|
setValue('substitutions', []);
|
||||||
}
|
}
|
||||||
|
|
||||||
function TabSource({ selected, receiver, setSelected }: TabSourceProps) {
|
|
||||||
const { items: libraryItems } = useLibrary();
|
|
||||||
const selectedInfo = libraryItems.find(item => item.id === selected);
|
|
||||||
const sortedItems = sortItemsForInlineSynthesis(receiver, libraryItems);
|
|
||||||
return (
|
return (
|
||||||
<div className='cc-fade-in flex flex-col'>
|
<div className='cc-fade-in flex flex-col'>
|
||||||
<PickSchema
|
<PickSchema
|
||||||
id='dlg_schema_picker' //
|
id='dlg_schema_picker'
|
||||||
items={sortedItems}
|
items={sortedItems}
|
||||||
itemType={LibraryItemType.RSFORM}
|
itemType={LibraryItemType.RSFORM}
|
||||||
rows={14}
|
rows={14}
|
||||||
value={selected ?? null}
|
value={sourceID}
|
||||||
onChange={setSelected}
|
onChange={handleSelectSource}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className='flex items-center gap-6 '>
|
<div className='flex items-center gap-6 '>
|
||||||
<span className='select-none'>Выбрана</span>
|
<span className='select-none'>Выбрана</span>
|
||||||
<TextInput
|
<TextInput
|
||||||
|
|
|
@ -1,32 +1,37 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { LibraryItemID } from '@/features/library/models/library';
|
import { Controller, useFormContext, useWatch } from 'react-hook-form';
|
||||||
|
|
||||||
import { ICstSubstitute } from '../../backend/api';
|
import { useDialogsStore } from '@/stores/dialogs';
|
||||||
|
|
||||||
|
import { IInlineSynthesisDTO } from '../../backend/api';
|
||||||
import { useRSFormSuspense } from '../../backend/useRSForm';
|
import { useRSFormSuspense } from '../../backend/useRSForm';
|
||||||
import PickSubstitutions from '../../components/PickSubstitutions';
|
import PickSubstitutions from '../../components/PickSubstitutions';
|
||||||
import { ConstituentaID, IRSForm } from '../../models/rsform';
|
import { DlgInlineSynthesisProps } from './DlgInlineSynthesis';
|
||||||
|
|
||||||
interface TabSubstitutionsProps {
|
function TabSubstitutions() {
|
||||||
receiver: IRSForm;
|
const { receiver } = useDialogsStore(state => state.props as DlgInlineSynthesisProps);
|
||||||
sourceID: LibraryItemID;
|
const { control } = useFormContext<IInlineSynthesisDTO>();
|
||||||
selected: ConstituentaID[];
|
const sourceID = useWatch({ control, name: 'source' });
|
||||||
|
const selected = useWatch({ control, name: 'items' });
|
||||||
|
|
||||||
substitutions: ICstSubstitute[];
|
const { schema: source } = useRSFormSuspense({ itemID: sourceID! });
|
||||||
setSubstitutions: React.Dispatch<React.SetStateAction<ICstSubstitute[]>>;
|
const selfSubstitution = receiver.id === source.id;
|
||||||
}
|
|
||||||
|
|
||||||
function TabSubstitutions({ sourceID, receiver, selected, substitutions, setSubstitutions }: TabSubstitutionsProps) {
|
|
||||||
const { schema: source } = useRSFormSuspense({ itemID: sourceID });
|
|
||||||
const schemas = [...(source ? [source] : []), ...(receiver ? [receiver] : [])];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<Controller
|
||||||
|
name='substitutions'
|
||||||
|
control={control}
|
||||||
|
render={({ field }) => (
|
||||||
<PickSubstitutions
|
<PickSubstitutions
|
||||||
value={substitutions}
|
value={field.value}
|
||||||
onChange={setSubstitutions}
|
onChange={field.onChange}
|
||||||
|
allowSelfSubstitution={selfSubstitution}
|
||||||
rows={10}
|
rows={10}
|
||||||
schemas={schemas}
|
schemas={selfSubstitution ? [source] : [source, receiver]}
|
||||||
filter={cst => cst.id !== source?.id || selected.includes(cst.id)}
|
filterCst={selected.length === 0 ? undefined : cst => selected.includes(cst.id)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,6 @@ import { describeAccessMode, labelAccessMode, tooltipText } from '@/utils/labels
|
||||||
import { generatePageQR, promptUnsaved, sharePage } from '@/utils/utils';
|
import { generatePageQR, promptUnsaved, sharePage } from '@/utils/utils';
|
||||||
|
|
||||||
import { useDownloadRSForm } from '../../backend/useDownloadRSForm';
|
import { useDownloadRSForm } from '../../backend/useDownloadRSForm';
|
||||||
import { useInlineSynthesis } from '../../backend/useInlineSynthesis';
|
|
||||||
import { useMutatingRSForm } from '../../backend/useMutatingRSForm';
|
import { useMutatingRSForm } from '../../backend/useMutatingRSForm';
|
||||||
import { useProduceStructure } from '../../backend/useProduceStructure';
|
import { useProduceStructure } from '../../backend/useProduceStructure';
|
||||||
import { useResetAliases } from '../../backend/useResetAliases';
|
import { useResetAliases } from '../../backend/useResetAliases';
|
||||||
|
@ -64,7 +63,6 @@ function MenuRSTabs() {
|
||||||
const { resetAliases } = useResetAliases();
|
const { resetAliases } = useResetAliases();
|
||||||
const { restoreOrder } = useRestoreOrder();
|
const { restoreOrder } = useRestoreOrder();
|
||||||
const { produceStructure } = useProduceStructure();
|
const { produceStructure } = useProduceStructure();
|
||||||
const { inlineSynthesis } = useInlineSynthesis();
|
|
||||||
const { download } = useDownloadRSForm();
|
const { download } = useDownloadRSForm();
|
||||||
|
|
||||||
const showInlineSynthesis = useDialogsStore(state => state.showInlineSynthesis);
|
const showInlineSynthesis = useDialogsStore(state => state.showInlineSynthesis);
|
||||||
|
@ -199,9 +197,7 @@ function MenuRSTabs() {
|
||||||
}
|
}
|
||||||
showInlineSynthesis({
|
showInlineSynthesis({
|
||||||
receiver: controller.schema,
|
receiver: controller.schema,
|
||||||
onInlineSynthesis: data => {
|
onSynthesis: () => controller.deselectAll()
|
||||||
void inlineSynthesis({ itemID: controller.schema.id, data }).then(() => controller.deselectAll());
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,6 @@ import { promptUnsaved } from '@/utils/utils';
|
||||||
|
|
||||||
import { ICstCreateDTO } from '../../backend/api';
|
import { ICstCreateDTO } from '../../backend/api';
|
||||||
import { useCstCreate } from '../../backend/useCstCreate';
|
import { useCstCreate } from '../../backend/useCstCreate';
|
||||||
import { useCstDelete } from '../../backend/useCstDelete';
|
|
||||||
import { useCstMove } from '../../backend/useCstMove';
|
import { useCstMove } from '../../backend/useCstMove';
|
||||||
import { useRSFormSuspense } from '../../backend/useRSForm';
|
import { useRSFormSuspense } from '../../backend/useRSForm';
|
||||||
import { ConstituentaID, CstType, IConstituenta, IRSForm } from '../../models/rsform';
|
import { ConstituentaID, CstType, IConstituenta, IRSForm } from '../../models/rsform';
|
||||||
|
@ -111,7 +110,6 @@ export const RSEditState = ({
|
||||||
|
|
||||||
const { cstCreate } = useCstCreate();
|
const { cstCreate } = useCstCreate();
|
||||||
const { cstMove } = useCstMove();
|
const { cstMove } = useCstMove();
|
||||||
const { cstDelete } = useCstDelete();
|
|
||||||
const { deleteItem } = useDeleteItem();
|
const { deleteItem } = useDeleteItem();
|
||||||
|
|
||||||
const showCreateCst = useDialogsStore(state => state.showCreateCst);
|
const showCreateCst = useDialogsStore(state => state.showCreateCst);
|
||||||
|
@ -202,26 +200,6 @@ export const RSEditState = ({
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleDeleteCst(deleted: ConstituentaID[]) {
|
|
||||||
const data = {
|
|
||||||
items: deleted
|
|
||||||
};
|
|
||||||
|
|
||||||
const isEmpty = deleted.length === schema.items.length;
|
|
||||||
const nextActive = isEmpty ? undefined : getNextActiveOnDelete(activeCst?.id, schema.items, deleted);
|
|
||||||
|
|
||||||
void cstDelete({ itemID: itemID, data }).then(() => {
|
|
||||||
setSelected(nextActive ? [nextActive] : []);
|
|
||||||
if (!nextActive) {
|
|
||||||
navigateRSForm({ tab: RSTabID.CST_LIST });
|
|
||||||
} else if (activeTab === RSTabID.CST_EDIT) {
|
|
||||||
navigateRSForm({ tab: activeTab, activeID: nextActive });
|
|
||||||
} else {
|
|
||||||
navigateRSForm({ tab: activeTab });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function moveUp() {
|
function moveUp() {
|
||||||
if (selected.length === 0) {
|
if (selected.length === 0) {
|
||||||
return;
|
return;
|
||||||
|
@ -307,7 +285,22 @@ export const RSEditState = ({
|
||||||
}
|
}
|
||||||
|
|
||||||
function promptDeleteCst() {
|
function promptDeleteCst() {
|
||||||
showDeleteCst({ schema: schema, selected: selected, onDelete: handleDeleteCst });
|
showDeleteCst({
|
||||||
|
schema: schema,
|
||||||
|
selected: selected,
|
||||||
|
afterDelete: (schema, deleted) => {
|
||||||
|
const isEmpty = deleted.length === schema.items.length;
|
||||||
|
const nextActive = isEmpty ? undefined : getNextActiveOnDelete(activeCst?.id, schema.items, deleted);
|
||||||
|
setSelected(nextActive ? [nextActive] : []);
|
||||||
|
if (!nextActive) {
|
||||||
|
navigateRSForm({ tab: RSTabID.CST_LIST });
|
||||||
|
} else if (activeTab === RSTabID.CST_EDIT) {
|
||||||
|
navigateRSForm({ tab: activeTab, activeID: nextActive });
|
||||||
|
} else {
|
||||||
|
navigateRSForm({ tab: activeTab });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
function promptTemplate() {
|
function promptTemplate() {
|
||||||
if (isModified && !promptUnsaved()) {
|
if (isModified && !promptUnsaved()) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user