Enable Marketplace for Flipper (#3491)

Summary:
This is PR on top of: https://github.com/facebook/flipper/pull/3473

It adds an option to Settings to allow distribution of marketplace plugins.

Also includes a simple fetch function to retrieve data from external API/server.

## Changelog

Allow marketplace plugins

Pull Request resolved: https://github.com/facebook/flipper/pull/3491

Test Plan:
1. Enable marketplace
2. Provide custom marketplace server (it will serve the list of internal plugins with downloadURL)
3. Test if can see Available plugins and can download/remove the plugin
4. If new update for the plugin, it should also allow auto update

Reviewed By: antonk52

Differential Revision: D34586339

Pulled By: nikoant

fbshipit-source-id: c887982aa0f0f9abd3b5360f22e8692a2445d345
This commit is contained in:
Anton Nikolaev
2022-03-07 02:49:49 -08:00
committed by Facebook GitHub Bot
parent 5b6000b424
commit 37ff34390a
9 changed files with 175 additions and 19 deletions

View File

@@ -18,7 +18,11 @@ import {connect} from 'react-redux';
import {State as Store} from '../reducers';
import {flush} from '../utils/persistor';
import ToggledSection from './settings/ToggledSection';
import {FilePathConfigField, ConfigText} from './settings/configFields';
import {
FilePathConfigField,
ConfigText,
URLConfigField,
} from './settings/configFields';
import KeyboardShortcutInput from './settings/KeyboardShortcutInput';
import {isEqual, isMatch, isEmpty} from 'lodash';
import LauncherSettingsPanel from '../fb-stubs/LauncherSettingsPanel';
@@ -30,7 +34,12 @@ import {
sleep,
} from 'flipper-common';
import {Modal, message, Button} from 'antd';
import {Layout, withTrackingScope, _NuxManagerContext} from 'flipper-plugin';
import {
Layout,
withTrackingScope,
_NuxManagerContext,
NUX,
} from 'flipper-plugin';
import {getRenderHostInstance} from '../RenderHost';
import {loadTheme} from '../utils/loadTheme';
@@ -118,6 +127,9 @@ class SettingsSheet extends Component<Props, State> {
reactNative,
darkMode,
suppressPluginErrors,
enablePluginMarketplace,
enablePluginMarketplaceAutoUpdate,
marketplaceURL,
} = this.state.updatedSettings;
const settingsPristine =
@@ -324,6 +336,51 @@ class SettingsSheet extends Component<Props, State> {
}}
/>
</ToggledSection>
<NUX
// TODO: provide link to Flipper doc with more details
title="Plugin marketplace serve as a way to distribute private/internal plugins"
placement="right">
<ToggledSection
label="Enable plugin marketplace"
toggled={enablePluginMarketplace}
frozen={false}
onChange={(v) => {
this.setState({
updatedSettings: {
...this.state.updatedSettings,
enablePluginMarketplace: v,
},
});
}}>
<URLConfigField
label="Martkeplace URL"
defaultValue={
marketplaceURL || 'http://plugin-marketplace.local/get-plugins'
}
onChange={(v) => {
this.setState({
updatedSettings: {
...this.state.updatedSettings,
marketplaceURL: v,
},
});
}}
/>
<ToggledSection
label="Enable auto update"
toggled={enablePluginMarketplaceAutoUpdate}
frozen={false}
onChange={(v) => {
this.setState({
updatedSettings: {
...this.state.updatedSettings,
enablePluginMarketplaceAutoUpdate: v,
},
});
}}
/>
</ToggledSection>
</NUX>
<Layout.Right center>
<span>Reset all new user tooltips</span>
<ResetTooltips />

View File

@@ -154,3 +154,60 @@ export function ConfigText(props: {content: string; frozen?: boolean}) {
</ConfigFieldContainer>
);
}
export function URLConfigField(props: {
label: string;
resetValue?: string;
defaultValue: string;
onChange: (path: string) => void;
frozen?: boolean;
}) {
const [value, setValue] = useState(props.defaultValue);
const [isValid, setIsValid] = useState(true);
useEffect(() => {
try {
const url = new URL(value);
const isValidUrl =
['http:', 'https:'].includes(url.protocol) &&
url.href.startsWith(value);
setIsValid(isValidUrl);
} catch (_) {
setIsValid(false);
}
}, [value]);
return (
<ConfigFieldContainer>
<InfoText>{props.label}</InfoText>
<FileInputBox
placeholder={props.label}
value={value}
isValid={isValid}
onChange={(e) => {
setValue(e.target.value);
props.onChange(e.target.value);
}}
/>
{props.resetValue && (
<FlexColumn
title={`Reset to default value ${props.resetValue}`}
onClick={() => {
setValue(props.resetValue!);
props.onChange(props.resetValue!);
}}>
<CenteredGlyph
color={theme.primaryColor}
name="undo"
variant="outline"
/>
</FlexColumn>
)}
{isValid ? null : (
<CenteredGlyph name="caution-triangle" color={colors.yellow} />
)}
{props.frozen && <GrayedOutOverlay />}
</ConfigFieldContainer>
);
}