Skip to content

Commit 9f418bf

Browse files
committed
Add offline support to details components
1 parent 8f3096b commit 9f418bf

File tree

6 files changed

+113
-46
lines changed

6 files changed

+113
-46
lines changed

packages/ra-core/src/controller/edit/useEditController.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ export const useEditController = <
108108
error,
109109
isLoading,
110110
isFetching,
111+
isPaused,
111112
isPending,
112113
refetch,
113114
} = useGetOne<RecordType, ErrorType>(
@@ -268,6 +269,7 @@ export const useEditController = <
268269
error,
269270
isFetching,
270271
isLoading,
272+
isPaused,
271273
isPending,
272274
mutationMode,
273275
record,
@@ -303,6 +305,7 @@ export interface EditControllerBaseResult<RecordType extends RaRecord = any>
303305
defaultTitle?: string;
304306
isFetching: boolean;
305307
isLoading: boolean;
308+
isPaused: boolean;
306309
refetch: UseGetOneHookValue<RecordType>['refetch'];
307310
redirect: RedirectionSideEffect;
308311
resource: string;

packages/ra-core/src/controller/field/useReferenceOneFieldController.tsx

Lines changed: 44 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -69,47 +69,57 @@ export const useReferenceOneFieldController = <
6969
const notify = useNotify();
7070
const { meta, ...otherQueryOptions } = queryOptions;
7171

72-
const { data, error, isFetching, isLoading, isPending, refetch } =
73-
useGetManyReference<RecordType, ErrorType>(
74-
reference,
75-
{
76-
target,
77-
id: get(record, source),
78-
pagination: { page: 1, perPage: 1 },
79-
sort,
80-
filter,
81-
meta,
82-
},
83-
{
84-
enabled: !!record,
85-
onError: error =>
86-
notify(
87-
typeof error === 'string'
88-
? error
89-
: (error as Error).message ||
90-
'ra.notification.http_error',
91-
{
92-
type: 'error',
93-
messageArgs: {
94-
_:
95-
typeof error === 'string'
96-
? error
97-
: (error as Error)?.message
98-
? (error as Error).message
99-
: undefined,
100-
},
101-
}
102-
),
103-
...otherQueryOptions,
104-
}
105-
);
72+
const {
73+
data,
74+
error,
75+
isFetching,
76+
isLoading,
77+
isPending,
78+
isPaused,
79+
isPlaceholderData,
80+
refetch,
81+
} = useGetManyReference<RecordType, ErrorType>(
82+
reference,
83+
{
84+
target,
85+
id: get(record, source),
86+
pagination: { page: 1, perPage: 1 },
87+
sort,
88+
filter,
89+
meta,
90+
},
91+
{
92+
enabled: !!record,
93+
onError: error =>
94+
notify(
95+
typeof error === 'string'
96+
? error
97+
: (error as Error).message ||
98+
'ra.notification.http_error',
99+
{
100+
type: 'error',
101+
messageArgs: {
102+
_:
103+
typeof error === 'string'
104+
? error
105+
: (error as Error)?.message
106+
? (error as Error).message
107+
: undefined,
108+
},
109+
}
110+
),
111+
...otherQueryOptions,
112+
}
113+
);
106114

107115
return {
108116
referenceRecord: data ? data[0] : undefined,
109117
error,
110118
isFetching,
111119
isLoading,
112120
isPending,
121+
isPaused,
122+
isPlaceholderData,
113123
refetch,
114124
};
115125
};

packages/ra-core/src/controller/show/useShowController.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ export const useShowController = <
9696
error,
9797
isLoading,
9898
isFetching,
99+
isPaused,
99100
isPending,
100101
refetch,
101102
} = useGetOne<RecordType, ErrorType>(
@@ -141,6 +142,7 @@ export const useShowController = <
141142
error,
142143
isLoading,
143144
isFetching,
145+
isPaused,
144146
isPending,
145147
record,
146148
refetch,
@@ -162,6 +164,7 @@ export interface ShowControllerBaseResult<RecordType extends RaRecord = any> {
162164
defaultTitle?: string;
163165
isFetching: boolean;
164166
isLoading: boolean;
167+
isPaused: boolean;
165168
resource: string;
166169
record?: RecordType;
167170
refetch: UseGetOneHookValue<RecordType>['refetch'];

packages/ra-ui-materialui/src/detail/EditView.tsx

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as React from 'react';
2-
import type { ReactElement, ElementType } from 'react';
2+
import type { ReactNode, ElementType } from 'react';
33
import {
44
Card,
55
CardContent,
@@ -14,8 +14,10 @@ import { useEditContext, useResourceDefinition } from 'ra-core';
1414

1515
import { EditActions } from './EditActions';
1616
import { Title } from '../layout';
17+
import { Offline } from '../Offline';
1718

1819
const defaultActions = <EditActions />;
20+
const defaultOffline = <Offline />;
1921

2022
export const EditView = (inProps: EditViewProps) => {
2123
const props = useThemeProps({
@@ -28,13 +30,31 @@ export const EditView = (inProps: EditViewProps) => {
2830
children,
2931
className,
3032
component: Content = Card,
33+
offline = defaultOffline,
3134
emptyWhileLoading = false,
3235
title,
3336
...rest
3437
} = props;
3538

3639
const { hasShow } = useResourceDefinition();
37-
const { resource, defaultTitle, record, isPending } = useEditContext();
40+
const { resource, defaultTitle, record, isPending, isPaused } =
41+
useEditContext();
42+
43+
if (isPaused && offline) {
44+
return (
45+
<Root className={clsx('edit-page', className)} {...rest}>
46+
<div
47+
className={clsx(
48+
EditClasses.main,
49+
EditClasses.noActions,
50+
EditClasses.offline
51+
)}
52+
>
53+
{offline}
54+
</div>
55+
</Root>
56+
);
57+
}
3858

3959
const finalActions =
4060
typeof actions === 'undefined' && hasShow ? defaultActions : actions;
@@ -68,11 +88,12 @@ export const EditView = (inProps: EditViewProps) => {
6888

6989
export interface EditViewProps
7090
extends Omit<React.HTMLAttributes<HTMLDivElement>, 'id' | 'title'> {
71-
actions?: ReactElement | false;
72-
aside?: ReactElement;
91+
actions?: ReactNode | false;
92+
aside?: ReactNode;
93+
offline?: ReactNode;
7394
component?: ElementType;
7495
emptyWhileLoading?: boolean;
75-
title?: string | ReactElement | false;
96+
title?: ReactNode;
7697
sx?: SxProps<Theme>;
7798
}
7899

@@ -82,6 +103,7 @@ export const EditClasses = {
82103
main: `${PREFIX}-main`,
83104
noActions: `${PREFIX}-noActions`,
84105
card: `${PREFIX}-card`,
106+
offline: `${PREFIX}-offline`,
85107
};
86108

87109
const Root = styled('div', {
@@ -95,6 +117,10 @@ const Root = styled('div', {
95117
[`& .${EditClasses.noActions}`]: {
96118
marginTop: '1em',
97119
},
120+
[`& .${EditClasses.offline}`]: {
121+
flexDirection: 'column',
122+
alignItems: 'unset',
123+
},
98124
[`& .${EditClasses.card}`]: {
99125
flex: '1 1 auto',
100126
},

packages/ra-ui-materialui/src/detail/ShowView.tsx

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as React from 'react';
2-
import type { ReactElement, ElementType } from 'react';
2+
import type { ReactNode, ElementType } from 'react';
33
import {
44
Card,
55
type ComponentsOverrides,
@@ -12,8 +12,10 @@ import clsx from 'clsx';
1212
import { useShowContext, useResourceDefinition } from 'ra-core';
1313
import { ShowActions } from './ShowActions';
1414
import { Title } from '../layout';
15+
import { Offline } from '../Offline';
1516

1617
const defaultActions = <ShowActions />;
18+
const defaultOffline = <Offline />;
1719

1820
export const ShowView = (inProps: ShowViewProps) => {
1921
const props = useThemeProps({
@@ -27,13 +29,30 @@ export const ShowView = (inProps: ShowViewProps) => {
2729
className,
2830
component: Content = Card,
2931
emptyWhileLoading = false,
32+
offline = defaultOffline,
3033
title,
3134
...rest
3235
} = props;
3336

34-
const { resource, defaultTitle, record } = useShowContext();
37+
const { resource, defaultTitle, isPaused, record } = useShowContext();
3538
const { hasEdit } = useResourceDefinition();
3639

40+
if (isPaused && offline) {
41+
return (
42+
<Root className={clsx('show-page', className)} {...rest}>
43+
<div
44+
className={clsx(
45+
ShowClasses.main,
46+
ShowClasses.noActions,
47+
ShowClasses.offline
48+
)}
49+
>
50+
{offline}
51+
</div>
52+
</Root>
53+
);
54+
}
55+
3756
const finalActions =
3857
typeof actions === 'undefined' && hasEdit ? defaultActions : actions;
3958

@@ -64,11 +83,12 @@ export const ShowView = (inProps: ShowViewProps) => {
6483

6584
export interface ShowViewProps
6685
extends Omit<React.HTMLAttributes<HTMLDivElement>, 'id' | 'title'> {
67-
actions?: ReactElement | false;
68-
aside?: ReactElement;
86+
actions?: ReactNode;
87+
aside?: ReactNode;
6988
component?: ElementType;
7089
emptyWhileLoading?: boolean;
71-
title?: string | ReactElement | false;
90+
offline?: ReactNode;
91+
title?: ReactNode;
7292
sx?: SxProps<Theme>;
7393
}
7494

@@ -78,6 +98,7 @@ export const ShowClasses = {
7898
main: `${PREFIX}-main`,
7999
noActions: `${PREFIX}-noActions`,
80100
card: `${PREFIX}-card`,
101+
offline: `${PREFIX}-offline`,
81102
};
82103

83104
const Root = styled('div', {
@@ -90,6 +111,10 @@ const Root = styled('div', {
90111
[`& .${ShowClasses.noActions}`]: {
91112
marginTop: '1em',
92113
},
114+
[`& .${ShowClasses.offline}`]: {
115+
flexDirection: 'column',
116+
alignItems: 'unset',
117+
},
93118
[`& .${ShowClasses.card}`]: {
94119
flex: '1 1 auto',
95120
},

packages/ra-ui-materialui/src/layout/Title.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as React from 'react';
2-
import { useEffect, useState, ReactElement } from 'react';
2+
import { useEffect, useState, ReactNode } from 'react';
33
import { createPortal } from 'react-dom';
44
import { RaRecord, TitleComponent, warning } from 'ra-core';
55

@@ -50,6 +50,6 @@ export interface TitleProps {
5050
className?: string;
5151
defaultTitle?: TitleComponent;
5252
record?: Partial<RaRecord>;
53-
title?: string | ReactElement;
53+
title?: ReactNode;
5454
preferenceKey?: string | false;
5555
}

0 commit comments

Comments
 (0)