This commit is contained in:
Andy Bunce 2017-08-24 18:17:53 +01:00
parent 251cf23fd8
commit 07509ce03b
19 changed files with 289 additions and 183 deletions

View file

@ -60,6 +60,22 @@ Vue.config.errorHandler = function (err, vm, info) {
alert("vue error");
};
//Returns a function, that, as long as it continues to be invoked, will not
//be triggered. The function will be called after it stops being called for
//N milliseconds. If `immediate` is passed, trigger the function on the
//leading edge, instead of the trailing. https://gist.github.com/nmsdvid/8807205
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
clearTimeout(timeout);
timeout = setTimeout(function() {
timeout = null;
if (!immediate) func.apply(context, args);
}, wait);
if (immediate && !timeout) func.apply(context, args);
};
};
// used by vue-ace
var Events = new Vue({});

View file

@ -10,8 +10,8 @@
</v-btn>
<v-toolbar-title>
<v-breadcrumbs>
<v-breadcrumbs-item v-for="item in crumbs" :key="item" :to="{ query: { url: '/' + item + '/' }}">
{{ item }}
<v-breadcrumbs-item v-for="item in crumbs" :key="item.path" :to="{ query: { url: item.path }}">
{{ item.name }}
</v-breadcrumbs-item>
</v-breadcrumbs>
</v-toolbar-title>
@ -149,7 +149,10 @@
return (this.protocol=="basexdb")?"developer_mode":"folder"
},
crumbs(){
return this.url.split("/").filter((a)=>a.length>0)
var parts=this.url.split("/").filter((a)=>a.length>0)
var a=parts.map(function(v,i,a){return {name:v,
path:"/"+a.slice(0,i+1).join("/")+"/"}})
return a
}
},
watch:{

View file

@ -12,17 +12,15 @@
<v-btn @click="imports()">
<v-icon>play_circle_outline</v-icon>
Imports</v-btn>
<v-menu :nudge-width="100">
<v-toolbar-title slot="activator">
<span>{{font}}</span>
<v-icon >arrow_drop_down</v-icon>
</v-toolbar-title>
<v-list>
<v-list-tile v-for="item in dropdown_font" :key="item.text">
<v-list-tile-title v-text="item.text" @click="font=item.text"></v-list-tile-title>
</v-list-tile>
</v-list>
</v-menu>
<v-menu offset-y>
<v-btn icon primary dark slot="activator"> <v-icon>more_vert</v-icon></v-btn>
<v-list>
<v-list-tile @click="plan">Show query plan</v-list-tile>
</v-list>
<v-list>
<v-list-tile @click="hitme">hit me</v-list-tile>
</v-list>
</v-menu>
</v-toolbar>
@ -37,25 +35,27 @@
{{result}}
</v-alert>
<v-card-actions v-if="show" >
JobId:
<v-chip class="green white--text">{{jobId}}</v-chip>
<v-progress-circular v-if="waiting" indeterminate class="primary--text"></v-progress-circular>
<v-chip class="primary white--text">{{jobId}}</v-chip>
<v-chip label class="grey white--text">
<v-avatar class="red"> <v-icon>lock</v-icon>W</v-avatar>
{{ jobState.writes }}</v-chip>
<v-chip label class="grey white--text">
<v-avatar class="amber"> <v-icon>lock</v-icon>R</v-avatar>
{{ jobState.reads }}</v-chip>
<v-spacer></v-spacer>
<v-chip class="green white--text">
<v-progress-circular v-if="waiting" indeterminate class="primary--text"></v-progress-circular>
<v-chip>{{ jobState.state }}</v-chip>
<v-chip class="primary white--text">
<v-avatar > <v-icon>timer</v-icon></v-avatar>
{{elapsed}}ms</v-chip>
</v-card-actions>
<v-card-text v-if="show">
<v-card-text v-if="showResult">
<v-flex xs12 style="height:200px" fill-height>
<vue-ace :content="result" mode="text" wrap="true" read-only="true"
<vue-ace :content="result" mode="text" wrap="false" read-only="true"
></vue-ace>
</v-flex>
</v-card-text>
@ -71,18 +71,12 @@
result:'',
elapsed: null,
show: false,
showError: false,
showError: false, //unused
showResult: false, //
jobId: null,
waiting: false,
start: null,
jobState: {},
font: 'Courier',
dropdown_font: [
{ text: 'Test select' },
{ text: 'Calibri' },
{ text: 'Courier' },
{ text: 'Verdana' }
]
jobState: {}
}
},
methods:{
@ -93,14 +87,13 @@
},
run(){
this.showError=this.show=false
this.awaitResult(false)
this.start = performance.now();
HTTP.post("eval/execute",Qs.stringify({xq:this.xq}))
.then(r=>{
this.elapsed=Math.floor(performance.now() - this.start);
this.result=r.data.result
this.jobId=null
this.show=true
})
.catch(r=> {
console.log("error",r)
@ -112,12 +105,12 @@
},
submit(){
var data={xq:this.xq}
this.showError=this.show=false
this.showResult=this.show=false
this.start = performance.now();
HTTP.post("eval/submit",Qs.stringify(data))
.then(r=>{
this.elapsed=Math.floor(performance.now() - this.start);
this.result=this.jobId=r.data.job
this.jobId=r.data.job
this.show=true
this.pollState()
@ -144,15 +137,38 @@
})
},
getResult(){
this.awaitResult(true)
HTTP.post("eval/result/"+this.jobId)
.then(r=>{
this.result=r.data.result
this.jobId=null
this.show=true
})
},
hitme(){
this.showResult=true
setTimeout(()=>{this.result="123\n".repeat(20000); },10);
},
imports(){
alert("@TODO imports")
},
plan(){
this.awaitResult(false)
HTTP.post("eval/plan",Qs.stringify({xq:this.xq}))
.then(r=>{
this.result=r.data.result
})
.catch(r=> {
console.log("error",r)
this.result=r.response.data
this.showError=true;
});
},
awaitResult(show){
// ace slow when setting large text while hidden
this.show=show
this.result="(Please wait..)"
this.showResult=true
}
},

View file

@ -24,6 +24,22 @@ function vue-api:eval($xq )
</json>
};
(:~
: query plan
:)
declare
%rest:POST %rest:path("/vue-poc/api/eval/plan")
%rest:form-param("xq", "{$xq}")
%output:method("json")
function vue-api:plan($xq )
{
let $x:=fn:trace($xq,"task: ")
let $r:=xquery:parse($xq,map{"compile":true(),"plan":true()})
return <json type="object" >
<result>{ serialize($r) }</result>
</json>
};
(:~
: submit a simple job
:)

View file

@ -20,6 +20,7 @@
<v-layout>
<v-flex xs5>
<pre style="overflow:auto;">{{ image.doc }}</pre>
<a :href="meta" target="_new" >full metadata</a>
</v-flex>
<v-flex xs7 >
@ -40,7 +41,10 @@
computed: {
path(){
return this.loaded?'/vue-poc/api/images/list/'+ this.id+ '/image':null
}
},
meta(){
return this.loaded?'/vue-poc/api/images/list/'+ this.id+ '/meta':null
}
},
created:function(){
var id=this._props.id

View file

@ -14,9 +14,10 @@
v-if="query.keyword || query.from || query.until">
<v-icon>clear</v-icon>
</v-btn>
<v-chip class="primary white--text">{{ total }}</v-chip>
<v-spacer></v-spacer>
<span v-if="!busy">
<v-chip class="primary white--text">{{ total }} in {{ elapsed | round(2) }} secs </v-chip>
Page:{{ query.page+1 }}
<v-btn @click.stop="query.page=Math.min(0,query.page-1)" :disabled="query.page==0" icon primary>
@ -25,6 +26,7 @@
<v-btn @click.stop="query.page+=1" icon primary>
<v-icon>arrow_forward</v-icon>
</v-btn>
</span>
</v-toolbar>
<v-progress-linear v-if="busy" v-bind:indeterminate="true" ></v-progress-linear>
<v-container v-if="!busy" fluid grid-list-md>
@ -163,6 +165,7 @@
keyword:null
},
total:null,
elapsed:null,
showFilter:false,
busy:false,
menu2:false,
@ -184,7 +187,7 @@
this.total=r.data.total
this.images=r.data.items
var t1 = performance.now();
console.log("Time: ",t1 - t0)
this.elapsed= 0.001 *(t1 - t0)
})
},
clear(){

View file

@ -72,7 +72,7 @@ declare
function vue-api:keywords()
{
let $keys:=
collection("/vue-poc/Pictures")/image/keywords/keyword
collection("/vue-poc/image")/image/keywords/keyword
=>distinct-values()
=>sort("http://www.w3.org/2005/xpath-functions/collation/html-ascii-case-insensitive")
return <json type="object" >
@ -82,14 +82,37 @@ return <json type="object" >
</json>
};
(:~ fields for image for json :)
(:~ full size image :)
declare
%rest:GET %rest:path("/vue-poc/api/images/list/{ $id }/image")
function vue-api:rawimage($id as xs:integer)
{
let $image as element(image):=db:open-id("vue-poc",$id)
let $path:=$cfg:IMAGEDIR || '../' || $vue-api:entity?access?path($image)
return (
web:response-header(map { 'media-type': web:content-type($path) }),
file:read-binary($path)
)
};
(:~ image metadata :)
declare
%rest:GET %rest:path("/vue-poc/api/images/list/{ $id }/meta")
function vue-api:meta($id as xs:integer)
{
let $image as element(image):=db:open-id("vue-poc",$id)
let $path:="vue-poc/meta/" || $vue-api:entity?access?path($image) || "/meta.xml"
return doc($path)
};
(:~ fields for thumbnail for json :)
declare function vue-api:get-image($image as element(image))
as element(*)*
{
let $id:=$vue-api:entity?access?id($image)
let $path:=$vue-api:entity?access?path($image)
let $name:=$vue-api:entity?access?name($image)
let $thumb:= $cfg:THUMBDIR || $path
let $thumb:= $cfg:THUMBDIR || $path
let $thumb:=if(file:exists($thumb)) then $thumb else $cfg:THUMBDIR || "missing.jpg"
return ( <id>{$id}</id>
,<name>{$name}</name>
@ -98,16 +121,5 @@ return ( <id>{$id}</id>
,<mime>{fetch:content-type($thumb)}</mime>)
};
declare
%rest:GET %rest:path("/vue-poc/api/images/list/{ $id }/image")
function vue-api:rawimage($id as xs:integer)
{
let $image as element(image):=db:open-id("vue-poc",$id)
let $path:=$cfg:IMAGEDIR || $vue-api:entity?access?path($image)
return (
web:response-header(map { 'media-type': web:content-type($path) }),
file:read-binary($path)
)
};

View file

@ -9,15 +9,15 @@ declare namespace c="http://www.w3.org/ns/xproc-step";
declare variable $DB:="vue-poc";
declare variable $CHUNK:=1000;
let $done:=uri-collection("vue-poc/Pictures")
let $done:=uri-collection("vue-poc/meta")
let $files:= doc("/vue-poc/pics.xml")//c:file[ends-with(lower-case(@name),".jpg")]
let $relpath:= $files!( ancestor-or-self::*/@name=>string-join("/"))
let $todo:= $relpath[not("/vue-poc/" || .|| "/meta.xml"=$done)]
let $todo:= $relpath[not("/vue-poc/meta/" || .|| "/meta.xml"=$done)]
return (for $f in subsequence($todo,1, $CHUNK)
let $spath:=$cfg:IMAGEDIR || "../" || $f
let $dbpath:=$f || "/meta.xml"
let $dbpath:="meta/" || $f || "/meta.xml"
let $meta:=imgmeta:read($spath)
return db:replace($DB,$dbpath,$meta),
db:output($todo=>count()))

View file

@ -4,7 +4,7 @@
:)
import module namespace metadata = 'expkg-zone58:image.metadata';
import module namespace cfg = "quodatum:media.image.configure" at "config.xqm";
for $meta in collection("/vue-poc/Pictures")/metadata
for $meta in collection("/vue-poc/meta")/metadata
let $loc:=db:path($meta)=>tokenize("/")
let $name:=$loc[count($loc)-1]
let $path:= subsequence($loc,1,count($loc)-1)=>string-join("/")
@ -14,5 +14,5 @@ for $meta in collection("/vue-poc/Pictures")/metadata
metadata:geo($meta),
metadata:keywords($meta)
} </image>
let $target:=$path || "/image.xml"
let $target:="image/"|| $path || "/image.xml"
return db:replace("vue-poc",$target,$image)

View file

@ -29,7 +29,7 @@ declare %updating function local:write-binary($data,$url as xs:string)
file:write-binary($url,$data)
)
};
let $done:=uri-collection("vue-poc/Pictures")
let $files:= doc("/vue-poc/pics.xml")//c:file[ends-with(lower-case(@name),".jpg")]
let $relpath:= $files!( ancestor-or-self::*/@name=>string-join("/"))

View file

@ -1,4 +1,4 @@
(: set original:)
for $i in collection("/vue-poc/Pictures")/image
for $i in collection("/vue-poc/image")/image
where $i[file/@path=>contains('original')]
return insert node attribute { 'original' } { true() } into $i

View file

@ -2,29 +2,30 @@
<template id="jobs">
<v-card >
<v-toolbar light>
<v-btn
light icon
:loading="loading"
@click="getJobs()"
:disabled="loading"
>
<v-icon>refresh</v-icon>
</v-btn>
<v-btn
@click="stop()"
:disabled="noSelection"
>Stop</v-btn>
<v-spacer></v-spacer>
<v-text-field
<v-text-field
append-icon="search"
label="Filter jobs"
single-line
hide-details
v-model="search"
></v-text-field>
></v-text-field>
<v-spacer></v-spacer>
<v-btn
light icon
:loading="loading"
@click="getJobs()"
@dblclick="autorefresh = !autorefresh"
:disabled="loading"
>
<v-icon>{{ autorefresh?'refresh':'arrow_downward' }}</v-icon>
</v-btn>
</v-toolbar>
<v-data-table
:headers="headers"
@ -44,13 +45,13 @@
></v-checkbox>
</td>
<td class="vtop"> <router-link :to="{name: 'jobShow', params: {job: props.item.id }}">{{props.item.id}}</router-link></td>
<td class="vtop text-xs-right">{{ props.item.state }}</td>
<td class="vtop "><div>{{ props.item.state }}</div>
<div>{{ props.item.type }}</div> </td>
<td class="vtop text-xs-right">{{ props.item.duration }}</td>
<td class="vtop text-xs-right">{{ props.item.type }}</td>
<td class="vtop text-xs-right">{{ props.item.writes }}</td>
<td class="vtop text-xs-right">{{ props.item.reads }}</td>
<td class="vtop text-xs-right">{{ props.item.user }}</td>
<td class="vtop"><code>{{ props.item.text }}</code></td>
<td class="vtop" ><code class="multiline-ellipsis">{{ props.item.text }}</code></td>
</template>
</v-data-table>
</v-card>
@ -67,7 +68,6 @@
},
{ text: 'State', value: 'state' },
{ text: 'Duration', value: 'duration' },
{ text: 'Type', value: 'type' },
{ text: 'WriteL', value: 'writes' },
{ text: 'ReadL', value: 'reads' },
{ text: 'User', value: 'user' },
@ -75,9 +75,10 @@
],
items:[
],
selected:[],
search:"",
loading:false
selected: [],
search: "",
loading: false,
autorefresh: true
}
},
methods:{
@ -87,7 +88,7 @@
.then(r=>{
this.loading=false
this.items=r.data
setTimeout(()=>{ this.getJobs() }, 10000);
if(this.autorefresh) setTimeout(()=>{ this.getJobs() }, 10000);
})
},
@ -102,7 +103,7 @@
noSelection: function () {
// `this` points to the vm instance
return this.selected.length==0
}
},
},
created(){
this.getJobs()

View file

@ -25,7 +25,7 @@ declare variable $vue:DEST:="static/app-gen.js";
declare function vue:feature($doc,$isComp as xs:boolean)
as xs:string
{
let $p:=vue:parse($doc)
let $p:=vue:parse($doc=>trace("feature: "))
let $script:= $p?script=>substring-after("{")
return if(empty($p?id)) then
@ -64,6 +64,20 @@ declare function vue:capitalize-first
concat(upper-case(substring($arg,1,1)), substring($arg,2))
};
declare function vue:feature-files($proj)
as xs:string*
{
let $FEATURES:="features/"=>file:resolve-path($proj=>trace("proj:"))
return fw:directory-list($FEATURES,map{"include-filter":".*\.vue"})
//c:file/@name/resolve-uri(.,base-uri(.))
};
declare function vue:feature-build($url as xs:string,$isComp as xs:boolean)
as xs:string
{
fetch:text($url)=>html5:doc()=>vue:feature($isComp)
};
(:~
: compile vue code to "static/app-gen.js"
: @param $proj root folder e.g "C:/Users/andy/git/vue-poc/src/vue-poc/"
@ -76,13 +90,12 @@ let $CORE:="components/core.js"=>file:resolve-path($proj)
let $FILTERS:="components/filters.js"=>file:resolve-path($proj)
let $DEST:="static/app-gen.js"=>file:resolve-path($proj)
let $files:= fw:directory-list($FEATURES,map{"include-filter":".*\.vue"})
//c:file/@name/resolve-uri(.,base-uri(.))
let $feats:=$files!(fetch:text(.)=>html5:doc()=>vue:feature(false()))
let $files:=vue:feature-files($proj)
let $feats:=$files!vue:feature-build(.,false())
let $files:= fw:directory-list($COMPONENTS,map{"include-filter":".*\.vue"})
//c:file/@name/resolve-uri(.,base-uri(.))
let $comps:=$files!(fetch:text(.)=>html5:doc()=>vue:feature(true()))
let $comps:=$files!vue:feature-build(.,true())
let $comment:="// generated " || current-dateTime() || "&#xA;&#xD;"
return file:write-text($DEST,string-join(($comment,

View file

@ -1,5 +1,5 @@
(: entity access maps
: auto generated from xml files in entities folder at: 2017-08-13T22:21:05.468+01:00
: auto generated from xml files in entities folder at: 2017-08-23T10:12:22.413+01:00
:)
module namespace entity = 'quodatum.models.generated';
@ -130,7 +130,7 @@ declare variable $entity:list:=map {
} },
"data": function() as element(image)*
{ collection("/vue-poc/Pictures")/image },
{ collection("/vue-poc/image")/image },
"views": map{
'filter': 'name'

View file

@ -24,6 +24,6 @@
<view name="filter">name</view>
</views>
<iconclass>fa fa-file</iconclass>
<data type="element(image)">collection("/vue-poc/Pictures")/image</data>
<data type="element(image)">collection("/vue-poc/image")/image</data>
</entity>

View file

@ -1,4 +1,4 @@
// generated 2017-08-21T11:24:21.865+01:00
// generated 2017-08-24T18:16:31.442+01:00
Vue.component('qd-link',{template:`
<a :href="href" :target="href"> {{href}}<v-icon>link</v-icon></a>
`,
@ -263,8 +263,8 @@ v0.0.3 </v-card-title> </v-card> </v-flex> <v-flex xs4="">
</v-btn>
<v-toolbar-title>
<v-breadcrumbs>
<v-breadcrumbs-item v-for="item in crumbs" :key="item" :to="{ query: { url: '/' + item + '/' }}">
{{ item }}
<v-breadcrumbs-item v-for="item in crumbs" :key="item.path" :to="{ query: { url: item.path }}">
{{ item.name }}
</v-breadcrumbs-item>
</v-breadcrumbs>
</v-toolbar-title>
@ -400,7 +400,10 @@ v0.0.3 </v-card-title> </v-card> </v-flex> <v-flex xs4="">
return (this.protocol=="basexdb")?"developer_mode":"folder"
},
crumbs(){
return this.url.split("/").filter((a)=>a.length>0)
var parts=this.url.split("/").filter((a)=>a.length>0)
var a=parts.map(function(v,i,a){return {name:v,
path:"/"+a.slice(0,i+1).join("/")+"/"}})
return a
}
},
watch:{
@ -746,17 +749,15 @@ v0.0.3 </v-card-title> </v-card> </v-flex> <v-flex xs4="">
<v-btn @click="imports()">
<v-icon>play_circle_outline</v-icon>
Imports</v-btn>
<v-menu :nudge-width="100">
<v-toolbar-title slot="activator">
<span>{{font}}</span>
<v-icon>arrow_drop_down</v-icon>
</v-toolbar-title>
<v-list>
<v-list-tile v-for="item in dropdown_font" :key="item.text">
<v-list-tile-title v-text="item.text" @click="font=item.text"></v-list-tile-title>
</v-list-tile>
</v-list>
</v-menu>
<v-menu offset-y="">
<v-btn icon="" primary="" dark="" slot="activator"> <v-icon>more_vert</v-icon></v-btn>
<v-list>
<v-list-tile @click="plan">Show query plan</v-list-tile>
</v-list>
<v-list>
<v-list-tile @click="hitme">hit me</v-list-tile>
</v-list>
</v-menu>
</v-toolbar>
@ -769,25 +770,27 @@ v0.0.3 </v-card-title> </v-card> </v-flex> <v-flex xs4="">
{{result}}
</v-alert>
<v-card-actions v-if="show">
JobId:
<v-chip class="green white--text">{{jobId}}</v-chip>
<v-progress-circular v-if="waiting" indeterminate="" class="primary--text"></v-progress-circular>
<v-chip class="primary white--text">{{jobId}}</v-chip>
<v-chip label="" class="grey white--text">
<v-avatar class="red"> <v-icon>lock</v-icon>W</v-avatar>
{{ jobState.writes }}</v-chip>
<v-chip label="" class="grey white--text">
<v-avatar class="amber"> <v-icon>lock</v-icon>R</v-avatar>
{{ jobState.reads }}</v-chip>
<v-spacer></v-spacer>
<v-chip class="green white--text">
<v-progress-circular v-if="waiting" indeterminate="" class="primary--text"></v-progress-circular>
<v-chip>{{ jobState.state }}</v-chip>
<v-chip class="primary white--text">
<v-avatar> <v-icon>timer</v-icon></v-avatar>
{{elapsed}}ms</v-chip>
</v-card-actions>
<v-card-text v-if="show">
<v-card-text v-if="showResult">
<v-flex xs12="" style="height:200px" fill-height="">
<vue-ace :content="result" mode="text" wrap="true" read-only="true"></vue-ace>
<vue-ace :content="result" mode="text" wrap="false" read-only="true"></vue-ace>
</v-flex>
</v-card-text>
</v-card>
@ -801,18 +804,12 @@ v0.0.3 </v-card-title> </v-card> </v-flex> <v-flex xs4="">
result:'',
elapsed: null,
show: false,
showError: false,
showError: false, //unused
showResult: false, //
jobId: null,
waiting: false,
start: null,
jobState: {},
font: 'Courier',
dropdown_font: [
{ text: 'Test select' },
{ text: 'Calibri' },
{ text: 'Courier' },
{ text: 'Verdana' }
]
jobState: {}
}
},
methods:{
@ -823,14 +820,13 @@ v0.0.3 </v-card-title> </v-card> </v-flex> <v-flex xs4="">
},
run(){
this.showError=this.show=false
this.awaitResult(false)
this.start = performance.now();
HTTP.post("eval/execute",Qs.stringify({xq:this.xq}))
.then(r=>{
this.elapsed=Math.floor(performance.now() - this.start);
this.result=r.data.result
this.jobId=null
this.show=true
})
.catch(r=> {
console.log("error",r)
@ -842,12 +838,12 @@ v0.0.3 </v-card-title> </v-card> </v-flex> <v-flex xs4="">
},
submit(){
var data={xq:this.xq}
this.showError=this.show=false
this.showResult=this.show=false
this.start = performance.now();
HTTP.post("eval/submit",Qs.stringify(data))
.then(r=>{
this.elapsed=Math.floor(performance.now() - this.start);
this.result=this.jobId=r.data.job
this.jobId=r.data.job
this.show=true
this.pollState()
@ -874,15 +870,38 @@ v0.0.3 </v-card-title> </v-card> </v-flex> <v-flex xs4="">
})
},
getResult(){
this.awaitResult(true)
HTTP.post("eval/result/"+this.jobId)
.then(r=>{
this.result=r.data.result
this.jobId=null
this.show=true
})
},
hitme(){
this.showResult=true
setTimeout(()=>{this.result="123\n".repeat(20000); },10);
},
imports(){
alert("@TODO imports")
},
plan(){
this.awaitResult(false)
HTTP.post("eval/plan",Qs.stringify({xq:this.xq}))
.then(r=>{
this.result=r.data.result
})
.catch(r=> {
console.log("error",r)
this.result=r.response.data
this.showError=true;
});
},
awaitResult(show){
// ace slow when setting large text while hidden
this.show=show
this.result="(Please wait..)"
this.showResult=true
}
},
@ -961,6 +980,7 @@ v0.0.3 </v-card-title> </v-card> </v-flex> <v-flex xs4="">
<v-layout>
<v-flex xs5="">
<pre style="overflow:auto;">{{ image.doc }}</pre>
<a :href="meta" target="_new">full metadata</a>
</v-flex>
<v-flex xs7="">
@ -980,7 +1000,10 @@ v0.0.3 </v-card-title> </v-card> </v-flex> <v-flex xs4="">
computed: {
path(){
return this.loaded?'/vue-poc/api/images/list/'+ this.id+ '/image':null
}
},
meta(){
return this.loaded?'/vue-poc/api/images/list/'+ this.id+ '/meta':null
}
},
created:function(){
var id=this._props.id
@ -1003,9 +1026,10 @@ v0.0.3 </v-card-title> </v-card> </v-flex> <v-flex xs4="">
<v-btn @click="clear" icon="" v-tooltip:top="{ html: 'Clear search' }" v-if="query.keyword || query.from || query.until">
<v-icon>clear</v-icon>
</v-btn>
<v-chip class="primary white--text">{{ total }}</v-chip>
<v-spacer></v-spacer>
<span v-if="!busy">
<v-chip class="primary white--text">{{ total }} in {{ elapsed | round(2) }} secs </v-chip>
Page:{{ query.page+1 }}
<v-btn @click.stop="query.page=Math.min(0,query.page-1)" :disabled="query.page==0" icon="" primary="">
@ -1014,6 +1038,7 @@ v0.0.3 </v-card-title> </v-card> </v-flex> <v-flex xs4="">
<v-btn @click.stop="query.page+=1" icon="" primary="">
<v-icon>arrow_forward</v-icon>
</v-btn>
</span>
</v-toolbar>
<v-progress-linear v-if="busy" v-bind:indeterminate="true"></v-progress-linear>
<v-container v-if="!busy" fluid="" grid-list-md="">
@ -1111,6 +1136,7 @@ v0.0.3 </v-card-title> </v-card> </v-flex> <v-flex xs4="">
keyword:null
},
total:null,
elapsed:null,
showFilter:false,
busy:false,
menu2:false,
@ -1132,7 +1158,7 @@ v0.0.3 </v-card-title> </v-card> </v-flex> <v-flex xs4="">
this.total=r.data.total
this.images=r.data.items
var t1 = performance.now();
console.log("Time: ",t1 - t0)
this.elapsed= 0.001 *(t1 - t0)
})
},
clear(){
@ -1300,15 +1326,15 @@ body
const Jobs=Vue.extend({template:`
<v-card>
<v-toolbar light="">
<v-btn light="" icon="" :loading="loading" @click="getJobs()" :disabled="loading">
<v-icon>refresh</v-icon>
</v-btn>
<v-btn @click="stop()" :disabled="noSelection">Stop</v-btn>
<v-text-field append-icon="search" label="Filter jobs" single-line="" hide-details="" v-model="search"></v-text-field>
<v-spacer></v-spacer>
<v-text-field append-icon="search" label="Filter jobs" single-line="" hide-details="" v-model="search"></v-text-field>
<v-btn light="" icon="" :loading="loading" @click="getJobs()" @dblclick="autorefresh = !autorefresh" :disabled="loading">
<v-icon>{{ autorefresh?'refresh':'arrow_downward' }}</v-icon>
</v-btn>
</v-toolbar>
<v-data-table :headers="headers" :items="items" :search="search" v-model="selected" select-all="" class="elevation-1" no-data-text="No Jobs currently running">
<template slot="items" scope="props">
@ -1316,13 +1342,13 @@ body
<v-checkbox primary="" hide-details="" v-model="props.selected"></v-checkbox>
</td>
<td class="vtop"> <router-link :to="{name: 'jobShow', params: {job: props.item.id }}">{{props.item.id}}</router-link></td>
<td class="vtop text-xs-right">{{ props.item.state }}</td>
<td class="vtop "><div>{{ props.item.state }}</div>
<div>{{ props.item.type }}</div> </td>
<td class="vtop text-xs-right">{{ props.item.duration }}</td>
<td class="vtop text-xs-right">{{ props.item.type }}</td>
<td class="vtop text-xs-right">{{ props.item.writes }}</td>
<td class="vtop text-xs-right">{{ props.item.reads }}</td>
<td class="vtop text-xs-right">{{ props.item.user }}</td>
<td class="vtop"><code>{{ props.item.text }}</code></td>
<td class="vtop"><code class="multiline-ellipsis">{{ props.item.text }}</code></td>
</template>
</v-data-table>
</v-card>
@ -1338,7 +1364,6 @@ body
},
{ text: 'State', value: 'state' },
{ text: 'Duration', value: 'duration' },
{ text: 'Type', value: 'type' },
{ text: 'WriteL', value: 'writes' },
{ text: 'ReadL', value: 'reads' },
{ text: 'User', value: 'user' },
@ -1346,9 +1371,10 @@ body
],
items:[
],
selected:[],
search:"",
loading:false
selected: [],
search: "",
loading: false,
autorefresh: true
}
},
methods:{
@ -1358,7 +1384,7 @@ body
.then(r=>{
this.loading=false
this.items=r.data
setTimeout(()=>{ this.getJobs() }, 10000);
if(this.autorefresh) setTimeout(()=>{ this.getJobs() }, 10000);
})
},
@ -1373,7 +1399,7 @@ body
noSelection: function () {
// `this` points to the vm instance
return this.selected.length==0
}
},
},
created(){
this.getJobs()
@ -2362,6 +2388,22 @@ Vue.config.errorHandler = function (err, vm, info) {
alert("vue error");
};
//Returns a function, that, as long as it continues to be invoked, will not
//be triggered. The function will be called after it stops being called for
//N milliseconds. If `immediate` is passed, trigger the function on the
//leading edge, instead of the trailing. https://gist.github.com/nmsdvid/8807205
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
clearTimeout(timeout);
timeout = setTimeout(function() {
timeout = null;
if (!immediate) func.apply(context, args);
}, wait);
if (immediate && !timeout) func.apply(context, args);
};
};
// used by vue-ace
var Events = new Vue({});

View file

@ -54,4 +54,14 @@ td.vtop {
height: 100%;
}
.multiline-ellipsis {
display: block;
display: -webkit-box;
max-height: 110px;
margin: 0 auto;
line-height: 1.4;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
}

View file

@ -6,7 +6,7 @@
declare namespace task="https://github.com/Quodatum/app-doc/task";
import module namespace bf = 'quodatum.tools.buildfields' at "../lib/entity-gen.xqm";
let $efolder:="file:///C:/Users/andy/workspace/app-doc/src/doc/data/doc/models"
let $target:="file:///C:/Users/andy/workspace/app-doc/src/doc/generated/models.xqm"
return (bf:write($efolder,$target),db:output("generated C:/Users/andy/workspace/app-doc/src/doc/generated/models.xqm"))
let $efolder:="C:/Users/andy/git/vue-poc/src/vue-poc/models"
let $target:="C:/Users/andy/git/vue-poc/src/vue-poc/models.gen.xqm"
return (bf:write($efolder,$target),db:output("generated " || $target))

View file

@ -1,30 +0,0 @@
(:~
: create vue files from app.html
:)
import module namespace html5="text.html5" at "html5parse.xqm";
declare namespace Document="java:ch.digitalfondue.jfiveparse.Document";
declare namespace Element="java:ch.digitalfondue.jfiveparse.Element";
declare namespace Node="java:ch.digitalfondue.jfiveparse.Node";
declare variable $DEST:="C:/Users/andy/git/vue-poc/src/vue-poc/templates/";
declare variable $SRC:="C:/Users/andy/git/vue-poc/src/vue-poc/static/app.html";
declare function local:process($node)
{
let $id:= Element:getAttribute($node,"id")
let $html:=Node:getInnerHTML($node)
let $name:=$DEST || $id || ".vue"
let $out:=``[<!DOCTYPE html>
<template id="`{$id}`">`{$html}`</template>
<script>
</script>
]``
return file:write-text($name,$out)
};
let $doc:=$SRC=>fetch:text()=>html5:doc()
let $matcher:=html5:selector()
let $nodes:= Document:getAllNodesMatching($doc,$matcher)
return $nodes=>html5:for-each(local:process#1)