Skip to content

Commit 4703450

Browse files
lblasafacebook-github-bot
authored andcommitted
App connection updates
Summary: Create and expose a function to be used to notify the user of current app connection state updates. If the update is an error, it will be shown as a notification with a button to troubleshoot the issue. ## READ - Each connection attempt has two update channels: - Step update: it will always display the latest update regardless of type. - Error: can aggregate multiple errors but do not get dismissed after a step update. The reason an error cannot be dismissed is because updates can come in succession as per our reconnection process and thus might make them unreadable and in-actionable. - Only display unique errors, remove duplicates. - Errors should be displayed chronologically. - Dismiss all errors after a connection is successfully established. - Both message channels can either be dismissed when clicked and also automatically once a connection is established. Reviewed By: antonk52 Differential Revision: D52218872 fbshipit-source-id: 0c4090755bfab462825d307e2ecf2ae4b2f28567
1 parent f25df74 commit 4703450

File tree

1 file changed

+102
-0
lines changed

1 file changed

+102
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @format
8+
*/
9+
10+
import {css} from '@emotion/css';
11+
import {Button, message, notification, Typography} from 'antd';
12+
import React from 'react';
13+
import {Layout} from './ui';
14+
15+
type ConnectionUpdate = {
16+
key: string;
17+
type: 'loading' | 'info' | 'success' | 'error' | 'warning';
18+
app: string;
19+
device: string;
20+
title: string;
21+
detail?: string;
22+
};
23+
24+
type ErrorUpdate = {
25+
entries: Set<string>;
26+
orderedEntries: Array<string>;
27+
};
28+
const errorUpdates = new Map<string, ErrorUpdate>();
29+
30+
const className = css`
31+
.ant-message-notice-content {
32+
width: 30%;
33+
}
34+
`;
35+
36+
export const connectionUpdate = (
37+
update: ConnectionUpdate,
38+
onClick: () => void,
39+
) => {
40+
const title = `${update.app} on ${update.device} ${update.title}`;
41+
42+
if (update.type === 'error') {
43+
const errors = errorUpdates.get(update.key) ?? {
44+
entries: new Set(),
45+
orderedEntries: [],
46+
};
47+
48+
if (update.detail && !errors.entries.has(update.detail)) {
49+
errors.entries.add(update.detail);
50+
errors.orderedEntries.push(update.detail);
51+
}
52+
53+
const content = errors.orderedEntries.reduce((accumulator, e) => {
54+
return accumulator.length > 0 ? accumulator + '\n' + e : e;
55+
});
56+
57+
errorUpdates.set(update.key, errors);
58+
notification.error({
59+
key: update.key,
60+
message: title,
61+
description: (
62+
<Layout.Bottom>
63+
<Typography.Text>{content}</Typography.Text>
64+
<div style={{marginTop: 10}}>
65+
<Button
66+
type="primary"
67+
style={{float: 'right'}}
68+
onClick={() => {
69+
notification.close(update.key);
70+
71+
onClick();
72+
}}>
73+
Troubleshoot
74+
</Button>
75+
</div>
76+
</Layout.Bottom>
77+
),
78+
duration: 0,
79+
onClose: () => message.destroy(update.key),
80+
});
81+
} else {
82+
if (update.type === 'success') {
83+
errorUpdates.delete(update.key);
84+
}
85+
86+
let content = title;
87+
if (update.detail) {
88+
content += `\n ${update.detail}`;
89+
}
90+
message.open({
91+
key: update.key,
92+
type: update.type,
93+
content,
94+
className,
95+
style: {
96+
marginTop: '68px',
97+
},
98+
duration: update.type === 'success' ? 3 : 0,
99+
onClick: () => message.destroy(update.key),
100+
});
101+
}
102+
};

0 commit comments

Comments
 (0)