Track plugin selection steps
Summary: Sets up some logging for the various drop-out points when going through the deeplink flow. Reviewed By: lblasa Differential Revision: D31345623 fbshipit-source-id: a06ca97c1e687e39ea97a1f47fd8bb614149056f
This commit is contained in:
committed by
Facebook GitHub Bot
parent
bce2cdc316
commit
37529af074
@@ -99,11 +99,16 @@ test('Will throw error on invalid deeplinks', async () => {
|
|||||||
).rejects.toThrowErrorMatchingInlineSnapshot(`"Unknown deeplink"`);
|
).rejects.toThrowErrorMatchingInlineSnapshot(`"Unknown deeplink"`);
|
||||||
|
|
||||||
expect(logger.track).toHaveBeenCalledTimes(2);
|
expect(logger.track).toHaveBeenCalledTimes(2);
|
||||||
expect(logger.track).toHaveBeenLastCalledWith('usage', 'deeplink', {
|
expect(logger.track).toHaveBeenLastCalledWith(
|
||||||
|
'usage',
|
||||||
|
'deeplink',
|
||||||
|
{
|
||||||
query: 'flipper://test',
|
query: 'flipper://test',
|
||||||
state: 'ERROR',
|
state: 'ERROR',
|
||||||
errorMessage: 'Unknown deeplink',
|
errorMessage: 'Unknown deeplink',
|
||||||
});
|
},
|
||||||
|
undefined,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Will throw error on invalid protocol', async () => {
|
test('Will throw error on invalid protocol', async () => {
|
||||||
@@ -116,11 +121,16 @@ test('Will throw error on invalid protocol', async () => {
|
|||||||
).rejects.toThrowErrorMatchingInlineSnapshot(`"Unknown deeplink"`);
|
).rejects.toThrowErrorMatchingInlineSnapshot(`"Unknown deeplink"`);
|
||||||
|
|
||||||
expect(logger.track).toHaveBeenCalledTimes(2);
|
expect(logger.track).toHaveBeenCalledTimes(2);
|
||||||
expect(logger.track).toHaveBeenLastCalledWith('usage', 'deeplink', {
|
expect(logger.track).toHaveBeenLastCalledWith(
|
||||||
|
'usage',
|
||||||
|
'deeplink',
|
||||||
|
{
|
||||||
query: 'notflipper://test',
|
query: 'notflipper://test',
|
||||||
state: 'ERROR',
|
state: 'ERROR',
|
||||||
errorMessage: 'Unknown deeplink',
|
errorMessage: 'Unknown deeplink',
|
||||||
});
|
},
|
||||||
|
undefined,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Will track deeplinks', async () => {
|
test('Will track deeplinks', async () => {
|
||||||
@@ -142,9 +152,14 @@ test('Will track deeplinks', async () => {
|
|||||||
'flipper://open-plugin?plugin-id=TestPlugin&client=TestApp&payload=universe',
|
'flipper://open-plugin?plugin-id=TestPlugin&client=TestApp&payload=universe',
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(logger.track).toHaveBeenCalledWith('usage', 'deeplink', {
|
expect(logger.track).toHaveBeenCalledWith(
|
||||||
|
'usage',
|
||||||
|
'deeplink',
|
||||||
|
{
|
||||||
query:
|
query:
|
||||||
'flipper://open-plugin?plugin-id=TestPlugin&client=TestApp&payload=universe',
|
'flipper://open-plugin?plugin-id=TestPlugin&client=TestApp&payload=universe',
|
||||||
state: 'INIT',
|
state: 'INIT',
|
||||||
});
|
},
|
||||||
|
undefined,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -20,22 +20,7 @@ import {selectPlugin, getAllClients} from './reducers/connections';
|
|||||||
import {Dialog} from 'flipper-plugin';
|
import {Dialog} from 'flipper-plugin';
|
||||||
import {handleOpenPluginDeeplink} from './dispatcher/handleOpenPluginDeeplink';
|
import {handleOpenPluginDeeplink} from './dispatcher/handleOpenPluginDeeplink';
|
||||||
import {message} from 'antd';
|
import {message} from 'antd';
|
||||||
|
import {track} from './deeplinkTracking';
|
||||||
type DeeplinkInteraction = {
|
|
||||||
state: 'INIT' | 'ERROR';
|
|
||||||
errorMessage?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
function track(
|
|
||||||
logger: Logger,
|
|
||||||
query: string,
|
|
||||||
interaction: DeeplinkInteraction,
|
|
||||||
) {
|
|
||||||
logger.track('usage', 'deeplink', {
|
|
||||||
...interaction,
|
|
||||||
query,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const UNKNOWN = 'Unknown deeplink';
|
const UNKNOWN = 'Unknown deeplink';
|
||||||
/**
|
/**
|
||||||
@@ -63,7 +48,7 @@ export async function handleDeeplink(
|
|||||||
throw unknownError();
|
throw unknownError();
|
||||||
}
|
}
|
||||||
if (uri.href.startsWith('flipper://open-plugin')) {
|
if (uri.href.startsWith('flipper://open-plugin')) {
|
||||||
return handleOpenPluginDeeplink(store, query);
|
return handleOpenPluginDeeplink(store, query, trackInteraction);
|
||||||
}
|
}
|
||||||
if (uri.pathname.match(/^\/*import\/*$/)) {
|
if (uri.pathname.match(/^\/*import\/*$/)) {
|
||||||
const url = uri.searchParams.get('url');
|
const url = uri.searchParams.get('url');
|
||||||
|
|||||||
48
desktop/app/src/deeplinkTracking.tsx
Normal file
48
desktop/app/src/deeplinkTracking.tsx
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
/**
|
||||||
|
* 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 {Logger} from './fb-interfaces/Logger';
|
||||||
|
|
||||||
|
export type OpenPluginParams = {
|
||||||
|
pluginId: string;
|
||||||
|
client: string | undefined;
|
||||||
|
devices: string[];
|
||||||
|
payload: string | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type DeeplinkInteraction = {
|
||||||
|
state:
|
||||||
|
| 'INIT'
|
||||||
|
| 'ERROR'
|
||||||
|
| 'PLUGIN_LIGHTHOUSE_BAIL'
|
||||||
|
| 'PLUGIN_STATUS_BAIL'
|
||||||
|
| 'PLUGIN_DEVICE_BAIL'
|
||||||
|
| 'PLUGIN_DEVICE_UNSUPPORTED'
|
||||||
|
| 'PLUGIN_CLIENT_UNSUPPORTED'
|
||||||
|
| 'PLUGIN_OPEN_SUCCESS';
|
||||||
|
errorMessage?: string;
|
||||||
|
plugin?: OpenPluginParams;
|
||||||
|
extra?: object;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function track(
|
||||||
|
logger: Logger,
|
||||||
|
query: string,
|
||||||
|
interaction: DeeplinkInteraction,
|
||||||
|
) {
|
||||||
|
logger.track(
|
||||||
|
'usage',
|
||||||
|
'deeplink',
|
||||||
|
{
|
||||||
|
...interaction,
|
||||||
|
query,
|
||||||
|
},
|
||||||
|
interaction.plugin?.pluginId,
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -19,11 +19,25 @@ import {
|
|||||||
createState,
|
createState,
|
||||||
useValue,
|
useValue,
|
||||||
DevicePluginClient,
|
DevicePluginClient,
|
||||||
|
Dialog,
|
||||||
} from 'flipper-plugin';
|
} from 'flipper-plugin';
|
||||||
import {parseOpenPluginParams} from '../handleOpenPluginDeeplink';
|
import {parseOpenPluginParams} from '../handleOpenPluginDeeplink';
|
||||||
import {handleDeeplink} from '../../deeplink';
|
import {handleDeeplink} from '../../deeplink';
|
||||||
import {selectPlugin} from '../../reducers/connections';
|
import {selectPlugin} from '../../reducers/connections';
|
||||||
|
|
||||||
|
let origAlertImpl: any;
|
||||||
|
let origConfirmImpl: any;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
origAlertImpl = Dialog.alert;
|
||||||
|
origConfirmImpl = Dialog.confirm;
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
Dialog.alert = origAlertImpl;
|
||||||
|
Dialog.confirm = origConfirmImpl;
|
||||||
|
});
|
||||||
|
|
||||||
test('open-plugin deeplink parsing', () => {
|
test('open-plugin deeplink parsing', () => {
|
||||||
const testpayload = 'http://www.google/?test=c o%20o+l';
|
const testpayload = 'http://www.google/?test=c o%20o+l';
|
||||||
const testLink =
|
const testLink =
|
||||||
@@ -83,6 +97,7 @@ test('Triggering a deeplink will work', async () => {
|
|||||||
const {renderer, client, store, logger} = await renderMockFlipperWithPlugin(
|
const {renderer, client, store, logger} = await renderMockFlipperWithPlugin(
|
||||||
definition,
|
definition,
|
||||||
);
|
);
|
||||||
|
logger.track = jest.fn();
|
||||||
|
|
||||||
expect(linksSeen).toEqual([]);
|
expect(linksSeen).toEqual([]);
|
||||||
|
|
||||||
@@ -120,6 +135,33 @@ test('Triggering a deeplink will work', async () => {
|
|||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
`);
|
`);
|
||||||
|
expect(logger.track).toHaveBeenCalledTimes(2);
|
||||||
|
expect(logger.track).toHaveBeenCalledWith(
|
||||||
|
'usage',
|
||||||
|
'deeplink',
|
||||||
|
{
|
||||||
|
query:
|
||||||
|
'flipper://open-plugin?plugin-id=TestPlugin&client=TestApp&payload=universe',
|
||||||
|
state: 'INIT',
|
||||||
|
},
|
||||||
|
undefined,
|
||||||
|
);
|
||||||
|
expect(logger.track).toHaveBeenCalledWith(
|
||||||
|
'usage',
|
||||||
|
'deeplink',
|
||||||
|
{
|
||||||
|
query:
|
||||||
|
'flipper://open-plugin?plugin-id=TestPlugin&client=TestApp&payload=universe',
|
||||||
|
state: 'PLUGIN_OPEN_SUCCESS',
|
||||||
|
plugin: {
|
||||||
|
client: 'TestApp',
|
||||||
|
devices: [],
|
||||||
|
payload: 'universe',
|
||||||
|
pluginId: 'TestPlugin',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'TestPlugin',
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('triggering a deeplink without applicable device can wait for a device', async () => {
|
test('triggering a deeplink without applicable device can wait for a device', async () => {
|
||||||
@@ -283,3 +325,63 @@ test('triggering a deeplink without applicable client can wait for a device', as
|
|||||||
</body>
|
</body>
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('triggering a deeplink with incompatible device will cause bail', async () => {
|
||||||
|
const definition = TestUtils.createTestDevicePlugin(
|
||||||
|
{
|
||||||
|
Component() {
|
||||||
|
return <p>Hello</p>;
|
||||||
|
},
|
||||||
|
devicePlugin() {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'DevicePlugin',
|
||||||
|
supportedDevices: [{os: 'iOS'}],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const {store, logger, createDevice} = await renderMockFlipperWithPlugin(
|
||||||
|
definition,
|
||||||
|
);
|
||||||
|
logger.track = jest.fn();
|
||||||
|
|
||||||
|
// Skipping user interactions.
|
||||||
|
Dialog.alert = (async () => {}) as any;
|
||||||
|
Dialog.confirm = (async () => {}) as any;
|
||||||
|
|
||||||
|
store.dispatch(
|
||||||
|
selectPlugin({selectedPlugin: 'nonexisting', deepLinkPayload: null}),
|
||||||
|
);
|
||||||
|
|
||||||
|
const handlePromise = handleDeeplink(
|
||||||
|
store,
|
||||||
|
logger,
|
||||||
|
`flipper://open-plugin?plugin-id=${definition.id}&devices=iOS`,
|
||||||
|
);
|
||||||
|
|
||||||
|
jest.runAllTimers();
|
||||||
|
|
||||||
|
// create a new device that doesn't match spec
|
||||||
|
createDevice({serial: 'device2', os: 'Android'});
|
||||||
|
|
||||||
|
// wait for dialogues
|
||||||
|
await handlePromise;
|
||||||
|
|
||||||
|
expect(logger.track).toHaveBeenCalledTimes(2);
|
||||||
|
expect(logger.track).toHaveBeenCalledWith(
|
||||||
|
'usage',
|
||||||
|
'deeplink',
|
||||||
|
{
|
||||||
|
plugin: {
|
||||||
|
client: undefined,
|
||||||
|
devices: ['iOS'],
|
||||||
|
payload: undefined,
|
||||||
|
pluginId: 'DevicePlugin',
|
||||||
|
},
|
||||||
|
query: 'flipper://open-plugin?plugin-id=DevicePlugin&devices=iOS',
|
||||||
|
state: 'PLUGIN_DEVICE_BAIL',
|
||||||
|
},
|
||||||
|
'DevicePlugin',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import {UserNotSignedInError} from '../utils/errors';
|
|||||||
import {selectPlugin, setPluginEnabled} from '../reducers/connections';
|
import {selectPlugin, setPluginEnabled} from '../reducers/connections';
|
||||||
import {getUpdateAvailableMessage} from '../chrome/UpdateIndicator';
|
import {getUpdateAvailableMessage} from '../chrome/UpdateIndicator';
|
||||||
import {Typography} from 'antd';
|
import {Typography} from 'antd';
|
||||||
import {getPluginStatus} from '../utils/pluginUtils';
|
import {getPluginStatus, PluginStatus} from '../utils/pluginUtils';
|
||||||
import {loadPluginsFromMarketplace} from './fb-stubs/pluginMarketplace';
|
import {loadPluginsFromMarketplace} from './fb-stubs/pluginMarketplace';
|
||||||
import {loadPlugin, switchPlugin} from '../reducers/pluginManager';
|
import {loadPlugin, switchPlugin} from '../reducers/pluginManager';
|
||||||
import {startPluginDownload} from '../reducers/pluginDownloads';
|
import {startPluginDownload} from '../reducers/pluginDownloads';
|
||||||
@@ -29,13 +29,7 @@ import Client from '../Client';
|
|||||||
import {RocketOutlined} from '@ant-design/icons';
|
import {RocketOutlined} from '@ant-design/icons';
|
||||||
import {showEmulatorLauncher} from '../sandy-chrome/appinspect/LaunchEmulator';
|
import {showEmulatorLauncher} from '../sandy-chrome/appinspect/LaunchEmulator';
|
||||||
import {getAllClients} from '../reducers/connections';
|
import {getAllClients} from '../reducers/connections';
|
||||||
|
import {DeeplinkInteraction, OpenPluginParams} from '../deeplinkTracking';
|
||||||
type OpenPluginParams = {
|
|
||||||
pluginId: string;
|
|
||||||
client: string | undefined;
|
|
||||||
devices: string[];
|
|
||||||
payload: string | undefined;
|
|
||||||
};
|
|
||||||
|
|
||||||
export function parseOpenPluginParams(query: string): OpenPluginParams {
|
export function parseOpenPluginParams(query: string): OpenPluginParams {
|
||||||
// 'flipper://open-plugin?plugin-id=graphql&client=facebook&devices=android,ios&chrome=1&payload='
|
// 'flipper://open-plugin?plugin-id=graphql&client=facebook&devices=android,ios&chrome=1&payload='
|
||||||
@@ -54,15 +48,33 @@ export function parseOpenPluginParams(query: string): OpenPluginParams {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function handleOpenPluginDeeplink(store: Store, query: string) {
|
export async function handleOpenPluginDeeplink(
|
||||||
|
store: Store,
|
||||||
|
query: string,
|
||||||
|
trackInteraction: (interaction: DeeplinkInteraction) => void,
|
||||||
|
) {
|
||||||
const params = parseOpenPluginParams(query);
|
const params = parseOpenPluginParams(query);
|
||||||
const title = `Opening plugin ${params.pluginId}…`;
|
const title = `Opening plugin ${params.pluginId}…`;
|
||||||
|
|
||||||
if (!(await verifyLighthouseAndUserLoggedIn(store, title))) {
|
if (!(await verifyLighthouseAndUserLoggedIn(store, title))) {
|
||||||
|
trackInteraction({
|
||||||
|
state: 'PLUGIN_LIGHTHOUSE_BAIL',
|
||||||
|
plugin: params,
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await verifyFlipperIsUpToDate(title);
|
await verifyFlipperIsUpToDate(title);
|
||||||
if (!(await verifyPluginStatus(store, params.pluginId, title))) {
|
const [pluginStatusResult, pluginStatus] = await verifyPluginStatus(
|
||||||
|
store,
|
||||||
|
params.pluginId,
|
||||||
|
title,
|
||||||
|
);
|
||||||
|
if (!pluginStatusResult) {
|
||||||
|
trackInteraction({
|
||||||
|
state: 'PLUGIN_STATUS_BAIL',
|
||||||
|
plugin: params,
|
||||||
|
extra: {pluginStatus},
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,6 +91,10 @@ export async function handleOpenPluginDeeplink(store: Store, query: string) {
|
|||||||
isDevicePlugin,
|
isDevicePlugin,
|
||||||
);
|
);
|
||||||
if (deviceOrClient === false) {
|
if (deviceOrClient === false) {
|
||||||
|
trackInteraction({
|
||||||
|
state: 'PLUGIN_DEVICE_BAIL',
|
||||||
|
plugin: params,
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const client: Client | undefined = isDevicePlugin
|
const client: Client | undefined = isDevicePlugin
|
||||||
@@ -95,6 +111,11 @@ export async function handleOpenPluginDeeplink(store: Store, query: string) {
|
|||||||
type: 'error',
|
type: 'error',
|
||||||
message: `This plugin is not supported by device ${device.displayTitle()}`,
|
message: `This plugin is not supported by device ${device.displayTitle()}`,
|
||||||
});
|
});
|
||||||
|
trackInteraction({
|
||||||
|
state: 'PLUGIN_DEVICE_UNSUPPORTED',
|
||||||
|
plugin: params,
|
||||||
|
extra: {device: device.displayTitle()},
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!isDevicePlugin && !client!.plugins.has(params.pluginId)) {
|
if (!isDevicePlugin && !client!.plugins.has(params.pluginId)) {
|
||||||
@@ -103,6 +124,12 @@ export async function handleOpenPluginDeeplink(store: Store, query: string) {
|
|||||||
type: 'error',
|
type: 'error',
|
||||||
message: `This plugin is not supported by client ${client!.query.app}`,
|
message: `This plugin is not supported by client ${client!.query.app}`,
|
||||||
});
|
});
|
||||||
|
trackInteraction({
|
||||||
|
state: 'PLUGIN_CLIENT_UNSUPPORTED',
|
||||||
|
plugin: params,
|
||||||
|
extra: {client: client!.query.app},
|
||||||
|
});
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify plugin enabled
|
// verify plugin enabled
|
||||||
@@ -137,6 +164,10 @@ export async function handleOpenPluginDeeplink(store: Store, query: string) {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
trackInteraction({
|
||||||
|
state: 'PLUGIN_OPEN_SUCCESS',
|
||||||
|
plugin: params,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if user is connected to VPN and logged in. Returns true if OK, or false if aborted
|
// check if user is connected to VPN and logged in. Returns true if OK, or false if aborted
|
||||||
@@ -269,7 +300,7 @@ async function verifyPluginStatus(
|
|||||||
store: Store,
|
store: Store,
|
||||||
pluginId: string,
|
pluginId: string,
|
||||||
title: string,
|
title: string,
|
||||||
): Promise<boolean> {
|
): Promise<[boolean, PluginStatus]> {
|
||||||
// make sure we have marketplace plugin data present
|
// make sure we have marketplace plugin data present
|
||||||
if (!isTest() && !store.getState().plugins.marketplacePlugins.length) {
|
if (!isTest() && !store.getState().plugins.marketplacePlugins.length) {
|
||||||
// plugins not yet fetched
|
// plugins not yet fetched
|
||||||
@@ -281,21 +312,21 @@ async function verifyPluginStatus(
|
|||||||
const [status, reason] = getPluginStatus(store, pluginId);
|
const [status, reason] = getPluginStatus(store, pluginId);
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case 'ready':
|
case 'ready':
|
||||||
return true;
|
return [true, status];
|
||||||
case 'unknown':
|
case 'unknown':
|
||||||
await Dialog.alert({
|
await Dialog.alert({
|
||||||
type: 'warning',
|
type: 'warning',
|
||||||
title,
|
title,
|
||||||
message: `No plugin with id '${pluginId}' is known to Flipper. Please correct the deeplink, or install the plugin from NPM using the plugin manager.`,
|
message: `No plugin with id '${pluginId}' is known to Flipper. Please correct the deeplink, or install the plugin from NPM using the plugin manager.`,
|
||||||
});
|
});
|
||||||
return false;
|
return [false, status];
|
||||||
case 'failed':
|
case 'failed':
|
||||||
await Dialog.alert({
|
await Dialog.alert({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
title,
|
title,
|
||||||
message: `We found plugin '${pluginId}', but failed to load it: ${reason}. Please check the logs for more details`,
|
message: `We found plugin '${pluginId}', but failed to load it: ${reason}. Please check the logs for more details`,
|
||||||
});
|
});
|
||||||
return false;
|
return [false, status];
|
||||||
case 'gatekeeped':
|
case 'gatekeeped':
|
||||||
if (
|
if (
|
||||||
!(await Dialog.confirm({
|
!(await Dialog.confirm({
|
||||||
@@ -318,7 +349,7 @@ async function verifyPluginStatus(
|
|||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
) {
|
) {
|
||||||
return false;
|
return [false, status];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'bundle_installable': {
|
case 'bundle_installable': {
|
||||||
@@ -328,7 +359,7 @@ async function verifyPluginStatus(
|
|||||||
}
|
}
|
||||||
case 'marketplace_installable': {
|
case 'marketplace_installable': {
|
||||||
if (!(await installMarketPlacePlugin(store, pluginId, title))) {
|
if (!(await installMarketPlacePlugin(store, pluginId, title))) {
|
||||||
return false;
|
return [false, status];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -402,19 +402,18 @@ export function computeActivePluginList({
|
|||||||
return pluginList;
|
return pluginList;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getPluginStatus(
|
export type PluginStatus =
|
||||||
store: Store,
|
|
||||||
id: string,
|
|
||||||
): [
|
|
||||||
state:
|
|
||||||
| 'ready'
|
| 'ready'
|
||||||
| 'unknown'
|
| 'unknown'
|
||||||
| 'failed'
|
| 'failed'
|
||||||
| 'gatekeeped'
|
| 'gatekeeped'
|
||||||
| 'bundle_installable'
|
| 'bundle_installable'
|
||||||
| 'marketplace_installable',
|
| 'marketplace_installable';
|
||||||
reason?: string,
|
|
||||||
] {
|
export function getPluginStatus(
|
||||||
|
store: Store,
|
||||||
|
id: string,
|
||||||
|
): [state: PluginStatus, reason?: string] {
|
||||||
const state: PluginsState = store.getState().plugins;
|
const state: PluginsState = store.getState().plugins;
|
||||||
if (state.devicePlugins.has(id) || state.clientPlugins.has(id)) {
|
if (state.devicePlugins.has(id) || state.clientPlugins.has(id)) {
|
||||||
return ['ready'];
|
return ['ready'];
|
||||||
|
|||||||
Reference in New Issue
Block a user