Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions frontend/src/lib/dialog/AlertDialog.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@
<BitsUiAlertDialog.Root bind:open={showDialog}>
<BitsUiAlertDialog.Portal>
<BitsUiAlertDialog.Overlay
class="bg-dialog-backlight fixed inset-0 z-40"
class="bg-dialog-backlight fixed inset-0 z-50"
/>
<BitsUiAlertDialog.Content
{...restProps}
class="border-border bg-window-background fixed top-1/2 left-1/2 z-40 -translate-x-1/2 -translate-y-1/2 rounded border border-solid p-2 shadow outline-none {size}"
class="border-border bg-window-background fixed top-1/2 left-1/2 z-50 -translate-x-1/2 -translate-y-1/2 rounded border border-solid p-2 shadow outline-none {size}"
{onkeydown}
>
<div class="flex items-start gap-3 p-2">
Expand Down
36 changes: 32 additions & 4 deletions frontend/src/lib/eventhandling/closeEventManager.svelte.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@

export let eventStack;

export const EventType = {
DIALOG: "dialog",
CLASS_EDITOR: "classEditor",
};

class EventStack {
constructor() {
this.stack = [];
Expand All @@ -25,12 +30,16 @@ class EventStack {

stack;

addEvent(event) {
this.stack.push(event);
/**
* @param {() => void} event - the close handler
* @param {string} [type] - optional category, e.g. "DIALOG" or "CLASS_EDITOR"
*/
addEvent(event, type = EventType.DIALOG) {
this.stack.push({ event, type });
}

removeEvent(event) {
const idOfEvent = this.stack.indexOf(event);
const idOfEvent = this.stack.findIndex(e => e.event === event);
if (idOfEvent === -1) return;
this.stack.splice(idOfEvent, 1);
}
Expand All @@ -43,7 +52,26 @@ class EventStack {
);
return;
}
this.stack.at(-1)(...args);
this.stack.at(-1).event(...args);
}

/**
* Closes all open events whose type is not in the excludedTypes list.
* Used when opening a new dialog via shortcut: all other dialogs close,
* but e.g. the ClassEditor (type "classEditor") stays open.
* @param {string[]} excludedTypes
*/
closeAllExcept(excludedTypes = []) {
const toClose = this.stack
.filter(e => !excludedTypes.includes(e.type))
.reverse();

for (const { event } of toClose) {
if (event() === false) {
return false;
}
}
return true;
}

registerActionGuard(fn) {
Expand Down
21 changes: 17 additions & 4 deletions frontend/src/lib/eventhandling/shortcutStore.svelte.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,19 @@
*
*/

import {
eventStack,
EventType,
} from "$lib/eventhandling/closeEventManager.svelte.js";

export const shortcutStore = {
/**
* @param {string} id - unique identifier
* @param {string[] | string[][]} keys - e.g. ["ctrl", "s"] or [["ctrl", "s"], ["ctrl", "shift", "s"]]
* @param {() => void} handler
* @param closeDialogs define if the shortcut should close open dialogs (default: false). If true, all open dialogs will be closed before executing the handler.
*/
register(id, keys, handler) {
register(id, keys, handler, closeDialogs = false) {
// Normalize to an array of key-combinations
if (registry[id]) {
console.warn(
Expand All @@ -30,7 +36,7 @@ export const shortcutStore = {
}
const combinations = Array.isArray(keys[0]) ? keys : [keys];
const normalizedCombos = combinations.map(normalizeCombo);
registry[id] = { combos: normalizedCombos, handler };
registry[id] = { combos: normalizedCombos, handler, closeDialogs };
return () => this.unregister(id);
},

Expand All @@ -44,10 +50,17 @@ export const shortcutStore = {
*/
handleEvent(event) {
const normalized = normalizeEvent(event);
for (const { combos, handler } of Object.values(registry)) {
for (const { combos, handler, closeDialogs } of Object.values(
registry,
)) {
if (combos.includes(normalized)) {
event.preventDefault();
handler();
eventStack.guardAction(() => {
if (closeDialogs) {
eventStack.closeAllExcept([EventType.CLASS_EDITOR]);
}
handler();
});
return true;
}
}
Expand Down
1 change: 1 addition & 0 deletions frontend/src/routes/ImportDialog.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,7 @@
onPrimary={importGraphs}
disablePrimary={!enableSubmit}
title="Import Schemas"
size="w-1/3"
>
<div class="mx-2 flex h-full max-h-[80vh] flex-col">
{#if !datasetSelectionLocked}
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/routes/KeyboardShortcutsDialog.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,10 @@
title="Keyboard Shortcuts"
titleIcon={faKeyboard}
readonly
size="w-full max-w-3xl"
size="w-full max-w-3xl h-2/3"
>
<div
class="mx-2 flex flex-col gap-6 overflow-y-auto py-2 max-h-96 sm:flex-row sm:gap-x-6"
class="mx-2 flex flex-col gap-6 overflow-y-auto py-2 h-full sm:flex-row sm:gap-x-6"
>
<div class="flex flex-1 flex-col gap-6">
{#each sections.slice(0, 2) as section}
Expand Down
18 changes: 14 additions & 4 deletions frontend/src/routes/layout/menu-bar/Edit.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -137,27 +137,37 @@
"newClass",
["shift", "n"],
() => (showNewClassDialog = true),
true,
),
shortcutStore.register(
"newPackage",
["alt", "n"],
() => (showNewPackageDialog = true),
true,
),
shortcutStore.register(
"namespaces",
["ctrl", "shift", "a"],
() => (showNamespaceDialog = true),
true,
),
shortcutStore.register(
"profileHeader",
["ctrl", "alt", "p"],
() => (showEditOntologyDialog = true),
true,
),
shortcutStore.register("editPackage", ["ctrl", "shift", "k"], () =>
launchPackageEditor(),
shortcutStore.register(
"editPackage",
["ctrl", "shift", "k"],
() => launchPackageEditor(),
true,
),
shortcutStore.register("toggleEdit", ["ctrl", "alt", "r"], () =>
toggleReadonly(),
shortcutStore.register(
"toggleEdit",
["ctrl", "alt", "r"],
() => toggleReadonly(),
true,
),
shortcutStore.register("copyClass", ["ctrl", "c"], () =>
copyClassWithShortcut(),
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/routes/layout/menu-bar/File.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -69,31 +69,37 @@
"import",
["ctrl", "i"],
() => (showImportDialog = true),
true,
),
shortcutStore.register(
"export",
["ctrl", "e"],
() => (showExportDialog = true),
true,
),
shortcutStore.register(
"shaclImport",
["ctrl", "shift", "i"],
() => (showSHACLUploadDialog = true),
true,
),
shortcutStore.register(
"shaclExport",
["ctrl", "shift", "e"],
() => (showSHACLExportDialog = true),
true,
),
shortcutStore.register(
"snapshot",
["ctrl", "shift", "s"],
() => (showSnapshotDialog = true),
true,
),
shortcutStore.register(
"settings",
["ctrl", "alt", "s"],
() => (showUserSettingDialog = true),
true,
),
);
});
Expand Down
1 change: 1 addition & 0 deletions frontend/src/routes/layout/menu-bar/Help.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
"keyboardShortcuts",
["?"],
() => (showKeyboardShortcutsDialog = true),
true,
),
);
});
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/routes/layout/menu-bar/View.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
"compare",
["ctrl", "shift", "c"],
() => (showCompareDialog = true),
true,
),
shortcutStore.register("migrate", ["ctrl", "shift", "m"], () =>
goto("/migrate"),
Expand All @@ -72,6 +73,7 @@
() => {
if (hasGraphSelected) showSHACLFullViewDialog = true;
},
hasGraphSelected,
),
);
});
Expand Down
7 changes: 5 additions & 2 deletions frontend/src/routes/mainpage/classEditor/classEditor.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@
import { BackendConnection } from "$lib/api/backend.js";
import LoadingSpinner from "$lib/components/LoadingSpinner.svelte";
import { PUBLIC_BACKEND_URL } from "$lib/config/runtime";
import { eventStack } from "$lib/eventhandling/closeEventManager.svelte.js";
import {
eventStack,
EventType,
} from "$lib/eventhandling/closeEventManager.svelte.js";
import { mapClassDtoToReactiveClass } from "$lib/models/reactive/mapper/map-dto-to-reactive-object.js";
import { adoptUnsavedClassChanges } from "$lib/models/reactive/utils/adopt-model-changes-utils.js";
import {
Expand Down Expand Up @@ -144,7 +147,7 @@
});

onMount(() => {
eventStack.addEvent(closeClassEditor);
eventStack.addEvent(closeClassEditor, EventType.CLASS_EDITOR);
eventStack.registerActionGuard(withUnsavedChangesCheck);
});

Expand Down