diff --git a/desktop/plugins/public/seamammals/package.json b/desktop/plugins/public/seamammals/package.json index 6284db117..d8e5b68fe 100644 --- a/desktop/plugins/public/seamammals/package.json +++ b/desktop/plugins/public/seamammals/package.json @@ -5,7 +5,7 @@ "private": true, "version": "0.0.0", "main": "dist/bundle.js", - "flipperBundlerEntry": "src/index.tsx", + "flipperBundlerEntry": "src/index_table.tsx", "license": "MIT", "keywords": [ "flipper-plugin" diff --git a/desktop/plugins/public/seamammals/src/__tests__/seamammals.spec.tsx b/desktop/plugins/public/seamammals/src/__tests__/seamammals.spec.tsx index d1f4ddca8..be365737a 100644 --- a/desktop/plugins/public/seamammals/src/__tests__/seamammals.spec.tsx +++ b/desktop/plugins/public/seamammals/src/__tests__/seamammals.spec.tsx @@ -29,7 +29,7 @@ import {act} from '@testing-library/react'; } import {TestUtils} from 'flipper-plugin'; -import * as MammalsPlugin from '..'; +import * as MammalsPlugin from '../index_custom'; test('It can store rows', () => { const {instance, sendEvent} = TestUtils.startPlugin(MammalsPlugin); diff --git a/desktop/plugins/public/seamammals/src/index.tsx b/desktop/plugins/public/seamammals/src/index_custom.tsx similarity index 100% rename from desktop/plugins/public/seamammals/src/index.tsx rename to desktop/plugins/public/seamammals/src/index_custom.tsx diff --git a/desktop/plugins/public/seamammals/src/index_table.tsx b/desktop/plugins/public/seamammals/src/index_table.tsx new file mode 100644 index 000000000..1d6f7e357 --- /dev/null +++ b/desktop/plugins/public/seamammals/src/index_table.tsx @@ -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[] = [ + { + 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({ + columns, + key: 'id', + method: 'newRow', +}); diff --git a/docs/tutorial/js-custom.mdx b/docs/tutorial/js-custom.mdx index 7298a205e..14ef1f563 100644 --- a/docs/tutorial/js-custom.mdx +++ b/docs/tutorial/js-custom.mdx @@ -1,7 +1,7 @@ --- id: js-custom title: Building A Custom Desktop Plugin -sidebar_label: Custom Plugin +sidebar_label: Desktop Plugin - Custom UI --- import useBaseUrl from '@docusaurus/useBaseUrl'; import Link from '@docusaurus/Link'; diff --git a/docs/tutorial/js-setup.mdx b/docs/tutorial/js-setup.mdx index 92b0c7528..78ed3df92 100644 --- a/docs/tutorial/js-setup.mdx +++ b/docs/tutorial/js-setup.mdx @@ -1,56 +1,39 @@ --- id: js-setup title: Building a Desktop Plugin -sidebar_label: Building a Desktop Plugin +sidebar_label: Desktop Plugin - Setup --- import useBaseUrl from '@docusaurus/useBaseUrl'; 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 -plugins here: https://fbflipper.com/docs/extending/js-setup. +on the desktop side. Custom cards UI for our sea mammals plugin -## Dynamic Plugin loading - [FB-Only] After scaffolding and starting Flipper from source, no further steps are needed to setup the desktop plugin. -By default, Flipper will start with the plugins it was bundled with. You can -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. +## Scaffolding a new Desktop plugin -Your file will then look something like this: - -```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. +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: ```bash -$ cd ~/Flipper/custom-plugins/ -$ npx flipper-pkg init +mkdir ~/FlipperPlugins +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`. -See [package.json](https://github.com/facebook/flipper/blob/master/desktop/plugins/public/seamammals/package.json) for an example. - -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. +After the process has finished, use `yarn watch` in the generated directory to start compiling the plugin on the fly. 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. + +For more background on the generated files and overal plugin structure, see the [Plugin Structure](../extending/desktop-plugin-structure) page. diff --git a/docs/tutorial/js-table.mdx b/docs/tutorial/js-table.mdx index a19faa8e6..3aaaa3260 100644 --- a/docs/tutorial/js-table.mdx +++ b/docs/tutorial/js-table.mdx @@ -1,18 +1,13 @@ --- id: js-table title: Showing a table +sidebar_label: Desktop Plugin - Table --- import useBaseUrl from '@docusaurus/useBaseUrl'; import Link from '@docusaurus/Link'; Android Tutorial App -
- -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 Custom Plugin 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. -
- ## Building a Table 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 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. +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 We start by defining what our table rows look like as types: -```js -type Id = number; - +```typescript type Row = { - id: Id, + id: number, title: 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: -```js -const columns = { - title: { - value: 'Title', - }, - url: { - value: 'URL', - }, -}; +```typescript +import {DataTableColumn} from 'flipper-plugin'; -const columnSizes = { - title: '15%', - url: 'flex', -}; +const columns: DataTableColumn[] = [ + { + key: 'title', + width: 150, + }, + { + key: 'url', + title: 'URL', + }, +]; ``` 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. -### Sidebar +### Configuring the table -When clicking on an element in your table, you can display a sidebar -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: +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! -```jsx -import {Panel, ManagedDataInspector} from 'flipper'; +```typescript +import {DataTableColumn, createTablePlugin} from 'flipper-plugin'; -function renderSidebar(row: Row) { - return ( - - - - ); -} -``` - -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: {row.title}, - filterValue: row.title, - }, - url: { - value: {row.url}, - 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({ - method: 'newRow', +module.exports = createTablePlugin({ columns, - columnSizes, - renderSidebar, - buildRow, + method: 'newRow', + key: 'id', }); ``` -*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 -of the function we call on the native side to inform -the desktop about new data we want to display. +The `method` refers to the method that should be listened to to fill the table with data. +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 `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 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 is a great source of information if something doesn't 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? You now have an interactive table that you can sort, filter and use to get additional information about 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, sometimes you want to go the extra mile and want diff --git a/website/sidebars.js b/website/sidebars.js index 389f7892e..79a9ec752 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -120,7 +120,6 @@ module.exports = { 'Desktop plugin APIs': [ 'extending/flipper-plugin', 'extending/styling-components', - 'extending/create-table-plugin', 'extending/search-and-filter', ...fbInternalOnly([ { @@ -131,6 +130,7 @@ module.exports = { 'Deprecated APIs': [ 'extending/ui-components', 'extending/js-plugin-api', + 'extending/create-table-plugin', ], }, ], diff --git a/website/static/img/android-tutorial-desktop.png b/website/static/img/android-tutorial-desktop.png index 1e1a3db42..d5f9bc873 100644 Binary files a/website/static/img/android-tutorial-desktop.png and b/website/static/img/android-tutorial-desktop.png differ