file selection

This commit is contained in:
Andy Bunce 2017-09-17 17:25:44 +01:00
parent 4c65218cba
commit 7081c4446c
10 changed files with 1865 additions and 1820 deletions

View file

@ -19,7 +19,7 @@ const router = new VueRouter({
{ path: '/server/users', component: Users,meta:{title:"Users"} }, { path: '/server/users', component: Users,meta:{title:"Users"} },
{ path: '/server/repo', component: Repo,meta:{title:"Repository"} }, { path: '/server/repo', component: Repo,meta:{title:"Repository"} },
{ path: '/files', component: Files,meta:{title:"File system"},props:{protocol:"webfile"} }, { path: '/files', component: Files,meta:{title:"File system"},props:{protocol:"webfile"} },
{ path: '/database', component: Files,meta:{title:"Databases"},props:{protocol:"basexdb"} }, { path: '/database', component: Files,meta:{title:"Databases"},props:{protocol:"xmldb"} },
{ path: '/ping', component: Ping,meta:{title:"Ping"} }, { path: '/ping', component: Ping,meta:{title:"Ping"} },
{ path: '/settings', component: Settings, meta:{title:"Settings"} }, { path: '/settings', component: Settings, meta:{title:"Settings"} },
{ path: '/acesettings', component: Acesettings, meta:{title:"Editor settings"} }, { path: '/acesettings', component: Acesettings, meta:{title:"Editor settings"} },

View file

@ -41,7 +41,7 @@ as element(json)
{ {
let $reader:=map{ let $reader:=map{
"webfile":ufile:webfile#1, "webfile":ufile:webfile#1,
"basexdb":ufile:basexdb#1 "xmldb":ufile:xmldb#1
} }
let $items:=$reader($protocol)($url) let $items:=$reader($protocol)($url)
return vue-api:items($items) return vue-api:items($items)
@ -53,32 +53,25 @@ declare function vue-api:items($items)
as element(json) as element(json)
{ {
<json type="object" > <json type="object" >
<folders type="array"> <items type="array">
{for $f in $items/c:directory {for $f in $items/*
order by $f/@name/lower-case(.) order by $f/@name/lower-case(.)
return <_ type="object"> return <_ type="object">
{vue-api:details($f,"folder")} {vue-api:details($f,"folder")}
</_> </_>
} }
</folders> </items>
<files type="array">
{for $f in $items/c:file
order by $f/@name/lower-case(.)
return <_ type="object">
{vue-api:details($f,"insert_drive_file")}
</_>
}
</files>
</json> </json>
}; };
declare function vue-api:details($f as element(*),$icon as xs:string) declare function vue-api:details($f as element(*),$type as xs:string)
as element(*)* as element(*)*
{ {
<name>{$f/@name/string()}</name> <name>{$f/@name/string()}</name>
,<icon>{$icon}</icon> ,<type>{if(local-name($f)="file" )then "file" else "folder"}</type>
,<modified>{$f/@last-modified/string()}</modified> ,<modified>{$f/@last-modified/string()}</modified>
,<size type="number">{$f/@size/string()}</size> ,<size type="number">{$f/@size/string()}</size>
,<selected type="boolean">false</selected>
,<mime>unknown</mime> ,<mime>unknown</mime>
}; };

View file

@ -4,7 +4,7 @@
<v-card> <v-card>
<v-toolbar > <v-toolbar dense >
<v-btn icon :to="{query: { url: '/' }}"> <v-btn icon :to="{query: { url: '/' }}">
<v-icon >{{icon}}</v-icon> <v-icon >{{icon}}</v-icon>
</v-btn> </v-btn>
@ -17,22 +17,25 @@
</v-toolbar-title> </v-toolbar-title>
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-btn v-if="selCount" @click="selectNone">Sel:{{selCount}}</v-btn>
<v-toolbar-items v-if="!selected"> <v-text-field v-if="!selCount" prepend-icon="search" label="Filter..." v-model="q" type="search"
<v-text-field prepend-icon="search" label="Filter..." v-model="q" type="search"
hide-details single-line @keyup.enter="setfilter"></v-text-field> hide-details single-line @keyup.enter="setfilter"></v-text-field>
<v-toolbar-items v-if="!selCount">
<v-btn icon v-for="b in buttons" :key="b.icon" @click="action(b)"> <v-btn icon v-for="b in buttons" :key="b.icon" @click="action(b)">
<v-avatar>
<v-icon v-text="b.icon"></v-icon> <v-icon v-text="b.icon"></v-icon>
</v-avatar>
</v-btn> </v-btn>
</v-toolbar-items> </v-toolbar-items>
<v-toolbar-items v-if="selected"> <v-toolbar-items v-if="selCount">
<v-btn icon v-for="b in selopts" :key="b.icon" @click="action(b)"> <v-btn icon v-for="b in selopts" :key="b.icon" @click="action(b)">
<v-icon v-text="b.icon"></v-icon> <v-icon v-text="b.icon"></v-icon>
</v-btn> </v-btn>
</v-toolbar-items> </v-toolbar-items>
<v-menu offset-y> <v-menu offset-y v-if="selCount">
<v-btn icon slot="activator"> <v-btn icon slot="activator">
<v-icon>more_vert</v-icon> <v-icon>more_vert</v-icon>
</v-btn> </v-btn>
@ -49,20 +52,18 @@
</v-list-tile> </v-list-tile>
</v-list> </v-list>
</v-menu> </v-menu>
</v-toolbar> </v-toolbar>
<v-layout v-if="!busy">
<v-progress-linear v-if="busy" v-bind:indeterminate="true" ></v-progress-linear>
<v-layout>
<v-flex> <v-flex>
<v-list v-if="!busy" two-line subheader> <v-list two-line subheader>
<v-subheader inset > <v-subheader inset >
<span >Folders ({{ folders.length }})</span> <span >Folders ({{ xfolders.length }})</span>
</v-subheader> </v-subheader>
<v-list-tile v-for="item in folders" v-bind:key="item.name" @click="folder(item)" avatar > <v-list-tile v-for="item in xfolders" v-bind:key="item.name" @click="folder(item)" avatar >
<v-list-tile-avatar > <v-list-tile-avatar >
<v-icon v-bind:class="[item.iconClass]">{{ item.icon }}</v-icon> <v-icon v-bind:class="[item.iconClass]">{{ itemIcon(item) }}</v-icon>
</v-list-tile-avatar> </v-list-tile-avatar>
<v-list-tile-content > <v-list-tile-content >
<v-list-tile-title>{{ item.name }}</v-list-tile-title> <v-list-tile-title>{{ item.name }}</v-list-tile-title>
@ -77,11 +78,11 @@
<v-divider inset></v-divider> <v-divider inset></v-divider>
<v-subheader inset> <v-subheader inset>
<span >Files ({{ files.length }})</span> <span >Files ({{ xfiles.length }})</span>
</v-subheader> </v-subheader>
<v-list-tile v-for="item in files" v-bind:key="item.name" > <v-list-tile v-for="item in xfiles" v-bind:key="item.name" >
<v-list-tile-avatar> <v-list-tile-avatar avatar @click.prevent.stop="item.selected =! item.selected ">
<v-icon v-bind:class="[item.iconClass]">{{ item.icon }}</v-icon> <v-icon v-bind:class="[item.iconClass]">{{ itemIcon(item) }}</v-icon>
</v-list-tile-avatar> </v-list-tile-avatar>
<v-list-tile-content @click="file(item.name)"> <v-list-tile-content @click="file(item.name)">
<v-list-tile-title >{{ item.name }}</v-list-tile-title> <v-list-tile-title >{{ item.name }}</v-list-tile-title>
@ -113,6 +114,7 @@
</v-navigation-drawer> </v-navigation-drawer>
</v-card> </v-card>
<v-progress-linear v-if="busy" v-bind:indeterminate="true" height="2"></v-progress-linear>
</v-container> </v-container>
</template> </template>
@ -122,18 +124,17 @@
data(){ data(){
return { return {
url: "", url: "",
folders: [], items: [],
files: [],
q: "", q: "",
busy: false, busy: false,
showInfo: false, showInfo: false,
selected: null, selected: [],
buttons: [ buttons: [
{method: this.todo, icon: "view_quilt"}, {method: this.todo, icon: "view_quilt"},
{method: this.add, icon: "add"}, {method: this.add, icon: "add"},
{method: this.todo, icon: "refresh"}, {method: this.load, icon: "refresh"},
{method: this.todo, icon: "sort"}, {method: this.todo, icon: "sort"},
{method: this.todo, icon: "select_all"} {method: this.selectAll, icon: "select_all"}
], ],
selopts: [ selopts: [
{method: this.todo, icon: "delete"}, {method: this.todo, icon: "delete"},
@ -153,12 +154,12 @@ selopts: [
folder (item) { folder (item) {
this.url=this.url+item.name+"/" this.url=this.url+item.name+"/"
}, },
load(url){ load(){
var url=this.url
this.busy=true this.busy=true
HTTP.get("collection",{params:{url:url,protocol:this.protocol}}) HTTP.get("collection",{params:{url:url,protocol:this.protocol}})
.then(r=>{ .then(r=>{
this.folders=r.data.folders this.items=r.data.items
this.files=r.data.files
this.busy=false this.busy=false
}) })
.catch(error=> { .catch(error=> {
@ -169,8 +170,7 @@ selopts: [
}, },
action(b){ action(b){
alert(b.icon) b.method(b.icon)
b.method()
}, },
add(){ add(){
alert("add") alert("add")
@ -191,13 +191,28 @@ selopts: [
this.$router.push({ name: 'jobShow', params: {job:job }}) this.$router.push({ name: 'jobShow', params: {job:job }})
}) })
}, },
todo(){ todo(icon){
alert("todo") alert("todo: " + icon)
},
itemIcon(item){
return item.selected?"check_circle":"folder"
},
selectAll(){
this.items.forEach(item=>{item.selected=true})
},
selectNone(){
this.items.forEach(item=>{item.selected=false})
} }
}, },
computed: { computed: {
icon(){ icon(){
return (this.protocol=="basexdb")?"developer_mode":"folder" return (this.protocol=="xmldb")?"developer_mode":"folder"
},
xfiles(){
return this.items.filter(item=>{return item.type!="folder"})
},
xfolders(){
return this.items.filter(item=>{return item.type=="folder"})
}, },
// array of {name:"that", path:"/this/that/"} for url // array of {name:"that", path:"/this/that/"} for url
crumbs(){ crumbs(){
@ -206,6 +221,9 @@ selopts: [
function(v,i,a){return {name:v, path:"/"+a.slice(0,i+1).join("/")+"/"}} function(v,i,a){return {name:v, path:"/"+a.slice(0,i+1).join("/")+"/"}}
) )
return a return a
},
selCount(){
return this.items.reduce((acc,item)=>{return acc+(item.selected?1:0)},0)
} }
}, },
watch:{ watch:{
@ -216,14 +234,14 @@ selopts: [
//console.log("ROUTE",vnew,vold) //console.log("ROUTE",vnew,vold)
var url=this.$route.query.url var url=this.$route.query.url
this.url=url?url:"/"; this.url=url?url:"/";
if(vnew.query.url != vold.query.url) this.load(this.url) if(vnew.query.url != vold.query.url) this.load()
} }
}, },
created:function(){ created:function(){
var url=this.$route.query.url var url=this.$route.query.url
this.url=url?url:"/"; this.url=url?url:"/";
this.q=this.$route.query.q || this.q this.q=this.$route.query.q || this.q
this.load(this.url) this.load()
} }
} }
</script> </script>

View file

@ -221,7 +221,7 @@ v-on:annotation="annotation"></vue-ace>
}) })
}, },
showfiles(){ showfiles(){
var target=this.protocol="basexdb"?"database":"files"; var target=this.protocol="xmldb"?"database":"files";
router.push({ path: target, query: { url: this.path.join("/"),protocol:this.protocol }}) router.push({ path: target, query: { url: this.path.join("/"),protocol:this.protocol }})
}, },
beautify(){ beautify(){
@ -267,7 +267,7 @@ v-on:annotation="annotation"></vue-ace>
}, },
computed:{ computed:{
icon(){ icon(){
return (this.protocol=="basexdb")?"account_balance":"folder" return (this.protocol=="xmldb")?"account_balance":"folder"
} }
}, },
created(){ created(){

View file

@ -25,7 +25,7 @@ function vue-api:edit-get($url as xs:string,$protocol as xs:string)
{ {
let $reader := map{ let $reader := map{
"webfile":vue-api:get-webfile#1, "webfile":vue-api:get-webfile#1,
"basexdb":vue-api:get-basexdb#1 "xmldb":vue-api:get-basexdb#1
} }
return $reader($protocol)($url) return $reader($protocol)($url)
}; };

View file

@ -2,6 +2,13 @@
<template id="task"> <template id="task">
<v-container fluid> <v-container fluid>
<h3>Available Tasks</h3> <h3>Available Tasks</h3>
<v-snackbar
:bottom="true"
v-model="snackbar"
>
got tasks, currently ignoring
<v-btn flat class="pink--text" @click.native="snackbar = false">Close</v-btn>
</v-snackbar>
<ul> <ul>
<li v-for="task in tasks" :key="task.to"> <li v-for="task in tasks" :key="task.to">
<router-link :to="task.to" v-text="task.text"></router-link> <router-link :to="task.to" v-text="task.text"></router-link>
@ -17,14 +24,15 @@
{to: "tasks/model", text: "model"}, {to: "tasks/model", text: "model"},
{to: "tasks/xqdoc", text: "xqdoc"}, {to: "tasks/xqdoc", text: "xqdoc"},
{to: "tasks/vuecompile", text: "vue compile"} {to: "tasks/vuecompile", text: "vue compile"}
] ],
snackbar: false
} }
}, },
methods:{ methods:{
getTasks(){ getTasks(){
HTTP.get("tasks/list") HTTP.get("tasks/list")
.then(r=>{ .then(r=>{
alert("tasks http") this.snackbar=true
}) })
} }
}, },

View file

@ -32,10 +32,10 @@ as element(c:directory)
error(xs:QName('ufile:badpath'),$path) error(xs:QName('ufile:badpath'),$path)
}; };
declare function ufile:basexdb($url as xs:string) declare function ufile:xmldb($url as xs:string)
as element(c:directory) as element(c:directory)
{ {
<c:directory name="" xml:base="basexdb:/" last-modified="2017-07-01T13:39:38.98691Z" size="4096">{ <c:directory name="" xml:base="xmldb:/" last-modified="2017-07-01T13:39:38.98691Z" size="4096">{
if($url="/") then if($url="/") then
db:list()! db:list()!
<c:directory name="{db:property(.,'name')}" <c:directory name="{db:property(.,'name')}"

View file

@ -1,5 +1,5 @@
(: entity access maps (: entity access maps
: auto generated from xml files in entities folder at: 2017-09-08T12:06:30.901+01:00 : auto generated from xml files in entities folder at: 2017-09-17T13:41:02.538+01:00
:) :)
module namespace entity = 'quodatum.models.generated'; module namespace entity = 'quodatum.models.generated';

File diff suppressed because it is too large Load diff

View file

@ -22,17 +22,20 @@
</head> </head>
<body> <body>
<div id="app"> <div id="app">
<h3><code>vue-poc</code> <small>(v0.1)</small> </h3>
<div class="spinner"> <div class="spinner">
<div class="rect1"></div> <div class="rect1"></div>
<div class="rect2"></div> <div class="rect2"></div>
<div class="rect3"></div> <div class="rect3"></div>
<div class="rect4"></div> <div class="rect4"></div>
<div class="rect5"></div> <div class="rect5"></div>
<span>loading...</span>
</div> </div>
</div> </div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.1/vue.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.4/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/vue-router/2.7.0/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/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://cdnjs.cloudflare.com/ajax/libs/qs/6.4.0/qs.js"></script>
<script src="https://unpkg.com/vuetify@0.15.7/dist/vuetify.min.js"></script> <script src="https://unpkg.com/vuetify@0.15.7/dist/vuetify.min.js"></script>