You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-07-16 00:14:34 +02:00
Mobile: Plugin support: Simplify reporting plugin issues (#10319)
This commit is contained in:
@ -0,0 +1,115 @@
|
||||
import { PluginItem } from '@joplin/lib/components/shared/config/plugins/types';
|
||||
import * as React from 'react';
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
import { Button, IconButton, List, Portal, Text } from 'react-native-paper';
|
||||
import getPluginIssueReportUrl from '@joplin/lib/services/plugins/utils/getPluginIssueReportUrl';
|
||||
import { Linking, ScrollView, StyleSheet, View } from 'react-native';
|
||||
import DismissibleDialog from '../../../../DismissibleDialog';
|
||||
import openWebsiteForPlugin from '../utils/openWebsiteForPlugin';
|
||||
|
||||
interface Props {
|
||||
themeId: number;
|
||||
size: number;
|
||||
item: PluginItem;
|
||||
onModalDismiss?: ()=> void;
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
aboutPluginContainer: {
|
||||
paddingLeft: 10,
|
||||
paddingRight: 10,
|
||||
paddingBottom: 10,
|
||||
},
|
||||
descriptionText: {
|
||||
marginTop: 5,
|
||||
marginBottom: 5,
|
||||
},
|
||||
fraudulentPluginButton: {
|
||||
opacity: 0.6,
|
||||
},
|
||||
});
|
||||
|
||||
const PluginInfoModal: React.FC<Props> = props => {
|
||||
const aboutPlugin = (
|
||||
<View style={styles.aboutPluginContainer}>
|
||||
<Text variant='titleLarge'>{props.item.manifest.name}</Text>
|
||||
<Text variant='bodyLarge'>{props.item.manifest.author ? _('by %s', props.item.manifest.author) : ''}</Text>
|
||||
<Text style={styles.descriptionText}>{props.item.manifest.description ?? _('No description')}</Text>
|
||||
</View>
|
||||
);
|
||||
|
||||
const onAboutPress = useCallback(() => {
|
||||
void openWebsiteForPlugin({ item: props.item });
|
||||
}, [props.item]);
|
||||
|
||||
const reportIssueUrl = useMemo(() => {
|
||||
return getPluginIssueReportUrl(props.item.manifest);
|
||||
}, [props.item]);
|
||||
|
||||
const onReportIssuePress = useCallback(() => {
|
||||
void Linking.openURL(reportIssueUrl);
|
||||
}, [reportIssueUrl]);
|
||||
|
||||
const reportIssueButton = (
|
||||
<List.Item
|
||||
left={props => <List.Icon {...props} icon='bug'/>}
|
||||
title={_('Report an issue')}
|
||||
onPress={onReportIssuePress}
|
||||
/>
|
||||
);
|
||||
|
||||
const onReportFraudulentPress = useCallback(() => {
|
||||
void Linking.openURL('https://github.com/laurent22/joplin/security/advisories/new');
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Portal>
|
||||
<DismissibleDialog
|
||||
themeId={props.themeId}
|
||||
visible={true}
|
||||
onDismiss={props.onModalDismiss}
|
||||
>
|
||||
<ScrollView>
|
||||
{aboutPlugin}
|
||||
<List.Item
|
||||
left={props => <List.Icon {...props} icon='web'/>}
|
||||
title={_('About')}
|
||||
onPress={onAboutPress}
|
||||
/>
|
||||
{ reportIssueUrl ? reportIssueButton : null }
|
||||
</ScrollView>
|
||||
<Button
|
||||
icon='shield-bug'
|
||||
style={styles.fraudulentPluginButton}
|
||||
onPress={onReportFraudulentPress}
|
||||
>{_('Report fraudulent plugin')}</Button>
|
||||
</DismissibleDialog>
|
||||
</Portal>
|
||||
);
|
||||
};
|
||||
|
||||
const PluginInfoButton: React.FC<Props> = props => {
|
||||
const [showInfoModal, setShowInfoModal] = useState(false);
|
||||
const onInfoButtonPress = useCallback(() => {
|
||||
setShowInfoModal(true);
|
||||
}, []);
|
||||
|
||||
const onModalDismiss = useCallback(() => {
|
||||
setShowInfoModal(false);
|
||||
props.onModalDismiss?.();
|
||||
}, [props.onModalDismiss]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{showInfoModal ? <PluginInfoModal {...props} onModalDismiss={onModalDismiss} /> : null}
|
||||
<IconButton
|
||||
size={props.size}
|
||||
icon='information'
|
||||
onPress={onInfoButtonPress}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default PluginInfoButton;
|
@ -6,6 +6,7 @@ import { PluginItem } from '@joplin/lib/components/shared/config/plugins/types';
|
||||
import shim from '@joplin/lib/shim';
|
||||
import PluginService from '@joplin/lib/services/plugins/PluginService';
|
||||
import ActionButton, { PluginCallback } from './ActionButton';
|
||||
import PluginInfoButton from './PluginInfoButton';
|
||||
|
||||
export enum InstallState {
|
||||
NotInstalled,
|
||||
@ -21,6 +22,7 @@ export enum UpdateState {
|
||||
}
|
||||
|
||||
interface Props {
|
||||
themeId: number;
|
||||
item: PluginItem;
|
||||
isCompatible: boolean;
|
||||
|
||||
@ -28,11 +30,11 @@ interface Props {
|
||||
installState?: InstallState;
|
||||
updateState?: UpdateState;
|
||||
|
||||
onAboutPress?: PluginCallback;
|
||||
onInstall?: PluginCallback;
|
||||
onUpdate?: PluginCallback;
|
||||
onDelete?: PluginCallback;
|
||||
onToggle?: PluginCallback;
|
||||
onAboutPress?: PluginCallback;
|
||||
onShowPluginLog?: PluginCallback;
|
||||
}
|
||||
|
||||
@ -113,7 +115,7 @@ const PluginBox: React.FC<Props> = props => {
|
||||
);
|
||||
const disableButton = <ActionButton item={item} onPress={props.onToggle} title={_('Disable')}/>;
|
||||
const enableButton = <ActionButton item={item} onPress={props.onToggle} title={_('Enable')}/>;
|
||||
const aboutButton = <ActionButton icon='web' item={item} onPress={props.onAboutPress} title={_('About')}/>;
|
||||
const aboutButton = <ActionButton item={item} onPress={props.onAboutPress} icon='web' title={_('About')}/>;
|
||||
|
||||
const renderErrorsChip = () => {
|
||||
if (!props.hasErrors) return null;
|
||||
@ -165,6 +167,13 @@ const PluginBox: React.FC<Props> = props => {
|
||||
);
|
||||
};
|
||||
|
||||
const renderRightEdgeButton = (buttonProps: { size: number }) => {
|
||||
// If .onAboutPress is given (e.g. when searching), there's another way to get information
|
||||
// about the plugin. In this case, we don't show the right-side information link.
|
||||
if (props.onAboutPress) return null;
|
||||
return <PluginInfoButton {...buttonProps} themeId={props.themeId} item={props.item}/>;
|
||||
};
|
||||
|
||||
const updateStateIsIdle = props.updateState !== UpdateState.Idle;
|
||||
|
||||
const titleComponent = <>
|
||||
@ -177,6 +186,7 @@ const PluginBox: React.FC<Props> = props => {
|
||||
titleStyle={styles.title}
|
||||
subtitle={manifest.description}
|
||||
left={PluginIcon}
|
||||
right={renderRightEdgeButton}
|
||||
/>
|
||||
<Card.Content>
|
||||
<View style={{ flexDirection: 'row' }}>
|
||||
|
Reference in New Issue
Block a user