addons/isl/src/BugButton.tsxblame
View source
b69ab311/**
b69ab312 * Copyright (c) Meta Platforms, Inc. and affiliates.
b69ab313 *
b69ab314 * This source code is licensed under the MIT license found in the
b69ab315 * LICENSE file in the root directory of this source tree.
b69ab316 */
b69ab317
b69ab318import type {Heartbeat} from './heartbeat';
b69ab319
b69ab3110import * as stylex from '@stylexjs/stylex';
b69ab3111import {Button} from 'isl-components/Button';
b69ab3112import {ErrorNotice} from 'isl-components/ErrorNotice';
b69ab3113import {Icon} from 'isl-components/Icon';
b69ab3114import {Tooltip} from 'isl-components/Tooltip';
b69ab3115import {useAtomValue} from 'jotai';
b69ab3116import {Copyable} from './Copyable';
b69ab3117import {DropdownFields} from './DropdownFields';
b69ab3118import {Internal} from './Internal';
b69ab3119import {DEFAULT_HEARTBEAT_TIMEOUT_MS, useHeartbeat} from './heartbeat';
b69ab3120import {t, T} from './i18n';
b69ab3121import platform from './platform';
b69ab3122import {applicationinfo} from './serverAPIState';
b69ab3123
b69ab3124import './BugButton.css';
b69ab3125
b69ab3126const styles = stylex.create({
b69ab3127 centered: {
b69ab3128 justifyContent: 'center',
b69ab3129 },
b69ab3130});
b69ab3131
b69ab3132export function BugButton() {
b69ab3133 return (
b69ab3134 <Tooltip
b69ab3135 trigger="click"
b69ab3136 component={dismiss => <BugDropdown dismiss={dismiss} />}
b69ab3137 group="topbar"
b69ab3138 placement="bottom">
b69ab3139 <Button icon data-testid="bug-button">
b69ab3140 <Icon icon="bug" />
b69ab3141 </Button>
b69ab3142 </Tooltip>
b69ab3143 );
b69ab3144}
b69ab3145
b69ab3146function BugDropdown({dismiss}: {dismiss: () => void}) {
b69ab3147 const heartbeat = useHeartbeat();
b69ab3148
b69ab3149 return (
b69ab3150 <DropdownFields
b69ab3151 title={<T>Help</T>}
b69ab3152 icon="bug"
b69ab3153 data-testid="bug-dropdown"
b69ab3154 className="bug-dropdown">
b69ab3155 <ISLVersion />
b69ab3156 <HeartbeatWarning heartbeat={heartbeat} />
b69ab3157 <div className="bug-dropdown-actions">
b69ab3158 <FileABug dismissBugDropdown={dismiss} heartbeat={heartbeat} />
b69ab3159 </div>
b69ab3160 </DropdownFields>
b69ab3161 );
b69ab3162}
b69ab3163
b69ab3164function ISLVersion() {
b69ab3165 const info = useAtomValue(applicationinfo);
b69ab3166 if (info == null) {
b69ab3167 return <Icon icon="loading" />;
b69ab3168 }
b69ab3169
b69ab3170 return (
b69ab3171 <div className="bug-dropdown-version">
b69ab3172 <Copyable children={`ISL version ${info.version} (${info.platformName})`} />
b69ab3173 </div>
b69ab3174 );
b69ab3175}
b69ab3176
b69ab3177function HeartbeatWarning({heartbeat}: {heartbeat: Heartbeat}) {
b69ab3178 const appInfo = useAtomValue(applicationinfo);
b69ab3179 if (heartbeat.type === 'timeout') {
b69ab3180 return (
b69ab3181 <>
b69ab3182 <ErrorNotice
b69ab3183 error={new Error(t(`Heartbeat timed out after ${DEFAULT_HEARTBEAT_TIMEOUT_MS}ms`))}
b69ab3184 title={t("Can't reach server — most features won't work")}
b69ab3185 description={t('The ISL server needs to be restarted')}></ErrorNotice>
b69ab3186 {appInfo && (
b69ab3187 <div>
b69ab3188 <T
b69ab3189 replace={{
b69ab3190 $logfile: (
b69ab3191 <code>
b69ab3192 <Copyable className="log-file-path">{appInfo.logFilePath}</Copyable>
b69ab3193 </code>
b69ab3194 ),
b69ab3195 }}>
b69ab3196 Your log file is located at: $logfile
b69ab3197 </T>
b69ab3198 </div>
b69ab3199 )}
b69ab31100 </>
b69ab31101 );
b69ab31102 }
b69ab31103 return null;
b69ab31104}
b69ab31105
b69ab31106function FileABug({
b69ab31107 dismissBugDropdown,
b69ab31108 heartbeat,
b69ab31109}: {
b69ab31110 dismissBugDropdown: () => void;
b69ab31111 heartbeat: Heartbeat;
b69ab31112}) {
b69ab31113 return Internal.FileABugButton != null ? (
b69ab31114 <Internal.FileABugButton dismissBugDropdown={dismissBugDropdown} heartbeat={heartbeat} />
b69ab31115 ) : (
b69ab31116 <OSSFileABug />
b69ab31117 );
b69ab31118}
b69ab31119
b69ab31120function OSSFileABug() {
b69ab31121 return (
b69ab31122 <>
b69ab31123 <Button
b69ab31124 xstyle={styles.centered}
b69ab31125 onClick={() => {
b69ab31126 platform.openExternalLink('https://sapling-scm.com/docs/addons/isl');
b69ab31127 }}>
b69ab31128 <Icon icon="book" slot="start" />
b69ab31129 <T>View Documentation</T>
b69ab31130 </Button>
b69ab31131 <Button
b69ab31132 xstyle={styles.centered}
b69ab31133 onClick={() => {
b69ab31134 platform.openExternalLink('https://discord.gg/X6baZ94Vzh');
b69ab31135 }}>
b69ab31136 <Icon icon="comment-discussion" slot="start" />
b69ab31137 <T>Help and Feedback on Discord</T>
b69ab31138 </Button>
b69ab31139 <Button
b69ab31140 xstyle={styles.centered}
b69ab31141 onClick={() => {
b69ab31142 platform.openExternalLink('https://github.com/facebook/sapling/issues');
b69ab31143 }}>
b69ab31144 <Icon icon="bug" slot="start" />
b69ab31145 <T>Report an Issue on GitHub</T>
b69ab31146 </Button>
b69ab31147 </>
b69ab31148 );
b69ab31149}