[mod] wsl
This commit is contained in:
parent
b741dc5952
commit
ddd772f563
69 changed files with 26660 additions and 25940 deletions
|
|
@ -1,19 +1,19 @@
|
|||
module namespace wsa = 'app/sockets';
|
||||
import module namespace ws="http://basex.org/modules/ws";
|
||||
|
||||
|
||||
declare function wsa:wsids()
|
||||
as xs:string*
|
||||
{
|
||||
ws:ids()
|
||||
};
|
||||
|
||||
declare %rest:path('/app/api/sockets')
|
||||
function wsa:list()
|
||||
as element(ul)
|
||||
{
|
||||
<ul>{
|
||||
wsa:wsids()!<li><a href="/app/sockets/{.}">{.}</a></li>
|
||||
}</ul>
|
||||
|
||||
module namespace wsa = 'app/sockets';
|
||||
import module namespace ws="http://basex.org/modules/ws";
|
||||
|
||||
|
||||
declare function wsa:wsids()
|
||||
as xs:string*
|
||||
{
|
||||
ws:ids()
|
||||
};
|
||||
|
||||
declare %rest:path('/app/api/sockets')
|
||||
function wsa:list()
|
||||
as element(ul)
|
||||
{
|
||||
<ul>{
|
||||
wsa:wsids()!<li><a href="/app/sockets/{.}">{.}</a></li>
|
||||
}</ul>
|
||||
|
||||
};
|
||||
|
|
@ -1,26 +1,26 @@
|
|||
module namespace _ = 'app/error-reporting';
|
||||
import module namespace cm = "app/cm" at "common.xqm";
|
||||
|
||||
|
||||
declare
|
||||
%rest:error("*")
|
||||
%rest:error-param("code", "{$code}")
|
||||
%rest:error-param("description", "{$description}")
|
||||
%rest:error-param("value", "{$value}")
|
||||
%rest:error-param("module", "{$module}")
|
||||
%rest:error-param("line-number", "{$line-number}")
|
||||
%rest:error-param("column-number","{$column-number}")
|
||||
%rest:error-param("additional", "{$additional}")
|
||||
function _:error($code,$description,$value,
|
||||
$module,$line-number,$column-number,$additional) {
|
||||
let $err:=map{"code":$code, "description":$description,
|
||||
"value": _:format($value), "module": $module,
|
||||
"line-number": $line-number, "column-number": $column-number,
|
||||
"additional": _:format($additional)}
|
||||
return cm:htmx2("error.htm", $err)
|
||||
};
|
||||
|
||||
declare function _:format($item)
|
||||
as xs:string{
|
||||
serialize($item,map{"method":"basex"})
|
||||
module namespace _ = 'app/error-reporting';
|
||||
import module namespace cm = "app/cm" at "common.xqm";
|
||||
|
||||
|
||||
declare
|
||||
%rest:error("*")
|
||||
%rest:error-param("code", "{$code}")
|
||||
%rest:error-param("description", "{$description}")
|
||||
%rest:error-param("value", "{$value}")
|
||||
%rest:error-param("module", "{$module}")
|
||||
%rest:error-param("line-number", "{$line-number}")
|
||||
%rest:error-param("column-number","{$column-number}")
|
||||
%rest:error-param("additional", "{$additional}")
|
||||
function _:error($code,$description,$value,
|
||||
$module,$line-number,$column-number,$additional) {
|
||||
let $err:=map{"code":$code, "description":$description,
|
||||
"value": _:format($value), "module": $module,
|
||||
"line-number": $line-number, "column-number": $column-number,
|
||||
"additional": _:format($additional)}
|
||||
return cm:htmx2("error.htm", $err)
|
||||
};
|
||||
|
||||
declare function _:format($item)
|
||||
as xs:string{
|
||||
serialize($item,map{"method":"basex"})
|
||||
};
|
||||
|
|
@ -1,102 +1,102 @@
|
|||
xquery version '3.1';
|
||||
(:~ save conversion outputs to file
|
||||
ensures target folders created
|
||||
save multiple docs when root <wrapper> found
|
||||
optionally serialize XML with default namespace
|
||||
@author quodatum Andy Bunce
|
||||
:)
|
||||
module namespace outlet = 'urn:conversion:outlet';
|
||||
|
||||
(: serialization options
|
||||
key is arbitary name, value is BaseX serialization option map
|
||||
for xml serializations the non-standard 'ns' option supplies a namespace to use as default ' :)
|
||||
declare variable $outlet:serial:=map{
|
||||
"xvrl": map{"method":"xml","ns":"http://www.xproc.org/ns/xvrl"},
|
||||
"docbook":map{"method":"xml","ns":"http://docbook.org/ns/docbook"},
|
||||
"csv": map{"method":"text"},
|
||||
"xml": map{"method":"xml"}
|
||||
};
|
||||
|
||||
(:~save $doc to $dest unless empty,will create directories as required
|
||||
@param $opts serialization options and ns to set a default namespace :)
|
||||
declare function outlet:save($doc as item(),$dest as xs:string?,$opts as map(*)?)
|
||||
as xs:string?{
|
||||
if (exists($dest))
|
||||
then
|
||||
let $doc:=if($opts?ns)
|
||||
then outlet:change-element-ns-deep($doc,$opts?ns,"")
|
||||
else $doc
|
||||
return (
|
||||
file:create-dir(file:parent($dest)),
|
||||
file:write($dest,$doc,map:remove($opts,"ns")),
|
||||
$dest
|
||||
)
|
||||
};
|
||||
|
||||
(:~ save file or files if node is wrapper
|
||||
@return paths to saved files
|
||||
:)
|
||||
declare function outlet:save-wrapper($doc as item(),$dest as xs:string?,$opts as map(*)?)
|
||||
as xs:string*{
|
||||
if ($doc/wrapper)
|
||||
then $doc/wrapper/result! outlet:save(*,file:resolve-path(@href,$dest),$opts)
|
||||
else outlet:save($doc,$dest,$opts)
|
||||
};
|
||||
|
||||
(:~ from functx http://www.xqueryfunctions.com/xq/functx_change-element-ns-deep.html :)
|
||||
declare function outlet:change-element-ns-deep
|
||||
( $nodes as node()* ,
|
||||
$newns as xs:string ,
|
||||
$prefix as xs:string ) as node()* {
|
||||
|
||||
for $node in $nodes
|
||||
return if ($node instance of element())
|
||||
then (element
|
||||
{QName ($newns,
|
||||
concat($prefix,
|
||||
if ($prefix = '')
|
||||
then ''
|
||||
else ':',
|
||||
local-name($node)))}
|
||||
{$node/@*,
|
||||
outlet:change-element-ns-deep($node/node(),
|
||||
$newns, $prefix)})
|
||||
else if ($node instance of document-node())
|
||||
then outlet:change-element-ns-deep($node/node(),
|
||||
$newns, $prefix)
|
||||
else $node
|
||||
} ;
|
||||
|
||||
(:~ @see https://stackoverflow.com/a/8600987/3210344 :)
|
||||
declare function outlet:remove-prefixes($node as node(), $prefixes as xs:string*)
|
||||
as node(){
|
||||
typeswitch ($node)
|
||||
case element()
|
||||
return
|
||||
if ($prefixes = ('#all', prefix-from-QName(node-name($node)))) then
|
||||
element {QName(namespace-uri($node), local-name($node))} {
|
||||
$node/@*,
|
||||
$node/node()/outlet:remove-prefixes(., $prefixes)
|
||||
}
|
||||
else
|
||||
element {node-name($node)} {
|
||||
$node/@*,
|
||||
$node/node()/outlet:remove-prefixes(., $prefixes)
|
||||
}
|
||||
case document-node()
|
||||
return
|
||||
document {
|
||||
$node/node()/outlet:remove-prefixes(., $prefixes)
|
||||
}
|
||||
default
|
||||
return $node
|
||||
};
|
||||
|
||||
(:~ relative file paths below folder $path, matching $selector :)
|
||||
declare function outlet:select($path as xs:string,$selector as map(xs:string,item()*))
|
||||
as xs:string*
|
||||
{
|
||||
file:list($path,true(),$selector?pattern)
|
||||
[some $i in $selector?include satisfies contains(.,$i)]
|
||||
[every $x in $selector?exclude satisfies not(contains(.,$x))]
|
||||
xquery version '3.1';
|
||||
(:~ save conversion outputs to file
|
||||
ensures target folders created
|
||||
save multiple docs when root <wrapper> found
|
||||
optionally serialize XML with default namespace
|
||||
@author quodatum Andy Bunce
|
||||
:)
|
||||
module namespace outlet = 'urn:conversion:outlet';
|
||||
|
||||
(: serialization options
|
||||
key is arbitary name, value is BaseX serialization option map
|
||||
for xml serializations the non-standard 'ns' option supplies a namespace to use as default ' :)
|
||||
declare variable $outlet:serial:=map{
|
||||
"xvrl": map{"method":"xml","ns":"http://www.xproc.org/ns/xvrl"},
|
||||
"docbook":map{"method":"xml","ns":"http://docbook.org/ns/docbook"},
|
||||
"csv": map{"method":"text"},
|
||||
"xml": map{"method":"xml"}
|
||||
};
|
||||
|
||||
(:~save $doc to $dest unless empty,will create directories as required
|
||||
@param $opts serialization options and ns to set a default namespace :)
|
||||
declare function outlet:save($doc as item(),$dest as xs:string?,$opts as map(*)?)
|
||||
as xs:string?{
|
||||
if (exists($dest))
|
||||
then
|
||||
let $doc:=if($opts?ns)
|
||||
then outlet:change-element-ns-deep($doc,$opts?ns,"")
|
||||
else $doc
|
||||
return (
|
||||
file:create-dir(file:parent($dest)),
|
||||
file:write($dest,$doc,map:remove($opts,"ns")),
|
||||
$dest
|
||||
)
|
||||
};
|
||||
|
||||
(:~ save file or files if node is wrapper
|
||||
@return paths to saved files
|
||||
:)
|
||||
declare function outlet:save-wrapper($doc as item(),$dest as xs:string?,$opts as map(*)?)
|
||||
as xs:string*{
|
||||
if ($doc/wrapper)
|
||||
then $doc/wrapper/result! outlet:save(*,file:resolve-path(@href,$dest),$opts)
|
||||
else outlet:save($doc,$dest,$opts)
|
||||
};
|
||||
|
||||
(:~ from functx http://www.xqueryfunctions.com/xq/functx_change-element-ns-deep.html :)
|
||||
declare function outlet:change-element-ns-deep
|
||||
( $nodes as node()* ,
|
||||
$newns as xs:string ,
|
||||
$prefix as xs:string ) as node()* {
|
||||
|
||||
for $node in $nodes
|
||||
return if ($node instance of element())
|
||||
then (element
|
||||
{QName ($newns,
|
||||
concat($prefix,
|
||||
if ($prefix = '')
|
||||
then ''
|
||||
else ':',
|
||||
local-name($node)))}
|
||||
{$node/@*,
|
||||
outlet:change-element-ns-deep($node/node(),
|
||||
$newns, $prefix)})
|
||||
else if ($node instance of document-node())
|
||||
then outlet:change-element-ns-deep($node/node(),
|
||||
$newns, $prefix)
|
||||
else $node
|
||||
} ;
|
||||
|
||||
(:~ @see https://stackoverflow.com/a/8600987/3210344 :)
|
||||
declare function outlet:remove-prefixes($node as node(), $prefixes as xs:string*)
|
||||
as node(){
|
||||
typeswitch ($node)
|
||||
case element()
|
||||
return
|
||||
if ($prefixes = ('#all', prefix-from-QName(node-name($node)))) then
|
||||
element {QName(namespace-uri($node), local-name($node))} {
|
||||
$node/@*,
|
||||
$node/node()/outlet:remove-prefixes(., $prefixes)
|
||||
}
|
||||
else
|
||||
element {node-name($node)} {
|
||||
$node/@*,
|
||||
$node/node()/outlet:remove-prefixes(., $prefixes)
|
||||
}
|
||||
case document-node()
|
||||
return
|
||||
document {
|
||||
$node/node()/outlet:remove-prefixes(., $prefixes)
|
||||
}
|
||||
default
|
||||
return $node
|
||||
};
|
||||
|
||||
(:~ relative file paths below folder $path, matching $selector :)
|
||||
declare function outlet:select($path as xs:string,$selector as map(xs:string,item()*))
|
||||
as xs:string*
|
||||
{
|
||||
file:list($path,true(),$selector?pattern)
|
||||
[some $i in $selector?include satisfies contains(.,$i)]
|
||||
[every $x in $selector?exclude satisfies not(contains(.,$x))]
|
||||
};
|
||||
|
|
@ -1,199 +1,199 @@
|
|||
xquery version '3.1';
|
||||
(:~
|
||||
Library to manage running multiple jobs using BaseX job:eval,
|
||||
where the jobs are the execution of one function for a set of arguments
|
||||
|
||||
The function will have signature `fn($key as xs:string) as element()`
|
||||
The function will typically create outputs and have side effects.
|
||||
|
||||
State information is persisted with the storage module, using the key '_wrangle'
|
||||
It is a map{$wid: {"jobs":}}
|
||||
requires basex 10+
|
||||
@licence BSD
|
||||
@author: quodatum
|
||||
@date: 2023/02/12
|
||||
:)
|
||||
module namespace wrangle = 'urn:quodatum:wrangler';
|
||||
(:~ semantic version :)
|
||||
declare variable $wrangle:version:="1.0.0";
|
||||
(:~ used in bindings to indicate a wrangle job and as store key :)
|
||||
declare variable $wrangle:id:="_wrangle";
|
||||
|
||||
(:~
|
||||
submit wrangle jobs for each $item
|
||||
@param wrangle data{xq:...,bindings:..}
|
||||
@return unique id for the job set
|
||||
:)
|
||||
declare function wrangle:queue($items as item()*,$wrangle as map(*))
|
||||
as xs:string{
|
||||
let $wid := random:uuid()
|
||||
let $jobs := $items!job:eval($wrangle?xq,
|
||||
map:merge(($wrangle?bindings(.),map:entry($wrangle:id,$wid))),
|
||||
map{"cache":true()}
|
||||
)
|
||||
|
||||
let $this := map:entry($wid,map:entry("jobs",$jobs!map:entry(.,
|
||||
map{
|
||||
"complete":false(),
|
||||
"details":job:list-details(.)
|
||||
})))
|
||||
|
||||
let $_:=store:put($wrangle:id,map:merge((($this,wrangle:store()))))
|
||||
return $wid
|
||||
};
|
||||
|
||||
(:~ active wrangle ids :)
|
||||
declare function wrangle:active()
|
||||
as xs:string*{
|
||||
job:list()!job:bindings(.)?($wrangle:id)=>distinct-values()
|
||||
};
|
||||
|
||||
(:~ known wrangles :)
|
||||
declare function wrangle:list()
|
||||
as xs:string*{
|
||||
wrangle:store()=>map:keys()
|
||||
};
|
||||
|
||||
(:~ details for $wid wrangle :)
|
||||
declare function wrangle:list-details($wid as xs:string)
|
||||
as map(*){
|
||||
wrangle:store()=>map:get($wid)
|
||||
};
|
||||
|
||||
(:~ all wrangled jobs :)
|
||||
declare function wrangle:job-list()
|
||||
as xs:string*{
|
||||
job:list()[job:bindings(.)=>map:contains($wrangle:id)]
|
||||
};
|
||||
|
||||
(:~ jobs for wrangle id :)
|
||||
declare function wrangle:job-list($wid as xs:string)
|
||||
as xs:string*{
|
||||
job:list()[job:bindings(.)?($wrangle:id) eq $wid]
|
||||
};
|
||||
|
||||
(:~ is wrangle id finished (or unknown) :)
|
||||
declare function wrangle:finished($wid as xs:string)
|
||||
as xs:string*{
|
||||
every $job in job:list()[job:bindings(.)?($wrangle:id) eq $wid] satisfies job:finished($job)
|
||||
};
|
||||
|
||||
(:~ wait wrangle id finished (or unknown) :)
|
||||
declare function wrangle:wait($wid as xs:string)
|
||||
as empty-sequence(){
|
||||
let $done:=every $job in job:list()[job:bindings(.)?($wrangle:id) eq $wid]
|
||||
satisfies empty(job:wait($job))
|
||||
return if($done) then ()
|
||||
};
|
||||
|
||||
(:~ cancel wrangle id :)
|
||||
declare function wrangle:remove($wid as xs:string)
|
||||
as empty-sequence(){
|
||||
job:list()[job:bindings(.)?($wrangle:id) eq $wid]!job:remove(.),
|
||||
store:put($wrangle:id,wrangle:store()=>map:remove($wid))
|
||||
};
|
||||
|
||||
(:~ tally of non-zero job status for $wid "scheduled", "queued", "running", "cached" :)
|
||||
declare function wrangle:status($wid as xs:string)
|
||||
as map(*){
|
||||
wrangle:job-list($wid)!job:list-details(.)/@state/string()
|
||||
=>fold-left(map{},wrangle:tally-count#2)
|
||||
};
|
||||
|
||||
(:~ job-results with no error as sequence:)
|
||||
declare function wrangle:results($wid as xs:string)
|
||||
as item()*{
|
||||
wrangle:job-list($wid)!wrangle:job-result(.)[not(?error)]?result
|
||||
};
|
||||
|
||||
(:~ error counts keyed on $err:code :)
|
||||
declare function wrangle:errors($wid as xs:string)
|
||||
as map(*){
|
||||
wrangle:job-list($wid)!wrangle:job-result(.)[?error]?result?code!string()
|
||||
=>fold-left(map{},wrangle:tally-count#2)
|
||||
};
|
||||
|
||||
(:~ key is $err:code values are joblists :)
|
||||
declare function wrangle:jobs-by-error($wid as xs:string)
|
||||
as map(*){
|
||||
(for $jobId in wrangle:job-list($wid)
|
||||
let $result:=wrangle:job-result($jobId)[?error]
|
||||
where exists($result)
|
||||
return map:entry($result?result?code!string(),$jobId)
|
||||
)
|
||||
=> map:merge( map{"duplicates":"combine"})
|
||||
};
|
||||
|
||||
(:~ return key for job:)
|
||||
declare function wrangle:job-key($jobId as xs:string)
|
||||
as xs:string{
|
||||
let $b:=job:bindings($jobId)
|
||||
return $b?(map:keys($b)[. ne $wrangle:id])
|
||||
};
|
||||
|
||||
(:~ return map from peek at result:)
|
||||
declare function wrangle:job-result($jobId as xs:string)
|
||||
as map(*){
|
||||
try{
|
||||
map{
|
||||
"error":false(),
|
||||
"result": job:result($jobId,map{"keep":true()})
|
||||
}
|
||||
}catch *{
|
||||
map{
|
||||
"error":true(),
|
||||
"result": map{"description": $err:description,
|
||||
"code": $err:code,
|
||||
"line": $err:column-number,
|
||||
"additional": $err:additional,
|
||||
"value":$err:value
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
(:~ XQuery for background service :)
|
||||
declare function wrangle:service()
|
||||
as xs:string{
|
||||
``[
|
||||
import module namespace wrangle = 'urn:quodatum:wrangler:v1'; at "`{ static-base-uri() }`";
|
||||
let $done:=wrangle:job-list()[job:finished(.)]
|
||||
if(exists($done))
|
||||
then let $w:=store:get($wrangle:id)
|
||||
for $job in $done
|
||||
group by $wid= job:bindings($job)?($wrangle:id)
|
||||
for $job in $job
|
||||
let $_:=store:put($wrangle:id)
|
||||
]``
|
||||
|
||||
};
|
||||
(:~ schedule as service :)
|
||||
declare function wrangle:schedule-service()
|
||||
as xs:string{
|
||||
wrangle:service()
|
||||
=>job:eval((), map { 'id':$wrangle:id, 'service':true(),
|
||||
'interval': 'PT1S','log': $wrangle:id})
|
||||
};
|
||||
|
||||
(:~ cached data as map :)
|
||||
declare function wrangle:store()
|
||||
as map(*){
|
||||
store:get-or-put($wrangle:id,function(){map{}})
|
||||
};
|
||||
|
||||
(:~ @return map string->count for fold-left :)
|
||||
declare %private function wrangle:tally-count($r as map(*),$this as xs:string)
|
||||
as map(*){
|
||||
map:merge(
|
||||
(map:entry($this,if(map:contains($r,$this)) then $r($this)+1 else 1),$r),
|
||||
map{"duplicates":"use-first"}
|
||||
)
|
||||
};
|
||||
(:~ @return map string->(string*) for fold-left :)
|
||||
declare %private function wrangle:tally-list($r as map(*),$key as xs:string,$value as xs:string)
|
||||
as map(*){
|
||||
map:merge(
|
||||
(map:entry($key,$value),$r),
|
||||
map{"duplicates":"combine"}
|
||||
)
|
||||
xquery version '3.1';
|
||||
(:~
|
||||
Library to manage running multiple jobs using BaseX job:eval,
|
||||
where the jobs are the execution of one function for a set of arguments
|
||||
|
||||
The function will have signature `fn($key as xs:string) as element()`
|
||||
The function will typically create outputs and have side effects.
|
||||
|
||||
State information is persisted with the storage module, using the key '_wrangle'
|
||||
It is a map{$wid: {"jobs":}}
|
||||
requires basex 10+
|
||||
@licence BSD
|
||||
@author: quodatum
|
||||
@date: 2023/02/12
|
||||
:)
|
||||
module namespace wrangle = 'urn:quodatum:wrangler';
|
||||
(:~ semantic version :)
|
||||
declare variable $wrangle:version:="1.0.0";
|
||||
(:~ used in bindings to indicate a wrangle job and as store key :)
|
||||
declare variable $wrangle:id:="_wrangle";
|
||||
|
||||
(:~
|
||||
submit wrangle jobs for each $item
|
||||
@param wrangle data{xq:...,bindings:..}
|
||||
@return unique id for the job set
|
||||
:)
|
||||
declare function wrangle:queue($items as item()*,$wrangle as map(*))
|
||||
as xs:string{
|
||||
let $wid := random:uuid()
|
||||
let $jobs := $items!job:eval($wrangle?xq,
|
||||
map:merge(($wrangle?bindings(.),map:entry($wrangle:id,$wid))),
|
||||
map{"cache":true()}
|
||||
)
|
||||
|
||||
let $this := map:entry($wid,map:entry("jobs",$jobs!map:entry(.,
|
||||
map{
|
||||
"complete":false(),
|
||||
"details":job:list-details(.)
|
||||
})))
|
||||
|
||||
let $_:=store:put($wrangle:id,map:merge((($this,wrangle:store()))))
|
||||
return $wid
|
||||
};
|
||||
|
||||
(:~ active wrangle ids :)
|
||||
declare function wrangle:active()
|
||||
as xs:string*{
|
||||
job:list()!job:bindings(.)?($wrangle:id)=>distinct-values()
|
||||
};
|
||||
|
||||
(:~ known wrangles :)
|
||||
declare function wrangle:list()
|
||||
as xs:string*{
|
||||
wrangle:store()=>map:keys()
|
||||
};
|
||||
|
||||
(:~ details for $wid wrangle :)
|
||||
declare function wrangle:list-details($wid as xs:string)
|
||||
as map(*){
|
||||
wrangle:store()=>map:get($wid)
|
||||
};
|
||||
|
||||
(:~ all wrangled jobs :)
|
||||
declare function wrangle:job-list()
|
||||
as xs:string*{
|
||||
job:list()[job:bindings(.)=>map:contains($wrangle:id)]
|
||||
};
|
||||
|
||||
(:~ jobs for wrangle id :)
|
||||
declare function wrangle:job-list($wid as xs:string)
|
||||
as xs:string*{
|
||||
job:list()[job:bindings(.)?($wrangle:id) eq $wid]
|
||||
};
|
||||
|
||||
(:~ is wrangle id finished (or unknown) :)
|
||||
declare function wrangle:finished($wid as xs:string)
|
||||
as xs:string*{
|
||||
every $job in job:list()[job:bindings(.)?($wrangle:id) eq $wid] satisfies job:finished($job)
|
||||
};
|
||||
|
||||
(:~ wait wrangle id finished (or unknown) :)
|
||||
declare function wrangle:wait($wid as xs:string)
|
||||
as empty-sequence(){
|
||||
let $done:=every $job in job:list()[job:bindings(.)?($wrangle:id) eq $wid]
|
||||
satisfies empty(job:wait($job))
|
||||
return if($done) then ()
|
||||
};
|
||||
|
||||
(:~ cancel wrangle id :)
|
||||
declare function wrangle:remove($wid as xs:string)
|
||||
as empty-sequence(){
|
||||
job:list()[job:bindings(.)?($wrangle:id) eq $wid]!job:remove(.),
|
||||
store:put($wrangle:id,wrangle:store()=>map:remove($wid))
|
||||
};
|
||||
|
||||
(:~ tally of non-zero job status for $wid "scheduled", "queued", "running", "cached" :)
|
||||
declare function wrangle:status($wid as xs:string)
|
||||
as map(*){
|
||||
wrangle:job-list($wid)!job:list-details(.)/@state/string()
|
||||
=>fold-left(map{},wrangle:tally-count#2)
|
||||
};
|
||||
|
||||
(:~ job-results with no error as sequence:)
|
||||
declare function wrangle:results($wid as xs:string)
|
||||
as item()*{
|
||||
wrangle:job-list($wid)!wrangle:job-result(.)[not(?error)]?result
|
||||
};
|
||||
|
||||
(:~ error counts keyed on $err:code :)
|
||||
declare function wrangle:errors($wid as xs:string)
|
||||
as map(*){
|
||||
wrangle:job-list($wid)!wrangle:job-result(.)[?error]?result?code!string()
|
||||
=>fold-left(map{},wrangle:tally-count#2)
|
||||
};
|
||||
|
||||
(:~ key is $err:code values are joblists :)
|
||||
declare function wrangle:jobs-by-error($wid as xs:string)
|
||||
as map(*){
|
||||
(for $jobId in wrangle:job-list($wid)
|
||||
let $result:=wrangle:job-result($jobId)[?error]
|
||||
where exists($result)
|
||||
return map:entry($result?result?code!string(),$jobId)
|
||||
)
|
||||
=> map:merge( map{"duplicates":"combine"})
|
||||
};
|
||||
|
||||
(:~ return key for job:)
|
||||
declare function wrangle:job-key($jobId as xs:string)
|
||||
as xs:string{
|
||||
let $b:=job:bindings($jobId)
|
||||
return $b?(map:keys($b)[. ne $wrangle:id])
|
||||
};
|
||||
|
||||
(:~ return map from peek at result:)
|
||||
declare function wrangle:job-result($jobId as xs:string)
|
||||
as map(*){
|
||||
try{
|
||||
map{
|
||||
"error":false(),
|
||||
"result": job:result($jobId,map{"keep":true()})
|
||||
}
|
||||
}catch *{
|
||||
map{
|
||||
"error":true(),
|
||||
"result": map{"description": $err:description,
|
||||
"code": $err:code,
|
||||
"line": $err:column-number,
|
||||
"additional": $err:additional,
|
||||
"value":$err:value
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
(:~ XQuery for background service :)
|
||||
declare function wrangle:service()
|
||||
as xs:string{
|
||||
``[
|
||||
import module namespace wrangle = 'urn:quodatum:wrangler:v1'; at "`{ static-base-uri() }`";
|
||||
let $done:=wrangle:job-list()[job:finished(.)]
|
||||
if(exists($done))
|
||||
then let $w:=store:get($wrangle:id)
|
||||
for $job in $done
|
||||
group by $wid= job:bindings($job)?($wrangle:id)
|
||||
for $job in $job
|
||||
let $_:=store:put($wrangle:id)
|
||||
]``
|
||||
|
||||
};
|
||||
(:~ schedule as service :)
|
||||
declare function wrangle:schedule-service()
|
||||
as xs:string{
|
||||
wrangle:service()
|
||||
=>job:eval((), map { 'id':$wrangle:id, 'service':true(),
|
||||
'interval': 'PT1S','log': $wrangle:id})
|
||||
};
|
||||
|
||||
(:~ cached data as map :)
|
||||
declare function wrangle:store()
|
||||
as map(*){
|
||||
store:get-or-put($wrangle:id,function(){map{}})
|
||||
};
|
||||
|
||||
(:~ @return map string->count for fold-left :)
|
||||
declare %private function wrangle:tally-count($r as map(*),$this as xs:string)
|
||||
as map(*){
|
||||
map:merge(
|
||||
(map:entry($this,if(map:contains($r,$this)) then $r($this)+1 else 1),$r),
|
||||
map{"duplicates":"use-first"}
|
||||
)
|
||||
};
|
||||
(:~ @return map string->(string*) for fold-left :)
|
||||
declare %private function wrangle:tally-list($r as map(*),$key as xs:string,$value as xs:string)
|
||||
as map(*){
|
||||
map:merge(
|
||||
(map:entry($key,$value),$r),
|
||||
map{"duplicates":"combine"}
|
||||
)
|
||||
};
|
||||
|
|
@ -1,21 +1,21 @@
|
|||
<!DOCTYPE HTML5>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{layout.htm}">
|
||||
|
||||
<head>
|
||||
<title>dev</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div layout:fragment="content">
|
||||
<sl-breadcrumb>
|
||||
<sl-breadcrumb-item href="/app/dev">DEV</sl-breadcrumb-item>
|
||||
<sl-breadcrumb-item>dba</sl-breadcrumb-item>
|
||||
|
||||
</sl-breadcrumb>
|
||||
<iframe src="/dba/logs?input=%2Fapp%2F|£" allowScripts="true"
|
||||
style="width:100%;height:80vh;overflow:clip;"></iframe>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
<!DOCTYPE HTML5>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{layout.htm}">
|
||||
|
||||
<head>
|
||||
<title>dev</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div layout:fragment="content">
|
||||
<sl-breadcrumb>
|
||||
<sl-breadcrumb-item href="/app/dev">DEV</sl-breadcrumb-item>
|
||||
<sl-breadcrumb-item>dba</sl-breadcrumb-item>
|
||||
|
||||
</sl-breadcrumb>
|
||||
<iframe src="/dba/logs?input=%2Fapp%2F|£" allowScripts="true"
|
||||
style="width:100%;height:80vh;overflow:clip;"></iframe>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -1,40 +1,40 @@
|
|||
<!DOCTYPE HTML5>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{layout.htm}">
|
||||
|
||||
<head>
|
||||
<title>Dev home</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div layout:fragment="content">
|
||||
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-light">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="#">Dev</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a href="/app/dev/dba" class="nav-link" >dba</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="/app/dev/jobs" class="nav-link" >jobs</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="/dba/logs?input=%2Fapp%2F|£" target="_blank" class="nav-link" >DBA <sl-icon name="box-arrow-up-right"></sl-icon></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="/app/api" target="_blank" class="nav-link" >wadl <sl-icon name="box-arrow-up-right"></sl-icon></a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
list tasks etc
|
||||
</div>
|
||||
</body>
|
||||
|
||||
<!DOCTYPE HTML5>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{layout.htm}">
|
||||
|
||||
<head>
|
||||
<title>Dev home</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div layout:fragment="content">
|
||||
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-light">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="#">Dev</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a href="/app/dev/dba" class="nav-link" >dba</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="/app/dev/jobs" class="nav-link" >jobs</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="/dba/logs?input=%2Fapp%2F|£" target="_blank" class="nav-link" >DBA <sl-icon name="box-arrow-up-right"></sl-icon></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="/app/api" target="_blank" class="nav-link" >wadl <sl-icon name="box-arrow-up-right"></sl-icon></a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
list tasks etc
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -1,28 +1,28 @@
|
|||
<!DOCTYPE HTML5>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{layout.htm}">
|
||||
|
||||
<head>
|
||||
<title>Jobs</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div layout:fragment="content" class="container-fluid">
|
||||
<div class="d-flex ">
|
||||
<sl-breadcrumb class="flex-grow-1" >
|
||||
<sl-breadcrumb-item href="/app/jobs">Jobs home</sl-breadcrumb-item>
|
||||
<sl-breadcrumb-item>jobs <span class="badge bg-secondary">4</span></sl-breadcrumb-item>
|
||||
</sl-breadcrumb>
|
||||
<sl-switch id="job-refresh" checked="checked" >Refresh</sl-switch>
|
||||
</div>
|
||||
|
||||
<h2>Jobs</h2>
|
||||
<hr />
|
||||
<div hx-get="/app/jobs/table" hx-trigger="every 1s [htmx.find('#job-refresh').checked]" >
|
||||
Nothing Yet!
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
|
||||
<!DOCTYPE HTML5>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{layout.htm}">
|
||||
|
||||
<head>
|
||||
<title>Jobs</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div layout:fragment="content" class="container-fluid">
|
||||
<div class="d-flex ">
|
||||
<sl-breadcrumb class="flex-grow-1" >
|
||||
<sl-breadcrumb-item href="/app/jobs">Jobs home</sl-breadcrumb-item>
|
||||
<sl-breadcrumb-item>jobs <span class="badge bg-secondary">4</span></sl-breadcrumb-item>
|
||||
</sl-breadcrumb>
|
||||
<sl-switch id="job-refresh" checked="checked" >Refresh</sl-switch>
|
||||
</div>
|
||||
|
||||
<h2>Jobs</h2>
|
||||
<hr />
|
||||
<div hx-get="/app/jobs/table" hx-trigger="every 1s [htmx.find('#job-refresh').checked]" >
|
||||
Nothing Yet!
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -1,27 +1,27 @@
|
|||
<!DOCTYPE HTML5>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{layout.htm}">
|
||||
|
||||
<head>
|
||||
<title>Error</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div layout:fragment="content" class="container">
|
||||
<h2 >Error: <span th:text="${code}" class="btn btn-danger"></span></h2>
|
||||
<dl>
|
||||
<dt>Description</dt>
|
||||
<dd th:text="${description}"></dd>
|
||||
<dt>Value</dt>
|
||||
<dd th:text="${value}"></dd>
|
||||
<dt>Module</dt>
|
||||
<dd ><span th:text="${module}"/>[<span th:text="${line-number}"/>,<span th:text="${column-number}"/>]</dd>
|
||||
<dt>Additional</dt>
|
||||
<dd>
|
||||
<pre th:text="${additional}"></pre>
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
<!DOCTYPE HTML5>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{layout.htm}">
|
||||
|
||||
<head>
|
||||
<title>Error</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div layout:fragment="content" class="container">
|
||||
<h2 >Error: <span th:text="${code}" class="btn btn-danger"></span></h2>
|
||||
<dl>
|
||||
<dt>Description</dt>
|
||||
<dd th:text="${description}"></dd>
|
||||
<dt>Value</dt>
|
||||
<dd th:text="${value}"></dd>
|
||||
<dt>Module</dt>
|
||||
<dd ><span th:text="${module}"/>[<span th:text="${line-number}"/>,<span th:text="${column-number}"/>]</dd>
|
||||
<dt>Additional</dt>
|
||||
<dd>
|
||||
<pre th:text="${additional}"></pre>
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -1,64 +1,64 @@
|
|||
<!DOCTYPE html>
|
||||
<html layout:decorate="~{layout.htm}"
|
||||
xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
|
||||
<head>
|
||||
|
||||
<title>Home</title>
|
||||
</head>
|
||||
<body>
|
||||
<div layout:fragment="content" class="container">
|
||||
<!-- have a button POST a click via AJAX -->
|
||||
<div style="display:inline-flex">
|
||||
<p th:text="${version}">ver</p>
|
||||
<sl-button hx-get="http://v2.jokeapi.dev/joke/Any?format=txt&safe-mode&type=single" hx-target="#joke-container" variant="default" hx-confirm="Do you want a Joke?">
|
||||
<sl-icon slot="prefix" name="emoji-laughing"></sl-icon>Joke
|
||||
</sl-button>
|
||||
<p id="joke-container" style="flex-grow:4"> </p>
|
||||
</div>
|
||||
<hr />
|
||||
|
||||
<form hx-put="/pdf3/api/contact/1" hx-target="this" hx-swap="outerHTML">
|
||||
<div>
|
||||
<label>First Name</label>
|
||||
<input type="text" name="firstName" value="Joe"/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Last Name</label>
|
||||
<input type="text" name="lastName" value="Blow"/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Email Address</label>
|
||||
<input type="email" name="email" value="joe@blow.com"/>
|
||||
</div>
|
||||
<button class="btn">Submit</button>
|
||||
<button class="btn" hx-get="/contact/1">Cancel</button>
|
||||
</form>
|
||||
<hr />
|
||||
<h2>Contacts</h2>
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Email</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="contacts-table" hx-get="/pdf3/api/contacts/table" hx-trigger="newContact from:body">
|
||||
</tbody>
|
||||
</table>
|
||||
<h2>Add A Contact</h2>
|
||||
<form hx-post="/pdf3/api/contacts">
|
||||
<label>
|
||||
Name
|
||||
<input name="name" type="text"/>
|
||||
</label>
|
||||
<label>
|
||||
Email
|
||||
<input name="email" type="email"/>
|
||||
</label>
|
||||
</form>
|
||||
<hr />
|
||||
|
||||
</div>
|
||||
</body>
|
||||
<!DOCTYPE html>
|
||||
<html layout:decorate="~{layout.htm}"
|
||||
xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
|
||||
<head>
|
||||
|
||||
<title>Home</title>
|
||||
</head>
|
||||
<body>
|
||||
<div layout:fragment="content" class="container">
|
||||
<!-- have a button POST a click via AJAX -->
|
||||
<div style="display:inline-flex">
|
||||
<p th:text="${version}">ver</p>
|
||||
<sl-button hx-get="http://v2.jokeapi.dev/joke/Any?format=txt&safe-mode&type=single" hx-target="#joke-container" variant="default" hx-confirm="Do you want a Joke?">
|
||||
<sl-icon slot="prefix" name="emoji-laughing"></sl-icon>Joke
|
||||
</sl-button>
|
||||
<p id="joke-container" style="flex-grow:4"> </p>
|
||||
</div>
|
||||
<hr />
|
||||
|
||||
<form hx-put="/pdf3/api/contact/1" hx-target="this" hx-swap="outerHTML">
|
||||
<div>
|
||||
<label>First Name</label>
|
||||
<input type="text" name="firstName" value="Joe"/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Last Name</label>
|
||||
<input type="text" name="lastName" value="Blow"/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Email Address</label>
|
||||
<input type="email" name="email" value="joe@blow.com"/>
|
||||
</div>
|
||||
<button class="btn">Submit</button>
|
||||
<button class="btn" hx-get="/contact/1">Cancel</button>
|
||||
</form>
|
||||
<hr />
|
||||
<h2>Contacts</h2>
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Email</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="contacts-table" hx-get="/pdf3/api/contacts/table" hx-trigger="newContact from:body">
|
||||
</tbody>
|
||||
</table>
|
||||
<h2>Add A Contact</h2>
|
||||
<form hx-post="/pdf3/api/contacts">
|
||||
<label>
|
||||
Name
|
||||
<input name="name" type="text"/>
|
||||
</label>
|
||||
<label>
|
||||
Email
|
||||
<input name="email" type="email"/>
|
||||
</label>
|
||||
</form>
|
||||
<hr />
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,68 +1,68 @@
|
|||
<!DOCTYPE HTML5>
|
||||
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta
|
||||
name="htmx-config"
|
||||
content='{
|
||||
"responseHandling":[
|
||||
{"code":"204", "swap": false},
|
||||
{"code":"[23]..", "swap": true},
|
||||
{"code":"404", "swap": true},
|
||||
{"code":"[45]..", "swap": false, "error":true},
|
||||
{"code":"...", "swap": true}
|
||||
],
|
||||
"selfRequestsOnly": false
|
||||
}'
|
||||
/>
|
||||
<title>LSP manager</title>
|
||||
<link rel="icon" href="/app/static/favicon.png" />
|
||||
<link rel="stylesheet" href="https://unpkg.com/missing.css@1.2.0" />
|
||||
<link rel="stylesheet" href="/app/static/styles.css" />
|
||||
<script defer="defer" src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/htmx.org@2.0.7/dist/htmx.js" integrity="sha384-yWakaGAFicqusuwOYEmoRjLNOC+6OFsdmwC2lbGQaRELtuVEqNzt11c2J711DeCZ" crossorigin="anonymous"></script>
|
||||
<script defer="defer" src="/app/static/script.js"></script>
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body hx-boost="true" hx-indicator="#indicator" data-bs-theme="light" >
|
||||
<div class='App'>
|
||||
<header id="header" class="navbar">
|
||||
|
||||
<nav >
|
||||
|
||||
<ul role="list">
|
||||
<li >
|
||||
<a class="active" aria-current="page" href="/app/home">Home</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="/app/socket">connections </a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</nav>
|
||||
|
||||
</header>
|
||||
<main id="main" class="App-main">
|
||||
<p layout:fragment="content">MAIN</p>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<button onclick="toast('Hi. '+new Date())">toast</button>
|
||||
|
||||
LoggedIn: ??
|
||||
<button type="button" class="btn btn-primary" id="liveToastBtn">Show live toast</button>
|
||||
|
||||
|
||||
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
<!DOCTYPE HTML5>
|
||||
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta
|
||||
name="htmx-config"
|
||||
content='{
|
||||
"responseHandling":[
|
||||
{"code":"204", "swap": false},
|
||||
{"code":"[23]..", "swap": true},
|
||||
{"code":"404", "swap": true},
|
||||
{"code":"[45]..", "swap": false, "error":true},
|
||||
{"code":"...", "swap": true}
|
||||
],
|
||||
"selfRequestsOnly": false
|
||||
}'
|
||||
/>
|
||||
<title>LSP manager</title>
|
||||
<link rel="icon" href="/app/static/favicon.png" />
|
||||
<link rel="stylesheet" href="https://unpkg.com/missing.css@1.2.0" />
|
||||
<link rel="stylesheet" href="/app/static/styles.css" />
|
||||
<script defer="defer" src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/htmx.org@2.0.7/dist/htmx.js" integrity="sha384-yWakaGAFicqusuwOYEmoRjLNOC+6OFsdmwC2lbGQaRELtuVEqNzt11c2J711DeCZ" crossorigin="anonymous"></script>
|
||||
<script defer="defer" src="/app/static/script.js"></script>
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body hx-boost="true" hx-indicator="#indicator" data-bs-theme="light" >
|
||||
<div class='App'>
|
||||
<header id="header" class="navbar">
|
||||
|
||||
<nav >
|
||||
|
||||
<ul role="list">
|
||||
<li >
|
||||
<a class="active" aria-current="page" href="/app/home">Home</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="/app/socket">connections </a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</nav>
|
||||
|
||||
</header>
|
||||
<main id="main" class="App-main">
|
||||
<p layout:fragment="content">MAIN</p>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<button onclick="toast('Hi. '+new Date())">toast</button>
|
||||
|
||||
LoggedIn: ??
|
||||
<button type="button" class="btn btn-primary" id="liveToastBtn">Show live toast</button>
|
||||
|
||||
|
||||
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -1,25 +1,25 @@
|
|||
<!DOCTYPE HTML5>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{layout.htm}">
|
||||
|
||||
<head>
|
||||
<title>Login</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div layout:fragment="content">
|
||||
<form onsubmit="${login}" action="${router.guardUrl()}">
|
||||
<fieldset style="width:50%;">
|
||||
<sl-input label="User name" value="${session.login}" oninput="${html.set(session, 'login')}"
|
||||
clearable="clearable"></sl-input>
|
||||
|
||||
<sl-input value="${session.password}" oninput="${html.set(session, 'password')}" type="password"
|
||||
label="Password" password-toggle="password-toggle" clearable="clearable"></sl-input>
|
||||
<input type="checkbox" checked="${session.loggedIn}" />
|
||||
</fieldset>
|
||||
<button type="submit">Login</button>
|
||||
<button onclick="${fastlogin}">Fast</button>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
<!DOCTYPE HTML5>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{layout.htm}">
|
||||
|
||||
<head>
|
||||
<title>Login</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div layout:fragment="content">
|
||||
<form onsubmit="${login}" action="${router.guardUrl()}">
|
||||
<fieldset style="width:50%;">
|
||||
<sl-input label="User name" value="${session.login}" oninput="${html.set(session, 'login')}"
|
||||
clearable="clearable"></sl-input>
|
||||
|
||||
<sl-input value="${session.password}" oninput="${html.set(session, 'password')}" type="password"
|
||||
label="Password" password-toggle="password-toggle" clearable="clearable"></sl-input>
|
||||
<input type="checkbox" checked="${session.loggedIn}" />
|
||||
</fieldset>
|
||||
<button type="submit">Login</button>
|
||||
<button onclick="${fastlogin}">Fast</button>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,42 +1,42 @@
|
|||
<!DOCTYPE HTML5>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{layout.htm}">
|
||||
|
||||
<head>
|
||||
<title>test</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div layout:fragment="content">
|
||||
<sl-card class="card-overview">
|
||||
|
||||
<div slot="header">
|
||||
<sl-tooltip>
|
||||
<div th:text="${pdf.slug}" slot="content">path</div>
|
||||
<sl-badge th:text="${pdf.index}">{pdf.index}</sl-badge>
|
||||
</sl-tooltip>
|
||||
|
||||
<a th:href="@{/pdfs/{pdf.id}/raw}" href="/app/pdfs/{pdf.id}/details"><small>{pdf}</small></a>
|
||||
<sl-button-group label="History">
|
||||
<sl-icon-button name="file-earmark-pdf" label="Settings"
|
||||
th:href="@{/pdfs/{pdf.id}/raw}" href="/app/pdfs/{pdf.id}/view"></sl-icon-button>
|
||||
|
||||
</sl-button-group>
|
||||
</div>
|
||||
|
||||
<div style="display:flex;">
|
||||
<div>
|
||||
<a href="/app/pdfs/{pdf.id}/details" class="holder center">
|
||||
<img src="/app/pdfs/{pdf.id}/cover" loading="{index >10?'lazy':'eager'}"
|
||||
alt="A kitten sits patiently." />
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
slug:<br /><small th:text="${pdf.id}">{pdf.id}</small><br />
|
||||
</div>
|
||||
</div>
|
||||
</sl-card>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
<!DOCTYPE HTML5>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{layout.htm}">
|
||||
|
||||
<head>
|
||||
<title>test</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div layout:fragment="content">
|
||||
<sl-card class="card-overview">
|
||||
|
||||
<div slot="header">
|
||||
<sl-tooltip>
|
||||
<div th:text="${pdf.slug}" slot="content">path</div>
|
||||
<sl-badge th:text="${pdf.index}">{pdf.index}</sl-badge>
|
||||
</sl-tooltip>
|
||||
|
||||
<a th:href="@{/pdfs/{pdf.id}/raw}" href="/app/pdfs/{pdf.id}/details"><small>{pdf}</small></a>
|
||||
<sl-button-group label="History">
|
||||
<sl-icon-button name="file-earmark-pdf" label="Settings"
|
||||
th:href="@{/pdfs/{pdf.id}/raw}" href="/app/pdfs/{pdf.id}/view"></sl-icon-button>
|
||||
|
||||
</sl-button-group>
|
||||
</div>
|
||||
|
||||
<div style="display:flex;">
|
||||
<div>
|
||||
<a href="/app/pdfs/{pdf.id}/details" class="holder center">
|
||||
<img src="/app/pdfs/{pdf.id}/cover" loading="{index >10?'lazy':'eager'}"
|
||||
alt="A kitten sits patiently." />
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
slug:<br /><small th:text="${pdf.id}">{pdf.id}</small><br />
|
||||
</div>
|
||||
</div>
|
||||
</sl-card>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -1,19 +1,19 @@
|
|||
<!DOCTYPE HTML5>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{layout.htm}">
|
||||
|
||||
<head>
|
||||
<title>404</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div layout:fragment="content">
|
||||
<h2>Page not found:</h2>
|
||||
<ul>
|
||||
<li th:text="${path}">Page: pdf2/${ path }</li>
|
||||
<li>Method: ${ method }</li>
|
||||
</ul>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
<!DOCTYPE HTML5>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{layout.htm}">
|
||||
|
||||
<head>
|
||||
<title>404</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div layout:fragment="content">
|
||||
<h2>Page not found:</h2>
|
||||
<ul>
|
||||
<li th:text="${path}">Page: pdf2/${ path }</li>
|
||||
<li>Method: ${ method }</li>
|
||||
</ul>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Loading…
Add table
Add a link
Reference in a new issue