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:
David Lechner
2022-05-12 12:33:21 -05:00
parent 65623f801d
commit edd8ebfd64
22 changed files with 673 additions and 468 deletions
+31 -16
View File
@@ -1,33 +1,48 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2022 The Pybricks Authors
import { getByLabelText, waitFor } from '@testing-library/dom';
import React from 'react';
import { testRender } from '../../test';
import Toolbar from './Toolbar';
describe('settings button', () => {
it('should open settings drawer', async () => {
describe('toolbar', () => {
it('should have bluetooth button', () => {
const [toolbar] = testRender(<Toolbar />);
const settingButton = toolbar.getByLabelText('Settings');
const runButton = toolbar.getByRole('button', { name: 'Bluetooth' });
expect(
toolbar.queryByRole('dialog', {
name: 'Settings & Help',
}),
).toBeNull();
expect(runButton).toBeDefined();
});
settingButton.click();
it('should have flash button', () => {
const [toolbar] = testRender(<Toolbar />);
const settingsDrawer = toolbar.getByRole('dialog', {
name: 'Settings & Help',
});
const runButton = toolbar.getByRole('button', { name: 'Flash' });
expect(settingsDrawer).toBeVisible();
expect(runButton).toBeDefined();
});
getByLabelText(settingsDrawer, 'Close').click();
it('should have run button', () => {
const [toolbar] = testRender(<Toolbar />);
await waitFor(() => expect(settingsDrawer).not.toBeVisible());
const runButton = toolbar.getByRole('button', { name: 'Run' });
expect(runButton).toBeDefined();
});
it('should have stop button', () => {
const [toolbar] = testRender(<Toolbar />);
const runButton = toolbar.getByRole('button', { name: 'Stop' });
expect(runButton).toBeDefined();
});
it('should have repl button', () => {
const [toolbar] = testRender(<Toolbar />);
const runButton = toolbar.getByRole('button', { name: 'REPL' });
expect(runButton).toBeDefined();
});
});
+1 -12
View File
@@ -2,21 +2,17 @@
// Copyright (c) 2020-2022 The Pybricks Authors
import { ButtonGroup } from '@blueprintjs/core';
import React, { useState } from 'react';
import SettingsDrawer from '../settings/SettingsDrawer';
import React from 'react';
import { preventBrowserNativeContextMenu } from '../utils/react';
import BluetoothButton from './buttons/bluetooth/BluetoothButton';
import FlashButton from './buttons/flash/FlashButton';
import ReplButton from './buttons/repl/ReplButton';
import RunButton from './buttons/run/RunButton';
import SettingsButton from './buttons/settings/SettingsButton';
import StopButton from './buttons/stop/StopButton';
import './toolbar.scss';
const Toolbar: React.VFC = (_props) => {
const [isSettingsDrawerOpen, setIsSettingsDrawerOpen] = useState(false);
return (
<div
role="toolbar"
@@ -32,13 +28,6 @@ const Toolbar: React.VFC = (_props) => {
<StopButton />
<ReplButton />
</ButtonGroup>
<ButtonGroup className="pb-toolbar-group pb-align-right">
<SettingsButton onAction={() => setIsSettingsDrawerOpen(true)} />
<SettingsDrawer
isOpen={isSettingsDrawerOpen}
onClose={() => setIsSettingsDrawerOpen(false)}
/>
</ButtonGroup>
</div>
);
};
@@ -1,21 +0,0 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2022 The Pybricks Authors
import { cleanup } from '@testing-library/react';
import React from 'react';
import { testRender } from '../../../../test';
import SettingsButton from './SettingsButton';
afterEach(() => {
cleanup();
});
it('should invoke callback when clicked', () => {
const handleAction = jest.fn();
const [button] = testRender(<SettingsButton onAction={handleAction} />);
button.getByRole('button', { name: 'Settings' }).click();
expect(handleAction).toHaveBeenCalled();
});
@@ -1,28 +0,0 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2021-2022 The Pybricks Authors
import { useI18n } from '@shopify/react-i18n';
import React from 'react';
import ActionButton, { ActionButtonProps } from '../../ActionButton';
import { I18nId } from './i18n';
import icon from './icon.svg';
type SettingsButtonProps = Pick<ActionButtonProps, 'onAction'>;
const SettingsButton: React.VoidFunctionComponent<SettingsButtonProps> = ({
onAction,
}) => {
// istanbul ignore next: babel-loader rewrites this line
const [i18n] = useI18n();
return (
<ActionButton
label={i18n.translate(I18nId.Label)}
tooltip={i18n.translate(I18nId.Tooltip)}
icon={icon}
onAction={onAction}
/>
);
};
export default SettingsButton;
-12
View File
@@ -1,12 +0,0 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2020-2022 The Pybricks Authors
import { lookup } from '../../../../test';
import { I18nId } from './i18n';
import en from './translations/en.json';
describe('Ensure .json file has matches for I18nId', () => {
test.each(Object.values(I18nId))('%s', (id) => {
expect(lookup(en, id)).toBeDefined();
});
});
-7
View File
@@ -1,7 +0,0 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2020-2022 The Pybricks Authors
export enum I18nId {
Label = 'label',
Tooltip = 'tooltip',
}
-1
View File
@@ -1 +0,0 @@
<svg width="50" height="50" enable-background="new 0 0 20 20" version="1.1" viewBox="0 0 50 50" xmlns="http://www.w3.org/2000/svg"><g id="cog_2_" transform="matrix(2.25,0,0,2.25,2.5,2.5)" fill="#fff"><g fill="#fff"><path d="m19 8h-2.31c-0.14-0.46-0.33-0.89-0.56-1.3l1.7-1.7c0.39-0.39 0.39-1.02 0-1.41l-1.41-1.41c-0.39-0.39-1.02-0.39-1.41 0l-1.7 1.7c-0.41-0.22-0.84-0.41-1.3-0.55v-2.33c0-0.55-0.45-1-1-1h-2.01c-0.55 0-1 0.45-1 1v2.33c-0.48 0.14-0.94 0.34-1.37 0.58l-1.63-1.63c-0.37-0.37-0.98-0.37-1.36 0l-1.36 1.36c-0.37 0.38-0.37 0.99 0 1.36l1.62 1.62c-0.24 0.44-0.44 0.89-0.59 1.38h-2.31c-0.55 0-1 0.45-1 1v2c0 0.55 0.45 1 1 1h2.31c0.14 0.46 0.33 0.89 0.56 1.3l-1.7 1.7c-0.39 0.39-0.39 1.02 0 1.41l1.41 1.41c0.39 0.39 1.02 0.39 1.41 0l1.7-1.7c0.41 0.22 0.84 0.41 1.3 0.55v2.33c0 0.55 0.45 1 1 1h2c0.55 0 1-0.45 1-1v-2.33c0.48-0.14 0.94-0.35 1.37-0.59l1.64 1.64c0.37 0.37 0.98 0.37 1.36 0l1.36-1.36c0.37-0.37 0.37-0.98 0-1.36l-1.62-1.62c0.24-0.43 0.45-0.89 0.6-1.38h2.3c0.55 0 1-0.45 1-1v-2c0-0.55-0.45-1-1-1zm-9 6c-2.21 0-4-1.79-4-4s1.79-4 4-4 4 1.79 4 4-1.79 4-4 4z" clip-rule="evenodd" fill="#fff" fill-rule="evenodd"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

@@ -1,4 +0,0 @@
{
"label": "Settings",
"tooltip": "Open settings and help"
}
+9 -20
View File
@@ -7,11 +7,16 @@
@use '../variables' as pb;
.pb-toolbar {
height: pb.$toolbar-height;
padding: 0 bp.$pt-grid-size * 1.5;
position: relative;
width: 100%;
padding: bp.$pt-grid-size bp.$pt-grid-size * 1.5;
z-index: bp.$pt-z-index-content;
// make small buttons more square and slightly smaller (some of this is
// done in react)
@media screen and (max-width: pb.$narrow-screen-limit) {
.#{bp.$ns}-button {
padding: 5px;
}
}
}
.pb-toolbar * {
@@ -20,7 +25,6 @@
.pb-toolbar-group {
align-items: center;
height: 100%;
&.pb-align-left {
float: left;
@@ -32,18 +36,3 @@
margin-left: bp.$pt-grid-size * 2;
}
}
// make small buttons more square and slightly smaller
@media screen and (max-width: 700px) {
.pb-toolbar .#{bp.$ns}-button {
padding: 5px;
}
}
// this is the point where the buttons start wrapping to 2 rows so we need to
// adjust the height so that they stay in the toolbar
@media screen and (max-width: 350px) {
.pb-toolbar-group {
height: 50%;
}
}