mirror of
https://github.com/YunoHost/yunohost-admin.git
synced 2024-09-03 20:06:15 +02:00
Merge pull request #279 from YunoHost/app-categories
WIP : App categories
This commit is contained in:
commit
1f47ce7927
8 changed files with 246 additions and 115 deletions
|
@ -631,8 +631,12 @@ input[type='radio'].nice-radio {
|
||||||
background-color: darkorchid;
|
background-color: darkorchid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.app-category-card {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
// only one card for small screens
|
// only one card for small screens
|
||||||
.app-card {
|
.app-card, .app-category-card {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
.btn-group {
|
.btn-group {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -653,13 +657,16 @@ input[type='radio'].nice-radio {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.app-state {
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.app-title {
|
.app-title, .app-category-title {
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-card-desc {
|
.app-card-desc, .app-category-card-desc {
|
||||||
height: 6rem;
|
height: 6rem;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
@ -670,6 +677,7 @@ input[type='radio'].nice-radio {
|
||||||
margin-bottom: 3px;
|
margin-bottom: 3px;
|
||||||
margin-right: 7px;
|
margin-right: 7px;
|
||||||
margin-top: -5px;
|
margin-top: -5px;
|
||||||
|
height: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.auto-width {
|
.auto-width {
|
||||||
|
@ -686,6 +694,7 @@ input[type='radio'].nice-radio {
|
||||||
|
|
||||||
.app-card .panel-body {
|
.app-card .panel-body {
|
||||||
padding: 1.5rem;
|
padding: 1.5rem;
|
||||||
|
padding-bottom: 0.5rem;
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
|
@ -697,6 +706,33 @@ input[type='radio'].nice-radio {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.app-category-card .panel-body {
|
||||||
|
padding: 2em;
|
||||||
|
height: 10em;
|
||||||
|
color: #333 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtag-selector {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-category-card {
|
||||||
|
text-decoration: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-category-card:hover {
|
||||||
|
border-color: #777;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-category-title {
|
||||||
|
line-height: 1em;
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-category-card-desc {
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Groups View **/
|
/** Groups View **/
|
||||||
#view-groups {
|
#view-groups {
|
||||||
|
@ -806,7 +842,7 @@ input[type='radio'].nice-radio {
|
||||||
}
|
}
|
||||||
|
|
||||||
// display 2 cards between 640 and 992px
|
// display 2 cards between 640 and 992px
|
||||||
.app-card {
|
.app-card, .app-category-card {
|
||||||
width: 47.9%;
|
width: 47.9%;
|
||||||
margin: 1%;
|
margin: 1%;
|
||||||
}
|
}
|
||||||
|
@ -908,7 +944,7 @@ input[type='radio'].nice-radio {
|
||||||
|
|
||||||
// bootstrap breakpoint for large screen is 992px
|
// bootstrap breakpoint for large screen is 992px
|
||||||
@media screen and (min-width: 992px) {
|
@media screen and (min-width: 992px) {
|
||||||
.app-card {
|
.app-card, .app-category-card {
|
||||||
// display 3 cards by row
|
// display 3 cards by row
|
||||||
width: 31.3%;
|
width: 31.3%;
|
||||||
margin: 1%;
|
margin: 1%;
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
// List installed apps
|
// List installed apps
|
||||||
app.get('#/apps', function (c) {
|
app.get('#/apps', function (c) {
|
||||||
c.api('GET', '/apps?installed', {}, function(data) {
|
c.api('GET', '/apps?full', {}, function(data) {
|
||||||
var apps = data['apps'];
|
var apps = data['apps'];
|
||||||
c.arraySortById(apps);
|
c.arraySortById(apps);
|
||||||
c.view('app/app_list', {apps: apps});
|
c.view('app/app_list', {apps: apps});
|
||||||
|
@ -70,7 +70,7 @@
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return 'success';
|
return 'info';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,101 +107,145 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// List available apps
|
|
||||||
app.get('#/apps/install', function (c) {
|
|
||||||
c.api('GET', '/apps', {}, function (data) {
|
|
||||||
c.api('GET', '/apps?raw', {}, function (dataraw) {
|
|
||||||
var apps = []
|
|
||||||
$.each(data['apps'], function(k, v) {
|
|
||||||
app = dataraw[v['id']];
|
|
||||||
app.level = parseInt(app.level);
|
|
||||||
|
|
||||||
if (app.high_quality && app.level > 7)
|
// Display catalog home page where users chooses to browse a specific category
|
||||||
{
|
app.get('#/apps/catalog', function (c) {
|
||||||
app.state = "high-quality";
|
c.api('GET', '/appscatalog?full&with_categories', {}, function (data) {
|
||||||
}
|
c.view('app/app_catalog_home', {categories: data["categories"]}, function() {
|
||||||
if ( app.maintained === false )
|
// Configure layout / rendering for app-category-cards
|
||||||
{
|
$('#category-selector').isotope({
|
||||||
app.maintained = "orphaned";
|
itemSelector: '.app-category-card',
|
||||||
}
|
layoutMode: 'fitRows',
|
||||||
else if ( app.maintained === true )
|
transitionDuration: 200
|
||||||
{
|
});
|
||||||
app.maintained = "maintained";
|
});
|
||||||
}
|
});
|
||||||
|
});
|
||||||
|
|
||||||
app.manifest.maintainer = extractMaintainer(app.manifest);
|
// Display app catalog for a specific category
|
||||||
var isWorking = (app.state === 'working' || app.state === "high-quality") && app.level > 0;
|
app.get('#/apps/catalog/:category', function (c) {
|
||||||
|
var category_id = c.params['category'];
|
||||||
|
c.api('GET', '/appscatalog?full&with_categories', {}, function (data) {
|
||||||
|
var apps = [];
|
||||||
|
$.each(data['apps'], function(name, app) {
|
||||||
|
|
||||||
// Keep only the first instance of each app and remove not working apps
|
// Ignore not working apps
|
||||||
if (!v['id'].match(/__[0-9]{1,5}$/) && (app.state !== 'notworking')) {
|
if (app.state === 'notworking') { return; }
|
||||||
|
|
||||||
app.installable = (!v.installed || app.manifest.multi_instance)
|
// Ignore apps not in this category
|
||||||
app.levelFormatted = isNaN(app.level) ? '?' : app.level;
|
if ((category_id !== "all") && (app.category !== category_id)) { return; }
|
||||||
|
|
||||||
app.levelColor = levelToColor(app.level);
|
app.id = app.manifest.id;
|
||||||
app.stateColor = stateToColor(app.state);
|
app.level = parseInt(app.level);
|
||||||
app.maintainedColor = maintainedStateToColor(app.maintained);
|
|
||||||
app.installColor = combineColors(app.stateColor, app.levelColor);
|
|
||||||
|
|
||||||
app.updateDate = app.lastUpdate * 1000 || 0;
|
if (app.high_quality && app.level > 7)
|
||||||
app.isSafe = (app.installColor !== 'danger');
|
{
|
||||||
app.isWorking = isWorking ? "isworking" : "notFullyWorking";
|
app.state = "high-quality";
|
||||||
app.isHighQuality = (app.state === "high-quality") ? "isHighQuality" : "";
|
}
|
||||||
app.decentQuality = (app.level > 4)?"decentQuality":"badQuality";
|
if ( app.maintained === false )
|
||||||
|
{
|
||||||
|
app.maintained = "orphaned";
|
||||||
|
}
|
||||||
|
else if ( app.maintained === true )
|
||||||
|
{
|
||||||
|
app.maintained = "maintained";
|
||||||
|
}
|
||||||
|
|
||||||
jQuery.extend(app, v);
|
app.manifest.maintainer = extractMaintainer(app.manifest);
|
||||||
apps.push(app);
|
var isWorking = (app.state === 'working' || app.state === "high-quality") && app.level > 0;
|
||||||
}
|
|
||||||
|
app.installable = (!app.installed || app.manifest.supports_multi_instance)
|
||||||
|
app.levelFormatted = isNaN(app.level) ? '?' : app.level;
|
||||||
|
|
||||||
|
app.levelColor = levelToColor(app.level);
|
||||||
|
app.stateColor = stateToColor(app.state);
|
||||||
|
app.maintainedColor = maintainedStateToColor(app.maintained);
|
||||||
|
app.installColor = combineColors(app.stateColor, app.levelColor);
|
||||||
|
|
||||||
|
app.updateDate = app.lastUpdate * 1000 || 0;
|
||||||
|
app.isSafe = (app.installColor !== 'danger');
|
||||||
|
app.isWorking = isWorking ? "isworking" : "notFullyWorking";
|
||||||
|
app.isHighQuality = (app.state === "high-quality") ? "isHighQuality" : "";
|
||||||
|
app.decentQuality = (app.level > 4)?"decentQuality":"badQuality";
|
||||||
|
|
||||||
|
apps.push(app);
|
||||||
|
});
|
||||||
|
|
||||||
|
var category = undefined;
|
||||||
|
$.each(data['categories'], function(i, this_category) {
|
||||||
|
if (this_category.id === category_id) { category = this_category; }
|
||||||
|
});
|
||||||
|
|
||||||
|
if (category_id === "all") {
|
||||||
|
category = {title: y18n.t("all_apps"), icon: "search"};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort app list
|
||||||
|
c.arraySortById(apps);
|
||||||
|
|
||||||
|
// setup filtering of apps once the view is loaded
|
||||||
|
function setupFilterEvents () {
|
||||||
|
// Uses plugin isotope to filter apps (we could had ordering to)
|
||||||
|
var cardGrid = jQuery('#apps').isotope({
|
||||||
|
itemSelector: '.app-card',
|
||||||
|
layoutMode: 'fitRows',
|
||||||
|
transitionDuration: 200
|
||||||
});
|
});
|
||||||
|
|
||||||
// Sort app list
|
// Default filter is 'decent quality apps'
|
||||||
c.arraySortById(apps);
|
cardGrid.isotope({ filter: '.decentQuality' });
|
||||||
|
|
||||||
// setup filtering of apps once the view is loaded
|
$(".subtag-selector button").on("click", function() {
|
||||||
function setupFilterEvents () {
|
var selector = $(this).parent();
|
||||||
// Uses plugin isotope to filter apps (we could had ordering to)
|
$("button", selector).removeClass("active");
|
||||||
var cardGrid = jQuery('.grid').isotope({
|
$(this).addClass("active");
|
||||||
itemSelector: '.app-card',
|
cardGrid.isotope({ filter: filterApps });
|
||||||
layoutMode: 'fitRows',
|
});
|
||||||
transitionDuration: 200
|
|
||||||
});
|
|
||||||
|
|
||||||
filterByClassAndName = function () {
|
filterApps = function () {
|
||||||
var input = jQuery("#filter-app-cards").val().toLowerCase();
|
|
||||||
var inputMatch = (jQuery(this).find('.app-title').text().toLowerCase().indexOf(input) > -1);
|
|
||||||
|
|
||||||
var filterClass = jQuery("#dropdownFilter").attr("data-filter");
|
// Check text search
|
||||||
var classMatch = (filterClass === '*') ? true : jQuery(this).hasClass(filterClass);
|
var input = jQuery("#filter-app-cards").val().toLowerCase();
|
||||||
return inputMatch && classMatch;
|
if (jQuery(this).find('.app-title').text().toLowerCase().indexOf(input) <= -1) return false;
|
||||||
},
|
|
||||||
|
|
||||||
// Default filter is 'decent quality apps'
|
// Check subtags
|
||||||
cardGrid.isotope({ filter: '.decentQuality' });
|
var subtag = $(".subtag-selector button.active").data("subtag");
|
||||||
|
var this_subtags = jQuery(this).data("subtags");
|
||||||
|
if ((subtag !== undefined) && (subtag !== "all")) {
|
||||||
|
if ((subtag === "others") && (this_subtags !== "")) return false;
|
||||||
|
if ((subtag !== "others") && (this_subtags.split(",").indexOf(subtag) <= -1)) return false;
|
||||||
|
}
|
||||||
|
|
||||||
jQuery('.dropdownFilter').on('click', function() {
|
// Check quality criteria
|
||||||
// change dropdown label
|
var class_ = jQuery("#dropdownFilter").data("filter");
|
||||||
jQuery('#app-cards-list-filter-text').text(jQuery(this).find('.menu-item').text());
|
if ((class_ !== '*') && (! jQuery(this).hasClass(class_))) return false;
|
||||||
// change filter attribute
|
|
||||||
jQuery('#dropdownFilter').attr("data-filter", jQuery(this).attr("data-filter"));
|
|
||||||
// filter !
|
|
||||||
cardGrid.isotope({ filter: filterByClassAndName });
|
|
||||||
});
|
|
||||||
|
|
||||||
jQuery("#filter-app-cards").on("keyup", function() {
|
return true;
|
||||||
cardGrid.isotope({ filter: filterByClassAndName });
|
},
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// render
|
jQuery('.dropdownFilter').on('click', function() {
|
||||||
c.view('app/app_list_install', {apps: apps}, setupFilterEvents);
|
// change dropdown label
|
||||||
|
jQuery('#app-cards-list-filter-text').text(jQuery(this).find('.menu-item').text());
|
||||||
|
// change filter attribute
|
||||||
|
jQuery('#dropdownFilter').data("filter", jQuery(this).data("filter"));
|
||||||
|
// filter !
|
||||||
|
cardGrid.isotope({ filter: filterApps });
|
||||||
|
});
|
||||||
|
|
||||||
|
jQuery("#filter-app-cards").on("keyup", function() {
|
||||||
|
cardGrid.isotope({ filter: filterApps });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// render
|
||||||
|
c.view('app/app_catalog_category', {apps: apps, category: category}, setupFilterEvents);
|
||||||
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Get app information
|
// Get app information
|
||||||
app.get('#/apps/:app', function (c) {
|
app.get('#/apps/:app', function (c) {
|
||||||
c.api('GET', '/apps/'+c.params['app']+'?raw', {}, function(data) {
|
c.api('GET', '/apps/'+c.params['app']+'?full', {}, function(data) {
|
||||||
c.api('GET', '/users/permissions', {}, function(data_permissions) {
|
c.api('GET', '/users/permissions', {}, function(data_permissions) {
|
||||||
|
|
||||||
// Permissions
|
// Permissions
|
||||||
|
@ -506,9 +550,9 @@
|
||||||
|
|
||||||
// App installation form
|
// App installation form
|
||||||
app.get('#/apps/install/:app', function (c) {
|
app.get('#/apps/install/:app', function (c) {
|
||||||
c.api('GET', '/apps?raw', {}, function(data) {
|
c.api('GET', '/appscatalog?full', {}, function(data) {
|
||||||
var app_name = c.params["app"];
|
var app_name = c.params["app"];
|
||||||
var app_infos = data[app_name];
|
var app_infos = data["apps"][app_name];
|
||||||
if (app_infos['state'] === "validated")
|
if (app_infos['state'] === "validated")
|
||||||
{
|
{
|
||||||
app_infos['state'] = "official";
|
app_infos['state'] = "official";
|
||||||
|
@ -535,7 +579,7 @@
|
||||||
{
|
{
|
||||||
c.appInstallForm(
|
c.appInstallForm(
|
||||||
c.params['app'],
|
c.params['app'],
|
||||||
data[c.params['app']].manifest,
|
app_infos.manifest,
|
||||||
c.params
|
c.params
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -622,7 +666,7 @@
|
||||||
|
|
||||||
// Get app change label page
|
// Get app change label page
|
||||||
app.get('#/apps/:app/changelabel', function (c) {
|
app.get('#/apps/:app/changelabel', function (c) {
|
||||||
c.api('GET', '/apps/'+c.params['app']+'?raw', {}, function(app_data) {
|
c.api('GET', '/apps/'+c.params['app']+'?full', {}, function(app_data) {
|
||||||
data = {
|
data = {
|
||||||
id: c.params['app'],
|
id: c.params['app'],
|
||||||
label: app_data.settings.label,
|
label: app_data.settings.label,
|
||||||
|
@ -641,7 +685,7 @@
|
||||||
|
|
||||||
// Get app change URL page
|
// Get app change URL page
|
||||||
app.get('#/apps/:app/changeurl', function (c) {
|
app.get('#/apps/:app/changeurl', function (c) {
|
||||||
c.api('GET', '/apps/'+c.params['app']+'?raw', {}, function(app_data) {
|
c.api('GET', '/apps/'+c.params['app']+'?full', {}, function(app_data) {
|
||||||
c.api('GET', '/domains', {}, function(domain_data) {
|
c.api('GET', '/domains', {}, function(domain_data) {
|
||||||
|
|
||||||
// Display a list of available domains
|
// Display a list of available domains
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
"advanced": "Advanced",
|
"advanced": "Advanced",
|
||||||
"remove": "Remove",
|
"remove": "Remove",
|
||||||
"administration_password": "Administration password",
|
"administration_password": "Administration password",
|
||||||
|
"all": "All",
|
||||||
"all_apps": "All apps",
|
"all_apps": "All apps",
|
||||||
"api_not_responding": "The YunoHost API is not responding. Maybe 'yunohost-api' is down or got restarted?",
|
"api_not_responding": "The YunoHost API is not responding. Maybe 'yunohost-api' is down or got restarted?",
|
||||||
"app_change_label": "Change Label",
|
"app_change_label": "Change Label",
|
||||||
|
@ -23,10 +24,12 @@
|
||||||
"app_no_actions": "This application doesn't have any actions",
|
"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": "not yet working",
|
||||||
"app_state_inprogress_explanation": "This maintainer of this app declared that this application is not ready yet for production use. BE CAREFUL!",
|
"app_state_inprogress_explanation": "This maintainer of this app declared that this application is not ready yet for production use. BE CAREFUL!",
|
||||||
"app_state_notworking": "not working",
|
"app_state_notworking": "not working",
|
||||||
"app_state_notworking_explanation": "This maintainer of this app declared it as 'not working'. IT WILL BREAK YOUR SYSTEM!",
|
"app_state_notworking_explanation": "This maintainer of this app declared it as 'not working'. IT WILL BREAK YOUR SYSTEM!",
|
||||||
|
"app_state_low_quality": "low quality",
|
||||||
|
"app_state_low_quality_explanation": "This app may be functional, but may still contain issues, or is not fully integrated with YunoHost, or it does not respect the good practices.",
|
||||||
"app_state_high-quality": "high quality",
|
"app_state_high-quality": "high quality",
|
||||||
"app_state_high-quality_explanation": "This app is well-integrated with YunoHost. It has been (and is!) peer-reviewed by the YunoHost app team. It can be expected to be safe and maintained on the long-term.",
|
"app_state_high-quality_explanation": "This app is well-integrated with YunoHost. It has been (and is!) peer-reviewed by the YunoHost app team. It can be expected to be safe and maintained on the long-term.",
|
||||||
"app_state_working": "working",
|
"app_state_working": "working",
|
||||||
|
@ -51,6 +54,7 @@
|
||||||
"begin": "Begin",
|
"begin": "Begin",
|
||||||
"both": "Both",
|
"both": "Both",
|
||||||
"cancel": "Cancel",
|
"cancel": "Cancel",
|
||||||
|
"catalog": "Catalog",
|
||||||
"check": "Check",
|
"check": "Check",
|
||||||
"close": "Close",
|
"close": "Close",
|
||||||
"configuration": "Configuration",
|
"configuration": "Configuration",
|
||||||
|
@ -218,8 +222,9 @@
|
||||||
"only_decent_quality_apps": "Only decent quality apps",
|
"only_decent_quality_apps": "Only decent quality apps",
|
||||||
"open": "Open",
|
"open": "Open",
|
||||||
"operations": "Operations",
|
"operations": "Operations",
|
||||||
"orphaned": "not maintained",
|
"orphaned": "Not maintained",
|
||||||
"orphaned_details": "This app is not maintained anymore. It may still be working but won't receive any upgrade. Feel free to come and revive it!",
|
"orphaned_details": "This app has not been maintained for quite some time. It may still be working, but won't receive any upgrade until somebody volunteers to take care of it. Feel free to contribute to revive it!",
|
||||||
|
"others": "Others",
|
||||||
"password": "Password",
|
"password": "Password",
|
||||||
"password_confirmation": "Password confirmation",
|
"password_confirmation": "Password confirmation",
|
||||||
"password_description": "Password must be at least %s characters long.",
|
"password_description": "Password must be at least %s characters long.",
|
||||||
|
|
|
@ -1,16 +1,20 @@
|
||||||
<div class="btn-breadcrumb">
|
<div class="btn-breadcrumb">
|
||||||
<a href="#/" ><i class="fa-home"></i><span class="sr-only">{{t 'home'}}</span></a>
|
<a href="#/" ><i class="fa-home"></i><span class="sr-only">{{t 'home'}}</span></a>
|
||||||
<a href="#/apps">{{t 'applications'}}</a>
|
<a href="#/apps">{{t 'applications'}}</a>
|
||||||
<a href="#/apps/install">{{t 'install'}}</a>
|
<a href="#/apps/catalog">{{t 'catalog'}}</a>
|
||||||
|
<a href="#/apps/catalog/{{category.id}}">{{category.title}}</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="separator"></div>
|
<div class="separator"></div>
|
||||||
|
|
||||||
<div class="input-group" id="app-filter-input">
|
<div class="input-group" id="app-filter-input">
|
||||||
<span class="input-group-addon"><i class="fas fa-search"></i></span>
|
<div class="input-group-btn"><a class="btn btn-primary" href="#/apps/catalog"><i class="fa-arrow-left"></i></a></div>
|
||||||
|
<span class="input-group-addon"><i class="fa-fw fa-{{category.icon}}"></i> {{category.title}}</span>
|
||||||
|
<span class="input-group-addon" style="background: white;border: none;"> </span>
|
||||||
|
<span class="input-group-addon"><i class="fa-search"></i></span>
|
||||||
<input type="text" id="filter-app-cards" class="form-control" role="textbox" placeholder="{{t 'search_for_apps'}}" aria-describedby="basic-addon0"/>
|
<input type="text" id="filter-app-cards" class="form-control" role="textbox" placeholder="{{t 'search_for_apps'}}" aria-describedby="basic-addon0"/>
|
||||||
<div class="input-group-btn">
|
<div class="input-group-btn">
|
||||||
<button type="button" role="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
<button class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
<span id="app-cards-list-filter-text">{{t 'only_decent_quality_apps'}}</span> <span class="caret"></span>
|
<span id="app-cards-list-filter-text">{{t 'only_decent_quality_apps'}}</span> <span class="caret"></span>
|
||||||
</button>
|
</button>
|
||||||
<ul id="dropdownFilter" class="dropdown-menu" data-filter="decentQuality" role="menu">
|
<ul id="dropdownFilter" class="dropdown-menu" data-filter="decentQuality" role="menu">
|
||||||
|
@ -24,32 +28,51 @@
|
||||||
|
|
||||||
<div class="separator"></div>
|
<div class="separator"></div>
|
||||||
|
|
||||||
<div class="list-group grid">
|
<div class="subtag-selector">
|
||||||
|
{{#if category.subtags}}
|
||||||
|
<button class="btn btn-default active" data-subtag="all">{{t 'all'}}</button>
|
||||||
|
{{/if}}
|
||||||
|
{{#category.subtags}}
|
||||||
|
<button class="btn btn-default" data-subtag="{{id}}">{{title}}</button>
|
||||||
|
{{/category.subtags}}
|
||||||
|
{{#if category.subtags}}
|
||||||
|
<button class="btn btn-default" data-subtag="others">{{t 'others'}}</button>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="separator"></div>
|
||||||
|
|
||||||
|
<div id="apps" class="list-group grid">
|
||||||
{{#apps}}
|
{{#apps}}
|
||||||
<div class="app-card panel panel-default {{status}} {{state}} {{isWorking}} {{isHighQuality}} {{decentQuality}} {{level}}-level">
|
<div class="app-card panel panel-default {{state}} {{isWorking}} {{isHighQuality}} {{decentQuality}} {{level}}-level" data-subtags="{{#subtags}}{{.}}{{#unless @last}},{{/unless}}{{/subtags}}">
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<h2 class="app-title">{{name}}</h2>
|
<h2 class="app-title">
|
||||||
<div class="category">
|
{{manifest.name}}
|
||||||
<span class="label label-{{stateColor}} label-as-badge app-state" title="{{t (concat 'app_state_' state '_explanation') }}">{{t (concat 'app_state_' state) }}</span>
|
{{#if (eq state 'working') }}
|
||||||
<a target="_BLANK" href="https://yunohost.org/#/packaging_apps_levels"><span class="label label-{{levelColor}} label-as-badge app-level" title="{{t 'app_level'}}">{{t 'level'}} {{levelFormatted}}</span></a>
|
{{#if (eq decentQuality 'badQuality')}}
|
||||||
<span class="label label-{{maintainedColor}} label-as-badge maintained-status" title="{{t (concat maintained '_details') }}"> {{t maintained}}</span>
|
<span class="label label-warning label-as-badge app-state" title="{{t 'app_state_low_quality_explanation' }}">{{t 'app_state_low_quality' }}</span>
|
||||||
</div>
|
{{/if}}
|
||||||
<div class="app-card-desc">{{description}}</div>
|
{{else}}
|
||||||
|
<span class="label label-{{stateColor}} label-as-badge app-state" title="{{t (concat 'app_state_' state '_explanation') }}">{{t (concat 'app_state_' state) }}</span>
|
||||||
|
{{/if}}
|
||||||
|
</h2>
|
||||||
|
<div class="app-card-desc">{{manifest.description}}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="app-card-date-maintainer">
|
<div class="app-card-date-maintainer">
|
||||||
<i class="fa-refresh"></i> {{formatDate updateDate day="numeric" month="long" year="numeric"}} -
|
{{#if (eq maintainedColor 'danger') }}
|
||||||
<span title="{{t 'current_maintainer_title'}}" class="maintained"></span><i class="fa-user"></i> {{manifest.maintainer}}</span>
|
<span class="text text-warning maintained-status" title="{{t (concat maintained '_details') }}"><i class="fa-fw fa-warning"></i> {{t maintained}}</span>
|
||||||
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
<div class="btn-group" role="group">
|
<div class="btn-group" role="group">
|
||||||
<a href="{{git.url}}" target="_BLANK" type="button" role="button" class="btn btn-default col-xs-4">
|
<a href="{{git.url}}" target="_BLANK" type="button" role="button" class="btn btn-default col-xs-4">
|
||||||
<i class="fa-globe"></i> Code
|
<i class="fa-fw fa-code"></i> Code
|
||||||
</a>
|
</a>
|
||||||
<a href="{{git.url}}/blob/master/README.md" target="_BLANK" type="button" role="button" class="btn btn-default col-xs-4">
|
<a href="{{git.url}}/blob/master/README.md" target="_BLANK" type="button" role="button" class="btn btn-default col-xs-4">
|
||||||
<i class="fa-book"></i> Readme
|
<i class="fa-fw fa-book"></i> Readme
|
||||||
</a>
|
</a>
|
||||||
{{#installable}}
|
{{#installable}}
|
||||||
<a href="#/apps/install/{{id}}" type="button" role="button" class="btn btn-{{installColor}} col-xs-4 active">
|
<a href="#/apps/install/{{manifest.id}}" type="button" role="button" class="btn btn-{{installColor}} col-xs-4 active">
|
||||||
<i class="fa-plus"></i> {{t 'install'}}{{^isSafe}} <i class="fa-warning"></i>{{/isSafe}}
|
<i class="fa-fw fa-plus"></i> {{t 'install'}}{{^isSafe}} <i class="fa-fw fa-warning"></i>{{/isSafe}}
|
||||||
</a>
|
</a>
|
||||||
{{/installable}}
|
{{/installable}}
|
||||||
{{^installable}}
|
{{^installable}}
|
||||||
|
@ -66,7 +89,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<p class="alert alert-warning">
|
<p class="alert alert-warning">
|
||||||
<span class="fa-warning"></span>
|
<span class="fa-fw fa-warning"></span>
|
||||||
{{t 'confirm_install_custom_app'}}
|
{{t 'confirm_install_custom_app'}}
|
||||||
</p>
|
</p>
|
||||||
<form action="#/apps/install/custom" method="POST" class="form-horizontal">
|
<form action="#/apps/install/custom" method="POST" class="form-horizontal">
|
||||||
|
@ -75,7 +98,7 @@
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<input type="url" id="url" name="url" class="form-control" value="" placeholder="https://github.com/USER/REPOSITORY" required pattern="^https://github.com/[a-zA-Z0-9-_.]+/[a-zA-Z0-9-_.]+[/]?$">
|
<input type="url" id="url" name="url" class="form-control" value="" placeholder="https://github.com/USER/REPOSITORY" required pattern="^https://github.com/[a-zA-Z0-9-_.]+/[a-zA-Z0-9-_.]+[/]?$">
|
||||||
<p class="text-warning">
|
<p class="text-warning">
|
||||||
<span class="fa-github"></span> {{t 'custom_app_url_only_github'}}
|
<span class="fa-fw fa-github"></span> {{t 'custom_app_url_only_github'}}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
23
src/views/app/app_catalog_home.ms
Normal file
23
src/views/app/app_catalog_home.ms
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
<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/catalog">{{t 'catalog'}}</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="separator"></div>
|
||||||
|
|
||||||
|
<div id="category-selector" class="list-group grid">
|
||||||
|
{{#categories}}
|
||||||
|
<a class="app-category-card panel panel-default" href="#/apps/catalog/{{id}}">
|
||||||
|
<div class="panel-body">
|
||||||
|
<h2 class="app-category-title"><span class="fa-fw fa-{{icon}}"></span> {{title}}</h2>
|
||||||
|
<h3 class="app-category-card-desc">{{description}}</h3>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{{/categories}}
|
||||||
|
<a class="app-category-card" href="#/apps/catalog/all">
|
||||||
|
<div class="panel-body">
|
||||||
|
<h2 class="app-category-title" style="padding-top: 3em'"><span class="fa-fw fa-search"></span> {{t 'all_apps'}}</h2>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
|
@ -22,7 +22,7 @@
|
||||||
<dt>{{t 'version'}}</dt>
|
<dt>{{t 'version'}}</dt>
|
||||||
<dd>{{version}}</dd>
|
<dd>{{version}}</dd>
|
||||||
<dt>{{t 'multi_instance'}}</dt>
|
<dt>{{t 'multi_instance'}}</dt>
|
||||||
<dd>{{manifest.multi_instance}}</dd>
|
<dd>{{supports_multi_instance}}</dd>
|
||||||
<dt>{{t 'install_time'}}</dt>
|
<dt>{{t 'install_time'}}</dt>
|
||||||
<dd>{{formatTime install_time day="numeric" month="long" year="numeric" hour="numeric" minute="numeric"}}</dd>
|
<dd>{{formatTime install_time day="numeric" month="long" year="numeric" hour="numeric" minute="numeric"}}</dd>
|
||||||
{{#if settings.domain}}
|
{{#if settings.domain}}
|
||||||
|
@ -64,7 +64,7 @@
|
||||||
<hr>
|
<hr>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<p>{{t 'app_info_changeurl_desc' settings.domain}}</p>
|
<p>{{t 'app_info_changeurl_desc' settings.domain}}</p>
|
||||||
{{#if change_url}}
|
{{#if supports_change_url}}
|
||||||
<a href="#/apps/{{settings.id}}/changeurl" role="button" class="btn btn-info slide">
|
<a href="#/apps/{{settings.id}}/changeurl" role="button" class="btn btn-info slide">
|
||||||
<span class="fa-exchange"></span> {{t 'app_change_url'}}
|
<span class="fa-exchange"></span> {{t 'app_change_url'}}
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<div class="btn-breadcrumb">
|
<div class="btn-breadcrumb">
|
||||||
<a href="#/" ><i class="fa-home"></i><span class="sr-only">{{t 'home'}}</span></a>
|
<a href="#/" ><i class="fa-home"></i><span class="sr-only">{{t 'home'}}</span></a>
|
||||||
<a href="#/apps">{{t 'applications'}}</a>
|
<a href="#/apps">{{t 'applications'}}</a>
|
||||||
<a href="#/apps/install">{{t 'install'}}</a>
|
<a href="#/apps/catalog">{{t 'catalog'}}</a>
|
||||||
<a href="#/apps/install/{{id}}">{{manifest.name}}</a>
|
<a href="#/apps/install/{{id}}">{{t 'install_name' manifest.name}}</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="separator"></div>
|
<div class="separator"></div>
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
<dt>{{t 'id'}}</dt>
|
<dt>{{t 'id'}}</dt>
|
||||||
<dd>{{id}}</dd>
|
<dd>{{id}}</dd>
|
||||||
<dt>{{t 'description'}}</dt>
|
<dt>{{t 'description'}}</dt>
|
||||||
<dd>{{description}}</dd>
|
<dd>{{manifest.description}}</dd>
|
||||||
{{#displayLicense}}
|
{{#displayLicense}}
|
||||||
<dt>{{t 'license'}}</dt>
|
<dt>{{t 'license'}}</dt>
|
||||||
<dd>{{manifest.license}}</dd>
|
<dd>{{manifest.license}}</dd>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="actions-group">
|
<div class="actions-group">
|
||||||
<a role="button" href="#/apps/install" class="btn btn-success slide">
|
<a role="button" href="#/apps/catalog" class="btn btn-success slide">
|
||||||
<span class="fa-plus"></span> {{t 'install'}}
|
<span class="fa-plus"></span> {{t 'install'}}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -16,7 +16,7 @@
|
||||||
<a href="#/apps/{{id}}" class="list-group-item slide" title="{{t 'infos'}}">
|
<a href="#/apps/{{id}}" class="list-group-item slide" title="{{t 'infos'}}">
|
||||||
<span class="fa-chevron-right pull-right"></span>
|
<span class="fa-chevron-right pull-right"></span>
|
||||||
<h2 class="list-group-item-heading">
|
<h2 class="list-group-item-heading">
|
||||||
{{label}} <small>{{name}}</small>
|
{{settings.label}} <small>{{name}}</small>
|
||||||
</h2>
|
</h2>
|
||||||
<p class="list-group-item-text">{{description}}</p>
|
<p class="list-group-item-text">{{description}}</p>
|
||||||
</a>
|
</a>
|
||||||
|
|
Loading…
Add table
Reference in a new issue