Skip to content
Merged
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
21 changes: 20 additions & 1 deletion scripts/collect-i18n-general.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as fs from 'fs'

import { comfyPageFixture as test } from '../browser_tests/fixtures/ComfyPage'
import { CORE_MENU_COMMANDS } from '../src/constants/coreMenuCommands'
import { DESKTOP_DIALOGS } from '../src/constants/desktopDialogs'
import { SERVER_CONFIG_ITEMS } from '../src/constants/serverConfig'
import type { FormItem, SettingParams } from '../src/platform/settings/types'
import type { ComfyCommandImpl } from '../src/stores/commandStore'
Expand Down Expand Up @@ -131,6 +132,23 @@ test('collect-i18n-general', async ({ comfyPage }) => {
])
)

// Desktop Dialogs
const allDesktopDialogsLocale = Object.fromEntries(
Object.values(DESKTOP_DIALOGS).map((dialog) => [
normalizeI18nKey(dialog.id),
{
title: dialog.title,
message: dialog.message,
buttons: Object.fromEntries(
dialog.buttons.map((button) => [
normalizeI18nKey(button.label),
button.label
])
)
}
])
)

fs.writeFileSync(
localePath,
JSON.stringify(
Expand All @@ -144,7 +162,8 @@ test('collect-i18n-general', async ({ comfyPage }) => {
...allSettingCategoriesLocale
},
serverConfigItems: allServerConfigsLocale,
serverConfigCategories: allServerConfigCategoriesLocale
serverConfigCategories: allServerConfigCategoriesLocale,
desktopDialogs: allDesktopDialogsLocale
},
null,
2
Expand Down
6 changes: 6 additions & 0 deletions src/assets/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@
--color-charcoal-700: #202121;
--color-charcoal-800: #171718;

--color-neutral-550: #636363;

--color-stone-100: #444444;
--color-stone-200: #828282;
--color-stone-300: #bbbbbb;
Expand Down Expand Up @@ -103,6 +105,10 @@
--color-danger-100: #c02323;
--color-danger-200: #d62952;

--color-coral-red-600: #973a40;
--color-coral-red-500: #c53f49;
--color-coral-red-400: #dd424e;

--color-bypass: #6a246a;
--color-error: #962a2a;

Expand Down
75 changes: 75 additions & 0 deletions src/constants/desktopDialogs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
export interface DialogAction {
readonly label: string
readonly action: 'openUrl' | 'close' | 'cancel'
readonly url?: string
readonly severity?: 'danger' | 'primary' | 'secondary' | 'warn'
readonly returnValue: string
}

interface DesktopDialog {
readonly title: string
readonly message: string
readonly buttons: DialogAction[]
}

export const DESKTOP_DIALOGS = {
/** Shown when a corrupt venv is detected. */
reinstallVenv: {
title: 'Reinstall ComfyUI (Fresh Start)?',
message: `Sorry, we can't launch ComfyUI because some installed packages aren't compatible.

Click Reinstall to restore ComfyUI and get back up and running.

Please note: if you've added custom nodes, you'll need to reinstall them after this process.`,
buttons: [
{
label: 'Learn More',
action: 'openUrl',
url: 'https://docs.comfy.org',
returnValue: 'openDocs'
},
{
label: 'Reinstall',
action: 'close',
severity: 'danger',
returnValue: 'resetVenv'
}
]
},
/** A dialog that is shown when an invalid dialog ID is provided. */
invalidDialog: {
title: 'Invalid Dialog',
message: `Invalid dialog ID was provided.`,
buttons: [
{
label: 'Close',
action: 'cancel',
returnValue: 'cancel'
}
]
}
} as const satisfies { [K: string]: DesktopDialog }

/** The ID of a desktop dialog. */
type DesktopDialogId = keyof typeof DESKTOP_DIALOGS

/**
* Checks if {@link id} is a valid dialog ID.
* @param id The string to check
* @returns `true` if the ID is a valid dialog ID, otherwise `false`
*/
function isDialogId(id: unknown): id is DesktopDialogId {
return typeof id === 'string' && id in DESKTOP_DIALOGS
}

/**
* Gets the dialog with the given ID.
* @param dialogId The ID of the dialog to get
* @returns The dialog with the given ID
*/
export function getDialog(
dialogId: string | string[]
): DesktopDialog & { id: DesktopDialogId } {
const id = isDialogId(dialogId) ? dialogId : 'invalidDialog'
return { id, ...structuredClone(DESKTOP_DIALOGS[id]) }
}
6 changes: 6 additions & 0 deletions src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,12 @@ const router = createRouter({
name: 'DesktopUpdateView',
component: () => import('@/views/DesktopUpdateView.vue'),
beforeEnter: guardElectronAccess
},
{
path: 'desktop-dialog/:dialogId',
name: 'DesktopDialogView',
component: () => import('@/views/DesktopDialogView.vue'),
beforeEnter: guardElectronAccess
}
]
}
Expand Down
70 changes: 70 additions & 0 deletions src/views/DesktopDialogView.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<template>
<div class="w-full h-full flex flex-col rounded-lg p-6 justify-between">
<h1 class="font-inter font-semibold text-xl m-0 italic">
{{ t(`desktopDialogs.${id}.title`, title) }}
</h1>
<p class="whitespace-pre-wrap">
{{ t(`desktopDialogs.${id}.message`, message) }}
</p>
<div class="flex w-full gap-2">
<Button
v-for="button in buttons"
:key="button.label"
class="rounded-lg first:mr-auto"
:label="
t(
`desktopDialogs.${id}.buttons.${normalizeI18nKey(button.label)}`,
button.label
)
"
:severity="button.severity ?? 'secondary'"
@click="handleButtonClick(button)"
/>
</div>
</div>
</template>

<script setup lang="ts">
import Button from 'primevue/button'
import { useRoute } from 'vue-router'

import { type DialogAction, getDialog } from '@/constants/desktopDialogs'
import { t } from '@/i18n'
import { electronAPI } from '@/utils/envUtil'
import { normalizeI18nKey } from '@/utils/formatUtil'

const route = useRoute()
const { id, title, message, buttons } = getDialog(route.params.dialogId)

const handleButtonClick = async (button: DialogAction) => {
await electronAPI().Dialog.clickButton(button.returnValue)
}
</script>

<style scoped>
@reference '../assets/css/style.css';

.p-button-secondary {
@apply text-white border-none bg-neutral-600;
}

.p-button-secondary:hover {
@apply bg-neutral-550;
}

.p-button-secondary:active {
@apply bg-neutral-500;
}

.p-button-danger {
@apply bg-coral-red-600;
}

.p-button-danger:hover {
@apply bg-coral-red-500;
}

.p-button-danger:active {
@apply bg-coral-red-400;
}
</style>