mirror of
https://github.com/YunoHost/yunohost-admin.git
synced 2024-09-03 20:06:15 +02:00
commit
8dd6195cfe
4 changed files with 261 additions and 140 deletions
|
@ -160,6 +160,49 @@
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Get app actions list
|
||||||
|
app.get('#/apps/:app/actions', function (c) {
|
||||||
|
c.api('/apps/'+c.params['app']+'/actions', function(data) {
|
||||||
|
$.each(data.actions, function(_, action) {
|
||||||
|
formatYunoHostStyleArguments(action.arguments, c.params);
|
||||||
|
|
||||||
|
// Multilingual description
|
||||||
|
action.description = (typeof action.description[y18n.locale] !== 'undefined') ?
|
||||||
|
action.description[y18n.locale] :
|
||||||
|
action.description['en']
|
||||||
|
;
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
c.view('app/app_actions', data);
|
||||||
|
return;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Perform application
|
||||||
|
app.put('#/apps/:app/actions/:action', function(c) {
|
||||||
|
// taken from app install
|
||||||
|
$.each(c.params, function(k, v) {
|
||||||
|
if (typeof(v) === 'object' && Array.isArray(v)) {
|
||||||
|
// And return only first value
|
||||||
|
c.params[k] = v[0];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var app_id = c.params['app'];
|
||||||
|
delete c.params['app'];
|
||||||
|
var action_id = c.params['action'];
|
||||||
|
delete c.params['action'];
|
||||||
|
|
||||||
|
var params = {
|
||||||
|
'args': c.serialize(c.params.toHash())
|
||||||
|
}
|
||||||
|
|
||||||
|
c.api('/apps/'+app_id+'/actions/'+action_id, function() { // http://api.yunohost.org/#!/app/app_install_post_2
|
||||||
|
c.redirect('#/apps/'+app_id+'/actions');
|
||||||
|
}, 'PUT', params);
|
||||||
|
});
|
||||||
|
|
||||||
// Get app config panel
|
// Get app config panel
|
||||||
app.get('#/apps/:app/config-panel', function (c) {
|
app.get('#/apps/:app/config-panel', function (c) {
|
||||||
c.api('/apps/'+c.params['app']+'/config-panel', function(data) {
|
c.api('/apps/'+c.params['app']+'/config-panel', function(data) {
|
||||||
|
@ -195,6 +238,141 @@
|
||||||
c.redirect('#/apps/install');
|
c.redirect('#/apps/install');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Helper function that formats YunoHost style arguments for generating a form
|
||||||
|
function formatYunoHostStyleArguments(args, params) {
|
||||||
|
if (!args) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is in place modification, I don't like it but it was done this way
|
||||||
|
$.each(args, function(k, v) {
|
||||||
|
|
||||||
|
// Default values
|
||||||
|
args[k].type = (typeof v.type !== 'undefined') ? v.type : 'string';
|
||||||
|
args[k].inputType = 'text';
|
||||||
|
args[k].required = (typeof v.optional !== 'undefined' && v.optional == "true") ? '' : 'required';
|
||||||
|
args[k].attributes = "";
|
||||||
|
args[k].helpText = "";
|
||||||
|
args[k].helpLink = "";
|
||||||
|
|
||||||
|
|
||||||
|
// Multilingual label
|
||||||
|
args[k].label = (typeof args[k].ask[y18n.locale] !== 'undefined') ?
|
||||||
|
args[k].ask[y18n.locale] :
|
||||||
|
args[k].ask['en']
|
||||||
|
;
|
||||||
|
|
||||||
|
// Multilingual help text
|
||||||
|
if (typeof args[k].help !== 'undefined') {
|
||||||
|
args[k].helpText = (typeof args[k].help[y18n.locale] !== 'undefined') ?
|
||||||
|
args[k].help[y18n.locale] :
|
||||||
|
args[k].help['en']
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Input with choices becomes select list
|
||||||
|
if (typeof args[k].choices !== 'undefined') {
|
||||||
|
// Update choices values with key and checked data
|
||||||
|
var choices = []
|
||||||
|
$.each(args[k].choices, function(ck, cv){
|
||||||
|
// Non key/value choices have numeric key, that we don't want.
|
||||||
|
if (typeof ck == "number") {
|
||||||
|
// Key is Value in this case.
|
||||||
|
ck = cv;
|
||||||
|
}
|
||||||
|
|
||||||
|
choices.push({
|
||||||
|
value: ck,
|
||||||
|
label: cv,
|
||||||
|
selected: (ck == args[k].default) ? true : false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
args[k].choices = choices;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special case for domain input.
|
||||||
|
// Display a list of available domains
|
||||||
|
if (v.name == 'domain' || args[k].type == 'domain') {
|
||||||
|
args[k].choices = [];
|
||||||
|
$.each(params.domains, function(key, domain){
|
||||||
|
args[k].choices.push({
|
||||||
|
value: domain,
|
||||||
|
label: domain,
|
||||||
|
selected: false
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Custom help link
|
||||||
|
args[k].helpLink += "<a href='#/domains'>"+y18n.t('manage_domains')+"</a>";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special case for admin / user input.
|
||||||
|
// Display a list of available users
|
||||||
|
if (v.name == 'admin' || args[k].type == 'user') {
|
||||||
|
args[k].choices = [];
|
||||||
|
$.each(params.users, function(username, user){
|
||||||
|
args[k].choices.push({
|
||||||
|
value: username,
|
||||||
|
label: user.fullname+' ('+user.mail+')',
|
||||||
|
selected: false
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Custom help link
|
||||||
|
args[k].helpLink += "<a href='#/users'>"+y18n.t('manage_users')+"</a>";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 'app' type input display a list of available apps
|
||||||
|
if (args[k].type == 'app') {
|
||||||
|
args[k].choices = [];
|
||||||
|
$.each(params.apps, function(key, app){
|
||||||
|
args[k].choices.push({
|
||||||
|
value: app.id,
|
||||||
|
label: app.name,
|
||||||
|
selected: false
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Custom help link
|
||||||
|
args[k].helpLink += "<a href='#/apps'>"+y18n.t('manage_apps')+"</a>";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Boolean fields
|
||||||
|
if (args[k].type == 'boolean') {
|
||||||
|
args[k].inputType = 'checkbox';
|
||||||
|
|
||||||
|
// Checked or not ?
|
||||||
|
if (typeof args[k].default !== 'undefined') {
|
||||||
|
if (args[k].default == true) {
|
||||||
|
args[k].attributes = 'checked="checked"';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 'default' is used as value, so we need to force it for checkboxes.
|
||||||
|
args[k].default = 1;
|
||||||
|
|
||||||
|
// Checkbox should not be required to be unchecked
|
||||||
|
args[k].required = '';
|
||||||
|
|
||||||
|
// Clone a hidden input with empty value
|
||||||
|
// https://stackoverflow.com/questions/476426/submit-an-html-form-with-empty-checkboxes
|
||||||
|
var inputClone = {
|
||||||
|
name : args[k].name,
|
||||||
|
inputType : 'hidden',
|
||||||
|
default : 0
|
||||||
|
};
|
||||||
|
args.push(inputClone);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 'password' type input.
|
||||||
|
if (v.name == 'password' || args[k].type == 'password') {
|
||||||
|
// Change html input type
|
||||||
|
args[k].inputType = 'password';
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Helper function that build app installation form
|
// Helper function that build app installation form
|
||||||
app.helper('appInstallForm', function(appId, manifest, params) {
|
app.helper('appInstallForm', function(appId, manifest, params) {
|
||||||
var data = {
|
var data = {
|
||||||
|
@ -202,134 +380,7 @@
|
||||||
manifest: manifest
|
manifest: manifest
|
||||||
};
|
};
|
||||||
|
|
||||||
if (typeof data.manifest.arguments.install !== 'undefined') {
|
formatYunoHostStyleArguments(data.manifest.arguments.install, params);
|
||||||
$.each(data.manifest.arguments.install, function(k, v) {
|
|
||||||
|
|
||||||
// Default values
|
|
||||||
data.manifest.arguments.install[k].type = (typeof v.type !== 'undefined') ? v.type : 'string';
|
|
||||||
data.manifest.arguments.install[k].inputType = 'text';
|
|
||||||
data.manifest.arguments.install[k].required = (typeof v.optional !== 'undefined' && v.optional == "true") ? '' : 'required';
|
|
||||||
data.manifest.arguments.install[k].attributes = "";
|
|
||||||
data.manifest.arguments.install[k].helpText = "";
|
|
||||||
data.manifest.arguments.install[k].helpLink = "";
|
|
||||||
|
|
||||||
|
|
||||||
// Multilingual label
|
|
||||||
data.manifest.arguments.install[k].label = (typeof data.manifest.arguments.install[k].ask[y18n.locale] !== 'undefined') ?
|
|
||||||
data.manifest.arguments.install[k].ask[y18n.locale] :
|
|
||||||
data.manifest.arguments.install[k].ask['en']
|
|
||||||
;
|
|
||||||
|
|
||||||
// Multilingual help text
|
|
||||||
if (typeof data.manifest.arguments.install[k].help !== 'undefined') {
|
|
||||||
data.manifest.arguments.install[k].helpText = (typeof data.manifest.arguments.install[k].help[y18n.locale] !== 'undefined') ?
|
|
||||||
data.manifest.arguments.install[k].help[y18n.locale] :
|
|
||||||
data.manifest.arguments.install[k].help['en']
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Input with choices becomes select list
|
|
||||||
if (typeof data.manifest.arguments.install[k].choices !== 'undefined') {
|
|
||||||
// Update choices values with key and checked data
|
|
||||||
var choices = []
|
|
||||||
$.each(data.manifest.arguments.install[k].choices, function(ck, cv){
|
|
||||||
// Non key/value choices have numeric key, that we don't want.
|
|
||||||
if (typeof ck == "number") {
|
|
||||||
// Key is Value in this case.
|
|
||||||
ck = cv;
|
|
||||||
}
|
|
||||||
|
|
||||||
choices.push({
|
|
||||||
value: ck,
|
|
||||||
label: cv,
|
|
||||||
selected: (ck == data.manifest.arguments.install[k].default) ? true : false,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
data.manifest.arguments.install[k].choices = choices;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Special case for domain input.
|
|
||||||
// Display a list of available domains
|
|
||||||
if (v.name == 'domain' || data.manifest.arguments.install[k].type == 'domain') {
|
|
||||||
data.manifest.arguments.install[k].choices = [];
|
|
||||||
$.each(params.domains, function(key, domain){
|
|
||||||
data.manifest.arguments.install[k].choices.push({
|
|
||||||
value: domain,
|
|
||||||
label: domain,
|
|
||||||
selected: false
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Custom help link
|
|
||||||
data.manifest.arguments.install[k].helpLink += "<a href='#/domains'>"+y18n.t('manage_domains')+"</a>";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Special case for admin / user input.
|
|
||||||
// Display a list of available users
|
|
||||||
if (v.name == 'admin' || data.manifest.arguments.install[k].type == 'user') {
|
|
||||||
data.manifest.arguments.install[k].choices = [];
|
|
||||||
$.each(params.users, function(username, user){
|
|
||||||
data.manifest.arguments.install[k].choices.push({
|
|
||||||
value: username,
|
|
||||||
label: user.fullname+' ('+user.mail+')',
|
|
||||||
selected: false
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Custom help link
|
|
||||||
data.manifest.arguments.install[k].helpLink += "<a href='#/users'>"+y18n.t('manage_users')+"</a>";
|
|
||||||
}
|
|
||||||
|
|
||||||
// 'app' type input display a list of available apps
|
|
||||||
if (data.manifest.arguments.install[k].type == 'app') {
|
|
||||||
data.manifest.arguments.install[k].choices = [];
|
|
||||||
$.each(params.apps, function(key, app){
|
|
||||||
data.manifest.arguments.install[k].choices.push({
|
|
||||||
value: app.id,
|
|
||||||
label: app.name,
|
|
||||||
selected: false
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Custom help link
|
|
||||||
data.manifest.arguments.install[k].helpLink += "<a href='#/apps'>"+y18n.t('manage_apps')+"</a>";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Boolean fields
|
|
||||||
if (data.manifest.arguments.install[k].type == 'boolean') {
|
|
||||||
data.manifest.arguments.install[k].inputType = 'checkbox';
|
|
||||||
|
|
||||||
// Checked or not ?
|
|
||||||
if (typeof data.manifest.arguments.install[k].default !== 'undefined') {
|
|
||||||
if (data.manifest.arguments.install[k].default == true) {
|
|
||||||
data.manifest.arguments.install[k].attributes = 'checked="checked"';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 'default' is used as value, so we need to force it for checkboxes.
|
|
||||||
data.manifest.arguments.install[k].default = 1;
|
|
||||||
|
|
||||||
// Checkbox should not be required to be unchecked
|
|
||||||
data.manifest.arguments.install[k].required = '';
|
|
||||||
|
|
||||||
// Clone a hidden input with empty value
|
|
||||||
// https://stackoverflow.com/questions/476426/submit-an-html-form-with-empty-checkboxes
|
|
||||||
var inputClone = {
|
|
||||||
name : data.manifest.arguments.install[k].name,
|
|
||||||
inputType : 'hidden',
|
|
||||||
default : 0
|
|
||||||
};
|
|
||||||
data.manifest.arguments.install.push(inputClone);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 'password' type input.
|
|
||||||
if (v.name == 'password' || data.manifest.arguments.install[k].type == 'password') {
|
|
||||||
// Change html input type
|
|
||||||
data.manifest.arguments.install[k].inputType = 'password';
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Multilingual description
|
// Multilingual description
|
||||||
data.description = (typeof data.manifest.description[y18n.locale] !== 'undefined') ?
|
data.description = (typeof data.manifest.description[y18n.locale] !== 'undefined') ?
|
||||||
|
|
|
@ -8,27 +8,28 @@
|
||||||
* Filters
|
* Filters
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
app.before(/domains\/add/, function (req){
|
|
||||||
|
function prefetchDomains(req) {
|
||||||
// Preload domains list.
|
// Preload domains list.
|
||||||
req.params.domains = [];
|
req.params.domains = [];
|
||||||
req.api('/domains', function(data) {
|
req.api('/domains', function(data) {
|
||||||
req.params.domains = data.domains;
|
req.params.domains = data.domains;
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
app.before(/apps\/install\//, function (req){
|
|
||||||
// Preload domains list.
|
function prefetchUsers(req){
|
||||||
req.params.domains = [];
|
|
||||||
req.api('/domains', function(data) {
|
|
||||||
req.params.domains = data.domains;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
app.before(/apps\/install\//, function (req){
|
|
||||||
// Preload users lists.
|
// Preload users lists.
|
||||||
req.params.users = [];
|
req.params.users = [];
|
||||||
req.api('/users', function(data) {
|
req.api('/users', function(data) {
|
||||||
req.params.users = data.users;
|
req.params.users = data.users;
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
|
app.before(/domains\/add/, prefetchDomains);
|
||||||
|
app.before(/apps\/install\//, prefetchDomains);
|
||||||
|
app.before(/apps\/install\//, prefetchUsers);
|
||||||
|
app.before(/apps\/\w+\/actions/, prefetchUsers);
|
||||||
|
app.before(/apps\/\w+\/actions/, prefetchDomains);
|
||||||
|
|
||||||
|
|
||||||
app.before({except: {path: ['#/logout', '#/login', '#/postinstall', '#/postinstall/domain', '#/postinstall/password']}}, function (req) {
|
app.before({except: {path: ['#/logout', '#/login', '#/postinstall', '#/postinstall/domain', '#/postinstall/password']}}, function (req) {
|
||||||
|
@ -45,4 +46,4 @@
|
||||||
|
|
||||||
app.after(function () {});
|
app.after(function () {});
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
"app_install_custom_no_manifest": "No manifest.json file",
|
"app_install_custom_no_manifest": "No manifest.json file",
|
||||||
"app_list": "App list",
|
"app_list": "App list",
|
||||||
"app_make_default": "Make default",
|
"app_make_default": "Make default",
|
||||||
|
"app_no_actions": "This application doesn't have any actions",
|
||||||
"app_repository": "Application origin: ",
|
"app_repository": "Application origin: ",
|
||||||
"app_state": "Application state: ",
|
"app_state": "Application state: ",
|
||||||
"app_state_inprogress": "In progress",
|
"app_state_inprogress": "In progress",
|
||||||
|
|
68
src/views/app/app_actions.ms
Normal file
68
src/views/app/app_actions.ms
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
<div class="btn-breadcrumb">
|
||||||
|
<a href="#/" ><i class="fa-home"></i><span class="sr-only">{{t 'home'}}</span></a>
|
||||||
|
<a href="#/apps">{{t 'applications'}}</a>
|
||||||
|
<a href="#/apps/{{app_id}}">{{app_name}}</a>
|
||||||
|
<a href="#/apps/{{app_id}}/actions">{{t 'app_actions'}}</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="separator"></div>
|
||||||
|
|
||||||
|
<div class="alert alert-warning" role="alert">{{t 'experimental_warning'}}</div>
|
||||||
|
|
||||||
|
{{#if actions}}
|
||||||
|
{{#actions}}
|
||||||
|
<form action="#/apps/{{../app_id}}/actions/{{id}}" method="PUT" class="form-horizontal form-app-install">
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h2 class="panel-title">{{name}}</h2>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<p>{{description}}</p>
|
||||||
|
{{#if arguments}}
|
||||||
|
{{#arguments}}
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="{{name}}" class="col-sm-12">{{label}}</label>
|
||||||
|
|
||||||
|
{{#if helpText}}
|
||||||
|
<span class="help-block help-block--help col-sm-12">{{{helpText}}}</span>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<div class="col-sm-12">
|
||||||
|
|
||||||
|
{{#if choices}}
|
||||||
|
<select id="{{name}}" name="{{name}}" required class="form-control" {{{attributes}}}>
|
||||||
|
{{#choices}}<option value="{{value}}" {{#if selected}}selected{{/if}}>{{label}}</option>{{/choices}}
|
||||||
|
</select>
|
||||||
|
{{else}}
|
||||||
|
<input type="{{inputType}}" id="{{name}}" name="{{name}}" class="form-control" value="{{default}}" placeholder="{{example}}" {{required}} {{{attributes}}}>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if helpLink}}
|
||||||
|
<span class="help-block help-block--link">{{{helpLink}}}</span>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if example}}
|
||||||
|
<span class="help-block help-block--example">{{t 'form_input_example' example}}</span>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/arguments}}
|
||||||
|
<hr>
|
||||||
|
{{/if}}
|
||||||
|
<input type="hidden" name="app" value="{{id}}">
|
||||||
|
<div class="text-center">
|
||||||
|
<input type="submit" class="btn btn-success slide back" value="{{t 'perform'}}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{{/actions}}
|
||||||
|
|
||||||
|
{{else}}
|
||||||
|
<div class="alert alert-warning">
|
||||||
|
<span class="fa-exclamation-triangle"></span>
|
||||||
|
{{t 'app_no_actions'}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
Loading…
Add table
Reference in a new issue