mirror of
https://github.com/pybricks/pybricks-code.git
synced 2026-09-14 10:35:11 +00:00
Add Activities
This adds a new Activities tab list and view similar to VS code. The Explorer and Settings are migrated to this view.
This commit is contained in:
@@ -5,7 +5,7 @@ import { cleanup, getByLabelText, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import React from 'react';
|
||||
import { testRender } from '../../test';
|
||||
import SettingsDrawer from './SettingsDrawer';
|
||||
import Settings from './Settings';
|
||||
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
@@ -14,9 +14,7 @@ afterEach(() => {
|
||||
|
||||
describe('showDocs setting switch', () => {
|
||||
it('should toggle setting', async () => {
|
||||
const [settings] = testRender(
|
||||
<SettingsDrawer isOpen={true} onClose={() => undefined} />,
|
||||
);
|
||||
const [settings] = testRender(<Settings />);
|
||||
|
||||
const showDocs = settings.getByLabelText('Documentation');
|
||||
expect(showDocs).toBeChecked();
|
||||
@@ -28,9 +26,7 @@ describe('showDocs setting switch', () => {
|
||||
|
||||
describe('darkMode setting switch', () => {
|
||||
it('should toggle setting', async () => {
|
||||
const [settings] = testRender(
|
||||
<SettingsDrawer isOpen={true} onClose={() => undefined} />,
|
||||
);
|
||||
const [settings] = testRender(<Settings />);
|
||||
|
||||
const darkMode = settings.getByLabelText('Dark mode');
|
||||
expect(darkMode).not.toBeChecked();
|
||||
@@ -45,11 +41,10 @@ describe('darkMode setting switch', () => {
|
||||
expect(localStorage.getItem('usehooks-ts-ternary-dark-mode')).toBe('"light"');
|
||||
});
|
||||
});
|
||||
|
||||
describe('flashCurrentProgram setting switch', () => {
|
||||
it('should toggle the setting', () => {
|
||||
const [settings] = testRender(
|
||||
<SettingsDrawer isOpen={true} onClose={() => undefined} />,
|
||||
);
|
||||
const [settings] = testRender(<Settings />);
|
||||
|
||||
expect(localStorage.getItem('setting.flashCurrentProgram')).toBe(null);
|
||||
|
||||
@@ -66,9 +61,7 @@ describe('hubName setting', () => {
|
||||
// old settings did not use json format, so lack quotes
|
||||
localStorage.setItem('setting.hubName', 'old name');
|
||||
|
||||
const [settings] = testRender(
|
||||
<SettingsDrawer isOpen={true} onClose={() => undefined} />,
|
||||
);
|
||||
const [settings] = testRender(<Settings />);
|
||||
|
||||
const textBox = settings.getByLabelText('Hub name');
|
||||
|
||||
@@ -76,9 +69,7 @@ describe('hubName setting', () => {
|
||||
});
|
||||
|
||||
it('should update the setting', () => {
|
||||
const [settings] = testRender(
|
||||
<SettingsDrawer isOpen={true} onClose={() => undefined} />,
|
||||
);
|
||||
const [settings] = testRender(<Settings />);
|
||||
|
||||
expect(localStorage.getItem('setting.hubName')).toBe(null);
|
||||
|
||||
@@ -91,9 +82,7 @@ describe('hubName setting', () => {
|
||||
|
||||
describe('about dialog', () => {
|
||||
it('should open the dialog when the button is clicked', async () => {
|
||||
const [settings] = testRender(
|
||||
<SettingsDrawer isOpen={true} onClose={() => undefined} />,
|
||||
);
|
||||
const [settings] = testRender(<Settings />);
|
||||
|
||||
const appName = process.env.REACT_APP_NAME;
|
||||
|
||||
@@ -0,0 +1,259 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2021-2022 The Pybricks Authors
|
||||
|
||||
import {
|
||||
AnchorButton,
|
||||
Button,
|
||||
ButtonGroup,
|
||||
ControlGroup,
|
||||
FormGroup,
|
||||
Icon,
|
||||
InputGroup,
|
||||
Intent,
|
||||
Label,
|
||||
Switch,
|
||||
} from '@blueprintjs/core';
|
||||
import { Tooltip2 } from '@blueprintjs/popover2';
|
||||
import { useI18n } from '@shopify/react-i18n';
|
||||
import React, { useState } from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { useTernaryDarkMode } from 'usehooks-ts';
|
||||
import AboutDialog from '../about/AboutDialog';
|
||||
import { appCheckForUpdate, appReload, appShowInstallPrompt } from '../app/actions';
|
||||
import {
|
||||
pybricksBugReportsUrl,
|
||||
pybricksGitterUrl,
|
||||
pybricksProjectsUrl,
|
||||
pybricksSupportUrl,
|
||||
tooltipDelay,
|
||||
} from '../app/constants';
|
||||
import { pseudolocalize } from '../i18n';
|
||||
import { useSelector } from '../reducers';
|
||||
import ExternalLinkIcon from '../utils/ExternalLinkIcon';
|
||||
import { isMacOS } from '../utils/os';
|
||||
import {
|
||||
useSettingFlashCurrentProgram,
|
||||
useSettingHubName,
|
||||
useSettingIsShowDocsEnabled,
|
||||
} from './hooks';
|
||||
import { I18nId } from './i18n';
|
||||
import './settings.scss';
|
||||
|
||||
const Settings: React.VoidFunctionComponent = () => {
|
||||
const { isSettingShowDocsEnabled, setIsSettingShowDocsEnabled } =
|
||||
useSettingIsShowDocsEnabled();
|
||||
const [isAboutDialogOpen, setIsAboutDialogOpen] = useState(false);
|
||||
const { isDarkMode, setTernaryDarkMode } = useTernaryDarkMode();
|
||||
|
||||
const [isFlashCurrentProgramEnabled, setIsFlashCurrentProgramEnabled] =
|
||||
useSettingFlashCurrentProgram();
|
||||
const isServiceWorkerRegistered = useSelector(
|
||||
(s) => s.app.isServiceWorkerRegistered,
|
||||
);
|
||||
const checkingForUpdate = useSelector((s) => s.app.checkingForUpdate);
|
||||
const updateAvailable = useSelector((s) => s.app.updateAvailable);
|
||||
const hasUnresolvedInstallPrompt = useSelector(
|
||||
(s) => s.app.hasUnresolvedInstallPrompt,
|
||||
);
|
||||
const promptingInstall = useSelector((s) => s.app.promptingInstall);
|
||||
const readyForOfflineUse = useSelector((s) => s.app.readyForOfflineUse);
|
||||
const { hubName, isHubNameValid, setHubName } = useSettingHubName();
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
// istanbul ignore next: babel-loader rewrites this line
|
||||
const [i18n] = useI18n();
|
||||
|
||||
return (
|
||||
<div aria-label={i18n.translate(I18nId.Title)}>
|
||||
<FormGroup
|
||||
label={i18n.translate(I18nId.AppearanceTitle)}
|
||||
helperText={i18n.translate(I18nId.AppearanceZoomHelp, {
|
||||
in: <span>{isMacOS() ? 'Cmd' : 'Ctrl'}-+</span>,
|
||||
out: <span>{isMacOS() ? 'Cmd' : 'Ctrl'}--</span>,
|
||||
})}
|
||||
>
|
||||
<Tooltip2
|
||||
content={i18n.translate(I18nId.AppearanceDocumentationTooltip)}
|
||||
rootBoundary="document"
|
||||
placement="left"
|
||||
targetTagName="div"
|
||||
hoverOpenDelay={tooltipDelay}
|
||||
>
|
||||
<Switch
|
||||
label={i18n.translate(I18nId.AppearanceDocumentationLabel)}
|
||||
checked={isSettingShowDocsEnabled}
|
||||
onChange={(e) =>
|
||||
setIsSettingShowDocsEnabled(
|
||||
(e.target as HTMLInputElement).checked,
|
||||
)
|
||||
}
|
||||
/>
|
||||
</Tooltip2>
|
||||
<Tooltip2
|
||||
content={i18n.translate(I18nId.AppearanceDarkModeTooltip)}
|
||||
rootBoundary="document"
|
||||
placement="left"
|
||||
targetTagName="div"
|
||||
hoverOpenDelay={tooltipDelay}
|
||||
>
|
||||
<Switch
|
||||
label={i18n.translate(I18nId.AppearanceDarkModeLabel)}
|
||||
checked={isDarkMode}
|
||||
onChange={(e) =>
|
||||
setTernaryDarkMode(
|
||||
(e.target as HTMLInputElement).checked
|
||||
? 'dark'
|
||||
: 'light',
|
||||
)
|
||||
}
|
||||
/>
|
||||
</Tooltip2>
|
||||
</FormGroup>
|
||||
<FormGroup label={i18n.translate(I18nId.FirmwareTitle)}>
|
||||
<Tooltip2
|
||||
content={i18n.translate(I18nId.FirmwareCurrentProgramTooltip)}
|
||||
rootBoundary="document"
|
||||
placement="left"
|
||||
targetTagName="div"
|
||||
hoverOpenDelay={tooltipDelay}
|
||||
>
|
||||
<Switch
|
||||
label={i18n.translate(I18nId.FirmwareCurrentProgramLabel)}
|
||||
checked={isFlashCurrentProgramEnabled}
|
||||
onChange={(e) =>
|
||||
setIsFlashCurrentProgramEnabled(
|
||||
(e.target as HTMLInputElement).checked,
|
||||
)
|
||||
}
|
||||
/>
|
||||
</Tooltip2>
|
||||
<ControlGroup vertical={true}>
|
||||
<Tooltip2
|
||||
content={i18n.translate(I18nId.FirmwareHubNameTooltip)}
|
||||
rootBoundary="document"
|
||||
placement="left"
|
||||
targetTagName="div"
|
||||
hoverOpenDelay={tooltipDelay}
|
||||
openOnTargetFocus={false}
|
||||
>
|
||||
<Label htmlFor="hub-name-input">
|
||||
{i18n.translate(I18nId.FirmwareHubNameLabel)}
|
||||
</Label>
|
||||
</Tooltip2>
|
||||
<InputGroup
|
||||
id="hub-name-input"
|
||||
value={hubName}
|
||||
onChange={(e) => setHubName(e.currentTarget.value)}
|
||||
onMouseOver={(e) => e.preventDefault()}
|
||||
className="pb-hub-name-input"
|
||||
intent={isHubNameValid ? Intent.NONE : Intent.DANGER}
|
||||
placeholder="Pybricks Hub"
|
||||
rightElement={
|
||||
isHubNameValid ? undefined : (
|
||||
<Tooltip2
|
||||
content={i18n.translate(
|
||||
I18nId.FirmwareHubNameErrorTooltip,
|
||||
)}
|
||||
rootBoundary="document"
|
||||
placement="bottom"
|
||||
targetTagName="div"
|
||||
>
|
||||
<Icon
|
||||
icon="error"
|
||||
intent={Intent.DANGER}
|
||||
itemType="div"
|
||||
/>
|
||||
</Tooltip2>
|
||||
)
|
||||
}
|
||||
/>
|
||||
</ControlGroup>
|
||||
</FormGroup>
|
||||
<FormGroup label={i18n.translate(I18nId.HelpTitle)}>
|
||||
<ButtonGroup minimal={true} vertical={true} alignText="left">
|
||||
<AnchorButton
|
||||
icon="lightbulb"
|
||||
href={pybricksProjectsUrl}
|
||||
target="blank_"
|
||||
>
|
||||
{i18n.translate(I18nId.HelpProjectsLabel)}
|
||||
<ExternalLinkIcon />
|
||||
</AnchorButton>
|
||||
<AnchorButton icon="help" href={pybricksSupportUrl} target="blank_">
|
||||
{i18n.translate(I18nId.HelpSupportLabel)}
|
||||
<ExternalLinkIcon />
|
||||
</AnchorButton>
|
||||
<AnchorButton icon="chat" href={pybricksGitterUrl} target="blank_">
|
||||
{i18n.translate(I18nId.HelpChatLabel)}
|
||||
<ExternalLinkIcon />
|
||||
</AnchorButton>
|
||||
<AnchorButton
|
||||
icon="virus"
|
||||
href={pybricksBugReportsUrl}
|
||||
target="blank_"
|
||||
>
|
||||
{i18n.translate(I18nId.HelpBugsLabel)}
|
||||
<ExternalLinkIcon />
|
||||
</AnchorButton>
|
||||
<AboutDialog
|
||||
isOpen={isAboutDialogOpen}
|
||||
onClose={() => setIsAboutDialogOpen(false)}
|
||||
/>
|
||||
</ButtonGroup>
|
||||
</FormGroup>
|
||||
<FormGroup
|
||||
label={i18n.translate(I18nId.AppTitle)}
|
||||
helperText={
|
||||
readyForOfflineUse && i18n.translate(I18nId.AppOfflineUseHelp)
|
||||
}
|
||||
>
|
||||
<ButtonGroup minimal={true} vertical={true} alignText="left">
|
||||
{hasUnresolvedInstallPrompt && (
|
||||
<Button
|
||||
icon="add"
|
||||
onClick={() => dispatch(appShowInstallPrompt())}
|
||||
loading={promptingInstall}
|
||||
>
|
||||
{i18n.translate(I18nId.AppInstallLabel)}
|
||||
</Button>
|
||||
)}
|
||||
{isServiceWorkerRegistered && !updateAvailable && (
|
||||
<Button
|
||||
icon="refresh"
|
||||
onClick={() => dispatch(appCheckForUpdate())}
|
||||
loading={checkingForUpdate}
|
||||
>
|
||||
{i18n.translate(I18nId.AppCheckForUpdateLabel)}
|
||||
</Button>
|
||||
)}
|
||||
{isServiceWorkerRegistered && updateAvailable && (
|
||||
<Button icon="refresh" onClick={() => dispatch(appReload())}>
|
||||
{i18n.translate(I18nId.AppRestartLabel)}
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
icon="info-sign"
|
||||
onClick={() => {
|
||||
setIsAboutDialogOpen(true);
|
||||
return true;
|
||||
}}
|
||||
>
|
||||
{i18n.translate(I18nId.AppAboutLabel)}
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</FormGroup>
|
||||
{process.env.NODE_ENV === 'development' && (
|
||||
<FormGroup label="Developer">
|
||||
<Switch
|
||||
checked={i18n.pseudolocalize !== false}
|
||||
onChange={() => pseudolocalize(!i18n.pseudolocalize)}
|
||||
label="Pseudolocalize"
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Settings;
|
||||
@@ -1,317 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2021-2022 The Pybricks Authors
|
||||
|
||||
import {
|
||||
AnchorButton,
|
||||
Button,
|
||||
ButtonGroup,
|
||||
Classes,
|
||||
ControlGroup,
|
||||
Drawer,
|
||||
DrawerSize,
|
||||
FormGroup,
|
||||
Icon,
|
||||
InputGroup,
|
||||
Intent,
|
||||
Label,
|
||||
Switch,
|
||||
} from '@blueprintjs/core';
|
||||
import { Tooltip2 } from '@blueprintjs/popover2';
|
||||
import { useI18n } from '@shopify/react-i18n';
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { useTernaryDarkMode } from 'usehooks-ts';
|
||||
import AboutDialog from '../about/AboutDialog';
|
||||
import { appCheckForUpdate, appReload, appShowInstallPrompt } from '../app/actions';
|
||||
import {
|
||||
pybricksBugReportsUrl,
|
||||
pybricksGitterUrl,
|
||||
pybricksProjectsUrl,
|
||||
pybricksSupportUrl,
|
||||
tooltipDelay,
|
||||
} from '../app/constants';
|
||||
import { pseudolocalize } from '../i18n';
|
||||
import { useSelector } from '../reducers';
|
||||
import ExternalLinkIcon from '../utils/ExternalLinkIcon';
|
||||
import { isMacOS } from '../utils/os';
|
||||
import {
|
||||
useSettingFlashCurrentProgram,
|
||||
useSettingHubName,
|
||||
useSettingIsShowDocsEnabled,
|
||||
} from './hooks';
|
||||
import { I18nId } from './i18n';
|
||||
import './settings.scss';
|
||||
|
||||
type SettingsProps = {
|
||||
isOpen: boolean;
|
||||
onClose(): void;
|
||||
};
|
||||
|
||||
const SettingsDrawer: React.VoidFunctionComponent<SettingsProps> = ({
|
||||
isOpen,
|
||||
onClose,
|
||||
}) => {
|
||||
const { isSettingShowDocsEnabled, setIsSettingShowDocsEnabled } =
|
||||
useSettingIsShowDocsEnabled();
|
||||
const [isAboutDialogOpen, setIsAboutDialogOpen] = useState(false);
|
||||
const { isDarkMode, setTernaryDarkMode } = useTernaryDarkMode();
|
||||
|
||||
const [isFlashCurrentProgramEnabled, setIsFlashCurrentProgramEnabled] =
|
||||
useSettingFlashCurrentProgram();
|
||||
const isServiceWorkerRegistered = useSelector(
|
||||
(s) => s.app.isServiceWorkerRegistered,
|
||||
);
|
||||
const checkingForUpdate = useSelector((s) => s.app.checkingForUpdate);
|
||||
const updateAvailable = useSelector((s) => s.app.updateAvailable);
|
||||
const hasUnresolvedInstallPrompt = useSelector(
|
||||
(s) => s.app.hasUnresolvedInstallPrompt,
|
||||
);
|
||||
const promptingInstall = useSelector((s) => s.app.promptingInstall);
|
||||
const readyForOfflineUse = useSelector((s) => s.app.readyForOfflineUse);
|
||||
const { hubName, isHubNameValid, setHubName } = useSettingHubName();
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
// istanbul ignore next: babel-loader rewrites this line
|
||||
const [i18n] = useI18n();
|
||||
|
||||
// HACK: set additional attributes that are not supported via Drawer props
|
||||
const handleDrawerOpening = useCallback<(node: HTMLElement) => void>((n) => {
|
||||
n.setAttribute('role', 'dialog');
|
||||
n.setAttribute('aria-modal', 'true');
|
||||
n.setAttribute('aria-labelledby', 'settings-drawer-dialog-title');
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Drawer
|
||||
isOpen={isOpen}
|
||||
icon="cog"
|
||||
size={DrawerSize.SMALL}
|
||||
title={
|
||||
<span id="settings-drawer-dialog-title">
|
||||
{i18n.translate(I18nId.Title)}
|
||||
</span>
|
||||
}
|
||||
onOpening={handleDrawerOpening}
|
||||
onClose={onClose}
|
||||
// work around https://github.com/palantir/blueprint/issues/5169
|
||||
shouldReturnFocusOnClose={false}
|
||||
>
|
||||
<div className={Classes.DRAWER_BODY}>
|
||||
<div className={Classes.DIALOG_BODY}>
|
||||
<FormGroup
|
||||
label={i18n.translate(I18nId.AppearanceTitle)}
|
||||
helperText={i18n.translate(I18nId.AppearanceZoomHelp, {
|
||||
in: <span>{isMacOS() ? 'Cmd' : 'Ctrl'}-+</span>,
|
||||
out: <span>{isMacOS() ? 'Cmd' : 'Ctrl'}--</span>,
|
||||
})}
|
||||
>
|
||||
<Tooltip2
|
||||
content={i18n.translate(
|
||||
I18nId.AppearanceDocumentationTooltip,
|
||||
)}
|
||||
rootBoundary="document"
|
||||
placement="left"
|
||||
targetTagName="div"
|
||||
hoverOpenDelay={tooltipDelay}
|
||||
>
|
||||
<Switch
|
||||
label={i18n.translate(
|
||||
I18nId.AppearanceDocumentationLabel,
|
||||
)}
|
||||
checked={isSettingShowDocsEnabled}
|
||||
onChange={(e) =>
|
||||
setIsSettingShowDocsEnabled(
|
||||
(e.target as HTMLInputElement).checked,
|
||||
)
|
||||
}
|
||||
/>
|
||||
</Tooltip2>
|
||||
<Tooltip2
|
||||
content={i18n.translate(I18nId.AppearanceDarkModeTooltip)}
|
||||
rootBoundary="document"
|
||||
placement="left"
|
||||
targetTagName="div"
|
||||
hoverOpenDelay={tooltipDelay}
|
||||
>
|
||||
<Switch
|
||||
label={i18n.translate(I18nId.AppearanceDarkModeLabel)}
|
||||
checked={isDarkMode}
|
||||
onChange={(e) =>
|
||||
setTernaryDarkMode(
|
||||
(e.target as HTMLInputElement).checked
|
||||
? 'dark'
|
||||
: 'light',
|
||||
)
|
||||
}
|
||||
/>
|
||||
</Tooltip2>
|
||||
</FormGroup>
|
||||
<FormGroup label={i18n.translate(I18nId.FirmwareTitle)}>
|
||||
<Tooltip2
|
||||
content={i18n.translate(
|
||||
I18nId.FirmwareCurrentProgramTooltip,
|
||||
)}
|
||||
rootBoundary="document"
|
||||
placement="left"
|
||||
targetTagName="div"
|
||||
hoverOpenDelay={tooltipDelay}
|
||||
>
|
||||
<Switch
|
||||
label={i18n.translate(
|
||||
I18nId.FirmwareCurrentProgramLabel,
|
||||
)}
|
||||
checked={isFlashCurrentProgramEnabled}
|
||||
onChange={(e) =>
|
||||
setIsFlashCurrentProgramEnabled(
|
||||
(e.target as HTMLInputElement).checked,
|
||||
)
|
||||
}
|
||||
/>
|
||||
</Tooltip2>
|
||||
<ControlGroup>
|
||||
<Tooltip2
|
||||
content={i18n.translate(I18nId.FirmwareHubNameTooltip)}
|
||||
rootBoundary="document"
|
||||
placement="left"
|
||||
targetTagName="div"
|
||||
hoverOpenDelay={tooltipDelay}
|
||||
openOnTargetFocus={false}
|
||||
>
|
||||
<Label
|
||||
className={Classes.INLINE}
|
||||
htmlFor="hub-name-input"
|
||||
>
|
||||
{i18n.translate(I18nId.FirmwareHubNameLabel)}
|
||||
</Label>
|
||||
</Tooltip2>
|
||||
<InputGroup
|
||||
id="hub-name-input"
|
||||
value={hubName}
|
||||
onChange={(e) => setHubName(e.currentTarget.value)}
|
||||
onMouseOver={(e) => e.preventDefault()}
|
||||
className="pb-hub-name-input"
|
||||
intent={isHubNameValid ? Intent.NONE : Intent.DANGER}
|
||||
placeholder="Pybricks Hub"
|
||||
rightElement={
|
||||
isHubNameValid ? undefined : (
|
||||
<Tooltip2
|
||||
content={i18n.translate(
|
||||
I18nId.FirmwareHubNameErrorTooltip,
|
||||
)}
|
||||
rootBoundary="document"
|
||||
placement="bottom"
|
||||
targetTagName="div"
|
||||
>
|
||||
<Icon
|
||||
icon="error"
|
||||
intent={Intent.DANGER}
|
||||
itemType="div"
|
||||
/>
|
||||
</Tooltip2>
|
||||
)
|
||||
}
|
||||
/>
|
||||
</ControlGroup>
|
||||
</FormGroup>
|
||||
<FormGroup label={i18n.translate(I18nId.HelpTitle)}>
|
||||
<ButtonGroup minimal={true} vertical={true} alignText="left">
|
||||
<AnchorButton
|
||||
icon="lightbulb"
|
||||
href={pybricksProjectsUrl}
|
||||
target="blank_"
|
||||
>
|
||||
{i18n.translate(I18nId.HelpProjectsLabel)}
|
||||
<ExternalLinkIcon />
|
||||
</AnchorButton>
|
||||
<AnchorButton
|
||||
icon="help"
|
||||
href={pybricksSupportUrl}
|
||||
target="blank_"
|
||||
>
|
||||
{i18n.translate(I18nId.HelpSupportLabel)}
|
||||
<ExternalLinkIcon />
|
||||
</AnchorButton>
|
||||
<AnchorButton
|
||||
icon="chat"
|
||||
href={pybricksGitterUrl}
|
||||
target="blank_"
|
||||
>
|
||||
{i18n.translate(I18nId.HelpChatLabel)}
|
||||
<ExternalLinkIcon />
|
||||
</AnchorButton>
|
||||
<AnchorButton
|
||||
icon="virus"
|
||||
href={pybricksBugReportsUrl}
|
||||
target="blank_"
|
||||
>
|
||||
{i18n.translate(I18nId.HelpBugsLabel)}
|
||||
<ExternalLinkIcon />
|
||||
</AnchorButton>
|
||||
<AboutDialog
|
||||
isOpen={isAboutDialogOpen}
|
||||
onClose={() => setIsAboutDialogOpen(false)}
|
||||
/>
|
||||
</ButtonGroup>
|
||||
</FormGroup>
|
||||
<FormGroup
|
||||
label={i18n.translate(I18nId.AppTitle)}
|
||||
helperText={
|
||||
readyForOfflineUse &&
|
||||
i18n.translate(I18nId.AppOfflineUseHelp)
|
||||
}
|
||||
>
|
||||
<ButtonGroup minimal={true} vertical={true} alignText="left">
|
||||
{hasUnresolvedInstallPrompt && (
|
||||
<Button
|
||||
icon="add"
|
||||
onClick={() => dispatch(appShowInstallPrompt())}
|
||||
loading={promptingInstall}
|
||||
>
|
||||
{i18n.translate(I18nId.AppInstallLabel)}
|
||||
</Button>
|
||||
)}
|
||||
{isServiceWorkerRegistered && !updateAvailable && (
|
||||
<Button
|
||||
icon="refresh"
|
||||
onClick={() => dispatch(appCheckForUpdate())}
|
||||
loading={checkingForUpdate}
|
||||
>
|
||||
{i18n.translate(I18nId.AppCheckForUpdateLabel)}
|
||||
</Button>
|
||||
)}
|
||||
{isServiceWorkerRegistered && updateAvailable && (
|
||||
<Button
|
||||
icon="refresh"
|
||||
onClick={() => dispatch(appReload())}
|
||||
>
|
||||
{i18n.translate(I18nId.AppRestartLabel)}
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
icon="info-sign"
|
||||
onClick={() => {
|
||||
setIsAboutDialogOpen(true);
|
||||
return true;
|
||||
}}
|
||||
>
|
||||
{i18n.translate(I18nId.AppAboutLabel)}
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</FormGroup>
|
||||
{process.env.NODE_ENV === 'development' && (
|
||||
<FormGroup label="Developer">
|
||||
<Switch
|
||||
checked={i18n.pseudolocalize !== false}
|
||||
onChange={() => pseudolocalize(!i18n.pseudolocalize)}
|
||||
label="Pseudolocalize"
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Drawer>
|
||||
);
|
||||
};
|
||||
|
||||
export default SettingsDrawer;
|
||||
Reference in New Issue
Block a user