Replace BOverlay with GOverlay component

BOverlay uses scoped slots internally which crash under @vue/compat
with a renderSlot TypeError. GOverlay is a simple CSS overlay with a
spinner, covering the same API surface used across the codebase:
show prop, opacity, no-fade, and a custom #overlay slot.

Migrated all 5 files that used BOverlay: GTable, HistoryList,
WorkflowList, BroadcastsList, and WorkflowRunFormSimple.
This commit is contained in:
Dannon Baker
2026-03-01 08:27:16 -05:00
parent 5229278e1b
commit 94100a32db
6 changed files with 100 additions and 16 deletions
@@ -0,0 +1,80 @@
<script setup lang="ts">
/**
* Overlay component that displays a semi-transparent loading overlay
* over its default slot content. Replaces bootstrap-vue's BOverlay.
*/
withDefaults(
defineProps<{
/** Controls overlay visibility */
show?: boolean;
/** Overlay background opacity (0-1) */
opacity?: number;
/** Disable fade transition */
noFade?: boolean;
}>(),
{
show: false,
opacity: 0.6,
noFade: false,
},
);
</script>
<template>
<div class="g-overlay-wrapper position-relative">
<slot />
<Transition v-if="!noFade" name="g-overlay-fade">
<div v-if="show" class="g-overlay" :style="{ '--g-overlay-opacity': opacity }">
<slot name="overlay">
<span class="g-overlay-spinner" />
</slot>
</div>
</Transition>
<div v-else-if="show" class="g-overlay" :style="{ '--g-overlay-opacity': opacity }">
<slot name="overlay">
<span class="g-overlay-spinner" />
</slot>
</div>
</div>
</template>
<style scoped lang="scss">
.g-overlay {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
background: rgba(255, 255, 255, var(--g-overlay-opacity, 0.6));
border-radius: 0.2rem;
z-index: 10;
}
.g-overlay-spinner {
display: inline-block;
width: 2rem;
height: 2rem;
border: 0.25em solid currentColor;
border-right-color: transparent;
border-radius: 50%;
animation: g-overlay-spin 0.75s linear infinite;
opacity: 0.75;
}
@keyframes g-overlay-spin {
to {
transform: rotate(360deg);
}
}
.g-overlay-fade-enter-active,
.g-overlay-fade-leave-active {
transition: opacity 0.15s ease;
}
.g-overlay-fade-enter,
.g-overlay-fade-leave-to {
opacity: 0;
}
</style>
+4 -3
View File
@@ -1,7 +1,7 @@
<script setup lang="ts" generic="T extends Record<string, any>">
import { faEllipsisV, faSort, faSortDown, faSortUp } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import { BAlert, BDropdown, BDropdownItem, BFormCheckbox, BOverlay } from "bootstrap-vue";
import { BAlert, BDropdown, BDropdownItem, BFormCheckbox } from "bootstrap-vue";
import { computed, ref } from "vue";
import type { BootstrapSize } from "@/components/Common";
@@ -17,6 +17,7 @@ import type {
TableField,
} from "./GTable.types";
import GOverlay from "@/components/BaseComponents/GOverlay.vue";
import LoadingSpan from "@/components/LoadingSpan.vue";
interface Props {
@@ -642,7 +643,7 @@ defineExpose({
<template>
<div :id="`g-table-container-${props.id}`" class="g-table-container" :class="containerClass">
<!-- Table wrapper -->
<BOverlay :show="overlayLoading" rounded="sm" class="position-relative w-100">
<GOverlay :show="overlayLoading" class="position-relative w-100">
<div
:id="`g-table-wrapper-${props.id}`"
class="position-relative w-100"
@@ -845,7 +846,7 @@ defineExpose({
<LoadingSpan :message="props.loadMoreMessage" />
</div>
</div>
</BOverlay>
</GOverlay>
</div>
</template>
@@ -21,7 +21,7 @@
import { faBurn, faColumns, faPlus, faTags, faTrash, faTrashRestore } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import { BAlert, BButton, BNav, BNavItem, BOverlay, BPagination } from "bootstrap-vue";
import { BAlert, BButton, BNav, BNavItem, BPagination } from "bootstrap-vue";
import { computed, onMounted, ref, watch } from "vue";
import { useRouter } from "vue-router/composables";
@@ -46,6 +46,7 @@ import { getHistoryListFilters } from "./historyList";
import GButton from "@/components/BaseComponents/GButton.vue";
import GLink from "@/components/BaseComponents/GLink.vue";
import GOverlay from "@/components/BaseComponents/GOverlay.vue";
import BreadcrumbHeading from "@/components/Common/BreadcrumbHeading.vue";
import FilterMenu from "@/components/Common/FilterMenu.vue";
import Heading from "@/components/Common/Heading.vue";
@@ -661,12 +662,11 @@ onMounted(async () => {
</GLink>
</BAlert>
</span>
<BOverlay
<GOverlay
v-else
id="history-list-overlay"
:show="overlay"
class="h-100 d-flex flex-column history-list-overlay"
rounded="sm">
class="h-100 d-flex flex-column history-list-overlay">
<HistoryCardList
:histories="historiesLoaded"
:shared-view="sharedView"
@@ -684,7 +684,7 @@ onMounted(async () => {
@on-history-card-click="onClick"
@updateFilter="updateFilterValue"
@tagClick="(tag) => updateFilterValue('tag', `'${tag}'`)" />
</BOverlay>
</GOverlay>
<div class="d-flex mt-1 align-items-center">
<div v-if="myView && selectedHistories.length" class="d-flex flex-gapx-1 w-100 position-absolute">
@@ -1,7 +1,7 @@
<script setup lang="ts">
import { faStar, faTags, faTrash } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import { BAlert, BButton, BNav, BNavItem, BOverlay, BPagination } from "bootstrap-vue";
import { BAlert, BButton, BNav, BNavItem, BPagination } from "bootstrap-vue";
import { faTrashRestore } from "font-awesome-6";
import { filter } from "underscore";
import { computed, onMounted, ref, watch } from "vue";
@@ -22,6 +22,7 @@ import type WorkflowCard from "./WorkflowCard.vue";
import WorkflowCardList from "./WorkflowCardList.vue";
import GLink from "@/components/BaseComponents/GLink.vue";
import GOverlay from "@/components/BaseComponents/GOverlay.vue";
import BreadcrumbHeading from "@/components/Common/BreadcrumbHeading.vue";
import FilterMenu from "@/components/Common/FilterMenu.vue";
import Heading from "@/components/Common/Heading.vue";
@@ -506,7 +507,7 @@ onMounted(() => {
</GLink>
</BAlert>
</span>
<BOverlay v-else id="workflow-cards" :show="overlay" rounded="sm" class="cards-list">
<GOverlay v-else id="workflow-cards" :show="overlay" class="cards-list">
<WorkflowCardList
:workflows="workflowsLoaded"
:published-view="published"
@@ -521,7 +522,7 @@ onMounted(() => {
@refreshList="load"
@tagClick="(tag) => updateFilterValue('tag', `'${tag}'`)"
@updateFilter="updateFilterValue" />
</BOverlay>
</GOverlay>
<div class="workflow-list-footer">
<div
@@ -2,7 +2,7 @@
import { faReadme } from "@fortawesome/free-brands-svg-icons";
import { faArrowRight, faCog, faSitemap } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import { BAlert, BFormInput, BModal, BOverlay } from "bootstrap-vue";
import { BAlert, BFormInput, BModal } from "bootstrap-vue";
import { storeToRefs } from "pinia";
import { computed, onBeforeMount, ref, watch } from "vue";
@@ -37,6 +37,7 @@ import WorkflowStorageConfiguration from "./WorkflowStorageConfiguration.vue";
import GButton from "@/components/BaseComponents/GButton.vue";
import GButtonGroup from "@/components/BaseComponents/GButtonGroup.vue";
import GCheckbox from "@/components/BaseComponents/GCheckbox.vue";
import GOverlay from "@/components/BaseComponents/GOverlay.vue";
import Heading from "@/components/Common/Heading.vue";
import FormDisplay from "@/components/Form/FormDisplay.vue";
import HelpText from "@/components/Help/HelpText.vue";
@@ -601,7 +602,7 @@ onBeforeMount(() => {
:style="{ 'overflow-y': 'auto', 'overflow-x': 'hidden' }">
<div v-if="showRightPanel" class="ui-form-header-underlay sticky-top" />
<Heading v-if="showRightPanel" class="sticky-top" h2 separator bold size="sm"> Parameters </Heading>
<BOverlay :show="changingCurrentHistory" no-fade rounded="sm" opacity="0.5">
<GOverlay :show="changingCurrentHistory" no-fade :opacity="0.5">
<template v-slot:overlay>
<LoadingSpan message="Changing your current history" />
</template>
@@ -616,7 +617,7 @@ onBeforeMount(() => {
@onValidation="onValidation"
@stop-flagging="checkInputMatching = false"
@update:active-node-id="updateActiveNodeId" />
</BOverlay>
</GOverlay>
</div>
<div v-if="showRightPanel" class="h-100 w-50 d-flex flex-shrink-0">
<WorkflowRunGraph
@@ -12,6 +12,7 @@ import type { BroadcastNotification } from "@/stores/broadcastsStore";
import BroadcastCard from "./BroadcastCard.vue";
import GButton from "@/components/BaseComponents/GButton.vue";
import GButtonGroup from "@/components/BaseComponents/GButtonGroup.vue";
import GOverlay from "@/components/BaseComponents/GOverlay.vue";
import Heading from "@/components/Common/Heading.vue";
import LoadingSpan from "@/components/LoadingSpan.vue";
@@ -160,7 +161,7 @@ loadBroadcastsList();
There are no broadcast notifications to show. Use the button above to create a new broadcast notification or
change the filters.
</BAlert>
<BOverlay v-else :show="overlay" rounded="sm">
<GOverlay v-else :show="overlay">
<BroadcastCard
v-for="notification in filteredBroadcasts"
:key="notification.id"
@@ -169,7 +170,7 @@ loadBroadcastsList();
@edit="onEdit"
@expire="onForceExpire"
@go-to-link="onGoToLink" />
</BOverlay>
</GOverlay>
</div>
</template>