Update setup and createTable tutorial to 100% Sandy
Summary: The current desktop plugin tutorial was outdated as it has several steps that are now automated, and still referred to old APIs. This has been updated now. Additionally left the intermediate code of the tutorial in the plugin, but splitting `index.tsx` into `index_table.tsx` and `index_custom.tsx` (which will be updated in the next diff) Clarified the tutorial page labels a little bit to show that 3 pages are covering the Desktop plugin development process. Changelog: Updated the Desktop plugin tutorial Reviewed By: jknoxville Differential Revision: D28990029 fbshipit-source-id: a06a7a774ceca3daf10f8e8fbd4e03191dbfd1cc
This commit is contained in:
committed by
Facebook GitHub Bot
parent
0ba08150f6
commit
a0c872dd38
@@ -5,7 +5,7 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"main": "dist/bundle.js",
|
"main": "dist/bundle.js",
|
||||||
"flipperBundlerEntry": "src/index.tsx",
|
"flipperBundlerEntry": "src/index_table.tsx",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"flipper-plugin"
|
"flipper-plugin"
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import {act} from '@testing-library/react';
|
|||||||
}
|
}
|
||||||
|
|
||||||
import {TestUtils} from 'flipper-plugin';
|
import {TestUtils} from 'flipper-plugin';
|
||||||
import * as MammalsPlugin from '..';
|
import * as MammalsPlugin from '../index_custom';
|
||||||
|
|
||||||
test('It can store rows', () => {
|
test('It can store rows', () => {
|
||||||
const {instance, sendEvent} = TestUtils.startPlugin(MammalsPlugin);
|
const {instance, sendEvent} = TestUtils.startPlugin(MammalsPlugin);
|
||||||
|
|||||||
43
desktop/plugins/public/seamammals/src/index_table.tsx
Normal file
43
desktop/plugins/public/seamammals/src/index_table.tsx
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*
|
||||||
|
* @format
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {DataTableColumn, createTablePlugin} from 'flipper-plugin';
|
||||||
|
|
||||||
|
type Row = {
|
||||||
|
id: number;
|
||||||
|
title: string;
|
||||||
|
url: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const columns: DataTableColumn<Row>[] = [
|
||||||
|
{
|
||||||
|
key: 'title',
|
||||||
|
width: 150,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'url',
|
||||||
|
title: 'URL',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Table based plugin, based on the table tutorial:
|
||||||
|
* https://fbflipper.com/docs/tutorial/js-table
|
||||||
|
*
|
||||||
|
* For a custom Plugin layout, update this file according to the custom plugin tutorial:
|
||||||
|
* https://fbflipper.com/docs/tutorial/js-custom
|
||||||
|
*
|
||||||
|
* The full API of createTablePlugin can be found here:
|
||||||
|
* https://fbflipper.com/docs/extending/flipper-plugin#createtableplugin
|
||||||
|
*/
|
||||||
|
module.exports = createTablePlugin<Row>({
|
||||||
|
columns,
|
||||||
|
key: 'id',
|
||||||
|
method: 'newRow',
|
||||||
|
});
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
id: js-custom
|
id: js-custom
|
||||||
title: Building A Custom Desktop Plugin
|
title: Building A Custom Desktop Plugin
|
||||||
sidebar_label: Custom Plugin
|
sidebar_label: Desktop Plugin - Custom UI
|
||||||
---
|
---
|
||||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||||
import Link from '@docusaurus/Link';
|
import Link from '@docusaurus/Link';
|
||||||
|
|||||||
@@ -1,56 +1,39 @@
|
|||||||
---
|
---
|
||||||
id: js-setup
|
id: js-setup
|
||||||
title: Building a Desktop Plugin
|
title: Building a Desktop Plugin
|
||||||
sidebar_label: Building a Desktop Plugin
|
sidebar_label: Desktop Plugin - Setup
|
||||||
---
|
---
|
||||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||||
|
|
||||||
Now that we have the native side covered, let's display the data we're sending
|
Now that we have the native side covered, let's display the data we're sending
|
||||||
on the desktop side. You can check out the full workflow of building Flipper desktop
|
on the desktop side.
|
||||||
plugins here: https://fbflipper.com/docs/extending/js-setup.
|
|
||||||
|
|
||||||
<img alt="Custom cards UI for our sea mammals plugin" src={useBaseUrl("img/js-custom.png")} />
|
<img alt="Custom cards UI for our sea mammals plugin" src={useBaseUrl("img/js-custom.png")} />
|
||||||
|
|
||||||
## Dynamic Plugin loading
|
|
||||||
|
|
||||||
<FbInternalOnly>
|
<FbInternalOnly>
|
||||||
[FB-Only] After scaffolding and starting Flipper from source, no further steps are needed to setup the desktop plugin.
|
[FB-Only] After scaffolding and starting Flipper from source, no further steps are needed to setup the desktop plugin.
|
||||||
</FbInternalOnly>
|
</FbInternalOnly>
|
||||||
|
|
||||||
<OssOnly>
|
<OssOnly>
|
||||||
|
|
||||||
By default, Flipper will start with the plugins it was bundled with. You can
|
## Scaffolding a new Desktop plugin
|
||||||
configure it to also look for plugins in custom directories. To do that,
|
|
||||||
modify the `~/.flipper/config.json` file that is created the first time
|
|
||||||
you start Flipper and add a newly created directory the `pluginPaths` attribute.
|
|
||||||
|
|
||||||
Your file will then look something like this:
|
A new Flipper Desktop plugin can be scaffolded by running `npx flipper-pkg init` in the directory where you want to store the plugin sources (Don't run this command inside the Flipper repository itself!). For example:
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"pluginPaths": [
|
|
||||||
"~/Flipper/custom-plugins/"
|
|
||||||
],
|
|
||||||
...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Creating the Plugin Package
|
|
||||||
|
|
||||||
With the loading part out of the way, we can create the new plugin. For that, first create a new folder inside the custom plugins directory. Then use `flipper-pkg init` to initialise a new Flipper desktop plugin package.
|
|
||||||
`flipper-pkg` is a NPM module, so we can run it directly using `npx` if Node and NPM are installed.
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ cd ~/Flipper/custom-plugins/
|
mkdir ~/FlipperPlugins
|
||||||
$ npx flipper-pkg init
|
cd ~/FlipperPlugins
|
||||||
|
npx flipper-pkg init
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Add the directory to the Flipper watch folder if asked. In this tutorial we will be creating a `client` plugin. `device` plugins are only used when creating plugins that _don't_ connect to a specific application and are pretty rare.
|
||||||
|
|
||||||
The tool will ask you to provide "id" and "title" for your plugin. Use "sea-mammals" as "id" and "Sea Mammals" as "title". After that the tool will create two files in the directory: `package.json` and `src/index.tsx`.
|
The tool will ask you to provide "id" and "title" for your plugin. Use "sea-mammals" as "id" and "Sea Mammals" as "title". After that the tool will create two files in the directory: `package.json` and `src/index.tsx`.
|
||||||
|
|
||||||
See [package.json](https://github.com/facebook/flipper/blob/master/desktop/plugins/public/seamammals/package.json) for an example.
|
After the process has finished, use `yarn watch` in the generated directory to start compiling the plugin on the fly.
|
||||||
|
|
||||||
To ensure there are no errors in the defined plugin, install packages (using `yarn install` or `npm install`) and execute script `lint` (`yarn lint` or `npm run lint`) which shows all the mismatches that should be fixed to make the plugin definition valid.
|
|
||||||
|
|
||||||
Now that our package has been set up, we are ready to build a UI for our plugin. Either by using a standardized table-based plugin, or by creating a custom UI.
|
Now that our package has been set up, we are ready to build a UI for our plugin. Either by using a standardized table-based plugin, or by creating a custom UI.
|
||||||
|
|
||||||
</OssOnly>
|
</OssOnly>
|
||||||
|
|
||||||
|
For more background on the generated files and overal plugin structure, see the [Plugin Structure](../extending/desktop-plugin-structure) page.
|
||||||
|
|||||||
@@ -1,18 +1,13 @@
|
|||||||
---
|
---
|
||||||
id: js-table
|
id: js-table
|
||||||
title: Showing a table
|
title: Showing a table
|
||||||
|
sidebar_label: Desktop Plugin - Table
|
||||||
---
|
---
|
||||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||||
import Link from '@docusaurus/Link';
|
import Link from '@docusaurus/Link';
|
||||||
|
|
||||||
<img alt="Android Tutorial App" src={useBaseUrl("img/android-tutorial-desktop.png")} />
|
<img alt="Android Tutorial App" src={useBaseUrl("img/android-tutorial-desktop.png")} />
|
||||||
|
|
||||||
<div class="warning">
|
|
||||||
|
|
||||||
The APIs described on this page are currently being revised, if you are looking for a plugin that does more than displaying a table, we recommend to skip to the <Link to={useBaseUrl('/docs/tutorial/js-custom')}>Custom Plugin</Link> page right away.
|
|
||||||
If you want to follow the steps on this page, **remove** `flipper-plugin` from the (peer)dependencies in the `package.json` of your scaffolded plugin.
|
|
||||||
</div>
|
|
||||||
|
|
||||||
## Building a Table
|
## Building a Table
|
||||||
|
|
||||||
We have found that one of the most useful things you can do to understand how your app works
|
We have found that one of the most useful things you can do to understand how your app works
|
||||||
@@ -20,16 +15,15 @@ is to give you easy access to the underlying data used to display items on scree
|
|||||||
easy way of doing this is by showing the data in a table. We have optimized for this
|
easy way of doing this is by showing the data in a table. We have optimized for this
|
||||||
particular use case that makes it dead-simple to expose your data in a table that you
|
particular use case that makes it dead-simple to expose your data in a table that you
|
||||||
can sort, filter and select items for more detailed information.
|
can sort, filter and select items for more detailed information.
|
||||||
|
For the purpose of this tutorial, we will be editing the `index.tsx` file that was generated in the previous scaffolding step, and update it as follows:
|
||||||
|
|
||||||
### Row Types
|
### Row Types
|
||||||
|
|
||||||
We start by defining what our table rows look like as types:
|
We start by defining what our table rows look like as types:
|
||||||
|
|
||||||
```js
|
```typescript
|
||||||
type Id = number;
|
|
||||||
|
|
||||||
type Row = {
|
type Row = {
|
||||||
id: Id,
|
id: number,
|
||||||
title: string,
|
title: string,
|
||||||
url: string,
|
url: string,
|
||||||
};
|
};
|
||||||
@@ -43,107 +37,47 @@ that we know when something new was added to the table. We will use the
|
|||||||
|
|
||||||
Next, we define which columns to show and how to display them:
|
Next, we define which columns to show and how to display them:
|
||||||
|
|
||||||
```js
|
```typescript
|
||||||
const columns = {
|
import {DataTableColumn} from 'flipper-plugin';
|
||||||
title: {
|
|
||||||
value: 'Title',
|
|
||||||
},
|
|
||||||
url: {
|
|
||||||
value: 'URL',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const columnSizes = {
|
const columns: DataTableColumn<Row>[] = [
|
||||||
title: '15%',
|
{
|
||||||
url: 'flex',
|
key: 'title',
|
||||||
};
|
width: 150,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'url',
|
||||||
|
title: 'URL',
|
||||||
|
},
|
||||||
|
];
|
||||||
```
|
```
|
||||||
|
|
||||||
The keys used here will show up again in the next step when building
|
The keys used here will show up again in the next step when building
|
||||||
your rows, so keep them consistent. The `value` we define for each column will show up as the header at the top of the table.
|
your rows, so keep them consistent. The `title` we define for each column will show up as the header at the top of the table, and will be default to the `key` value if omitted.
|
||||||
|
|
||||||
For the size you can either choose a fixed proportion or choose `flex`
|
For the `width` you can either choose a fixed number (pixels), a percentage, or leave it out
|
||||||
to distribute the remaining available space.
|
to distribute the remaining available space.
|
||||||
|
|
||||||
### Sidebar
|
### Configuring the table
|
||||||
|
|
||||||
When clicking on an element in your table, you can display a sidebar
|
With a type describing the data we'll be storing, `Row`, and a descriptions of the columns to display, getting up table showing our data, including search / sort and a details view is now trivial!
|
||||||
which gives more detail about an object than what is shown inline in the
|
|
||||||
table. You could, for instance, show images that you referenced.
|
|
||||||
For this tutorial, however, we will just show the full object by
|
|
||||||
using our `ManagedDataInspector` UI component:
|
|
||||||
|
|
||||||
```jsx
|
```typescript
|
||||||
import {Panel, ManagedDataInspector} from 'flipper';
|
import {DataTableColumn, createTablePlugin} from 'flipper-plugin';
|
||||||
|
|
||||||
function renderSidebar(row: Row) {
|
module.exports = createTablePlugin<Row>({
|
||||||
return (
|
|
||||||
<Panel floating={false} heading={'Info'}>
|
|
||||||
<ManagedDataInspector data={row} expandRoot={true} />
|
|
||||||
</Panel>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
You'll notice how the function takes the `Row` type we have defined
|
|
||||||
before and returns a React component. What you render in this sidebar is
|
|
||||||
entirely up to you.
|
|
||||||
|
|
||||||
### Building Rows
|
|
||||||
|
|
||||||
In the same way that we create our sidebar from a `Row`, we
|
|
||||||
also render individual rows in our table but instead of a React
|
|
||||||
component, we provide a description of the data based
|
|
||||||
on the column keys we have set up before.
|
|
||||||
|
|
||||||
```jsx
|
|
||||||
function buildRow(row: Row): TableBodyRow {
|
|
||||||
return {
|
|
||||||
columns: {
|
|
||||||
title: {
|
|
||||||
value: <Text>{row.title}</Text>,
|
|
||||||
filterValue: row.title,
|
|
||||||
},
|
|
||||||
url: {
|
|
||||||
value: <Text>{row.url}</Text>,
|
|
||||||
filterValue: row.url,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
key: row.id,
|
|
||||||
copyText: JSON.stringify(row),
|
|
||||||
filterValue: `${row.title} ${row.url}`,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
The `title` and `url` fields correspond to the keys
|
|
||||||
we have previously set up as part of the `columns`
|
|
||||||
object.
|
|
||||||
|
|
||||||
`filterValue` is used to power the search bar at the top
|
|
||||||
of the table. Defining `copyText` allows you to come up
|
|
||||||
with a serialization scheme so users can right-click on
|
|
||||||
any row and copy the content to their clipboard.
|
|
||||||
|
|
||||||
### Putting it all to work
|
|
||||||
|
|
||||||
Now that we've build all the individual pieces, we
|
|
||||||
just need to hook it all up using `createTablePlugin`:
|
|
||||||
|
|
||||||
```js
|
|
||||||
export default createTablePlugin<Row>({
|
|
||||||
method: 'newRow',
|
|
||||||
columns,
|
columns,
|
||||||
columnSizes,
|
method: 'newRow',
|
||||||
renderSidebar,
|
key: 'id',
|
||||||
buildRow,
|
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
*See [index.tsx](https://github.com/facebook/flipper/blob/master/desktop/plugins/public/seamammals/src/index.tsx)*
|
|
||||||
|
|
||||||
The `method` we define here corresponds to the name
|
The `method` refers to the method that should be listened to to fill the table with data.
|
||||||
of the function we call on the native side to inform
|
The string `"newRow"` that is used here refers back to identifier we used with `connection.send` to send our data to the Flipper desktop application in the previous step.
|
||||||
the desktop about new data we want to display.
|
|
||||||
|
The `key` property is optional, but by setting it the `'id'` field will be used as identifier. As a result, once a `newRow` message arrives with an existing `id`, it will overwrite the old entry, rather than appending a new one.
|
||||||
|
|
||||||
|
The `createTablePlugin` API supports more options, which are documented [here](../extending/flipper-plugin#createtableplugin).
|
||||||
|
|
||||||
And that's it! Starting Flipper will now compile your
|
And that's it! Starting Flipper will now compile your
|
||||||
plugin and connect to the native side. It's a good
|
plugin and connect to the native side. It's a good
|
||||||
@@ -151,12 +85,14 @@ idea to start Flipper from the command line to see
|
|||||||
any potential errors. The console in the DevTools
|
any potential errors. The console in the DevTools
|
||||||
is a great source of information if something doesn't
|
is a great source of information if something doesn't
|
||||||
work as expected, too.
|
work as expected, too.
|
||||||
|
The final result of this step can be seen at [index_table.tsx](https://github.com/facebook/flipper/blob/master/desktop/plugins/public/seamammals/src/index_table.tsx).
|
||||||
|
|
||||||
## What's next?
|
## What's next?
|
||||||
|
|
||||||
You now have an interactive table that you can sort,
|
You now have an interactive table that you can sort,
|
||||||
filter and use to get additional information about
|
filter and use to get additional information about
|
||||||
the stuff you see on screen.
|
the stuff you see on screen.
|
||||||
|
`createTablePlugin` is a high level abstraction that takes care of both connection management and a standardized UI for the most common scenario.
|
||||||
|
|
||||||
For many cases, this is already all you need. However,
|
For many cases, this is already all you need. However,
|
||||||
sometimes you want to go the extra mile and want
|
sometimes you want to go the extra mile and want
|
||||||
|
|||||||
@@ -120,7 +120,6 @@ module.exports = {
|
|||||||
'Desktop plugin APIs': [
|
'Desktop plugin APIs': [
|
||||||
'extending/flipper-plugin',
|
'extending/flipper-plugin',
|
||||||
'extending/styling-components',
|
'extending/styling-components',
|
||||||
'extending/create-table-plugin',
|
|
||||||
'extending/search-and-filter',
|
'extending/search-and-filter',
|
||||||
...fbInternalOnly([
|
...fbInternalOnly([
|
||||||
{
|
{
|
||||||
@@ -131,6 +130,7 @@ module.exports = {
|
|||||||
'Deprecated APIs': [
|
'Deprecated APIs': [
|
||||||
'extending/ui-components',
|
'extending/ui-components',
|
||||||
'extending/js-plugin-api',
|
'extending/js-plugin-api',
|
||||||
|
'extending/create-table-plugin',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 92 KiB After Width: | Height: | Size: 641 KiB |
Reference in New Issue
Block a user