Files
ComfyUI_frontend/src/components/builder/BuilderSaveDialogContent.vue
pythongosssss 7864e780e7 feat: App mode - Rework save flow (#10439)
## Summary

Users were finding the final step of the builder flow
confusing/misleading, with the "choose default mode" not actually saving
the workflow and people losing changes. This updates it to remove
"save"/"set default" as a step in the builder, and changes it to a
distinct action.

## Changes

- **What**: 
- add mode selection tab on footer toolbar
- extract reusable radio group component
- remove setting default mode dialog
- add save/save as/saved dialogs

## Screenshots (if applicable)


https://github.com/user-attachments/assets/c7439c2e-a917-4f2b-b176-f8bb8c10026d

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10439-feat-App-mode-Rework-save-flow-32d6d73d3650814781b6c7bbea685a97)
by [Unito](https://www.unito.io)
2026-03-27 12:53:09 -07:00

72 lines
1.9 KiB
Vue

<template>
<BuilderDialog @close="emit('close')">
<template #title>
{{ $t('builderToolbar.saveAs') }}
</template>
<div class="flex flex-col gap-2">
<label :for="inputId" class="text-sm text-muted-foreground">
{{ $t('builderToolbar.filename') }}
</label>
<input
:id="inputId"
v-model="filename"
autofocus
type="text"
class="focus-visible:ring-ring flex h-10 min-h-8 items-center self-stretch rounded-lg border-none bg-secondary-background pl-4 text-sm text-base-foreground"
@keydown.enter="
filename.trim() && emit('save', filename.trim(), openAsApp)
"
/>
</div>
<div class="flex flex-col gap-2">
<label :id="radioGroupLabelId" class="text-sm text-muted-foreground">
{{ $t('builderToolbar.defaultViewLabel') }}
</label>
<ViewTypeRadioGroup
v-model="openAsApp"
:aria-labelledby="radioGroupLabelId"
/>
</div>
<template #footer>
<Button variant="muted-textonly" size="lg" @click="emit('close')">
{{ $t('g.cancel') }}
</Button>
<Button
variant="secondary"
size="lg"
:disabled="!filename.trim()"
@click="emit('save', filename.trim(), openAsApp)"
>
{{ $t('g.save') }}
</Button>
</template>
</BuilderDialog>
</template>
<script setup lang="ts">
import { ref, useId } from 'vue'
import Button from '@/components/ui/button/Button.vue'
import BuilderDialog from './BuilderDialog.vue'
import ViewTypeRadioGroup from './ViewTypeRadioGroup.vue'
const { defaultFilename, defaultOpenAsApp = true } = defineProps<{
defaultFilename: string
defaultOpenAsApp?: boolean
}>()
const emit = defineEmits<{
save: [filename: string, openAsApp: boolean]
close: []
}>()
const inputId = useId()
const radioGroupLabelId = useId()
const filename = ref(defaultFilename)
const openAsApp = ref(defaultOpenAsApp)
</script>