diff --git a/packages/editor-ui/src/components/SourceControlInitializationErrorMessage.vue b/packages/editor-ui/src/components/SourceControlInitializationErrorMessage.vue new file mode 100644 index 00000000000..f7c1bc7022f --- /dev/null +++ b/packages/editor-ui/src/components/SourceControlInitializationErrorMessage.vue @@ -0,0 +1,17 @@ + + + diff --git a/packages/editor-ui/src/init.test.ts b/packages/editor-ui/src/init.test.ts index d7b381e3f57..d4e366988b7 100644 --- a/packages/editor-ui/src/init.test.ts +++ b/packages/editor-ui/src/init.test.ts @@ -8,6 +8,13 @@ import { createTestingPinia } from '@pinia/testing'; import { setActivePinia } from 'pinia'; import { useSettingsStore } from '@/stores/settings.store'; import { useVersionsStore } from '@/stores/versions.store'; +import { AxiosError } from 'axios'; + +const showMessage = vi.fn(); + +vi.mock('@/composables/useToast', () => ({ + useToast: () => ({ showMessage }), +})); vi.mock('@/stores/users.store', () => ({ useUsersStore: vi.fn().mockReturnValue({ initialize: vi.fn() }), @@ -108,5 +115,21 @@ describe('Init', () => { expect(cloudStoreSpy).toHaveBeenCalledTimes(1); }); + + it('should handle source control initialization error', async () => { + vi.mocked(useUsersStore).mockReturnValue({ currentUser: { id: '123' } } as ReturnType< + typeof useUsersStore + >); + vi.spyOn(sourceControlStore, 'getPreferences').mockRejectedValueOnce( + new AxiosError('Something went wrong', '404'), + ); + const consoleSpy = vi.spyOn(window.console, 'error'); + await initializeAuthenticatedFeatures(false); + expect(showMessage).toHaveBeenCalled(); + expect(consoleSpy).toHaveBeenCalledWith( + 'Failed to initialize source control store', + expect.anything(), + ); + }); }); }); diff --git a/packages/editor-ui/src/init.ts b/packages/editor-ui/src/init.ts index dfdcbe42d22..8b3a69f8203 100644 --- a/packages/editor-ui/src/init.ts +++ b/packages/editor-ui/src/init.ts @@ -1,3 +1,4 @@ +import { h } from 'vue'; import { useCloudPlanStore } from '@/stores/cloudPlan.store'; import { useNodeTypesStore } from '@/stores/nodeTypes.store'; import { useRootStore } from '@/stores/root.store'; @@ -8,6 +9,9 @@ import { useExternalHooks } from '@/composables/useExternalHooks'; import { useVersionsStore } from '@/stores/versions.store'; import { useProjectsStore } from '@/stores/projects.store'; import { useRolesStore } from './stores/roles.store'; +import { useToast } from '@/composables/useToast'; +import { useI18n } from '@/composables/useI18n'; +import SourceControlInitializationErrorMessage from '@/components/SourceControlInitializationErrorMessage.vue'; let coreInitialized = false; let authenticatedFeaturesInitialized = false; @@ -41,8 +45,10 @@ export async function initializeCore() { /** * Initializes the features of the application that require an authenticated user */ -export async function initializeAuthenticatedFeatures() { - if (authenticatedFeaturesInitialized) { +export async function initializeAuthenticatedFeatures( + initialized: boolean = authenticatedFeaturesInitialized, +) { + if (initialized) { return; } @@ -51,6 +57,8 @@ export async function initializeAuthenticatedFeatures() { return; } + const i18n = useI18n(); + const toast = useToast(); const sourceControlStore = useSourceControlStore(); const settingsStore = useSettingsStore(); const rootStore = useRootStore(); @@ -60,7 +68,17 @@ export async function initializeAuthenticatedFeatures() { const rolesStore = useRolesStore(); if (sourceControlStore.isEnterpriseSourceControlEnabled) { - await sourceControlStore.getPreferences(); + try { + await sourceControlStore.getPreferences(); + } catch (e) { + toast.showMessage({ + title: i18n.baseText('settings.sourceControl.connection.error'), + message: h(SourceControlInitializationErrorMessage), + type: 'error', + duration: 0, + }); + console.error('Failed to initialize source control store', e); + } } if (settingsStore.isTemplatesEnabled) { diff --git a/packages/editor-ui/src/plugins/i18n/locales/en.json b/packages/editor-ui/src/plugins/i18n/locales/en.json index a9d0045c533..fd17df3433f 100644 --- a/packages/editor-ui/src/plugins/i18n/locales/en.json +++ b/packages/editor-ui/src/plugins/i18n/locales/en.json @@ -1881,6 +1881,9 @@ "settings.sourceControl.actionBox.description": "Use multiple instances for different environments (dev, prod, etc.), deploying between them via a Git repository.", "settings.sourceControl.actionBox.description.link": "More info", "settings.sourceControl.actionBox.buttonText": "See plans", + "settings.sourceControl.connection.error": "Source control failed to connect", + "settings.sourceControl.connection.error.message": "We couldn't find the repository connected to this instance. Please double-check your {link} on this instance.", + "settings.sourceControl.connection.error.link": "Git configuration", "settings.sourceControl.description": "Use multiple instances for different environments (dev, prod, etc.), deploying between them via a Git repository. {link}", "settings.sourceControl.description.link": "More info", "settings.sourceControl.gitConfig": "Git configuration",