Skip to content

Commit 0b7e8da

Browse files
authored
Merge pull request openlibhums#5293 from openlibhums/b-sexy-plugin-list
Enhance plugin list page layout and list them in alphabetical order
2 parents 5234452 + fce8322 commit 0b7e8da

3 files changed

Lines changed: 190 additions & 25 deletions

File tree

src/core/views.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2170,14 +2170,21 @@ def plugin_list(request):
21702170
{
21712171
"model": plugin,
21722172
"manager_url": manager_url,
2173-
"name": getattr(plugin_settings, "PLUGIN_NAME"),
2173+
"settings": plugin_settings,
21742174
},
21752175
)
21762176
except (ImportError, NoReverseMatch) as e:
2177-
failed_to_load.append(plugin)
2177+
failed_to_load.append({"plugin": plugin, "error": str(e)})
21782178
logger.error("Importing plugin %s failed: %s" % (plugin, e))
21792179
logger.exception(e)
21802180

2181+
plugin_list.sort(
2182+
key=lambda p: (
2183+
getattr(p["settings"], "DISPLAY_NAME", None)
2184+
or getattr(p["settings"], "PLUGIN_NAME", "")
2185+
).lower()
2186+
)
2187+
21812188
template = "core/manager/plugins.html"
21822189
context = {
21832190
"plugins": plugin_list,

src/static/admin/css/admin.css

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1091,6 +1091,126 @@ ul.menu {
10911091
}
10921092
}
10931093

1094+
1095+
/*
1096+
* Plugin list
1097+
* Compact list layout for the plugin manager page.
1098+
*/
1099+
1100+
.plugin-list {
1101+
list-style: none;
1102+
margin: 0;
1103+
padding: 0;
1104+
border: 1px solid #ddd;
1105+
border-radius: 4px;
1106+
overflow: hidden;
1107+
}
1108+
1109+
.plugin-list-item {
1110+
display: flex;
1111+
align-items: center;
1112+
gap: 1rem;
1113+
padding: 0.75rem 1rem;
1114+
border-bottom: 1px solid #eee;
1115+
background: #fff;
1116+
transition: background 0.1s;
1117+
}
1118+
1119+
.plugin-list-item:last-child {
1120+
border-bottom: none;
1121+
}
1122+
1123+
.plugin-list-item:hover {
1124+
background: #f9f9f9;
1125+
}
1126+
1127+
.plugin-list-item-badge-failed {
1128+
background: #fde8e8;
1129+
color: #c0392b;
1130+
}
1131+
1132+
.plugin-list-item-icon {
1133+
flex-shrink: 0;
1134+
width: 2rem;
1135+
height: 2rem;
1136+
background: #e8e8e8;
1137+
border-radius: 6px;
1138+
display: flex;
1139+
align-items: center;
1140+
justify-content: center;
1141+
color: #666;
1142+
font-size: 1rem;
1143+
}
1144+
1145+
.plugin-list-item-body {
1146+
flex: 1;
1147+
min-width: 0;
1148+
}
1149+
1150+
.plugin-list-item-title {
1151+
display: flex;
1152+
align-items: center;
1153+
gap: 0.4rem;
1154+
flex-wrap: wrap;
1155+
margin-bottom: 0.2rem;
1156+
}
1157+
1158+
.plugin-list-item-name {
1159+
font-weight: 600;
1160+
font-size: 0.95rem;
1161+
}
1162+
1163+
.plugin-list-item-badge {
1164+
display: inline-block;
1165+
font-size: 0.7rem;
1166+
font-weight: 600;
1167+
padding: 0.1em 0.5em;
1168+
border-radius: 3px;
1169+
background: #e0e0e0;
1170+
color: #444;
1171+
}
1172+
1173+
.plugin-list-item-badge-version {
1174+
background: #e8f0fe;
1175+
color: #3367d6;
1176+
}
1177+
1178+
.plugin-list-item-desc {
1179+
font-size: 0.82rem;
1180+
color: #666;
1181+
white-space: nowrap;
1182+
overflow: hidden;
1183+
text-overflow: ellipsis;
1184+
}
1185+
1186+
.plugin-list-item-meta {
1187+
flex-shrink: 0;
1188+
text-align: right;
1189+
font-size: 0.78rem;
1190+
color: #888;
1191+
white-space: nowrap;
1192+
}
1193+
1194+
.plugin-list-item-action {
1195+
flex-shrink: 0;
1196+
}
1197+
1198+
.plugin-list-item-action .button {
1199+
margin: 0;
1200+
padding: 0.35rem 0.9rem;
1201+
font-size: 0.82rem;
1202+
}
1203+
1204+
.plugin-list-count {
1205+
font-size: 0.75rem;
1206+
color: #888;
1207+
font-weight: normal;
1208+
}
1209+
1210+
.plugin-list-empty {
1211+
padding: 2rem;
1212+
text-align: center;
1213+
color: #888;
10941214
.custom-radio-group {
10951215
display: flex;
10961216
flex-direction: column;
@@ -1122,6 +1242,7 @@ ul.menu {
11221242
.ou-depth {
11231243
margin-left: calc(var(--ou-depth, 0) * 1rem);
11241244
}
1245+
11251246
/*
11261247
* Accessible Modals
11271248
* Uses the dialog tag.
Lines changed: 60 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
{% extends "admin/core/base.html" %}
22

3-
43
{% block title %}Plugins{% endblock title %}
54
{% block title-section %}Plugins{% endblock %}
65

@@ -12,37 +11,75 @@
1211

1312

1413
{% block body %}
15-
<section>
16-
<div class="row expanded" data-equalizer>
17-
<div class="large-4 columns end">
18-
<div class="box" data-equalizer-watch>
14+
<section>
15+
<div class="row expanded">
16+
<div class="large-6 medium-12 small-12 columns">
17+
18+
<div class="box">
1919
<div class="title-area">
20-
<h2>Installed Plugins</h2>
20+
<h2>Installed Plugins <small class="plugin-list-count">{{ plugins|length }} installed</small></h2>
2121
</div>
2222
<div class="content">
23-
<div class="button-group stacked">
23+
24+
<ul class="plugin-list">
2425
{% for plugin in plugins %}
25-
{% if plugin.manager_url %}
26-
<a class="button" href="{% url plugin.manager_url %}">{{ plugin.name|capfirst }}</a>
27-
{% else %}
28-
<a class="button disabled" href="">{{ plugin.model.name|capfirst }}</a>
29-
{% endif %}
26+
<li class="plugin-list-item">
27+
<div class="plugin-list-item-icon">
28+
<i class="fa fa-puzzle-piece"></i>
29+
</div>
30+
<div class="plugin-list-item-body">
31+
<div class="plugin-list-item-title">
32+
<span class="plugin-list-item-name">
33+
{{ plugin.settings.DISPLAY_NAME|default:plugin.settings.PLUGIN_NAME|capfirst }}
34+
</span>
35+
<span class="plugin-list-item-badge plugin-list-item-badge-version">
36+
v{{ plugin.settings.VERSION }}
37+
</span>
38+
</div>
39+
{% if plugin.settings.DESCRIPTION %}
40+
<div class="plugin-list-item-desc" title="{{ plugin.settings.DESCRIPTION }}">
41+
{{ plugin.settings.DESCRIPTION }}
42+
</div>
43+
{% endif %}
44+
</div>
45+
<div class="plugin-list-item-meta"></div>
46+
<div class="plugin-list-item-action">
47+
{% if plugin.manager_url %}
48+
<a class="button small" href="{% url plugin.manager_url %}">Manage</a>
49+
{% else %}
50+
<a class="button small disabled" href="">No settings</a>
51+
{% endif %}
52+
</div>
53+
</li>
3054
{% endfor %}
31-
</div>
32-
{% if failed_to_load %}
33-
<div class="bs-callout bs-callout-danger">
34-
<p>Some installed plugins failed to load:</p>
35-
<ul>
3655
{% for failed in failed_to_load %}
37-
<li>{{ failed.name }}</li>
56+
<li class="plugin-list-item">
57+
<div class="plugin-list-item-icon">
58+
<i class="fa fa-puzzle-piece"></i>
59+
</div>
60+
<div class="plugin-list-item-body">
61+
<div class="plugin-list-item-title">
62+
<span class="plugin-list-item-name">{{ failed.plugin.name|capfirst }}</span>
63+
<span class="plugin-list-item-badge plugin-list-item-badge-failed">Failed</span>
64+
</div>
65+
<div class="plugin-list-item-desc" title="{{ failed.error }}">
66+
{{ failed.error }}
67+
</div>
68+
</div>
69+
<div class="plugin-list-item-meta"></div>
70+
<div class="plugin-list-item-action"></div>
71+
</li>
3872
{% endfor %}
39-
</ul>
40-
</div>
41-
{% endif %}
42-
</div>
73+
{% if not plugins and not failed_to_load %}
74+
<li class="plugin-list-empty">No plugins are currently installed.</li>
75+
{% endif %}
76+
</ul>
4377

78+
</div>
4479
</div>
80+
4581
</div>
4682
</div>
47-
</section>
83+
</section>
4884
{% endblock body %}
85+

0 commit comments

Comments
 (0)