/** * Copyright (c) Meta Platforms, Inc. and 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, getFlipperLib, } from 'flipper-plugin'; import {clone} from 'lodash'; import React from 'react'; import {Button, notification} from 'antd'; type SharedPreferencesChangeEvent = { preferences: string; name: string; time: number; deleted: boolean; value?: any; }; type SharedPreferences = Record; type SharedPreferencesEntry = { preferences: SharedPreferences; changesList: Array; }; 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 >; setSharedPreference: ( params: SetSharedPreferenceParams, ) => Promise; deleteSharedPreference: ( params: DeleteSharedPreferenceParams, ) => Promise; }; export function plugin(client: PluginClient) { const selectedPreferences = createState(null, { persist: 'selectedPreferences', }); const setSelectedPreferences = (value: string) => selectedPreferences.set(value); const sharedPreferences = createState>( {}, {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, }); } async function saveToFile() { if (selectedPreferences.get() != null) { try { const name = selectedPreferences.get() as string; await getFlipperLib().exportFile( JSON.stringify(sharedPreferences.get()[name]), { defaultPath: name, }, ); } catch (e) { notification.error({ message: 'Save failed', description: `Could not save shared preferences to file`, duration: 15, }); } } } async function loadFromFile() { const file = await getFlipperLib().importFile(); if (file && file.encoding === 'utf-8' && typeof file.data === 'string') { try { const preferences = JSON.parse(file.data) as SharedPreferencesEntry; const name = selectedPreferences.get(); if (name != null) { updateSharedPreferences({ name: name, preferences: preferences.preferences, }); for (const key in preferences.preferences) { await client.send('setSharedPreference', { sharedPreferencesName: name, preferenceName: key, preferenceValue: preferences.preferences[key], }); } } } catch (e) { console.warn('Unable to import shared preferences', e); } } else { console.warn( 'The loaded file either has wrong encoding or is not a valid json file', ); } } 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, saveToFile, loadFromFile, }; } 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 = Updated; const DELETED_LABEL = Deleted; 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 ( Preference File