Commit Graph

5 Commits

Author SHA1 Message Date
Michel Weststrate
685cc09b3b DeviceLogs plugin to Sandy
Summary:
Converted the DeviceLogs plugin to sandy.

Kept logic and UI the same (so same batching, localstorage mechanisms etc). But used sandy api's for log subscribing, state, and separating the logical part of the component from the UI.

Note that some mechanisms work slightly different, like deeplinking and scrollToBottom handling, to reflect the fact that plugins are now long lived

Reviewed By: jknoxville

Differential Revision: D22845466

fbshipit-source-id: 7c98b2ddd9121dc730768ee1bece7e71bb5bec16
2020-08-20 13:32:47 -07:00
Michel Weststrate
642261c0d0 Cleanup and some code reuse between Device- and normal Plugins
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
2020-08-04 07:08:32 -07:00
Michel Weststrate
91ed4e31c0 Introduce DevicePlugin APIs
Summary:
This stack introduces Sandy device plugins, they are quite similar to normal plugins, but, a devicePlugin module is organized as

```
export function supportsDevice(device): boolean

export function devicePlugin(devicePluginClient)

export function Component
```

Device plugins get access to the device meta data and can subscribe to the `onLogEntry` callback and `onDestroy` lifecycle.

They will be able to store state just as normal plugins, but can't send or receive methods, so devicePluginClient is a bit limited.

This diff only sets up most of the new data structures, and makes sure everything still compiles and no existing tests fail.

To prevent this diff from becoming to big, actually loading, rendering and testing device plugins will be done in next diffs

Please take a critical look at the api proposed and the (especially) the public names used :)

Reviewed By: passy, nikoant

Differential Revision: D22691351

fbshipit-source-id: bdbbd7f86d14b646fc9a693ad19f33583a76f26d
2020-08-04 07:08:31 -07:00
Michel Weststrate
0e4a6d659b Make sure plugins can serialize and deserialize
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
2020-07-14 09:06:59 -07:00
Michel Weststrate
d16c6061c1 Introduce createState which can be used in components to propagate updates
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
2020-07-01 09:12:37 -07:00