diff --git a/example/package.json b/example/package.json
index 3d6a85500..7d667078d 100644
--- a/example/package.json
+++ b/example/package.json
@@ -5,6 +5,7 @@
"dependencies": {
"@development-framework/dm-core": "^1.3.3",
"@development-framework/dm-core-plugins": "^1.3.3",
+ "@tanstack/react-query": "^5.37.1",
"plotly.js": "^2.18.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
diff --git a/packages/dm-core/src/ApplicationContext.tsx b/packages/dm-core/src/ApplicationContext.tsx
index 4273918fc..144954656 100644
--- a/packages/dm-core/src/ApplicationContext.tsx
+++ b/packages/dm-core/src/ApplicationContext.tsx
@@ -1,3 +1,4 @@
+import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import React, {
Dispatch,
ReactNode,
@@ -20,6 +21,7 @@ const DEFAULT_ROLE: TRole = {
authServerRoleName: 'anonymous',
label: 'Anonymous',
}
+const queryClient = new QueryClient()
export const ApplicationContext = React.createContext<
| {
name: string
@@ -153,7 +155,9 @@ export const DMApplicationProvider = (props: {
loading,
}}
>
- {props.children}
+
+ {props.children}
+
)
diff --git a/packages/dm-core/src/components/ViewCreator/ViewCreator.tsx b/packages/dm-core/src/components/ViewCreator/ViewCreator.tsx
index 801ef4553..dad07c1b7 100644
--- a/packages/dm-core/src/components/ViewCreator/ViewCreator.tsx
+++ b/packages/dm-core/src/components/ViewCreator/ViewCreator.tsx
@@ -1,7 +1,14 @@
import { Typography } from '@equinor/eds-core-react'
-import { AxiosResponse } from 'axios'
-import React, { useEffect, useMemo, useState } from 'react'
-import { EntityView, Loading, TAttribute, useApplication } from '../../index'
+import { useQuery } from '@tanstack/react-query'
+import { AxiosError } from 'axios'
+import React, { useMemo, useState } from 'react'
+import {
+ EntityView,
+ ErrorResponse,
+ Loading,
+ TAttribute,
+ useApplication,
+} from '../../index'
import {
IUIPlugin,
TInlineRecipeViewConfig,
@@ -40,31 +47,32 @@ type TViewCreator = Omit & {
export const ViewCreator = (props: TViewCreator): React.ReactElement => {
const { idReference, viewConfig, onOpen, onSubmit, onChange } = props
const { dmssAPI } = useApplication()
- const [isLoading, setIsLoading] = useState(true)
const [error, setError] = useState()
- const [attribute, setAttribute] = useState()
- const [directAddress, setDirectAddress] = useState()
const reference = useMemo(
() => getTarget(idReference, viewConfig),
[idReference, viewConfig]
)
+ const queryKeys = ['attributes', reference, viewConfig.resolve]
- useEffect(() => {
- dmssAPI
- .attributeGet({
- address: reference,
- resolve: props.viewConfig.resolve,
- })
- .then((response: AxiosResponse) => {
- setAttribute(response.data.attribute)
- setDirectAddress(response.data.address)
- })
- .catch((error) => setError(error))
- .finally(() => setIsLoading(false))
- }, [reference])
+ const { isPending, data } = useQuery<{
+ address: string
+ attribute: TAttribute
+ }>({
+ staleTime: 5 * 1000,
+ refetchOnMount: false,
+ queryKey: queryKeys,
+ queryFn: () =>
+ dmssAPI
+ .attributeGet({
+ address: reference,
+ resolve: props.viewConfig.resolve,
+ })
+ .then((response: any) => response.data)
+ .catch((error: AxiosError) => setError(error)),
+ })
- if (isLoading || !directAddress) return
+ if (isPending || !data?.address) return
if (error)
return (
@@ -72,7 +80,7 @@ export const ViewCreator = (props: TViewCreator): React.ReactElement => {
{error.message})
)
- if (attribute === undefined)
+ if (data.attribute === undefined)
throw new Error('Unable to find type and dimensions for view')
if (viewConfig === undefined)
@@ -82,8 +90,8 @@ export const ViewCreator = (props: TViewCreator): React.ReactElement => {
if (isInlineRecipeViewConfig(viewConfig)) {
return (
{
if (isReferenceViewConfig(viewConfig)) {
return (
{
} else if (isViewConfig(viewConfig)) {
return (
{
document: T | null
isLoading: boolean
@@ -55,68 +56,80 @@ export function useDocument(
depth?: number | undefined,
notify: boolean = true
): IUseDocumentReturnType {
- const [document, setDocument] = useState(null)
- const [isLoading, setLoading] = useState(true)
- const [error, setError] = useState(null)
const { dmssAPI } = useApplication()
+ const [errorResponse, setErrorResponse] = useState(null)
+ const queryClient = useQueryClient()
- useEffect(() => {
- setLoading(true)
- const documentDepth: number = depth ?? 0
- if (documentDepth < 0 || documentDepth > 999)
- throw new Error('Depth must be a positive number < 999')
- dmssAPI
- .documentGet({
- address: idReference,
- depth: documentDepth,
- })
- .then((response: any) => {
- const data = response.data
- setDocument(data)
- setError(null)
- })
- .catch((error: AxiosError) => {
- console.error(error)
- if (notify)
- toast.error(
- 'Unable to retrieve document, with message: ' +
- error.response?.data.message ?? error.message
+ const queryKeys = ['documents', idReference, depth]
+ const documentDepth: number = depth ?? 0
+ if (documentDepth < 0 || documentDepth > 999)
+ throw new Error('Depth must be a positive number < 999')
+
+ const { isPending, data } = useQuery({
+ staleTime: 5 * 1000,
+ refetchOnMount: false,
+ queryKey: queryKeys,
+ queryFn: () =>
+ dmssAPI
+ .documentGet({
+ address: idReference,
+ depth: documentDepth,
+ })
+ .then((response: any) => response.data)
+ .catch((error: AxiosError) => {
+ console.error(error)
+ if (notify)
+ toast.error(
+ 'Unable to retrieve document, with message: ' +
+ error.response?.data.message ?? error.message
+ )
+ setErrorResponse(
+ error.response?.data || { message: error.name, data: error }
)
- setError(error.response?.data || { message: error.name, data: error })
- })
- .finally(() => setLoading(false))
- }, [idReference, depth])
+ }),
+ })
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- async function updateDocument(
- newDocument: T,
- notify: boolean = true,
- partialUpdate: boolean = false,
- throwError: boolean = false
- ): Promise {
- setLoading(true)
- return dmssAPI
- .documentUpdate({
- idAddress: idReference,
- data: JSON.stringify(newDocument),
- partialUpdate: partialUpdate,
- })
- .then((response: any) => {
- const data = response.data.data
- setDocument(data)
- setError(null)
- if (notify) toast.success('Document updated')
- })
- .catch((error: AxiosError) => {
- console.error(error)
- if (notify) toast.error(error.response?.data.message ?? error.message)
- setError(error.response?.data || { message: error.name, data: error })
- if (throwError) {
+ const mutation = useMutation({
+ mutationFn: ({
+ newDocument,
+ partialUpdate,
+ notify,
+ throwError,
+ }: {
+ newDocument: T
+ notify?: boolean
+ partialUpdate?: boolean
+ throwError?: boolean
+ }) =>
+ dmssAPI
+ .documentUpdate({
+ idAddress: idReference,
+ data: JSON.stringify(newDocument),
+ partialUpdate: partialUpdate,
+ })
+ .then((response: any) => {
+ queryClient.setQueryData(queryKeys, response.data.data)
+ setErrorResponse(null)
+ if (notify) toast.success('Document updated')
+ })
+ .catch((error: AxiosError) => {
+ console.error(error)
+ if (notify) toast.error(error.response?.data.message ?? error.message)
+ setErrorResponse(
+ error.response?.data || { message: error.name, data: error }
+ )
+ if (throwError) {
throw new Error(JSON.stringify(error, null, 2))
}
- })
- .finally(() => setLoading(false))
- }
+ }),
+ })
- return { document, isLoading, updateDocument, error, setError }
+ return {
+ document: data || null,
+ isLoading: isPending,
+ updateDocument: (newDocument: T, notify, partialUpdate, throwError) =>
+ mutation.mutateAsync({ newDocument, notify, partialUpdate, throwError }),
+ error: errorResponse,
+ setError: setErrorResponse
+ }
}