F: Implement react-query for backend interactions

This commit is contained in:
Ivan 2025-01-27 15:02:00 +03:00
parent 519b5f6634
commit fe65dcd574
9 changed files with 40 additions and 88 deletions

View File

@ -1,8 +1,7 @@
import { useQuery, useQueryClient, useSuspenseQuery } from '@tanstack/react-query';
import { useQuery, useSuspenseQuery } from '@tanstack/react-query';
import { useLibrary, useLibrarySuspense } from '@/backend/library/useLibrary';
import { LibraryItemID } from '@/models/library';
import { IOperationSchema, IOperationSchemaData } from '@/models/oss';
import { OssLoader } from '@/models/OssLoader';
import { ossApi } from './api';
@ -25,23 +24,3 @@ export function useOssSuspense({ itemID }: { itemID: LibraryItemID }) {
const schema = new OssLoader(data!, libraryItems).produceOSS();
return { schema };
}
export function useOssUpdate({ itemID }: { itemID?: LibraryItemID }) {
const { items: libraryItems } = useLibrary();
const client = useQueryClient();
const queryKey = [ossApi.getOssQueryOptions({ itemID }).queryKey];
return {
update: (data: IOperationSchemaData) =>
client.setQueryData(queryKey, new OssLoader(data, libraryItems).produceOSS()),
partialUpdate: (data: Partial<IOperationSchema>) =>
client.setQueryData(queryKey, (prev: IOperationSchema) => (prev ? { ...prev, ...data } : prev))
};
}
export function useOssInvalidate({ itemID }: { itemID?: LibraryItemID }) {
const client = useQueryClient();
const queryKey = [ossApi.getOssQueryOptions({ itemID }).queryKey];
return {
invalidate: () => client.invalidateQueries({ queryKey })
};
}

View File

@ -20,7 +20,6 @@ export const useCheckConstituenta = () => {
onSuccess?: DataCallback<IExpressionParse>
) => mutation.mutate(data, { onSuccess }),
isPending: mutation.isPending,
error: mutation.error,
reset: mutation.reset
error: mutation.error
};
};

View File

@ -1,32 +0,0 @@
'use client';
import { useCallback, useState } from 'react';
import { DataCallback } from '@/backend/apiTransport';
import { ICheckConstituentaDTO } from '@/backend/rsform/api';
import { useCheckConstituenta } from '@/backend/rsform/useCheckConstituenta';
import { IConstituenta, type IRSForm } from '@/models/rsform';
import { IExpressionParse } from '@/models/rslang';
function useRSParse({ schema }: { schema?: IRSForm }) {
const [parseData, setParseData] = useState<IExpressionParse | undefined>(undefined);
const resetParse = useCallback(() => setParseData(undefined), []);
const { checkConstituenta: checkInternal, isPending, error, reset } = useCheckConstituenta();
function checkConstituenta(expression: string, activeCst: IConstituenta, onSuccess?: DataCallback<IExpressionParse>) {
const data: ICheckConstituentaDTO = {
definition_formal: expression,
alias: activeCst.alias,
cst_type: activeCst.cst_type
};
checkInternal({ itemID: schema!.id, data }, parse => {
setParseData(parse);
onSuccess?.(parse);
});
}
return { parseData, checkConstituenta, resetParse, error, reset, isPending };
}
export default useRSParse;

View File

@ -1,6 +1,6 @@
'use client';
import { createContext, useCallback, useContext, useEffect, useState } from 'react';
import { createContext, useContext, useEffect, useState } from 'react';
import { toast } from 'react-toastify';
import { useConceptNavigation } from '@/app/Navigation/NavigationContext';
@ -130,16 +130,13 @@ export const OssEditState = ({ itemID, children }: React.PropsWithChildren<OssEd
router.push(url);
}
const navigateOperationSchema = useCallback(
(target: OperationID) => {
function navigateOperationSchema(target: OperationID) {
const node = schema.operationByID.get(target);
if (!node?.result) {
return;
}
router.push(urls.schema_props({ id: node.result, tab: RSTabID.CST_LIST }));
},
[router, schema]
);
}
function deleteSchema() {
if (!schema || !window.confirm(prompts.deleteOSS)) {

View File

@ -4,6 +4,9 @@ import { ReactCodeMirrorRef } from '@uiw/react-codemirror';
import { useEffect, useRef, useState } from 'react';
import { toast } from 'react-toastify';
import { DataCallback } from '@/backend/apiTransport';
import { ICheckConstituentaDTO } from '@/backend/rsform/api';
import { useCheckConstituenta } from '@/backend/rsform/useCheckConstituenta';
import { useIsProcessingRSForm } from '@/backend/rsform/useIsProcessingRSForm';
import BadgeHelp from '@/components/info/BadgeHelp';
import { CProps } from '@/components/props';
@ -11,7 +14,6 @@ import RSInput from '@/components/RSInput';
import { parser as rslangParser } from '@/components/RSInput/rslang/parserAST';
import { RSTextWrapper } from '@/components/RSInput/textEditing';
import Overlay from '@/components/ui/Overlay';
import useRSParse from '@/hooks/useRSParse';
import { HelpTopic } from '@/models/miscellaneous';
import { ConstituentaID, IConstituenta } from '@/models/rsform';
import { getDefinitionPrefix } from '@/models/rsformAPI';
@ -60,17 +62,31 @@ function EditorRSExpression({
const controller = useRSEdit();
const [isModified, setIsModified] = useState(false);
const parser = useRSParse({ schema: controller.schema });
const rsInput = useRef<ReactCodeMirrorRef>(null);
const [parseData, setParseData] = useState<IExpressionParse | undefined>(undefined);
const isProcessing = useIsProcessingRSForm();
const showControls = usePreferencesStore(state => state.showExpressionControls);
const showAST = useDialogsStore(state => state.showShowAST);
const { checkConstituenta: checkInternal, isPending } = useCheckConstituenta();
function checkConstituenta(expression: string, activeCst: IConstituenta, onSuccess?: DataCallback<IExpressionParse>) {
const data: ICheckConstituentaDTO = {
definition_formal: expression,
alias: activeCst.alias,
cst_type: activeCst.cst_type
};
checkInternal({ itemID: controller.schema.id, data }, parse => {
setParseData(parse);
onSuccess?.(parse);
});
}
useEffect(() => {
setIsModified(false);
parser.resetParse();
}, [activeCst, parser, toggleReset]);
setParseData(undefined);
}, [activeCst, toggleReset]);
function handleChange(newValue: string) {
onChangeExpression(newValue);
@ -78,7 +94,7 @@ function EditorRSExpression({
}
function handleCheckExpression(callback?: (parse: IExpressionParse) => void) {
parser.checkConstituenta(value, activeCst, parse => {
checkConstituenta(value, activeCst, parse => {
onChangeLocalParse(parse);
if (parse.errors.length > 0) {
onShowError(parse.errors[0], parse.prefixLen);
@ -152,10 +168,10 @@ function EditorRSExpression({
className='w-fit pl-[8.5rem] xs:pl-[2rem] flex gap-1'
>
<StatusBar
processing={parser.isPending}
processing={isPending}
isModified={isModified}
activeCst={activeCst}
parseData={parser.parseData}
parseData={parseData}
onAnalyze={() => handleCheckExpression()}
/>
<BadgeHelp topic={HelpTopic.UI_CST_STATUS} offset={4} />
@ -181,10 +197,10 @@ function EditorRSExpression({
/>
<ParsingResult
isOpen={!!parser.parseData && parser.parseData.errors.length > 0}
data={parser.parseData}
isOpen={!!parseData && parseData.errors.length > 0}
data={parseData}
disabled={disabled}
onShowError={error => onShowError(error, parser.parseData?.prefixLen ?? 0)}
onShowError={error => onShowError(error, parseData?.prefixLen ?? 0)}
/>
</div>
);

View File

@ -381,7 +381,6 @@ function MenuRSTabs() {
</Dropdown>
</div>
) : null}
router.push(urls.schema(itemID, version), newTab);
{controller.isArchive && user ? (
<Button
dense

View File

@ -99,13 +99,7 @@ export const RSEditState = ({ itemID, versionID, activeTab, children }: React.Pr
const [selected, setSelected] = useState<ConstituentaID[]>([]);
const canDeleteSelected = selected.length > 0 && selected.every(id => !schema.cstByID.get(id)?.is_inherited);
const activeCst: IConstituenta | undefined = (() => {
if (!schema || selected.length === 0) {
return undefined;
} else {
return schema.cstByID.get(selected[-1]);
}
})();
const activeCst = selected.length === 0 ? undefined : schema.cstByID.get(selected[selected.length - 1]);
const { cstCreate } = useCstCreate();
const { cstMove } = useCstMove();

View File

@ -37,14 +37,14 @@ function RSTabs() {
return () => {
document.title = oldTitle;
};
}, [schema?.title]);
}, [schema.title]);
useEffect(() => {
hideFooter(activeTab !== RSTabID.CARD);
setIsModified(false);
if (activeTab === RSTabID.CST_EDIT) {
const cstID = Number(cstQuery);
if (cstID && schema?.cstByID.has(cstID)) {
if (cstID && schema.cstByID.has(cstID)) {
setSelected([cstID]);
} else {
setSelected([]);

View File

@ -1 +1 @@
export { default } from './RSTabs';
export { default } from './RSFormPage';