Implemented routing instead of internal state
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				/ Build the server (push) Successful in 3m5s
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	/ Build the server (push) Successful in 3m5s
				
			This commit is contained in:
		
							
								
								
									
										20
									
								
								frontend/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										20
									
								
								frontend/package-lock.json
									
									
									
										generated
									
									
									
								
							@@ -11,6 +11,7 @@
 | 
				
			|||||||
        "@microsoft/fetch-event-source": "^2.0.1",
 | 
					        "@microsoft/fetch-event-source": "^2.0.1",
 | 
				
			||||||
        "filesize": "^10.1.0",
 | 
					        "filesize": "^10.1.0",
 | 
				
			||||||
        "qrcode-svg": "^1.1.0",
 | 
					        "qrcode-svg": "^1.1.0",
 | 
				
			||||||
 | 
					        "svelte-spa-router": "^3.3.0",
 | 
				
			||||||
        "tailwind-merge": "^1.14.0"
 | 
					        "tailwind-merge": "^1.14.0"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "devDependencies": {
 | 
					      "devDependencies": {
 | 
				
			||||||
@@ -2619,6 +2620,14 @@
 | 
				
			|||||||
        "node": ">=8.10.0"
 | 
					        "node": ">=8.10.0"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/regexparam": {
 | 
				
			||||||
 | 
					      "version": "2.0.1",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/regexparam/-/regexparam-2.0.1.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-zRgSaYemnNYxUv+/5SeoHI0eJIgTL/A2pUtXUPLHQxUldagouJ9p+K6IbIZ/JiQuCEv2E2B1O11SjVQy3aMCkw==",
 | 
				
			||||||
 | 
					      "engines": {
 | 
				
			||||||
 | 
					        "node": ">=8"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/relateurl": {
 | 
					    "node_modules/relateurl": {
 | 
				
			||||||
      "version": "0.2.7",
 | 
					      "version": "0.2.7",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz",
 | 
				
			||||||
@@ -3037,6 +3046,17 @@
 | 
				
			|||||||
        "node": ">=12"
 | 
					        "node": ">=12"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/svelte-spa-router": {
 | 
				
			||||||
 | 
					      "version": "3.3.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/svelte-spa-router/-/svelte-spa-router-3.3.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-cwRNe7cxD43sCvSfEeaKiNZg3FCizGxeMcf7CPiWRP3jKXjEma3vxyyuDtPOam6nWbVxl9TNM3hlE/i87ZlqcQ==",
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "regexparam": "2.0.1"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "funding": {
 | 
				
			||||||
 | 
					        "url": "https://github.com/sponsors/ItalyPaleAle"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/svg.draggable.js": {
 | 
					    "node_modules/svg.draggable.js": {
 | 
				
			||||||
      "version": "2.2.2",
 | 
					      "version": "2.2.2",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/svg.draggable.js/-/svg.draggable.js-2.2.2.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/svg.draggable.js/-/svg.draggable.js-2.2.2.tgz",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -35,6 +35,7 @@
 | 
				
			|||||||
    "@microsoft/fetch-event-source": "^2.0.1",
 | 
					    "@microsoft/fetch-event-source": "^2.0.1",
 | 
				
			||||||
    "filesize": "^10.1.0",
 | 
					    "filesize": "^10.1.0",
 | 
				
			||||||
    "qrcode-svg": "^1.1.0",
 | 
					    "qrcode-svg": "^1.1.0",
 | 
				
			||||||
 | 
					    "svelte-spa-router": "^3.3.0",
 | 
				
			||||||
    "tailwind-merge": "^1.14.0"
 | 
					    "tailwind-merge": "^1.14.0"
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,37 +1,24 @@
 | 
				
			|||||||
<script lang="ts">
 | 
					<script lang="ts">
 | 
				
			||||||
    import {changeStateFunction, error_banner, info_banner, rpc, session, show_working, state, StateE, token, workingWrapperO} from './store';
 | 
					    import {error_banner, info_banner, rpc, session, show_working, token, workingWrapperO} from './store';
 | 
				
			||||||
    import {Banner, Navbar, Spinner} from 'flowbite-svelte';
 | 
					    import {Banner, Navbar, NavBrand, Spinner} from 'flowbite-svelte';
 | 
				
			||||||
 | 
					    import Router, {replace} from 'svelte-spa-router';
 | 
				
			||||||
 | 
					    import {routes} from './routes';
 | 
				
			||||||
    import {FileStorage} from './icons';
 | 
					    import {FileStorage} from './icons';
 | 
				
			||||||
    import LinkButton from './components/LinkButton.svelte';
 | 
					    import LinkButton from './components/LinkButton.svelte';
 | 
				
			||||||
    import Login from './pages/Login.svelte';
 | 
					    import A from './components/A.svelte';
 | 
				
			||||||
    import Signup from './pages/Signup.svelte';
 | 
					 | 
				
			||||||
    import ResetPassword from './pages/ResetPassword.svelte';
 | 
					 | 
				
			||||||
    import Profile from './pages/Profile.svelte';
 | 
					 | 
				
			||||||
    import TfaSetup from './pages/TfaSetup.svelte';
 | 
					 | 
				
			||||||
    import Admin from './pages/Admin.svelte';
 | 
					 | 
				
			||||||
    import View from './pages/View.svelte';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const s = session.s;
 | 
					    const s = session.s;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function homeClick() {
 | 
					 | 
				
			||||||
        if ($token == null)
 | 
					 | 
				
			||||||
            $state.s = StateE.LOGIN;
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
            $state = { s: StateE.VIEW, view_node: 0 };
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    async function leaveSudo() {
 | 
					    async function leaveSudo() {
 | 
				
			||||||
        await workingWrapperO(() => rpc.Admin_unsudo($token ?? ''));
 | 
					        await workingWrapperO(() => rpc.Admin_unsudo($token ?? ''));
 | 
				
			||||||
        await session.update($token);
 | 
					        await session.update($token);
 | 
				
			||||||
        state.set({s: StateE.ADMIN, view_node: 0});
 | 
					        await replace('/admin');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function logout() {
 | 
					    function logout() {
 | 
				
			||||||
        rpc.Auth_logout($token ?? '');
 | 
					        rpc.Auth_logout($token ?? '');
 | 
				
			||||||
        token.set(null);
 | 
					        token.set(null);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    homeClick();
 | 
					 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<main class="h-screen w-screen p-4 flex flex-col">
 | 
					<main class="h-screen w-screen p-4 flex flex-col">
 | 
				
			||||||
@@ -49,43 +36,22 @@
 | 
				
			|||||||
        <Banner position="absolute" dismissable={false}><Spinner size="5" class="mr-2" />Working</Banner>
 | 
					        <Banner position="absolute" dismissable={false}><Spinner size="5" class="mr-2" />Working</Banner>
 | 
				
			||||||
    {/if}
 | 
					    {/if}
 | 
				
			||||||
    <Navbar class="flex-grow-0">
 | 
					    <Navbar class="flex-grow-0">
 | 
				
			||||||
        <button on:click={homeClick} id="home-button" class="flex items-center">
 | 
					        <NavBrand href={$token == null ? '#/login' : '#/view/0'}>
 | 
				
			||||||
            <FileStorage width="1.5em" height="1.5em"/>
 | 
					            <FileStorage width="1.5em" height="1.5em"/>
 | 
				
			||||||
            <span id="navbar-text">MFileserver</span>
 | 
					            <span id="navbar-text" class="ml-2">MFileserver</span>
 | 
				
			||||||
        </button>
 | 
					        </NavBrand>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        {#if $token != null}
 | 
					        {#if $token != null}
 | 
				
			||||||
            <div class="flex md:order-2">
 | 
					            <div class="flex md:order-2 gap-x-2">
 | 
				
			||||||
                {#if $s?.sudo} <LinkButton on:click={leaveSudo}>Leave sudo</LinkButton> {/if}
 | 
					                {#if $s?.sudo} <LinkButton on:click={leaveSudo}>Leave sudo</LinkButton> {/if}
 | 
				
			||||||
                {#if $s?.admin} <LinkButton on:click={changeStateFunction(StateE.ADMIN)}>Admin</LinkButton> {/if}
 | 
					                {#if $s?.admin} <A href="#/admin">Admin</A> {/if}
 | 
				
			||||||
                <LinkButton on:click={changeStateFunction(StateE.VIEW, 0)}>Files</LinkButton>
 | 
					                <A href="#/view/0">Files</A>
 | 
				
			||||||
                <LinkButton on:click={changeStateFunction(StateE.PROFILE)}>Profile</LinkButton>
 | 
					                <A href="#/profile">Profile</A>
 | 
				
			||||||
                <LinkButton on:click={logout}>Logout</LinkButton>
 | 
					                <LinkButton on:click={logout}>Logout</LinkButton>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
        {/if}
 | 
					        {/if}
 | 
				
			||||||
    </Navbar>
 | 
					    </Navbar>
 | 
				
			||||||
    <span class="grid justify-items-center mt-10">
 | 
					    <span class="grid justify-items-center mt-10">
 | 
				
			||||||
        {#if $state.s === StateE.LOGIN } <Login/>
 | 
					        <Router {routes} />
 | 
				
			||||||
        {:else if $state.s === StateE.SIGNUP} <Signup/>
 | 
					 | 
				
			||||||
        {:else if $state.s === StateE.RESET_PASSWORD} <ResetPassword/>
 | 
					 | 
				
			||||||
        {:else if $state.s === StateE.PROFILE} <Profile/>
 | 
					 | 
				
			||||||
        {:else if $state.s === StateE.TFA_SETUP} <TfaSetup/>
 | 
					 | 
				
			||||||
        {:else if $state.s === StateE.ADMIN} <Admin/>
 | 
					 | 
				
			||||||
        {:else if $state.s === StateE.VIEW} <View/>
 | 
					 | 
				
			||||||
        {:else} <span>You are in state {$state.s}, which should not be possible, please report this.</span>
 | 
					 | 
				
			||||||
        {/if}
 | 
					 | 
				
			||||||
    </span>
 | 
					    </span>
 | 
				
			||||||
</main>
 | 
					</main>
 | 
				
			||||||
 | 
					 | 
				
			||||||
<style>
 | 
					 | 
				
			||||||
    #navbar-text {
 | 
					 | 
				
			||||||
        margin-left: 0.5em;
 | 
					 | 
				
			||||||
        font-weight: 500;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    #home-button {
 | 
					 | 
				
			||||||
        background: none;
 | 
					 | 
				
			||||||
        border: none;
 | 
					 | 
				
			||||||
        cursor: pointer;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
</style>
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										8
									
								
								frontend/src/components/A.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								frontend/src/components/A.svelte
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					<script lang="ts">
 | 
				
			||||||
 | 
					    import {A} from 'flowbite-svelte';
 | 
				
			||||||
 | 
					    export let href: string;
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<A {href} aClass="hover:text-primary-400 transition-colors">
 | 
				
			||||||
 | 
					    <slot></slot>
 | 
				
			||||||
 | 
					</A>
 | 
				
			||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
<script lang="ts">
 | 
					<script lang="ts">
 | 
				
			||||||
    import {rpc, show_working, state, token} from '../store';
 | 
					    import {rpc, show_working, token} from '../store';
 | 
				
			||||||
    import {Button, ButtonGroup, Modal} from 'flowbite-svelte';
 | 
					    import {Button, ButtonGroup, Modal} from 'flowbite-svelte';
 | 
				
			||||||
    import {afterUpdate} from 'svelte';
 | 
					    import {afterUpdate, createEventDispatcher} from 'svelte';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let show_confirm = false;
 | 
					    let show_confirm = false;
 | 
				
			||||||
    let show_modal = false;
 | 
					    let show_modal = false;
 | 
				
			||||||
@@ -9,6 +9,8 @@
 | 
				
			|||||||
    let text = '';
 | 
					    let text = '';
 | 
				
			||||||
    let nodes: number[] = [];
 | 
					    let nodes: number[] = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const dispatch = createEventDispatcher<{reload_node: null}>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async function real_delete() {
 | 
					    async function real_delete() {
 | 
				
			||||||
        show_confirm = false;
 | 
					        show_confirm = false;
 | 
				
			||||||
        show_modal = true;
 | 
					        show_modal = true;
 | 
				
			||||||
@@ -27,7 +29,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        show_working.set(false);
 | 
					        show_working.set(false);
 | 
				
			||||||
        show_modal = false;
 | 
					        show_modal = false;
 | 
				
			||||||
        state.update(v => v);
 | 
					        dispatch('reload_node');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    export const del = async (n: number[]) => {
 | 
					    export const del = async (n: number[]) => {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,11 +4,12 @@
 | 
				
			|||||||
</script>
 | 
					</script>
 | 
				
			||||||
<script lang="ts">
 | 
					<script lang="ts">
 | 
				
			||||||
    import {Checkbox, Dropdown, DropdownItem, Spinner, Table, TableBody, TableBodyCell, TableBodyRow, TableHead, TableHeadCell, Tooltip} from 'flowbite-svelte';
 | 
					    import {Checkbox, Dropdown, DropdownItem, Spinner, Table, TableBody, TableBodyCell, TableBodyRow, TableHead, TableHeadCell, Tooltip} from 'flowbite-svelte';
 | 
				
			||||||
    import {Folder, FolderParent, DocumentBlank, CaretLeft} from '../icons';
 | 
					 | 
				
			||||||
    import {filesize} from 'filesize';
 | 
					    import {filesize} from 'filesize';
 | 
				
			||||||
    import {api, changeStateFunction, download, StateE, token, rpc} from '../store';
 | 
					    import {Folder, FolderParent, DocumentBlank, CaretLeft} from '../icons';
 | 
				
			||||||
 | 
					    import {api, download, token, rpc} from '../store';
 | 
				
			||||||
    import LinkButton from './LinkButton.svelte';
 | 
					    import LinkButton from './LinkButton.svelte';
 | 
				
			||||||
    import DeleteModal from './DeleteModal.svelte';
 | 
					    import DeleteModal from './DeleteModal.svelte';
 | 
				
			||||||
 | 
					    import A from './A.svelte';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    export let node: api.Node;
 | 
					    export let node: api.Node;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -43,11 +44,12 @@
 | 
				
			|||||||
    $: ctx_style = `top: ${ctx_y}px; left: ${ctx_x}px; position: fixed;`;
 | 
					    $: ctx_style = `top: ${ctx_y}px; left: ${ctx_x}px; position: fixed;`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function onCtxMenu(node: api.Node, e: MouseEvent) {
 | 
					    function onCtxMenu(node: api.Node, e: MouseEvent) {
 | 
				
			||||||
 | 
					        console.log(e);
 | 
				
			||||||
        e.preventDefault();
 | 
					        e.preventDefault();
 | 
				
			||||||
        if (!ctx_hidden)
 | 
					        if (!ctx_hidden)
 | 
				
			||||||
            return ctx_hidden = true;
 | 
					            return ctx_hidden = true;
 | 
				
			||||||
        ctx_x = e.pageX;
 | 
					        ctx_x = e.clientX;
 | 
				
			||||||
        ctx_y = e.pageY;
 | 
					        ctx_y = e.clientY;
 | 
				
			||||||
        ctx_node = node;
 | 
					        ctx_node = node;
 | 
				
			||||||
        ctx_hidden = false;
 | 
					        ctx_hidden = false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -70,7 +72,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
<svelte:body on:click={() => (ctx_hidden = true)} />
 | 
					<svelte:body on:click={() => (ctx_hidden = true)} />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<DeleteModal bind:del={del} />
 | 
					<DeleteModal bind:del={del} on:reload_node />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<Table hoverable>
 | 
					<Table hoverable>
 | 
				
			||||||
    <TableHead theadClass="text-xs">
 | 
					    <TableHead theadClass="text-xs">
 | 
				
			||||||
@@ -86,7 +88,7 @@
 | 
				
			|||||||
            <TableBodyRow>
 | 
					            <TableBodyRow>
 | 
				
			||||||
                <TableBodyCell class="!p-4"></TableBodyCell>
 | 
					                <TableBodyCell class="!p-4"></TableBodyCell>
 | 
				
			||||||
                <TableBodyCell class="px-2 w-0"><FolderParent /></TableBodyCell>
 | 
					                <TableBodyCell class="px-2 w-0"><FolderParent /></TableBodyCell>
 | 
				
			||||||
                <TableBodyCell class="pl-0"><LinkButton on:click={changeStateFunction(StateE.VIEW, node.parent ?? 0)}>..</LinkButton></TableBodyCell>
 | 
					                <TableBodyCell class="pl-0"><A href={'#/view/' + node.parent}>..</A></TableBodyCell>
 | 
				
			||||||
                <TableBodyCell></TableBodyCell>
 | 
					                <TableBodyCell></TableBodyCell>
 | 
				
			||||||
            </TableBodyRow>
 | 
					            </TableBodyRow>
 | 
				
			||||||
        {/if}
 | 
					        {/if}
 | 
				
			||||||
@@ -94,7 +96,7 @@
 | 
				
			|||||||
            <TableBodyRow on:contextmenu={onCtxMenu.bind(null, node)}>
 | 
					            <TableBodyRow on:contextmenu={onCtxMenu.bind(null, node)}>
 | 
				
			||||||
                <TableBodyCell class="p-2 pl-4 w-0 h-0"><Checkbox bind:group={selected} value={node.id}/></TableBodyCell>
 | 
					                <TableBodyCell class="p-2 pl-4 w-0 h-0"><Checkbox bind:group={selected} value={node.id}/></TableBodyCell>
 | 
				
			||||||
                <TableBodyCell class="px-2 w-0"><Folder /></TableBodyCell>
 | 
					                <TableBodyCell class="px-2 w-0"><Folder /></TableBodyCell>
 | 
				
			||||||
                <TableBodyCell class="pl-0"><LinkButton on:click={changeStateFunction(StateE.VIEW, node.id)}>{node.name}</LinkButton></TableBodyCell>
 | 
					                <TableBodyCell class="pl-0"><A href={'#/view/' + node.id}>{node.name}</A></TableBodyCell>
 | 
				
			||||||
                <TableBodyCell></TableBodyCell>
 | 
					                <TableBodyCell></TableBodyCell>
 | 
				
			||||||
            </TableBodyRow>
 | 
					            </TableBodyRow>
 | 
				
			||||||
        {/each}
 | 
					        {/each}
 | 
				
			||||||
@@ -112,7 +114,7 @@
 | 
				
			|||||||
                        <DocumentBlank />
 | 
					                        <DocumentBlank />
 | 
				
			||||||
                    {/if}
 | 
					                    {/if}
 | 
				
			||||||
                </TableBodyCell>
 | 
					                </TableBodyCell>
 | 
				
			||||||
                <TableBodyCell class="pl-0"><LinkButton on:click={changeStateFunction(StateE.VIEW, node.id)}>{node.name}</LinkButton></TableBodyCell>
 | 
					                <TableBodyCell class="pl-0"><A href={'#/view/' + node.id}>{node.name}</A></TableBodyCell>
 | 
				
			||||||
                <TableBodyCell>{filesize(node.size ?? 0, {base: 2, standard: 'jedec'})}</TableBodyCell>
 | 
					                <TableBodyCell>{filesize(node.size ?? 0, {base: 2, standard: 'jedec'})}</TableBodyCell>
 | 
				
			||||||
            </TableBodyRow>
 | 
					            </TableBodyRow>
 | 
				
			||||||
        {/each}
 | 
					        {/each}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,7 +16,7 @@
 | 
				
			|||||||
    .link-button {
 | 
					    .link-button {
 | 
				
			||||||
        background: none;
 | 
					        background: none;
 | 
				
			||||||
        border: none;
 | 
					        border: none;
 | 
				
			||||||
        padding: 0 0.25em;
 | 
					        padding: 0;
 | 
				
			||||||
        cursor: pointer;
 | 
					        cursor: pointer;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
</style>
 | 
					</style>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,11 @@
 | 
				
			|||||||
<script lang="ts">
 | 
					<script lang="ts">
 | 
				
			||||||
    import {state, token, type UploadFile} from '../store';
 | 
					    import {token, type UploadFile} from '../store';
 | 
				
			||||||
    import {Button, Modal, Progressbar} from 'flowbite-svelte';
 | 
					    import {Button, Modal, Progressbar} from 'flowbite-svelte';
 | 
				
			||||||
    import {filesize} from 'filesize';
 | 
					    import {filesize} from 'filesize';
 | 
				
			||||||
 | 
					    import {createEventDispatcher} from 'svelte';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const dispatch = createEventDispatcher<{reload_node: null}>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    interface MyFile extends UploadFile {
 | 
					    interface MyFile extends UploadFile {
 | 
				
			||||||
        waiting: boolean,
 | 
					        waiting: boolean,
 | 
				
			||||||
@@ -24,7 +28,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    function close() {
 | 
					    function close() {
 | 
				
			||||||
        show_modal = false;
 | 
					        show_modal = false;
 | 
				
			||||||
        state.update(v => v);
 | 
					        dispatch('reload_node');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async function realUpload(file: MyFile) {
 | 
					    async function realUpload(file: MyFile) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,10 @@
 | 
				
			|||||||
import "./app.pcss";
 | 
					import "./app.pcss";
 | 
				
			||||||
import App from "./App.svelte";
 | 
					import App from "./App.svelte";
 | 
				
			||||||
import {state, StateE, token} from './store';
 | 
					import {token} from './store';
 | 
				
			||||||
 | 
					import {replace} from 'svelte-spa-router';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
token.subscribe(v => {
 | 
					token.subscribe(v => {
 | 
				
			||||||
    if (v == null) state.set({s: StateE.LOGIN, view_node: 0});
 | 
					    if (v == null) replace('/login').then()
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const app = new App({
 | 
					const app = new App({
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,9 @@
 | 
				
			|||||||
<script lang="ts">
 | 
					<script lang="ts">
 | 
				
			||||||
    import {api, rpc, session, state, StateE, token, workingWrapperO, workingWrapperR} from '../store';
 | 
					    import {api, rpc, session, token, workingWrapperO, workingWrapperR} from '../store';
 | 
				
			||||||
    import {Checkbox, Table, TableBody, TableBodyCell, TableBodyRow, TableHead, TableHeadCell} from 'flowbite-svelte';
 | 
					    import {Checkbox, Table, TableBody, TableBodyCell, TableBodyRow, TableHead, TableHeadCell} from 'flowbite-svelte';
 | 
				
			||||||
    import {Checkmark, Error} from '../icons';
 | 
					    import {Checkmark, Error} from '../icons';
 | 
				
			||||||
    import LinkButton from '../components/LinkButton.svelte';
 | 
					    import LinkButton from '../components/LinkButton.svelte';
 | 
				
			||||||
 | 
					    import {replace} from 'svelte-spa-router';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let users: api.UserInfo[] = [];
 | 
					    let users: api.UserInfo[] = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -25,7 +26,7 @@
 | 
				
			|||||||
    async function sudo(user: number) {
 | 
					    async function sudo(user: number) {
 | 
				
			||||||
        if (await workingWrapperO(() => rpc.Admin_sudo($token ?? '', user))) {
 | 
					        if (await workingWrapperO(() => rpc.Admin_sudo($token ?? '', user))) {
 | 
				
			||||||
            await session.update($token);
 | 
					            await session.update($token);
 | 
				
			||||||
            state.set({s: StateE.VIEW, view_node: 0});
 | 
					            await replace('/view/0');
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,8 @@
 | 
				
			|||||||
<script lang="ts">
 | 
					<script lang="ts">
 | 
				
			||||||
    import {Button, ButtonGroup, Card, Input, InputAddon} from 'flowbite-svelte';
 | 
					    import {Button, ButtonGroup, Card, Input, InputAddon} from 'flowbite-svelte';
 | 
				
			||||||
    import {Email, OTP, Password} from '../icons';
 | 
					    import {Email, OTP, Password} from '../icons';
 | 
				
			||||||
    import {changeStateFunction, rpc, state, StateE, token, workingWrapperR, api} from '../store';
 | 
					    import {rpc, token, workingWrapperR, api} from '../store';
 | 
				
			||||||
 | 
					    import {replace} from 'svelte-spa-router';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let ask_tfa = false;
 | 
					    let ask_tfa = false;
 | 
				
			||||||
    let username = '', password = '', tfa = '';
 | 
					    let username = '', password = '', tfa = '';
 | 
				
			||||||
@@ -14,7 +15,7 @@
 | 
				
			|||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        token.set(resp.token);
 | 
					        token.set(resp.token);
 | 
				
			||||||
        state.set({s: StateE.VIEW, view_node: 0});
 | 
					        await replace('/view/0');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function keyUp(e: KeyboardEvent) {
 | 
					    function keyUp(e: KeyboardEvent) {
 | 
				
			||||||
@@ -41,9 +42,9 @@
 | 
				
			|||||||
            <Input type="password" placeholder="Password" bind:value={password} on:keyup={keyUp}></Input>
 | 
					            <Input type="password" placeholder="Password" bind:value={password} on:keyup={keyUp}></Input>
 | 
				
			||||||
        </ButtonGroup>
 | 
					        </ButtonGroup>
 | 
				
			||||||
        <ButtonGroup class="w-full flex flex-nowrap">
 | 
					        <ButtonGroup class="w-full flex flex-nowrap">
 | 
				
			||||||
            <Button class="flex-1 flex-grow" color="primary" outline on:click={changeStateFunction(StateE.SIGNUP)}>Signup</Button>
 | 
					            <Button class="flex-1 flex-grow" color="primary" outline href="#/signup">Signup</Button>
 | 
				
			||||||
            <Button class="flex-1 flex-grow" color="primary" on:click={login}>Login</Button>
 | 
					            <Button class="flex-1 flex-grow" color="primary" on:click={login}>Login</Button>
 | 
				
			||||||
            <Button class="flex-1 flex-grow" color="primary" outline on:click={changeStateFunction(StateE.RESET_PASSWORD)}>Forget password</Button>
 | 
					            <Button class="flex-1 flex-grow" color="primary" outline href="#/reset_pw">Forget password</Button>
 | 
				
			||||||
        </ButtonGroup>
 | 
					        </ButtonGroup>
 | 
				
			||||||
    {/if}
 | 
					    {/if}
 | 
				
			||||||
</Card>
 | 
					</Card>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
<script lang="ts">
 | 
					<script lang="ts">
 | 
				
			||||||
    import {changeStateFunction, error_banner, rpc, session, StateE, token, workingWrapperO} from '../store';
 | 
					    import {error_banner, rpc, session, token, workingWrapperO} from '../store';
 | 
				
			||||||
    import {Accordion, AccordionItem, Button, ButtonGroup, Input, InputAddon} from 'flowbite-svelte';
 | 
					    import {Accordion, AccordionItem, Button, ButtonGroup, Input, InputAddon} from 'flowbite-svelte';
 | 
				
			||||||
    import {Password} from '../icons';
 | 
					    import {Password} from '../icons';
 | 
				
			||||||
    import {info_banner} from '../store.js';
 | 
					    import {info_banner} from '../store.js';
 | 
				
			||||||
@@ -69,7 +69,7 @@
 | 
				
			|||||||
        {#if tfa_enabled}
 | 
					        {#if tfa_enabled}
 | 
				
			||||||
            <Button class="w-full" color="red" on:click={disableTfa}>Disable</Button>
 | 
					            <Button class="w-full" color="red" on:click={disableTfa}>Disable</Button>
 | 
				
			||||||
        {:else}
 | 
					        {:else}
 | 
				
			||||||
            <Button class="w-full" color="green" on:click={changeStateFunction(StateE.TFA_SETUP)}>Enable</Button>
 | 
					            <Button class="w-full" color="green" href="#/tfa">Enable</Button>
 | 
				
			||||||
        {/if}
 | 
					        {/if}
 | 
				
			||||||
    </AccordionItem>
 | 
					    </AccordionItem>
 | 
				
			||||||
    <AccordionItem>
 | 
					    <AccordionItem>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,8 @@
 | 
				
			|||||||
<script lang="ts">
 | 
					<script lang="ts">
 | 
				
			||||||
    import {Button, ButtonGroup, Card, Input, InputAddon} from 'flowbite-svelte';
 | 
					    import {Button, ButtonGroup, Card, Input, InputAddon} from 'flowbite-svelte';
 | 
				
			||||||
    import {Email, EmailNew, Password} from '../icons';
 | 
					    import {Email, EmailNew, Password} from '../icons';
 | 
				
			||||||
    import {changeStateFunction, error_banner, info_banner, rpc, state, StateE, workingWrapper, workingWrapperO} from '../store';
 | 
					    import {error_banner, info_banner, rpc, workingWrapper, workingWrapperO} from '../store';
 | 
				
			||||||
 | 
					    import {replace} from 'svelte-spa-router';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let enter_key = false;
 | 
					    let enter_key = false;
 | 
				
			||||||
    let username = '', key = '', password = '', password2 = '';
 | 
					    let username = '', key = '', password = '', password2 = '';
 | 
				
			||||||
@@ -20,7 +21,7 @@
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (await workingWrapperO(() => rpc.Auth_reset_password(key, password)))
 | 
					        if (await workingWrapperO(() => rpc.Auth_reset_password(key, password)))
 | 
				
			||||||
            $state.s = StateE.LOGIN;
 | 
					            await replace('/login');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function keyUp(e: KeyboardEvent) {
 | 
					    function keyUp(e: KeyboardEvent) {
 | 
				
			||||||
@@ -49,7 +50,7 @@
 | 
				
			|||||||
            <Input type="password" placeholder="Repeat password" bind:value={password2} on:keyup={keyUp}></Input>
 | 
					            <Input type="password" placeholder="Repeat password" bind:value={password2} on:keyup={keyUp}></Input>
 | 
				
			||||||
        </ButtonGroup>
 | 
					        </ButtonGroup>
 | 
				
			||||||
        <ButtonGroup class="w-full flex flex-nowrap">
 | 
					        <ButtonGroup class="w-full flex flex-nowrap">
 | 
				
			||||||
            <Button class="flex-1 flex-grow" color="primary" outline on:click={changeStateFunction(StateE.LOGIN)}>Login</Button>
 | 
					            <Button class="flex-1 flex-grow" color="primary" outline href="#/login">Login</Button>
 | 
				
			||||||
            <Button class="flex-1 flex-grow" color="primary" on:click={changePw}>Change password</Button>
 | 
					            <Button class="flex-1 flex-grow" color="primary" on:click={changePw}>Change password</Button>
 | 
				
			||||||
        </ButtonGroup>
 | 
					        </ButtonGroup>
 | 
				
			||||||
    {:else}
 | 
					    {:else}
 | 
				
			||||||
@@ -58,7 +59,7 @@
 | 
				
			|||||||
            <Input type="email" placeholder="Email" bind:value={username} on:keyup={keyUp}></Input>
 | 
					            <Input type="email" placeholder="Email" bind:value={username} on:keyup={keyUp}></Input>
 | 
				
			||||||
        </ButtonGroup>
 | 
					        </ButtonGroup>
 | 
				
			||||||
        <ButtonGroup class="w-full flex flex-nowrap">
 | 
					        <ButtonGroup class="w-full flex flex-nowrap">
 | 
				
			||||||
            <Button class="flex-1 flex-grow" color="primary" outline on:click={changeStateFunction(StateE.LOGIN)}>Login</Button>
 | 
					            <Button class="flex-1 flex-grow" color="primary" outline href="#/login">Login</Button>
 | 
				
			||||||
            <Button class="flex-1 flex-grow" color="primary" on:click={sendKey}>Send recovery key</Button>
 | 
					            <Button class="flex-1 flex-grow" color="primary" on:click={sendKey}>Send recovery key</Button>
 | 
				
			||||||
            <Button class="flex-1 flex-grow" color="primary" outline on:click={() => (enter_key = true)}>Enter key</Button>
 | 
					            <Button class="flex-1 flex-grow" color="primary" outline on:click={() => (enter_key = true)}>Enter key</Button>
 | 
				
			||||||
        </ButtonGroup>
 | 
					        </ButtonGroup>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,8 @@
 | 
				
			|||||||
<script lang="ts">
 | 
					<script lang="ts">
 | 
				
			||||||
    import {Button, ButtonGroup, Card, Input, InputAddon} from 'flowbite-svelte';
 | 
					    import {Button, ButtonGroup, Card, Input, InputAddon} from 'flowbite-svelte';
 | 
				
			||||||
    import {Email, Password} from '../icons';
 | 
					    import {Email, Password} from '../icons';
 | 
				
			||||||
    import {changeStateFunction, error_banner, info_banner, rpc, state, StateE, workingWrapperO} from '../store';
 | 
					    import {error_banner, info_banner, rpc, workingWrapperO} from '../store';
 | 
				
			||||||
 | 
					    import {replace} from 'svelte-spa-router';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let username = '', username2 = '', password = '', password2 = '';
 | 
					    let username = '', username2 = '', password = '', password2 = '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -20,7 +21,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        if (resp) {
 | 
					        if (resp) {
 | 
				
			||||||
            info_banner.set('Account created, please wait till an administrator approves it');
 | 
					            info_banner.set('Account created, please wait till an administrator approves it');
 | 
				
			||||||
            $state.s = StateE.LOGIN;
 | 
					            await replace('/login');
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -48,7 +49,7 @@
 | 
				
			|||||||
        <Input type="password" placeholder="Repeat password" bind:value={password2} on:keyup={keyUp}></Input>
 | 
					        <Input type="password" placeholder="Repeat password" bind:value={password2} on:keyup={keyUp}></Input>
 | 
				
			||||||
    </ButtonGroup>
 | 
					    </ButtonGroup>
 | 
				
			||||||
    <ButtonGroup class="w-full flex flex-nowrap">
 | 
					    <ButtonGroup class="w-full flex flex-nowrap">
 | 
				
			||||||
        <Button class="flex-1 flex-grow" color="primary" outline on:click={changeStateFunction(StateE.LOGIN)}>Login</Button>
 | 
					        <Button class="flex-1 flex-grow" color="primary" outline href="#/login">Login</Button>
 | 
				
			||||||
        <Button class="flex-1 flex-grow" color="primary" on:click={signup}>Singup</Button>
 | 
					        <Button class="flex-1 flex-grow" color="primary" on:click={signup}>Singup</Button>
 | 
				
			||||||
    </ButtonGroup>
 | 
					    </ButtonGroup>
 | 
				
			||||||
</Card>
 | 
					</Card>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,9 @@
 | 
				
			|||||||
<script lang="ts">
 | 
					<script lang="ts">
 | 
				
			||||||
    import {Button, ButtonGroup, Card, Input, InputAddon, StepIndicator, Tooltip} from 'flowbite-svelte';
 | 
					    import {Button, ButtonGroup, Card, Input, InputAddon, StepIndicator, Tooltip} from 'flowbite-svelte';
 | 
				
			||||||
    import {OTP} from '../icons';
 | 
					    import {OTP} from '../icons';
 | 
				
			||||||
    import {info_banner, rpc, session, state, StateE, token, workingWrapperO, workingWrapperR} from '../store';
 | 
					    import {info_banner, rpc, session, token, workingWrapperO, workingWrapperR} from '../store';
 | 
				
			||||||
    import QRCode from 'qrcode-svg';
 | 
					    import QRCode from 'qrcode-svg';
 | 
				
			||||||
 | 
					    import {replace} from 'svelte-spa-router';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const s = session.s;
 | 
					    const s = session.s;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -35,7 +36,6 @@
 | 
				
			|||||||
    async function completeSetup() {
 | 
					    async function completeSetup() {
 | 
				
			||||||
        if (await workingWrapperO(() => rpc.Auth_tfa_complete($token ?? '', code))) {
 | 
					        if (await workingWrapperO(() => rpc.Auth_tfa_complete($token ?? '', code))) {
 | 
				
			||||||
            info_banner.set("Successfully set up two factor authentication");
 | 
					            info_banner.set("Successfully set up two factor authentication");
 | 
				
			||||||
            $state.s = StateE.LOGIN;
 | 
					 | 
				
			||||||
            token.set(null);
 | 
					            token.set(null);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,33 +1,38 @@
 | 
				
			|||||||
<script lang="ts">
 | 
					<script lang="ts">
 | 
				
			||||||
    import {Breadcrumb, Dropzone, Modal, Progressbar} from 'flowbite-svelte';
 | 
					    import {Breadcrumb, Dropzone, Modal, Progressbar} from 'flowbite-svelte';
 | 
				
			||||||
    import {derived} from 'svelte/store';
 | 
					    import {writable} from 'svelte/store';
 | 
				
			||||||
    import {CloudUpload} from '../icons';
 | 
					    import {CloudUpload} from '../icons';
 | 
				
			||||||
    import {api, changeStateFunction, rpc, state, StateE, token, type UploadFile, workingWrapperR} from '../store';
 | 
					    import {api, rpc, token, type UploadFile, workingWrapperR} from '../store';
 | 
				
			||||||
    import LinkButton from '../components/LinkButton.svelte';
 | 
					 | 
				
			||||||
    import DirViewer from '../components/DirViewer.svelte';
 | 
					    import DirViewer from '../components/DirViewer.svelte';
 | 
				
			||||||
    import UploadModal from '../components/UploadModal.svelte';
 | 
					    import UploadModal from '../components/UploadModal.svelte';
 | 
				
			||||||
    import FileViewer from '../components/FileViewer.svelte';
 | 
					    import FileViewer from '../components/FileViewer.svelte';
 | 
				
			||||||
 | 
					    import A from '../components/A.svelte';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    interface Data {
 | 
					    interface Data {
 | 
				
			||||||
        node: api.Node|null,
 | 
					        node: api.Node|null,
 | 
				
			||||||
        segments: api.PathSegment[]
 | 
					        segments: api.PathSegment[]
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let data = derived<typeof state, Data>(
 | 
					    export let params: {id?: string}|undefined = {};
 | 
				
			||||||
        state,
 | 
					    $: {
 | 
				
			||||||
        ($state, set) => {
 | 
					        let id = 0;
 | 
				
			||||||
            (async () => {
 | 
					        if (params && params.id) {
 | 
				
			||||||
                let node = await workingWrapperR<api.Node>(() => rpc.FS_get_node($token ?? '', $state.view_node));
 | 
					            id = parseInt(params.id);
 | 
				
			||||||
                if (!node)
 | 
					            if (id >= 0)
 | 
				
			||||||
                    return $state.view_node = 0;
 | 
					                updateData(id);
 | 
				
			||||||
                let segments = await workingWrapperR<api.PathSegment[]>(() => rpc.FS_get_path($token ?? '', node!.id));
 | 
					        }
 | 
				
			||||||
                if (!segments)
 | 
					    }
 | 
				
			||||||
                    return $state.view_node = 0;
 | 
					
 | 
				
			||||||
                set({node: node as Data['node'], segments });
 | 
					    const data = writable<Data>({node: null, segments: []});
 | 
				
			||||||
            })();
 | 
					    async function updateData(id: number) {
 | 
				
			||||||
        },
 | 
					        let node = await workingWrapperR<api.Node>(() => rpc.FS_get_node($token ?? '', id));
 | 
				
			||||||
        { node: null, segments: [] }
 | 
					        if (!node)
 | 
				
			||||||
    );
 | 
					            return;
 | 
				
			||||||
 | 
					        let segments = await workingWrapperR<api.PathSegment[]>(() => rpc.FS_get_path($token ?? '', id));
 | 
				
			||||||
 | 
					        if (!segments)
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        data.set({node: node as Data['node'], segments });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const getFile = async (entry: FileSystemEntry) => new Promise<File>((o, e) => (entry as FileSystemFileEntry).file(o, e));
 | 
					    const getFile = async (entry: FileSystemEntry) => new Promise<File>((o, e) => (entry as FileSystemFileEntry).file(o, e));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -70,7 +75,7 @@
 | 
				
			|||||||
        const files: UploadFile[] = [];
 | 
					        const files: UploadFile[] = [];
 | 
				
			||||||
        for (const f of input.files)
 | 
					        for (const f of input.files)
 | 
				
			||||||
            files.push({
 | 
					            files.push({
 | 
				
			||||||
                id: $state.view_node,
 | 
					                id: $data.node?.id ?? 0,
 | 
				
			||||||
                name: f.name,
 | 
					                name: f.name,
 | 
				
			||||||
                full_name: f.name,
 | 
					                full_name: f.name,
 | 
				
			||||||
                file: f,
 | 
					                file: f,
 | 
				
			||||||
@@ -89,7 +94,7 @@
 | 
				
			|||||||
            if (!entry)
 | 
					            if (!entry)
 | 
				
			||||||
                console.error("Failed to get entry for: ", i);
 | 
					                console.error("Failed to get entry for: ", i);
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
                files.push(...await handleEntry($state.view_node, '', entry));
 | 
					                files.push(...await handleEntry($data.node?.id ?? 0, '', entry));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        await upload(files);
 | 
					        await upload(files);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -120,7 +125,7 @@
 | 
				
			|||||||
                {#if i > 0}<li class="inline-flex items-center">/</li>{/if}
 | 
					                {#if i > 0}<li class="inline-flex items-center">/</li>{/if}
 | 
				
			||||||
                <li class="inline-flex items-center">
 | 
					                <li class="inline-flex items-center">
 | 
				
			||||||
                    {#if segment.id !== null}
 | 
					                    {#if segment.id !== null}
 | 
				
			||||||
                        <LinkButton on:click={changeStateFunction(StateE.VIEW, segment.id)}>{segment.id === 0 ? 'Files' : segment.name}</LinkButton>
 | 
					                        <A href={'#/view/' + segment.id}>{segment.id === 0 ? 'Files' : segment.name}</A>
 | 
				
			||||||
                    {:else}
 | 
					                    {:else}
 | 
				
			||||||
                        <span style="padding: 0 0.25em;">{segment.name}</span>
 | 
					                        <span style="padding: 0 0.25em;">{segment.name}</span>
 | 
				
			||||||
                    {/if}
 | 
					                    {/if}
 | 
				
			||||||
@@ -142,10 +147,10 @@
 | 
				
			|||||||
    {:else if $data.node.file}
 | 
					    {:else if $data.node.file}
 | 
				
			||||||
        <FileViewer node={$data.node} />
 | 
					        <FileViewer node={$data.node} />
 | 
				
			||||||
    {:else}
 | 
					    {:else}
 | 
				
			||||||
        <DirViewer node={$data.node} />
 | 
					        <DirViewer node={$data.node} on:reload_node={() => updateData($data.node?.id ?? 0)} />
 | 
				
			||||||
    {/if}
 | 
					    {/if}
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
<UploadModal bind:upload={real_upload}/>
 | 
					<UploadModal bind:upload={real_upload} on:reload_node={() => updateData($data.node?.id ?? 0)} />
 | 
				
			||||||
{#if upload_progress_data.current !== upload_progress_data.total}
 | 
					{#if upload_progress_data.current !== upload_progress_data.total}
 | 
				
			||||||
    <Modal open dismissable={false} title="Creating files">
 | 
					    <Modal open dismissable={false} title="Creating files">
 | 
				
			||||||
        <div class="mb-1 flex justify-between">
 | 
					        <div class="mb-1 flex justify-between">
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										17
									
								
								frontend/src/routes.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								frontend/src/routes.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					import Login from './pages/Login.svelte';
 | 
				
			||||||
 | 
					import Signup from './pages/Signup.svelte';
 | 
				
			||||||
 | 
					import ResetPassword from './pages/ResetPassword.svelte';
 | 
				
			||||||
 | 
					import Profile from './pages/Profile.svelte';
 | 
				
			||||||
 | 
					import TfaSetup from './pages/TfaSetup.svelte';
 | 
				
			||||||
 | 
					import Admin from './pages/Admin.svelte';
 | 
				
			||||||
 | 
					import View from './pages/View.svelte';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const routes = {
 | 
				
			||||||
 | 
					    '/login': Login,
 | 
				
			||||||
 | 
					    '/signup': Signup,
 | 
				
			||||||
 | 
					    '/reset_pw': ResetPassword,
 | 
				
			||||||
 | 
					    '/profile': Profile,
 | 
				
			||||||
 | 
					    '/tfa': TfaSetup,
 | 
				
			||||||
 | 
					    '/admin': Admin,
 | 
				
			||||||
 | 
					    '/view/:id': View
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,14 +1,9 @@
 | 
				
			|||||||
import {MRPCConnector, type Session, type Response} from './api';
 | 
					import {MRPCConnector, type Session, type Response} from './api';
 | 
				
			||||||
import {get, type Writable, writable} from 'svelte/store';
 | 
					import {type Writable, writable} from 'svelte/store';
 | 
				
			||||||
import {filesize} from 'filesize';
 | 
					import {filesize} from 'filesize';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export * as api from './api';
 | 
					export * as api from './api';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export enum StateE { LOGIN, SIGNUP, RESET_PASSWORD, PROFILE, TFA_SETUP, ADMIN, VIEW }
 | 
					 | 
				
			||||||
export interface State {
 | 
					 | 
				
			||||||
    s: StateE,
 | 
					 | 
				
			||||||
    view_node: number
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
export interface UploadFile {
 | 
					export interface UploadFile {
 | 
				
			||||||
    id: number,
 | 
					    id: number,
 | 
				
			||||||
    name: string,
 | 
					    name: string,
 | 
				
			||||||
@@ -21,15 +16,12 @@ export const show_working = writable<boolean>(false);
 | 
				
			|||||||
export const info_banner = writable<string>('');
 | 
					export const info_banner = writable<string>('');
 | 
				
			||||||
export const error_banner = writable<string>('');
 | 
					export const error_banner = writable<string>('');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const state = writable<State>({s: StateE.LOGIN, view_node: 0});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const rpc = new MRPCConnector('/mrpc');
 | 
					export const rpc = new MRPCConnector('/mrpc');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const token = writable<string|null>(localStorage.getItem('token'));
 | 
					export const token = writable<string|null>(localStorage.getItem('token'));
 | 
				
			||||||
export const session: { s: Writable<Session|null>, update: (token: string|null) => Promise<void> } = {
 | 
					export const session: { s: Writable<Session|null>, update: (token: string|null) => Promise<void> } = {
 | 
				
			||||||
    s: writable(null),
 | 
					    s: writable(null),
 | 
				
			||||||
    update: async (t: string|null) => {
 | 
					    update: async (t: string|null) => {
 | 
				
			||||||
        console.log('S');
 | 
					 | 
				
			||||||
        if (t == null) {
 | 
					        if (t == null) {
 | 
				
			||||||
            session.s.set(null);
 | 
					            session.s.set(null);
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
@@ -50,14 +42,6 @@ token.subscribe(v => {
 | 
				
			|||||||
        localStorage.setItem('token', v);
 | 
					        localStorage.setItem('token', v);
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
export function changeStateFunction(target: StateE, node?: number): () => void {
 | 
					 | 
				
			||||||
    return () => {
 | 
					 | 
				
			||||||
        const new_node = node ?? get(state).view_node;
 | 
					 | 
				
			||||||
        state.set({s: target, view_node: new_node});
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export async function workingWrapper<T>(fn: () => Promise<T>): Promise<T|null> {
 | 
					export async function workingWrapper<T>(fn: () => Promise<T>): Promise<T|null> {
 | 
				
			||||||
    let r = null;
 | 
					    let r = null;
 | 
				
			||||||
    error_banner.set('');
 | 
					    error_banner.set('');
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user