Integrated terminal (#1295)

* Add terminal tab

* Add basic terminal

* Style terminal

* Add keybinding

* Auto scroll:

* Mock for jest test
This commit is contained in:
Chenlei Hu
2024-10-24 23:31:00 +02:00
committed by GitHub
parent d142893244
commit 14a6687cc9
8 changed files with 138 additions and 31 deletions

View File

@@ -1,34 +1,42 @@
<template>
<Tabs v-model:value="bottomPanelStore.activeBottomPanelTabId">
<TabList pt:tabList="border-none">
<div class="w-full flex justify-between">
<div class="tabs-container">
<Tab
v-for="tab in bottomPanelStore.bottomPanelTabs"
:key="tab.id"
:value="tab.id"
class="p-3 border-none"
>
<span class="font-bold">
{{ tab.title.toUpperCase() }}
</span>
</Tab>
<div class="flex flex-col h-full">
<Tabs v-model:value="bottomPanelStore.activeBottomPanelTabId">
<TabList pt:tabList="border-none">
<div class="w-full flex justify-between">
<div class="tabs-container">
<Tab
v-for="tab in bottomPanelStore.bottomPanelTabs"
:key="tab.id"
:value="tab.id"
class="p-3 border-none"
>
<span class="font-bold">
{{ tab.title.toUpperCase() }}
</span>
</Tab>
</div>
<Button
class="justify-self-end"
icon="pi pi-times"
severity="secondary"
size="small"
text
@click="bottomPanelStore.bottomPanelVisible = false"
/>
</div>
<Button
class="justify-self-end"
icon="pi pi-times"
severity="secondary"
size="small"
text
@click="bottomPanelStore.bottomPanelVisible = false"
/>
</div>
</TabList>
</Tabs>
<ExtensionSlot
v-if="bottomPanelStore.activeBottomPanelTab"
:extension="bottomPanelStore.activeBottomPanelTab"
/>
</TabList>
</Tabs>
<!-- h-0 to force the div to flex-grow -->
<div class="flex-grow h-0">
<ExtensionSlot
v-if="
bottomPanelStore.bottomPanelVisible &&
bottomPanelStore.activeBottomPanelTab
"
:extension="bottomPanelStore.activeBottomPanelTab"
/>
</div>
</div>
</template>
<script setup lang="ts">

View File

@@ -0,0 +1,61 @@
<template>
<div class="p-terminal rounded-none h-full w-full">
<ScrollPanel class="h-full w-full" ref="scrollPanelRef">
<pre class="px-4 whitespace-pre-wrap">{{ log }}</pre>
</ScrollPanel>
</div>
</template>
<script setup lang="ts">
import ScrollPanel from 'primevue/scrollpanel'
import { api } from '@/scripts/api'
import { onBeforeUnmount, onMounted, ref, watch } from 'vue'
const log = ref<string>('')
const scrollPanelRef = ref<InstanceType<typeof ScrollPanel> | null>(null)
/**
* Whether the user has scrolled to the bottom of the terminal.
* This is used to prevent the terminal from scrolling to the bottom
* when new logs are fetched.
*/
const scrolledToBottom = ref(false)
let intervalId: number = 0
onMounted(async () => {
const element = scrollPanelRef.value?.$el
const scrollContainer = element?.querySelector('.p-scrollpanel-content')
if (scrollContainer) {
scrollContainer.addEventListener('scroll', () => {
scrolledToBottom.value =
scrollContainer.scrollTop + scrollContainer.clientHeight ===
scrollContainer.scrollHeight
})
}
const scrollToBottom = () => {
if (scrollContainer) {
scrollContainer.scrollTop = scrollContainer.scrollHeight
}
}
watch(log, () => {
if (scrolledToBottom.value) {
scrollToBottom()
}
})
const fetchLogs = async () => {
log.value = await api.getLogs()
}
await fetchLogs()
scrollToBottom()
intervalId = window.setInterval(fetchLogs, 500)
})
onBeforeUnmount(() => {
window.clearInterval(intervalId)
})
</script>