vuetify 0.14.2
This commit is contained in:
parent
efc929ca69
commit
e5f691bf6c
24 changed files with 1078 additions and 197 deletions
|
|
@ -54,6 +54,7 @@ const router = new VueRouter({
|
|||
{ path: '/eval', component: Eval,meta:{title:"Evaluate XQuery"} },
|
||||
{ path: '/logs', component: Log,meta:{title:"Server logs"} },
|
||||
{ path: '/tasks', component: Task,meta:{title:"Runnable tasks"} },
|
||||
{ path: '/tasks/model', component: Model,meta:{title:"build model"} },
|
||||
{ path: '/jobs', component: Job,meta:{title:"Jobs"} },
|
||||
{ path: '*', component: Notfound,meta:{title:"Page not found"} }
|
||||
],
|
||||
|
|
@ -94,42 +95,42 @@ const app = new Vue({
|
|||
text: 'Collections' ,
|
||||
model: false,
|
||||
children: [
|
||||
{href: 'database', text: 'Databases',icon: 'account_balance' },
|
||||
{href: 'files', text: 'File system',icon: 'folder' },
|
||||
{href: 'edit',text: 'edit',icon: 'mode_edit'},
|
||||
{href: 'history',text: 'history',icon: 'history'},
|
||||
{href: 'logs',text: 'Server logs',icon: 'dns'}
|
||||
{href: '/database', text: 'Databases',icon: 'account_balance' },
|
||||
{href: '/files', text: 'File system',icon: 'folder' },
|
||||
{href: '/edit',text: 'edit',icon: 'mode_edit'},
|
||||
{href: '/history',text: 'history',icon: 'history'},
|
||||
{href: '/logs',text: 'Server logs',icon: 'dns'}
|
||||
]},
|
||||
{
|
||||
icon: 'directions_run',
|
||||
text: 'Actions' ,
|
||||
model: false,
|
||||
children: [
|
||||
{href: 'eval',text: 'Query',icon: 'play_circle_outline'},
|
||||
{href: 'jobs',text: 'Running jobs',icon: 'dashboard'},
|
||||
{href: 'tasks',text: 'Tasks',icon: 'history'},
|
||||
{href: '/eval',text: 'Query',icon: 'play_circle_outline'},
|
||||
{href: '/jobs',text: 'Running jobs',icon: 'dashboard'},
|
||||
{href: '/tasks',text: 'Tasks',icon: 'history'}
|
||||
]},
|
||||
{
|
||||
icon: 'more_horiz',
|
||||
text: 'More' ,
|
||||
model: false,
|
||||
children: [
|
||||
{href: 'people',text: 'People',icon: 'person'},
|
||||
{href: 'select',text: 'select',icon: 'extension'},
|
||||
{href: 'puzzle',text: 'Puzzle',icon: 'extension'},
|
||||
{href: 'images',text: 'Images',icon: 'camera_roll'},
|
||||
{href: 'tabs',text: 'tabs',icon: 'switch_camera'},
|
||||
{href: 'ping',text: 'ping',icon: 'update'},
|
||||
{href: 'thumbnail',text: 'thumbnail',icon: 'touch_app'}
|
||||
{href: '/people',text: 'People',icon: 'person'},
|
||||
{href: '/select',text: 'select',icon: 'extension'},
|
||||
{href: '/puzzle',text: 'Puzzle',icon: 'extension'},
|
||||
{href: '/images',text: 'Images',icon: 'camera_roll'},
|
||||
{href: '/tabs',text: 'tabs',icon: 'switch_camera'},
|
||||
{href: '/ping',text: 'ping',icon: 'update'},
|
||||
{href: '/thumbnail',text: 'thumbnail',icon: 'touch_app'}
|
||||
]},
|
||||
{href: 'settings',text: 'settings',icon: 'settings' }
|
||||
{href: '/settings',text: 'settings',icon: 'settings' }
|
||||
]
|
||||
|
||||
}},
|
||||
methods: {
|
||||
|
||||
search(){
|
||||
this.$router.push({path: 'search',query: { q: this.q }})
|
||||
this.$router.push({path: '/search',query: { q: this.q }})
|
||||
},
|
||||
logout(){
|
||||
HTTP.get("logout").then(r=>{
|
||||
|
|
|
|||
|
|
@ -30,9 +30,7 @@
|
|||
<v-list-tile-action>
|
||||
<v-icon>{{ item.model ? 'keyboard_arrow_up' : 'keyboard_arrow_down' }}</v-icon>
|
||||
</v-list-tile-action>
|
||||
<v-list-tile-content>
|
||||
|
||||
</v-list-tile-content>
|
||||
</v-list-tile>
|
||||
<template v-for="(child, i) in item.children" >
|
||||
<v-list-tile :to="child.href" :key="i" ripple>
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
abbrev="vue-poc" version="0.0.3" spec="1.0">
|
||||
<title>vue-poc test of vue.js.</title>
|
||||
<dependency name="ace" version="1.2.7" />
|
||||
<dependency name="vuetify" version="0.13.0" />
|
||||
<dependency name="vue" version="2.3.4" />
|
||||
<dependency name="vuetify" version="0.14.2" />
|
||||
<dependency name="vue" version="2.4.1" />
|
||||
<dependency name="vue-router" version="2.5.3" />
|
||||
<dependency name="google-material" version="0.0.0" />
|
||||
<dependency name="js-beautify" version="1.6.12" />
|
||||
|
|
|
|||
|
|
@ -5,45 +5,9 @@
|
|||
:)
|
||||
module namespace vue-api = 'quodatum:vue.api.collection';
|
||||
import module namespace rest = "http://exquery.org/ns/restxq";
|
||||
import module namespace fw="quodatum:file.walker";
|
||||
import module namespace ufile = 'vue-poc/file' at "../../lib/file.xqm";
|
||||
declare namespace c="http://www.w3.org/ns/xproc-step";
|
||||
|
||||
(:~ defines accessor functions for each collection type
|
||||
:)
|
||||
declare variable $vue-api:MODE:=map{
|
||||
"webfile":
|
||||
function($url)
|
||||
as element(c:directory)
|
||||
{
|
||||
let $path := ufile:web( $url)=>trace("vue-api:web ")
|
||||
return if( file:exists($path))then
|
||||
fw:directory-list($path,map{"max-depth":1,"include-info":true()})
|
||||
else
|
||||
error(xs:QName('vue-api:badpath'),$path)
|
||||
},
|
||||
"basexdb":
|
||||
function($url)
|
||||
as element(c:directory)
|
||||
{
|
||||
<c:directory name="" xml:base="basexdb:/" last-modified="2017-07-01T13:39:38.98691Z" size="4096">{
|
||||
if($url="/") then
|
||||
db:list()!
|
||||
<c:directory name="{db:property(.,'name')}"
|
||||
last-modified="{db:property(.,'timestamp')}"
|
||||
size="{db:property(.,'size')}"/>
|
||||
|
||||
else
|
||||
let $map:=vue-api:collection-next($url)
|
||||
for $name in map:keys($map)
|
||||
(: db:list-details($db as xs:string, $path as xs:string) as element(resource)* :)
|
||||
return if($map($name)="file") then
|
||||
<c:file name="{$name}" size="0"/>
|
||||
else
|
||||
<c:directory name="{$name}" size="0"/>
|
||||
}</c:directory>
|
||||
}
|
||||
};
|
||||
|
||||
(:~
|
||||
: history list
|
||||
|
|
@ -59,7 +23,7 @@ function vue-api:history( )
|
|||
<items type="array">
|
||||
{$h!(<_ type="object">
|
||||
<url>{@url/string()}</url>
|
||||
<mode>{@mode/string()}</mode>
|
||||
<protocol>{@mode/string()}</protocol>
|
||||
</_>)}
|
||||
</items>
|
||||
</json>
|
||||
|
|
@ -70,18 +34,28 @@ function vue-api:history( )
|
|||
: Returns folder info.
|
||||
:)
|
||||
declare
|
||||
%rest:path("/vue-poc/api/file")
|
||||
%rest:path("/vue-poc/api/collection")
|
||||
%rest:query-param("url", "{$url}")
|
||||
%rest:query-param("protocol", "{$protocol}")
|
||||
%rest:query-param("protocol", "{$protocol}","webfile")
|
||||
%rest:produces("application/json")
|
||||
%output:method("json")
|
||||
function vue-api:file($url as xs:string,$protocol as xs:string?)
|
||||
function vue-api:file($url as xs:string,$protocol as xs:string)
|
||||
as element(json)
|
||||
{
|
||||
let $mode:=if(map:contains($vue-api:MODE,string($protocol)))then $protocol else "webfile"
|
||||
let $reader:=$vue-api:MODE($mode)
|
||||
let $items:=$reader($url)
|
||||
return <json type="object" >
|
||||
let $reader:=map{
|
||||
"webfile":ufile:webfile#1,
|
||||
"basexdb":ufile:basexdb#1
|
||||
}
|
||||
let $items:=$reader($protocol)($url)
|
||||
return vue-api:items($items)
|
||||
};
|
||||
|
||||
|
||||
|
||||
declare function vue-api:items($items)
|
||||
as element(json)
|
||||
{
|
||||
<json type="object" >
|
||||
<folders type="array">
|
||||
{for $f in $items/c:directory
|
||||
order by $f/@name/lower-case(.)
|
||||
|
|
@ -112,23 +86,3 @@ as element(*)*
|
|||
};
|
||||
|
||||
|
||||
(:~ return map of next level database contents
|
||||
:@param $url a database base collection e.g /dbname/fred/
|
||||
:)
|
||||
declare function vue-api:collection-next($url as xs:string)
|
||||
as map(*)
|
||||
{
|
||||
if(not(starts-with($url,"/")) or ends-with($url,"/")) then
|
||||
error(xs:QName('vue-api:badpath'),$url)
|
||||
else
|
||||
fold-left(
|
||||
uri-collection($url ),
|
||||
map{},
|
||||
function($acc,$this){
|
||||
let $s:=substring-after($this ,$url || "/")
|
||||
let $isDir:=contains($s,"/")
|
||||
let $s:=if($isDir)then substring-before($s,"/") else $s
|
||||
return map:merge((map:entry($s,if($isDir)then "directory" else "file"),$acc))
|
||||
}
|
||||
)
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
<v-container fluid>
|
||||
|
||||
<v-card>
|
||||
<v-toolbar>
|
||||
<v-toolbar light>
|
||||
<v-menu bottom right>
|
||||
<v-btn icon slot="activator"><v-icon >{{icon}}</v-icon></v-btn>
|
||||
<v-list>
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
<v-spacer></v-spacer>
|
||||
<v-text-field prepend-icon="search" label="Filter..." v-model="q" type="search"
|
||||
hide-details single-line dark @keyup.native.enter="filter"></v-text-field>
|
||||
hide-details single-line @keyup.native.enter="filter"></v-text-field>
|
||||
<v-icon>view_module</v-icon>
|
||||
</v-toolbar>
|
||||
|
||||
|
|
@ -96,7 +96,7 @@
|
|||
},
|
||||
load(url){
|
||||
this.busy=true
|
||||
HTTP.get("file",{params:{url:url,protocol:this.protocol}})
|
||||
HTTP.get("collection",{params:{url:url,protocol:this.protocol}})
|
||||
.then(r=>{
|
||||
this.folders=r.data.folders
|
||||
this.files=r.data.files
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
<v-list>
|
||||
<v-list-tile v-for="item in items" v-bind:key="item.title" @click="doEdit(item)" avatar>
|
||||
<v-list-tile-action>
|
||||
<v-chip v-text="item.mode">Example Chip</v-chip>
|
||||
<v-chip v-text="item.protocol">Example Chip</v-chip>
|
||||
</v-list-tile-action>
|
||||
<v-list-tile-content>
|
||||
<v-list-tile-title @click="doEdit(item)" v-text="item.url"></v-list-tile-title>
|
||||
|
|
@ -31,7 +31,7 @@
|
|||
},
|
||||
doEdit(item){
|
||||
console.log("history: ",item)
|
||||
router.push({ path: 'edit', query: { url:item.url, mode:item.mode }})
|
||||
router.push({ path: 'edit', query: { url:item.url, protocol:item.protocol }})
|
||||
}
|
||||
},
|
||||
created:function(){
|
||||
|
|
|
|||
|
|
@ -9,5 +9,5 @@
|
|||
<entry mode="webfile" url='/vue-poc/static/resources/turtle.ttl' />
|
||||
<entry mode="webfile" url='/vue-poc/static/resources/task.xsd' />
|
||||
<entry mode="basexdb" url='/abide/abide.xml' />
|
||||
|
||||
<entry mode="basexdb" url='/vue-poc' />
|
||||
</history>
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
<v-toolbar class="grey lighten-2 black--text">
|
||||
<v-menu >
|
||||
<v-btn primary icon dark slot="activator" v-tooltip:top="{ html: path.join('/') }"><v-icon >folder</v-icon></v-btn>
|
||||
<v-btn primary icon dark slot="activator" v-tooltip:top="{ html: path.join('/') }"><v-icon >{{icon}}</v-icon></v-btn>
|
||||
<v-list>
|
||||
<v-list-tile v-for="item in path" :key="item">
|
||||
<v-list-tile-content @click="showfiles()">
|
||||
|
|
@ -70,14 +70,14 @@
|
|||
<v-list-tile-avatar>
|
||||
<v-icon >settings</v-icon>
|
||||
</v-list-tile-avatar>
|
||||
<v-list-tile-title >Show settings</v-list-tile-title>
|
||||
<v-list-tile-title @click="acecmd('showSettingsMenu')" >Show settings</v-list-tile-title>
|
||||
</v-list-tile>
|
||||
|
||||
<v-list-tile @click="acecmd('showKeyboardShortcuts')" avatar>
|
||||
<v-list-tile-avatar>
|
||||
<v-icon >keyboard</v-icon>
|
||||
</v-list-tile-avatar>
|
||||
<v-list-tile-title >Show keyboard commands</v-list-tile-title>
|
||||
<v-list-tile-title @click="acecmd('showKeyboardShortcuts')" >Show keyboard commands</v-list-tile-title>
|
||||
</v-list-tile>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
|
|
@ -212,7 +212,8 @@ v-on:annotation="annotation"></vue-ace>
|
|||
})
|
||||
},
|
||||
showfiles(){
|
||||
router.push({ path: 'files', query: { url: this.path.join("/") }})
|
||||
var target=this.protocol="basexdb"?"database":"files";
|
||||
router.push({ path: target, query: { url: this.path.join("/"),protocol:this.protocol }})
|
||||
},
|
||||
beautify(){
|
||||
this.busy=true
|
||||
|
|
@ -251,6 +252,11 @@ v-on:annotation="annotation"></vue-ace>
|
|||
if(this.dirty)event.preventDefault();
|
||||
}
|
||||
},
|
||||
computed:{
|
||||
icon(){
|
||||
return (this.protocol=="basexdb")?"account_balance":"folder"
|
||||
}
|
||||
},
|
||||
created(){
|
||||
//https://forum.vuejs.org/t/detect-browser-close/5001/3 @fixme
|
||||
document.addEventListener('beforeunload', this.leaving);
|
||||
|
|
|
|||
|
|
@ -18,22 +18,16 @@ declare namespace c="http://www.w3.org/ns/xproc-step";
|
|||
declare
|
||||
%rest:GET %rest:path("/vue-poc/api/edit")
|
||||
%rest:query-param("url", "{$url}")
|
||||
%rest:query-param("protocol", "{$protocol}")
|
||||
%rest:query-param("protocol", "{$protocol}","webfile")
|
||||
%rest:produces("application/json")
|
||||
%output:method("json")
|
||||
function vue-api:edit-get($url as xs:string,$protocol as xs:string)
|
||||
{
|
||||
let $path := ufile:web( $url)=>trace("path ")
|
||||
return if( file:exists($path))then
|
||||
let $type:=mt:type($path)
|
||||
let $fetch:=mt:fetch-fn($type("treat-as"))
|
||||
return <json type="object" >
|
||||
<url>{$url}</url>
|
||||
<mimetype>{$type?type}</mimetype>
|
||||
<data>{$fetch($path)}</data>
|
||||
</json>
|
||||
else
|
||||
error(xs:QName('vue-api:raw'),$path)
|
||||
let $reader := map{
|
||||
"webfile":vue-api:get-webfile#1,
|
||||
"basexdb":vue-api:get-basexdb#1
|
||||
}
|
||||
return $reader($protocol)($url)
|
||||
};
|
||||
|
||||
(:~
|
||||
|
|
@ -61,3 +55,39 @@ function vue-api:edit-post($url as xs:string,$data)
|
|||
error(xs:QName('vue-api:raw'),$path)
|
||||
};
|
||||
|
||||
(:~
|
||||
: Returns a file content.
|
||||
:)
|
||||
declare function vue-api:get-webfile($url as xs:string)
|
||||
as element(json)
|
||||
{
|
||||
let $path := ufile:web( $url)=>trace("path ")
|
||||
return if( file:exists($path))then
|
||||
let $type:=mt:type($path)
|
||||
let $fetch:=mt:fetch-fn($type("treat-as"))
|
||||
return <json type="object" >
|
||||
<url>{$url}</url>
|
||||
<mimetype>{$type?type}</mimetype>
|
||||
<data>{$fetch($path)}</data>
|
||||
</json>
|
||||
else
|
||||
error(xs:QName('vue-api:raw'),$url)
|
||||
};
|
||||
|
||||
(:~
|
||||
: Returns a file content.
|
||||
:)
|
||||
declare function vue-api:get-basexdb($url as xs:string)
|
||||
as element(json)
|
||||
{
|
||||
if( doc-available($url))then
|
||||
|
||||
let $doc:=doc($url)
|
||||
return <json type="object" >
|
||||
<url>{$url}</url>
|
||||
<mimetype>application/xml</mimetype>
|
||||
<data>{serialize($doc)}</data>
|
||||
</json>
|
||||
else
|
||||
error(xs:QName('vue-api:raw'),$url)
|
||||
};
|
||||
|
|
@ -1,13 +1,46 @@
|
|||
<!DOCTYPE html>
|
||||
<!--
|
||||
image list ui
|
||||
|
||||
-->
|
||||
<template id="images">
|
||||
|
||||
<v-card>
|
||||
<v-card-actions>
|
||||
<v-btn @click.native="page+=1">next</v-btn>
|
||||
{{page}}
|
||||
<v-btn @click.native="page-=1">back</v-btn>
|
||||
|
||||
<v-spacer></v-spacer>
|
||||
<v-select
|
||||
v-bind:items="keywords"
|
||||
v-model="query.keyword"
|
||||
label="Keyword"
|
||||
autocomplete
|
||||
></v-select>
|
||||
<v-dialog
|
||||
persistent
|
||||
v-model="modal"
|
||||
lazy
|
||||
full-width
|
||||
>
|
||||
<v-text-field
|
||||
slot="activator"
|
||||
label="Earliest date"
|
||||
v-model="query.from"
|
||||
prepend-icon="event"
|
||||
readonly
|
||||
></v-text-field>
|
||||
<v-date-picker v-model="query.from" scrollable actions>
|
||||
<template scope="{ save, cancel }">
|
||||
<v-card-actions>
|
||||
<v-btn flat primary @click.native="cancel()">Cancel</v-btn>
|
||||
<v-btn flat primary @click.native="save()">Save</v-btn>
|
||||
</v-card-actions>
|
||||
</template>
|
||||
</v-date-picker>
|
||||
</v-dialog>
|
||||
<v-btn @click.native="clear()">Clear</v-btn>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn @click.native="query.page+=1">next</v-btn>
|
||||
{{query.page}}
|
||||
<v-btn @click.native="query.page-=1">back</v-btn>
|
||||
</v-card-actions>
|
||||
<v-container fluid grid-list-md>
|
||||
<v-layout row wrap>
|
||||
|
|
@ -16,9 +49,9 @@
|
|||
v-for="image in images"
|
||||
:key="image.name"
|
||||
>
|
||||
<v-card @click="selected()" class="grey lighten-2 pt-1">
|
||||
<v-card @click="selected(image)" class="grey lighten-2 pt-1">
|
||||
<v-card-media :src="src(image)" height="80px" :contain="true"></v-card-media>
|
||||
<v-card-actions v-tooltip:top="{ html: image.name }">
|
||||
<v-card-actions v-tooltip:top="{ html: image.id + ' '+image.name }">
|
||||
|
||||
<v-btn icon small>
|
||||
<v-icon>favorite</v-icon>
|
||||
|
|
@ -35,6 +68,16 @@
|
|||
</v-flex>
|
||||
</v-layout>
|
||||
</v-container>
|
||||
<v-navigation-drawer left light temporary v-model="showInfo">
|
||||
<v-card>
|
||||
<v-toolbar class="green white--text">
|
||||
<v-toolbar-title >{{selitem.name}}</v-toolbar-title>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn flat icon @click.native="showInfo = false"><v-icon>highlight_off</v-icon></v-btn>
|
||||
</v-toolbar>
|
||||
<v-card-text> blah blah </v-card-text>
|
||||
</v-card>
|
||||
</v-navigation-drawer>
|
||||
</v-card>
|
||||
|
||||
</template>
|
||||
|
|
@ -42,35 +85,56 @@
|
|||
<script>{
|
||||
data: () => ({
|
||||
images:[],
|
||||
page:0
|
||||
query:{page:0, // current page
|
||||
from:null,
|
||||
keyword:null
|
||||
},
|
||||
modal:false, // showing datepicker
|
||||
|
||||
keywords:[],
|
||||
showInfo:false,
|
||||
selitem:"TODO"
|
||||
}),
|
||||
methods:{
|
||||
src(item){
|
||||
//return "https://unsplash.it/150/300?image="+Math.floor(Math.random() * 100) + 1
|
||||
return "data:image/jpeg;base64,"+item.data
|
||||
},
|
||||
getImages(){
|
||||
HTTP.get("images/list?page="+this.page)
|
||||
HTTP.get("images/list",{params:this.query})
|
||||
.then(r=>{
|
||||
this.images=r.data.items
|
||||
})
|
||||
|
||||
},
|
||||
selected(){
|
||||
alert("not yet")
|
||||
clear(){
|
||||
this.query.from=null;
|
||||
this.query.keyword=null;
|
||||
},
|
||||
selected(image){
|
||||
this.selitem=image;
|
||||
this.showInfo=true;
|
||||
}
|
||||
|
||||
},
|
||||
watch:{
|
||||
page(v){
|
||||
this.$router.push({ query: { page: this.page }})
|
||||
"query":{
|
||||
handler:function(v){
|
||||
this.$router.push({ query: this.query })
|
||||
},
|
||||
deep:true
|
||||
},
|
||||
$route(v){
|
||||
this.getImages()
|
||||
}
|
||||
},
|
||||
created:function(){
|
||||
this.page=this.$route.query.page || this.page
|
||||
this.query.page=Number(this.$route.query.page) || this.query.page
|
||||
this.query.keyword=this.$route.query.keyword || this.query.keyword
|
||||
this.query.from=this.$route.query.from || this.query.from
|
||||
this.getImages()
|
||||
HTTP.get("images/keywords")
|
||||
.then(r=>{
|
||||
this.keywords=r.data.items
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -4,9 +4,8 @@
|
|||
: @author Andy Bunce may-2017
|
||||
:)
|
||||
module namespace vue-api = 'quodatum:vue.api.images';
|
||||
import module namespace thb="expkg-zone58:image.thumbnailator";
|
||||
import module namespace rest = "http://exquery.org/ns/restxq";
|
||||
import module namespace fw="quodatum:file.walker";
|
||||
import module namespace entity = 'quodatum.models.generated' at "../../models.gen.xqm";
|
||||
declare namespace c="http://www.w3.org/ns/xproc-step";
|
||||
|
||||
declare variable $vue-api:PICS:="c:\tmp\";
|
||||
|
|
@ -18,33 +17,64 @@ declare
|
|||
%rest:GET %rest:path("/vue-poc/api/images/list")
|
||||
%rest:produces("application/json")
|
||||
%rest:query-param("page", "{$page}",0)
|
||||
%rest:query-param("from", "{$from}")
|
||||
%rest:query-param("keyword", "{$keyword}")
|
||||
%output:method("json")
|
||||
function vue-api:list( $page as xs:integer)
|
||||
function vue-api:list( $page as xs:integer,
|
||||
$from,
|
||||
$keyword
|
||||
)
|
||||
{
|
||||
let $a:=trace(($from,$keyword),"----------")
|
||||
let $rowsPerPage:=24
|
||||
let $opt:=map{"include-filter":".*\.jpg",
|
||||
"max-depth":-1,
|
||||
"include-info":true()}
|
||||
let $d:= fw:directory-list($vue-api:PICS,$opt)
|
||||
let $f:=$d//c:file/@name/resolve-uri(encode-for-uri(.),base-uri(.))
|
||||
let $images:=subsequence($f,1+$rowsPerPage*$page,$rowsPerPage)
|
||||
let $entity:=$entity:list("thumbnail")
|
||||
let $images:=$entity("data")()
|
||||
let $images:=if($from)then $images[datetaken ge $from] else $images
|
||||
let $images:=if($keyword)then $images[keywords/keyword = $keyword] else $images
|
||||
let $images:=subsequence($images,1+$rowsPerPage*$page,$rowsPerPage)
|
||||
|
||||
return <json type="object" >
|
||||
<items type="array">{
|
||||
for $f in $images
|
||||
return <_ type="object">
|
||||
{vue-api:get-image($f)}
|
||||
{vue-api:get-image($f,$entity)}
|
||||
</_>
|
||||
}</items>
|
||||
</json>
|
||||
};
|
||||
|
||||
(:~
|
||||
: keywords
|
||||
:)
|
||||
declare
|
||||
%rest:GET %rest:path("/vue-poc/api/images/keywords")
|
||||
%rest:produces("application/json")
|
||||
%output:method("json")
|
||||
function vue-api:keywords()
|
||||
{
|
||||
let $keys:=
|
||||
collection("/vue-poc/Pictures")/image/keywords/keyword
|
||||
=>distinct-values()
|
||||
=>sort("http://www.w3.org/2005/xpath-functions/collation/html-ascii-case-insensitive")
|
||||
return <json type="object" >
|
||||
<items type="array">{
|
||||
$keys!<_ >{.}</_>
|
||||
}</items>
|
||||
</json>
|
||||
};
|
||||
|
||||
declare function vue-api:get-image($f as xs:string)
|
||||
declare function vue-api:get-image($image as element(image),$entity)
|
||||
as element(*)*
|
||||
{
|
||||
<name>{$f}</name>
|
||||
,<data>{fetch:binary($f)}</data>
|
||||
,<mime>{fetch:content-type($f)}</mime>
|
||||
let $id:=$entity?access?id($image)
|
||||
let $path:=$entity?access?path($image)
|
||||
let $name:=$entity?access?name($image)
|
||||
let $thumb:= $vue-api:PICS || $path
|
||||
let $thumb:=if(file:exists($thumb)) then $thumb else "C:\tmp\art.jpg"
|
||||
return ( <id>{$id}</id>
|
||||
,<name>{$name}</name>
|
||||
,<data>{fetch:binary($thumb)}</data>
|
||||
,<mime>{fetch:content-type($thumb)}</mime>)
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
215
src/vue-poc/features/model.build/entity-gen.xqm
Normal file
215
src/vue-poc/features/model.build/entity-gen.xqm
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
(:~
|
||||
: generate xquery access code for entity definitions
|
||||
:)
|
||||
module namespace bf = 'quodatum.tools.buildfields';
|
||||
declare default function namespace 'quodatum.tools.buildfields';
|
||||
declare namespace ent="https://github.com/Quodatum/app-doc/entity";
|
||||
|
||||
(:~
|
||||
: write generated xquery module from entity xml
|
||||
: @param efolder full path to folder with entities e.g. fn:resolve-uri("./data/models")
|
||||
: @param dest full name of xqm to create e.g. fn:resolve-uri("models.xqm")
|
||||
:)
|
||||
declare %updating function write($efolder as xs:string,$dest as xs:string)
|
||||
{
|
||||
let $src:=bf:module(bf:sources($efolder))
|
||||
return file:write-text($dest,$src)
|
||||
};
|
||||
|
||||
(:~
|
||||
: generate xquery module for given entities as a string
|
||||
:)
|
||||
declare function module($entities as element(ent:entity)*) as xs:string
|
||||
{
|
||||
let $src:= <text>(: entity access maps
|
||||
: auto generated from xml files in entities folder at: {fn:current-dateTime()}
|
||||
:)
|
||||
|
||||
module namespace entity = 'quodatum.models.generated';
|
||||
{bf:build-modules($entities)}
|
||||
{bf:build-namespaces($entities)}
|
||||
{( bf:build-describe($entities))}
|
||||
|
||||
(:~ map of access functions for entity :)
|
||||
declare function entity:fields($entity as xs:string)
|
||||
as map(*){{
|
||||
$entity:list($entity)("access")
|
||||
}};
|
||||
</text>
|
||||
|
||||
return $src
|
||||
};
|
||||
|
||||
(:~
|
||||
: generate xquery for to return field value in the format: "name":function($_){}
|
||||
:)
|
||||
declare function accessfn($f as element(ent:field)) as xs:string
|
||||
{
|
||||
let $type:=$f/@type/fn:string()
|
||||
return <field>
|
||||
"{$f/@name/fn:string()}": function($_ as element()) as {$type} {{$_/{$f/ent:xpath } }}</field>
|
||||
};
|
||||
|
||||
declare function generate($e as element(ent:entity)) as xs:string
|
||||
{
|
||||
let $fields:=for $field in $e/ent:fields/ent:field
|
||||
order by $field/@name
|
||||
return $field
|
||||
|
||||
let $filter:=$e/ent:views/ent:view[@name="filter"]=>fn:tokenize()
|
||||
let $filter:= $e/ent:fields/ent:field[@name=$filter]/ent:xpath/fn:concat("$item/",.)
|
||||
|
||||
return <field>
|
||||
"{$e/@name/fn:string()}": map{{
|
||||
"name": "{ $e/@name/fn:string()}",
|
||||
"description": "{ escape($e/ent:description)}",
|
||||
"access": map{{ {$fields!accessfn(.)=>fn:string-join(",")} }},
|
||||
|
||||
"filter": function($item,$q) as xs:boolean{{
|
||||
some $e in ( {fn:string-join($filter,", ")}) satisfies
|
||||
fn:contains($e,$q, 'http://www.w3.org/2005/xpath-functions/collation/html-ascii-case-insensitive')
|
||||
}},
|
||||
"json": map{{ {$fields!jsonfn(.)=>fn:string-join(",")} }},
|
||||
|
||||
"data": function() as {$e/ent:data/@type/fn:string(.)}*
|
||||
{{ {let $a:=$e/ent:data/fn:string() return if($a)then $a else "()"} }},
|
||||
|
||||
"views": map{{
|
||||
{$e/ent:views/ent:view!("'" || @name || "': '" ||. || "'")=>fn:string-join(',')}
|
||||
}}
|
||||
}}</field>
|
||||
};
|
||||
|
||||
(:~
|
||||
: @return sequence of element(entity) items for definitions at path
|
||||
:)
|
||||
declare function sources($path as xs:string) as element(ent:entity)*
|
||||
{
|
||||
let $_:=fn:trace($path,"DD")
|
||||
let $p:=fn:resolve-uri($path) || "/"
|
||||
return for $f in file:list($p)
|
||||
order by $f
|
||||
return fn:doc(fn:concat($p,$f))/ent:entity
|
||||
};
|
||||
|
||||
(:map for entity :)
|
||||
declare function build-map($entity as element(ent:entity)) as xs:string
|
||||
{
|
||||
let $m:=for $field in $entity/ent:fields/ent:field
|
||||
order by $field/@name
|
||||
return accessfn($field)
|
||||
return <text>
|
||||
declare variable $entity:{$entity/@name/fn:string()}: map{{ {fn:string-join($m,",")}
|
||||
}};
|
||||
|
||||
</text>
|
||||
};
|
||||
|
||||
(:~
|
||||
: return xml for suitable json serialization for field
|
||||
:)
|
||||
declare function jsonfn($f as element(ent:field))
|
||||
as xs:string
|
||||
{
|
||||
let $name:=$f/@name/fn:string()
|
||||
let $type:=$f/@type/fn:string()
|
||||
let $opt:=fn:contains($type,"?")
|
||||
let $repeat:=fn:contains($type,"*")
|
||||
let $json-type:=json-type($type)
|
||||
let $mult:=if($repeat) then "*" else "?"
|
||||
|
||||
let $at:=if($json-type ne "string")
|
||||
then "attribute type {'" || $json-type || "'},"
|
||||
else ""
|
||||
(: generate json xml :)
|
||||
let $simple:=function() as xs:string{
|
||||
<field>(: {$type} :)
|
||||
fn:data($_/{$f/ent:xpath })!element {$name} {{ {$at} .}}
|
||||
</field>
|
||||
}
|
||||
let $array:=function() as xs:string{
|
||||
<field>(: array of strings :)
|
||||
element {$name} {{
|
||||
attribute type {{"array"}},
|
||||
$_/{$f/ent:xpath }!element _ {{ attribute type {{"string"}}, .}}
|
||||
}}
|
||||
</field>
|
||||
}
|
||||
(: serialize when element :)
|
||||
let $element:=function() as xs:string{
|
||||
<field>element {$name} {{
|
||||
attribute type {{"string"}},
|
||||
fn:serialize($_/{$f/ent:xpath})}}</field>
|
||||
}
|
||||
|
||||
return <field>
|
||||
"{$name}": function($_ as element()) as element({$name}){$mult} {{
|
||||
{if($repeat)then
|
||||
$array()
|
||||
else if($type="element()") then
|
||||
$element()
|
||||
else $simple()} }}</field>
|
||||
};
|
||||
|
||||
|
||||
(:~ convert xs type to json
|
||||
:)
|
||||
declare function json-type($xsd as xs:string) as xs:string{
|
||||
switch ($xsd)
|
||||
case "element()" return "string"
|
||||
case "xs:boolean" return "boolean"
|
||||
case "xs:integer" return "number"
|
||||
case "xs:float" return "number"
|
||||
case "xs:double" return "number"
|
||||
case "xs:string*" return "array"
|
||||
default return "string"
|
||||
};
|
||||
|
||||
(:~ declare any namespaces found :)
|
||||
declare function build-namespaces($entities as element()*){
|
||||
for $n in distinct-deep($entities/ent:namespace)
|
||||
return
|
||||
<text>declare namespace {$n/@prefix/fn:string()}='{$n/@uri/fn:string()}';
|
||||
</text>
|
||||
};
|
||||
(:~ declare any namespaces found :)
|
||||
declare function build-modules($entities as element()*){
|
||||
for $n in distinct-deep($entities/ent:module)
|
||||
return
|
||||
<text>import module namespace {$n/@prefix/fn:string()}='{$n/@namespace/fn:string()}';
|
||||
</text>
|
||||
};
|
||||
|
||||
declare function build-describe($entities){
|
||||
let $m:=for $e in $entities
|
||||
return generate($e)
|
||||
return <text>
|
||||
declare variable $entity:list:=map {{ {fn:string-join($m,",")}
|
||||
}};
|
||||
|
||||
</text>
|
||||
};
|
||||
|
||||
declare function escape($str as xs:string)
|
||||
as xs:string{
|
||||
fn:replace(
|
||||
fn:replace($str,'"','""'),
|
||||
"'","''")
|
||||
};
|
||||
|
||||
(:-----from functx-------------------:)
|
||||
|
||||
declare function distinct-deep
|
||||
( $nodes as node()* ) as node()* {
|
||||
|
||||
for $seq in (1 to fn:count($nodes))
|
||||
return $nodes[$seq][fn:not(is-node-in-sequence-deep-equal(
|
||||
.,$nodes[fn:position() < $seq]))]
|
||||
};
|
||||
|
||||
declare function is-node-in-sequence-deep-equal
|
||||
( $node as node()? ,
|
||||
$seq as node()* ) as xs:boolean {
|
||||
|
||||
some $nodeInSeq in $seq satisfies fn:deep-equal($nodeInSeq,$node)
|
||||
} ;
|
||||
79
src/vue-poc/features/model.build/model.vue
Normal file
79
src/vue-poc/features/model.build/model.vue
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
<!DOCTYPE html>
|
||||
<template id="model">
|
||||
<v-container fluid>
|
||||
<v-card >
|
||||
<v-card-title class="blue accent-4">
|
||||
<span class="white--text">Generate <code>model.gen.xqm</code></span>
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<v-container fluid>
|
||||
<v-layout row wrap>
|
||||
|
||||
<v-flex xs6>
|
||||
<v-text-field v-model="params.efolder"
|
||||
label="Folder containing model definitions as xml"
|
||||
></v-text-field>
|
||||
</v-flex>
|
||||
|
||||
<v-flex xs6>
|
||||
<v-text-field v-model="params.target"
|
||||
label="Path to xqm file to generate"
|
||||
></v-text-field>
|
||||
</v-flex>
|
||||
<v-flex xs12>
|
||||
<code>{{code}}</code>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
|
||||
</v-container>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-btn primary @click.native="submit()" :loading="waiting"
|
||||
:disabled="waiting">
|
||||
<v-icon>play_circle_outline</v-icon>
|
||||
Run</v-btn>
|
||||
</v-card-actions>
|
||||
<v-snackbar v-model="snackbar.show"
|
||||
:timeout="6000"
|
||||
:success="snackbar.context === 'success'"
|
||||
:error="snackbar.context === 'error'"
|
||||
>
|
||||
{{ snackbar.msg }}
|
||||
<v-btn dark flat @click.native="snackbar.show = false">Close</v-btn>
|
||||
</v-snackbar>
|
||||
</v-card>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script>{
|
||||
data: function(){
|
||||
return {
|
||||
params:{
|
||||
efolder:"C:/Users/andy/git/vue-poc/src/vue-poc/models",
|
||||
target:"C:/Users/andy/git/vue-poc/src/vue-poc/models.gen.xqm"
|
||||
},
|
||||
waiting:false,
|
||||
snackbar:{show:false,msg:"",context:"success"},
|
||||
}
|
||||
},
|
||||
methods:{
|
||||
submit(){
|
||||
this.waiting=true
|
||||
HTTP.post("tasks/model",Qs.stringify(this.params))
|
||||
.then(r=>{
|
||||
this.waiting=false
|
||||
this.snackbar={show:true,msg:r.data.msg,context:"success"}
|
||||
console.log(r.data)
|
||||
})
|
||||
.catch(error=>{
|
||||
this.waiting=false
|
||||
this.snackbar={show:true,msg:"Problem",context:"error"}
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
},
|
||||
computed:{
|
||||
code(){return 'import module namespace entity = "quodatum.models.generated" at "'+this.params.target+'";'}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
27
src/vue-poc/features/model.build/rxq-model.xqm
Normal file
27
src/vue-poc/features/model.build/rxq-model.xqm
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
(:~
|
||||
: Update `generated/models.xqm` from files in `data/models`
|
||||
: using file:///C:/Users/andy/workspace/app-doc/src/doc/data/doc/models
|
||||
: $efolder:="file:///C:/Users/andy/workspace/app-doc/src/doc/data/doc/models"
|
||||
: $target:="file:///C:/Users/andy/workspace/app-doc/src/doc/generated/models.xqm"
|
||||
:)
|
||||
module namespace vue-api = 'quodatum:vue.api';
|
||||
|
||||
import module namespace bf = 'quodatum.tools.buildfields' at "entity-gen.xqm";
|
||||
|
||||
(:~
|
||||
: Returns a file content.
|
||||
:)
|
||||
declare
|
||||
%rest:POST %rest:path("/vue-poc/api/tasks/model")
|
||||
%rest:form-param("efolder", "{$efolder}")
|
||||
%rest:form-param("target", "{$target}")
|
||||
%rest:produces("application/json")
|
||||
%output:method("json")
|
||||
%updating
|
||||
function vue-api:model($efolder ,$target )
|
||||
{(
|
||||
prof:variables(),
|
||||
bf:write($efolder,$target),
|
||||
db:output(<json type="object"><msg>Updated: {$target}</msg></json>)
|
||||
)};
|
||||
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
<template id="task">
|
||||
<v-container fluid>
|
||||
<h1>Tasks</h1>
|
||||
<router-link to="tasks/model">model</router-link>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
|
|
|
|||
215
src/vue-poc/lib/entity-gen.xqm
Normal file
215
src/vue-poc/lib/entity-gen.xqm
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
(:~
|
||||
: generate xquery access code for entity definitions
|
||||
:)
|
||||
module namespace bf = 'quodatum.tools.buildfields';
|
||||
declare default function namespace 'quodatum.tools.buildfields';
|
||||
declare namespace ent="https://github.com/Quodatum/app-doc/entity";
|
||||
|
||||
(:~
|
||||
: write generated xquery module from entity xml
|
||||
: @param efolder full path to folder with entities e.g. fn:resolve-uri("./data/models")
|
||||
: @param dest full name of xqm to create e.g. fn:resolve-uri("models.xqm")
|
||||
:)
|
||||
declare %updating function write($efolder as xs:string,$dest as xs:string)
|
||||
{
|
||||
let $src:=bf:module(bf:sources($efolder))
|
||||
return file:write-text($dest,$src)
|
||||
};
|
||||
|
||||
(:~
|
||||
: generate xquery module for given entities as a string
|
||||
:)
|
||||
declare function module($entities as element(ent:entity)*) as xs:string
|
||||
{
|
||||
let $src:= <text>(: entity access maps
|
||||
: auto generated from xml files in entities folder at: {fn:current-dateTime()}
|
||||
:)
|
||||
|
||||
module namespace entity = 'quodatum.models.generated';
|
||||
{bf:build-modules($entities)}
|
||||
{bf:build-namespaces($entities)}
|
||||
{( bf:build-describe($entities))}
|
||||
|
||||
(:~ map of access functions for entity :)
|
||||
declare function entity:fields($entity as xs:string)
|
||||
as map(*){{
|
||||
$entity:list($entity)("access")
|
||||
}};
|
||||
</text>
|
||||
|
||||
return $src
|
||||
};
|
||||
|
||||
(:~
|
||||
: generate xquery for to return field value in the format: "name":function($_){}
|
||||
:)
|
||||
declare function accessfn($f as element(ent:field)) as xs:string
|
||||
{
|
||||
let $type:=$f/@type/fn:string()
|
||||
return <field>
|
||||
"{$f/@name/fn:string()}": function($_ as element()) as {$type} {{$_/{$f/ent:xpath } }}</field>
|
||||
};
|
||||
|
||||
declare function generate($e as element(ent:entity)) as xs:string
|
||||
{
|
||||
let $fields:=for $field in $e/ent:fields/ent:field
|
||||
order by $field/@name
|
||||
return $field
|
||||
|
||||
let $filter:=$e/ent:views/ent:view[@name="filter"]=>fn:tokenize()
|
||||
let $filter:= $e/ent:fields/ent:field[@name=$filter]/ent:xpath/fn:concat("$item/",.)
|
||||
|
||||
return <field>
|
||||
"{$e/@name/fn:string()}": map{{
|
||||
"name": "{ $e/@name/fn:string()}",
|
||||
"description": "{ escape($e/ent:description)}",
|
||||
"access": map{{ {$fields!accessfn(.)=>fn:string-join(",")} }},
|
||||
|
||||
"filter": function($item,$q) as xs:boolean{{
|
||||
some $e in ( {fn:string-join($filter,", ")}) satisfies
|
||||
fn:contains($e,$q, 'http://www.w3.org/2005/xpath-functions/collation/html-ascii-case-insensitive')
|
||||
}},
|
||||
"json": map{{ {$fields!jsonfn(.)=>fn:string-join(",")} }},
|
||||
|
||||
"data": function() as {$e/ent:data/@type/fn:string(.)}*
|
||||
{{ {let $a:=$e/ent:data/fn:string() return if($a)then $a else "()"} }},
|
||||
|
||||
"views": map{{
|
||||
{$e/ent:views/ent:view!("'" || @name || "': '" ||. || "'")=>fn:string-join(',')}
|
||||
}}
|
||||
}}</field>
|
||||
};
|
||||
|
||||
(:~
|
||||
: @return sequence of element(entity) items for definitions at path
|
||||
:)
|
||||
declare function sources($path as xs:string) as element(ent:entity)*
|
||||
{
|
||||
let $_:=fn:trace($path,"DD")
|
||||
let $p:=fn:resolve-uri($path) || "/"
|
||||
return for $f in file:list($p)
|
||||
order by $f
|
||||
return fn:doc(fn:concat($p,$f))/ent:entity
|
||||
};
|
||||
|
||||
(:map for entity :)
|
||||
declare function build-map($entity as element(ent:entity)) as xs:string
|
||||
{
|
||||
let $m:=for $field in $entity/ent:fields/ent:field
|
||||
order by $field/@name
|
||||
return accessfn($field)
|
||||
return <text>
|
||||
declare variable $entity:{$entity/@name/fn:string()}: map{{ {fn:string-join($m,",")}
|
||||
}};
|
||||
|
||||
</text>
|
||||
};
|
||||
|
||||
(:~
|
||||
: return xml for suitable json serialization for field
|
||||
:)
|
||||
declare function jsonfn($f as element(ent:field))
|
||||
as xs:string
|
||||
{
|
||||
let $name:=$f/@name/fn:string()
|
||||
let $type:=$f/@type/fn:string()
|
||||
let $opt:=fn:contains($type,"?")
|
||||
let $repeat:=fn:contains($type,"*")
|
||||
let $json-type:=json-type($type)
|
||||
let $mult:=if($repeat) then "*" else "?"
|
||||
|
||||
let $at:=if($json-type ne "string")
|
||||
then "attribute type {'" || $json-type || "'},"
|
||||
else ""
|
||||
(: generate json xml :)
|
||||
let $simple:=function() as xs:string{
|
||||
<field>(: {$type} :)
|
||||
fn:data($_/{$f/ent:xpath })!element {$name} {{ {$at} .}}
|
||||
</field>
|
||||
}
|
||||
let $array:=function() as xs:string{
|
||||
<field>(: array of strings :)
|
||||
element {$name} {{
|
||||
attribute type {{"array"}},
|
||||
$_/{$f/ent:xpath }!element _ {{ attribute type {{"string"}}, .}}
|
||||
}}
|
||||
</field>
|
||||
}
|
||||
(: serialize when element :)
|
||||
let $element:=function() as xs:string{
|
||||
<field>element {$name} {{
|
||||
attribute type {{"string"}},
|
||||
fn:serialize($_/{$f/ent:xpath})}}</field>
|
||||
}
|
||||
|
||||
return <field>
|
||||
"{$name}": function($_ as element()) as element({$name}){$mult} {{
|
||||
{if($repeat)then
|
||||
$array()
|
||||
else if($type="element()") then
|
||||
$element()
|
||||
else $simple()} }}</field>
|
||||
};
|
||||
|
||||
|
||||
(:~ convert xs type to json
|
||||
:)
|
||||
declare function json-type($xsd as xs:string) as xs:string{
|
||||
switch ($xsd)
|
||||
case "element()" return "string"
|
||||
case "xs:boolean" return "boolean"
|
||||
case "xs:integer" return "number"
|
||||
case "xs:float" return "number"
|
||||
case "xs:double" return "number"
|
||||
case "xs:string*" return "array"
|
||||
default return "string"
|
||||
};
|
||||
|
||||
(:~ declare any namespaces found :)
|
||||
declare function build-namespaces($entities as element()*){
|
||||
for $n in distinct-deep($entities/ent:namespace)
|
||||
return
|
||||
<text>declare namespace {$n/@prefix/fn:string()}='{$n/@uri/fn:string()}';
|
||||
</text>
|
||||
};
|
||||
(:~ declare any namespaces found :)
|
||||
declare function build-modules($entities as element()*){
|
||||
for $n in distinct-deep($entities/ent:module)
|
||||
return
|
||||
<text>import module namespace {$n/@prefix/fn:string()}='{$n/@namespace/fn:string()}';
|
||||
</text>
|
||||
};
|
||||
|
||||
declare function build-describe($entities){
|
||||
let $m:=for $e in $entities
|
||||
return generate($e)
|
||||
return <text>
|
||||
declare variable $entity:list:=map {{ {fn:string-join($m,",")}
|
||||
}};
|
||||
|
||||
</text>
|
||||
};
|
||||
|
||||
declare function escape($str as xs:string)
|
||||
as xs:string{
|
||||
fn:replace(
|
||||
fn:replace($str,'"','""'),
|
||||
"'","''")
|
||||
};
|
||||
|
||||
(:-----from functx-------------------:)
|
||||
|
||||
declare function distinct-deep
|
||||
( $nodes as node()* ) as node()* {
|
||||
|
||||
for $seq in (1 to fn:count($nodes))
|
||||
return $nodes[$seq][fn:not(is-node-in-sequence-deep-equal(
|
||||
.,$nodes[fn:position() < $seq]))]
|
||||
};
|
||||
|
||||
declare function is-node-in-sequence-deep-equal
|
||||
( $node as node()? ,
|
||||
$seq as node()* ) as xs:boolean {
|
||||
|
||||
some $nodeInSeq in $seq satisfies fn:deep-equal($nodeInSeq,$node)
|
||||
} ;
|
||||
|
|
@ -4,7 +4,8 @@
|
|||
: @author Andy Bunce, 2017
|
||||
:)
|
||||
module namespace ufile = 'vue-poc/file';
|
||||
|
||||
import module namespace fw="quodatum:file.walker";
|
||||
declare namespace c="http://www.w3.org/ns/xproc-step";
|
||||
(:~
|
||||
: resolve path relative to basex webpath
|
||||
: file("/fred")=>C:\Program Files (x86)\BaseX\webapp\fred
|
||||
|
|
@ -21,3 +22,54 @@ as xs:string
|
|||
return file:resolve-path($file,$webroot)
|
||||
};
|
||||
|
||||
declare function ufile:webfile($url as xs:string)
|
||||
as element(c:directory)
|
||||
{
|
||||
let $path := ufile:web( $url)=>trace("vue-api:web ")
|
||||
return if( file:exists($path))then
|
||||
fw:directory-list($path,map{"max-depth":1,"include-info":true()})
|
||||
else
|
||||
error(xs:QName('ufile:badpath'),$path)
|
||||
};
|
||||
|
||||
declare function ufile:basexdb($url as xs:string)
|
||||
as element(c:directory)
|
||||
{
|
||||
<c:directory name="" xml:base="basexdb:/" last-modified="2017-07-01T13:39:38.98691Z" size="4096">{
|
||||
if($url="/") then
|
||||
db:list()!
|
||||
<c:directory name="{db:property(.,'name')}"
|
||||
last-modified="{db:property(.,'timestamp')}"
|
||||
size="{db:property(.,'size')}"/>
|
||||
|
||||
else
|
||||
let $map:=ufile:collection-next($url)
|
||||
for $name in map:keys($map)
|
||||
(: db:list-details($db as xs:string, $path as xs:string) as element(resource)* :)
|
||||
return if($map($name)="file") then
|
||||
<c:file name="{$name}" size="0"/>
|
||||
else
|
||||
<c:directory name="{$name}" size="0"/>
|
||||
}</c:directory>
|
||||
};
|
||||
|
||||
(:~ return map of next level database contents
|
||||
:@param $url a database base collection e.g /dbname/fred/
|
||||
:)
|
||||
declare function ufile:collection-next($url as xs:string)
|
||||
as map(*)
|
||||
{
|
||||
if(not(starts-with($url,"/")) or ends-with($url,"/")) then
|
||||
error(xs:QName('ufile:badcollection'),$url)
|
||||
else
|
||||
fold-left(
|
||||
uri-collection($url ),
|
||||
map{},
|
||||
function($acc,$this){
|
||||
let $s:=substring-after($this ,$url || "/")
|
||||
let $isDir:=contains($s,"/")
|
||||
let $s:=if($isDir)then substring-before($s,"/") else $s
|
||||
return map:merge((map:entry($s,if($isDir)then "directory" else "file"),$acc))
|
||||
}
|
||||
)
|
||||
};
|
||||
|
|
|
|||
56
src/vue-poc/models.gen.xqm
Normal file
56
src/vue-poc/models.gen.xqm
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
(: entity access maps
|
||||
: auto generated from xml files in entities folder at: 2017-07-17T17:47:26.588+01:00
|
||||
:)
|
||||
|
||||
module namespace entity = 'quodatum.models.generated';
|
||||
declare namespace c='http://www.w3.org/ns/xproc-step';
|
||||
|
||||
declare variable $entity:list:=map {
|
||||
"thumbnail": map{
|
||||
"name": "thumbnail",
|
||||
"description": "an image.",
|
||||
"access": map{
|
||||
"id": function($_ as element()) as xs:integer {$_/db:node-id(.) },
|
||||
"name": function($_ as element()) as xs:string {$_/file/@name },
|
||||
"path": function($_ as element()) as xs:string {$_/file/@path },
|
||||
"size": function($_ as element()) as xs:integer {$_/0 } },
|
||||
|
||||
"filter": function($item,$q) as xs:boolean{
|
||||
some $e in ( $item/file/@name) satisfies
|
||||
fn:contains($e,$q, 'http://www.w3.org/2005/xpath-functions/collation/html-ascii-case-insensitive')
|
||||
},
|
||||
"json": map{
|
||||
"id": function($_ as element()) as element(id)? {
|
||||
(: xs:integer :)
|
||||
fn:data($_/db:node-id(.))!element id { attribute type {'number'}, .}
|
||||
},
|
||||
"name": function($_ as element()) as element(name)? {
|
||||
(: xs:string :)
|
||||
fn:data($_/file/@name)!element name { .}
|
||||
},
|
||||
"path": function($_ as element()) as element(path)? {
|
||||
(: xs:string :)
|
||||
fn:data($_/file/@path)!element path { .}
|
||||
},
|
||||
"size": function($_ as element()) as element(size)? {
|
||||
(: xs:integer :)
|
||||
fn:data($_/0)!element size { attribute type {'number'}, .}
|
||||
} },
|
||||
|
||||
"data": function() as element(image)*
|
||||
{ collection("/vue-poc/Pictures")/image },
|
||||
|
||||
"views": map{
|
||||
'filter': 'name'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
(:~ map of access functions for entity :)
|
||||
declare function entity:fields($entity as xs:string)
|
||||
as map(*){
|
||||
$entity:list($entity)("access")
|
||||
};
|
||||
|
||||
|
|
@ -1,15 +1,22 @@
|
|||
<entity name="thumbnail" xmlns="https://github.com/Quodatum/app-doc/entity">
|
||||
<description>an image.</description>
|
||||
<namespace prefix="c" uri="http://www.w3.org/ns/xproc-step"/>
|
||||
<module prefix="cmpx" namespace="quodatum.cmpx" />
|
||||
<fields>
|
||||
<field name="id" type="xs:integer">
|
||||
<description>Database Id.</description>
|
||||
<xpath>db:node-id(.)</xpath>
|
||||
</field>
|
||||
<field name="name" type="xs:string">
|
||||
<description>File name.</description>
|
||||
<xpath>@name</xpath>
|
||||
<xpath>file/@name</xpath>
|
||||
</field>
|
||||
<field name="path" type="xs:string">
|
||||
<description>File path. e.g. Pictures/2012/2012-06-23/skating.jpg</description>
|
||||
<xpath>file/@path</xpath>
|
||||
</field>
|
||||
<field name="size" type="xs:integer">
|
||||
<description>file size.</description>
|
||||
<xpath>@size</xpath>
|
||||
<xpath>0</xpath>
|
||||
</field>
|
||||
|
||||
</fields>
|
||||
|
|
@ -17,6 +24,6 @@
|
|||
<view name="filter">name</view>
|
||||
</views>
|
||||
<iconclass>fa fa-file</iconclass>
|
||||
<data type="element(*)">doc("/vue-poc/pics.xml")//c:file</data>
|
||||
<data type="element(image)">collection("/vue-poc/Pictures")/image</data>
|
||||
|
||||
</entity>
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
// generated 2017-07-12T11:37:10.722+01:00
|
||||
// generated 2017-07-17T17:49:54.864+01:00
|
||||
Vue.component('my-component',{template:`
|
||||
<a :href="href" :target="href"> {{href}}<v-icon>link</v-icon></a>
|
||||
`,
|
||||
|
|
@ -36,9 +36,7 @@
|
|||
<v-list-tile-action>
|
||||
<v-icon>{{ item.model ? 'keyboard_arrow_up' : 'keyboard_arrow_down' }}</v-icon>
|
||||
</v-list-tile-action>
|
||||
<v-list-tile-content>
|
||||
|
||||
</v-list-tile-content>
|
||||
</v-list-tile>
|
||||
<template v-for="(child, i) in item.children">
|
||||
<v-list-tile :to="child.href" :key="i" ripple="">
|
||||
|
|
@ -157,7 +155,7 @@ v0.0.2 </v-card-title> </v-card> </v-flex> <v-flex xs4="">
|
|||
<v-container fluid="">
|
||||
|
||||
<v-card>
|
||||
<v-toolbar>
|
||||
<v-toolbar light="">
|
||||
<v-menu bottom="" right="">
|
||||
<v-btn icon="" slot="activator"><v-icon>{{icon}}</v-icon></v-btn>
|
||||
<v-list>
|
||||
|
|
@ -169,7 +167,7 @@ v0.0.2 </v-card-title> </v-card> </v-flex> <v-flex xs4="">
|
|||
<v-toolbar-title>{{ url }}</v-toolbar-title>
|
||||
|
||||
<v-spacer></v-spacer>
|
||||
<v-text-field prepend-icon="search" label="Filter..." v-model="q" type="search" hide-details="" single-line="" dark="" @keyup.native.enter="filter"></v-text-field>
|
||||
<v-text-field prepend-icon="search" label="Filter..." v-model="q" type="search" hide-details="" single-line="" @keyup.native.enter="filter"></v-text-field>
|
||||
<v-icon>view_module</v-icon>
|
||||
</v-toolbar>
|
||||
|
||||
|
|
@ -248,7 +246,7 @@ v0.0.2 </v-card-title> </v-card> </v-flex> <v-flex xs4="">
|
|||
},
|
||||
load(url){
|
||||
this.busy=true
|
||||
HTTP.get("file",{params:{url:url,protocol:this.protocol}})
|
||||
HTTP.get("collection",{params:{url:url,protocol:this.protocol}})
|
||||
.then(r=>{
|
||||
this.folders=r.data.folders
|
||||
this.files=r.data.files
|
||||
|
|
@ -311,7 +309,7 @@ v0.0.2 </v-card-title> </v-card> </v-flex> <v-flex xs4="">
|
|||
<v-list>
|
||||
<v-list-tile v-for="item in items" v-bind:key="item.title" @click="doEdit(item)" avatar="">
|
||||
<v-list-tile-action>
|
||||
<v-chip v-text="item.mode">Example Chip</v-chip>
|
||||
<v-chip v-text="item.protocol">Example Chip</v-chip>
|
||||
</v-list-tile-action>
|
||||
<v-list-tile-content>
|
||||
<v-list-tile-title @click="doEdit(item)" v-text="item.url"></v-list-tile-title>
|
||||
|
|
@ -337,7 +335,7 @@ v0.0.2 </v-card-title> </v-card> </v-flex> <v-flex xs4="">
|
|||
},
|
||||
doEdit(item){
|
||||
console.log("history: ",item)
|
||||
router.push({ path: 'edit', query: { url:item.url, mode:item.mode }})
|
||||
router.push({ path: 'edit', query: { url:item.url, protocol:item.protocol }})
|
||||
}
|
||||
},
|
||||
created:function(){
|
||||
|
|
@ -357,7 +355,7 @@ v0.0.2 </v-card-title> </v-card> </v-flex> <v-flex xs4="">
|
|||
|
||||
<v-toolbar class="grey lighten-2 black--text">
|
||||
<v-menu>
|
||||
<v-btn primary="" icon="" dark="" slot="activator" v-tooltip:top="{ html: path.join('/') }"><v-icon>folder</v-icon></v-btn>
|
||||
<v-btn primary="" icon="" dark="" slot="activator" v-tooltip:top="{ html: path.join('/') }"><v-icon>{{icon}}</v-icon></v-btn>
|
||||
<v-list>
|
||||
<v-list-tile v-for="item in path" :key="item">
|
||||
<v-list-tile-content @click="showfiles()">
|
||||
|
|
@ -416,14 +414,14 @@ v0.0.2 </v-card-title> </v-card> </v-flex> <v-flex xs4="">
|
|||
<v-list-tile-avatar>
|
||||
<v-icon>settings</v-icon>
|
||||
</v-list-tile-avatar>
|
||||
<v-list-tile-title>Show settings</v-list-tile-title>
|
||||
<v-list-tile-title @click="acecmd('showSettingsMenu')">Show settings</v-list-tile-title>
|
||||
</v-list-tile>
|
||||
|
||||
<v-list-tile @click="acecmd('showKeyboardShortcuts')" avatar="">
|
||||
<v-list-tile-avatar>
|
||||
<v-icon>keyboard</v-icon>
|
||||
</v-list-tile-avatar>
|
||||
<v-list-tile-title>Show keyboard commands</v-list-tile-title>
|
||||
<v-list-tile-title @click="acecmd('showKeyboardShortcuts')">Show keyboard commands</v-list-tile-title>
|
||||
</v-list-tile>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
|
|
@ -555,7 +553,8 @@ v0.0.2 </v-card-title> </v-card> </v-flex> <v-flex xs4="">
|
|||
})
|
||||
},
|
||||
showfiles(){
|
||||
router.push({ path: 'files', query: { url: this.path.join("/") }})
|
||||
var target=this.protocol="basexdb"?"database":"files";
|
||||
router.push({ path: target, query: { url: this.path.join("/"),protocol:this.protocol }})
|
||||
},
|
||||
beautify(){
|
||||
this.busy=true
|
||||
|
|
@ -594,6 +593,11 @@ v0.0.2 </v-card-title> </v-card> </v-flex> <v-flex xs4="">
|
|||
if(this.dirty)event.preventDefault();
|
||||
}
|
||||
},
|
||||
computed:{
|
||||
icon(){
|
||||
return (this.protocol=="basexdb")?"account_balance":"folder"
|
||||
}
|
||||
},
|
||||
created(){
|
||||
//https://forum.vuejs.org/t/detect-browser-close/5001/3 @fixme
|
||||
document.addEventListener('beforeunload', this.leaving);
|
||||
|
|
@ -788,18 +792,31 @@ v0.0.2 </v-card-title> </v-card> </v-flex> <v-flex xs4="">
|
|||
|
||||
<v-card>
|
||||
<v-card-actions>
|
||||
<v-btn @click.native="page+=1">next</v-btn>
|
||||
{{page}}
|
||||
<v-btn @click.native="page-=1">back</v-btn>
|
||||
|
||||
<v-spacer></v-spacer>
|
||||
<v-select v-bind:items="keywords" v-model="query.keyword" label="Keyword" autocomplete=""></v-select>
|
||||
<v-dialog persistent="" v-model="modal" lazy="" full-width="">
|
||||
<v-text-field slot="activator" label="Earliest date" v-model="query.from" prepend-icon="event" readonly=""></v-text-field>
|
||||
<v-date-picker v-model="query.from" scrollable="" actions="">
|
||||
<template scope="{ save, cancel }">
|
||||
<v-card-actions>
|
||||
<v-btn flat="" primary="" @click.native="cancel()">Cancel</v-btn>
|
||||
<v-btn flat="" primary="" @click.native="save()">Save</v-btn>
|
||||
</v-card-actions>
|
||||
</template>
|
||||
</v-date-picker>
|
||||
</v-dialog>
|
||||
<v-btn @click.native="clear()">Clear</v-btn>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn @click.native="query.page+=1">next</v-btn>
|
||||
{{query.page}}
|
||||
<v-btn @click.native="query.page-=1">back</v-btn>
|
||||
</v-card-actions>
|
||||
<v-container fluid="" grid-list-md="">
|
||||
<v-layout row="" wrap="">
|
||||
<v-flex height="80px" xs2="" v-for="image in images" :key="image.name">
|
||||
<v-card @click="selected()" class="grey lighten-2 pt-1">
|
||||
<v-card @click="selected(image)" class="grey lighten-2 pt-1">
|
||||
<v-card-media :src="src(image)" height="80px" :contain="true"></v-card-media>
|
||||
<v-card-actions v-tooltip:top="{ html: image.name }">
|
||||
<v-card-actions v-tooltip:top="{ html: image.id + ' '+image.name }">
|
||||
|
||||
<v-btn icon="" small="">
|
||||
<v-icon>favorite</v-icon>
|
||||
|
|
@ -816,41 +833,72 @@ v0.0.2 </v-card-title> </v-card> </v-flex> <v-flex xs4="">
|
|||
</v-flex>
|
||||
</v-layout>
|
||||
</v-container>
|
||||
<v-navigation-drawer left="" light="" temporary="" v-model="showInfo">
|
||||
<v-card>
|
||||
<v-toolbar class="green white--text">
|
||||
<v-toolbar-title>{{selitem.name}}</v-toolbar-title>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn flat="" icon="" @click.native="showInfo = false"><v-icon>highlight_off</v-icon></v-btn>
|
||||
</v-toolbar>
|
||||
<v-card-text> blah blah </v-card-text>
|
||||
</v-card>
|
||||
</v-navigation-drawer>
|
||||
</v-card>
|
||||
|
||||
`,
|
||||
|
||||
data: () => ({
|
||||
images:[],
|
||||
page:0
|
||||
query:{page:0, // current page
|
||||
from:null,
|
||||
keyword:null
|
||||
},
|
||||
modal:false, // showing datepicker
|
||||
|
||||
keywords:[],
|
||||
showInfo:false,
|
||||
selitem:"TODO"
|
||||
}),
|
||||
methods:{
|
||||
src(item){
|
||||
//return "https://unsplash.it/150/300?image="+Math.floor(Math.random() * 100) + 1
|
||||
return "data:image/jpeg;base64,"+item.data
|
||||
},
|
||||
getImages(){
|
||||
HTTP.get("images/list?page="+this.page)
|
||||
HTTP.get("images/list",{params:this.query})
|
||||
.then(r=>{
|
||||
this.images=r.data.items
|
||||
})
|
||||
|
||||
},
|
||||
selected(){
|
||||
alert("not yet")
|
||||
clear(){
|
||||
this.query.from=null;
|
||||
this.query.keyword=null;
|
||||
},
|
||||
selected(image){
|
||||
this.selitem=image;
|
||||
this.showInfo=true;
|
||||
}
|
||||
|
||||
},
|
||||
watch:{
|
||||
page(v){
|
||||
this.$router.push({ query: { page: this.page }})
|
||||
"query":{
|
||||
handler:function(v){
|
||||
this.$router.push({ query: this.query })
|
||||
},
|
||||
deep:true
|
||||
},
|
||||
$route(v){
|
||||
this.getImages()
|
||||
}
|
||||
},
|
||||
created:function(){
|
||||
this.page=this.$route.query.page || this.page
|
||||
this.query.page=Number(this.$route.query.page) || this.query.page
|
||||
this.query.keyword=this.$route.query.keyword || this.query.keyword
|
||||
this.query.from=this.$route.query.from || this.query.from
|
||||
this.getImages()
|
||||
HTTP.get("images/keywords")
|
||||
.then(r=>{
|
||||
this.keywords=r.data.items
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1015,6 +1063,75 @@ v0.0.2 </v-card-title> </v-card> </v-flex> <v-flex xs4="">
|
|||
}
|
||||
}
|
||||
|
||||
);
|
||||
const Model=Vue.extend({template:`
|
||||
<v-container fluid="">
|
||||
<v-card>
|
||||
<v-card-title class="blue accent-4">
|
||||
<span class="white--text">Generate <code>model.gen.xqm</code></span>
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<v-container fluid="">
|
||||
<v-layout row="" wrap="">
|
||||
|
||||
<v-flex xs6="">
|
||||
<v-text-field v-model="params.efolder" label="Folder containing model definitions as xml"></v-text-field>
|
||||
</v-flex>
|
||||
|
||||
<v-flex xs6="">
|
||||
<v-text-field v-model="params.target" label="Path to xqm file to generate"></v-text-field>
|
||||
</v-flex>
|
||||
<v-flex xs12="">
|
||||
<code>{{code}}</code>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
|
||||
</v-container>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-btn primary="" @click.native="submit()" :loading="waiting" :disabled="waiting">
|
||||
<v-icon>play_circle_outline</v-icon>
|
||||
Run</v-btn>
|
||||
</v-card-actions>
|
||||
<v-snackbar v-model="snackbar.show" :timeout="6000" :success="snackbar.context === 'success'" :error="snackbar.context === 'error'">
|
||||
{{ snackbar.msg }}
|
||||
<v-btn dark="" flat="" @click.native="snackbar.show = false">Close</v-btn>
|
||||
</v-snackbar>
|
||||
</v-card>
|
||||
</v-container>
|
||||
`,
|
||||
|
||||
data: function(){
|
||||
return {
|
||||
params:{
|
||||
efolder:"C:/Users/andy/git/vue-poc/src/vue-poc/models",
|
||||
target:"C:/Users/andy/git/vue-poc/src/vue-poc/models.gen.xqm"
|
||||
},
|
||||
waiting:false,
|
||||
snackbar:{show:false,msg:"",context:"success"},
|
||||
}
|
||||
},
|
||||
methods:{
|
||||
submit(){
|
||||
this.waiting=true
|
||||
HTTP.post("tasks/model",Qs.stringify(this.params))
|
||||
.then(r=>{
|
||||
this.waiting=false
|
||||
this.snackbar={show:true,msg:r.data.msg,context:"success"}
|
||||
console.log(r.data)
|
||||
})
|
||||
.catch(error=>{
|
||||
this.waiting=false
|
||||
this.snackbar={show:true,msg:"Problem",context:"error"}
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
},
|
||||
computed:{
|
||||
code(){return 'import module namespace entity = "quodatum.models.generated" at "'+this.params.target+'";'}
|
||||
}
|
||||
}
|
||||
|
||||
);
|
||||
const People=Vue.extend({template:`
|
||||
<v-container fluid="">
|
||||
|
|
@ -1493,6 +1610,7 @@ v0.0.2 </v-card-title> </v-card> </v-flex> <v-flex xs4="">
|
|||
const Task=Vue.extend({template:`
|
||||
<v-container fluid="">
|
||||
<h1>Tasks</h1>
|
||||
<router-link to="tasks/model">model</router-link>
|
||||
</v-container>
|
||||
`,
|
||||
|
||||
|
|
@ -1633,6 +1751,7 @@ const router = new VueRouter({
|
|||
{ path: '/eval', component: Eval,meta:{title:"Evaluate XQuery"} },
|
||||
{ path: '/logs', component: Log,meta:{title:"Server logs"} },
|
||||
{ path: '/tasks', component: Task,meta:{title:"Runnable tasks"} },
|
||||
{ path: '/tasks/model', component: Model,meta:{title:"build model"} },
|
||||
{ path: '/jobs', component: Job,meta:{title:"Jobs"} },
|
||||
{ path: '*', component: Notfound,meta:{title:"Page not found"} }
|
||||
],
|
||||
|
|
@ -1673,42 +1792,42 @@ const app = new Vue({
|
|||
text: 'Collections' ,
|
||||
model: false,
|
||||
children: [
|
||||
{href: 'database', text: 'Databases',icon: 'account_balance' },
|
||||
{href: 'files', text: 'File system',icon: 'folder' },
|
||||
{href: 'edit',text: 'edit',icon: 'mode_edit'},
|
||||
{href: 'history',text: 'history',icon: 'history'},
|
||||
{href: 'logs',text: 'Server logs',icon: 'dns'}
|
||||
{href: '/database', text: 'Databases',icon: 'account_balance' },
|
||||
{href: '/files', text: 'File system',icon: 'folder' },
|
||||
{href: '/edit',text: 'edit',icon: 'mode_edit'},
|
||||
{href: '/history',text: 'history',icon: 'history'},
|
||||
{href: '/logs',text: 'Server logs',icon: 'dns'}
|
||||
]},
|
||||
{
|
||||
icon: 'directions_run',
|
||||
text: 'Actions' ,
|
||||
model: false,
|
||||
children: [
|
||||
{href: 'eval',text: 'Query',icon: 'play_circle_outline'},
|
||||
{href: 'jobs',text: 'Running jobs',icon: 'dashboard'},
|
||||
{href: 'tasks',text: 'Tasks',icon: 'history'},
|
||||
{href: '/eval',text: 'Query',icon: 'play_circle_outline'},
|
||||
{href: '/jobs',text: 'Running jobs',icon: 'dashboard'},
|
||||
{href: '/tasks',text: 'Tasks',icon: 'history'}
|
||||
]},
|
||||
{
|
||||
icon: 'more_horiz',
|
||||
text: 'More' ,
|
||||
model: false,
|
||||
children: [
|
||||
{href: 'people',text: 'People',icon: 'person'},
|
||||
{href: 'select',text: 'select',icon: 'extension'},
|
||||
{href: 'puzzle',text: 'Puzzle',icon: 'extension'},
|
||||
{href: 'images',text: 'Images',icon: 'camera_roll'},
|
||||
{href: 'tabs',text: 'tabs',icon: 'switch_camera'},
|
||||
{href: 'ping',text: 'ping',icon: 'update'},
|
||||
{href: 'thumbnail',text: 'thumbnail',icon: 'touch_app'}
|
||||
{href: '/people',text: 'People',icon: 'person'},
|
||||
{href: '/select',text: 'select',icon: 'extension'},
|
||||
{href: '/puzzle',text: 'Puzzle',icon: 'extension'},
|
||||
{href: '/images',text: 'Images',icon: 'camera_roll'},
|
||||
{href: '/tabs',text: 'tabs',icon: 'switch_camera'},
|
||||
{href: '/ping',text: 'ping',icon: 'update'},
|
||||
{href: '/thumbnail',text: 'thumbnail',icon: 'touch_app'}
|
||||
]},
|
||||
{href: 'settings',text: 'settings',icon: 'settings' }
|
||||
{href: '/settings',text: 'settings',icon: 'settings' }
|
||||
]
|
||||
|
||||
}},
|
||||
methods: {
|
||||
|
||||
search(){
|
||||
this.$router.push({path: 'search',query: { q: this.q }})
|
||||
this.$router.push({path: '/search',query: { q: this.q }})
|
||||
},
|
||||
logout(){
|
||||
HTTP.get("logout").then(r=>{
|
||||
|
|
|
|||
|
|
@ -9,17 +9,17 @@
|
|||
<title>Vue Router Test</title>
|
||||
<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Roboto:300,400,500,700,400italic">
|
||||
<link rel="stylesheet" href="//fonts.googleapis.com/icon?family=Material+Icons">
|
||||
<link href="https://unpkg.com/vuetify@0.13.1/dist/vuetify.min.css" rel="stylesheet" type="text/css">
|
||||
<link href="https://unpkg.com/vuetify@0.14.2/dist/vuetify.min.css" rel="stylesheet" type="text/css">
|
||||
<link href="https://unpkg.com/vue-multiselect@2.0.0-beta.15/dist/vue-multiselect.min.css" rel="stylesheet" type="text/css">
|
||||
|
||||
<link href="/vue-poc/ui/app.css" rel="stylesheet" type="text/css">
|
||||
<link rel="shortcut icon" href="/vue-poc/ui/icon.png"/>
|
||||
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.1/vue.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue-router/2.5.3/vue-router.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.16.1/axios.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/qs/6.4.0/qs.js"></script>
|
||||
<script src="https://unpkg.com/vuetify@0.13.1/dist/vuetify.min.js"></script>
|
||||
<script src="https://unpkg.com/vuetify@0.14.2/dist/vuetify.min.js"></script>
|
||||
<script src="https://unpkg.com/vue-multiselect@2.0.0-beta.15/dist/vue-multiselect.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.7/ace.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.7/ext-language_tools.js"></script>
|
||||
|
|
|
|||
15
src/vue-poc/tasks/createimage.xq
Normal file
15
src/vue-poc/tasks/createimage.xq
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
(:~ generate image docs from meta docs 52 sec :)
|
||||
import module namespace metadata = 'expkg-zone58:image.metadata';
|
||||
|
||||
for $meta in collection("/vue-poc/Pictures")/metadata
|
||||
let $loc:=db:path($meta)=>tokenize("/")
|
||||
let $name:=$loc[count($loc)-1]
|
||||
let $path:= subsequence($loc,1,count($loc)-1)=>string-join("/")
|
||||
let $image:=<image>
|
||||
<file name="{$name}" path="{$path}"/>{
|
||||
metadata:core($meta),
|
||||
metadata:geo($meta),
|
||||
metadata:keywords($meta)
|
||||
} </image>
|
||||
let $target:=$path || "/image.xml"
|
||||
return db:replace("vue-poc",$target,$image)
|
||||
12
src/vue-poc/tasks/generate-model-local.xq
Normal file
12
src/vue-poc/tasks/generate-model-local.xq
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
(:~
|
||||
: Update `generated/models.xqm` from files in `data/models`
|
||||
: using file:///C:/Users/andy/workspace/app-doc/src/doc/data/doc/models
|
||||
:)
|
||||
|
||||
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"))
|
||||
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
(:~
|
||||
: create app.js from vue files
|
||||
: create app-gen.js from vue files
|
||||
:)
|
||||
import module namespace html5="text.html5" at "html5parse.xqm";
|
||||
import module namespace fw="quodatum:file.walker";
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue