Compare commits

..

10 Commits

9 changed files with 277 additions and 229 deletions
@@ -2,9 +2,10 @@ import { db } from './database';
import { get_display_by_id } from './stores/displays'; import { get_display_by_id } from './stores/displays';
import { import {
get_current_folder_elements, get_current_folder_elements,
create_path_on_all_selected_displays,
get_file_by_id, get_file_by_id,
remove_all_files_without_display, remove_all_files_without_display,
remove_file_from_display remove_file_from_display_recusively
} from './stores/files'; } from './stores/files';
import { notifications } from './stores/notification'; import { notifications } from './stores/notification';
import { generate_thumbnail } from './stores/thumbnails'; import { generate_thumbnail } from './stores/thumbnails';
@@ -28,6 +29,8 @@ export async function add_upload(
) { ) {
if (file_list.length === 0) return console.warn('Upload canceled: no selected files'); if (file_list.length === 0) return console.warn('Upload canceled: no selected files');
await create_path_on_all_selected_displays(current_file_path, selected_display_ids);
const used_file_names: string[] = await ( const used_file_names: string[] = await (
await get_current_folder_elements(current_file_path, selected_display_ids) await get_current_folder_elements(current_file_path, selected_display_ids)
).map((e) => e.name); ).map((e) => e.name);
@@ -414,11 +417,11 @@ async function show_error(task: FileTransferTask, error: ProgressEvent | string)
`Datei: "${task.file_name}", Display-IP: ${task.display.ip}\nFehler: ${error}` `Datei: "${task.file_name}", Display-IP: ${task.display.ip}\nFehler: ${error}`
); );
if (task_data.type === 'upload') { if (task_data.type === 'upload') {
await remove_file_from_display(task.display.id, task.file_primary_key); await remove_file_from_display_recusively(task.display.id, task.file_primary_key);
await remove_all_files_without_display(); await remove_all_files_without_display();
} else if (task_data.type === 'sync') { } else if (task_data.type === 'sync') {
for (const display_id of task_data.destination_displays.map((e) => e.id)) { for (const display_id of task_data.destination_displays.map((e) => e.id)) {
await remove_file_from_display(display_id, task.file_primary_key); await remove_file_from_display_recusively(display_id, task.file_primary_key);
} }
await remove_all_files_without_display(); await remove_all_files_without_display();
} }
+31 -5
View File
@@ -42,16 +42,35 @@ export async function delete_and_deselect_unique_files_from_display(display_id:
.equals(display_id) .equals(display_id)
.toArray(); .toArray();
for (const file of files_on_display) { for (const file of files_on_display) {
await remove_file_from_display(display_id, file.file_primary_key); await remove_file_from_display_recusively(display_id, file.file_primary_key);
} }
await remove_all_files_without_display(); await remove_all_files_without_display();
} }
export async function remove_file_from_display(display_id: string, file_primary_key: string) { export async function remove_file_from_display_recusively(display_id: string, file_primary_key: string) {
const found = await db.files_on_display.get([display_id, file_primary_key]); const found = await db.files_on_display.get([display_id, file_primary_key]);
if (!found) return; if (!found) return;
select(selected_file_ids, file_primary_key, 'deselect'); select(selected_file_ids, file_primary_key, 'deselect');
await db.files_on_display.delete([display_id, file_primary_key]); await db.files_on_display.delete([display_id, file_primary_key]);
const inode_element = await get_file_by_id(found.file_primary_key);
if (!inode_element) return;
if (inode_element.type === 'inode/directory') {
const path_inside_folder = inode_element.path + inode_element.name + `/`;
const primary_file_keys_in_folder = (
await db.files.where('path').equals(path_inside_folder).toArray()
).map((e) => get_file_primary_key(e));
const primary_file_keys_in_folder_on_display = (
await db.files_on_display
.where('file_primary_key')
.anyOf(primary_file_keys_in_folder)
.filter((file) => file.display_id === display_id)
.toArray()
).map((e) => e.file_primary_key);
for (const file_key of primary_file_keys_in_folder_on_display) {
await remove_file_from_display_recusively(display_id, file_key);
}
}
} }
export async function remove_all_files_without_display() { export async function remove_all_files_without_display() {
@@ -272,7 +291,7 @@ export async function update_folder_elements_recursively(
if (diff.deleted.length > 0) { if (diff.deleted.length > 0) {
// Remove old Folder-Elements // Remove old Folder-Elements
for (const old_element of diff.deleted) { for (const old_element of diff.deleted) {
remove_file_from_display(display.id, get_file_primary_key(old_element)); remove_file_from_display_recusively(display.id, get_file_primary_key(old_element));
} }
await remove_all_files_without_display(); await remove_all_files_without_display();
} }
@@ -377,6 +396,14 @@ export async function create_folder_on_all_selected_displays(
path: string, path: string,
selected_display_ids: string[] selected_display_ids: string[]
): Promise<void> { ): Promise<void> {
const path_with_folder_name = (path += folder_name + '/');
await create_path_on_all_selected_displays(path_with_folder_name, selected_display_ids);
}
export async function create_path_on_all_selected_displays(
path: string,
selected_display_ids: string[]
) {
const path_parts = path const path_parts = path
.slice(1, path.length - 1) .slice(1, path.length - 1)
.split('/') .split('/')
@@ -397,9 +424,8 @@ export async function create_folder_on_all_selected_displays(
const displays = await getDisplaysForPath(currentPath); const displays = await getDisplaysForPath(currentPath);
if (!displays.length) continue; if (!displays.length) continue;
const folders_to_create = [...path_parts.slice(depth), folder_name];
for (const display of displays) { for (const display of displays) {
await create_folders(display.ip, currentPath, folders_to_create); await create_folders(display.ip, currentPath, path_parts.slice(depth));
remaining_display_ids = remaining_display_ids.filter((id) => id !== display.id); remaining_display_ids = remaining_display_ids.filter((id) => id !== display.id);
} }
} }
+1 -4
View File
@@ -75,6 +75,7 @@
title: 'Neuen Bildschirm hinzufügen', title: 'Neuen Bildschirm hinzufügen',
title_icon: Monitor, title_icon: Monitor,
title_class: '!text-xl', title_class: '!text-xl',
window_class: 'w-3xl',
closable: true closable: true
}; };
}; };
@@ -231,10 +232,6 @@
icon: Plus, icon: Plus,
name: 'Neuen Bildschirm hinzufügen', name: 'Neuen Bildschirm hinzufügen',
on_select: show_new_display_popup on_select: show_new_display_popup
},
{
icon: Settings,
name: 'Weitere Einstellungen'
} }
]} ]}
> >
@@ -66,12 +66,6 @@
is_selected: () => editor_state.editor?.isActive('strike') ?? false, is_selected: () => editor_state.editor?.isActive('strike') ?? false,
title: 'Durchgestrichen', title: 'Durchgestrichen',
icon: Strikethrough icon: Strikethrough
},
{
onclick: () => {},
is_selected: () => false,
title: 'QR-Code anfügen',
icon: QrCode
} }
], ],
[ [
+207 -207
View File
@@ -1,221 +1,221 @@
module.exports = { module.exports = {
content: ['./src/**/*.{html,js,svelte,ts}'], content: ['./src/**/*.{html,js,svelte,ts}'],
safelist: [ safelist: [
'bg-stone-50', 'bg-stone-50',
'bg-stone-100', 'bg-stone-100',
'bg-stone-150', 'bg-stone-150',
'bg-stone-200', 'bg-stone-200',
'bg-stone-250', 'bg-stone-250',
'bg-stone-300', 'bg-stone-300',
'bg-stone-350', 'bg-stone-350',
'bg-stone-400', 'bg-stone-400',
'bg-stone-450', 'bg-stone-450',
'bg-stone-500', 'bg-stone-500',
'bg-stone-550', 'bg-stone-550',
'bg-stone-600', 'bg-stone-600',
'bg-stone-650', 'bg-stone-650',
'bg-stone-700', 'bg-stone-700',
'bg-stone-750', 'bg-stone-750',
'bg-stone-800', 'bg-stone-800',
'bg-stone-850', 'bg-stone-850',
'bg-stone-900', 'bg-stone-900',
'bg-stone-950', 'bg-stone-950',
'hover:bg-stone-50', 'hover:bg-stone-50',
'hover:bg-stone-100', 'hover:bg-stone-100',
'hover:bg-stone-150', 'hover:bg-stone-150',
'hover:bg-stone-200', 'hover:bg-stone-200',
'hover:bg-stone-250', 'hover:bg-stone-250',
'hover:bg-stone-300', 'hover:bg-stone-300',
'hover:bg-stone-350', 'hover:bg-stone-350',
'hover:bg-stone-400', 'hover:bg-stone-400',
'hover:bg-stone-450', 'hover:bg-stone-450',
'hover:bg-stone-500', 'hover:bg-stone-500',
'hover:bg-stone-550', 'hover:bg-stone-550',
'hover:bg-stone-600', 'hover:bg-stone-600',
'hover:bg-stone-650', 'hover:bg-stone-650',
'hover:bg-stone-700', 'hover:bg-stone-700',
'hover:bg-stone-750', 'hover:bg-stone-750',
'hover:bg-stone-800', 'hover:bg-stone-800',
'hover:bg-stone-850', 'hover:bg-stone-850',
'hover:bg-stone-900', 'hover:bg-stone-900',
'hover:bg-stone-950', 'hover:bg-stone-950',
'active:bg-stone-50', 'active:bg-stone-50',
'active:bg-stone-100', 'active:bg-stone-100',
'active:bg-stone-150', 'active:bg-stone-150',
'active:bg-stone-200', 'active:bg-stone-200',
'active:bg-stone-250', 'active:bg-stone-250',
'active:bg-stone-300', 'active:bg-stone-300',
'active:bg-stone-350', 'active:bg-stone-350',
'active:bg-stone-400', 'active:bg-stone-400',
'active:bg-stone-450', 'active:bg-stone-450',
'active:bg-stone-500', 'active:bg-stone-500',
'active:bg-stone-550', 'active:bg-stone-550',
'active:bg-stone-600', 'active:bg-stone-600',
'active:bg-stone-650', 'active:bg-stone-650',
'active:bg-stone-700', 'active:bg-stone-700',
'active:bg-stone-750', 'active:bg-stone-750',
'active:bg-stone-800', 'active:bg-stone-800',
'active:bg-stone-850', 'active:bg-stone-850',
'active:bg-stone-900', 'active:bg-stone-900',
'active:bg-stone-950', 'active:bg-stone-950',
'focus:bg-stone-50', 'focus:bg-stone-50',
'focus:bg-stone-100', 'focus:bg-stone-100',
'focus:bg-stone-150', 'focus:bg-stone-150',
'focus:bg-stone-200', 'focus:bg-stone-200',
'focus:bg-stone-250', 'focus:bg-stone-250',
'focus:bg-stone-300', 'focus:bg-stone-300',
'focus:bg-stone-350', 'focus:bg-stone-350',
'focus:bg-stone-400', 'focus:bg-stone-400',
'focus:bg-stone-450', 'focus:bg-stone-450',
'focus:bg-stone-500', 'focus:bg-stone-500',
'focus:bg-stone-550', 'focus:bg-stone-550',
'focus:bg-stone-600', 'focus:bg-stone-600',
'focus:bg-stone-650', 'focus:bg-stone-650',
'focus:bg-stone-700', 'focus:bg-stone-700',
'focus:bg-stone-750', 'focus:bg-stone-750',
'focus:bg-stone-800', 'focus:bg-stone-800',
'focus:bg-stone-850', 'focus:bg-stone-850',
'focus:bg-stone-900', 'focus:bg-stone-900',
'focus:bg-stone-950', 'focus:bg-stone-950',
'text-stone-50', 'text-stone-50',
'text-stone-150', 'text-stone-150',
'text-stone-200', 'text-stone-200',
'text-stone-250', 'text-stone-250',
'text-stone-300', 'text-stone-300',
'text-stone-350', 'text-stone-350',
'text-stone-100', 'text-stone-100',
'text-stone-400', 'text-stone-400',
'text-stone-450', 'text-stone-450',
'text-stone-500', 'text-stone-500',
'text-stone-550', 'text-stone-550',
'text-stone-600', 'text-stone-600',
'text-stone-650', 'text-stone-650',
'text-stone-700', 'text-stone-700',
'text-stone-750', 'text-stone-750',
'text-stone-800', 'text-stone-800',
'text-stone-850', 'text-stone-850',
'text-stone-900', 'text-stone-900',
'text-stone-950', 'text-stone-950',
'group-hover:text-stone-100', 'group-hover:text-stone-100',
'group-hover:text-stone-150', 'group-hover:text-stone-150',
'group-hover:text-stone-200', 'group-hover:text-stone-200',
'group-hover:text-stone-50', 'group-hover:text-stone-50',
'group-hover:text-stone-250', 'group-hover:text-stone-250',
'group-hover:text-stone-300', 'group-hover:text-stone-300',
'group-hover:text-stone-350', 'group-hover:text-stone-350',
'group-hover:text-stone-400', 'group-hover:text-stone-400',
'group-hover:text-stone-450', 'group-hover:text-stone-450',
'group-hover:text-stone-500', 'group-hover:text-stone-500',
'group-hover:text-stone-550', 'group-hover:text-stone-550',
'group-hover:text-stone-600', 'group-hover:text-stone-600',
'group-hover:text-stone-650', 'group-hover:text-stone-650',
'group-hover:text-stone-700', 'group-hover:text-stone-700',
'group-hover:text-stone-750', 'group-hover:text-stone-750',
'group-hover:text-stone-800', 'group-hover:text-stone-800',
'group-hover:text-stone-850', 'group-hover:text-stone-850',
'group-hover:text-stone-900', 'group-hover:text-stone-900',
'group-hover:text-stone-950', 'group-hover:text-stone-950',
'group-active:text-stone-50', 'group-active:text-stone-50',
'group-active:text-stone-100', 'group-active:text-stone-100',
'group-active:text-stone-150', 'group-active:text-stone-150',
'group-active:text-stone-200', 'group-active:text-stone-200',
'group-active:text-stone-250', 'group-active:text-stone-250',
'group-active:text-stone-300', 'group-active:text-stone-300',
'group-active:text-stone-350', 'group-active:text-stone-350',
'group-active:text-stone-400', 'group-active:text-stone-400',
'group-active:text-stone-450', 'group-active:text-stone-450',
'group-active:text-stone-500', 'group-active:text-stone-500',
'group-active:text-stone-550', 'group-active:text-stone-550',
'group-active:text-stone-600', 'group-active:text-stone-600',
'group-active:text-stone-650', 'group-active:text-stone-650',
'group-active:text-stone-700', 'group-active:text-stone-700',
'group-active:text-stone-750', 'group-active:text-stone-750',
'group-active:text-stone-800', 'group-active:text-stone-800',
'group-active:text-stone-850', 'group-active:text-stone-850',
'group-active:text-stone-950', 'group-active:text-stone-950',
'group-active:text-stone-900', 'group-active:text-stone-900',
'border-stone-50', 'border-stone-50',
'border-stone-100', 'border-stone-100',
'border-stone-150', 'border-stone-150',
'border-stone-200', 'border-stone-200',
'border-stone-250', 'border-stone-250',
'border-stone-300', 'border-stone-300',
'border-stone-350', 'border-stone-350',
'border-stone-400', 'border-stone-400',
'border-stone-450', 'border-stone-450',
'border-stone-500', 'border-stone-500',
'border-stone-550', 'border-stone-550',
'border-stone-600', 'border-stone-600',
'border-stone-650', 'border-stone-650',
'border-stone-700', 'border-stone-700',
'border-stone-750', 'border-stone-750',
'border-stone-800', 'border-stone-800',
'border-stone-850', 'border-stone-850',
'border-stone-900', 'border-stone-900',
'border-stone-950', 'border-stone-950',
'group-hover:border-stone-50', 'group-hover:border-stone-50',
'group-hover:border-stone-100', 'group-hover:border-stone-100',
'group-hover:border-stone-150', 'group-hover:border-stone-150',
'group-hover:border-stone-200', 'group-hover:border-stone-200',
'group-hover:border-stone-250', 'group-hover:border-stone-250',
'group-hover:border-stone-300', 'group-hover:border-stone-300',
'group-hover:border-stone-350', 'group-hover:border-stone-350',
'group-hover:border-stone-400', 'group-hover:border-stone-400',
'group-hover:border-stone-450', 'group-hover:border-stone-450',
'group-hover:border-stone-500', 'group-hover:border-stone-500',
'group-hover:border-stone-550', 'group-hover:border-stone-550',
'group-hover:border-stone-600', 'group-hover:border-stone-600',
'group-hover:border-stone-650', 'group-hover:border-stone-650',
'group-hover:border-stone-700', 'group-hover:border-stone-700',
'group-hover:border-stone-750', 'group-hover:border-stone-750',
'group-hover:border-stone-800', 'group-hover:border-stone-800',
'group-hover:border-stone-850', 'group-hover:border-stone-850',
'group-hover:border-stone-950', 'group-hover:border-stone-950',
'group-hover:border-stone-900', 'group-hover:border-stone-900',
'group-active:border-stone-50', 'group-active:border-stone-50',
'group-active:border-stone-100', 'group-active:border-stone-100',
'group-active:border-stone-150', 'group-active:border-stone-150',
'group-active:border-stone-200', 'group-active:border-stone-200',
'group-active:border-stone-250', 'group-active:border-stone-250',
'group-active:border-stone-300', 'group-active:border-stone-300',
'group-active:border-stone-350', 'group-active:border-stone-350',
'group-active:border-stone-400', 'group-active:border-stone-400',
'group-active:border-stone-450', 'group-active:border-stone-450',
'group-active:border-stone-500', 'group-active:border-stone-500',
'group-active:border-stone-550', 'group-active:border-stone-550',
'group-active:border-stone-600', 'group-active:border-stone-600',
'group-active:border-stone-650', 'group-active:border-stone-650',
'group-active:border-stone-700', 'group-active:border-stone-700',
'group-active:border-stone-750', 'group-active:border-stone-750',
'group-active:border-stone-800', 'group-active:border-stone-800',
'group-active:border-stone-850', 'group-active:border-stone-850',
'group-active:border-stone-900', 'group-active:border-stone-900',
'group-active:border-stone-950', 'group-active:border-stone-950',
'h-10', 'h-10',
'h-15', 'h-15',
'h-20', 'h-20',
'h-25', 'h-25',
'h-30', 'h-30',
'h-35', 'h-35',
'h-40', 'h-40',
'right-0', 'right-0',
'left-0', 'left-0',
'hover:bg-red-400', 'hover:bg-red-400',
'active:bg-red-500', 'active:bg-red-500',
'hover:bg-stone-600/70', 'hover:bg-stone-600/70',
'active:bg-stone-500/80', 'active:bg-stone-500/80'
], ]
} };
+12 -1
View File
@@ -116,7 +116,7 @@
after = ["network-online.target"]; after = ["network-online.target"];
wants = ["network-online.target"]; wants = ["network-online.target"];
path = config.environment.systemPackages; path = config.environment.systemPackages;
script = "nu ${./update.sh}"; script = "nu ${./update.nu}";
serviceConfig = { serviceConfig = {
WorkingDirectory = "/home/mudics/mudics"; WorkingDirectory = "/home/mudics/mudics";
User = "mudics"; User = "mudics";
@@ -152,6 +152,17 @@
}; };
}; };
systemd.services.enable-wol = {
wantedBy = ["multi-user.target"];
after = ["network.target"];
path = with pkgs; [ethtool nushell];
script = "nu ${./wol.nu}";
serviceConfig = {
Type = "oneshot";
User = "root";
};
};
systemd.tmpfiles.rules = [ systemd.tmpfiles.rules = [
"d /home/mudics/mudics 0755 mudics - -" "d /home/mudics/mudics 0755 mudics - -"
]; ];
View File
+11
View File
@@ -0,0 +1,11 @@
#!/usr/bin/env nu
ls /sys/class/net | get name | path basename | where $it != "lo" | each {|iface|
print $"Enabling WoL on ($iface)..."
try {
ethtool -s $iface wol g
print $"Successfully enabled WoL on ($iface)"
} catch {
print $"Failed to enable WoL on ($iface). It might not be supported."
}
}
+9 -3
View File
@@ -5,16 +5,22 @@ import (
"fmt" "fmt"
"os" "os"
"os/exec" "os/exec"
"path/filepath"
) )
func OpenBrowserWindow(url string, fullscreen bool) error { func OpenBrowserWindow(url string, fullscreen bool) error {
bins := []string{"chromium", "chromium-browser"} bins := []string{"chromium", "chromium-browser"}
tempDirPath, err := os.MkdirTemp("", "plg-mudics-browser-") home, err := os.UserHomeDir()
if err != nil { if err != nil {
return err return fmt.Errorf("unable to determine user home directory: %w", err)
} }
args := []string{fmt.Sprintf("--app=%s", url), "--autoplay-policy=no-user-gesture-required", fmt.Sprintf("--user-data-dir=%s", tempDirPath)} browserProfileDirPath := filepath.Join(home, ".local", "share", "plg-mudics", "browser")
if err := os.MkdirAll(browserProfileDirPath, os.ModePerm); err != nil {
return fmt.Errorf("failed to create local config directory: %w", err)
}
args := []string{fmt.Sprintf("--app=%s", url), "--autoplay-policy=no-user-gesture-required", fmt.Sprintf("--user-data-dir=%s", browserProfileDirPath)}
if fullscreen { if fullscreen {
args = append(args, "--start-fullscreen") args = append(args, "--start-fullscreen")
} }