plugin management page

This commit is contained in:
antelle 2017-02-19 12:40:21 +01:00
parent 624a1c10c7
commit 9c30035381
7 changed files with 113 additions and 31 deletions

View File

@ -450,6 +450,11 @@
"setPlInstallLabel": "Plugin URL",
"setPlInstallBtn": "Install",
"setPlInstallBtnProgress": "Installing",
"setPlUninstallBtn": "Uninstall",
"setPlLocaleBtn": "Switch to this language",
"setPlJs": "code",
"setPlCss": "styles",
"setPlLoc": "language",
"setAboutTitle": "About",
"setAboutBuilt": "This app is built with these awesome tools",

View File

@ -7,33 +7,40 @@ const PluginCollection = require('./plugin-collection');
const PluginManager = Backbone.Model.extend({
defaults: {
state: '',
installing: false,
installing: null,
uninstalling: null,
lastInstall: null,
plugins: new PluginCollection()
},
install(url) {
this.set('installing', true);
return Plugin.load(url).then(plugin => {
const plugins = this.get('plugins');
return Promise.resolve().then(() => {
if (plugins.get(plugin.id)) {
return plugins.get(plugin.id).uninstall().then(() => {
plugins.remove(plugin.id);
});
}
}).then(() => {
const lastInstall = { url, dt: new Date() };
this.set({ installing: url, lastInstall: lastInstall });
return Plugin.load(url).then(plugin =>
this.uninstall(plugin.id).then(() => {
const plugins = this.get('plugins');
plugins.push(plugin);
return plugin.install().then(() => {
this.set('installing', false);
}).catch(e => {
this.set('installing', false);
throw e;
this.set({ installing: null });
});
});
}).catch(e => {
this.set('installing', false);
})
).catch(e => {
this.set({ installing: null, lastInstall: _.extend(lastInstall, { error: e.toString() }) });
throw e;
});
},
uninstall(id) {
const plugins = this.get('plugins');
const plugin = plugins.get(id);
if (!plugin) {
return Promise.resolve();
}
this.set('uninstalling', id);
return plugin.uninstall().then(() => {
plugins.remove(id);
this.set('uninstalling', null);
});
}
});

View File

@ -21,9 +21,11 @@ const Plugin = Backbone.Model.extend({
resources: null,
initialize(manifest, url) {
this.set('name', manifest.name);
this.set('manifest', manifest);
this.set('url', url);
this.set({
name: manifest.name,
manifest,
url
});
this.logger = new Logger(`plugin:${manifest.name}`);
},
@ -136,8 +138,10 @@ const Plugin = Backbone.Model.extend({
if (this.resources.loc) {
promises.push(this.applyLoc(manifest.locale, this.resources.loc));
}
this.set('status', 'active');
return Promise.all(promises)
.then(() => {
this.set('status', 'active');
})
.catch(e => {
this.logger.info('Install error', e);
this.uninstall();
@ -211,11 +215,15 @@ const Plugin = Backbone.Model.extend({
removeLoc(locale) {
delete SettingsManager.allLocales[locale.name];
delete SettingsManager.customLocales[locale.name];
if (SettingsManager.activeLocale === locale.name) {
SettingsManager.setLocale('en');
}
},
uninstall() {
const manifest = this.get('manifest');
this.logger.info('Uninstalling plugin with resources', Object.keys(manifest.resources).join(', '));
this.set('status', 'uninstalling');
const ts = this.logger.ts();
return Promise.resolve().then(() => {
if (manifest.resources.css) {
@ -232,6 +240,7 @@ const Plugin = Backbone.Model.extend({
if (manifest.resources.loc) {
this.removeLoc(this.get('manifest').locale);
}
this.set('status', 'inactive');
this.logger.info('Uninstall complete', this.logger.ts(ts));
});
}

View File

@ -3,18 +3,33 @@
const Backbone = require('backbone');
const Locale = require('../../util/locale');
const PluginManager = require('../../plugins/plugin-manager');
const AppSettingsModel = require('../../models/app-settings-model');
const SettingsPluginsView = Backbone.View.extend({
template: require('templates/settings/settings-plugins.hbs'),
events: {
'click .settings_plugins-install-btn': 'installClick'
'click .settings_plugins-install-btn': 'installClick',
'click .settings_plugins-uninstall-btn': 'uninstallClick',
'click .settings_plugins-use-locale-btn': 'useLocaleClick'
},
initialize() {
this.listenTo(PluginManager, 'change:installing change:uninstalling', this.render.bind(this));
},
render() {
const lastInstall = PluginManager.get('lastInstall') || {};
this.renderTemplate({
plugins: []
plugins: PluginManager.get('plugins').map(plugin => ({
id: plugin.id,
manifest: plugin.get('manifest'),
status: plugin.get('status')
})),
lastInstallUrl: PluginManager.get('installing') || (lastInstall.error ? lastInstall.url : ''),
lastInstallError: lastInstall.error
});
return this;
},
installClick() {
@ -44,6 +59,16 @@ const SettingsPluginsView = Backbone.View.extend({
const urlTextBox = this.$el.find('#settings__plugins-install-url');
urlTextBox.prop('disabled', false);
installBtn.text(Locale.setPlInstallBtn).prop('disabled', false);
},
uninstallClick(e) {
const pluginId = $(e.target).data('plugin');
PluginManager.uninstall(pluginId);
},
useLocaleClick(e) {
const locale = $(e.target).data('locale');
AppSettingsModel.instance.set('locale', locale);
}
});

View File

@ -148,7 +148,17 @@
}
&__plugins {
&-install-error {
margin-top: $base-padding-h;
margin-top: $base-padding-v;
}
&-plugin-files {
margin-top: $base-padding-v;
margin-bottom: $base-padding-v;
}
&-plugin-file {
padding-left: $base-padding-h;
}
&-plugin-desc {
margin-bottom: $base-padding-v;
}
}
}

View File

@ -20,8 +20,6 @@
<h3>Core components</h3>
<ul>
<li><a href="https://github.com/keeweb/kdbxweb" target="_blank">kdbxweb</a><span class="muted-color">, web kdbx library</span></li>
<li><a href="https://github.com/vibornoff/asmcrypto.js/" target="_blank">asmcrypto</a><span class="muted-color">, JavaScript cryptographic library
with performance in mind</span></li>
<li><a href="http://nodeca.github.io/pako/" target="_blank">pako</a><span class="muted-color">, zlib port to JavaScript, very fast</span></li>
</ul>

View File

@ -1,12 +1,40 @@
<div>
<h1><i class="fa fa-puzzle-piece"></i> {{res 'plugins'}}</h1>
<div class="settings__plugins-list">
{{#each plugins as |plugin|}}
<div class="settings__plugins-plugin">
<h2>{{plugin.id}}</h2>
<div>{{plugin.manifest.description}}</div>
<div>
<ul class="settings__plugins-plugin-files">
{{#if plugin.manifest.resources.js}}<li class="settings__plugins-plugin-file"><i class="fa fa-code"></i> {{res 'setPlJs'}}</li>{{/if}}
{{#if plugin.manifest.resources.css}}<li class="settings__plugins-plugin-file"><i class="fa fa-paint-brush"></i> {{res 'setPlCss'}}</li>{{/if}}
{{#if plugin.manifest.resources.loc}}<li class="settings__plugins-plugin-file"><i class="fa fa-language"></i> {{res 'setPlLoc'}}: {{plugin.manifest.locale.title}}</li>{{/if}}
</ul>
</div>
<div class="settings__plugins-plugin-desc">
<a href="{{plugin.manifest.url}}" target="_blank">{{plugin.manifest.url}}</a>, v{{plugin.manifest.version}}, created by
<a href="{{plugin.manifest.author.url}}" target="_blank">{{plugin.manifest.author.name}}</a> ({{plugin.manifest.author.email}})
</div>
<div class="settings__plugins-plugin-buttons">
<button class="settings_plugins-uninstall-btn btn-silent" data-plugin="{{plugin.id}}">{{res 'setPlUninstallBtn'}}</button>
{{#if plugin.manifest.resources.loc}}
<button class="settings_plugins-use-locale-btn btn-silent" data-locale="{{plugin.manifest.locale.name}}">{{res 'setPlLocaleBtn'}}</button>
{{/if}}
</div>
</div>
{{/each}}
</div>
<h2>{{res 'setPlInstallTitle'}}</h2>
<div class="settings__plugins-list"></div>
<div class="settings__plugins-install">
<div>{{res 'setPlInstallDesc'}}</div>
<label for="settings__plugins-install-url">{{res 'setPlInstallLabel'}}</label>
<input type="text" class="settings__input input-base" id="settings__plugins-install-url" value="http://localhost:8085/plugins/examples/psychodelic/" />
<button class="settings_plugins-install-btn">{{res 'setPlInstallBtn'}}</button>
<div class="error-color settings__plugins-install-error"></div>
<input type="text" class="settings__input input-base" id="settings__plugins-install-url" value="{{lastInstallUrl}}" />
<button class="settings_plugins-install-btn" {{#if installing}}disabled{{/if}}>
{{#if installing}}{{res 'setPlInstallBtnProgress'}}{{else}}{{res 'setPlInstallBtn'}}{{/if}}
</button>
{{#if lastInstallError}}
<div class="error-color settings__plugins-install-error">{{lastInstallError}}</div>
{{/if}}
</div>
</div>