File edit modal
This commit is contained in:
@@ -7,7 +7,12 @@ function EditWindow() {
|
||||
)
|
||||
|
||||
let clone = document.getElementById("tpl_edit_file").content.cloneNode(true)
|
||||
this.notification = clone.querySelector(".edit_file_notification")
|
||||
this.fileNameField = clone.querySelector(".edit_file_name_field")
|
||||
|
||||
clone.querySelector(".btn_delete_file").addEventListener("click", () => { this.deleteFile() })
|
||||
clone.querySelector(".edit_file_name_form").addEventListener("submit", e => { this.renameFile(e) })
|
||||
|
||||
this.modal.setBody(clone)
|
||||
|
||||
this.btnEdit = document.getElementById("btn_edit")
|
||||
@@ -29,6 +34,8 @@ EditWindow.prototype.toggle = function() {
|
||||
EditWindow.prototype.setFile = function (file) {
|
||||
this.file = file
|
||||
this.modal.setTitle("Editing " + file.name)
|
||||
this.notification.style.display = "none"
|
||||
this.fileNameField.value = file.name
|
||||
|
||||
if (this.file.can_edit) {
|
||||
this.btnEdit.style.display = ""
|
||||
@@ -37,16 +44,44 @@ EditWindow.prototype.setFile = function(file) {
|
||||
}
|
||||
}
|
||||
|
||||
EditWindow.prototype.deleteFile = function() {
|
||||
EditWindow.prototype.notify = function (success, content) {
|
||||
this.notification.style.display = ""
|
||||
this.notification.classList = "edit_file_notification " + (success ? "highlight_green" : "highlight_red")
|
||||
this.notification.innerHTML = content
|
||||
}
|
||||
|
||||
EditWindow.prototype.deleteFile = async function () {
|
||||
if (!confirm("Are you sure you want to delete '" + this.file.name + "'?")) {
|
||||
return
|
||||
}
|
||||
|
||||
fetch(
|
||||
this.file.get_href, {method: "DELETE"}
|
||||
).then(resp => {
|
||||
this.modal.setBody(document.createTextNode("This file has been deleted"))
|
||||
}).catch(err => {
|
||||
alert("Error! Could not delete file")
|
||||
})
|
||||
try {
|
||||
const resp = await fetch(this.file.get_href, { method: "DELETE" });
|
||||
if (resp.status >= 400) {
|
||||
throw (await resp.json()).message
|
||||
}
|
||||
|
||||
this.notify(true, "This file has been deleted, you can close the page")
|
||||
} catch (err) {
|
||||
this.notify(false, "Could not delete file: " + err)
|
||||
}
|
||||
}
|
||||
|
||||
EditWindow.prototype.renameFile = async function (e) {
|
||||
e.preventDefault()
|
||||
|
||||
const form = new FormData()
|
||||
form.append("action", "rename")
|
||||
form.append("name", this.fileNameField.value)
|
||||
|
||||
try {
|
||||
const resp = await fetch(this.file.get_href, { method: "POST", body: form });
|
||||
if (resp.status >= 400) {
|
||||
throw (await resp.json()).message
|
||||
}
|
||||
|
||||
this.notify(true, "File name has been changed. Reload the page to see the changes")
|
||||
} catch (err) {
|
||||
this.notify(false, "Could not change file name: " + err)
|
||||
}
|
||||
}
|
||||
|
@@ -87,8 +87,7 @@ Viewer.prototype.setFile = function(file) {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
||||
body: "token=" + this.viewToken
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
// Clean up the previous viewer if possible
|
||||
@@ -176,6 +175,9 @@ Viewer.prototype.keyboardEvent = function(evt) {
|
||||
if (evt.ctrlKey || evt.altKey || evt.metaKey) {
|
||||
return // prevent custom shortcuts from interfering with system shortcuts
|
||||
}
|
||||
if (document.activeElement.type && document.activeElement.type === "text") {
|
||||
return // Prevent shortcuts from interfering with input fields
|
||||
}
|
||||
|
||||
console.debug("Key pressed: " + evt.keyCode)
|
||||
switch (evt.keyCode) {
|
||||
@@ -247,8 +249,8 @@ function fileFromAPIResp(resp) {
|
||||
function fileFromSkyNet(resp) {
|
||||
let file = fileFromAPIResp(resp)
|
||||
file.icon_href = "/res/img/mime/empty.png"
|
||||
file.get_href = "https://skydrain.net/file/"+resp.id
|
||||
file.download_href = "https://skydrain.net/file/"+resp.id+"?attachment=1"
|
||||
file.get_href = "https://siasky.net/file/" + resp.id
|
||||
file.download_href = "https://siasky.net/file/" + resp.id + "?attachment=1"
|
||||
file.view_href = ""
|
||||
file.timeseries_href = ""
|
||||
file.stats_href = ""
|
||||
|
@@ -244,7 +244,15 @@
|
||||
</template>
|
||||
|
||||
<template id="tpl_edit_file">
|
||||
<h3>Delete file</h3>
|
||||
<div class="edit_file_notification" style="display: none;"></div>
|
||||
<h3>Rename</h3>
|
||||
<form class="edit_file_name_form" style="display: flex; width: 100%">
|
||||
<input class="edit_file_name_field" type="text" style="flex: 1 1 auto"/>
|
||||
<button class="edit_file_name_submit" role="submit" style="flex: 0 0 auto">
|
||||
<i class="icon">save</i> Save
|
||||
</button>
|
||||
</form>
|
||||
<h3>Delete</h3>
|
||||
<p>
|
||||
When you delete a file it cannot be recovered.
|
||||
Nobody will be able to download it and the link will
|
||||
|
@@ -1,40 +1,33 @@
|
||||
{{ define "filesystem" }}<!DOCTYPE html>
|
||||
{{define "filesystem"}}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
{{template "meta_tags" .Title}}
|
||||
<title>{{.Title}}</title>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
{{template "user_style" .}}
|
||||
<style>{{template "file_manager.css" .}}</style>
|
||||
<script>var apiEndpoint = '{{.APIEndpoint}}';</script>
|
||||
|
||||
<link rel="icon" sizes="32x32" href="/res/img/pixeldrain_32.png" />
|
||||
<link rel="icon" sizes="128x128" href="/res/img/pixeldrain_128.png" />
|
||||
<link rel="icon" sizes="152x152" href="/res/img/pixeldrain_152.png" />
|
||||
<link rel="icon" sizes="180x180" href="/res/img/pixeldrain_180.png" />
|
||||
<link rel="icon" sizes="192x192" href="/res/img/pixeldrain_192.png" />
|
||||
<link rel="icon" sizes="196x196" href="/res/img/pixeldrain_196.png" />
|
||||
<link rel="icon" sizes="256x256" href="/res/img/pixeldrain_256.png" />
|
||||
<link rel="apple-touch-icon" sizes="152x152" href="/res/img/pixeldrain_152.png" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/res/img/pixeldrain_180.png" />
|
||||
<link rel="shortcut icon" sizes="196x196" href="/res/img/pixeldrain_196.png" />
|
||||
<meta name="theme-color" content="#75AD38"/>
|
||||
|
||||
{{ template "opengraph" .OGData }}
|
||||
<script>
|
||||
const initialNode = {{.Other}};
|
||||
window.api_endpoint = '{{.APIEndpoint}}';
|
||||
</script>
|
||||
|
||||
<link rel='stylesheet' href='/res/svelte/filesystem.css'>
|
||||
<script defer src='/res/svelte/filesystem.js'></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
{{template "page_top" .}}
|
||||
|
||||
<h1>{{ .Title}}</h1>
|
||||
|
||||
<div class="page_content">
|
||||
<div class="limit_width">
|
||||
<h2>
|
||||
<a href="/fs">Buckets</a>
|
||||
{{ range $node := .Other.Path }}
|
||||
/ <a href="{{ $node.HREF }}">{{ $node.Name }}</a>
|
||||
{{ end }}
|
||||
{{ if ne .Other.Base.Name "" }}
|
||||
/ {{ .Other.Base.Name }}
|
||||
{{ end }}
|
||||
</h2>
|
||||
|
||||
{{ range $node := .Other.Children }}
|
||||
<a class="node" href="{{ $node.HREF }}"><div>
|
||||
<img src="{{ $node.Icon }}"/>
|
||||
<span>{{ $node.Name }}</span>
|
||||
</div></a>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{template "page_bottom" .}}
|
||||
{{template "analytics"}}
|
||||
</body>
|
||||
<body></body>
|
||||
</html>
|
||||
{{end}}
|
||||
|
@@ -1,33 +0,0 @@
|
||||
{{define "filesystem_svelte"}}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>{{.Title}}</title>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
{{template "user_style" .}}
|
||||
|
||||
<link rel="icon" sizes="32x32" href="/res/img/pixeldrain_32.png" />
|
||||
<link rel="icon" sizes="128x128" href="/res/img/pixeldrain_128.png" />
|
||||
<link rel="icon" sizes="152x152" href="/res/img/pixeldrain_152.png" />
|
||||
<link rel="icon" sizes="180x180" href="/res/img/pixeldrain_180.png" />
|
||||
<link rel="icon" sizes="192x192" href="/res/img/pixeldrain_192.png" />
|
||||
<link rel="icon" sizes="196x196" href="/res/img/pixeldrain_196.png" />
|
||||
<link rel="icon" sizes="256x256" href="/res/img/pixeldrain_256.png" />
|
||||
<link rel="apple-touch-icon" sizes="152x152" href="/res/img/pixeldrain_152.png" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/res/img/pixeldrain_180.png" />
|
||||
<link rel="shortcut icon" sizes="196x196" href="/res/img/pixeldrain_196.png" />
|
||||
<meta name="theme-color" content="#75AD38"/>
|
||||
|
||||
{{ template "opengraph" .OGData }}
|
||||
<script>
|
||||
const initialNode = {{.Other}};
|
||||
window.api_endpoint = '{{.APIEndpoint}}';
|
||||
</script>
|
||||
|
||||
<link rel='stylesheet' href='/res/svelte/filesystem.css'>
|
||||
<script defer src='/res/svelte/filesystem.js'></script>
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
||||
{{end}}
|
@@ -13,8 +13,7 @@ let new_bucket_name
|
||||
const get_buckets = async () => {
|
||||
loading = true;
|
||||
try {
|
||||
let resp = await fs_get_buckets();
|
||||
buckets = resp.buckets;
|
||||
buckets = await fs_get_buckets();
|
||||
} catch (err) {
|
||||
alert(err);
|
||||
} finally {
|
||||
|
@@ -28,7 +28,7 @@ func (wc *WebController) adminGlobalsForm(td *TemplateData, r *http.Request) (f
|
||||
return f
|
||||
}
|
||||
var globalsMap = make(map[string]string)
|
||||
for _, v := range globals.Globals {
|
||||
for _, v := range globals {
|
||||
f.Fields = append(f.Fields, Field{
|
||||
Name: v.Key,
|
||||
DefaultValue: v.Value,
|
||||
|
@@ -225,7 +225,7 @@ func (wc *WebController) serveSkynetViewer(w http.ResponseWriter, r *http.Reques
|
||||
|
||||
// Get the first few bytes from the file to probe the content type and
|
||||
// length
|
||||
rq, err := http.NewRequest("GET", "https://skydrain.net/file/"+p.ByName("id"), nil)
|
||||
rq, err := http.NewRequest("GET", "https://siasky.net/file/"+p.ByName("id"), nil)
|
||||
if err != nil {
|
||||
log.Warn("Failed to make request to sia portal: %s", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
|
@@ -3,123 +3,12 @@ package webcontroller
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"fornaxian.tech/pixeldrain_server/api/restapi/apitype"
|
||||
"github.com/Fornaxian/log"
|
||||
"github.com/julienschmidt/httprouter"
|
||||
)
|
||||
|
||||
type filesystemPath struct {
|
||||
Path []filesystemNode
|
||||
Base filesystemNode
|
||||
Children []filesystemNode
|
||||
}
|
||||
|
||||
type filesystemNode struct {
|
||||
HREF string
|
||||
Icon string
|
||||
Name string
|
||||
Type string
|
||||
FileSize int64
|
||||
FileType string
|
||||
}
|
||||
|
||||
func convFilesystemNode(bucketID string, v apitype.FilesystemNode) (node filesystemNode) {
|
||||
node = filesystemNode{
|
||||
HREF: "/fs/" + bucketID + v.Path,
|
||||
Type: v.Type,
|
||||
Name: v.Name,
|
||||
FileSize: v.FileSize,
|
||||
FileType: v.FileType,
|
||||
}
|
||||
if node.Type == "dir" {
|
||||
node.Icon = "/res/img/mime/folder.png"
|
||||
} else {
|
||||
node.Icon = "/res/img/mime/empty.png"
|
||||
}
|
||||
|
||||
return node
|
||||
}
|
||||
|
||||
func (wc *WebController) serveFilesystem(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
||||
var err error
|
||||
var td = wc.newTemplateData(w, r)
|
||||
var path = strings.TrimPrefix(p.ByName("path"), "/")
|
||||
var fsPath filesystemPath
|
||||
|
||||
if path == "" {
|
||||
buckets, err := td.PixelAPI.GetFilesystemBuckets()
|
||||
if err != nil {
|
||||
if err.Error() == "not_found" {
|
||||
wc.templates.Get().ExecuteTemplate(w, "404", td)
|
||||
} else if err.Error() == "authentication_required" {
|
||||
http.Redirect(w, r, "/login", http.StatusSeeOther)
|
||||
} else {
|
||||
log.Error("Failed to get buckets: %s", err)
|
||||
wc.templates.Get().ExecuteTemplate(w, "500", td)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
for _, v := range buckets.Buckets {
|
||||
fsPath.Children = append(fsPath.Children, filesystemNode{
|
||||
HREF: "/fs/" + v.ID,
|
||||
Icon: "/res/img/mime/folder-remote.png",
|
||||
Type: "dir",
|
||||
Name: v.Name,
|
||||
FileSize: 0,
|
||||
FileType: "inode/directory",
|
||||
})
|
||||
}
|
||||
} else {
|
||||
log.Info("getting path %s", path)
|
||||
node, err := td.PixelAPI.GetFilesystemPath(path)
|
||||
if err != nil {
|
||||
if err.Error() == "not_found" || err.Error() == "path_not_found" {
|
||||
wc.templates.Get().ExecuteTemplate(w, "404", td)
|
||||
} else {
|
||||
log.Error("Failed to get path: %s", err)
|
||||
wc.templates.Get().ExecuteTemplate(w, "500", td)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if node.Base.Type == "file" {
|
||||
http.Redirect(w, r, "/api/filesystem/"+path, http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
||||
for _, v := range node.Parents {
|
||||
fsPath.Path = append(fsPath.Path, convFilesystemNode(node.Bucket.ID, v))
|
||||
}
|
||||
|
||||
fsPath.Base = convFilesystemNode(node.Bucket.ID, node.Base)
|
||||
|
||||
for _, v := range node.Base.Children {
|
||||
fsPath.Children = append(fsPath.Children, convFilesystemNode(node.Bucket.ID, v))
|
||||
}
|
||||
}
|
||||
|
||||
sort.Slice(fsPath.Children, func(i, j int) (less bool) {
|
||||
// Directories always come first. Make sure we're comparing apples with
|
||||
// apples
|
||||
if fsPath.Children[i].Type != fsPath.Children[j].Type {
|
||||
return fsPath.Children[i].Type == "dir"
|
||||
}
|
||||
|
||||
return fsPath.Children[i].Name < fsPath.Children[j].Name
|
||||
})
|
||||
|
||||
td.Title = "Filesystem"
|
||||
td.Other = fsPath
|
||||
err = wc.templates.Get().ExecuteTemplate(w, "filesystem", td)
|
||||
if err != nil && !strings.Contains(err.Error(), "broken pipe") {
|
||||
log.Error("Error executing template filesystem: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (wc *WebController) serveDirectory(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
||||
var err error
|
||||
var td = wc.newTemplateData(w, r)
|
||||
@@ -138,7 +27,7 @@ func (wc *WebController) serveDirectory(w http.ResponseWriter, r *http.Request,
|
||||
|
||||
td.Title = fmt.Sprintf("%s ~ pixeldrain", node.Base.Name)
|
||||
td.Other = node
|
||||
err = wc.templates.Get().ExecuteTemplate(w, "filesystem_svelte", td)
|
||||
err = wc.templates.Get().ExecuteTemplate(w, "filesystem", td)
|
||||
if err != nil && !strings.Contains(err.Error(), "broken pipe") {
|
||||
log.Error("Error executing template filesystem: %s", err)
|
||||
}
|
||||
|
@@ -114,6 +114,7 @@ func New(
|
||||
{GET, "u/:id" /* */, wc.serveFileViewer},
|
||||
{GET, "u/:id/preview" /* */, wc.serveFilePreview},
|
||||
{GET, "l/:id" /* */, wc.serveListViewer},
|
||||
{GET, "d/*path" /* */, wc.serveDirectory},
|
||||
{GET, "s/:id" /* */, wc.serveSkynetViewer},
|
||||
{GET, "t" /* */, wc.serveTemplate("text_editor", false)},
|
||||
{GET, "donation" /* */, wc.serveMarkdown("donation.md", false)},
|
||||
@@ -150,10 +151,6 @@ func New(
|
||||
{GET, "user/password_reset_confirm" /**/, wc.serveForm(wc.passwordResetConfirmForm, false)},
|
||||
{PST, "user/password_reset_confirm" /**/, wc.serveForm(wc.passwordResetConfirmForm, false)},
|
||||
|
||||
// Filesystem
|
||||
{GET, "fs/*path", wc.serveFilesystem},
|
||||
{GET, "d/*path", wc.serveDirectory},
|
||||
|
||||
{GET, "patreon_activate" /* */, wc.serveForm(wc.patreonLinkForm, true)},
|
||||
{PST, "patreon_activate" /* */, wc.serveForm(wc.patreonLinkForm, true)},
|
||||
|
||||
|
Reference in New Issue
Block a user