lint things, add sidebar

This commit is contained in:
Vargha Csongor
2025-04-29 17:10:06 +02:00
parent e5061d6b4f
commit 9802513d8e
20 changed files with 2374 additions and 2315 deletions

2
.vscode/launch.json vendored
View File

@@ -11,7 +11,7 @@
"mode": "debug",
"program": "${workspaceFolder}/apps/db-adapter/main.go",
"env": {
"HTTP_PORT": ":8080",
"HTTP_PORT": ":5237",
"MEMGRAPH_URI": "bolt://127.0.0.1:7687",
"MEMGRAPH_USER": "memgraph",
"MEMGRAPH_PASSWORD": "memgraph"

View File

@@ -158,5 +158,6 @@
"welcome": "Welcome to Generations Heritage",
"yes": "Yes",
"zip_code": "Zip Code",
"add_life_event": "Add life-event"
"add_life_event": "Add life-event",
"deleted_profiles": "Deleted profiles"
}

View File

@@ -156,5 +156,7 @@
"welcome": "Üdvözöljük a Generációk Öröksége oldalán",
"yes": "Igen",
"zip_code": "Irányítószám",
"add_life_event": "Életesemény hozzadása"
"add_life_event": "Életesemény hozzadása",
"deleted_profiles": "Törölt profilok",
"managed_profiles": "Adminisztrált profilok"
}

View File

@@ -69,4 +69,4 @@
"openapi-fetch": "^0.13.5",
"pikaday": "^1.8.2"
}
}
}

View File

@@ -27,7 +27,7 @@ const authHandle: Handle = async ({ event, resolve }) => {
if (session !== null) {
setSessionTokenCookie(event, token, session.expiresAt);
} else {
console.log('Session token is invalid');
console.error('Session token is invalid');
deleteSessionTokenCookie(event);
}

File diff suppressed because it is too large Load Diff

View File

@@ -7,6 +7,8 @@
add_administrator
} from '$lib/paraglide/messages';
export let id: string;
export let XUserId: string;
export let top: number | undefined;
export let left: number | undefined;
export let right: number | undefined;
@@ -18,6 +20,7 @@
export let addAdmin: (() => void) | undefined;
let contextMenu: HTMLDivElement;
let isAdmin: boolean = false;
onMount(() => {
if (top) {
contextMenu.style.top = `${top}px`;
@@ -31,6 +34,16 @@
if (bottom) {
contextMenu.style.bottom = `${bottom}px`;
}
fetch(`/api/admin/${id}/${XUserId}`
).then((response) => {
if(response.status === 200){
isAdmin = true;
}else {
isAdmin = false
}
}).catch((error) => {
console.error('Error fetching admin status:', error);
});
});
</script>
@@ -51,7 +64,9 @@
</button>
<button onclick={addRelationship} class="btn">{add_relationship()}</button>
<button onclick={addAdmin} class="btn">{add_administrator()}</button>
<button onclick={deleteNode} class="btn">{remove()}</button>
{#if (Number(XUserId) !== Number(id)) && isAdmin}
<button onclick={deleteNode} class="btn">{remove()}</button>
{/if}
</div>
<style>

View File

@@ -78,7 +78,7 @@ export class FamilyTree extends dagre.graphlib.Graph {
}
newEdge.type = 'smoothstep';
newEdges.push(newEdge), newEdge;
newEdges.push(newEdge);
});
const layoutedNodes = nodes.map((node) => {

View File

@@ -10,6 +10,8 @@ export type NodeMenu = {
addRelationship: () => void;
addRecipe: (() => void) | undefined;
addAdmin: (() => void) | undefined;
id: string;
XUserId: string;
top: number | undefined;
left: number | undefined;
right: number | undefined;

View File

@@ -44,8 +44,8 @@
} = $props();
let birth_date: HTMLInputElement;
let relationship_from_time: HTMLInputElement;
let relationship_until: HTMLInputElement;
let relationship_from_time: HTMLInputElement = $state({} as HTMLInputElement);
let relationship_until: HTMLInputElement = $state({} as HTMLInputElement);
let draftRelationship: (components['schemas']['FamilyRelationship'] & { type: string }) | null =
$state({} as components['schemas']['FamilyRelationship'] & { type: string });
@@ -266,22 +266,22 @@
></textarea>
</div>
<div class="flex flex-col">
<label class="label" for="from_time">{from_time()}</label>
<label class="label" for="relationship_from_time">{from_time()}</label>
<input
type="text"
name="from_time"
id="from_time"
name="relationship_from_time"
id="relationship_from_time"
class="input input-bordered validator pika-single"
placeholder={optional_field()}
bind:this={relationship_from_time}
/>
</div>
<div class="flex flex-col">
<label class="label" for="until">{until()}</label>
<label class="label" for="relationship_until">{until()}</label>
<input
type="text"
name="until"
id="until"
name="relationship_until"
id="relationship_until"
class="input input-bordered validator pika-single"
placeholder={optional_field()}
bind:this={relationship_until}

View File

@@ -0,0 +1,34 @@
<script>
export let show = false;
</script>
{#if show}
<label for="my-drawer" class="btn btn-circle drawer-button swap swap-rotate">
<!-- this hidden checkbox controls the state -->
<input id="my-drawer" type="checkbox" class="drawer-toggle" />
<!-- hamburger icon -->
<svg
class="swap-off fill-current"
xmlns="http://www.w3.org/2000/svg"
width="32"
height="32"
viewBox="0 0 512 512"
>
<path d="M64,384H448V341.33H64Zm0-106.67H448V234.67H64ZM64,128v42.67H448V128Z" />
</svg>
<!-- close icon -->
<svg
class="swap-on fill-current"
xmlns="http://www.w3.org/2000/svg"
width="32"
height="32"
viewBox="0 0 512 512"
>
<polygon
points="400 145.49 366.51 112 256 222.51 145.49 112 112 145.49 222.51 256 112 366.51 145.49 400 256 289.49 366.51 400 400 366.51 289.49 256 400 145.49"
/>
</svg>
</label>
{/if}

View File

@@ -0,0 +1,12 @@
<script>
import { deleted_profiles, managed_profiles } from '$lib/paraglide/messages';
</script>
<div class="drawer-side">
<label for="my-drawer" aria-label="close sidebar" class="drawer-overlay"></label>
<ul class="menu bg-base-200 text-base-content min-h-full w-80 p-4">
<!-- Sidebar content here -->
<li><button class="btn btn-soft btn-primary">{managed_profiles}</button></li>
<li><button class="btn btn-soft btn-primary">{deleted_profiles()}</button></li>
</ul>
</div>

View File

@@ -1,4 +1,5 @@
import { describe, it, expect, vi } from 'vitest';
import type { Mock } from 'vitest';
import { switchToLanguage } from './switchToLanguage';
import { i18n } from '$lib/i18n';
import { goto } from '$app/navigation';
@@ -28,8 +29,8 @@ describe('switchToLanguage', () => {
const canonicalPath = '/canonical-path';
const localisedPath = '/en/canonical-path';
i18n.route.mockReturnValue(canonicalPath);
i18n.resolveRoute.mockReturnValue(localisedPath);
(i18n.route as Mock).mockReturnValue(canonicalPath);
(i18n.resolveRoute as Mock).mockReturnValue(localisedPath);
switchToLanguage(newLanguage);

View File

@@ -6,10 +6,14 @@
import ThemeButton from '$lib/ThemeSelect.svelte';
import Logout from '$lib/Logout.svelte';
import { page } from '$app/state';
import HamburgerIcon from '$lib/sidebar/hamburgerIcon.svelte';
</script>
<ParaglideJS {i18n}>
{@render children()}
<div class="absolute top-2 left-2 flex flex-row items-center gap-2">
<HamburgerIcon show={!page.url.pathname.includes('login')} />
</div>
<div class="absolute top-2 right-2 flex flex-row items-center gap-2">
<ThemeButton />
<Logout show={!page.url.pathname.includes('login')} />

View File

@@ -1,5 +1,5 @@
import { redirect } from '@sveltejs/kit';
import { parseFamilyTree } from '$lib/graph/fetch_family_tree';
import { parseFamilyTree } from '$lib/graph/parse_family_tree';
import type { components } from '$lib/api/api.gen';
import type { RequestEvent } from './$types';
import { browser } from '$app/environment';
@@ -24,7 +24,6 @@ export async function load(event: RequestEvent) {
}
const data = (await response.json()) as components['schemas']['FamilyTree'];
const layout = parseFamilyTree(data) as Layout & { id: string };
layout.id = event.locals.session.userId;

View File

@@ -10,9 +10,8 @@
ConnectionLineType
} from '@xyflow/svelte';
import '@xyflow/svelte/dist/style.css';
import type { Node, Edge, NodeTypes, NodeEventWithPointer } from '@xyflow/svelte';
import type { Node, Edge, NodeEventWithPointer } from '@xyflow/svelte';
import PersonNode from '$lib/graph/PersonNode.svelte';
import PersonModal from '$lib/profile/Modal.svelte';
import PersonMenu from '$lib/graph/PersonMenu.svelte';
import CreatePerson from '$lib/profile/create/Modal.svelte';
@@ -21,11 +20,12 @@
import type { NodeMenu } from '$lib/graph/model';
import { handleNodeClick } from '$lib/graph/node_click';
import { onMount } from 'svelte';
import { FamilyTree } from '$lib/graph/layout';
import { tailwindClassToPixels } from '$lib/tailwindSizeToPx';
import type { Layout } from '$lib/graph/model';
import SideBar from '$lib/sidebar/sideBar.svelte';
let { data }: { data: Layout & { id: string } } = $props();
let selectedPerson: components['schemas']['PersonProperties'] & { id: number | null } = $state({
@@ -62,6 +62,7 @@
}
openPersonMenu = {
XUserId: data.id,
onClick: () => {
openPersonMenu = undefined;
},
@@ -108,6 +109,7 @@
relationshipStart = Number(node.id);
openPersonMenu = undefined;
},
id: node.id,
top: event.clientY < clientHeight - 200 ? event.clientY : undefined,
left: event.clientX < clientWidth - 200 ? event.clientX : undefined,
right: event.clientX >= clientWidth - 200 ? clientWidth - event.clientX : undefined,
@@ -178,46 +180,48 @@
<svelte:head>
<title>{title({ page: family_tree() })}</title>
</svelte:head>
<div style="height:100vh;" class="!bg-base-200 flex flex-col">
<SvelteFlowProvider>
<SvelteFlow
bind:nodes
bind:edges
onnodeclick={handleNodeClickFunc}
onnodecontextmenu={handleContextMenu}
onpaneclick={handlePaneClick}
class="!bg-base-200"
{nodeTypes}
fitView
onlyRenderVisibleElements
connectionLineType={ConnectionLineType.SmoothStep}
>
<MiniMap class="!bg-base-300" />
<Controls class="!bg-base-300" />
{#if openPersonPanel}
<PersonModal
person={selectedPerson}
closeModal={() => {
openPersonPanel = false;
}}
/>
{/if}
{#if createPerson}
<CreatePerson
onOnlyPersonCreation={() => {
createPerson = false;
}}
{onCreation}
closeModal={() => {
createPerson = false;
}}
relationshipStartID={relationshipStart}
></CreatePerson>
{/if}
{#if openPersonMenu !== undefined}
<PersonMenu {...openPersonMenu!} />
{/if}
</SvelteFlow>
</SvelteFlowProvider>
<div class="drawer">
<div style="height:100vh;" class="!bg-base-200 drawer-content flex flex-col">
<SvelteFlowProvider>
<SvelteFlow
bind:nodes
bind:edges
onnodeclick={handleNodeClickFunc}
onnodecontextmenu={handleContextMenu}
onpaneclick={handlePaneClick}
class="!bg-base-200"
{nodeTypes}
fitView
onlyRenderVisibleElements
connectionLineType={ConnectionLineType.SmoothStep}
>
<MiniMap class="!bg-base-300" />
<Controls class="!bg-base-300" />
{#if openPersonPanel}
<PersonModal
person={selectedPerson}
closeModal={() => {
openPersonPanel = false;
}}
/>
{/if}
{#if createPerson}
<CreatePerson
onOnlyPersonCreation={() => {
createPerson = false;
}}
{onCreation}
closeModal={() => {
createPerson = false;
}}
relationshipStartID={relationshipStart}
></CreatePerson>
{/if}
{#if openPersonMenu !== undefined}
<PersonMenu {...openPersonMenu!} />
{/if}
</SvelteFlow>
</SvelteFlowProvider>
</div>
<SideBar />
</div>

View File

@@ -35,7 +35,7 @@ export async function GET(event: RequestEvent): Promise<Response> {
message: 'Family tree is empty'
});
}
var graphToReturn: components['schemas']['FamilyTree'] = {
people: [],
relationships: response.data.relationships

View File

@@ -20,7 +20,7 @@ export async function POST(event: RequestEvent): Promise<Response> {
}
});
if (response.response.ok) {
if (response.response.ok && response.response.status === 200) {
return new Response(JSON.stringify(response.data), {
status: response.response.status
});

View File

@@ -53,6 +53,7 @@ func (srv *server) GetFamilyTreeWithSpousesById(
err = FlattenFamilyTree(res, &results)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
return
}