🔧 ui: BulmaDrawer state machine rework

This commit is contained in:
Jörn-Michael Miehe 2025-12-28 01:10:28 +00:00
parent d5c935ade7
commit eacd1da482
5 changed files with 54 additions and 80 deletions

View file

@ -2,7 +2,7 @@
<ConfigView /> <ConfigView />
<CalendarAssistant /> <CalendarAssistant />
<DoorMapEditor /> <DoorMapEditor />
<BulmaDrawer header="Vorschau" @open="(ready) => ready()"> <BulmaDrawer header="Vorschau">
<UserView /> <UserView />
</BulmaDrawer> </BulmaDrawer>
</template> </template>

View file

@ -1,7 +1,7 @@
<template> <template>
<MultiModal @handle="on_modal_handle" /> <MultiModal @handle="on_modal_handle" />
<BulmaDrawer header="Kalender-Assistent" @open="on_open" refreshable> <BulmaDrawer header="Kalender-Assistent" :opening="on_open" refreshable>
<div class="card-content"> <div class="card-content">
<div class="content"> <div class="content">
<p>Hervorgehobenen Tagen wurde kein Buchstabe zugewiesen.</p> <p>Hervorgehobenen Tagen wurde kein Buchstabe zugewiesen.</p>
@ -63,8 +63,7 @@ function on_modal_handle(handle: HMultiModal) {
modal = handle; modal = handle;
} }
async function on_open(ready: () => void, fail: () => void) { async function on_open() {
try {
const [day_parts, day_image_names] = await Promise.all([ const [day_parts, day_image_names] = await Promise.all([
API.request<NumStrDict>("admin/day_parts"), API.request<NumStrDict>("admin/day_parts"),
API.request<NumStrDict>("admin/day_image_names"), API.request<NumStrDict>("admin/day_image_names"),
@ -85,11 +84,6 @@ async function on_open(ready: () => void, fail: () => void) {
_ensure_day_in_data(day); _ensure_day_in_data(day);
day_data.value[day].image_name = image_name; day_data.value[day].image_name = image_name;
}); });
ready();
} catch {
fail();
}
} }
async function door_click(day: number) { async function door_click(day: number) {

View file

@ -1,5 +1,5 @@
<template> <template>
<BulmaDrawer header="Konfiguration" @open="on_open" refreshable> <BulmaDrawer header="Konfiguration" :opening="on_open" refreshable>
<div class="card-content"> <div class="card-content">
<div class="columns"> <div class="columns">
<div class="column is-one-third"> <div class="column is-one-third">
@ -247,24 +247,16 @@ function fmt_puzzle_date(name: keyof AdminConfigModel["puzzle"]): string {
return DateTime.fromISO(iso_date).toLocaleString(DateTime.DATE_SHORT); return DateTime.fromISO(iso_date).toLocaleString(DateTime.DATE_SHORT);
} }
async function on_open(ready: () => void, fail: () => void) { async function on_open() {
try { const [store_update, new_admin_config_model, new_doors] = await Promise.all([
const [store_update, new_admin_config_model, new_doors] = await Promise.all(
[
store.update(), store.update(),
API.request<AdminConfigModel>("admin/config_model"), API.request<AdminConfigModel>("admin/config_model"),
API.request<DoorSaved[]>("admin/doors"), API.request<DoorSaved[]>("admin/doors"),
], ]);
);
void store_update; void store_update;
admin_config_model.value = new_admin_config_model; admin_config_model.value = new_admin_config_model;
doors.value = new_doors; doors.value = new_doors;
ready();
} catch {
fail();
}
} }
async function load_dav_credentials() { async function load_dav_credentials() {

View file

@ -1,5 +1,5 @@
<template> <template>
<BulmaDrawer header="Türchen bearbeiten" @open="on_open"> <BulmaDrawer header="Türchen bearbeiten" :opening="load_doors">
<nav class="level is-mobile mb-0" style="overflow-x: auto"> <nav class="level is-mobile mb-0" style="overflow-x: auto">
<BulmaButton <BulmaButton
:disabled="current_step === 0" :disabled="current_step === 0"
@ -128,15 +128,6 @@ async function save_doors() {
} }
} }
async function on_open(ready: () => void, fail: () => void) {
try {
load_doors();
ready();
} catch {
fail();
}
}
async function on_download() { async function on_download() {
if (confirm("Aktuelle Änderungen verwerfen und Status vom Server laden?")) { if (confirm("Aktuelle Änderungen verwerfen und Status vom Server laden?")) {
loading_doors.value = true; loading_doors.value = true;

View file

@ -4,11 +4,11 @@
<header class="card-header is-unselectable" style="cursor: pointer"> <header class="card-header is-unselectable" style="cursor: pointer">
<p class="card-header-title" @click="toggle">{{ header }}</p> <p class="card-header-title" @click="toggle">{{ header }}</p>
<p v-if="refreshable" class="card-header-icon px-0"> <p v-if="refreshable && is_open" class="card-header-icon px-0">
<BulmaButton class="is-small is-primary" @click="refresh"> <BulmaButton class="is-small is-primary" @click="load">
<FontAwesomeIcon <FontAwesomeIcon
:icon="['fas', 'arrows-rotate']" :icon="['fas', 'arrows-rotate']"
:spin="is_open && state === 'loading'" :spin="state === 'loading'"
/> />
</BulmaButton> </BulmaButton>
</p> </p>
@ -27,7 +27,7 @@
<progress class="progress is-primary" /> <progress class="progress is-primary" />
</div> </div>
<div <div
v-else-if="state === 'failed'" v-else-if="state === 'err'"
class="card-content has-text-danger has-text-centered" class="card-content has-text-danger has-text-centered"
> >
<span class="icon is-large"> <span class="icon is-large">
@ -40,42 +40,39 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref } from "vue"; import { computed, ref } from "vue";
import BulmaButton from "./Button.vue"; import BulmaButton from "./Button.vue";
withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
header: string; header: string;
opening?: () => Promise<void>;
refreshable?: boolean; refreshable?: boolean;
}>(), }>(),
{ refreshable: false }, { opening: async () => {}, refreshable: false },
); );
const emit = defineEmits<{ const state = ref<"closed" | "loading" | "ok" | "err">("closed");
(event: "open", ready: () => void, fail: () => void): void; const is_open = computed(() => state.value !== "closed");
}>();
const is_open = ref(false);
const state = ref<"loading" | "ready" | "failed">("loading");
function toggle() {
is_open.value = !is_open.value;
async function toggle() {
if (is_open.value) { if (is_open.value) {
state.value = "loading"; state.value = "closed";
} else {
emit( await load();
"open",
() => (state.value = "ready"),
() => (state.value = "failed"),
);
} }
} }
function refresh() { async function load() {
is_open.value = false; state.value = "loading";
toggle();
try {
await props.opening();
state.value = "ok";
} catch {
state.value = "err";
}
} }
</script> </script>