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:
committed by
Facebook GitHub Bot
parent
5b6000b424
commit
37ff34390a
@@ -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 />
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user