Convert to Shared Preference Plugin to Sandy
Summary: per title In addition, this diff adds `startUnactivated` option to allow setting up `onSend` mock implementation. Reviewed By: mweststrate Differential Revision: D24477989 fbshipit-source-id: f913574ebacdd436e8511baa43744249a014e90b
This commit is contained in:
committed by
Facebook GitHub Bot
parent
467a6b16fb
commit
402ea2fc14
@@ -43,6 +43,7 @@ interface StartPluginOptions {
|
||||
initialState?: Record<string, any>;
|
||||
isArchived?: boolean;
|
||||
isBackgroundPlugin?: boolean;
|
||||
startUnactivated?: boolean;
|
||||
/** Provide a set of unsupported methods to simulate older clients that don't support certain methods yet */
|
||||
unsupportedMethods?: string[];
|
||||
}
|
||||
@@ -235,7 +236,9 @@ export function startPlugin<Module extends FlipperPluginModule<any>>(
|
||||
if (options?.isBackgroundPlugin) {
|
||||
pluginInstance.connect(); // otherwise part of activate
|
||||
}
|
||||
if (!options?.startUnactivated) {
|
||||
pluginInstance.activate();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,291 +0,0 @@
|
||||
/**
|
||||
* 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 {
|
||||
ManagedTable,
|
||||
Text,
|
||||
Heading,
|
||||
FlexColumn,
|
||||
colors,
|
||||
FlexRow,
|
||||
ManagedDataInspector,
|
||||
styled,
|
||||
Select,
|
||||
} from 'flipper';
|
||||
import {FlipperPlugin} from 'flipper';
|
||||
|
||||
import {clone} from 'lodash';
|
||||
|
||||
type SharedPreferencesChangeEvent = {|
|
||||
preferences: string,
|
||||
name: string,
|
||||
time: number,
|
||||
deleted: boolean,
|
||||
value: string,
|
||||
|};
|
||||
|
||||
export type SharedPreferences = {|
|
||||
[name: string]: any,
|
||||
|};
|
||||
|
||||
type SharedPreferencesEntry = {
|
||||
preferences: SharedPreferences,
|
||||
changesList: Array<SharedPreferencesChangeEvent>,
|
||||
};
|
||||
|
||||
type SharedPreferencesMap = {
|
||||
[name: string]: SharedPreferencesEntry,
|
||||
};
|
||||
|
||||
type SharedPreferencesState = {|
|
||||
selectedPreferences: ?string,
|
||||
sharedPreferences: SharedPreferencesMap,
|
||||
|};
|
||||
|
||||
const CHANGELOG_COLUMNS = {
|
||||
event: {
|
||||
value: 'Event',
|
||||
},
|
||||
name: {
|
||||
value: 'Name',
|
||||
},
|
||||
value: {
|
||||
value: 'Value',
|
||||
},
|
||||
};
|
||||
|
||||
const CHANGELOG_COLUMN_SIZES = {
|
||||
event: '30%',
|
||||
name: '30%',
|
||||
value: '30%',
|
||||
};
|
||||
|
||||
const UPDATED_LABEL = <Text color={colors.lime}>Updated</Text>;
|
||||
const DELETED_LABEL = <Text color={colors.cherry}>Deleted</Text>;
|
||||
|
||||
const InspectorColumn = styled(FlexColumn)({
|
||||
flexGrow: 0.2,
|
||||
});
|
||||
|
||||
const ChangelogColumn = styled(FlexColumn)({
|
||||
flexGrow: 0.8,
|
||||
paddingLeft: '16px',
|
||||
});
|
||||
|
||||
const RootColumn = styled(FlexColumn)({
|
||||
paddingLeft: '16px',
|
||||
paddingRight: '16px',
|
||||
paddingTop: '16px',
|
||||
});
|
||||
|
||||
export default class extends FlipperPlugin<SharedPreferencesState> {
|
||||
state = {
|
||||
selectedPreferences: null,
|
||||
sharedPreferences: {},
|
||||
};
|
||||
|
||||
reducers = {
|
||||
UpdateSharedPreferences(state: SharedPreferencesState, results: Object) {
|
||||
const update = results.update;
|
||||
const entry = state.sharedPreferences[update.name] || {changesList: []};
|
||||
entry.preferences = update.preferences;
|
||||
state.sharedPreferences[update.name] = entry;
|
||||
return {
|
||||
...state,
|
||||
selectedPreferences: state.selectedPreferences || update.name,
|
||||
sharedPreferences: {
|
||||
...state.sharedPreferences,
|
||||
[update.name]: entry,
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
ChangeSharedPreferences(state: SharedPreferencesState, event: Object) {
|
||||
const change = event.change;
|
||||
const entry = state.sharedPreferences[change.preferences];
|
||||
if (entry == null) {
|
||||
return state;
|
||||
}
|
||||
let newEntry;
|
||||
if (change.deleted) {
|
||||
const newPreferences = {
|
||||
...entry.preferences,
|
||||
};
|
||||
delete newPreferences[change.name];
|
||||
newEntry = {
|
||||
...entry,
|
||||
preferences: newPreferences,
|
||||
};
|
||||
} else {
|
||||
newEntry = {
|
||||
...entry,
|
||||
preferences: {
|
||||
...entry.preferences,
|
||||
[change.name]: change.value,
|
||||
},
|
||||
};
|
||||
}
|
||||
newEntry.changesList = [change, ...entry.changesList];
|
||||
return {
|
||||
...state,
|
||||
sharedPreferences: {
|
||||
...state.sharedPreferences,
|
||||
[change.preferences]: newEntry,
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
UpdateSelectedSharedPreferences(
|
||||
state: SharedPreferencesState,
|
||||
event: Object,
|
||||
) {
|
||||
return {
|
||||
...state,
|
||||
selectedPreferences: event.selected,
|
||||
sharedPreferences: state.sharedPreferences,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
init() {
|
||||
this.client
|
||||
.call('getAllSharedPreferences')
|
||||
.then((results: {[name: string]: SharedPreferences}) => {
|
||||
Object.entries(results).forEach(([name, prefs]) => {
|
||||
const update = {name: name, preferences: prefs};
|
||||
this.dispatchAction({update, type: 'UpdateSharedPreferences'});
|
||||
});
|
||||
});
|
||||
|
||||
this.client.subscribe(
|
||||
'sharedPreferencesChange',
|
||||
(change: SharedPreferencesChangeEvent) => {
|
||||
this.dispatchAction({change, type: 'ChangeSharedPreferences'});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
onSharedPreferencesChanged = (path: Array<string>, value: any) => {
|
||||
const selectedPreferences = this.state.selectedPreferences;
|
||||
if (selectedPreferences == null) {
|
||||
return;
|
||||
}
|
||||
const entry = this.state.sharedPreferences[selectedPreferences];
|
||||
if (entry == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const values = entry.preferences;
|
||||
let newValue = value;
|
||||
if (path.length === 2 && values) {
|
||||
newValue = clone(values[path[0]]);
|
||||
newValue[path[1]] = value;
|
||||
}
|
||||
this.client
|
||||
.call('setSharedPreference', {
|
||||
sharedPreferencesName: this.state.selectedPreferences,
|
||||
preferenceName: path[0],
|
||||
preferenceValue: newValue,
|
||||
})
|
||||
.then((results: SharedPreferences) => {
|
||||
const update = {
|
||||
name: this.state.selectedPreferences,
|
||||
preferences: results,
|
||||
};
|
||||
this.dispatchAction({update, type: 'UpdateSharedPreferences'});
|
||||
});
|
||||
};
|
||||
|
||||
onSharedPreferencesSelected = (selected: string) => {
|
||||
this.dispatchAction({
|
||||
selected: selected,
|
||||
type: 'UpdateSelectedSharedPreferences',
|
||||
});
|
||||
};
|
||||
|
||||
onSharedPreferencesDeleted = (path: Array<string>) => {
|
||||
this.client
|
||||
.call('deleteSharedPreference', {
|
||||
sharedPreferencesName: this.state.selectedPreferences,
|
||||
preferenceName: path[0],
|
||||
})
|
||||
.then((results: SharedPreferences) => {
|
||||
const update = {
|
||||
name: this.state.selectedPreferences,
|
||||
preferences: results,
|
||||
};
|
||||
this.dispatchAction({update, type: 'UpdateSharedPreferences'});
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const selectedPreferences = this.state.selectedPreferences;
|
||||
if (selectedPreferences == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const entry = this.state.sharedPreferences[selectedPreferences];
|
||||
if (entry == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<RootColumn grow={true}>
|
||||
<Heading>
|
||||
<span style={{marginRight: '16px'}}>Preference File</span>
|
||||
<Select
|
||||
options={Object.keys(this.state.sharedPreferences)
|
||||
.sort((a, b) => (a.toLowerCase() > b.toLowerCase() ? 1 : -1))
|
||||
.reduce((obj, item) => {
|
||||
obj[item] = item;
|
||||
return obj;
|
||||
}, {})}
|
||||
selected={this.state.selectedPreferences}
|
||||
onChange={this.onSharedPreferencesSelected}
|
||||
/>
|
||||
</Heading>
|
||||
<FlexRow grow={true} scrollable={true}>
|
||||
<InspectorColumn>
|
||||
<Heading>Inspector</Heading>
|
||||
<ManagedDataInspector
|
||||
data={entry.preferences}
|
||||
setValue={this.onSharedPreferencesChanged}
|
||||
onDelete={this.onSharedPreferencesDeleted}
|
||||
/>
|
||||
</InspectorColumn>
|
||||
<ChangelogColumn>
|
||||
<Heading>Changelog</Heading>
|
||||
<ManagedTable
|
||||
columnSizes={CHANGELOG_COLUMN_SIZES}
|
||||
columns={CHANGELOG_COLUMNS}
|
||||
rowLineHeight={26}
|
||||
rows={entry.changesList.map((element, index) => {
|
||||
return {
|
||||
columns: {
|
||||
event: {
|
||||
value: element.deleted ? DELETED_LABEL : UPDATED_LABEL,
|
||||
},
|
||||
name: {
|
||||
value: element.name,
|
||||
},
|
||||
value: {
|
||||
value: String(element.value),
|
||||
},
|
||||
},
|
||||
|
||||
key: String(index),
|
||||
};
|
||||
})}
|
||||
/>
|
||||
</ChangelogColumn>
|
||||
</FlexRow>
|
||||
</RootColumn>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
"id": "Preferences",
|
||||
"version": "0.63.0",
|
||||
"main": "dist/bundle.js",
|
||||
"flipperBundlerEntry": "index.js",
|
||||
"flipperBundlerEntry": "src/index.tsx",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"flipper-plugin"
|
||||
@@ -12,6 +12,9 @@
|
||||
"dependencies": {
|
||||
"lodash": "^4.17.19"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"flipper-plugin": "0.63.0"
|
||||
},
|
||||
"title": "Shared Preferences Viewer",
|
||||
"bugs": {
|
||||
"email": "halsibai@fb.com"
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
/**
|
||||
* 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 {TestUtils} from 'flipper-plugin';
|
||||
import * as plugin from '..';
|
||||
|
||||
async function sleep(ms: number) {
|
||||
return new Promise((resolve) => setTimeout(() => resolve(), ms));
|
||||
}
|
||||
|
||||
// this testing is inspired by Flipper sample app
|
||||
test('general plugin logic testing', async () => {
|
||||
const {instance, onSend, connect, sendEvent} = TestUtils.startPlugin(plugin, {
|
||||
startUnactivated: true,
|
||||
});
|
||||
onSend.mockImplementation(async (method, params) => {
|
||||
switch (method) {
|
||||
case 'getAllSharedPreferences':
|
||||
return {
|
||||
sample: {Hello: 'world'},
|
||||
other_sample: {SomeKey: 1337},
|
||||
};
|
||||
case 'setSharedPreference': {
|
||||
const p = params as plugin.SetSharedPreferenceParams;
|
||||
return {[p.preferenceName]: p.preferenceValue};
|
||||
}
|
||||
case 'deleteSharedPreference': {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Retrieve some data when connect
|
||||
connect();
|
||||
await sleep(1000);
|
||||
expect(onSend).toBeCalledWith('getAllSharedPreferences', {});
|
||||
expect(instance.sharedPreferences.get()).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"other_sample": Object {
|
||||
"changesList": Array [],
|
||||
"preferences": Object {
|
||||
"SomeKey": 1337,
|
||||
},
|
||||
},
|
||||
"sample": Object {
|
||||
"changesList": Array [],
|
||||
"preferences": Object {
|
||||
"Hello": "world",
|
||||
},
|
||||
},
|
||||
}
|
||||
`);
|
||||
expect(instance.selectedPreferences.get()).toEqual('sample');
|
||||
|
||||
instance.setSelectedPreferences('other_sample');
|
||||
expect(instance.selectedPreferences.get()).toEqual('other_sample');
|
||||
|
||||
// test changing preference
|
||||
const changedPref = {
|
||||
sharedPreferencesName: 'other_sample',
|
||||
preferenceName: 'SomeKey',
|
||||
preferenceValue: 5555,
|
||||
};
|
||||
await instance.setSharedPreference(changedPref);
|
||||
// this is sent from client after successful update
|
||||
sendEvent('sharedPreferencesChange', {
|
||||
deleted: false,
|
||||
name: 'SomeKey',
|
||||
preferences: 'sample',
|
||||
time: 1,
|
||||
value: 5555,
|
||||
});
|
||||
expect(onSend).toBeCalledWith('setSharedPreference', changedPref);
|
||||
expect(instance.sharedPreferences.get().sample.preferences.SomeKey).toEqual(
|
||||
5555,
|
||||
);
|
||||
expect(instance.sharedPreferences.get()).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"other_sample": Object {
|
||||
"changesList": Array [],
|
||||
"preferences": Object {
|
||||
"SomeKey": 5555,
|
||||
},
|
||||
},
|
||||
"sample": Object {
|
||||
"changesList": Array [
|
||||
Object {
|
||||
"deleted": false,
|
||||
"name": "SomeKey",
|
||||
"preferences": "sample",
|
||||
"time": 1,
|
||||
"value": 5555,
|
||||
},
|
||||
],
|
||||
"preferences": Object {
|
||||
"Hello": "world",
|
||||
"SomeKey": 5555,
|
||||
},
|
||||
},
|
||||
}
|
||||
`);
|
||||
|
||||
// test deleting preference
|
||||
const deletedPref = {
|
||||
sharedPreferencesName: 'other_sample',
|
||||
preferenceName: 'SomeKey',
|
||||
};
|
||||
await instance.deleteSharedPreference(deletedPref);
|
||||
// this is sent from client after successful update
|
||||
sendEvent('sharedPreferencesChange', {
|
||||
deleted: true,
|
||||
name: 'SomeKey',
|
||||
preferences: 'sample',
|
||||
time: 2,
|
||||
});
|
||||
expect(onSend).toBeCalledWith('deleteSharedPreference', deletedPref);
|
||||
expect(
|
||||
instance.sharedPreferences.get().sample.preferences.SomeKey,
|
||||
).toBeUndefined();
|
||||
expect(instance.sharedPreferences.get()).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"other_sample": Object {
|
||||
"changesList": Array [],
|
||||
"preferences": Object {},
|
||||
},
|
||||
"sample": Object {
|
||||
"changesList": Array [
|
||||
Object {
|
||||
"deleted": true,
|
||||
"name": "SomeKey",
|
||||
"preferences": "sample",
|
||||
"time": 2,
|
||||
},
|
||||
Object {
|
||||
"deleted": false,
|
||||
"name": "SomeKey",
|
||||
"preferences": "sample",
|
||||
"time": 1,
|
||||
"value": 5555,
|
||||
},
|
||||
],
|
||||
"preferences": Object {
|
||||
"Hello": "world",
|
||||
},
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
// TODO: Add unit test for UI
|
||||
235
desktop/plugins/shared_preferences/src/index.tsx
Normal file
235
desktop/plugins/shared_preferences/src/index.tsx
Normal file
@@ -0,0 +1,235 @@
|
||||
/**
|
||||
* 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 {
|
||||
ManagedTable,
|
||||
Text,
|
||||
Heading,
|
||||
FlexColumn,
|
||||
colors,
|
||||
FlexRow,
|
||||
ManagedDataInspector,
|
||||
styled,
|
||||
Select,
|
||||
} from 'flipper';
|
||||
import {PluginClient, createState, usePlugin, useValue} from 'flipper-plugin';
|
||||
import {clone} from 'lodash';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
type SharedPreferencesChangeEvent = {
|
||||
preferences: string;
|
||||
name: string;
|
||||
time: number;
|
||||
deleted: boolean;
|
||||
value?: any;
|
||||
};
|
||||
type SharedPreferences = Record<string, any>;
|
||||
type SharedPreferencesEntry = {
|
||||
preferences: SharedPreferences;
|
||||
changesList: Array<SharedPreferencesChangeEvent>;
|
||||
};
|
||||
|
||||
export type SetSharedPreferenceParams = {
|
||||
sharedPreferencesName: string;
|
||||
preferenceName: string;
|
||||
preferenceValue: any;
|
||||
};
|
||||
type DeleteSharedPreferenceParams = {
|
||||
sharedPreferencesName: string;
|
||||
preferenceName: string;
|
||||
};
|
||||
|
||||
type Events = {sharedPreferencesChange: SharedPreferencesChangeEvent};
|
||||
type Methods = {
|
||||
getAllSharedPreferences: (params: {}) => Promise<
|
||||
Record<string, SharedPreferences>
|
||||
>;
|
||||
setSharedPreference: (
|
||||
params: SetSharedPreferenceParams,
|
||||
) => Promise<SharedPreferences>;
|
||||
deleteSharedPreference: (
|
||||
params: DeleteSharedPreferenceParams,
|
||||
) => Promise<SharedPreferences>;
|
||||
};
|
||||
|
||||
export function plugin(client: PluginClient<Events, Methods>) {
|
||||
const selectedPreferences = createState<string | null>(null, {
|
||||
persist: 'selectedPreferences',
|
||||
});
|
||||
const setSelectedPreferences = (value: string) =>
|
||||
selectedPreferences.set(value);
|
||||
const sharedPreferences = createState<Record<string, SharedPreferencesEntry>>(
|
||||
{},
|
||||
{persist: 'sharedPreferences'},
|
||||
);
|
||||
|
||||
function updateSharedPreferences(update: {name: string; preferences: any}) {
|
||||
if (selectedPreferences.get() == null) {
|
||||
selectedPreferences.set(update.name);
|
||||
}
|
||||
sharedPreferences.update((draft) => {
|
||||
const entry = draft[update.name] || {changesList: []};
|
||||
entry.preferences = update.preferences;
|
||||
draft[update.name] = entry;
|
||||
});
|
||||
}
|
||||
|
||||
async function setSharedPreference(params: SetSharedPreferenceParams) {
|
||||
const results = await client.send('setSharedPreference', params);
|
||||
updateSharedPreferences({
|
||||
name: params.sharedPreferencesName,
|
||||
preferences: results,
|
||||
});
|
||||
}
|
||||
async function deleteSharedPreference(params: DeleteSharedPreferenceParams) {
|
||||
const results = await client.send('deleteSharedPreference', params);
|
||||
updateSharedPreferences({
|
||||
name: params.sharedPreferencesName,
|
||||
preferences: results,
|
||||
});
|
||||
}
|
||||
|
||||
client.onMessage('sharedPreferencesChange', (change) =>
|
||||
sharedPreferences.update((draft) => {
|
||||
const entry = draft[change.preferences];
|
||||
if (entry == null) {
|
||||
return;
|
||||
}
|
||||
if (change.deleted) {
|
||||
delete entry.preferences[change.name];
|
||||
} else {
|
||||
entry.preferences[change.name] = change.value;
|
||||
}
|
||||
entry.changesList.unshift(change);
|
||||
draft[change.preferences] = entry;
|
||||
}),
|
||||
);
|
||||
client.onConnect(async () => {
|
||||
const results = await client.send('getAllSharedPreferences', {});
|
||||
Object.entries(results).forEach(([name, prefs]) =>
|
||||
updateSharedPreferences({name: name, preferences: prefs}),
|
||||
);
|
||||
});
|
||||
|
||||
return {
|
||||
selectedPreferences,
|
||||
sharedPreferences,
|
||||
setSelectedPreferences,
|
||||
setSharedPreference,
|
||||
deleteSharedPreference,
|
||||
};
|
||||
}
|
||||
|
||||
const CHANGELOG_COLUMNS = {
|
||||
event: {value: 'Event'},
|
||||
name: {value: 'Name'},
|
||||
value: {value: 'Value'},
|
||||
};
|
||||
const CHANGELOG_COLUMN_SIZES = {
|
||||
event: '30%',
|
||||
name: '30%',
|
||||
value: '30%',
|
||||
};
|
||||
|
||||
const UPDATED_LABEL = <Text color={colors.lime}>Updated</Text>;
|
||||
const DELETED_LABEL = <Text color={colors.cherry}>Deleted</Text>;
|
||||
|
||||
const InspectorColumn = styled(FlexColumn)({flexGrow: 0.2});
|
||||
const ChangelogColumn = styled(FlexColumn)({
|
||||
flexGrow: 0.8,
|
||||
paddingLeft: '16px',
|
||||
});
|
||||
const RootColumn = styled(FlexColumn)({
|
||||
paddingLeft: '16px',
|
||||
paddingRight: '16px',
|
||||
paddingTop: '16px',
|
||||
});
|
||||
|
||||
export function Component() {
|
||||
const instance = usePlugin(plugin);
|
||||
const selectedPreferences = useValue(instance.selectedPreferences);
|
||||
const sharedPreferences = useValue(instance.sharedPreferences);
|
||||
|
||||
if (selectedPreferences == null) {
|
||||
return null;
|
||||
}
|
||||
const entry = sharedPreferences[selectedPreferences];
|
||||
if (entry == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<RootColumn grow={true}>
|
||||
<Heading>
|
||||
<span style={{marginRight: '16px'}}>Preference File</span>
|
||||
<Select
|
||||
options={Object.keys(sharedPreferences)
|
||||
.sort((a, b) => (a.toLowerCase() > b.toLowerCase() ? 1 : -1))
|
||||
.reduce((obj, item) => {
|
||||
obj[item] = item;
|
||||
return obj;
|
||||
}, {} as Record<string, string>)}
|
||||
selected={selectedPreferences}
|
||||
onChange={instance.setSelectedPreferences}
|
||||
/>
|
||||
</Heading>
|
||||
<FlexRow grow={true} scrollable={true}>
|
||||
<InspectorColumn>
|
||||
<Heading>Inspector</Heading>
|
||||
<ManagedDataInspector
|
||||
data={entry.preferences}
|
||||
setValue={async (path: Array<string>, value: any) => {
|
||||
if (entry == null) {
|
||||
return;
|
||||
}
|
||||
const values = entry.preferences;
|
||||
let newValue = value;
|
||||
if (path.length === 2 && values) {
|
||||
newValue = clone(values[path[0]]);
|
||||
newValue[path[1]] = value;
|
||||
}
|
||||
await instance.setSharedPreference({
|
||||
sharedPreferencesName: selectedPreferences,
|
||||
preferenceName: path[0],
|
||||
preferenceValue: newValue,
|
||||
});
|
||||
}}
|
||||
onDelete={async (path: Array<string>) =>
|
||||
await instance.deleteSharedPreference({
|
||||
sharedPreferencesName: selectedPreferences,
|
||||
preferenceName: path[0],
|
||||
})
|
||||
}
|
||||
/>
|
||||
</InspectorColumn>
|
||||
<ChangelogColumn>
|
||||
<Heading>Changelog</Heading>
|
||||
<ManagedTable
|
||||
columnSizes={CHANGELOG_COLUMN_SIZES}
|
||||
columns={CHANGELOG_COLUMNS}
|
||||
rowLineHeight={26}
|
||||
rows={entry.changesList.map((element, index) => {
|
||||
return {
|
||||
columns: {
|
||||
event: {
|
||||
value: element.deleted ? DELETED_LABEL : UPDATED_LABEL,
|
||||
},
|
||||
name: {value: element.name},
|
||||
value: {value: String(element.value)},
|
||||
},
|
||||
key: String(index),
|
||||
};
|
||||
})}
|
||||
/>
|
||||
</ChangelogColumn>
|
||||
</FlexRow>
|
||||
</RootColumn>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user