Summary:
^
Basically, update Jest and fix any raised issues. Mainly:
- Update necessary dependencies
- Update snapshots
- `useFakeTimers` caused a few issues which meant that the way we hook into the performance object had to be tweaked. The main code change is: `//fbsource/xplat/sonar/desktop/scripts/jest-setup-after.tsx`
- `mocked` -> `jest.mocked`
Changelog: Update Jest to v29.5.1
Reviewed By: antonk52
Differential Revision: D46319818
fbshipit-source-id: d218ca8f7e43abac6b00844953ddeb7f4e1010a2
Summary:
flipper-server-companion depends on flipper-plugin. flipper-plugin includes dependencies that run only in a browser. Splitting flipper-plugin into core and browser packages helps to avoid including browser-only dependencies into flipper-server bundle.
As a result, bundle size could be cut in half. Subsequently, RSS usage drops as there is twice as less code to process for V8.
Note: it currently breaks external flipper-data-source package. It will be restored in subsequent diffs
Reviewed By: lblasa
Differential Revision: D38658285
fbshipit-source-id: 751b11fa9f3a2d938ce166687b8310ba8b059dee
Summary: Moved Logger, sleep, timeout and server contract types to flipper-common packages.
Reviewed By: passy
Differential Revision: D31475790
fbshipit-source-id: 42d2147698875f9e919ad5250f9953f3bff3ec2d
Summary:
To make the DataSource abstraction reusable for other teams and an upcoming talk, this diff moves all DataSource storage & virtualization logic in one folder.
Will set up a build process and demo project in later diffs.
Reviewed By: nikoant
Differential Revision: D28056700
fbshipit-source-id: 7cfe5b40bbbe387da711f765a604a45029d451c7
Summary: Flipper Sandy plugins didn't have an event to hook into that is run _after_ any state snapshot is loaded, which was needed by the graphQL plugin, as they do some post processing when a data snapshot is restored.
Reviewed By: passy
Differential Revision: D28189573
fbshipit-source-id: 4ef992f3fafc32787eab3bc235059f2c41396c80
Summary:
In many cases, the onExport handler doesn't try to customise the format, but merely fetch some additional information before creating an export.
By allowing the `onExport` handler to also return nothing, and instead merely update existing state, this case will be easier to express now;
Reviewed By: nikoant
Differential Revision: D28026558
fbshipit-source-id: 2b90b3e1ced6a6a5b42938b6f6b74b0eb9ceafc0
Summary:
Some styling fixes and minor improvements in DataTable, used by network plugin:
- be able to customise the context menu
- be able to customise how entire rows are copied and presented on the clipboard to be able to deviate from the standard JSON
- deeplink handling was made async, this gives the plugin the opportunity to first handle initial setup and rendering before trying to jump somewhere which is a typical use case for deeplinking
Reviewed By: passy
Differential Revision: D27947186
fbshipit-source-id: a56f081d60520c4bc2ad3c547a8ca5b9357e71a1
Summary:
This diff is primarily cosmetic, just pushing code around to make the API more intuitive. Most importantly, DataSource was split into DataSource and DataSourceView classes, the latter being accessible through `datasource.view`.
The benefit of this is two fold:
1. Conceptually it is much clearer now which operations operate on the _source_ records, and which ones on the derived _view_.
2. This will make it easier in the future to support multiple views to be based on a single data source.
This refactoring also nicely found 2 cases where datasource logic and view logic were mixed.
The only semantic change in this diff is that both DataSource and DataSourceView are now iterable, so that one can do a `for (const record of ds)` / `for (const record of ds.view)`
Reviewed By: nikoant
Differential Revision: D26976838
fbshipit-source-id: 3726e92b3c6ee3417dc66cbbe6e288797eecf70e
Summary: Make sure that DataSources can be serialized directly with a single setting, just like plain state atoms
Reviewed By: nikoant
Differential Revision: D26944954
fbshipit-source-id: 2b0d625d7d67f27a7c2e33dd7c4b534dfa4d3e82
Summary: Per title, this allows for pre-processing data after it is deserialized and before it is stored in the plugin
Reviewed By: nikoant
Differential Revision: D26126423
fbshipit-source-id: bc08a6ab205d2a0d551515563cd85a197595ddb2
Summary: Make sure that GKs can be used in pure sandy plugins.
Reviewed By: jknoxville
Differential Revision: D25368358
fbshipit-source-id: c7c6aa4ecf0443cb3b5d90e22e8aca9a73a69389
Summary: This diff adds the `client.onUnhandledMessage` handler, to be able to handle messages for which we don't know the names upfront. Some existing plugins that only send one kind of message can benefit from this, as can generic plugins, like the createTablePlugin
Reviewed By: passy
Differential Revision: D24949453
fbshipit-source-id: 0fed81e28aee350632c09ee3bb834f306dc8b100
Summary: expose `appName`, `appId` and `device` to Sandy plugins. Will be used in next diff to migrate navigation plugin
Reviewed By: cekkaewnumchai
Differential Revision: D24857253
fbshipit-source-id: 03ac3d376d5d1950bcf3d78386a65ce167b517e3
Summary: `supportsMethod` wasn't implemented in the new sandy APIs so far, but is needed for D24108772
Reviewed By: cekkaewnumchai
Differential Revision: D24109496
fbshipit-source-id: 694344b423c1805baa193e4f2e1ad5f28483378b
Summary:
Added support for `createPaste` in Sandy plugins
Nice minimalistic example of how to expose a Flipper api to Sandy.
Note that some indirection could be removed by having an interface that is shared directly between `BasePluginClient` and `FlipperLib` (e.g. `PublicFlipperLib`). In contrast to `addMenuEntries` from the previous diff, `createPaste` is basically exposed verbatim to Sandy without additional wrapping, so those cases could be made simpler. Maybe will do that later.
Reviewed By: passy
Differential Revision: D22815873
fbshipit-source-id: e6d0773a35341edfe5de0898317eaadf88de79d0
Summary:
[interesting] since it shows how Flipper APIs are exposed through sandy. However, the next diff is a much simpler example of that
This diff adds support for adding menu entries for sandy plugin (renamed keyboard actions to menus, as it always creates a menu entry, but not necessarily a keyboard shortcut)
```
client.addMenuEntry(
// custom entry
{
label: 'Reset Selection',
topLevelMenu: 'Edit',
handler: () => {
selectedID.set(null);
},
},
// based on built-in action (sets standard label, shortcut)
{
action: 'createPaste',
handler: () => {
console.log('creating paste');
},
},
);
```
Most of this diff is introducing the concept of FlipperUtils, a set of static Flipper methods (not related to a device or client) that can be used from Sandy. This will for example be used to implement things as `createPaste` as well
Reviewed By: nikoant
Differential Revision: D22766990
fbshipit-source-id: ce90af3b700e6c3d9a779a3bab4673ba356f3933
Summary: Introducing a base abstract class (blegh) to share some life cycle management between Device- and normal plugins. Cleaned up the test utils a bit as well + some old TODO's that now have been taken care of
Reviewed By: nikoant
Differential Revision: D22727089
fbshipit-source-id: 507816f1bfdbc6e7e71d4bd365b881b6710ca917
Summary:
Device plugins have an activate and deactivate hook, that reflects the plugin being selected in the UI. Added these same hooks to client plugins as well. In practice they are called at the same times as `onConnect` and `onDisconnect`, except for background plugins, which connect only once, so it is pretty useful to be still able to make the distinction.
Since there is now quite some common functionality between plugins and device plugins, will clean things a bit up in a next diff
[Interesting] as it explains the difference between the different lifecycle methods of plugins, and the impact of being a background plugin
LIfecycle summary:
1. app connects
2. for background plugins: connect them (`onConnect`)
3. user selects a plugin, triggers `onActivate`. will also trigger `onConnect` the plugin if it _isnt_ a bg plugin
4. user selects a different plugin, triggers `onDeactivate`. will also trigger `onDisconnect` if it isn't a bg plugin.
5. app is unloaded. Triggers `onDisconnect` for bg plugins. Triggers `onDestroy` for all plugins,
Reviewed By: jknoxville
Differential Revision: D22724791
fbshipit-source-id: 9fe2e666eb37fa2e0bd00fa61d78d2d4b1080137
Summary:
Make sure device plugins can be deeplinked as well.
(note that the duplication between `Plugin` and `DevicePlugin` is cleaned up again in D22727089, first wanted to make it work and tested, then clean)
DeepLink no longer have to be strings, per popular requests, as that makes direct linking between plugins easier (online links from the outside world have to arrive as strings)
Reviewed By: jknoxville, nikoant
Differential Revision: D22727091
fbshipit-source-id: 523c90b1e1fbf3700fdb4f62699dd57070cbc980
Summary:
This adds support for handling incoming deeplinks in a Sandy plugin, which can be done by using a `client.onDeepLink(deepLink => { } )` listener
Also generalized deeplinks to not just support strings, but also richer objects, which is beneficial to plugin to plugin linking.
Reviewed By: jknoxville
Differential Revision: D22524749
fbshipit-source-id: 2cbe8d52f6eac91a1c1c8c8494706952920b9181
Summary:
This plugin adds serialization capabilities to Sandy plugins buy setting the a `persist: <key>` flag. This shouldn't be used for state that is unserializable, too big, too sensitive, or irrelevant during export / import.
Using an explicit `persist` flag is done to make plugins robust to changes over time; as long as the key is kept the same, state variables can be renamed and reordered without breaking the import / export format. Also it allows us to detect some changes in the import / export format and warn about it.
Alternative designs considered but not implemented would be:
1. requiring the user to explicitly return the state from the factory (e.g. `const todos = createState([]); return { todos }`,
2. or construct the state from client (e.g. `const todos = client.createState([])`)
3. enable persistence by default, and store states in the order the states were created (much like useState in React). This was implemented in the first versions of this diff, but as pointed out in the discussions, this is too sensitive too (accidental) format changes, as the storage format would be quite implicit
A nice benefit of the current approach, especially compared with alternative approach 1, is that state being restored is immediately visible in the plugin factory. In other words, directly after initialization `const todos = createState([])`, the `todos.get()` is actually set to the state that is being restored, rather than having still the initial state which is only overridden rather. So this behaves very much like the `useState` hook in React.
Furthermore, in the future we could use the same `persist` key in combination with other options, such as `saveToLocalStorage`, in case some state acts as a 'preference' (T69989583).
`TestUtils.startPlugin` supports starting plugins with an initial state by using the optional `initialState` field
Actually wiring up the serialization and deserialization into the export / import functionality of Flipper is done in the next diff.
Reviewed By: jknoxville
Differential Revision: D22432770
fbshipit-source-id: 9a4849582c2f6f54d1e40f65a6cba73092c28fe8
Summary:
Introduced a minimal state abstraction so that state can be maintained in the plugin instance, but subscribe to by the UI.
At a later point we could pick an off the shelve solution like Recoil or MobX, or introduce cursors to read something deep etc etc, but for now that doesn't seem to be needed at all, and I think this will be pretty comprehensible for plugin authors (see also the 25th diff in this stack).
The api
```
createState(initialValue): Atom
Atom {
get() // returns current value
set(newValue) // sets a new value
update(draft => { }) // updates a complex value using Immer behind the scenes
}
// hook, subscribes to the updates of the Atom and always returns the current value
useValue(atom)
```
Reviewed By: nikoant
Differential Revision: D22306673
fbshipit-source-id: c49f5af85ae9929187e4d8a051311a07c1b88eb5
Summary:
`usePlugin(pluginFactory)` returns the current plugin instance's api that was exposed by the plugin directory.
Passing `pluginFactory` is technically strictly not needed, but having the user pass it, we can make sure it is strongly typed
Reviewed By: nikoant
Differential Revision: D22286293
fbshipit-source-id: 4268b6849b8cd3d524103de7eadbd6c0a65c7a61
Summary: This diffs adds the capability to listen to messages in Sandy plugins. Although API wise it looks more like the old `this.subscribe`, semantically it behaves like the `persistedStateReducer`; messages are queued if the plugin is enabled but not active.
Reviewed By: nikoant
Differential Revision: D22282711
fbshipit-source-id: 885faa702fe779ac8d593c1d224b2be13e688d47
Summary: Sandy plugins can now send messages to plugins. The methods and params are strongly typed in implementation and unit tests, based on the <Methods> generic of FlipperClient.
Reviewed By: nikoant
Differential Revision: D22256972
fbshipit-source-id: 549523a402949b3eb6bb4b4ca160dedb5c5e722d
Summary:
This sets up the initial infra that is to be used by plugin devs to test plugins.
There is not much yet to see, as there is no state or message sending yet. But at least the life cycle of plugins can be test, things are strongly typed and everything is in the place where it should be :)
N.b. the import difference with these utils and the createFlipperMock utilities in Flipper are
1. this testing infra is entirely inside flipper-plugin package, so that plugin devs don't need flipper as a dependency
2. this testing infra doesn't provide abstractions for plugin / device / client switching; it tests plugins purely in isolation of the rest of the world (except for firing `onConnect` / `onDisconnect` which is normally the effect of switching plugins)
Reviewed By: nikoant
Differential Revision: D22255262
fbshipit-source-id: b94ccbab720d2b49428a646aed3c55af71a5bc80