From 71626e9c4fdb5a02bc0055831be9ff915b528301 Mon Sep 17 00:00:00 2001 From: Piotr Blaszczyk Date: Fri, 26 Jun 2026 08:42:56 +0200 Subject: [PATCH] fix: remove misleading upgrade prompts from the UI --- .changeset/duplicate-to-drafts-conditional.md | 5 ++ .changeset/template-selector-title.md | 5 ++ apps/demo/src/app/plugins/help/README.md | 2 +- .../help/assets/maciej-teska-workflow.jpg | Bin 8510 -> 0 bytes .../src/app/plugins/help/assets/watermark.svg | 31 +------ .../components/app-bar/get-app-bar-button.tsx | 20 ----- .../help/components/footer-support-button.tsx | 14 --- .../help/functions/add-items-to-dots.tsx | 32 ------- .../help/functions/open-help-modal.tsx | 13 --- .../help/functions/open-no-access-modal.tsx | 15 ---- .../plugins/help/locales/en/translation.json | 14 --- .../plugins/help/locales/pl/translation.json | 14 --- .../modals/no-access/no-access.module.css | 16 ---- .../help/modals/no-access/no-access.tsx | 15 ---- .../sales-contact/sales-contact.module.css | 32 ------- .../modals/sales-contact/sales-contact.tsx | 48 ----------- .../src/app/plugins/help/plugin-exports.ts | 80 +----------------- .../features/app-bar/app-bar-container.tsx | 3 +- .../project-selection.spec.tsx | 63 ++++++++++++++ .../project-selection/project-selection.tsx | 21 +++-- .../open-template-selector-modal.tsx | 2 +- 21 files changed, 96 insertions(+), 349 deletions(-) create mode 100644 .changeset/duplicate-to-drafts-conditional.md create mode 100644 .changeset/template-selector-title.md delete mode 100644 apps/demo/src/app/plugins/help/assets/maciej-teska-workflow.jpg delete mode 100644 apps/demo/src/app/plugins/help/components/app-bar/get-app-bar-button.tsx delete mode 100644 apps/demo/src/app/plugins/help/components/footer-support-button.tsx delete mode 100644 apps/demo/src/app/plugins/help/functions/add-items-to-dots.tsx delete mode 100644 apps/demo/src/app/plugins/help/functions/open-help-modal.tsx delete mode 100644 apps/demo/src/app/plugins/help/functions/open-no-access-modal.tsx delete mode 100644 apps/demo/src/app/plugins/help/locales/en/translation.json delete mode 100644 apps/demo/src/app/plugins/help/locales/pl/translation.json delete mode 100644 apps/demo/src/app/plugins/help/modals/no-access/no-access.module.css delete mode 100644 apps/demo/src/app/plugins/help/modals/no-access/no-access.tsx delete mode 100644 apps/demo/src/app/plugins/help/modals/sales-contact/sales-contact.module.css delete mode 100644 apps/demo/src/app/plugins/help/modals/sales-contact/sales-contact.tsx create mode 100644 packages/sdk/src/features/app-bar/components/project-selection/project-selection.spec.tsx diff --git a/.changeset/duplicate-to-drafts-conditional.md b/.changeset/duplicate-to-drafts-conditional.md new file mode 100644 index 000000000..c77e7342b --- /dev/null +++ b/.changeset/duplicate-to-drafts-conditional.md @@ -0,0 +1,5 @@ +--- +'@workflowbuilder/sdk': patch +--- + +The app bar's "Duplicate to Drafts" menu item now renders only when an `onDuplicateClick` handler is provided, removing the default no-op button. diff --git a/.changeset/template-selector-title.md b/.changeset/template-selector-title.md new file mode 100644 index 000000000..05bf1a61e --- /dev/null +++ b/.changeset/template-selector-title.md @@ -0,0 +1,5 @@ +--- +'@workflowbuilder/sdk': patch +--- + +The template selector modal title now uses the SDK's own `templateSelector.title` string instead of an unrelated plugin translation key. diff --git a/apps/demo/src/app/plugins/help/README.md b/apps/demo/src/app/plugins/help/README.md index de65348a0..0adf94dd0 100644 --- a/apps/demo/src/app/plugins/help/README.md +++ b/apps/demo/src/app/plugins/help/README.md @@ -1,6 +1,6 @@ # Help -Removal of this plugin will result in an application without the "_Unlock Full Product Access_" popup and watermark in the corner. +Removal of this plugin will result in an application without the watermark in the corner. ## Plugins in Workflow Builder diff --git a/apps/demo/src/app/plugins/help/assets/maciej-teska-workflow.jpg b/apps/demo/src/app/plugins/help/assets/maciej-teska-workflow.jpg deleted file mode 100644 index 17fc759931a252da5d20463786cc7a6c1a957f6b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8510 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 - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + diff --git a/apps/demo/src/app/plugins/help/components/app-bar/get-app-bar-button.tsx b/apps/demo/src/app/plugins/help/components/app-bar/get-app-bar-button.tsx deleted file mode 100644 index f946a21f0..000000000 --- a/apps/demo/src/app/plugins/help/components/app-bar/get-app-bar-button.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { NavButton } from '@synergycodes/overflow-ui'; -import { Icon } from '@workflowbuilder/sdk'; -import type { TranslationKey, WBIcon } from '@workflowbuilder/sdk'; -import i18n from 'i18next'; - -import { openNoAccessModal } from '../../functions/open-no-access-modal'; - -export function getAppBarButton(icon: WBIcon, tooltip?: TranslationKey) { - function mockAppBarButton() { - return ( - - - - ); - } - - Object.defineProperty(mockAppBarButton, 'name', { value: `mockAppBarButton` }); - - return mockAppBarButton; -} diff --git a/apps/demo/src/app/plugins/help/components/footer-support-button.tsx b/apps/demo/src/app/plugins/help/components/footer-support-button.tsx deleted file mode 100644 index 8acf4a4c6..000000000 --- a/apps/demo/src/app/plugins/help/components/footer-support-button.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { Button } from '@synergycodes/overflow-ui'; -import { useTranslation } from 'react-i18next'; - -import { openHelpModal } from '../functions/open-help-modal'; - -export function FooterSupportButton() { - const { t } = useTranslation(); - - return ( - - ); -} diff --git a/apps/demo/src/app/plugins/help/functions/add-items-to-dots.tsx b/apps/demo/src/app/plugins/help/functions/add-items-to-dots.tsx deleted file mode 100644 index 35096a5fb..000000000 --- a/apps/demo/src/app/plugins/help/functions/add-items-to-dots.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { type MenuItemProps } from '@synergycodes/overflow-ui'; -import { Icon } from '@workflowbuilder/sdk'; -import i18n from 'i18next'; - -import { openNoAccessModal } from './open-no-access-modal'; - -export function addItemsToDots({ returnValue }: { returnValue: unknown }) { - if (!Array.isArray(returnValue)) { - return; - } - - const items = returnValue as MenuItemProps[]; - - const newItems: MenuItemProps[] = [ - { - label: i18n.t('header.controls.saveAsImage'), - icon: , - onClick: openNoAccessModal, - }, - { - type: 'separator', - }, - { - label: i18n.t('header.controls.archive'), - icon: , - destructive: true, - onClick: openNoAccessModal, - }, - ]; - - return { replacedReturn: [...items, ...newItems] }; -} diff --git a/apps/demo/src/app/plugins/help/functions/open-help-modal.tsx b/apps/demo/src/app/plugins/help/functions/open-help-modal.tsx deleted file mode 100644 index ce76640c7..000000000 --- a/apps/demo/src/app/plugins/help/functions/open-help-modal.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { Info } from '@phosphor-icons/react'; -import { openModal } from '@workflowbuilder/sdk'; -import i18n from 'i18next'; - -import { SalesContact } from '../modals/sales-contact/sales-contact'; - -export function openHelpModal() { - openModal({ - content: , - icon: , - title: i18n.t('plugins.help.helpSupport'), - }); -} diff --git a/apps/demo/src/app/plugins/help/functions/open-no-access-modal.tsx b/apps/demo/src/app/plugins/help/functions/open-no-access-modal.tsx deleted file mode 100644 index 94e58146a..000000000 --- a/apps/demo/src/app/plugins/help/functions/open-no-access-modal.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { Icon, openModal } from '@workflowbuilder/sdk'; -import i18n from 'i18next'; - -import { NoAccess } from '../modals/no-access/no-access'; -import { SalesContact } from '../modals/sales-contact/sales-contact'; - -export function openNoAccessModal() { - openModal({ - content: , - footer: , - footerVariant: 'separated', - icon: , - title: i18n.t('plugins.help.header'), - }); -} diff --git a/apps/demo/src/app/plugins/help/locales/en/translation.json b/apps/demo/src/app/plugins/help/locales/en/translation.json deleted file mode 100644 index 9cc572475..000000000 --- a/apps/demo/src/app/plugins/help/locales/en/translation.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "plugins": { - "help": { - "helpSupport": "Help & Support", - "header": "Unlock Full Product Access", - "title": "Reach out to learn more", - "subtitle": "Connect with us for full access details.", - "tooltipElk": "Refresh layout", - "tooltipUndo": "Undo", - "tooltipRedo": "Redo", - "tooltipOpen": "Open" - } - } -} diff --git a/apps/demo/src/app/plugins/help/locales/pl/translation.json b/apps/demo/src/app/plugins/help/locales/pl/translation.json deleted file mode 100644 index 426d35a16..000000000 --- a/apps/demo/src/app/plugins/help/locales/pl/translation.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "plugins": { - "help": { - "helpSupport": "Pomoc i wsparcie", - "header": "Otrzymaj pełny dostęp do produktu", - "title": "Skontaktuj się, aby dowiedzieć się więcej", - "subtitle": "Uzyskaj szczegółowe informacje o pełnym dostępie.", - "tooltipElk": "Odśwież layout", - "tooltipUndo": "Cofnij", - "tooltipRedo": "Ponów", - "tooltipOpen": "Otwórz" - } - } -} diff --git a/apps/demo/src/app/plugins/help/modals/no-access/no-access.module.css b/apps/demo/src/app/plugins/help/modals/no-access/no-access.module.css deleted file mode 100644 index b88c019ef..000000000 --- a/apps/demo/src/app/plugins/help/modals/no-access/no-access.module.css +++ /dev/null @@ -1,16 +0,0 @@ -:root { - --wb-no-access-color: var(--ax-txt-primary-default); - --wb-no-access-sub-title-color: var(--ax-txt-secondary-default); -} - -.container { - width: 100%; - display: flex; - flex-direction: column; - gap: 0.5rem; - color: var(--wb-no-access-color); - - .sub-title { - color: var(--wb-no-access-sub-title-color); - } -} diff --git a/apps/demo/src/app/plugins/help/modals/no-access/no-access.tsx b/apps/demo/src/app/plugins/help/modals/no-access/no-access.tsx deleted file mode 100644 index 1d2cdd8f5..000000000 --- a/apps/demo/src/app/plugins/help/modals/no-access/no-access.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import clsx from 'clsx'; -import { useTranslation } from 'react-i18next'; - -import styles from './no-access.module.css'; - -export function NoAccess() { - const { t } = useTranslation(); - - return ( -
- {t('plugins.help.title')} - {t('plugins.help.subtitle')} -
- ); -} diff --git a/apps/demo/src/app/plugins/help/modals/sales-contact/sales-contact.module.css b/apps/demo/src/app/plugins/help/modals/sales-contact/sales-contact.module.css deleted file mode 100644 index 5789f3621..000000000 --- a/apps/demo/src/app/plugins/help/modals/sales-contact/sales-contact.module.css +++ /dev/null @@ -1,32 +0,0 @@ -:root { - --wb-sales-contact-color: var(--ax-txt-primary-default); - --wb-sales-contact-position-color: var(--ax-txt-secondary-default); -} - -.container { - width: 100%; - display: flex; - justify-content: space-between; - gap: 0.25rem; - - .details-container { - display: flex; - align-items: center; - gap: 0.5rem; - - .details { - display: flex; - flex-direction: column; - color: var(--wb-sales-contact-color); - - .position { - color: var(--wb-sales-contact-position-color); - } - } - } - - .buttons { - display: flex; - gap: 0.625rem; - } -} diff --git a/apps/demo/src/app/plugins/help/modals/sales-contact/sales-contact.tsx b/apps/demo/src/app/plugins/help/modals/sales-contact/sales-contact.tsx deleted file mode 100644 index 1c778f81e..000000000 --- a/apps/demo/src/app/plugins/help/modals/sales-contact/sales-contact.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { LinkedinLogo, PaperPlaneRight } from '@phosphor-icons/react'; -import { Avatar, Button } from '@synergycodes/overflow-ui'; -import clsx from 'clsx'; - -import styles from './sales-contact.module.css'; - -import imageUrl from '../../assets/maciej-teska-workflow.jpg'; - -const salesDetails = { - name: 'Maciej Teska', - imageUrl, - position: 'CEO', - email: 'maciej.teska@workflowbuilder.io', - linkedInUrl: 'https://linkedin.com/in/maciej-teska', -}; - -export function SalesContact() { - const { name, position, imageUrl, email, linkedInUrl } = salesDetails; - function handleLinkedInClick() { - window.open(`${linkedInUrl}`, '_blank'); - } - - function handleEmailClick() { - globalThis.location.href = `mailto:${email}`; - } - - return ( -
-
- -
- {name} - {position} -
-
-
- - -
-
- ); -} diff --git a/apps/demo/src/app/plugins/help/plugin-exports.ts b/apps/demo/src/app/plugins/help/plugin-exports.ts index a48f9dd80..0026430e5 100644 --- a/apps/demo/src/app/plugins/help/plugin-exports.ts +++ b/apps/demo/src/app/plugins/help/plugin-exports.ts @@ -1,86 +1,10 @@ -import { - hasRegisteredComponentDecorator, - registerComponentDecorator, - registerFunctionDecorator, - registerPluginTranslation, -} from '@workflowbuilder/sdk'; -import type { DiagramContainerProps, ProjectSelectionProps, PropertiesBarProps } from '@workflowbuilder/sdk'; +import { registerComponentDecorator } from '@workflowbuilder/sdk'; +import type { DiagramContainerProps } from '@workflowbuilder/sdk'; -import { getAppBarButton } from './components/app-bar/get-app-bar-button'; -import { FooterSupportButton } from './components/footer-support-button'; import { Watermark } from './components/watermark/watermark'; -import { addItemsToDots } from './functions/add-items-to-dots'; -import { openNoAccessModal } from './functions/open-no-access-modal'; -import * as translationEN from './locales/en/translation.json'; -import * as translationPL from './locales/pl/translation.json'; export function plugin(): void { - registerComponentDecorator('OptionalFooterContent', { - content: FooterSupportButton, - place: 'after', - }); - registerComponentDecorator('DiagramContainer', { content: Watermark, }); - - registerFunctionDecorator('getControlsDotsItems', { - callback: addItemsToDots, - place: 'after', - priority: 10, - }); - - registerComponentDecorator('ProjectSelection', { - modifyProps: (props) => ({ - ...props, - onDuplicateClick: openNoAccessModal, - }), - }); - - registerComponentDecorator('PropertiesBar', { - modifyProps: (props) => ({ - ...props, - onMenuHeaderClick: openNoAccessModal, - }), - }); - - registerComponentDecorator('OptionalAppBarTools', { - content: getAppBarButton('FolderOpen', 'plugins.help.tooltipOpen'), - place: 'after', - priority: 10, - }); - - /* - This plugin checks whether those buttons are already registered - to avoid rendering hints about features that have been added to the project. - */ - if (hasRegisteredComponentDecorator('OptionalAppBarTools', 'UndoRedo') === false) { - registerComponentDecorator('OptionalAppBarTools', { - content: getAppBarButton('ArrowUUpLeft', 'plugins.help.tooltipUndo'), - place: 'after', - name: 'OptionalAppBarToolsArrowUUpLeft', - }); - - registerComponentDecorator('OptionalAppBarTools', { - content: getAppBarButton('ArrowUUpRight', 'plugins.help.tooltipRedo'), - place: 'after', - name: 'OptionalAppBarToolsArrowUUpRight', - }); - } - - if (hasRegisteredComponentDecorator('OptionalAppBarControls', 'ElkLayout') === false) { - registerComponentDecorator('OptionalAppBarControls', { - content: getAppBarButton('TreeStructureDown', 'plugins.help.tooltipElk'), - place: 'before', - }); - } - - registerPluginTranslation({ - en: { - translation: translationEN, - }, - pl: { - translation: translationPL, - }, - }); } diff --git a/packages/sdk/src/features/app-bar/app-bar-container.tsx b/packages/sdk/src/features/app-bar/app-bar-container.tsx index c0c1782e0..b6236cf39 100644 --- a/packages/sdk/src/features/app-bar/app-bar-container.tsx +++ b/packages/sdk/src/features/app-bar/app-bar-container.tsx @@ -1,7 +1,6 @@ import styles from './app-bar.module.css'; import './variables.css'; -import { noop } from '../../utils/noop'; import { Controls } from './components/controls/controls'; import { ProjectSelection } from './components/project-selection/project-selection'; import { Toolbar } from './components/toolbar/toolbar'; @@ -17,7 +16,7 @@ export function AppBarContainer() { return (
- +
); diff --git a/packages/sdk/src/features/app-bar/components/project-selection/project-selection.spec.tsx b/packages/sdk/src/features/app-bar/components/project-selection/project-selection.spec.tsx new file mode 100644 index 000000000..a75151c66 --- /dev/null +++ b/packages/sdk/src/features/app-bar/components/project-selection/project-selection.spec.tsx @@ -0,0 +1,63 @@ +import type { MenuItemProps } from '@synergycodes/overflow-ui'; +import { fireEvent, render, screen } from '@testing-library/react'; +import { describe, expect, it, vi } from 'vitest'; + +// Render the menu's `items` inline so we can assert on them without driving the +// real overflow-ui popover. The component also imports Input/NavButton, so the +// mock must expose them too. +vi.mock('@synergycodes/overflow-ui', () => ({ + Menu: ({ items }: { items: MenuItemProps[] }) => ( +
    + {items.map((item) => ( +
  • + +
  • + ))} +
+ ), + NavButton: () => null, + Input: () => null, +})); + +vi.mock('@workflow-builder/icons', () => ({ + Icon: () => null, +})); + +vi.mock('react-i18next', () => ({ + useTranslation: () => ({ t: (key: string) => key }), +})); + +vi.mock('../../../../features/variables/modals/modal-settings', () => ({ + openModalWorkflowSettings: vi.fn(), +})); + +vi.mock('../../../../store/store', () => ({ + useStore: ( + selector: (state: { documentName: string; isReadOnlyMode: boolean; setDocumentName: () => void }) => T, + ) => selector({ documentName: 'Doc', isReadOnlyMode: false, setDocumentName: () => {} }), +})); + +const { ProjectSelection } = await import('./project-selection'); + +const DUPLICATE_LABEL = 'header.projectSelection.duplicateToDrafts'; +const SETTINGS_LABEL = 'common.settings'; + +describe('ProjectSelection — "Duplicate to Drafts" visibility', () => { + it('omits the item when no onDuplicateClick is provided (default editor)', () => { + render(); + + expect(screen.getByText(SETTINGS_LABEL)).toBeDefined(); + expect(screen.queryByText(DUPLICATE_LABEL)).toBeNull(); + }); + + it('renders the item and wires the handler when onDuplicateClick is provided', () => { + const onDuplicateClick = vi.fn(); + render(); + + const item = screen.getByText(DUPLICATE_LABEL); + expect(item).toBeDefined(); + + fireEvent.click(item); + expect(onDuplicateClick).toHaveBeenCalledTimes(1); + }); +}); diff --git a/packages/sdk/src/features/app-bar/components/project-selection/project-selection.tsx b/packages/sdk/src/features/app-bar/components/project-selection/project-selection.tsx index 168de52a7..6ca66b438 100644 --- a/packages/sdk/src/features/app-bar/components/project-selection/project-selection.tsx +++ b/packages/sdk/src/features/app-bar/components/project-selection/project-selection.tsx @@ -19,7 +19,10 @@ import { withOptionalComponentPlugins } from '../../../plugins-core/adapters/ada * @category Components */ export type ProjectSelectionProps = { - /** Optional handler wired into the kebab menu's "Duplicate to drafts" item. */ + /** + * Optional handler for the kebab menu's "Duplicate to Drafts" item. The item + * is rendered only when this is provided — omit it and the item is absent. + */ onDuplicateClick?: () => void; }; @@ -46,11 +49,17 @@ function ProjectSelectionComponent({ onDuplicateClick }: ProjectSelectionProps) icon: , onClick: openModalWorkflowSettings, }, - { - label: t('header.projectSelection.duplicateToDrafts'), - icon: , - onClick: onDuplicateClick, - }, + // Rendered only when the host wires a handler; without one it would be a + // dead no-op item, so we leave it out entirely. + ...(onDuplicateClick + ? [ + { + label: t('header.projectSelection.duplicateToDrafts'), + icon: , + onClick: onDuplicateClick, + }, + ] + : []), ], [onDuplicateClick, t], ); diff --git a/packages/sdk/src/features/modals/template-selector/open-template-selector-modal.tsx b/packages/sdk/src/features/modals/template-selector/open-template-selector-modal.tsx index e66c173f5..4a6b45475 100644 --- a/packages/sdk/src/features/modals/template-selector/open-template-selector-modal.tsx +++ b/packages/sdk/src/features/modals/template-selector/open-template-selector-modal.tsx @@ -10,7 +10,7 @@ export function openTemplateSelectorModal() { openModal({ content: , icon: , - title: i18n.t('plugins.help.header'), + title: i18n.t('templateSelector.title'), onModalClosed: () => useStore.getState().setDiagramModel(undefined, { skipIfNotEmpty: true }), }); }