* [pve-devel] [PATCH http-server v2] formatter: html: update to bootstrap 5
@ 2025-06-05 9:02 Dominik Csapak
2025-06-10 8:17 ` [pve-devel] applied: " Thomas Lamprecht
0 siblings, 1 reply; 2+ messages in thread
From: Dominik Csapak @ 2025-06-05 9:02 UTC (permalink / raw)
To: pve-devel
this makes a few changes necessary, but not too much:
* include the different directory for bootstrap5
* use different navbar markup
* different classes for navbar container + items
* add classes to pre tag since it's not styled anymore in newer
bootstrap versions
* add 'form-label' to labels
* use containers with 'mb-3' for form + buttons
* use 'd-grid' container for button instead of 'btn-block'
* add 'breadcrumb-item' where necessary
Since bootstrap 5 does not depend on jQuery anymore, use that chance to
remove it here as dependency too. For that remove the 'button'
and 'add_js' subs that were never actually used.
Also remove the general /js/ alias and the now unnecessary fonts for
bootstrap.
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
changes from v1:
* remove more default aliases since i could not find a user of those
* adapt commit message
* fix wrong delete_auth_cookie call change, that changed
from `delete_auth_cookie()` -> `delete_auth_cookie`
* change included dir to end with `/` otherwise the alias won't work
debian/control | 3 +-
src/PVE/APIServer/AnyEvent.pm | 8 +-
src/PVE/APIServer/Formatter/Bootstrap.pm | 37 +------
src/PVE/APIServer/Formatter/HTML.pm | 132 +++++++++++++----------
4 files changed, 83 insertions(+), 97 deletions(-)
diff --git a/debian/control b/debian/control
index 0d0161e..4ce0368 100644
--- a/debian/control
+++ b/debian/control
@@ -15,8 +15,7 @@ Depends: libanyevent-http-perl,
libhttp-date-perl,
libhttp-message-perl,
libio-socket-ssl-perl,
- libjs-bootstrap,
- libjs-jquery,
+ libjs-bootstrap5,
libjson-perl,
libnet-ip-perl,
libpve-common-perl (>= 8.0.2),
diff --git a/src/PVE/APIServer/AnyEvent.pm b/src/PVE/APIServer/AnyEvent.pm
index b71a9a5..e1f3141 100644
--- a/src/PVE/APIServer/AnyEvent.pm
+++ b/src/PVE/APIServer/AnyEvent.pm
@@ -2025,12 +2025,8 @@ sub new {
$self->{formatter_config}->{csrfgen_func} =
$self->can('generate_csrf_prevention_token');
- # add default dirs which includes jquery and bootstrap
- my $jsbase = '/usr/share/javascript';
- add_dirs($self->{dirs}, '/js/' => "$jsbase/");
- # libjs-bootstrap uses symlinks for this, which we do not want to allow..
- my $glyphicons = '/usr/share/fonts/truetype/glyphicons/';
- add_dirs($self->{dirs}, '/js/bootstrap/fonts/' => "$glyphicons");
+ # libjs-bootstrap5 uses a different dir with symlinks
+ add_dirs($self->{dirs}, '/bootstrap5/' => "/usr/share/bootstrap-html/");
# init inotify
PVE::INotify::inotify_init();
diff --git a/src/PVE/APIServer/Formatter/Bootstrap.pm b/src/PVE/APIServer/Formatter/Bootstrap.pm
index 0055d64..6b3f350 100644
--- a/src/PVE/APIServer/Formatter/Bootstrap.pm
+++ b/src/PVE/APIServer/Formatter/Bootstrap.pm
@@ -53,7 +53,7 @@ sub body {
<title>$self->{title}</title>
<!-- Bootstrap -->
- <link href="/js/bootstrap/css/bootstrap.min.css" rel="stylesheet">
+ <link href="/bootstrap5/css/bootstrap.min.css" rel="stylesheet">
<script type="text/javascript">
$jssetup
@@ -65,10 +65,8 @@ body {
}
</style>
- <!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
- <script src="/js/jquery/jquery.min.js"></script>
- <!-- Include all compiled plugins (below), or include individual files as needed -->
- <script src="/js/bootstrap/js/bootstrap.min.js"></script>
+ <!-- Include bootstrap bundle (everything necessary to run) -->
+ <script src="/bootstrap5/js/bootstrap.bundle.min.js"></script>
</head>
<body>
@@ -155,33 +153,4 @@ sub alert {
return $self->el(class => "alert alert-danger", %param);
}
-sub add_js {
- my ($self, $js) = @_;
-
- $self->{js} .= $js . "\n";
-}
-
-my $format_event_callback = sub {
- my ($info) = @_;
-
- my $pstr = encode_json($info->{param});
- return "function(e){$info->{fn}.apply(e, $pstr);}";
-};
-
-sub button {
- my ($self, %param) = @_;
-
- $param{tag} = 'button';
- $param{class} = "btn btn-default btn-xs";
-
- if (my $click = delete $param{click}) {
- my ($html, $id) = $self->el(%param);
- my $cb = &$format_event_callback($click);
- $self->add_js("jQuery('#$id').on('click', $cb);");
- return $html;
- } else {
- return $self->el(%param);
- }
-}
-
1;
diff --git a/src/PVE/APIServer/Formatter/HTML.pm b/src/PVE/APIServer/Formatter/HTML.pm
index 2ce0723..d236d7d 100644
--- a/src/PVE/APIServer/Formatter/HTML.pm
+++ b/src/PVE/APIServer/Formatter/HTML.pm
@@ -27,75 +27,86 @@ my $get_portal_login_url = sub {
sub render_page {
my ($doc, $html, $config) = @_;
- my $items = [];
-
- push @$items, {
- tag => 'li',
- cn => {
- tag => 'a',
- href => $get_portal_login_url->($config),
- onclick => "PVE.delete_auth_cookie();",
- text => "Logout",
- }};
-
my $base_url = $get_portal_base_url->($config);
my $nav = $doc->el(
- class => "navbar navbar-inverse navbar-fixed-top",
- role => "navigation", cn => {
- class => "container", cn => [
+ class => "navbar navbar-dark navbar-expand-lg bg-dark fixed-top",
+ 'data-bs-theme' => 'dark',
+ role => "navigation",
+ cn => {
+ class => "container",
+ cn => [
{
- class => "navbar-header", cn => [
- {
- tag => 'button',
- type => 'button',
- class => "navbar-toggle",
- 'data-toggle' => "collapse",
- 'data-target' => ".navbar-collapse",
- cn => [
- { tag => 'span', class => 'sr-only', text => "Toggle navigation" },
- { tag => 'span', class => 'icon-bar' },
- { tag => 'span', class => 'icon-bar' },
- { tag => 'span', class => 'icon-bar' },
- ],
- },
+ tag => 'a',
+ class => "navbar-brand",
+ href => $base_url,
+ text => $config->{title},
+ },
+ {
+ tag => 'button',
+ type => 'button',
+ class => "navbar-toggler",
+ 'data-bs-toggle' => "collapse",
+ 'data-bs-target' => ".navbarNav",
+ cn => [
{
- tag => 'a',
- class => "navbar-brand",
- href => $base_url,
- text => $config->{title},
+ tag => 'span',
+ class => 'navbar-toggler-icon',
},
],
},
{
- class => "collapse navbar-collapse",
+ class => "collapse navbar-collapse navbarNav",
cn => {
tag => 'ul',
- class => "nav navbar-nav",
- cn => $items,
+ class => "navbar-nav",
+ cn => [
+ {
+ tag => 'li',
+ class => 'nav-item',
+ cn => {
+ tag => 'a',
+ class => 'nav-link',
+ href => $get_portal_login_url->($config),
+ onclick => "PVE.delete_auth_cookie();",
+ text => "Logout",
+ },
+ }
+ ],
},
},
- ],
- });
+ ]
+ }
+ );
- $items = [];
+ my $items = [];
my @pcomp = split('/', $doc->{url});
shift @pcomp; # empty
shift @pcomp; # api2
shift @pcomp; # $format
my $href = $base_url;
- push @$items, { tag => 'li', cn => {
- tag => 'a',
- href => $href,
- text => 'Home'}};
-
- foreach my $comp (@pcomp) {
- $href .= "/".encode_entities($comp);
- push @$items, { tag => 'li', cn => {
+ push @$items, {
+ tag => 'li',
+ class => 'breadcrumb-item',
+ cn => {
tag => 'a',
href => $href,
- text => $comp}};
+ text => 'Home',
+ },
+ };
+
+ foreach my $comp (@pcomp) {
+ $href .= "/" . encode_entities($comp);
+ push @$items, {
+ tag => 'li',
+ class => 'breadcrumb-item',
+ cn => {
+ tag => 'a',
+ href => $href,
+ text => $comp,
+ },
+ };
}
my $breadcrumbs = $doc->el(tag => 'ol', class => 'breadcrumb container', cn => $items);
@@ -114,6 +125,7 @@ my $login_form = sub {
my $items = [
{
tag => 'label',
+ class => 'form-label',
text => "Please sign in",
},
{
@@ -150,14 +162,24 @@ my $login_form = sub {
action => $get_portal_login_url->($config),
cn => [
{
- class => 'form-group',
- cn => $items,
+ class => "mb-3",
+ cn => [
+ {
+ class => 'form-group',
+ cn => $items,
+ },
+ ],
},
{
- tag => 'button',
- type => 'submit',
- class => 'btn btn-lg btn-primary btn-block',
- text => "Sign in",
+ class => "d-grid",
+ cn => [
+ {
+ tag => 'button',
+ type => 'submit',
+ class => 'btn btn-lg btn-primary',
+ text => "Sign in",
+ },
+ ],
},
],
});
@@ -236,13 +258,13 @@ PVE::APIServer::Formatter::register_formatter($portal_format, sub {
} else {
my $json = to_json($data, {allow_nonref => 1, pretty => 1, canonical => 1});
- $html .= $doc->el(tag => 'pre', text => $json);
+ $html .= $doc->el(tag => 'pre', class => 'bg-light border rounded p-2', text => $json);
}
} else {
my $json = to_json($data, {allow_nonref => 1, pretty => 1, canonical => 1});
- $html .= $doc->el(tag => 'pre', text => $json);
+ $html .= $doc->el(tag => 'pre', class => 'bg-light border rounded p-2', text => $json);
}
$html = $doc->el(class => 'container', html => $html);
--
2.39.5
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
^ permalink raw reply [flat|nested] 2+ messages in thread
* [pve-devel] applied: [PATCH http-server v2] formatter: html: update to bootstrap 5
2025-06-05 9:02 [pve-devel] [PATCH http-server v2] formatter: html: update to bootstrap 5 Dominik Csapak
@ 2025-06-10 8:17 ` Thomas Lamprecht
0 siblings, 0 replies; 2+ messages in thread
From: Thomas Lamprecht @ 2025-06-10 8:17 UTC (permalink / raw)
To: pve-devel, Dominik Csapak
On Thu, 05 Jun 2025 11:02:51 +0200, Dominik Csapak wrote:
> this makes a few changes necessary, but not too much:
> * include the different directory for bootstrap5
> * use different navbar markup
> * different classes for navbar container + items
> * add classes to pre tag since it's not styled anymore in newer
> bootstrap versions
> * add 'form-label' to labels
> * use containers with 'mb-3' for form + buttons
> * use 'd-grid' container for button instead of 'btn-block'
> * add 'breadcrumb-item' where necessary
>
> [...]
Applied, thanks!
[1/1] formatter: html: update to bootstrap 5
commit: 157d9875f6f11ae44c3f9281bba809afeb342ea8
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2025-06-10 8:18 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-06-05 9:02 [pve-devel] [PATCH http-server v2] formatter: html: update to bootstrap 5 Dominik Csapak
2025-06-10 8:17 ` [pve-devel] applied: " Thomas Lamprecht
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox