fix #609: enable/disable plugins

This commit is contained in:
antelle 2017-04-26 22:06:07 +02:00
parent 8cf469e55c
commit 4433654686
5 changed files with 92 additions and 43 deletions

View File

@ -453,8 +453,9 @@
"setPlInstallBtn": "Install",
"setPlInstallBtnProgress": "Installing",
"setPlUninstallBtn": "Uninstall",
"setPlDisableBtn": "Disable",
"setPlEnableBtn": "Enable",
"setPlUpdateBtn": "Update",
"setPlUpdating": "Updating",
"setPlLocaleBtn": "Switch to this language",
"setPlThemeBtn": "Switch to this theme",
"setPlJs": "code",

View File

@ -6,10 +6,7 @@ const Logger = require('../util/logger');
const PluginManager = Backbone.Model.extend({
defaults: {
state: '',
installing: null,
uninstalling: null,
updating: null,
lastInstall: null,
plugins: new PluginCollection()
},
@ -54,10 +51,36 @@ const PluginManager = Backbone.Model.extend({
if (!plugin) {
return Promise.resolve();
}
this.set('uninstalling', id);
this.trigger('change');
return plugin.uninstall().then(() => {
plugins.remove(id);
this.set('uninstalling', null);
this.trigger('change');
this.saveState();
});
},
disable(id) {
const plugins = this.get('plugins');
const plugin = plugins.get(id);
if (!plugin || plugin.get('status') !== Plugin.STATUS_ACTIVE) {
return Promise.resolve();
}
this.trigger('change');
return plugin.disable().then(() => {
this.trigger('change');
this.saveState();
});
},
activate(id) {
const plugins = this.get('plugins');
const plugin = plugins.get(id);
if (!plugin || plugin.get('status') === Plugin.STATUS_ACTIVE) {
return Promise.resolve();
}
this.trigger('change');
return plugin.install(true).then(() => {
this.trigger('change');
this.saveState();
});
},
@ -65,21 +88,21 @@ const PluginManager = Backbone.Model.extend({
update(id) {
const plugins = this.get('plugins');
const oldPlugin = plugins.get(id);
if (!oldPlugin) {
if (!oldPlugin || [Plugin.STATUS_ACTIVE, Plugin.STATUS_INACTIVE, Plugin.STATUS_NONE].indexOf(oldPlugin.get('status')) < 0) {
return Promise.reject();
}
const url = oldPlugin.get('url');
this.set({ updating: id });
this.trigger('change');
return Plugin.loadFromUrl(url).then(newPlugin => {
return oldPlugin.update(newPlugin).then(() => {
this.set({ updating: null });
this.trigger('change');
this.saveState();
}).catch(e => {
this.set('updating', null);
this.trigger('change');
throw e;
});
}).catch(e => {
this.set({ updating: null });
this.trigger('change');
throw e;
});
},
@ -90,7 +113,7 @@ const PluginManager = Backbone.Model.extend({
url: desc.url,
local: true
});
return plugin.install()
return plugin.install(desc.enabled)
.then(() => plugin)
.catch(() => plugin);
},
@ -99,9 +122,15 @@ const PluginManager = Backbone.Model.extend({
SettingsStore.save('plugins', {
plugins: this.get('plugins').map(plugin => ({
manifest: plugin.get('manifest'),
url: plugin.get('url')
url: plugin.get('url'),
enabled: plugin.get('status') === 'active'
}))
});
},
getStatus(id) {
const plugin = this.get('plugins').get(id);
return plugin ? plugin.get('status') : '';
}
});

View File

@ -13,22 +13,26 @@ const io = new IoCache({
logger: new Logger('storage-plugin-files')
});
const Plugin = Backbone.Model.extend({
idAttribute: 'name',
const PluginStatus = {
STATUS_NONE: '',
STATUS_ACTIVE: 'active',
STATUS_INACTIVE: 'inactive',
STATUS_INSTALLING: 'installing',
STATUS_ACTIVATING: 'activating',
STATUS_UNINSTALLING: 'uninstalling',
STATUS_UPDATING: 'updating',
STATUS_INVALID: 'invalid',
STATUS_ERROR: 'error',
};
const Plugin = Backbone.Model.extend(_.extend({}, PluginStatus, {
idAttribute: 'name',
defaults: {
name: '',
manifest: '',
url: '',
status: 'inactive',
status: '',
installTime: null,
installError: null,
updateError: null
@ -43,7 +47,7 @@ const Plugin = Backbone.Model.extend({
this.logger = new Logger(`plugin:${name}`);
},
install() {
install(activate) {
const ts = this.logger.ts();
this.set('status', this.STATUS_INSTALLING);
return Promise.resolve().then(() => {
@ -53,6 +57,11 @@ const Plugin = Backbone.Model.extend({
this.set('status', this.STATUS_INVALID);
throw 'Plugin validation error: ' + error;
}
this.set('status', this.STATUS_INACTIVE);
if (!activate) {
this.logger.info('Loaded inactive plugin');
return;
}
return this.installWithManifest()
.then(() => this.set('installTime', this.logger.ts() - ts))
.catch(err => {
@ -358,8 +367,17 @@ const Plugin = Backbone.Model.extend({
},
uninstall() {
return this.disable.then(() => {
return this.deleteResources().then(() => {
this.set('status', '');
this.logger.info('Uninstall complete', this.logger.ts(ts));
});
});
},
disable() {
const manifest = this.get('manifest');
this.logger.info('Uninstalling plugin with resources', Object.keys(manifest.resources).join(', '));
this.logger.info('Disabling plugin with resources', Object.keys(manifest.resources).join(', '));
this.set('status', this.STATUS_UNINSTALLING);
const ts = this.logger.ts();
return Promise.resolve().then(() => {
@ -376,10 +394,8 @@ const Plugin = Backbone.Model.extend({
if (manifest.theme) {
this.removeTheme(manifest.theme);
}
return this.deleteResources().then(() => {
this.set('status', this.STATUS_INACTIVE);
this.logger.info('Uninstall complete', this.logger.ts(ts));
});
this.set('status', this.STATUS_INACTIVE);
this.logger.info('Disable complete', this.logger.ts(ts));
});
},
@ -432,7 +448,9 @@ const Plugin = Backbone.Model.extend({
});
});
}
});
}));
_.extend(Plugin, PluginStatus);
Plugin.loadFromUrl = function(url) {
if (url[url.length - 1] !== '/') {

View File

@ -9,13 +9,15 @@ const SettingsPluginsView = Backbone.View.extend({
events: {
'click .settings_plugins-install-btn': 'installClick',
'click .settings_plugins-uninstall-btn': 'uninstallClick',
'click .settings_plugins-disable-btn': 'disableClick',
'click .settings_plugins-enable-btn': 'enableClick',
'click .settings_plugins-update-btn': 'updateClick',
'click .settings_plugins-use-locale-btn': 'useLocaleClick',
'click .settings_plugins-use-theme-btn': 'useThemeClick'
},
initialize() {
this.listenTo(PluginManager, 'change:installing change:uninstalling change:updating', this.render.bind(this));
this.listenTo(PluginManager, 'change', this.render.bind(this));
},
render() {
@ -29,8 +31,7 @@ const SettingsPluginsView = Backbone.View.extend({
updateError: plugin.get('updateError')
})),
lastInstallUrl: PluginManager.get('installing') || (lastInstall.error ? lastInstall.url : ''),
lastInstallError: lastInstall.error,
updating: PluginManager.get('updating')
lastInstallError: lastInstall.error
});
return this;
},
@ -66,17 +67,21 @@ const SettingsPluginsView = Backbone.View.extend({
uninstallClick(e) {
const pluginId = $(e.target).data('plugin');
if (PluginManager.get('updating') === pluginId || PluginManager.get('uninstalling') === pluginId) {
return;
}
PluginManager.uninstall(pluginId);
},
disableClick(e) {
const pluginId = $(e.target).data('plugin');
PluginManager.disable(pluginId);
},
enableClick(e) {
const pluginId = $(e.target).data('plugin');
PluginManager.activate(pluginId);
},
updateClick(e) {
const pluginId = $(e.target).data('plugin');
if (PluginManager.get('updating') === pluginId || PluginManager.get('uninstalling') === pluginId) {
return;
}
PluginManager.update(pluginId);
},

View File

@ -15,21 +15,17 @@
<div class="settings__plugins-plugin-desc">
<a href="{{plugin.manifest.url}}" target="_blank">{{plugin.manifest.url}}</a>, v{{plugin.manifest.version}},
{{#res 'setPlCreatedBy'}}<a href="{{plugin.manifest.author.url}}" target="_blank">{{plugin.manifest.author.name}}</a> ({{plugin.manifest.author.email}}){{/res}},
{{#res 'setPlLoadTime'}}{{plugin.installTime}}ms{{/res}}
{{#ifeq plugin.status 'active'}}{{#res 'setPlLoadTime'}}{{plugin.installTime}}ms{{/res}}{{else}}{{plugin.status}}{{/ifeq}}
{{#ifeq plugin.status 'error'}}<span class="error-color">&nbsp;({{res 'setPlLoadError'}}){{/ifeq}}
{{#if plugin.updateError}}<div class="error-color settings__plugins-upd-error">{{res 'setPlUpdateError'}}: <pre>{{plugin.updateError}}</pre></div>{{/if}}
</div>
<div class="settings__plugins-plugin-buttons">
<button class="settings_plugins-uninstall-btn btn-error" data-plugin="{{plugin.id}}">{{res 'setPlUninstallBtn'}}</button>
<button class="settings_plugins-update-btn btn-silent" data-plugin="{{plugin.id}}">
{{~#ifeq plugin.id ../updating}}{{res 'setPlUpdating'}}&hellip;{{else}}{{res 'setPlUpdateBtn'}}{{/ifeq~}}
</button>
{{#if plugin.manifest.locale}}
<button class="settings_plugins-use-locale-btn btn-silent" data-locale="{{plugin.manifest.locale.name}}">{{res 'setPlLocaleBtn'}}</button>
{{/if}}
{{#if plugin.manifest.theme}}
<button class="settings_plugins-use-theme-btn btn-silent" data-theme="{{plugin.manifest.theme.name}}">{{res 'setPlThemeBtn'}}</button>
{{/if}}
{{#ifeq plugin.status 'active'}}<button class="settings_plugins-disable-btn btn-silent" data-plugin="{{plugin.id}}">{{res 'setPlDisableBtn'}}</button>{{/ifeq}}
{{#ifeq plugin.status 'inactive'}}<button class="settings_plugins-enable-btn btn-silent" data-plugin="{{plugin.id}}">{{res 'setPlEnableBtn'}}</button>{{/ifeq}}
<button class="settings_plugins-update-btn btn-silent" data-plugin="{{plugin.id}}">{{res 'setPlUpdateBtn'}}</button>
{{#if plugin.manifest.locale}}<button class="settings_plugins-use-locale-btn btn-silent" data-locale="{{plugin.manifest.locale.name}}">{{res 'setPlLocaleBtn'}}</button>{{/if}}
{{#if plugin.manifest.theme}}<button class="settings_plugins-use-theme-btn btn-silent" data-theme="{{plugin.manifest.theme.name}}">{{res 'setPlThemeBtn'}}</button>{{/if}}
</div>
</div>
{{/each}}