diff --git a/e2e-tests/fixtures/ExternalSources.ts b/e2e-tests/fixtures/ExternalSources.ts index ec04ddf63b..083fc26441 100644 --- a/e2e-tests/fixtures/ExternalSources.ts +++ b/e2e-tests/fixtures/ExternalSources.ts @@ -4,6 +4,7 @@ export class ExternalSources { alertError: Locator; closeButton: Locator; createTypesButton: Locator; + createTypesModal: Locator; deleteSourceButton: Locator; deleteSourceButtonConfirmation: Locator; derivationATypeName: string = 'DerivationA'; @@ -67,6 +68,7 @@ export class ExternalSources { async createType(typeName: string, typeSchema: string, isSourceType: boolean) { await this.createTypesButton.click(); + await expect(this.createTypesModal).toBeVisible(); if (isSourceType) { await this.page.getByRole('radio', { name: 'External Source Type' }).click(); } @@ -80,8 +82,8 @@ export class ExternalSources { } else { await this.waitForToast('External Event Type Created Successfully'); } + await expect(this.createTypesModal).not.toBeVisible(); } - async deleteDerivationGroup(derivationGroupName: string) { await this.page.getByRole('button', { exact: true, name: 'Derivation Group' }).click(); await this.page.getByRole('row', { name: derivationGroupName }).hover(); @@ -195,6 +197,7 @@ export class ExternalSources { this.externalSourcesTable = page.locator('#external-sources-table'); this.createTypesButton = page.getByLabel('Create external source types or external event types.'); this.manageGroupsAndTypesButton = page.getByLabel('Manage and inspect existing'); + this.createTypesModal = page.locator(`.modal:has-text("Create New External Source/Event Types")`); } async uploadExternalSource( @@ -202,6 +205,9 @@ export class ExternalSources { inputFileName: string = this.externalSourceFileName, ) { await this.fillInputFile(inputFilePath); + // Wait for all errors to disappear, assuming stores are just taking time to load + await this.page.getByLabel('please create one before uploading an external source').waitFor({ state: 'hidden' }); + await this.page.getByLabel('Please create it!').waitFor({ state: 'hidden' }); await this.uploadButton.click(); await this.waitForToast('External Source Created Successfully'); await expect(this.externalSourcesTable).toBeVisible(); diff --git a/e2e-tests/tests/external-sources.test.ts b/e2e-tests/tests/external-sources.test.ts index 4cd12d3464..1efcd0c4ce 100644 --- a/e2e-tests/tests/external-sources.test.ts +++ b/e2e-tests/tests/external-sources.test.ts @@ -116,7 +116,6 @@ test.describe.serial('External Source Error Handling', () => { externalSources.externalSourceTypeSchema, true, ); - await page.waitForTimeout(5000); await externalSources.uploadExternalSource(); await externalSources.deselectSourceButton.click(); await expect(externalSources.externalSourcesTable).toBeVisible(); diff --git a/src/components/external-source/ExternalSourceManager.svelte b/src/components/external-source/ExternalSourceManager.svelte index c4aa77efe5..2149813000 100644 --- a/src/components/external-source/ExternalSourceManager.svelte +++ b/src/components/external-source/ExternalSourceManager.svelte @@ -7,6 +7,7 @@ import ExternalEventIcon from '../../assets/external-event-box-with-arrow.svg?component'; import ExternalSourceIcon from '../../assets/external-source-box.svg?component'; import { catchError } from '../../stores/errors'; + import { externalEventTypes } from '../../stores/external-event'; import { createDerivationGroupError, createExternalSourceError, @@ -157,6 +158,8 @@ let file: File | undefined; let externalSourceFileInput: HTMLInputElement; let parsedExternalSource: ExternalSourceJson | undefined; + let isUploadDisabled: boolean = true; + let uploadDisabledMessage: string | null = null; // For filtering purposes (modelled after TimelineEditorLayerFilter): let filterExpression: string = ''; @@ -336,6 +339,20 @@ return planDerivationGroupLink.derivation_group_name === selectedSource?.derivation_group_name; }); + $: if (parsedExternalSource !== undefined) { + if ($externalEventTypes.length === 0) { + uploadDisabledMessage = `No external event types are currently defined, please create one before uploading an external source!`; + isUploadDisabled = true; + } else if ($externalSourceTypes.length === 0) { + uploadDisabledMessage = `External Source Type "${parsedExternalSource.source.source_type}" is not defined. Please create it!`; + isUploadDisabled = true; + } + isUploadDisabled = doesSourceTypeAndEventTypesExist(parsedExternalSource); + } else { + isUploadDisabled = true; + uploadDisabledMessage = null; + } + // Permissions $: hasCreatePermission = featurePermissions.externalSource.canCreate(user); @@ -463,6 +480,27 @@ return featurePermissions.externalSource.canDelete(user, [externalSource]); } } + + function doesSourceTypeAndEventTypesExist(externalSource: ExternalSourceJson): boolean { + // Check that the External Source Type for the source to-be-uploaded exists + const externalSourceType = $externalSourceTypes.find(sourceType => sourceType.name === externalSource.source.source_type); + if (externalSourceType === undefined) { + uploadDisabledMessage = `External Source Type "${externalSource.source.source_type}" is not defined. Please create it!` + return true; + } + + // Check that all the External Event Types for the source to-be-uploaded exist + const newSourceExternalEventTypes: string[] = Array.from(new Set(externalSource.events.map(event => event.event_type))); + for (const eventType of newSourceExternalEventTypes) { + if ($externalEventTypes.find(eventTypeFromDB => eventTypeFromDB.name === eventType) === undefined) { + uploadDisabledMessage = `External Event Type "${eventType}" is not defined. Please create it!` + return true; + } + } + + uploadDisabledMessage = null; + return false; + } @@ -636,6 +674,7 @@ > +
@@ -660,7 +699,7 @@
{/if}