diff --git a/packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginBox.tsx b/packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginBox.tsx index 7670fde1c2..527547205d 100644 --- a/packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginBox.tsx +++ b/packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginBox.tsx @@ -26,6 +26,7 @@ interface Props { installState?: InstallState; updateState?: UpdateState; themeId: number; + isCompatible: boolean; onToggle?: Function; onDelete?: Function; onInstall?: Function; @@ -34,28 +35,20 @@ interface Props { function manifestToItem(manifest: PluginManifest): PluginItem { return { - id: manifest.id, - name: manifest.name, - version: manifest.version, - description: manifest.description, + manifest: manifest, enabled: true, deleted: false, devMode: false, hasBeenUpdated: false, - homepage_url: manifest.homepage_url, }; } export interface PluginItem { - id: string; - name: string; - version: string; - description: string; + manifest: PluginManifest; enabled: boolean; deleted: boolean; devMode: boolean; hasBeenUpdated: boolean; - homepage_url: string; } const CellRoot = styled.div` @@ -71,6 +64,8 @@ const CellRoot = styled.div` margin-right: 20px; margin-bottom: 20px; box-shadow: 1px 1px 3px rgba(0,0,0,0.2); + + opacity: ${props => props.isCompatible ? '1' : '0.6'}; `; const CellTop = styled.div` @@ -91,6 +86,12 @@ const CellFooter = styled.div` flex-direction: row; `; +const NeedUpgradeMessage = styled.span` + font-family: ${props => props.theme.fontFamily}; + color: ${props => props.theme.colorWarn}; + font-size: ${props => props.theme.fontSize}px; +`; + const DevModeLabel = styled.div` border: 1px solid ${props => props.theme.color}; border-radius: 4px; @@ -132,8 +133,8 @@ export default function(props: Props) { const item = props.item ? props.item : manifestToItem(props.manifest); const onNameClick = useCallback(() => { - if (!props.item.homepage_url) return; - bridge().openExternal(props.item.homepage_url); + if (!props.item.manifest.homepage_url) return; + bridge().openExternal(props.item.manifest.homepage_url); }, [props.item]); // For plugins in dev mode things like enabling/disabling or @@ -194,6 +195,16 @@ export default function(props: Props) { function renderFooter() { if (item.devMode) return null; + if (!props.isCompatible) { + return ( + + + {_('Please upgrade Joplin to use this plugin')} + + + ); + } + return ( {renderDeleteButton()} @@ -205,13 +216,13 @@ export default function(props: Props) { } return ( - + - {item.name} {item.deleted ? _('(%s)', 'Deleted') : ''}v{item.version} + {item.manifest.name} {item.deleted ? _('(%s)', 'Deleted') : ''}v{item.manifest.version} {renderToggleButton()} - {item.description} + {item.manifest.description} {renderFooter()} diff --git a/packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginsStates.tsx b/packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginsStates.tsx index ba78cb7aeb..7c80dff61b 100644 --- a/packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginsStates.tsx +++ b/packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginsStates.tsx @@ -63,20 +63,16 @@ function usePluginItems(plugins: Plugins, settings: PluginSettings): PluginItem[ }; output.push({ - id: pluginId, - name: plugin.manifest.name, - version: plugin.manifest.version, - description: plugin.manifest.description, + manifest: plugin.manifest, enabled: setting.enabled, deleted: setting.deleted, devMode: plugin.devMode, hasBeenUpdated: setting.hasBeenUpdated, - homepage_url: plugin.manifest.homepage_url, }); } output.sort((a: PluginItem, b: PluginItem) => { - return a.name < b.name ? -1 : +1; + return a.manifest.name < b.manifest.name ? -1 : +1; }); return output; @@ -134,12 +130,12 @@ export default function(props: Props) { const onDelete = useCallback(async (event: any) => { const item: PluginItem = event.item; - const confirm = await bridge().showConfirmMessageBox(_('Delete plugin "%s"?', item.name)); + const confirm = await bridge().showConfirmMessageBox(_('Delete plugin "%s"?', item.manifest.name)); if (!confirm) return; const newSettings = produce(pluginSettings, (draft: PluginSettings) => { - if (!draft[item.id]) draft[item.id] = defaultPluginSetting(); - draft[item.id].deleted = true; + if (!draft[item.manifest.id]) draft[item.manifest.id] = defaultPluginSetting(); + draft[item.manifest.id].deleted = true; }); props.onChange({ value: pluginService.serializePluginSettings(newSettings) }); @@ -149,8 +145,8 @@ export default function(props: Props) { const item: PluginItem = event.item; const newSettings = produce(pluginSettings, (draft: PluginSettings) => { - if (!draft[item.id]) draft[item.id] = defaultPluginSetting(); - draft[item.id].enabled = !draft[item.id].enabled; + if (!draft[item.manifest.id]) draft[item.manifest.id] = defaultPluginSetting(); + draft[item.manifest.id].enabled = !draft[item.manifest.id].enabled; }); props.onChange({ value: pluginService.serializePluginSettings(newSettings) }); @@ -213,8 +209,8 @@ export default function(props: Props) { for (const item of items) { if (item.deleted) continue; - const isUpdating = updatingPluginsIds[item.id]; - const onUpdateHandler = canBeUpdatedPluginIds[item.id] ? onUpdate : null; + const isUpdating = updatingPluginsIds[item.manifest.id]; + const onUpdateHandler = canBeUpdatedPluginIds[item.manifest.id] ? onUpdate : null; let updateState = UpdateState.Idle; if (onUpdateHandler) updateState = UpdateState.CanUpdate; @@ -222,10 +218,11 @@ export default function(props: Props) { if (item.hasBeenUpdated) updateState = UpdateState.HasBeenUpdated; output.push(); diff --git a/packages/lib/services/plugins/PluginService.ts b/packages/lib/services/plugins/PluginService.ts index 9564630207..3a1a0698c0 100644 --- a/packages/lib/services/plugins/PluginService.ts +++ b/packages/lib/services/plugins/PluginService.ts @@ -334,8 +334,12 @@ export default class PluginService extends BaseService { } } + public isCompatible(pluginVersion: string): boolean { + return compareVersions(this.appVersion_, pluginVersion) >= 0; + } + public async runPlugin(plugin: Plugin) { - if (compareVersions(this.appVersion_, plugin.manifest.app_min_version) < 0) { + if (!this.isCompatible(plugin.manifest.app_min_version)) { throw new Error(`Plugin "${plugin.id}" was disabled because it requires Joplin version ${plugin.manifest.app_min_version} and current version is ${this.appVersion_}.`); } else { this.store_.dispatch({