Create and upload a universal export when using the support request link
Summary: Design doc: https://docs.google.com/document/d/1HLCFl46RfqG0o1mSt8SWrwf_HMfOCRg_oENioc1rkvQ/edit# Reviewed By: passy Differential Revision: D40586468 fbshipit-source-id: 4d6a8706c7d1cad1951bda701c51f0998c985628
This commit is contained in:
committed by
Facebook GitHub Bot
parent
970c03d942
commit
778a56d7ac
@@ -12,11 +12,12 @@ import {State} from '../reducers';
|
|||||||
export type SupportRequestDetails = {
|
export type SupportRequestDetails = {
|
||||||
title?: string;
|
title?: string;
|
||||||
whatAlreadyTried?: string;
|
whatAlreadyTried?: string;
|
||||||
|
everythingEverywhereAllAtOnceExportDownloadURL?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function openSupportRequestForm(
|
export default function openSupportRequestForm(
|
||||||
_state: State,
|
_state: State,
|
||||||
_details?: SupportRequestDetails,
|
_details?: SupportRequestDetails,
|
||||||
): void {
|
): Promise<void> {
|
||||||
throw new Error('Not implemented!');
|
throw new Error('Not implemented!');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -255,8 +255,6 @@ function ExtrasMenu() {
|
|||||||
const {showWelcomeAtStartup} = settings;
|
const {showWelcomeAtStartup} = settings;
|
||||||
const [welcomeVisible, setWelcomeVisible] = useState(showWelcomeAtStartup);
|
const [welcomeVisible, setWelcomeVisible] = useState(showWelcomeAtStartup);
|
||||||
|
|
||||||
const fullState = useStore((state) => state);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<NUX
|
<NUX
|
||||||
@@ -305,21 +303,7 @@ function ExtrasMenu() {
|
|||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
</Menu.SubMenu>
|
</Menu.SubMenu>
|
||||||
<Menu.Divider />
|
<Menu.Divider />
|
||||||
{config.isFBBuild ? (
|
{config.isFBBuild ? <OpenSupportRequestMenuItem /> : null}
|
||||||
<>
|
|
||||||
<Menu.Item
|
|
||||||
key="feedback"
|
|
||||||
onClick={() => {
|
|
||||||
getLogger().track('usage', 'support-form-source', {
|
|
||||||
source: 'sidebar',
|
|
||||||
group: undefined,
|
|
||||||
});
|
|
||||||
openSupportRequestForm(fullState);
|
|
||||||
}}>
|
|
||||||
Feedback
|
|
||||||
</Menu.Item>
|
|
||||||
</>
|
|
||||||
) : null}
|
|
||||||
<Menu.Item key="settings" onClick={() => setShowSettings(true)}>
|
<Menu.Item key="settings" onClick={() => setShowSettings(true)}>
|
||||||
Settings
|
Settings
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
@@ -433,21 +417,51 @@ function DebugLogsButton({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ExportEverythingEverywhereAllAtOnceButton() {
|
function OpenSupportRequestMenuItem() {
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
|
|
||||||
const [status, setStatus] = useState<
|
const [status, setStatus] = useState<
|
||||||
ExportEverythingEverywhereAllAtOnceStatus | undefined
|
ExportEverythingEverywhereAllAtOnceStatus | undefined
|
||||||
>();
|
>();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ExportEverythingEverywhereAllAtOnceStatusModal
|
||||||
|
status={status}
|
||||||
|
setStatus={setStatus}
|
||||||
|
/>
|
||||||
|
<Menu.Item
|
||||||
|
key="feedback"
|
||||||
|
onClick={async () => {
|
||||||
|
getLogger().track('usage', 'support-form-source', {
|
||||||
|
source: 'sidebar',
|
||||||
|
group: undefined,
|
||||||
|
});
|
||||||
|
await exportEverythingEverywhereAllAtOnce(
|
||||||
|
store,
|
||||||
|
(...args) => setStatus(args),
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
}}>
|
||||||
|
Feedback
|
||||||
|
</Menu.Item>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ExportEverythingEverywhereAllAtOnceStatusModal({
|
||||||
|
status,
|
||||||
|
setStatus,
|
||||||
|
}: {
|
||||||
|
status: ExportEverythingEverywhereAllAtOnceStatus | undefined;
|
||||||
|
setStatus: (
|
||||||
|
newStatus: ExportEverythingEverywhereAllAtOnceStatus | undefined,
|
||||||
|
) => void;
|
||||||
|
}) {
|
||||||
const [statusMessage, setStatusMessage] = useState<JSX.Element | undefined>();
|
const [statusMessage, setStatusMessage] = useState<JSX.Element | undefined>();
|
||||||
|
|
||||||
const exportEverythingEverywhereAllAtOnceTracked = useTrackedCallback(
|
|
||||||
'Debug data export',
|
|
||||||
() => exportEverythingEverywhereAllAtOnce(store, setStatus),
|
|
||||||
[store, setStatus],
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
switch (status) {
|
switch (status?.[0]) {
|
||||||
case 'logs': {
|
case 'logs': {
|
||||||
setStatusMessage(<p>Exporting Flipper logs...</p>);
|
setStatusMessage(<p>Exporting Flipper logs...</p>);
|
||||||
return;
|
return;
|
||||||
@@ -492,6 +506,23 @@ function ExportEverythingEverywhereAllAtOnceButton() {
|
|||||||
setStatusMessage(<p>Creating an archive...</p>);
|
setStatusMessage(<p>Creating an archive...</p>);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
case 'upload': {
|
||||||
|
setStatusMessage(<p>Uploading the archive...</p>);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case 'support': {
|
||||||
|
setStatusMessage(<p>Creating a support request...</p>);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case 'error': {
|
||||||
|
setStatusMessage(
|
||||||
|
<>
|
||||||
|
<p>Oops! Something went wrong.</p>
|
||||||
|
<p>{status[1]}</p>
|
||||||
|
</>,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
case 'done': {
|
case 'done': {
|
||||||
setStatusMessage(<p>Done!</p>);
|
setStatusMessage(<p>Done!</p>);
|
||||||
return;
|
return;
|
||||||
@@ -504,7 +535,6 @@ function ExportEverythingEverywhereAllAtOnceButton() {
|
|||||||
}, [status]);
|
}, [status]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
|
||||||
<Modal
|
<Modal
|
||||||
visible={!!status}
|
visible={!!status}
|
||||||
centered
|
centered
|
||||||
@@ -515,6 +545,28 @@ function ExportEverythingEverywhereAllAtOnceButton() {
|
|||||||
footer={null}>
|
footer={null}>
|
||||||
{statusMessage}
|
{statusMessage}
|
||||||
</Modal>
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ExportEverythingEverywhereAllAtOnceButton() {
|
||||||
|
const store = useStore();
|
||||||
|
const [status, setStatus] = useState<
|
||||||
|
ExportEverythingEverywhereAllAtOnceStatus | undefined
|
||||||
|
>();
|
||||||
|
|
||||||
|
const exportEverythingEverywhereAllAtOnceTracked = useTrackedCallback(
|
||||||
|
'Debug data export',
|
||||||
|
() =>
|
||||||
|
exportEverythingEverywhereAllAtOnce(store, (...args) => setStatus(args)),
|
||||||
|
[store, setStatus],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ExportEverythingEverywhereAllAtOnceStatusModal
|
||||||
|
status={status}
|
||||||
|
setStatus={setStatus}
|
||||||
|
/>
|
||||||
<NUX title="Press this button if you have issues with Flipper. It will collect Flipper debug data that you can send to the Flipper team to get help.">
|
<NUX title="Press this button if you have issues with Flipper. It will collect Flipper debug data that you can send to the Flipper team to get help.">
|
||||||
<LeftRailButton
|
<LeftRailButton
|
||||||
icon={<BugOutlined />}
|
icon={<BugOutlined />}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import {
|
|||||||
DeviceDebugFile,
|
DeviceDebugFile,
|
||||||
DeviceDebugCommand,
|
DeviceDebugCommand,
|
||||||
timeout,
|
timeout,
|
||||||
|
getStringFromErrorLike,
|
||||||
} from 'flipper-common';
|
} from 'flipper-common';
|
||||||
import {Store, MiddlewareAPI} from '../reducers';
|
import {Store, MiddlewareAPI} from '../reducers';
|
||||||
import {DeviceExport} from 'flipper-frontend-core';
|
import {DeviceExport} from 'flipper-frontend-core';
|
||||||
@@ -41,6 +42,8 @@ import {exportLogs} from '../chrome/ConsoleLogs';
|
|||||||
import JSZip from 'jszip';
|
import JSZip from 'jszip';
|
||||||
import {safeFilename} from './safeFilename';
|
import {safeFilename} from './safeFilename';
|
||||||
import {getExportablePlugins} from '../selectors/connections';
|
import {getExportablePlugins} from '../selectors/connections';
|
||||||
|
import {notification} from 'antd';
|
||||||
|
import openSupportRequestForm from '../fb-stubs/openSupportRequestForm';
|
||||||
|
|
||||||
export const IMPORT_FLIPPER_TRACE_EVENT = 'import-flipper-trace';
|
export const IMPORT_FLIPPER_TRACE_EVENT = 'import-flipper-trace';
|
||||||
export const EXPORT_FLIPPER_TRACE_EVENT = 'export-flipper-trace';
|
export const EXPORT_FLIPPER_TRACE_EVENT = 'export-flipper-trace';
|
||||||
@@ -621,15 +624,19 @@ async function startDeviceFlipperFolderExport() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type ExportEverythingEverywhereAllAtOnceStatus =
|
export type ExportEverythingEverywhereAllAtOnceStatus =
|
||||||
| 'logs'
|
| ['logs']
|
||||||
| 'files'
|
| ['files']
|
||||||
| 'state'
|
| ['state']
|
||||||
| 'archive'
|
| ['archive']
|
||||||
| 'done'
|
| ['upload']
|
||||||
| 'cancelled';
|
| ['support']
|
||||||
|
| ['done']
|
||||||
|
| ['error', string]
|
||||||
|
| ['cancelled'];
|
||||||
export async function exportEverythingEverywhereAllAtOnce(
|
export async function exportEverythingEverywhereAllAtOnce(
|
||||||
store: MiddlewareAPI,
|
store: MiddlewareAPI,
|
||||||
onStatusUpdate?: (status: ExportEverythingEverywhereAllAtOnceStatus) => void,
|
onStatusUpdate?: (...args: ExportEverythingEverywhereAllAtOnceStatus) => void,
|
||||||
|
openSupportRequest?: boolean,
|
||||||
) {
|
) {
|
||||||
const zip = new JSZip();
|
const zip = new JSZip();
|
||||||
|
|
||||||
@@ -704,12 +711,58 @@ export async function exportEverythingEverywhereAllAtOnce(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (openSupportRequest) {
|
||||||
|
if (exportedFilePath) {
|
||||||
|
onStatusUpdate?.('upload');
|
||||||
|
|
||||||
|
let everythingEverywhereAllAtOnceExportDownloadURL: string | undefined;
|
||||||
|
try {
|
||||||
|
everythingEverywhereAllAtOnceExportDownloadURL =
|
||||||
|
await getRenderHostInstance().flipperServer.exec(
|
||||||
|
'intern-cloud-upload',
|
||||||
|
exportedFilePath,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(
|
||||||
|
'exportEverythingEverywhereAllAtOnce -> failed to upload export to intern',
|
||||||
|
exportedFilePath,
|
||||||
|
);
|
||||||
|
notification.warn({
|
||||||
|
message: 'Failed to upload debug data',
|
||||||
|
description: `Flipper failed to upload debug export (${exportedFilePath}) automatically. Please, attach it to the support request manually in the comments after it is created.`,
|
||||||
|
duration: null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onStatusUpdate?.('support');
|
||||||
|
try {
|
||||||
|
await openSupportRequestForm(store.getState(), {
|
||||||
|
everythingEverywhereAllAtOnceExportDownloadURL,
|
||||||
|
});
|
||||||
|
onStatusUpdate?.('done');
|
||||||
|
} catch (e) {
|
||||||
|
console.error(
|
||||||
|
'exportEverythingEverywhereAllAtOnce -> failed to create a support request',
|
||||||
|
e,
|
||||||
|
);
|
||||||
|
onStatusUpdate?.('error', getStringFromErrorLike(e));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
notification.warn({
|
||||||
|
message: 'Export cancelled',
|
||||||
|
description: `Exporting Flipper debug data was cancelled. Flipper team will not be able to help you without this data. Please, restart the export.`,
|
||||||
|
duration: null,
|
||||||
|
});
|
||||||
|
onStatusUpdate?.('cancelled');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if (exportedFilePath) {
|
if (exportedFilePath) {
|
||||||
onStatusUpdate?.('done');
|
onStatusUpdate?.('done');
|
||||||
} else {
|
} else {
|
||||||
onStatusUpdate?.('cancelled');
|
onStatusUpdate?.('cancelled');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export async function startFileExport(dispatch: Store['dispatch']) {
|
export async function startFileExport(dispatch: Store['dispatch']) {
|
||||||
const file = await getRenderHostInstance().showSaveDialog?.({
|
const file = await getRenderHostInstance().showSaveDialog?.({
|
||||||
|
|||||||
Reference in New Issue
Block a user