From 8f3832657b5300ee444bdc47ea7781820db58f13 Mon Sep 17 00:00:00 2001 From: Fritz Heiden Date: Tue, 15 Apr 2025 00:26:34 +0200 Subject: [PATCH] feat: add download remotes as file --- www/src/components/list.jsx | 18 ++++++---- www/src/data/serializer.js | 4 +-- www/src/tools/file-utils.js | 30 ++++++++++++++++ www/src/views/remotes/remotes-list-view.jsx | 39 +++++++++++++++++++-- 4 files changed, 79 insertions(+), 12 deletions(-) create mode 100644 www/src/tools/file-utils.js diff --git a/www/src/components/list.jsx b/www/src/components/list.jsx index d346c25..bbe0495 100644 --- a/www/src/components/list.jsx +++ b/www/src/components/list.jsx @@ -8,7 +8,17 @@ import { } from "solid-js"; function List(props) { - props = mergeProps({ items: [], showHeader: true, selectable: true }, props); + props = mergeProps( + { + items: [], + showHeader: true, + selectable: true, + onListItemsSelect: () => {}, + onLazyLoad: () => {}, + onListItemClick: () => {}, + }, + props + ); const [listItems, setListItems] = createSignal([]); const selectedItems = createMemo(() => listItems() @@ -31,16 +41,13 @@ function List(props) { ); }); createEffect(() => { - if (!props.onListItemsSelect) return; props.onListItemsSelect(selectedItems()); }); const observer = new IntersectionObserver((entries) => { entries.forEach((entry) => { if (entry.isIntersecting) { - if (props.onLazyLoad) { - props.onLazyLoad(); - } + props.onLazyLoad(); } }); }); @@ -61,7 +68,6 @@ function List(props) { }); function handleListItemClick(item) { - if (!props.onListItemClick) return; props.onListItemClick(item); } diff --git a/www/src/data/serializer.js b/www/src/data/serializer.js index 58a5899..9833963 100644 --- a/www/src/data/serializer.js +++ b/www/src/data/serializer.js @@ -61,9 +61,7 @@ const Serializer = (function () { return { id: remote.getId(), title: remote.getTitle(), - commands: remote.getCommands().map((command) => ({ - id: command.getId(), - })), + commands: serializeCommands(remote.getCommands()), }; } diff --git a/www/src/tools/file-utils.js b/www/src/tools/file-utils.js new file mode 100644 index 0000000..36eb706 --- /dev/null +++ b/www/src/tools/file-utils.js @@ -0,0 +1,30 @@ +function FileUtils() { + function createJsonFile(jsonData, fileName) { + const json = JSON.stringify(jsonData, null, 2); + const file = new File([json], fileName, { + type: "text/json;charset=utf-8", + }); + return file; + } + + function downloadFile(file) { + console.log(file) + const url = URL.createObjectURL(file); + const link = document.createElement("a"); + link.setAttribute("href", url); + link.setAttribute("download", file.name); + link.style.visibility = "hidden"; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + } + + return { + createJsonFile, + downloadFile, + }; +} + +FileUtils = new FileUtils(); + +export default FileUtils; diff --git a/www/src/views/remotes/remotes-list-view.jsx b/www/src/views/remotes/remotes-list-view.jsx index 58e1deb..66075b7 100644 --- a/www/src/views/remotes/remotes-list-view.jsx +++ b/www/src/views/remotes/remotes-list-view.jsx @@ -1,13 +1,18 @@ -import { createResource, onMount } from "solid-js"; +import { createMemo, createResource, createSignal, onMount } from "solid-js"; import List from "../../components/list"; import RemotesService from "../../services/remotes-service"; import CreateRemoteModal from "../../modals/create-remote-modal"; import DeleteRemoteModal from "../../modals/delete-remote-modal"; +import FileUtils from "../../tools/file-utils"; +import Serializer from "../../data/serializer"; +import RemoteService from "../../services/remotes-service"; function RemotesList(props) { const [remotes, { refetch: refetchRemotes }] = createResource( RemotesService.getRemotes ); + const [selectedRemotes, setSelectedRemotes] = createSignal([]); + const canExport = createMemo(() => selectedRemotes().length > 0); onMount(() => { refetchRemotes(); @@ -16,7 +21,7 @@ function RemotesList(props) { CreateRemoteModal.onRemoteCreated(() => { refetchRemotes(); }); - + DeleteRemoteModal.onRemoteDeleted(() => { refetchRemotes(); }); @@ -30,6 +35,25 @@ function RemotesList(props) { DeleteRemoteModal.Handler.show(); } + function handleListItemsSelect(items) { + setSelectedRemotes(items.map((item) => item.remote)); + } + + async function handleExport() { + let remotes = await Promise.all( + selectedRemotes().map((remote) => RemoteService.getRemote(remote.getId())) + ); + let files = remotes.map((remote) => + FileUtils.createJsonFile( + Serializer.serializeRemote(remote), + `${remote.getTitle()}.remote.json` + ) + ); + if (files.length >= 1) { + FileUtils.downloadFile(files[0]); + } + } + return ( <>
@@ -37,9 +61,17 @@ function RemotesList(props) { {props.navigation ? props.navigation : null}
+
@@ -62,6 +94,7 @@ function RemotesList(props) { }, ]} onListItemClick={() => {}} + onListItemsSelect={handleListItemsSelect} items={(remotes() || []).map((remote) => ({ id: { html: {remote.getId()},