Skip to content

Commit 2e2e10c

Browse files
committed
Improve Offline component design for reference fields and inputs
1 parent 84207e0 commit 2e2e10c

File tree

11 files changed

+108
-17
lines changed

11 files changed

+108
-17
lines changed

docs/DataProviders.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -945,6 +945,10 @@ export const App = () => (
945945
```
946946
{% endraw %}
947947

948+
This is enough to make all the standard react-admin features support offline scenarios.
949+
950+
## Adding Offline Support To Custom Mutations
951+
948952
If you have [custom mutations](./Actions.md#calling-custom-methods) on your dataProvider, you can enable offline support for them too. For instance, if your `dataProvider` exposes a `banUser()` method:
949953

950954
```ts

examples/simple/src/comments/CommentList.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import {
3030
useListContext,
3131
useTranslate,
3232
Exporter,
33+
Offline,
3334
} from 'react-admin';
3435

3536
const commentFilters = [
@@ -63,9 +64,10 @@ const exporter: Exporter = (records, fetchRelatedRecords) =>
6364
});
6465

6566
const CommentGrid = () => {
66-
const { data } = useListContext();
67+
const { data, isPaused, isPlaceholderData } = useListContext();
6768
const translate = useTranslate();
6869

70+
if (isPaused && (data == null || isPlaceholderData)) return <Offline />;
6971
if (!data) return null;
7072
return (
7173
<Grid spacing={2} container>

examples/simple/src/posts/PostEdit.tsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import {
3131
useCreateSuggestionContext,
3232
EditActionsProps,
3333
CanAccess,
34+
Translate,
3435
} from 'react-admin';
3536
import {
3637
Box,
@@ -40,7 +41,9 @@ import {
4041
DialogActions,
4142
DialogContent,
4243
TextField as MuiTextField,
44+
Tooltip,
4345
} from '@mui/material';
46+
import ReportProblemOutlinedIcon from '@mui/icons-material/ReportProblemOutlined';
4447
import PostTitle from './PostTitle';
4548
import TagReferenceInput from './TagReferenceInput';
4649

@@ -229,6 +232,22 @@ const PostEdit = () => (
229232
reference="comments"
230233
target="post_id"
231234
sx={{ lineHeight: 'inherit' }}
235+
offline={
236+
<Tooltip
237+
title={
238+
<Translate i18nKey="ra.notification.offline" />
239+
}
240+
>
241+
<ReportProblemOutlinedIcon
242+
color="warning"
243+
sx={{
244+
marginTop: -2,
245+
position: 'relative',
246+
top: theme => theme.spacing(0.5),
247+
}}
248+
/>
249+
</Tooltip>
250+
}
232251
/>
233252
}
234253
>

examples/simple/src/posts/PostShow.tsx

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@ import {
2323
useShowController,
2424
useLocaleState,
2525
useRecordContext,
26+
Translate,
2627
} from 'react-admin';
28+
import { Tooltip } from '@mui/material';
29+
import ReportProblemOutlinedIcon from '@mui/icons-material/ReportProblemOutlined';
2730
import PostTitle from './PostTitle';
2831

2932
const CreateRelatedComment = () => {
@@ -112,11 +115,36 @@ const PostShow = () => {
112115
</TabbedShowLayout.Tab>
113116
<TabbedShowLayout.Tab
114117
label="post.form.comments"
118+
sx={{
119+
'& .MuiTab-root > span': {
120+
display: 'flex',
121+
alignItems: 'center',
122+
},
123+
}}
115124
count={
116125
<ReferenceManyCount
117126
reference="comments"
118127
target="post_id"
119-
sx={{ lineHeight: 'inherit' }}
128+
sx={{
129+
lineHeight: 'inherit',
130+
}}
131+
offline={
132+
<Tooltip
133+
title={
134+
<Translate i18nKey="ra.notification.offline" />
135+
}
136+
>
137+
<ReportProblemOutlinedIcon
138+
color="warning"
139+
sx={{
140+
marginTop: -2,
141+
position: 'relative',
142+
top: theme =>
143+
theme.spacing(0.5),
144+
}}
145+
/>
146+
</Tooltip>
147+
}
120148
/>
121149
}
122150
>

examples/simple/src/tags/TagList.tsx

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
useListContext,
77
EditButton,
88
Title,
9+
Offline,
910
} from 'react-admin';
1011
import {
1112
Box,
@@ -25,15 +26,27 @@ const TagList = () => (
2526
<ListBase perPage={1000}>
2627
<Stack>
2728
<ListActions />
28-
<Box maxWidth="20em" marginTop="1em">
29-
<Card>
30-
<Tree />
31-
</Card>
32-
</Box>
29+
<TagListView />
3330
</Stack>
3431
</ListBase>
3532
);
3633

34+
const TagListView = () => {
35+
const { data, isPaused } = useListContext();
36+
37+
if (isPaused && data == null) {
38+
return <Offline sx={{ width: '100%' }} />;
39+
}
40+
41+
return (
42+
<Box maxWidth="20em" marginTop="1em">
43+
<Card>
44+
<Tree />
45+
</Card>
46+
</Box>
47+
);
48+
};
49+
3750
const Tree = () => {
3851
const { data, defaultTitle } = useListContext();
3952
const [openChildren, setOpenChildren] = useState<string[]>([]);

packages/ra-ui-materialui/src/Offline.tsx

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@ import {
77
Typography,
88
} from '@mui/material';
99
import { useGetResourceLabel, useResourceContext, useTranslate } from 'ra-core';
10+
import clsx from 'clsx';
1011

1112
export const Offline = (props: Offline) => {
12-
const { message: messageProp } = props;
13+
const { icon, message: messageProp, variant = 'standard', ...rest } = props;
1314
const translate = useTranslate();
1415
const resource = useResourceContext(props);
1516
const getResourceLabel = useGetResourceLabel();
@@ -31,23 +32,43 @@ export const Offline = (props: Offline) => {
3132
}
3233
);
3334
return (
34-
<Root severity="warning" {...props}>
35+
<Root
36+
className={clsx(OfflineClasses.root, {
37+
[OfflineClasses.inline]: variant === 'inline',
38+
})}
39+
severity="warning"
40+
variant={variant === 'inline' ? 'outlined' : variant}
41+
icon={variant === 'inline' ? false : icon}
42+
{...rest}
43+
>
3544
<Typography variant="body2">{message}</Typography>
3645
</Root>
3746
);
3847
};
3948

40-
export interface Offline extends AlertProps {
49+
export interface Offline extends Omit<AlertProps, 'variant'> {
4150
resource?: string;
4251
message?: string;
52+
variant?: AlertProps['variant'] | 'inline';
4353
}
4454

4555
const PREFIX = 'RaOffline';
56+
export const OfflineClasses = {
57+
root: `${PREFIX}-root`,
58+
inline: `${PREFIX}-inline`,
59+
};
4660

4761
const Root = styled(Alert, {
4862
name: PREFIX,
4963
overridesResolver: (props, styles) => styles.root,
50-
})(() => ({}));
64+
})(() => ({
65+
[`&.${OfflineClasses.inline}`]: {
66+
border: 'none',
67+
display: 'inline-flex',
68+
padding: 0,
69+
margin: 0,
70+
},
71+
}));
5172

5273
declare module '@mui/material/styles' {
5374
interface ComponentNameToClassKey {

packages/ra-ui-materialui/src/field/ReferenceField.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ export interface ReferenceFieldProps<
105105

106106
// useful to prevent click bubbling in a datagrid with rowClick
107107
const stopPropagation = e => e.stopPropagation();
108-
const defaultOffline = <Offline />;
108+
const defaultOffline = <Offline variant="inline" />;
109109

110110
export const ReferenceFieldView = <
111111
RecordType extends Record<string, any> = Record<string, any>,

packages/ra-ui-materialui/src/field/ReferenceManyCount.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { sanitizeFieldRestProps } from './sanitizeFieldRestProps';
2121
import { Link } from '../Link';
2222
import { Offline } from '../Offline';
2323

24-
const defaultOffline = <Offline />;
24+
const defaultOffline = <Offline variant="inline" />;
2525

2626
/**
2727
* Fetch and render the number of records related to the current one

packages/ra-ui-materialui/src/field/ReferenceOneField.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import { FieldProps } from './types';
1919
import { ReferenceFieldView } from './ReferenceField';
2020
import { Offline } from '../Offline';
2121

22-
const defaultOffline = <Offline />;
22+
const defaultOffline = <Offline variant="inline" />;
2323

2424
/**
2525
* Render the related record in a one-to-one relationship

packages/ra-ui-materialui/src/input/ReferenceArrayInput.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,12 @@ export const ReferenceArrayInput = (props: ReferenceArrayInputProps) => {
101101

102102
return isPaused && allChoices == null ? (
103103
offline ?? (
104-
<Labeled {...props}>
105-
<Offline />
104+
<Labeled
105+
source={props.source}
106+
label={props.label}
107+
resource={props.resource}
108+
>
109+
<Offline variant="inline" />
106110
</Labeled>
107111
)
108112
) : (

0 commit comments

Comments
 (0)