Merge FilesystemAPI and FilesystemUtil to avoid circular dependencies
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
<script>
|
||||
import { fs_encode_path } from "./FilesystemUtil";
|
||||
<script lang="ts">
|
||||
import { fs_encode_path } from "./FilesystemAPI";
|
||||
import { FSNavigator } from "./FSNavigator";
|
||||
|
||||
export let nav
|
||||
export let nav: FSNavigator
|
||||
</script>
|
||||
|
||||
<div class="breadcrumbs">
|
||||
|
@@ -2,8 +2,7 @@
|
||||
import Chart from "../util/Chart.svelte";
|
||||
import { formatDataVolume, formatDate, formatThousands } from "../util/Formatting.svelte";
|
||||
import Modal from "../util/Modal.svelte";
|
||||
import { fs_timeseries } from "./FilesystemAPI";
|
||||
import { fs_path_url } from "./FilesystemUtil";
|
||||
import { fs_path_url, fs_timeseries } from "./FilesystemAPI";
|
||||
import { generate_share_path, generate_share_url } from "./Sharebar.svelte";
|
||||
import { color_by_name } from "../util/Util.svelte";
|
||||
import { tick } from "svelte";
|
||||
|
@@ -1,6 +1,5 @@
|
||||
import { fs_get_node, FSNode, FSPath, FSPermissions } from "./FilesystemAPI";
|
||||
import { fs_encode_path, fs_split_path } from "./FilesystemUtil";
|
||||
import { Writable } from "svelte/store"
|
||||
import { fs_get_node, fs_encode_path, fs_split_path, type FSNode, type FSPath, type FSPermissions } from "./FilesystemAPI";
|
||||
import { type Writable } from "svelte/store"
|
||||
|
||||
export class FSNavigator {
|
||||
// Parts of the raw API response
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<script>
|
||||
import { onMount } from "svelte";
|
||||
import { formatDataVolume, formatThousands } from "../util/Formatting.svelte"
|
||||
import { fs_path_url } from "./FilesystemUtil";
|
||||
import { fs_path_url } from "./FilesystemAPI";
|
||||
|
||||
export let nav
|
||||
|
||||
|
@@ -8,7 +8,7 @@ import DetailsWindow from './DetailsWindow.svelte';
|
||||
import FilePreview from './viewers/FilePreview.svelte';
|
||||
import SearchView from './SearchView.svelte';
|
||||
import UploadWidget from './upload_widget/UploadWidget.svelte';
|
||||
import { fs_path_url } from './FilesystemUtil';
|
||||
import { fs_path_url } from './FilesystemAPI';
|
||||
import { branding_from_path } from './edit_window/Branding.js'
|
||||
import Menu from './Menu.svelte';
|
||||
import { FSNavigator } from "./FSNavigator"
|
||||
|
@@ -1,69 +1,11 @@
|
||||
import { fs_path_url } from './FilesystemUtil'
|
||||
// Response types
|
||||
// ==============
|
||||
|
||||
export type GenericResponse = {
|
||||
value: string,
|
||||
message: string,
|
||||
}
|
||||
|
||||
export const fs_check_response = async (resp: Response) => {
|
||||
let text = await resp.text()
|
||||
if (resp.status >= 400) {
|
||||
let error: any
|
||||
try {
|
||||
error = JSON.parse(text) as GenericResponse
|
||||
} catch (err) {
|
||||
error = text
|
||||
}
|
||||
throw error
|
||||
}
|
||||
return JSON.parse(text)
|
||||
}
|
||||
|
||||
export type NodeOptions = {
|
||||
mode: number | undefined,
|
||||
created: Date | undefined,
|
||||
modified: Date | undefined,
|
||||
shared: boolean | undefined,
|
||||
|
||||
branding_enabled: boolean | undefined,
|
||||
brand_input_color: string | undefined,
|
||||
brand_highlight_color: string | undefined,
|
||||
brand_danger_color: string | undefined,
|
||||
brand_background_color: string | undefined,
|
||||
brand_body_color: string | undefined,
|
||||
brand_card_color: string | undefined,
|
||||
brand_header_image: string | undefined,
|
||||
brand_header_link: string | undefined,
|
||||
brand_background_image: string | undefined,
|
||||
}
|
||||
|
||||
// mkdir only supports the "mode" option
|
||||
export const fs_mkdir = async (path: string, opts: NodeOptions) => {
|
||||
const form = new FormData()
|
||||
form.append("action", "mkdir")
|
||||
|
||||
if (opts && opts.mode) {
|
||||
form.append("mode", opts.mode.toFixed(0))
|
||||
}
|
||||
|
||||
return await fs_check_response(
|
||||
await fetch(fs_path_url(path), { method: "POST", body: form })
|
||||
)
|
||||
}
|
||||
|
||||
export const fs_mkdirall = async (path: string, opts: NodeOptions) => {
|
||||
const form = new FormData()
|
||||
form.append("action", "mkdirall")
|
||||
|
||||
if (opts && opts.mode) {
|
||||
form.append("mode", opts.mode.toFixed(0))
|
||||
}
|
||||
|
||||
return await fs_check_response(
|
||||
await fetch(fs_path_url(path), { method: "POST", body: form })
|
||||
)
|
||||
}
|
||||
|
||||
export type FSPath = {
|
||||
path: Array<FSNode>,
|
||||
base_index: number,
|
||||
@@ -100,6 +42,58 @@ export type FSPermissions = {
|
||||
delete: boolean,
|
||||
}
|
||||
|
||||
// API parameters
|
||||
// ==============
|
||||
|
||||
export type NodeOptions = {
|
||||
mode: number | undefined,
|
||||
created: Date | undefined,
|
||||
modified: Date | undefined,
|
||||
shared: boolean | undefined,
|
||||
|
||||
branding_enabled: boolean | undefined,
|
||||
brand_input_color: string | undefined,
|
||||
brand_highlight_color: string | undefined,
|
||||
brand_danger_color: string | undefined,
|
||||
brand_background_color: string | undefined,
|
||||
brand_body_color: string | undefined,
|
||||
brand_card_color: string | undefined,
|
||||
brand_header_image: string | undefined,
|
||||
brand_header_link: string | undefined,
|
||||
brand_background_image: string | undefined,
|
||||
}
|
||||
|
||||
// API methods
|
||||
// ===========
|
||||
|
||||
// mkdir only supports the "mode" option
|
||||
export const fs_mkdir = async (path: string, opts: NodeOptions) => {
|
||||
const form = new FormData()
|
||||
form.append("action", "mkdir")
|
||||
|
||||
if (opts && opts.mode) {
|
||||
form.append("mode", opts.mode.toFixed(0))
|
||||
}
|
||||
|
||||
return await fs_check_response(
|
||||
await fetch(fs_path_url(path), { method: "POST", body: form })
|
||||
)
|
||||
}
|
||||
|
||||
export const fs_mkdirall = async (path: string, opts: NodeOptions) => {
|
||||
const form = new FormData()
|
||||
form.append("action", "mkdirall")
|
||||
|
||||
if (opts && opts.mode) {
|
||||
form.append("mode", opts.mode.toFixed(0))
|
||||
}
|
||||
|
||||
return await fs_check_response(
|
||||
await fetch(fs_path_url(path), { method: "POST", body: form })
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
export const fs_get_node = async (path: string) => {
|
||||
return await fs_check_response(
|
||||
await fetch(fs_path_url(path) + "?stat")
|
||||
@@ -182,3 +176,102 @@ export const fs_import = async (parent_dir_path = "", filelist: Array<string>) =
|
||||
await fetch(fs_path_url(parent_dir_path), { method: "POST", body: form })
|
||||
) as GenericResponse
|
||||
}
|
||||
|
||||
// Utility functions
|
||||
// =================
|
||||
|
||||
export const fs_check_response = async (resp: Response) => {
|
||||
let text = await resp.text()
|
||||
if (resp.status >= 400) {
|
||||
let error: any
|
||||
try {
|
||||
error = JSON.parse(text) as GenericResponse
|
||||
} catch (err) {
|
||||
error = text
|
||||
}
|
||||
throw error
|
||||
}
|
||||
return JSON.parse(text)
|
||||
}
|
||||
|
||||
export const fs_path_url = (path: string) => {
|
||||
if (!path || path.length === 0) {
|
||||
return ""
|
||||
}
|
||||
if (path[0] !== "/") {
|
||||
path = "/" + path
|
||||
}
|
||||
|
||||
if (window["api_endpoint"] !== undefined) {
|
||||
return window["api_endpoint"] + "/filesystem" + fs_encode_path(path)
|
||||
} else {
|
||||
throw Error("api_endpoint is undefined")
|
||||
}
|
||||
}
|
||||
|
||||
export const fs_encode_path = (path: string) => {
|
||||
// Encode all path elements separately to preserve forward slashes
|
||||
let split = path.split("/")
|
||||
for (let i = 0; i < split.length; i++) {
|
||||
split[i] = encodeURIComponent(split[i])
|
||||
}
|
||||
return split.join("/")
|
||||
}
|
||||
|
||||
export const fs_split_path = (path: string) => {
|
||||
let patharr = path.split("/")
|
||||
return { base: patharr.pop(), parent: patharr.join("/") }
|
||||
}
|
||||
|
||||
export const fs_thumbnail_url = (path: string, width = 64, height = 64) => {
|
||||
return fs_path_url(path) + "?thumbnail&width=" + width + "&height=" + height
|
||||
}
|
||||
|
||||
export const fs_node_type = (node: FSNode) => {
|
||||
if (node.type === "dir") {
|
||||
return "dir"
|
||||
} else if (node.file_type === "application/bittorrent" || node.file_type === "application/x-bittorrent") {
|
||||
return "torrent"
|
||||
} else if (node.file_type === "application/zip") {
|
||||
return "zip"
|
||||
} else if (node.file_type.startsWith("image")) {
|
||||
return "image"
|
||||
} else if (
|
||||
node.file_type.startsWith("video") ||
|
||||
node.file_type === "application/matroska" ||
|
||||
node.file_type === "application/x-matroska"
|
||||
) {
|
||||
return "video"
|
||||
} else if (
|
||||
node.file_type.startsWith("audio") ||
|
||||
node.file_type === "application/ogg" ||
|
||||
node.name.endsWith(".mp3")
|
||||
) {
|
||||
return "audio"
|
||||
} else if (
|
||||
node.file_type === "application/pdf" ||
|
||||
node.file_type === "application/x-pdf"
|
||||
) {
|
||||
return "pdf"
|
||||
} else if (
|
||||
node.file_type === "application/json" ||
|
||||
node.file_type.startsWith("text")
|
||||
) {
|
||||
return "text"
|
||||
} else {
|
||||
return "file"
|
||||
}
|
||||
}
|
||||
|
||||
export const fs_node_icon = (node: FSNode, width = 64, height = 64) => {
|
||||
if (node.type === "dir") {
|
||||
// Folders with an ID are publically shared, use the shared folder icon
|
||||
if (node.id) {
|
||||
return "/res/img/mime/folder-remote.png"
|
||||
} else {
|
||||
return "/res/img/mime/folder.png"
|
||||
}
|
||||
}
|
||||
|
||||
return fs_thumbnail_url(node.path, width, height)
|
||||
}
|
||||
|
@@ -1,83 +0,0 @@
|
||||
import { FSNode } from "./FilesystemAPI"
|
||||
|
||||
export const fs_split_path = (path: string) => {
|
||||
let patharr = path.split("/")
|
||||
return { base: patharr.pop(), parent: patharr.join("/") }
|
||||
}
|
||||
|
||||
export const fs_encode_path = (path: string) => {
|
||||
// Encode all path elements separately to preserve forward slashes
|
||||
let split = path.split("/")
|
||||
for (let i = 0; i < split.length; i++) {
|
||||
split[i] = encodeURIComponent(split[i])
|
||||
}
|
||||
return split.join("/")
|
||||
}
|
||||
|
||||
export const fs_path_url = (path: string) => {
|
||||
if (!path || path.length === 0) {
|
||||
return ""
|
||||
}
|
||||
if (path[0] !== "/") {
|
||||
path = "/" + path
|
||||
}
|
||||
|
||||
if (window["api_endpoint"] !== undefined) {
|
||||
return window["api_endpoint"] + "/filesystem" + fs_encode_path(path)
|
||||
} else {
|
||||
throw Error("api_endpoint is undefined")
|
||||
}
|
||||
}
|
||||
|
||||
export const fs_thumbnail_url = (path: string, width = 64, height = 64) => {
|
||||
return fs_path_url(path) + "?thumbnail&width=" + width + "&height=" + height
|
||||
}
|
||||
|
||||
export const fs_node_type = (node: FSNode) => {
|
||||
if (node.type === "dir") {
|
||||
return "dir"
|
||||
} else if (node.file_type === "application/bittorrent" || node.file_type === "application/x-bittorrent") {
|
||||
return "torrent"
|
||||
} else if (node.file_type === "application/zip") {
|
||||
return "zip"
|
||||
} else if (node.file_type.startsWith("image")) {
|
||||
return "image"
|
||||
} else if (
|
||||
node.file_type.startsWith("video") ||
|
||||
node.file_type === "application/matroska" ||
|
||||
node.file_type === "application/x-matroska"
|
||||
) {
|
||||
return "video"
|
||||
} else if (
|
||||
node.file_type.startsWith("audio") ||
|
||||
node.file_type === "application/ogg" ||
|
||||
node.name.endsWith(".mp3")
|
||||
) {
|
||||
return "audio"
|
||||
} else if (
|
||||
node.file_type === "application/pdf" ||
|
||||
node.file_type === "application/x-pdf"
|
||||
) {
|
||||
return "pdf"
|
||||
} else if (
|
||||
node.file_type === "application/json" ||
|
||||
node.file_type.startsWith("text")
|
||||
) {
|
||||
return "text"
|
||||
} else {
|
||||
return "file"
|
||||
}
|
||||
}
|
||||
|
||||
export const fs_node_icon = (node: FSNode, width = 64, height = 64) => {
|
||||
if (node.type === "dir") {
|
||||
// Folders with an ID are publically shared, use the shared folder icon
|
||||
if (node.id) {
|
||||
return "/res/img/mime/folder-remote.png"
|
||||
} else {
|
||||
return "/res/img/mime/folder.png"
|
||||
}
|
||||
}
|
||||
|
||||
return fs_thumbnail_url(node.path, width, height)
|
||||
}
|
@@ -1,7 +1,6 @@
|
||||
<script>
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import { fs_search } from "./FilesystemAPI";
|
||||
import { fs_encode_path, fs_thumbnail_url } from "./FilesystemUtil";
|
||||
import { fs_search, fs_encode_path, fs_thumbnail_url } from "./FilesystemAPI";
|
||||
|
||||
export let nav
|
||||
|
||||
|
@@ -31,8 +31,7 @@ export const generate_share_path = path => {
|
||||
</script>
|
||||
|
||||
<script>
|
||||
import { fs_update } from "./FilesystemAPI";
|
||||
import { fs_encode_path } from "./FilesystemUtil";
|
||||
import { fs_update, fs_encode_path } from "./FilesystemAPI";
|
||||
|
||||
export let visible = false
|
||||
export let share_url = ""
|
||||
|
@@ -1,8 +1,7 @@
|
||||
<script>
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import FilePicker from "../filemanager/FilePicker.svelte";
|
||||
import { fs_update } from "../FilesystemAPI";
|
||||
import { fs_node_type } from "../FilesystemUtil";
|
||||
import { fs_update, fs_node_type } from "../FilesystemAPI";
|
||||
import CustomBanner from "../viewers/CustomBanner.svelte";
|
||||
|
||||
let dispatch = createEventDispatcher()
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<script>
|
||||
import { createEventDispatcher } from "svelte"
|
||||
import { fs_encode_path, fs_node_icon, fs_node_type } from "../FilesystemUtil";
|
||||
import { fs_node_icon, fs_node_type, fs_encode_path } from "./../FilesystemAPI";
|
||||
let dispatch = createEventDispatcher()
|
||||
|
||||
export let nav
|
||||
@@ -11,7 +11,7 @@ export let large_icons = false
|
||||
<div class="gallery">
|
||||
{#each $nav.children as child, index (child.path)}
|
||||
<a class="file"
|
||||
href={"/d"+fs_encode_path(child.path)}
|
||||
href={"/d"+fs_encode_path(child.path)}
|
||||
on:click|preventDefault={() => dispatch("node_click", index)}
|
||||
on:contextmenu={e => dispatch("node_context", {event: e, index: index})}
|
||||
class:selected={child.fm_selected}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<script>
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import { formatDataVolume } from "../../util/Formatting.svelte";
|
||||
import { fs_encode_path, fs_node_icon } from "../FilesystemUtil";
|
||||
import { formatDataVolume } from "./../../util/Formatting.svelte";
|
||||
import { fs_encode_path, fs_node_icon } from "./../FilesystemAPI"
|
||||
|
||||
let dispatch = createEventDispatcher()
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
//
|
||||
// on_error is called when the upload has failed. The parameters are the error
|
||||
|
||||
import { fs_path_url } from "../FilesystemUtil"
|
||||
import { fs_path_url } from "./../FilesystemAPI"
|
||||
|
||||
// code and an error message
|
||||
export const upload_file = (file, path, on_progress, on_success, on_error) => {
|
||||
|
@@ -1,8 +1,8 @@
|
||||
<script>
|
||||
import { onMount } from 'svelte'
|
||||
import { fs_encode_path, fs_node_icon, fs_path_url } from '../FilesystemUtil';
|
||||
import FileTitle from '../../file_viewer/viewers/FileTitle.svelte';
|
||||
import TextBlock from '../../file_viewer/viewers/TextBlock.svelte';
|
||||
import { fs_path_url, fs_encode_path, fs_node_icon } from "./../FilesystemAPI"
|
||||
import FileTitle from './../../file_viewer/viewers/FileTitle.svelte';
|
||||
import TextBlock from './../../file_viewer/viewers/TextBlock.svelte';
|
||||
|
||||
export let nav
|
||||
let player
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<script>
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import IconBlock from "../../file_viewer/viewers/IconBlock.svelte";
|
||||
import { fs_thumbnail_url } from "../FilesystemUtil";
|
||||
import { fs_thumbnail_url } from "../FilesystemAPI";
|
||||
import TextBlock from "../../file_viewer/viewers/TextBlock.svelte";
|
||||
let dispatch = createEventDispatcher()
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<script>
|
||||
import { onMount, tick } from "svelte";
|
||||
import Spinner from "../../util/Spinner.svelte";
|
||||
import { fs_node_type } from "../FilesystemUtil";
|
||||
import { fs_node_type } from "./../FilesystemAPI";
|
||||
import FileManager from "../filemanager/FileManager.svelte";
|
||||
import Audio from "./Audio.svelte";
|
||||
import File from "./File.svelte";
|
||||
|
@@ -1,14 +1,14 @@
|
||||
<script>
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import { swipe_nav } from "../../file_viewer/viewers/SwipeNavigate.ts";
|
||||
import { fs_path_url } from "../FilesystemUtil";
|
||||
import { swipe_nav } from "./../../file_viewer/viewers/SwipeNavigate";
|
||||
import { fs_path_url } from "./../FilesystemAPI";
|
||||
|
||||
let dispatch = createEventDispatcher()
|
||||
let dispatch = createEventDispatcher();
|
||||
|
||||
export let nav
|
||||
let container
|
||||
let zoom = false
|
||||
let x, y = 0
|
||||
let x = 0, y = 0
|
||||
let dragging = false
|
||||
|
||||
export const update = () => {
|
||||
@@ -65,7 +65,6 @@ const mouseup = (e) => {
|
||||
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
|
||||
<img
|
||||
on:dblclick={() => {zoom = !zoom}}
|
||||
on:doubletap={() => {zoom = !zoom}}
|
||||
on:mousedown={mousedown}
|
||||
on:load={on_load}
|
||||
on:error={on_load}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<script>
|
||||
import { fs_path_url } from "../FilesystemUtil";
|
||||
import { fs_path_url } from "../FilesystemAPI";
|
||||
|
||||
export let nav
|
||||
</script>
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<script>
|
||||
import { tick } from "svelte";
|
||||
import { fs_path_url } from "../FilesystemUtil";
|
||||
import { fs_path_url } from "../FilesystemAPI";
|
||||
|
||||
export let nav
|
||||
let text_type = "text"
|
||||
|
@@ -5,7 +5,7 @@ import { formatDate } from "../../util/Formatting.svelte"
|
||||
import TorrentItem from "./TorrentItem.svelte"
|
||||
import IconBlock from "../../file_viewer/viewers/IconBlock.svelte";
|
||||
import TextBlock from "../../file_viewer/viewers/TextBlock.svelte";
|
||||
import { fs_node_icon, fs_path_url } from "../FilesystemUtil";
|
||||
import { fs_node_icon, fs_path_url } from "../FilesystemAPI";
|
||||
import CopyButton from "../../layout/CopyButton.svelte";
|
||||
|
||||
let dispatch = createEventDispatcher()
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<script>
|
||||
import { onMount, createEventDispatcher, tick } from "svelte";
|
||||
import { fs_path_url } from "../FilesystemUtil";
|
||||
import { fs_path_url } from "../FilesystemAPI";
|
||||
let dispatch = createEventDispatcher()
|
||||
|
||||
export let nav
|
||||
|
@@ -4,7 +4,7 @@ import { formatDataVolume, formatDate } from "../../util/Formatting.svelte"
|
||||
import ZipItem from "../../file_viewer/viewers/ZipItem.svelte";
|
||||
import IconBlock from "../../file_viewer/viewers/IconBlock.svelte";
|
||||
import TextBlock from "../../file_viewer/viewers/TextBlock.svelte";
|
||||
import { fs_node_icon, fs_path_url } from "../FilesystemUtil";
|
||||
import { fs_node_icon, fs_path_url } from "../FilesystemAPI";
|
||||
|
||||
let dispatch = createEventDispatcher()
|
||||
|
||||
|
Reference in New Issue
Block a user