Skip to content

Commit 5497970

Browse files
authored
Cloud feedback Extension (#6626)
This pull request introduces a new extensible system for adding custom action bar buttons to the top menu, and demonstrates its use by adding a cloud feedback button. The changes include defining a new `ActionBarButton` type, updating the extension system to support action bar buttons, creating a Pinia store to aggregate buttons from extensions, and updating the UI to render these buttons in the top menu. The cloud feedback button is now conditionally loaded for cloud environments. **Extensible Action Bar Button System** * Defined a new `ActionBarButton` interface in `comfy.ts` for describing buttons (icon, label, tooltip, class, click handler) and added an `actionBarButtons` property to the `ComfyExtension` interface to allow extensions to contribute buttons. [[1]](diffhunk://#diff-c29886a1b0c982c6fff3545af0ca <img width="1134" height="437" alt="Screenshot 2025-11-07 at 01 07 36" src="https://github.com/user-attachments/assets/36b6145a-0b82-4f7d-88e8-f2ea350a359b" /> 8ec269876c2cf3948f867d08c14032c04d66R60-R82) [[2]](diffhunk://#diff-c29886a1b0c982c6fff3545af0ca8ec269876c2cf3948f867d08c14032c04d66R128-R131) * Created a Pinia store (`actionBarButtonStore.ts`) that collects all action bar buttons from registered extensions for use in the UI. **UI Integration** * Added a new `ActionBarButtons.vue` component that renders all action bar buttons using the store, and integrated it into the top menu section (`TopMenuSection.vue`). [[1]](diffhunk://#diff-d6820f57cde865083d515ac0c23e1ad09e6fbc6792d742ae948a1d3b772be473R1-R28) [[2]](diffhunk://#diff-45dffe390927ed2d5ba2426a139c52adae28ce15f81821c88e7991944562074cR10) [[3]](diffhunk://#diff-45dffe390927ed2d5ba2426a139c52adae28ce15f81821c88e7991944562074cR28) **Cloud Feedback Button Extension** * Implemented a new extension (`cloudFeedbackTopbarButton.ts`) that registers a "Feedback" button opening the Zendesk feedback page, and ensured it loads only in cloud environments. [[1]](diffhunk://#diff-b84a6a0dfaca19fd77b3fae6999a40c3ab8d04ed22636fcdecc65b385a8e9a98R1-R24) [[2]](diffhunk://#diff-236993d9e4213efe96d267c75c3292d32b93aa4dd6c3318d26a397e0ae56bc87R32) ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-6626-Cloud-feedback-Extension-2a46d73d36508170bd07f582ccfabb3c) by [Unito](https://www.unito.io)
1 parent 64e704c commit 5497970

File tree

7 files changed

+106
-1
lines changed

7 files changed

+106
-1
lines changed

src/components/TopMenuSection.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
<div
88
class="actionbar-container pointer-events-auto flex h-12 items-center rounded-lg border border-[var(--interface-stroke)] px-2 shadow-interface"
99
>
10+
<ActionBarButtons />
1011
<!-- Support for legacy topbar elements attached by custom scripts, hidden if no elements present -->
1112
<div
1213
ref="legacyCommandsContainerRef"
@@ -24,6 +25,7 @@ import { onMounted, ref } from 'vue'
2425
2526
import ComfyActionbar from '@/components/actionbar/ComfyActionbar.vue'
2627
import SubgraphBreadcrumb from '@/components/breadcrumb/SubgraphBreadcrumb.vue'
28+
import ActionBarButtons from '@/components/topbar/ActionBarButtons.vue'
2729
import CurrentUserButton from '@/components/topbar/CurrentUserButton.vue'
2830
import LoginButton from '@/components/topbar/LoginButton.vue'
2931
import { useCurrentUser } from '@/composables/auth/useCurrentUser'
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<template>
2+
<div class="flex h-full shrink-0 items-center gap-1">
3+
<Button
4+
v-for="(button, index) in actionBarButtonStore.buttons"
5+
:key="index"
6+
v-tooltip.bottom="button.tooltip"
7+
:label="button.label"
8+
:aria-label="button.tooltip || button.label"
9+
:class="button.class"
10+
text
11+
rounded
12+
severity="secondary"
13+
class="h-7"
14+
@click="button.onClick"
15+
>
16+
<template #icon>
17+
<i :class="button.icon" />
18+
</template>
19+
</Button>
20+
</div>
21+
</template>
22+
23+
<script lang="ts" setup>
24+
import Button from 'primevue/button'
25+
26+
import { useActionBarButtonStore } from '@/stores/actionBarButtonStore'
27+
28+
const actionBarButtonStore = useActionBarButtonStore()
29+
</script>
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { t } from '@/i18n'
2+
import { useExtensionService } from '@/services/extensionService'
3+
import type { ActionBarButton } from '@/types/comfy'
4+
5+
// Zendesk feedback URL - update this with the actual URL
6+
const ZENDESK_FEEDBACK_URL =
7+
'https://support.comfy.org/hc/en-us/requests/new?ticket_form_id=43066738713236'
8+
9+
const buttons: ActionBarButton[] = [
10+
{
11+
icon: 'icon-[lucide--message-circle-question-mark]',
12+
label: t('actionbar.feedback'),
13+
tooltip: t('actionbar.feedbackTooltip'),
14+
onClick: () => {
15+
window.open(ZENDESK_FEEDBACK_URL, '_blank', 'noopener,noreferrer')
16+
}
17+
}
18+
]
19+
20+
useExtensionService().registerExtension({
21+
name: 'Comfy.Cloud.FeedbackButton',
22+
actionBarButtons: buttons
23+
})

src/extensions/core/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ if (isCloud) {
2929
await import('./cloudRemoteConfig')
3030
await import('./cloudBadges')
3131
await import('./cloudSessionCookie')
32+
await import('./cloudFeedbackTopbarButton')
3233

3334
if (window.__CONFIG__?.subscription_required) {
3435
await import('./cloudSubscription')

src/locales/en/main.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2282,7 +2282,9 @@
22822282
}
22832283
},
22842284
"actionbar": {
2285-
"dockToTop": "Dock to top"
2285+
"dockToTop": "Dock to top",
2286+
"feedback": "Feedback",
2287+
"feedbackTooltip": "Feedback"
22862288
},
22872289
"desktopDialogs": {
22882290
"": {

src/stores/actionBarButtonStore.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { defineStore } from 'pinia'
2+
import { computed } from 'vue'
3+
4+
import type { ActionBarButton } from '@/types/comfy'
5+
6+
import { useExtensionStore } from './extensionStore'
7+
8+
export const useActionBarButtonStore = defineStore('actionBarButton', () => {
9+
const extensionStore = useExtensionStore()
10+
11+
const buttons = computed<ActionBarButton[]>(() =>
12+
extensionStore.extensions.flatMap((e) => e.actionBarButtons ?? [])
13+
)
14+
15+
return {
16+
buttons
17+
}
18+
})

src/types/comfy.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,32 @@ export interface TopbarBadge {
5757
tooltip?: string
5858
}
5959

60+
/*
61+
* Action bar button definition: add buttons to the action bar
62+
*/
63+
export interface ActionBarButton {
64+
/**
65+
* Icon class to display (e.g., "icon-[lucide--message-circle-question-mark]")
66+
*/
67+
icon: string
68+
/**
69+
* Optional label text to display next to the icon
70+
*/
71+
label?: string
72+
/**
73+
* Optional tooltip text to show on hover
74+
*/
75+
tooltip?: string
76+
/**
77+
* Optional CSS classes to apply to the button
78+
*/
79+
class?: string
80+
/**
81+
* Click handler for the button
82+
*/
83+
onClick: () => void
84+
}
85+
6086
export type MissingNodeType =
6187
| string
6288
// Primarily used by group nodes.
@@ -102,6 +128,10 @@ export interface ComfyExtension {
102128
* Badges to add to the top bar
103129
*/
104130
topbarBadges?: TopbarBadge[]
131+
/**
132+
* Buttons to add to the action bar
133+
*/
134+
actionBarButtons?: ActionBarButton[]
105135
/**
106136
* Allows any initialisation, e.g. loading resources. Called after the canvas is created but before nodes are added
107137
* @param app The ComfyUI app instance

0 commit comments

Comments
 (0)