Files
flipper/desktop/plugins/shared_preferences/src/index.tsx
Chaiwat Ekkaewnumchai 402ea2fc14 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
2020-10-23 06:22:02 -07:00

236 lines
6.6 KiB
TypeScript

/**
* 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>
);
}