diff --git a/ui/desktop/src/App.test.tsx b/ui/desktop/src/App.test.tsx index 8524d781d689..1e150509cdc3 100644 --- a/ui/desktop/src/App.test.tsx +++ b/ui/desktop/src/App.test.tsx @@ -139,6 +139,7 @@ vi.mock('react-router-dom', () => ({ HashRouter: ({ children }: { children: React.ReactNode }) => <>{children}, Routes: ({ children }: { children: React.ReactNode }) => <>{children}, Route: ({ element }: { element: React.ReactNode }) => element, + Navigate: () => null, useNavigate: () => mockNavigate, useLocation: () => ({ state: null, pathname: '/' }), useSearchParams: () => [mockSearchParams, mockSetSearchParams], diff --git a/ui/desktop/src/App.tsx b/ui/desktop/src/App.tsx index dca6bba5503d..098ac5aaf2bb 100644 --- a/ui/desktop/src/App.tsx +++ b/ui/desktop/src/App.tsx @@ -2,6 +2,7 @@ import { useEffect, useState, useRef } from 'react'; import { IpcRendererEvent } from 'electron'; import { HashRouter, + Navigate, Routes, Route, useNavigate, @@ -45,7 +46,6 @@ import PermissionSettingsView from './components/settings/permission/PermissionS import ExtensionsView, { ExtensionsViewOptions } from './components/extensions/ExtensionsView'; import RecipesView from './components/recipes/RecipesView'; import SkillsView from './components/skills/SkillsView'; -import AppsView from './components/apps/AppsView'; import StandaloneAppView from './components/apps/StandaloneAppView'; import { View, ViewOptions } from './utils/navigationUtils'; @@ -691,7 +691,7 @@ export function AppInner() { } /> - } /> + } /> } /> } /> } /> diff --git a/ui/desktop/src/components/BaseChat.tsx b/ui/desktop/src/components/BaseChat.tsx index f80ec0e0b746..ba37462ccdcf 100644 --- a/ui/desktop/src/components/BaseChat.tsx +++ b/ui/desktop/src/components/BaseChat.tsx @@ -1,11 +1,5 @@ import { AppEvents } from '../constants/events'; -import React, { - useCallback, - useEffect, - useMemo, - useRef, - useState, -} from 'react'; +import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { defineMessages, useIntl } from '../i18n'; import { useLocation, useNavigate } from 'react-router-dom'; import { SearchView } from './conversation/SearchView'; @@ -54,7 +48,7 @@ const i18n = defineMessages({ }, recipeCreatedTitle: { id: 'baseChat.recipeCreatedTitle', - defaultMessage: 'Recipe created successfully!', + defaultMessage: 'Workflow created successfully!', }, recipeCreatedMessage: { id: 'baseChat.recipeCreatedMessage', @@ -199,7 +193,11 @@ export default function BaseChat({ const latestInference = useMemo(() => { for (let i = messages.length - 1; i >= 0; i--) { const message = messages[i]; - if (message.role === 'assistant' && message.metadata.userVisible && message.metadata.inference) { + if ( + message.role === 'assistant' && + message.metadata.userVisible && + message.metadata.inference + ) { return message.metadata.inference; } } @@ -373,7 +371,9 @@ export default function BaseChat({
-

{intl.formatMessage(i18n.failedToLoadSession)}

+

+ {intl.formatMessage(i18n.failedToLoadSession)} +

{sessionLoadError}

- {isCreateMode ? intl.formatMessage(i18n.createRecipeTitle) : intl.formatMessage(i18n.viewEditRecipeTitle)} + {isCreateMode + ? intl.formatMessage(i18n.createRecipeTitle) + : intl.formatMessage(i18n.viewEditRecipeTitle)}

{isCreateMode @@ -589,7 +597,9 @@ export default function CreateEditRecipeModal({ className="inline-flex items-center justify-center gap-2 px-4 py-2" > - {isSaving ? intl.formatMessage(i18n.saving) : intl.formatMessage(i18n.saveAndRunRecipe)} + {isSaving + ? intl.formatMessage(i18n.saving) + : intl.formatMessage(i18n.saveAndRunRecipe)}

diff --git a/ui/desktop/src/components/recipes/CreateRecipeFromSessionModal.tsx b/ui/desktop/src/components/recipes/CreateRecipeFromSessionModal.tsx index 9d1b46228f0f..054b6db2665a 100644 --- a/ui/desktop/src/components/recipes/CreateRecipeFromSessionModal.tsx +++ b/ui/desktop/src/components/recipes/CreateRecipeFromSessionModal.tsx @@ -16,11 +16,11 @@ import { defineMessages, useIntl } from '../../i18n'; const i18n = defineMessages({ title: { id: 'createRecipeFromSession.title', - defaultMessage: 'Create Recipe from Session', + defaultMessage: 'Create Workflow from Session', }, subtitle: { id: 'createRecipeFromSession.subtitle', - defaultMessage: 'Create a reusable recipe based on your current conversation.', + defaultMessage: 'Create a reusable workflow based on your current conversation.', }, analyzingTitle: { id: 'createRecipeFromSession.analyzingTitle', @@ -40,7 +40,7 @@ const i18n = defineMessages({ }, stageGenerating: { id: 'createRecipeFromSession.stageGenerating', - defaultMessage: 'Generating recipe structure...', + defaultMessage: 'Generating workflow structure...', }, stageFinalizing: { id: 'createRecipeFromSession.stageFinalizing', @@ -64,19 +64,19 @@ const i18n = defineMessages({ }, createRecipe: { id: 'createRecipeFromSession.createRecipe', - defaultMessage: 'Create Recipe', + defaultMessage: 'Create Workflow', }, createAndRunRecipe: { id: 'createRecipeFromSession.createAndRunRecipe', - defaultMessage: 'Create & Run Recipe', + defaultMessage: 'Create & Run Workflow', }, failedToCreateTitle: { id: 'createRecipeFromSession.failedToCreateTitle', - defaultMessage: 'Failed to create recipe', + defaultMessage: 'Failed to create workflow', }, failedToCreateDefaultMsg: { id: 'createRecipeFromSession.failedToCreateDefaultMsg', - defaultMessage: 'An unexpected error occurred while creating the recipe. Please try again.', + defaultMessage: 'An unexpected error occurred while creating the workflow. Please try again.', }, }); @@ -279,10 +279,7 @@ export default function CreateRecipeFromSessionModal({ console.error('Failed to create recipe:', error); toastError({ title: intl.formatMessage(i18n.failedToCreateTitle), - msg: errorMessage( - error, - intl.formatMessage(i18n.failedToCreateDefaultMsg) - ), + msg: errorMessage(error, intl.formatMessage(i18n.failedToCreateDefaultMsg)), }); } finally { setIsCreating(false); @@ -307,10 +304,10 @@ export default function CreateRecipeFromSessionModal({
-

{intl.formatMessage(i18n.title)}

-

- {intl.formatMessage(i18n.subtitle)} -

+

+ {intl.formatMessage(i18n.title)} +

+

{intl.formatMessage(i18n.subtitle)}

)} diff --git a/ui/desktop/src/components/recipes/ImportRecipeForm.tsx b/ui/desktop/src/components/recipes/ImportRecipeForm.tsx index d67a14fd4956..8461f4ed69fe 100644 --- a/ui/desktop/src/components/recipes/ImportRecipeForm.tsx +++ b/ui/desktop/src/components/recipes/ImportRecipeForm.tsx @@ -15,11 +15,11 @@ import { defineMessages, useIntl } from '../../i18n'; const i18n = defineMessages({ importRecipeTitle: { id: 'importRecipeForm.importRecipeTitle', - defaultMessage: 'Import Recipe', + defaultMessage: 'Import Workflow', }, recipeDeeplinkLabel: { id: 'importRecipeForm.recipeDeeplinkLabel', - defaultMessage: 'Recipe Deeplink', + defaultMessage: 'Workflow Deeplink', }, deeplinkPlaceholder: { id: 'importRecipeForm.deeplinkPlaceholder', @@ -27,7 +27,7 @@ const i18n = defineMessages({ }, deeplinkHint: { id: 'importRecipeForm.deeplinkHint', - defaultMessage: 'Paste a recipe deeplink starting with "goose://recipe?config="', + defaultMessage: 'Paste a workflow deeplink starting with "goose://recipe?config="', }, or: { id: 'importRecipeForm.or', @@ -35,11 +35,11 @@ const i18n = defineMessages({ }, recipeFileLabel: { id: 'importRecipeForm.recipeFileLabel', - defaultMessage: 'Recipe File', + defaultMessage: 'Workflow File', }, recipeFileHint: { id: 'importRecipeForm.recipeFileHint', - defaultMessage: 'Upload a YAML or JSON file containing the recipe structure', + defaultMessage: 'Upload a YAML or JSON file containing the workflow structure', }, example: { id: 'importRecipeForm.example', @@ -47,7 +47,8 @@ const i18n = defineMessages({ }, reviewWarning: { id: 'importRecipeForm.reviewWarning', - defaultMessage: 'Ensure you review contents of recipe files before adding them to ApeMind Agent.', + defaultMessage: + 'Ensure you review contents of workflow files before adding them to ApeMind Agent.', }, cancel: { id: 'importRecipeForm.cancel', @@ -59,15 +60,16 @@ const i18n = defineMessages({ }, importRecipeButton: { id: 'importRecipeForm.importRecipeButton', - defaultMessage: 'Import Recipe', + defaultMessage: 'Import Workflow', }, expectedRecipeStructure: { id: 'importRecipeForm.expectedRecipeStructure', - defaultMessage: 'Expected Recipe Structure', + defaultMessage: 'Expected Workflow Structure', }, schemaDescription: { id: 'importRecipeForm.schemaDescription', - defaultMessage: 'Your YAML or JSON file should follow this structure. Required fields are: title, description, and either instructions or prompt.', + defaultMessage: + 'Your YAML or JSON file should follow this structure. Required fields are: title, description, and either instructions or prompt.', }, }); @@ -95,7 +97,7 @@ const importRecipeSchema = z }, 'File is too large, max size is 1MB'), }) .refine((data) => (data.deeplink && data.deeplink.trim()) || data.recipeUploadFile, { - message: 'Either of deeplink or recipe file are required', + message: 'Either a deeplink or workflow file is required', path: ['deeplink'], }); @@ -119,11 +121,11 @@ export default function ImportRecipeForm({ isOpen, onClose, onSuccess }: ImportR try { let recipe: Recipe; - // Parse recipe from either deeplink or recipe file + // Parse workflow from either deeplink or file. if (value.deeplink && value.deeplink.trim()) { const parsedRecipe = await parseDeeplink(value.deeplink.trim()); if (!parsedRecipe) { - throw new Error('Invalid deeplink or recipe format'); + throw new Error('Invalid deeplink or workflow format'); } recipe = parsedRecipe; } else { @@ -144,14 +146,14 @@ export default function ImportRecipeForm({ isOpen, onClose, onSuccess }: ImportR toastSuccess({ title: recipe.title.trim(), - msg: 'Recipe imported successfully', + msg: 'Workflow imported successfully', }); } catch (error) { - console.error('Failed to import recipe:', error); + console.error('Failed to import workflow:', error); toastError({ title: 'Import Failed', - msg: `Failed to import recipe: ${errorMessage(error, 'Unknown error')}`, + msg: `Failed to import workflow: ${errorMessage(error, 'Unknown error')}`, traceback: errorMessage(error), }); } finally { @@ -195,7 +197,7 @@ export default function ImportRecipeForm({ isOpen, onClose, onSuccess }: ImportR await parseRecipeFromFile(fileContent); } catch (error) { toastError({ - title: 'Invalid Recipe File', + title: 'Invalid Workflow File', msg: errorMessage(error, 'Unknown error'), }); } @@ -208,7 +210,9 @@ export default function ImportRecipeForm({ isOpen, onClose, onSuccess }: ImportR <>
-

{intl.formatMessage(i18n.importRecipeTitle)}

+

+ {intl.formatMessage(i18n.importRecipeTitle)} +

{ @@ -354,7 +358,9 @@ export default function ImportRecipeForm({ isOpen, onClose, onSuccess }: ImportR disabled={!canSubmit || importing || isSubmitting} variant="default" > - {importing || isSubmitting ? intl.formatMessage(i18n.importing) : intl.formatMessage(i18n.importRecipeButton)} + {importing || isSubmitting + ? intl.formatMessage(i18n.importing) + : intl.formatMessage(i18n.importRecipeButton)} )} @@ -368,7 +374,9 @@ export default function ImportRecipeForm({ isOpen, onClose, onSuccess }: ImportR
-

{intl.formatMessage(i18n.expectedRecipeStructure)}

+

+ {intl.formatMessage(i18n.expectedRecipeStructure)} +

@@ -815,7 +822,11 @@ export default function RecipesView() { variant={schedule_cron ? 'default' : 'outline'} size="sm" className="h-8 w-8 p-0" - title={schedule_cron ? intl.formatMessage(i18n.editSchedule) : intl.formatMessage(i18n.addSchedule)} + title={ + schedule_cron + ? intl.formatMessage(i18n.editSchedule) + : intl.formatMessage(i18n.addSchedule) + } > @@ -888,7 +899,9 @@ export default function RecipesView() { return (

{intl.formatMessage(i18n.noSavedRecipes)}

-

{intl.formatMessage(i18n.noSavedRecipesDescription)}

+

+ {intl.formatMessage(i18n.noSavedRecipesDescription)} +

); } @@ -944,7 +957,10 @@ export default function RecipesView() {
- setSearchTerm(term)} placeholder={intl.formatMessage(i18n.searchRecipesPlaceholder)}> + setSearchTerm(term)} + placeholder={intl.formatMessage(i18n.searchRecipesPlaceholder)} + >
- {intl.formatMessage(i18n.scheduleDialogTitle, { action: scheduleRecipeManifest.schedule_cron ? 'Edit' : 'Add' })} + {intl.formatMessage(i18n.scheduleDialogTitle, { + action: scheduleRecipeManifest.schedule_cron ? 'Edit' : 'Add', + })}
diff --git a/ui/desktop/src/components/recipes/shared/CreateSubRecipeInline.tsx b/ui/desktop/src/components/recipes/shared/CreateSubRecipeInline.tsx index e02b70ab6c29..4f94c6d59d2b 100644 --- a/ui/desktop/src/components/recipes/shared/CreateSubRecipeInline.tsx +++ b/ui/desktop/src/components/recipes/shared/CreateSubRecipeInline.tsx @@ -13,15 +13,15 @@ import { defineMessages, useIntl } from '../../../i18n'; const i18n = defineMessages({ title: { id: 'createSubRecipeInline.title', - defaultMessage: 'Create New Subrecipe', + defaultMessage: 'Create New Sub-workflow', }, subtitle: { id: 'createSubRecipeInline.subtitle', - defaultMessage: 'Create a simple recipe to use as a callable tool in your main recipe', + defaultMessage: 'Create a simple workflow to use as a callable tool in your main workflow', }, closeModal: { id: 'createSubRecipeInline.closeModal', - defaultMessage: 'Close create subrecipe modal', + defaultMessage: 'Close create sub-workflow modal', }, nameLabel: { id: 'createSubRecipeInline.nameLabel', @@ -37,7 +37,7 @@ const i18n = defineMessages({ }, recipeTitleLabel: { id: 'createSubRecipeInline.recipeTitleLabel', - defaultMessage: 'Recipe Title', + defaultMessage: 'Workflow Title', }, recipeTitlePlaceholder: { id: 'createSubRecipeInline.recipeTitlePlaceholder', @@ -45,11 +45,11 @@ const i18n = defineMessages({ }, recipeDescriptionLabel: { id: 'createSubRecipeInline.recipeDescriptionLabel', - defaultMessage: 'Recipe Description', + defaultMessage: 'Workflow Description', }, recipeDescriptionPlaceholder: { id: 'createSubRecipeInline.recipeDescriptionPlaceholder', - defaultMessage: 'What this recipe does when executed', + defaultMessage: 'What this workflow does when executed', }, instructionsLabel: { id: 'createSubRecipeInline.instructionsLabel', @@ -57,7 +57,7 @@ const i18n = defineMessages({ }, instructionsPlaceholder: { id: 'createSubRecipeInline.instructionsPlaceholder', - defaultMessage: 'Instructions for the AI when this subrecipe is called...', + defaultMessage: 'Instructions for the AI when this sub-workflow is called...', }, toolDescriptionLabel: { id: 'createSubRecipeInline.toolDescriptionLabel', @@ -81,7 +81,7 @@ const i18n = defineMessages({ }, preconfiguredValuesHint: { id: 'createSubRecipeInline.preconfiguredValuesHint', - defaultMessage: 'Optional parameter values that are always passed to the subrecipe', + defaultMessage: 'Optional parameter values that are always passed to the sub-workflow', }, cancel: { id: 'createSubRecipeInline.cancel', @@ -93,7 +93,7 @@ const i18n = defineMessages({ }, createAndAdd: { id: 'createSubRecipeInline.createAndAdd', - defaultMessage: 'Create & Add Subrecipe', + defaultMessage: 'Create & Add Sub-workflow', }, validationFailed: { id: 'createSubRecipeInline.validationFailed', @@ -101,7 +101,7 @@ const i18n = defineMessages({ }, validationMsg: { id: 'createSubRecipeInline.validationMsg', - defaultMessage: 'Name, title, recipe description, and instructions are required.', + defaultMessage: 'Name, title, workflow description, and instructions are required.', }, duplicateName: { id: 'createSubRecipeInline.duplicateName', @@ -109,11 +109,11 @@ const i18n = defineMessages({ }, duplicateNameMsg: { id: 'createSubRecipeInline.duplicateNameMsg', - defaultMessage: 'A subrecipe named "{name}" already exists. Please use a unique name.', + defaultMessage: 'A sub-workflow named "{name}" already exists. Please use a unique name.', }, createdSuccess: { id: 'createSubRecipeInline.createdSuccess', - defaultMessage: 'Subrecipe created successfully', + defaultMessage: 'Sub-workflow created successfully', }, saveFailed: { id: 'createSubRecipeInline.saveFailed', @@ -121,7 +121,7 @@ const i18n = defineMessages({ }, saveFailedMsg: { id: 'createSubRecipeInline.saveFailedMsg', - defaultMessage: 'Failed to save subrecipe: {error}', + defaultMessage: 'Failed to save sub-workflow: {error}', }, }); @@ -221,12 +221,24 @@ export default function CreateSubRecipeInline({ toastError({ title: intl.formatMessage(i18n.saveFailed), - msg: intl.formatMessage(i18n.saveFailedMsg, { error: error instanceof Error ? error.message : 'Unknown error' }), + msg: intl.formatMessage(i18n.saveFailedMsg, { + error: error instanceof Error ? error.message : 'Unknown error', + }), }); } finally { setIsSaving(false); } - }, [form, name, toolDescription, sequentialWhenRepeated, values, existingSubRecipes, onSubRecipeSaved, onClose, intl]); + }, [ + form, + name, + toolDescription, + sequentialWhenRepeated, + values, + existingSubRecipes, + onSubRecipeSaved, + onClose, + intl, + ]); if (!isOpen) return null; @@ -236,10 +248,10 @@ export default function CreateSubRecipeInline({ {/* Header */}
-

{intl.formatMessage(i18n.title)}

-

- {intl.formatMessage(i18n.subtitle)} -

+

+ {intl.formatMessage(i18n.title)} +

+

{intl.formatMessage(i18n.subtitle)}

{/* Title Field */} @@ -283,7 +293,8 @@ export default function CreateSubRecipeInline({ htmlFor="subrecipe-title" className="block text-sm font-medium text-text-standard mb-2" > - {intl.formatMessage(i18n.recipeTitleLabel)} * + {intl.formatMessage(i18n.recipeTitleLabel)}{' '} + * - {intl.formatMessage(i18n.recipeDescriptionLabel)} * + {intl.formatMessage(i18n.recipeDescriptionLabel)}{' '} + * - {intl.formatMessage(i18n.instructionsLabel)} * + {intl.formatMessage(i18n.instructionsLabel)}{' '} + *