File uploads
This commit is contained in:
parent
33b10e6527
commit
8a3970645f
5
file.go
5
file.go
@ -12,7 +12,7 @@ import (
|
|||||||
type File struct {
|
type File struct {
|
||||||
ID int
|
ID int
|
||||||
UserID int `db:"user_id"`
|
UserID int `db:"user_id"`
|
||||||
NodeID int
|
NodeID int `db:"node_id"`
|
||||||
Filename string
|
Filename string
|
||||||
Size int64
|
Size int64
|
||||||
MIME string
|
MIME string
|
||||||
@ -49,7 +49,7 @@ func (session Session) AddFile(file *File) (err error) { // {{{
|
|||||||
func (session Session) Files(nodeID int) (files []File, err error) { // {{{
|
func (session Session) Files(nodeID int) (files []File, err error) { // {{{
|
||||||
var rows *sqlx.Rows
|
var rows *sqlx.Rows
|
||||||
rows, err = db.Queryx(
|
rows, err = db.Queryx(
|
||||||
`SELECT * FROM files WHERE user_id = $1 AND node_id = $2`,
|
`SELECT * FROM file WHERE user_id = $1 AND node_id = $2`,
|
||||||
session.UserID,
|
session.UserID,
|
||||||
nodeID,
|
nodeID,
|
||||||
)
|
)
|
||||||
@ -58,6 +58,7 @@ func (session Session) Files(nodeID int) (files []File, err error) { // {{{
|
|||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
||||||
|
files = []File{}
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
file := File{}
|
file := File{}
|
||||||
if err = rows.StructScan(&file); err != nil {
|
if err = rows.StructScan(&file); err != nil {
|
||||||
|
4
node.go
4
node.go
@ -17,6 +17,7 @@ type Node struct {
|
|||||||
Updated time.Time
|
Updated time.Time
|
||||||
Children []Node
|
Children []Node
|
||||||
Crumbs []Node
|
Crumbs []Node
|
||||||
|
Files []File
|
||||||
Complete bool
|
Complete bool
|
||||||
Level int
|
Level int
|
||||||
}
|
}
|
||||||
@ -108,6 +109,7 @@ func (session Session) RootNode() (node Node, err error) {// {{{
|
|||||||
node.Complete = true
|
node.Complete = true
|
||||||
node.Children = []Node{}
|
node.Children = []Node{}
|
||||||
node.Crumbs = []Node{}
|
node.Crumbs = []Node{}
|
||||||
|
node.Files = []File{}
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
row := Node{}
|
row := Node{}
|
||||||
if err = rows.StructScan(&row); err != nil {
|
if err = rows.StructScan(&row); err != nil {
|
||||||
@ -202,6 +204,7 @@ func (session Session) Node(nodeID int) (node Node, err error) {// {{{
|
|||||||
}
|
}
|
||||||
|
|
||||||
node.Crumbs, err = session.NodeCrumbs(node.ID)
|
node.Crumbs, err = session.NodeCrumbs(node.ID)
|
||||||
|
node.Files, err = session.Files(node.ID)
|
||||||
|
|
||||||
return
|
return
|
||||||
}// }}}
|
}// }}}
|
||||||
@ -271,6 +274,7 @@ func (session Session) CreateNode(parentID int, name string) (node Node, err err
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
node.Children = []Node{}
|
node.Children = []Node{}
|
||||||
|
node.Files = []File{}
|
||||||
node.Complete = true
|
node.Complete = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,17 +193,41 @@ header .menu {
|
|||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
font-size: 0.85em;
|
font-size: 0.85em;
|
||||||
color: #333;
|
color: #333;
|
||||||
width: 100ex;
|
width: 900px;
|
||||||
resize: none;
|
resize: none;
|
||||||
border: none;
|
border: none;
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
.node-content[contenteditable] {
|
|
||||||
outline: 0px solid transparent;
|
|
||||||
}
|
|
||||||
.node-content:invalid {
|
.node-content:invalid {
|
||||||
border-bottom: 1px solid #eee;
|
background: #f5f5f5;
|
||||||
border-radius: 8px;
|
}
|
||||||
|
#file-section {
|
||||||
|
justify-self: center;
|
||||||
|
width: 900px;
|
||||||
|
margin-top: 32px;
|
||||||
|
padding: 32px;
|
||||||
|
background: #f5f5f5;
|
||||||
|
}
|
||||||
|
#file-section .header {
|
||||||
|
font-weight: bold;
|
||||||
|
color: #000;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
#file-section .files {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr min-content;
|
||||||
|
grid-gap: 8px 16px;
|
||||||
|
color: #444;
|
||||||
|
font-size: 0.85em;
|
||||||
|
}
|
||||||
|
#file-section .files .filename {
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
#file-section .files .size {
|
||||||
|
white-space: nowrap;
|
||||||
|
text-align: right;
|
||||||
}
|
}
|
||||||
.tree {
|
.tree {
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
@ -213,4 +237,8 @@ header .menu {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
justify-self: start;
|
justify-self: start;
|
||||||
}
|
}
|
||||||
|
#file-section {
|
||||||
|
width: 100%;
|
||||||
|
justify-self: start;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -75,6 +75,8 @@ export class NodeUI extends Component {
|
|||||||
<div class="node-name">${node.Name}</div>
|
<div class="node-name">${node.Name}</div>
|
||||||
<${NodeContent} key=${node.ID} content=${node.Content} ref=${this.nodeContent} />
|
<${NodeContent} key=${node.ID} content=${node.Content} ref=${this.nodeContent} />
|
||||||
` : html``}
|
` : html``}
|
||||||
|
|
||||||
|
<${NodeFiles} node=${this.node.value} />
|
||||||
`
|
`
|
||||||
}//}}}
|
}//}}}
|
||||||
componentDidMount() {//{{{
|
componentDidMount() {//{{{
|
||||||
@ -212,6 +214,39 @@ class NodeContent extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class NodeFiles extends Component {
|
class NodeFiles extends Component {
|
||||||
|
render({ node }) {//{{{
|
||||||
|
if(node.Files === null || node.Files.length == 0)
|
||||||
|
return
|
||||||
|
|
||||||
|
let files = node.Files
|
||||||
|
.sort((a, b)=>{
|
||||||
|
if(a.Filename.toUpperCase() < b.Filename.toUpperCase()) return -1
|
||||||
|
if(a.Filename.toUpperCase() > b.Filename.toUpperCase()) return 1
|
||||||
|
return 0
|
||||||
|
})
|
||||||
|
.map(file=>
|
||||||
|
html`
|
||||||
|
<div class="filename">${file.Filename}</div>
|
||||||
|
<div class="size">${this.formatSize(file.Size)}</div>
|
||||||
|
`
|
||||||
|
)
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<div id="file-section">
|
||||||
|
<div class="header">Files</div>
|
||||||
|
<div class="files">
|
||||||
|
${files}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
}//}}}
|
||||||
|
formatSize(size) {//{{{
|
||||||
|
if(size < 1048576) {
|
||||||
|
return `${Math.round(size / 1024)} KiB`
|
||||||
|
} else {
|
||||||
|
return `${Math.round(size / 1048576)} MiB`
|
||||||
|
}
|
||||||
|
}//}}}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Node {
|
class Node {
|
||||||
@ -224,6 +259,7 @@ class Node {
|
|||||||
this.Content = ''
|
this.Content = ''
|
||||||
this.Children = []
|
this.Children = []
|
||||||
this.Crumbs = []
|
this.Crumbs = []
|
||||||
|
this.Files = []
|
||||||
}//}}}
|
}//}}}
|
||||||
retrieve(callback) {//{{{
|
retrieve(callback) {//{{{
|
||||||
this.app.request('/node/retrieve', { ID: this.ID })
|
this.app.request('/node/retrieve', { ID: this.ID })
|
||||||
@ -234,6 +270,7 @@ class Node {
|
|||||||
this.Content = res.Node.Content
|
this.Content = res.Node.Content
|
||||||
this.Children = res.Node.Children
|
this.Children = res.Node.Children
|
||||||
this.Crumbs = res.Node.Crumbs
|
this.Crumbs = res.Node.Crumbs
|
||||||
|
this.Files = res.Node.Files
|
||||||
callback(this)
|
callback(this)
|
||||||
})
|
})
|
||||||
.catch(this.app.responseError)
|
.catch(this.app.responseError)
|
||||||
@ -294,8 +331,8 @@ class Menu extends Component {
|
|||||||
}//}}}
|
}//}}}
|
||||||
}
|
}
|
||||||
class UploadUI extends Component {
|
class UploadUI extends Component {
|
||||||
constructor() {//{{{
|
constructor(props) {//{{{
|
||||||
super()
|
super(props)
|
||||||
this.file = createRef()
|
this.file = createRef()
|
||||||
this.filelist = signal([])
|
this.filelist = signal([])
|
||||||
this.fileRefs = []
|
this.fileRefs = []
|
||||||
@ -339,9 +376,14 @@ class UploadUI extends Component {
|
|||||||
progress=>{
|
progress=>{
|
||||||
this.progressRefs[i].current.innerHTML = `${progress}%`
|
this.progressRefs[i].current.innerHTML = `${progress}%`
|
||||||
},
|
},
|
||||||
()=>{
|
res=>{
|
||||||
|
this.props.nodeui.node.value.Files.push(res.File)
|
||||||
|
this.props.nodeui.forceUpdate()
|
||||||
|
|
||||||
this.fileRefs[i].current.classList.add("done")
|
this.fileRefs[i].current.classList.add("done")
|
||||||
this.progressRefs[i].current.classList.add("done")
|
this.progressRefs[i].current.classList.add("done")
|
||||||
|
|
||||||
|
this.props.nodeui.upload.value = false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}//}}}
|
}//}}}
|
||||||
@ -368,7 +410,7 @@ class UploadUI extends Component {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
doneCallback()
|
doneCallback(response)
|
||||||
})
|
})
|
||||||
|
|
||||||
request.upload.addEventListener('progress', evt=>{
|
request.upload.addEventListener('progress', evt=>{
|
||||||
|
@ -227,18 +227,46 @@ header {
|
|||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
font-size: 0.85em;
|
font-size: 0.85em;
|
||||||
color: #333;
|
color: #333;
|
||||||
width: 100ex;
|
width: 900px;
|
||||||
resize: none;
|
resize: none;
|
||||||
border: none;
|
border: none;
|
||||||
outline: none;
|
outline: none;
|
||||||
|
|
||||||
&[contenteditable] {
|
&:invalid {
|
||||||
outline: 0px solid transparent;
|
background: #f5f5f5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#file-section {
|
||||||
|
justify-self: center;
|
||||||
|
width: 900px;
|
||||||
|
margin-top: 32px;
|
||||||
|
padding: 32px;
|
||||||
|
background: #f5f5f5;
|
||||||
|
|
||||||
|
.header {
|
||||||
|
font-weight: bold;
|
||||||
|
color: #000;
|
||||||
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:invalid {
|
.files {
|
||||||
border-bottom: 1px solid #eee;
|
display: grid;
|
||||||
border-radius: 8px;
|
grid-template-columns: 1fr min-content;
|
||||||
|
grid-gap: 8px 16px;
|
||||||
|
color: #444;
|
||||||
|
font-size: 0.85em;
|
||||||
|
|
||||||
|
.filename {
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.size {
|
||||||
|
white-space: nowrap;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,4 +279,9 @@ header {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
justify-self: start;
|
justify-self: start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#file-section {
|
||||||
|
width: 100%;
|
||||||
|
justify-self: start;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user