Skip to content

Commit

Permalink
Add about panel in settings dialog (#799)
Browse files Browse the repository at this point in the history
* basic about page

* Remove frontend version from setting dialog header

* Style about page

* basic system stats

* Basic styling

* Reword

* Format memory amount
  • Loading branch information
huchenlei authored Sep 12, 2024
1 parent d2b3e32 commit 637f5b5
Show file tree
Hide file tree
Showing 8 changed files with 227 additions and 20 deletions.
40 changes: 40 additions & 0 deletions src/components/common/DeviceInfo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<template>
<div class="grid grid-cols-2 gap-2">
<template v-for="col in deviceColumns" :key="col.field">
<div class="font-medium">{{ $t(col.header) }}</div>
<div>{{ formatValue(props.device[col.field], col.field) }}</div>
</template>
</div>
</template>

<script setup lang="ts">
import type { DeviceStats } from '@/types/apiTypes'
const props = defineProps<{
device: DeviceStats
}>()
const deviceColumns = [
{ field: 'name', header: 'Name' },
{ field: 'type', header: 'Type' },
{ field: 'vram_total', header: 'VRAM Total' },
{ field: 'vram_free', header: 'VRAM Free' },
{ field: 'torch_vram_total', header: 'Torch VRAM Total' },
{ field: 'torch_vram_free', header: 'Torch VRAM Free' }
]
const formatValue = (value: any, field: string) => {
if (
['vram_total', 'vram_free', 'torch_vram_total', 'torch_vram_free'].includes(
field
)
) {
const mb = Math.round(value / (1024 * 1024))
if (mb >= 1024) {
return `${(mb / 1024).toFixed(2)} GB`
}
return `${mb} MB`
}
return value
}
</script>
55 changes: 55 additions & 0 deletions src/components/common/SystemStatsPanel.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<template>
<div class="system-stats">
<div class="mb-6">
<h2 class="text-2xl font-semibold mb-4">{{ $t('systemInfo') }}</h2>
<div class="grid grid-cols-2 gap-2">
<template v-for="col in systemColumns" :key="col.field">
<div class="font-medium">{{ $t(col.header) }}</div>
<div>{{ systemInfo[col.field] }}</div>
</template>
</div>
</div>

<Divider />

<div>
<h2 class="text-2xl font-semibold mb-4">{{ $t('devices') }}</h2>
<TabView v-if="props.stats.devices.length > 1">
<TabPanel
v-for="device in props.stats.devices"
:key="device.index"
:header="device.name"
>
<DeviceInfo :device="device" />
</TabPanel>
</TabView>
<DeviceInfo v-else :device="props.stats.devices[0]" />
</div>
</div>
</template>

<script setup lang="ts">
import { computed } from 'vue'
import TabView from 'primevue/tabview'
import TabPanel from 'primevue/tabpanel'
import Divider from 'primevue/divider'
import type { SystemStats } from '@/types/apiTypes'
import DeviceInfo from '@/components/common/DeviceInfo.vue'
const props = defineProps<{
stats: SystemStats
}>()
const systemInfo = computed(() => ({
...props.stats.system,
argv: props.stats.system.argv.join(' ')
}))
const systemColumns = [
{ field: 'os', header: 'OS' },
{ field: 'python_version', header: 'Python Version' },
{ field: 'embedded_python', header: 'Embedded Python' },
{ field: 'pytorch_version', header: 'Pytorch Version' },
{ field: 'argv', header: 'Arguments' }
]
</script>
17 changes: 14 additions & 3 deletions src/components/dialog/content/SettingDialogContent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@
}"
/>
</TabPanel>
<TabPanel key="about" value="About">
<AboutPanel />
</TabPanel>
</TabPanels>
</Tabs>
</div>
Expand All @@ -70,17 +73,25 @@ import SettingGroup from './setting/SettingGroup.vue'
import SearchBox from '@/components/common/SearchBox.vue'
import NoResultsPlaceholder from '@/components/common/NoResultsPlaceholder.vue'
import { flattenTree } from '@/utils/treeUtil'
import AboutPanel from './setting/AboutPanel.vue'
interface ISettingGroup {
label: string
settings: SettingParams[]
}
const aboutPanelNode: SettingTreeNode = {
key: 'about',
label: 'About',
children: []
}
const settingStore = useSettingStore()
const settingRoot = computed<SettingTreeNode>(() => settingStore.settingTree)
const categories = computed<SettingTreeNode[]>(
() => settingRoot.value.children || []
)
const categories = computed<SettingTreeNode[]>(() => [
...(settingRoot.value.children || []),
aboutPanelNode
])
const activeCategory = ref<SettingTreeNode | null>(null)
const searchResults = ref<ISettingGroup[]>([])
Expand Down
68 changes: 68 additions & 0 deletions src/components/dialog/content/setting/AboutPanel.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<template>
<div>
<h2 class="text-2xl font-bold mb-2">{{ $t('about') }}</h2>
<div class="space-y-2">
<a
v-for="link in links"
:key="link.url"
:href="link.url"
target="_blank"
rel="noopener noreferrer"
class="inline-flex items-center no-underline"
>
<Tag class="mr-2">
<template #icon>
<i :class="[link.icon, 'mr-2 text-xl']"></i>
</template>
{{ link.label }}
</Tag>
</a>
</div>

<Divider />

<SystemStatsPanel
v-if="systemStatsStore.systemStats"
:stats="systemStatsStore.systemStats"
/>
</div>
</template>

<script setup lang="ts">
import { useSystemStatsStore } from '@/stores/systemStatsStore'
import Tag from 'primevue/tag'
import Divider from 'primevue/divider'
import { computed, onMounted } from 'vue'
import SystemStatsPanel from '@/components/common/SystemStatsPanel.vue'
const systemStatsStore = useSystemStatsStore()
const frontendVersion = window['__COMFYUI_FRONTEND_VERSION__']
const coreVersion = computed(
() => systemStatsStore.systemStats?.system?.comfyui_version ?? ''
)
const links = computed(() => [
{
label: `ComfyUI ${coreVersion.value}`,
url: 'https://github.com/comfyanonymous/ComfyUI',
icon: 'pi pi-github'
},
{
label: `ComfyUI_frontend v${frontendVersion}`,
url: 'https://github.com/Comfy-Org/ComfyUI_frontend',
icon: 'pi pi-github'
},
{
label: 'Discord',
url: 'https://www.comfy.org/discord',
icon: 'pi pi-discord'
},
{ label: 'ComfyOrg', url: 'https://www.comfy.org/', icon: 'pi pi-globe' }
])
onMounted(async () => {
if (!systemStatsStore.systemStats) {
await systemStatsStore.fetchSystemStats()
}
})
</script>
6 changes: 0 additions & 6 deletions src/components/dialog/header/SettingDialogHeader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,10 @@
<h2>
<i class="pi pi-cog"></i>
<span>{{ $t('settings') }}</span>
<Tag :value="frontendVersion" severity="secondary" class="version-tag" />
</h2>
</div>
</template>

<script setup lang="ts">
import Tag from 'primevue/tag'
const frontendVersion = 'v' + window['__COMFYUI_FRONTEND_VERSION__']
</script>

<style scoped>
.pi-cog {
font-size: 1.25rem;
Expand Down
3 changes: 3 additions & 0 deletions src/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import { createI18n } from 'vue-i18n'

const messages = {
en: {
systemInfo: 'System Info',
devices: 'Devices',
about: 'About',
add: 'Add',
confirm: 'Confirm',
reset: 'Reset',
Expand Down
34 changes: 34 additions & 0 deletions src/stores/systemStatsStore.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { defineStore } from 'pinia'
import { ref } from 'vue'
import { api } from '@/scripts/api'
import type { SystemStats } from '@/types/apiTypes'

export const useSystemStatsStore = defineStore('systemStats', () => {
const systemStats = ref<SystemStats | null>(null)
const isLoading = ref(false)
const error = ref<string | null>(null)

async function fetchSystemStats() {
isLoading.value = true
error.value = null

try {
systemStats.value = await api.getSystemStats()
} catch (err) {
error.value =
err instanceof Error
? err.message
: 'An error occurred while fetching system stats'
console.error('Error fetching system stats:', err)
} finally {
isLoading.value = false
}
}

return {
systemStats,
isLoading,
error,
fetchSystemStats
}
})
24 changes: 13 additions & 11 deletions src/types/apiTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,17 @@ const zPromptResponse = z.object({
})
.optional()
})

const zDeviceStats = z.object({
name: z.string(),
type: z.string(),
index: z.number(),
vram_total: z.number(),
vram_free: z.number(),
torch_vram_total: z.number(),
torch_vram_free: z.number()
})

export const zSystemStats = z.object({
system: z.object({
os: z.string(),
Expand All @@ -396,17 +407,7 @@ export const zSystemStats = z.object({
pytorch_version: z.string(),
argv: z.array(z.string())
}),
devices: z.array(
z.object({
name: z.string(),
type: z.string(),
index: z.number().optional(),
vram_total: z.number(),
vram_free: z.number(),
torch_vram_total: z.number(),
torch_vram_free: z.number()
})
)
devices: z.array(zDeviceStats)
})
const zUser = z.object({
storage: z.enum(['server', 'browser']),
Expand Down Expand Up @@ -500,6 +501,7 @@ export type EmbeddingsResponse = z.infer<typeof zEmbeddingsResponse>
export type ExtensionsResponse = z.infer<typeof zExtensionsResponse>
export type PromptResponse = z.infer<typeof zPromptResponse>
export type Settings = z.infer<typeof zSettings>
export type DeviceStats = z.infer<typeof zDeviceStats>
export type SystemStats = z.infer<typeof zSystemStats>
export type User = z.infer<typeof zUser>
export type UserData = z.infer<typeof zUserData>

0 comments on commit 637f5b5

Please sign in to comment.