1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-11-29 22:48:10 +02:00

Chore: Apply changes from mobile plugins to lib/ and app-desktop/ (#10079)

This commit is contained in:
Henry Heino
2024-03-09 03:03:57 -08:00
committed by GitHub
parent 91004f5714
commit 25cd5affca
37 changed files with 418 additions and 205 deletions

View File

@@ -22,35 +22,35 @@ export interface Joplin {
export default class BasePlatformImplementation {
public get versionInfo(): VersionInfo {
throw new Error('Not implemented');
throw new Error('Not implemented: versionInfo');
}
public get clipboard(): any {
throw new Error('Not implemented');
throw new Error('Not implemented: clipboard');
}
public get nativeImage(): any {
throw new Error('Not implemented');
throw new Error('Not implemented: nativeImage');
}
public get window(): WindowImplementation {
throw new Error('Not implemented');
throw new Error('Not implemented: window');
}
public registerComponent(_name: string, _component: any) {
throw new Error('Not implemented');
throw new Error('Not implemented: registerComponent');
}
public unregisterComponent(_name: string) {
throw new Error('Not implemented');
throw new Error('Not implemented: unregisterComponent');
}
public get joplin(): Joplin {
throw new Error('Not implemented');
throw new Error('Not implemented: joplin');
}
public get imaging(): ImagingImplementation {
throw new Error('Not implemented');
throw new Error('Not implemented: imaging');
}
}

View File

@@ -22,6 +22,10 @@ export default abstract class BasePluginRunner extends BaseService {
throw new Error(`Not implemented: ${plugin} / ${sandbox}`);
}
public async stop(plugin: Plugin): Promise<void> {
throw new Error(`Not implemented ${plugin} stop`);
}
public async waitForSandboxCalls(): Promise<void> {
throw new Error('Not implemented: waitForSandboxCalls');
}

View File

@@ -39,6 +39,7 @@ export default class Plugin {
private contentScriptMessageListeners_: Record<string, Function> = {};
private dataDir_: string;
private dataDirCreated_ = false;
private hasErrors_ = false;
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
public constructor(baseDir: string, manifest: PluginManifest, scriptText: string, dispatch: Function, dataDir: string) {
@@ -97,6 +98,14 @@ export default class Plugin {
return Object.keys(this.viewControllers_).length;
}
public get hasErrors(): boolean {
return this.hasErrors_;
}
public set hasErrors(hasErrors: boolean) {
this.hasErrors_ = hasErrors;
}
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
public on(eventName: string, callback: Function) {
return this.eventEmitter_.on(eventName, callback);
@@ -190,4 +199,11 @@ export default class Plugin {
return this.contentScriptMessageListeners_[id](message);
}
public onUnload() {
this.dispatch_({
type: 'PLUGIN_UNLOAD',
pluginId: this.id,
});
}
}

View File

@@ -144,6 +144,22 @@ export default class PluginService extends BaseService {
delete this.plugins_[pluginId];
}
public async unloadPlugin(pluginId: string) {
const plugin = this.plugins_[pluginId];
if (plugin) {
this.logger().info(`Unloading plugin ${pluginId}`);
plugin.onUnload();
await this.runner_.stop(plugin);
this.deletePluginAt(pluginId);
this.startedPlugins_ = { ...this.startedPlugins_ };
delete this.startedPlugins_[pluginId];
} else {
this.logger().info(`Unable to unload plugin ${pluginId} -- already unloaded`);
}
}
private async deletePluginFiles(plugin: Plugin) {
await shim.fsDriver().remove(plugin.baseDir);
}
@@ -167,7 +183,7 @@ export default class PluginService extends BaseService {
return output;
}
public serializePluginSettings(settings: PluginSettings): any {
public serializePluginSettings(settings: PluginSettings): string {
return JSON.stringify(settings);
}
@@ -343,7 +359,7 @@ export default class PluginService extends BaseService {
private pluginEnabled(settings: PluginSettings, pluginId: string): boolean {
if (!settings[pluginId]) return true;
return settings[pluginId].enabled !== false;
return settings[pluginId].enabled !== false && settings[pluginId].deleted !== true;
}
public callStatsSummary(pluginId: string, duration: number) {
@@ -407,6 +423,20 @@ export default class PluginService extends BaseService {
}
}
public async loadAndRunDevPlugins(settings: PluginSettings) {
const devPluginOptions = { devMode: true, builtIn: false };
if (Setting.value('plugins.devPluginPaths')) {
const paths = Setting.value('plugins.devPluginPaths').split(',').map((p: string) => p.trim());
await this.loadAndRunPlugins(paths, settings, devPluginOptions);
}
// Also load dev plugins that have passed via command line arguments
if (Setting.value('startupDevPlugins')) {
await this.loadAndRunPlugins(Setting.value('startupDevPlugins'), settings, devPluginOptions);
}
}
public isCompatible(pluginVersion: string): boolean {
return compareVersions(this.appVersion_, pluginVersion) >= 0;
}
@@ -450,6 +480,7 @@ export default class PluginService extends BaseService {
public async installPluginFromRepo(repoApi: RepositoryApi, pluginId: string): Promise<Plugin> {
const pluginPath = await repoApi.downloadPlugin(pluginId);
const plugin = await this.installPlugin(pluginPath);
await shim.fsDriver().remove(pluginPath);
return plugin;
}
@@ -467,6 +498,13 @@ export default class PluginService extends BaseService {
const preloadedPlugin = await this.loadPluginFromPath(jplPath);
await this.deletePluginFiles(preloadedPlugin);
// On mobile, it's necessary to create the plugin directory before we can copy
// into it.
if (!(await shim.fsDriver().exists(Setting.value('pluginDir')))) {
logger.info(`Creating plugin directory: ${Setting.value('pluginDir')}`);
await shim.fsDriver().mkdir(Setting.value('pluginDir'));
}
const destPath = `${Setting.value('pluginDir')}/${preloadedPlugin.id}.jpl`;
await shim.fsDriver().copy(jplPath, destPath);

View File

@@ -68,6 +68,10 @@ export default class RepositoryApi {
this.tempDir_ = tempDir;
}
public static ofDefaultJoplinRepo(tempDirPath: string) {
return new RepositoryApi('https://github.com/joplin/plugins', tempDirPath);
}
public async initialize() {
// https://github.com/joplin/plugins
// https://api.github.com/repos/joplin/plugins/releases
@@ -183,6 +187,12 @@ export default class RepositoryApi {
}
}
output.sort((m1, m2) => {
if (m1._recommended && !m2._recommended) return -1;
if (!m1._recommended && m2._recommended) return +1;
return m1.name.toLowerCase() < m2.name.toLowerCase() ? -1 : +1;
});
return output;
}

View File

@@ -47,6 +47,9 @@ export default class WebviewController extends ViewController {
private messageListener_: Function = null;
private closeResponse_: CloseResponse = null;
// True if a **panel** is shown in a modal window.
private panelInModalMode_ = false;
public constructor(handle: ViewHandle, pluginId: string, store: any, baseDir: string, containerType: ContainerType) {
super(handle, pluginId, store);
this.baseDir_ = toSystemSlashes(baseDir, 'linux');
@@ -150,8 +153,26 @@ export default class WebviewController extends ViewController {
return this.show(false);
}
// This method allows us to determine whether a panel is shown in dialog mode,
// which is used on mobile.
public setIsShownInModal(shown: boolean) {
this.panelInModalMode_ = shown;
}
public get visible(): boolean {
const mainLayout = this.store.getState().mainLayout;
const appState = this.store.getState();
if (this.panelInModalMode_) {
return true;
}
const mainLayout = appState.mainLayout;
// Mobile: There is no appState.mainLayout
if (!mainLayout) {
return false;
}
const item = findItemByKey(mainLayout, this.handle);
return item ? item.visible : false;
}

View File

@@ -55,8 +55,7 @@ import { Command } from './types';
export default class JoplinCommands {
/**
* <span class="platform-desktop">desktop</span> Executes the given
* command.
* Executes the given command.
*
* The command can take any number of arguments, and the supported
* arguments will vary based on the command. For custom commands, this
@@ -78,7 +77,7 @@ export default class JoplinCommands {
}
/**
* <span class="platform-desktop">desktop</span> Registers a new command.
* Registers a new command.
*
* ```typescript
* // Register a new commmand called "testCommand1"

View File

@@ -1,7 +1,7 @@
/* eslint-disable multiline-comment-style */
import shim from '../../../shim';
import Plugin from '../Plugin';
import * as fs from 'fs-extra';
export interface Implementation {
injectCustomStyles(elementId: string, cssFilePath: string): Promise<void>;
@@ -36,7 +36,7 @@ export default class JoplinWindow {
* for an example.
*/
public async loadNoteCssFile(filePath: string) {
const cssString = await fs.readFile(filePath, 'utf8');
const cssString = await shim.fsDriver().readFile(filePath, 'utf8');
this.store_.dispatch({
type: 'CUSTOM_CSS_APPEND',

View File

@@ -227,6 +227,8 @@ export interface VersionInfo {
version: string;
profileVersion: number;
syncVersion: number;
platform: 'desktop'|'mobile';
}
// =================================================================

View File

@@ -1,13 +1,18 @@
import { Draft } from 'immer';
import { ContainerType } from './WebviewController';
import { ButtonSpec } from './api/types';
export interface ViewInfo {
view: any;
plugin: any;
}
interface PluginViewState {
export interface PluginViewState {
id: string;
type: string;
opened: boolean;
buttons: ButtonSpec[];
fitToContent?: boolean;
scripts?: string[];
html?: string;
commandName?: string;
location?: string;
containerType: ContainerType;
}
interface PluginViewStates {
@@ -29,6 +34,11 @@ interface PluginState {
views: PluginViewStates;
}
export interface ViewInfo {
view: PluginViewState;
plugin: PluginState;
}
export interface PluginStates {
[key: string]: PluginState;
}
@@ -181,6 +191,10 @@ const reducer = (draftRoot: Draft<any>, action: any) => {
break;
}
case 'PLUGIN_UNLOAD':
delete draft.plugins[action.pluginId];
break;
}
} catch (error) {
error.message = `In plugin reducer: ${error.message} Action: ${JSON.stringify(action)}`;