25
1
mirror of https://github.com/processone/ejabberd.git synced 2024-11-20 16:15:59 +01:00

WebAdmin: Add make_command functions to produce HTML command element

Support to sort tables using Sortable library from:
  https://github.com/tofsjonas/sortable
This commit is contained in:
Badlop 2024-05-10 17:21:43 +02:00
parent 74d6f0a68d
commit 30bd8f1570
10 changed files with 1037 additions and 35 deletions

View File

@ -26,6 +26,18 @@
{tuple, [rterm()]} | {list, rterm()} | {tuple, [rterm()]} | {list, rterm()} |
rescode | restuple. rescode | restuple.
%% The purpose of a command can either be:
%% - informative: its purpose is to obtain information
%% - modifier: its purpose is to produce some change in the server
%%
%% A modifier command should be designed just to produce its desired side-effect,
%% and its result term should just be success or failure: rescode or restuple.
%%
%% ejabberd_web_admin:make_command/2 considers that commands
%% with result type different than rescode or restuple
%% are commands that can be safely executed automatically
%% to get information and build the web page.
-type oauth_scope() :: atom(). -type oauth_scope() :: atom().
%% ejabberd_commands OAuth ReST ACL definition: %% ejabberd_commands OAuth ReST ACL definition:

View File

@ -62,6 +62,11 @@
[{<<"type">>, Type}, {<<"name">>, Name}, [{<<"type">>, Type}, {<<"name">>, Name},
{<<"value">>, Value}])). {<<"value">>, Value}])).
-define(INPUTPH(Type, Name, Value, PlaceHolder),
?XA(<<"input">>,
[{<<"type">>, Type}, {<<"name">>, Name},
{<<"value">>, Value}, {<<"placeholder">>, PlaceHolder}])).
-define(INPUTT(Type, Name, Value), -define(INPUTT(Type, Name, Value),
?INPUT(Type, Name, (translate:translate(Lang, Value)))). ?INPUT(Type, Name, (translate:translate(Lang, Value)))).
@ -95,16 +100,27 @@
-define(XRES(Text), -define(XRES(Text),
?XAC(<<"p">>, [{<<"class">>, <<"result">>}], Text)). ?XAC(<<"p">>, [{<<"class">>, <<"result">>}], Text)).
-define(DIVRES(Elements),
?XAE(<<"div">>, [{<<"class">>, <<"result">>}], Elements)).
%% Guide Link %% Guide Link
-define(XREST(Text), ?XRES((translate:translate(Lang, Text)))). -define(XREST(Text), ?XRES((translate:translate(Lang, Text)))).
-define(GL(Ref, Title), -define(GL(Ref, Title),
?XAE(<<"div">>, [{<<"class">>, <<"guidelink">>}], ?XAE(<<"div">>, [{<<"class">>, <<"guidelink">>}],
[?XAE(<<"a">>, [?XAE(<<"a">>,
[{<<"href">>, <<"https://docs.ejabberd.im/admin/configuration/", Ref/binary>>}, [{<<"href">>, <<"https://docs.ejabberd.im/", Ref/binary>>},
{<<"target">>, <<"_blank">>}], {<<"target">>, <<"_blank">>}],
[?C(<<"docs: ", Title/binary>>)])])). [?C(<<"docs: ", Title/binary>>)])])).
%% h1 with a Guide Link %% h1 with a Guide Link
-define(H1GL(Name, Ref, Title), -define(H1GLraw(Name, Ref, Title),
[?XC(<<"h1">>, Name), ?GL(Ref, Title)]). [?XC(<<"h1">>, Name), ?GL(Ref, Title), ?BR]).
-define(H1GL(Name, RefConf, Title),
?H1GLraw(Name, <<"admin/configuration/", RefConf/binary>>, Title)).
-define(ANCHORL(Ref),
?XAE(<<"div">>, [{<<"class">>, <<"anchorlink">>}],
[?XAE(<<"a">>,
[{<<"href">>, <<"#", Ref/binary>>}],
[?C(<<"<=">>)])])).

View File

@ -112,6 +112,7 @@ defmodule Ejabberd.MixProject do
if_version_below(~c"24", [{:d, :SYSTOOLS_APP_DEF_WITHOUT_OPTIONAL}]) ++ if_version_below(~c"24", [{:d, :SYSTOOLS_APP_DEF_WITHOUT_OPTIONAL}]) ++
if_version_below(~c"24", [{:d, :OTP_BELOW_24}]) ++ if_version_below(~c"24", [{:d, :OTP_BELOW_24}]) ++
if_version_below(~c"25", [{:d, :OTP_BELOW_25}]) ++ if_version_below(~c"25", [{:d, :OTP_BELOW_25}]) ++
if_version_below(~c"26", [{:d, :OTP_BELOW_26}]) ++
if_version_below(~c"27", [{:d, :OTP_BELOW_27}]) ++ if_version_below(~c"27", [{:d, :OTP_BELOW_27}]) ++
if_type_exported(:odbc, {:opaque, :connection_reference, 0}, [{:d, :ODBC_HAS_TYPES}]) if_type_exported(:odbc, {:opaque, :connection_reference, 0}, [{:d, :ODBC_HAS_TYPES}])
defines = for {:d, value} <- result, do: {:d, value} defines = for {:d, value} <- result, do: {:d, value}

View File

@ -136,11 +136,7 @@ ul li #navhead a, ul li #navheadsub a, ul li #navheadsubsub a {
margin-bottom: -1px; margin-bottom: -1px;
} }
thead tr td { thead tr td {
background: #3eaffa; background: #cae7e4;
color: #fff;
}
thead tr td a {
color: #fff;
} }
td.copy { td.copy {
text-align: center; text-align: center;
@ -227,22 +223,29 @@ h3 {
padding-top: 25px; padding-top: 25px;
width: 70%; width: 70%;
} }
div.anchorlink {
display: inline-block;
float: right;
margin-top: 1em;
margin-right: 1em;
}
div.anchorlink a {
padding: 3px;
background: #cae7e4;
font-size: 0.75em;
color: black;
}
div.guidelink, div.guidelink,
p[dir=ltr] { p[dir=ltr] {
display: inline-block; display: inline-block;
float: right; float: right;
margin-top: 1em;
margin: 0;
margin-right: 1em; margin-right: 1em;
} }
div.guidelink a, div.guidelink a,
p[dir=ltr] a { p[dir=ltr] a {
display: inline-block;
border-radius: 3px;
padding: 3px; padding: 3px;
background: #3eaffa; background: #3eaffa;
font-size: 0.75em; font-size: 0.75em;
color: #fff; color: #fff;
} }
@ -265,7 +268,7 @@ input,
select { select {
font-size: 1em; font-size: 1em;
} }
p.result { .result {
border: 1px; border: 1px;
border-style: dashed; border-style: dashed;
border-color: #FE8A02; border-color: #FE8A02;
@ -284,3 +287,18 @@ p.result {
color: #cb2431; color: #cb2431;
transition: none; transition: none;
} }
h3.api {
border-bottom: 1px solid #b6b6b6;
}
details > summary {
background-color: #dbeceb;
border: none;
cursor: pointer;
list-style: none;
padding: 8px;
}
details > pre, details > p {
background-color: #e6f1f0;
margin: 0;
padding: 10px;
}

1
priv/css/sortable.min.css vendored Normal file
View File

@ -0,0 +1 @@
.sortable thead th:not(.no-sort){cursor:pointer}.sortable thead th:not(.no-sort)::after,.sortable thead th:not(.no-sort)::before{transition:color .1s ease-in-out;font-size:1.2em;color:rgba(0,0,0,0)}.sortable thead th:not(.no-sort)::after{margin-left:3px;content:"▸"}.sortable thead th:not(.no-sort):hover::after{color:inherit}.sortable thead th:not(.no-sort)[aria-sort=descending]::after{color:inherit;content:"▾"}.sortable thead th:not(.no-sort)[aria-sort=ascending]::after{color:inherit;content:"▴"}.sortable thead th:not(.no-sort).indicator-left::after{content:""}.sortable thead th:not(.no-sort).indicator-left::before{margin-right:3px;content:"▸"}.sortable thead th:not(.no-sort).indicator-left:hover::before{color:inherit}.sortable thead th:not(.no-sort).indicator-left[aria-sort=descending]::before{color:inherit;content:"▾"}.sortable thead th:not(.no-sort).indicator-left[aria-sort=ascending]::before{color:inherit;content:"▴"}/*# sourceMappingURL=sortable-base.min.css.map */

3
priv/js/sortable.min.js vendored Normal file
View File

@ -0,0 +1,3 @@
document.addEventListener("click",function(c){try{function h(b,a){return b.nodeName===a?b:h(b.parentNode,a)}var v=c.shiftKey||c.altKey,d=h(c.target,"TH"),m=d.parentNode,n=m.parentNode,g=n.parentNode;function p(b){var a;return v?b.dataset.sortAlt:null!==(a=b.dataset.sort)&&void 0!==a?a:b.textContent}if("THEAD"===n.nodeName&&g.classList.contains("sortable")&&!d.classList.contains("no-sort")){var q,f=m.cells,r=+d.dataset.sortTbr;for(c=0;c<f.length;c++)f[c]===d?q=+d.dataset.sortCol||c:f[c].setAttribute("aria-sort",
"none");f="descending";if("descending"===d.getAttribute("aria-sort")||g.classList.contains("asc")&&"ascending"!==d.getAttribute("aria-sort"))f="ascending";d.setAttribute("aria-sort",f);var w="ascending"===f,x=g.classList.contains("n-last"),t=function(b,a,e){a=p(a.cells[e]);b=p(b.cells[e]);if(x){if(""===a&&""!==b)return-1;if(""===b&&""!==a)return 1}e=+a-+b;a=isNaN(e)?a.localeCompare(b):e;return w?-a:a};for(c=0;c<g.tBodies.length;c++){var k=g.tBodies[c],u=[].slice.call(k.rows,0);u.sort(function(b,a){var e=
t(b,a,q);return 0!==e||isNaN(r)?e:t(b,a,r)});var l=k.cloneNode();l.append.apply(l,u);g.replaceChild(l,k)}}}catch(h){}});

View File

@ -130,6 +130,7 @@
{if_version_below, "24", {d, 'SYSTOOLS_APP_DEF_WITHOUT_OPTIONAL'}}, {if_version_below, "24", {d, 'SYSTOOLS_APP_DEF_WITHOUT_OPTIONAL'}},
{if_version_below, "24", {d, 'OTP_BELOW_24'}}, {if_version_below, "24", {d, 'OTP_BELOW_24'}},
{if_version_below, "25", {d, 'OTP_BELOW_25'}}, {if_version_below, "25", {d, 'OTP_BELOW_25'}},
{if_version_below, "26", {d, 'OTP_BELOW_26'}},
{if_version_below, "27", {d, 'OTP_BELOW_27'}}, {if_version_below, "27", {d, 'OTP_BELOW_27'}},
{if_var_false, debug, no_debug_info}, {if_var_false, debug, no_debug_info},
{if_var_true, debug, debug_info}, {if_var_true, debug, debug_info},

View File

@ -344,10 +344,10 @@ validator(from) ->
fun(L) when is_list(L) -> fun(L) when is_list(L) ->
lists:map( lists:map(
fun({K, V}) -> {(econf:enum([tag]))(K), (econf:binary())(V)}; fun({K, V}) -> {(econf:enum([tag]))(K), (econf:binary())(V)};
(A) -> (econf:enum([ejabberd_xmlrpc, mod_cron, mod_http_api, ejabberd_ctl]))(A) (A) -> (econf:enum([ejabberd_xmlrpc, mod_cron, mod_http_api, ejabberd_ctl, ejabberd_web_admin]))(A)
end, lists:flatten(L)); end, lists:flatten(L));
(A) -> (A) ->
[(econf:enum([ejabberd_xmlrpc, mod_cron, mod_http_api, ejabberd_ctl]))(A)] [(econf:enum([ejabberd_xmlrpc, mod_cron, mod_http_api, ejabberd_ctl, ejabberd_web_admin]))(A)]
end; end;
validator(what) -> validator(what) ->
econf:and_then( econf:and_then(

View File

@ -32,7 +32,8 @@
%% gen_server callbacks %% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, -export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]). terminate/2, code_change/3]).
-export([get_commands_spec/0]). -export([get_commands_spec/0, format_arg/2,
get_usage_command/4]).
-include("ejabberd_ctl.hrl"). -include("ejabberd_ctl.hrl").
-include("ejabberd_commands.hrl"). -include("ejabberd_commands.hrl").
@ -786,7 +787,7 @@ print_usage_help(MaxC, ShCode) ->
longdesc = lists:flatten(LongDesc), longdesc = lists:flatten(LongDesc),
args = ArgsDef, args = ArgsDef,
result = {help, string}}, result = {help, string}},
print_usage_command2("help", C, MaxC, ShCode). print(get_usage_command2("help", C, MaxC, ShCode), []).
%%----------------------------- %%-----------------------------
@ -848,11 +849,14 @@ maybe_add_policy_arguments(Args, _) ->
-spec print_usage_command(Cmd::string(), MaxC::integer(), -spec print_usage_command(Cmd::string(), MaxC::integer(),
ShCode::boolean(), Version::integer()) -> ok. ShCode::boolean(), Version::integer()) -> ok.
print_usage_command(Cmd, MaxC, ShCode, Version) -> print_usage_command(Cmd, MaxC, ShCode, Version) ->
print(get_usage_command(Cmd, MaxC, ShCode, Version), []).
get_usage_command(Cmd, MaxC, ShCode, Version) ->
Name = list_to_atom(Cmd), Name = list_to_atom(Cmd),
C = ejabberd_commands:get_command_definition(Name, Version), C = ejabberd_commands:get_command_definition(Name, Version),
print_usage_command2(Cmd, C, MaxC, ShCode). get_usage_command2(Cmd, C, MaxC, ShCode).
print_usage_command2(Cmd, C, MaxC, ShCode) -> get_usage_command2(Cmd, C, MaxC, ShCode) ->
#ejabberd_commands{ #ejabberd_commands{
tags = TagsAtoms, tags = TagsAtoms,
definer = Definer, definer = Definer,
@ -926,12 +930,12 @@ print_usage_command2(Cmd, C, MaxC, ShCode) ->
false -> "" false -> ""
end, end,
case Cmd of First = case Cmd of
"help" -> ok; "help" -> "";
_ -> print([NameFmt, "\n", ArgsFmt, "\n", ReturnsFmt, _ -> [NameFmt, "\n", ArgsFmt, "\n", ReturnsFmt,
"\n\n", ExampleFmt, TagsFmt, "\n\n", ModuleFmt, NoteFmt, DescFmt, "\n\n"], []) "\n\n", ExampleFmt, TagsFmt, "\n\n", ModuleFmt, NoteFmt, DescFmt, "\n\n"]
end, end,
print([LongDescFmt, NoteEjabberdctlList, NoteEjabberdctlTuple], []). [First, LongDescFmt, NoteEjabberdctlList, NoteEjabberdctlTuple].
%%----------------------------- %%-----------------------------
%% Format Arguments Help %% Format Arguments Help

File diff suppressed because it is too large Load Diff