diff --git a/UnicadoGUI/Frontend/src/lib/BaseButton.svelte b/UnicadoGUI/Frontend/src/lib/BaseButton.svelte new file mode 100644 index 0000000000000000000000000000000000000000..ba58bbe99edcd0d1066fd9ecd47ef864739a73ed --- /dev/null +++ b/UnicadoGUI/Frontend/src/lib/BaseButton.svelte @@ -0,0 +1,17 @@ +<script> + import { Button, Icon } from "@sveltestrap/sveltestrap"; + + export let color = "primary"; + export let outline = false; + export let iconName = ""; + export let text = ""; + export let onClick = () => {}; + +</script> + +<Button {color} {outline} on:click={onClick}> + {#if iconName} + <Icon name={iconName} />{' '} + {/if} + {text} +</Button> diff --git a/UnicadoGUI/Frontend/src/lib/DeleteProjectByIdButton.svelte b/UnicadoGUI/Frontend/src/lib/DeleteProjectByIdButton.svelte new file mode 100644 index 0000000000000000000000000000000000000000..4852c13fe70aec51100af65498eba816cb93c61e --- /dev/null +++ b/UnicadoGUI/Frontend/src/lib/DeleteProjectByIdButton.svelte @@ -0,0 +1,41 @@ +<script lang="ts"> + import { Modal, ModalHeader, ModalBody, ModalFooter, Button, Icon } from "@sveltestrap/sveltestrap"; + import { removeProjectById, getProjectNameById } from '../stores/projects'; + import { createEventDispatcher } from 'svelte'; + + export let projectId : number; + const dispatch = createEventDispatcher(); + let isModalOpen = false; + + function openModal() { + isModalOpen = true; + dispatch('openModal'); + } + + function closeModal() { + isModalOpen = false; + dispatch('closeModal'); + } + + function handleDeleteProject() { + if (projectId) { + removeProjectById(projectId); + closeModal(); + } + } +</script> + +<Button color="danger" outline on:click={openModal}> + <Icon name="trash" /> +</Button> + +<Modal isOpen={isModalOpen} toggle={closeModal}> + <ModalHeader toggle={closeModal}>Remove Project</ModalHeader> + <ModalBody> + <p>Are you sure you want to remove the project with the name: <strong>{getProjectNameById(projectId)}</strong>?</p> + </ModalBody> + <ModalFooter> + <Button color="danger" on:click={handleDeleteProject}>Remove Project</Button> + <Button color="secondary" on:click={closeModal}>Cancel</Button> + </ModalFooter> +</Modal> \ No newline at end of file diff --git a/UnicadoGUI/Frontend/src/lib/DeleteProjectByNameButton.svelte b/UnicadoGUI/Frontend/src/lib/DeleteProjectByNameButton.svelte new file mode 100644 index 0000000000000000000000000000000000000000..1ce1018aaea3ceefcc8bcdeb7ad5dc73675f7e2e --- /dev/null +++ b/UnicadoGUI/Frontend/src/lib/DeleteProjectByNameButton.svelte @@ -0,0 +1,56 @@ +<script lang="ts"> + import { Modal, ModalHeader, ModalBody, ModalFooter, Button, Icon } from "@sveltestrap/sveltestrap"; + import { removeProject } from '../stores/projects'; + import { createEventDispatcher } from 'svelte'; + + export let projectToRemove = ''; // Der Name des zu löschenden Projekts + const dispatch = createEventDispatcher(); + let isModalOpen = false; + + function openModal() { + isModalOpen = true; + dispatch('openModal'); // Optional: Benachrichtige Hauptkomponente + } + + function closeModal() { + isModalOpen = false; + dispatch('closeModal'); // Optional: Benachrichtige Hauptkomponente + } + + function handleDeleteProject() { + if (projectToRemove.trim() !== '') { + removeProject(projectToRemove); + projectToRemove = ''; // Eingabefeld leeren + closeModal(); // Modal schließen nach dem Löschen + } + } + + function handleKeyDown(event: KeyboardEvent) { + if (event.key === 'Enter') { + handleDeleteProject(); + } + } +</script> + +<!-- Button zum Öffnen des Modals --> +<Button color="danger" outline on:click={openModal}> + <Icon name="trash" /> Remove Project +</Button> + +<!-- Modal zum Löschen eines Projekts --> +<Modal isOpen={isModalOpen} toggle={closeModal}> + <ModalHeader toggle={closeModal}>Remove Project</ModalHeader> + <ModalBody> + <input + type="text" + bind:value={projectToRemove} + placeholder="Enter project name to remove..." + class="form-control" + on:keydown={handleKeyDown} + /> + </ModalBody> + <ModalFooter> + <Button color="danger" on:click={handleDeleteProject}>Remove Project</Button> + <Button color="secondary" on:click={closeModal}>Cancel</Button> + </ModalFooter> +</Modal> diff --git a/UnicadoGUI/Frontend/src/lib/LoadProjectsFromServerButton.svelte b/UnicadoGUI/Frontend/src/lib/LoadProjectsFromServerButton.svelte new file mode 100644 index 0000000000000000000000000000000000000000..11a882a788aec9fad95454eeb271d719e9fca96d --- /dev/null +++ b/UnicadoGUI/Frontend/src/lib/LoadProjectsFromServerButton.svelte @@ -0,0 +1,18 @@ +<script> + import { Button, Icon } from "@sveltestrap/sveltestrap"; + import { loadProjectsFromServer } from '../stores/projects'; + + const triggerFileDownload = async () => { + try { + await loadProjectsFromServer(); + console.log("Project list Loaded successfully"); + } catch (error) { + console.error("Error while trying to load the project list", error); + } + } +</script> + +<Button on:click={triggerFileDownload}> + <Icon name="cloud-upload"/> + Load project Liste from the server +</Button> \ No newline at end of file diff --git a/UnicadoGUI/Frontend/src/lib/LoadProjectsFromZipButton.svelte b/UnicadoGUI/Frontend/src/lib/LoadProjectsFromZipButton.svelte new file mode 100644 index 0000000000000000000000000000000000000000..6b864982adf7860b6397b49f54f0c906d3ae569b --- /dev/null +++ b/UnicadoGUI/Frontend/src/lib/LoadProjectsFromZipButton.svelte @@ -0,0 +1,29 @@ +<script lang="ts"> +import { Button, Icon} from "@sveltestrap/sveltestrap"; +import { loadProjectsFromZip } from '../stores/projects'; + +function handleFileUpload(event : Event) { + const target = event.target as HTMLInputElement; + const selectedFile = target.files ? target.files[0] : null; + if (selectedFile) { + loadProjectsFromZip(selectedFile); + } + } + +function triggerFileInput() { + const fileInput = document.getElementById('file-input'); + if (fileInput) { + fileInput.click(); + } else { + console.error('file-input not found'); + } + } +</script> + +<input type="file" accept=".zip" id="file-input" on:change={handleFileUpload} style="display: none;" /> + + +<Button on:click={triggerFileInput}> + <Icon name="cloud-upload"/> + Load project Liste von zip-file +</Button> \ No newline at end of file diff --git a/UnicadoGUI/Frontend/src/lib/NewProjectButton.svelte b/UnicadoGUI/Frontend/src/lib/NewProjectButton.svelte new file mode 100644 index 0000000000000000000000000000000000000000..6927270890777898af16c542014f7d2fedefc8fd --- /dev/null +++ b/UnicadoGUI/Frontend/src/lib/NewProjectButton.svelte @@ -0,0 +1,51 @@ +<script> + import { Modal, ModalHeader, ModalBody, ModalFooter, Button, Icon } from "@sveltestrap/sveltestrap"; + import { addProject } from '../stores/projects'; + import { createEventDispatcher } from 'svelte'; + + export let projectName = ''; + const dispatch = createEventDispatcher(); + let isModalOpen = false; + + /** function openModal() { + isModalOpen = true; + dispatch('openModal'); + } +*/ + function closeModal() { + isModalOpen = false; + dispatch('closeModal'); + } + + function handleAddProject() { + if (projectName.trim() !== '') { + addProject(projectName); + projectName = ''; + closeModal(); + } + } + + function handleKeyDown(/** @type KeyboardEvent **/ event) { + if (event.key === 'Enter') { + handleAddProject(); + } + } + +</script> + +<Modal isOpen={isModalOpen} toggle={closeModal}> + <ModalHeader toggle={closeModal}>Add New Project</ModalHeader> + <ModalBody> + <input + type="text" + bind:value={projectName} + placeholder="Enter project name..." + class="form-control" + on:keydown={handleKeyDown} + /> + </ModalBody> + <ModalFooter> + <Button color="primary" on:click={handleAddProject}>Add Project</Button> + <Button color="secondary" on:click={closeModal}>Cancel</Button> + </ModalFooter> +</Modal> \ No newline at end of file diff --git a/UnicadoGUI/Frontend/src/lib/SaveProjectsToServerButton.svelte b/UnicadoGUI/Frontend/src/lib/SaveProjectsToServerButton.svelte new file mode 100644 index 0000000000000000000000000000000000000000..96c752f7170baa06679ad9cf37393f41fb5be7fb --- /dev/null +++ b/UnicadoGUI/Frontend/src/lib/SaveProjectsToServerButton.svelte @@ -0,0 +1,18 @@ +<script> + import { Button, Icon} from "@sveltestrap/sveltestrap"; + import { saveProjectsOnServer } from '../stores/projects'; + + const triggerFileUpload = async () => { + try { + await saveProjectsOnServer(); + console.log("Project list saved successfully"); + } catch (error) { + console.error("Error while trying to save the project list", error); + } + } +</script> + +<Button on:click={triggerFileUpload}> + <Icon name="cloud-upload"/> + Save projects list on the server +</Button> \ No newline at end of file diff --git a/UnicadoGUI/Frontend/src/lib/SaveProjectsToZipButton.svelte b/UnicadoGUI/Frontend/src/lib/SaveProjectsToZipButton.svelte new file mode 100644 index 0000000000000000000000000000000000000000..0847799f61d8b60c6a30711bf37ae5e17e8b2861 --- /dev/null +++ b/UnicadoGUI/Frontend/src/lib/SaveProjectsToZipButton.svelte @@ -0,0 +1,20 @@ +<script lang="ts"> + import { Button, Icon } from "@sveltestrap/sveltestrap"; + import { saveProjectsAsZip } from '../stores/projects'; + + const handleSave = async () => { + try { + await saveProjectsAsZip(); + console.log("Projects saved successfully"); + } catch (error) { + console.error("Error while trying to save the project list", error); + } + } +</script> + + + +<Button on:click={handleSave}> + <Icon name="cloud-download"/> + Save Project list to a zip-file +</Button> \ No newline at end of file diff --git a/UnicadoGUI/Frontend/src/routes/+layout.svelte b/UnicadoGUI/Frontend/src/routes/+layout.svelte index de970f03f97b9e5b7a4dc6557d0f382d6e796d8d..d0ae914fc6f9bcc6361e2464f2b137dce773b2be 100644 --- a/UnicadoGUI/Frontend/src/routes/+layout.svelte +++ b/UnicadoGUI/Frontend/src/routes/+layout.svelte @@ -1,8 +1,8 @@ <script lang="ts"> import {Container, Image, Row, Styles, Col, Nav, NavItem, NavLink, Icon, Modal, ModalHeader, ModalBody, ModalFooter, Button} from '@sveltestrap/sveltestrap'; - import { removeProjectbyId, userProjects, addProject } from '../stores/projects'; + import { userProjects, addProject } from '../stores/projects'; import { onMount } from 'svelte'; - + import DeleteProjectByIdButton from '$lib/DeleteProjectByIdButton.svelte'; let projects : any[] = []; let showModal = false; let projectName = ''; @@ -39,9 +39,6 @@ function newProject() { } } - function deleteProject(id: number) { - removeProjectbyId(id); - } </script> <Container fluid> @@ -67,9 +64,7 @@ function newProject() { <Icon name="airplane"></Icon> <span class="ms-1 d-none d-sm-inline">{project.name}</span> </NavLink> - <Button outline on:click={() => deleteProject(project.id)}> - <Icon name="trash"/> <!-- Icon zum Entfernen des Projekts --> - </Button> + <DeleteProjectByIdButton projectId={project.id} /> {#if openProjectIndex === index} <ul class="sub-menu"> diff --git a/UnicadoGUI/Frontend/src/routes/+page.svelte b/UnicadoGUI/Frontend/src/routes/+page.svelte index 2579143ae852bd779432a9f9a3ed4ea3ec4e9182..f6317e014443521b1f1f7223e451a66fd8106869 100644 --- a/UnicadoGUI/Frontend/src/routes/+page.svelte +++ b/UnicadoGUI/Frontend/src/routes/+page.svelte @@ -1,127 +1,25 @@ <script> - import { Button, Styles, Icon, Modal, ModalHeader, ModalBody, ModalFooter} from "@sveltestrap/sveltestrap"; - import { addProject, removeProject, saveProjectsAsZip, loadProjectsFromZip, saveProjectsOnServer, loadProjectsFromServer } from '../stores/projects'; - let projectName = ''; - let projectToRemove = ''; - let showModal = false; + import { Styles } from "@sveltestrap/sveltestrap"; - function newProject() { - if (projectName.trim() !== '') { - addProject(projectName); - projectName = ''; - closeModal() - } - } - - function deleteProject() { - if (projectToRemove.trim() !== '') { - removeProject(projectToRemove); - projectToRemove = ''; - } - } - - function openModal() { - showModal = true; - } - - function closeModal() { - showModal = false; - } - const handleSave = async () => { - try { - await saveProjectsAsZip(); - console.log("Projects saved successfully"); - } catch (error) { - console.error("Error while trying to save the project list", error); - } - } - - function handleFileUpload(/** @type any */event) { - const selectedFile = event.target.files[0]; - if (selectedFile) { - loadProjectsFromZip(selectedFile); - } - } - - function triggerFileInput() { - const fileInput = document.getElementById('file-input'); - if (fileInput) { - fileInput.click(); - } else { - console.error('file-input not found'); - } - } - - const triggerFileUpload = async () => { - try { - await saveProjectsOnServer(); - console.log("Project list saved successfully"); - } catch (error) { - console.error("Error while trying to save the project list", error); - } - } - - - const triggerFileDownload = async () => { - try { - await loadProjectsFromServer(); - console.log("Project list Loaded successfully"); - } catch (error) { - console.error("Error while trying to load the project list", error); - } - } + let projectName = ""; + let projectToRemove = ""; + import NewProjectButton from "$lib/NewProjectButton.svelte"; + import DeleteProjectButton from "$lib/DeleteProjectByNameButton.svelte"; + import SaveProjectsToZipButton from "$lib/SaveProjectsToZipButton.svelte"; + import LoadProjectsFromZipButton from "$lib/LoadProjectsFromZipButton.svelte"; + import LoadProjectFromServerButton from "$lib/LoadProjectsFromServerButton.svelte"; + import SaveProjectsToServerButton from "$lib/SaveProjectsToServerButton.svelte"; </script> -<h1>Welcome to the UNICADO WebApp</h1> - -<Button color="dark" outline on:click={openModal}> - <Icon name="window-plus"/> - New Project -</Button> - -<Button color="dark" outline on:click={deleteProject}> - <Icon name="window-plus"/> - Remove Project -</Button> - -<Button on:click={handleSave}> - <Icon name="cloud-download"/> - Save Project list to a zip-file -</Button> -<input type="file" accept=".zip" id="file-input" on:change={handleFileUpload} style="display: none;" /> - -<Button on:click={triggerFileInput}> - <Icon name="cloud-upload"/> - Load project Liste von zip-file -</Button> - -<Button on:click={triggerFileUpload}> - <Icon name="cloud-upload"/> - Save projects list on the server -</Button> +<h1>Welcome to the UNICADO WebApp</h1> -<Button on:click={triggerFileDownload}> - <Icon name="cloud-upload"/> - Load project Liste from the server -</Button> -{#if showModal} - <Modal isOpen={showModal} toggle={closeModal}> - <ModalHeader toggle={closeModal}>Add New Project</ModalHeader> - <ModalBody> - <input - type="text" - bind:value={projectName} - placeholder="Enter project name..." - /> - </ModalBody> - <ModalFooter> - <Button color="primary" on:click={newProject}>Add Project</Button>{' '} - <Button color="secondary" on:click={closeModal}>Cancel</Button> - </ModalFooter> - </Modal> -{/if} +<NewProjectButton bind:projectName /> +<DeleteProjectButton bind:projectToRemove /> +<SaveProjectsToZipButton /> +<LoadProjectsFromZipButton /> -<p>Create new Project....<br>Open existing Project...</p> +<LoadProjectFromServerButton /> +<SaveProjectsToServerButton /> -<Styles/> \ No newline at end of file +<Styles /> diff --git a/UnicadoGUI/Frontend/src/stores/projects.js b/UnicadoGUI/Frontend/src/stores/projects.js index 830e7814f6397e813582fb93c022b27fc45ddde1..c6bedbfc3cc9be1e5c3f5b8c3b3fa008715d464e 100644 --- a/UnicadoGUI/Frontend/src/stores/projects.js +++ b/UnicadoGUI/Frontend/src/stores/projects.js @@ -45,7 +45,7 @@ export function removeProject(name) { /** * @param {number} id */ -export function removeProjectbyId(id) { +export function removeProjectById(id) { userProjects.update(projects => { return projects.filter((/** @type {{ id: number; }} */ project) => project.id !== id); }); @@ -64,7 +64,6 @@ export function removeProjectbyId(id) { * @returns {Promise<void>} */ export const saveProjectsAsZip = async () => { - const zip = new JSZip(); /** @type {Project[]} */ let projectArray = []; @@ -77,10 +76,26 @@ export const saveProjectsAsZip = async () => { const a = document.createElement('a'); a.href = url; a.download = 'projects.zip'; + + document.body.appendChild(a); a.click(); + + document.body.removeChild(a); URL.revokeObjectURL(url); }; +/** + * @param {number} id - Die Projekt-ID + * @returns {string | undefined} - Der Name des Projekts oder undefined, wenn nicht gefunden + */ +export function getProjectNameById(id) { + let projectName; + userProjects.subscribe((projects) => { + const project = projects.find( (/** @type {Project} */ p) => p.id === id); + projectName = project ? project.name : undefined; + })(); + return projectName; +} /**