Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Block simulate API calls if datasource version is missing #657

Merged
merged 5 commits into from
Mar 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ import {
injectParameters,
prepareDocsForSimulate,
unwrapTransformedDocs,
useDataSourceVersion,
useMissingDataSourceVersion,
} from '../../../../../../utils';
import { TextField } from '../../../input_fields';
import {
Expand Down Expand Up @@ -94,6 +96,11 @@ const MAX_INPUT_DOCS = 10;
export function ConfigureExpressionModal(props: ConfigureExpressionModalProps) {
const dispatch = useAppDispatch();
const dataSourceId = getDataSourceId();
const dataSourceVersion = useDataSourceVersion(dataSourceId);
const missingDataSourceVersion = useMissingDataSourceVersion(
dataSourceId,
dataSourceVersion
);
const { values, setFieldValue, setFieldTouched } = useFormikContext<
WorkflowFormValues
>();
Expand Down Expand Up @@ -407,6 +414,8 @@ export function ConfigureExpressionModal(props: ConfigureExpressionModalProps) {
style={{ width: '100px' }}
isLoading={isFetching}
disabled={
(props.context === PROCESSOR_CONTEXT.INGEST &&
missingDataSourceVersion) ||
onIngestAndNoDocs ||
onSearchAndNoQuery ||
!props.isDataFetchingAvailable ||
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ import {
injectParameters,
prepareDocsForSimulate,
unwrapTransformedDocs,
useDataSourceVersion,
useMissingDataSourceVersion,
} from '../../../../../../utils';
import { TextField } from '../../../input_fields';
import {
Expand Down Expand Up @@ -91,6 +93,11 @@ export function ConfigureMultiExpressionModal(
) {
const dispatch = useAppDispatch();
const dataSourceId = getDataSourceId();
const dataSourceVersion = useDataSourceVersion(dataSourceId);
const missingDataSourceVersion = useMissingDataSourceVersion(
dataSourceId,
dataSourceVersion
);
const { values, setFieldValue, setFieldTouched } = useFormikContext<
WorkflowFormValues
>();
Expand Down Expand Up @@ -433,6 +440,8 @@ export function ConfigureMultiExpressionModal(
style={{ width: '100px' }}
isLoading={isFetching}
disabled={
(props.context === PROCESSOR_CONTEXT.INGEST &&
missingDataSourceVersion) ||
onIngestAndNoDocs ||
onSearchAndNoQuery ||
!props.isDataFetchingAvailable ||
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ import {
injectParameters,
prepareDocsForSimulate,
unwrapTransformedDocs,
useDataSourceVersion,
useMissingDataSourceVersion,
} from '../../../../../../utils';
import { TextField } from '../../../input_fields';
import {
Expand Down Expand Up @@ -102,6 +104,11 @@ const PROMPT_EDITOR_ID = 'promptEditor';
export function ConfigureTemplateModal(props: ConfigureTemplateModalProps) {
const dispatch = useAppDispatch();
const dataSourceId = getDataSourceId();
const dataSourceVersion = useDataSourceVersion(dataSourceId);
const missingDataSourceVersion = useMissingDataSourceVersion(
dataSourceId,
dataSourceVersion
);
const { values, setFieldValue, setFieldTouched } = useFormikContext<
WorkflowFormValues
>();
Expand Down Expand Up @@ -638,6 +645,8 @@ export function ConfigureTemplateModal(props: ConfigureTemplateModalProps) {
style={{ width: '100px' }}
isLoading={isFetching}
disabled={
(props.context === PROCESSOR_CONTEXT.INGEST &&
missingDataSourceVersion) ||
onIngestAndNoDocs ||
onSearchAndNoQuery ||
!props.isDataFetchingAvailable ||
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import {
import {
formikToUiConfig,
getDataSourceFromURL,
getEffectiveVersion,
getDataSourceVersion,
} from '../../../utils';
import {
CollapseProcessor,
Expand Down Expand Up @@ -120,9 +120,9 @@ export function ProcessorsList(props: ProcessorsListProps) {
}

if (dataSourceId !== undefined) {
getEffectiveVersion(dataSourceId)
getDataSourceVersion(dataSourceId)
.then((ver) => {
setVersion(ver);
setVersion(ver || MIN_SUPPORTED_VERSION);
})
.catch(console.error);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ import { EnrichSearchRequest } from './enrich_search_request';
import { EnrichSearchResponse } from './enrich_search_response';
import {
CachedFormikState,
MIN_SUPPORTED_VERSION,
OMIT_SYSTEM_INDEX_PATTERN,
WorkflowConfig,
} from '../../../../../common';
import { catIndices, useAppDispatch } from '../../../../store';
import { getDataSourceId, getEffectiveVersion } from '../../../../utils';
import { getDataSourceId, getDataSourceVersion } from '../../../../utils';

interface SearchInputsProps {
uiConfig: WorkflowConfig;
Expand All @@ -42,10 +43,11 @@ export function SearchInputs(props: SearchInputsProps) {
const checkVersion = async () => {
try {
if (dataSourceId !== undefined) {
const version = await getEffectiveVersion(dataSourceId);
const version =
(await getDataSourceVersion(dataSourceId)) || MIN_SUPPORTED_VERSION;
setShowTransformQuery(semver.gte(version, '2.19.0'));
} else {
setShowTransformQuery(true);
setShowTransformQuery(true);
}
} catch (error) {
console.error('Error checking version:', error);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ import {
sleep,
useDataSourceVersion,
getIsPreV219,
useMissingDataSourceVersion,
} from '../../../utils';
import { BooleanField } from './input_fields';
import '../workspace/workspace-styles.scss';
Expand Down Expand Up @@ -104,6 +105,10 @@ export function WorkflowInputs(props: WorkflowInputsProps) {
const dataSourceId = getDataSourceId();
const dataSourceVersion = useDataSourceVersion(dataSourceId);
const isPreV219 = getIsPreV219(dataSourceVersion);
const missingDataSourceVersion = useMissingDataSourceVersion(
dataSourceId,
dataSourceVersion
);

// transient running states
const [isUpdatingSearchPipeline, setIsUpdatingSearchPipeline] = useState<
Expand Down Expand Up @@ -610,7 +615,10 @@ export function WorkflowInputs(props: WorkflowInputsProps) {
if (
!isEmpty(values?.ingest?.enrich) &&
values?.ingest?.pipelineName !== undefined &&
values?.ingest?.pipelineName !== ''
values?.ingest?.pipelineName !== '' &&
// if the data source version is missing/undefined, we cannot
// guarantee that the simulate API will be available
!missingDataSourceVersion
) {
const curDocs = prepareDocsForSimulate(
values?.ingest?.docs,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,11 @@ import {
WORKFLOW_NAME_RESTRICTIONS,
} from '../../../../common';
import { WORKFLOWS_TAB } from '../workflows';
import { getDataSourceId, getEffectiveVersion, formatDisplayVersion } from '../../../utils/utils';
import {
getDataSourceId,
formatDisplayVersion,
useDataSourceVersion,
} from '../../../utils/utils';

interface ImportWorkflowModalProps {
isImportModalOpen: boolean;
Expand All @@ -62,17 +66,7 @@ interface ImportWorkflowModalProps {
export function ImportWorkflowModal(props: ImportWorkflowModalProps) {
const dispatch = useAppDispatch();
const dataSourceId = getDataSourceId();
const [dataSourceVersion, setDataSourceVersion] = useState<
string | undefined
>(undefined);
useEffect(() => {
async function getVersion() {
if (dataSourceId !== undefined) {
setDataSourceVersion(await getEffectiveVersion(dataSourceId));
}
}
getVersion();
}, [dataSourceId]);
const dataSourceVersion = useDataSourceVersion(dataSourceId);
const { workflows } = useSelector((state: AppState) => state.workflows);

// workflow name state
Expand Down Expand Up @@ -171,7 +165,9 @@ export function ImportWorkflowModal(props: ImportWorkflowModalProps) {
<>
<EuiFlexItem>
<EuiCallOut
title={`The uploaded file is not compatible with the current data source version ${formatDisplayVersion(dataSourceVersion)}. Upload a compatible file or switch to another data source.`}
title={`The uploaded file is not compatible with the current data source version ${formatDisplayVersion(
dataSourceVersion
)}. Upload a compatible file or switch to another data source.`}
iconType={'alert'}
color="danger"
/>
Expand Down
8 changes: 5 additions & 3 deletions public/pages/workflows/new_workflow/new_workflow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import { enrichPresetWorkflowWithUiMetadata } from './utils';
import {
getDataSourceId,
isDataSourceReady,
getEffectiveVersion,
getDataSourceVersion,
} from '../../../utils';
import { getDataSourceEnabled } from '../../../services';
import semver from 'semver';
Expand Down Expand Up @@ -64,7 +64,8 @@ const filterPresetsByVersion = async (
WORKFLOW_TYPE.CUSTOM,
];

const version = await getEffectiveVersion(dataSourceId);
const version =
(await getDataSourceVersion(dataSourceId)) || MIN_SUPPORTED_VERSION;

if (semver.lt(version, MIN_SUPPORTED_VERSION)) {
return [];
Expand Down Expand Up @@ -159,7 +160,8 @@ export function NewWorkflow(props: NewWorkflowProps) {
return;
}

const version = await getEffectiveVersion(dataSourceId);
const version =
(await getDataSourceVersion(dataSourceId)) || MIN_SUPPORTED_VERSION;

const enrichedWorkflows = presetWorkflows.map((presetWorkflow) =>
enrichPresetWorkflowWithUiMetadata(presetWorkflow, version)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ export function QuickConfigureModal(props: QuickConfigureModalProps) {
<EuiFlexGroup direction="column" gutterSize="s">
<EuiFlexItem>
<TextField
label="Name - required"
label="Name"
fullWidth={true}
fieldPath={`name`}
showError={true}
Expand Down Expand Up @@ -308,7 +308,7 @@ export function QuickConfigureModal(props: QuickConfigureModalProps) {
modelCategory={MODEL_CATEGORY.LLM}
fieldPath="llm"
showMissingInterfaceCallout={false}
label="Large language model - required"
label="Large language model"
helpText="The large language model to generate user-friendly responses."
fullWidth={true}
showError={true}
Expand Down Expand Up @@ -340,7 +340,7 @@ export function QuickConfigureModal(props: QuickConfigureModalProps) {
modelCategory={MODEL_CATEGORY.EMBEDDING}
fieldPath="embeddingModel"
showMissingInterfaceCallout={false}
label="Embedding model - required"
label="Embedding model"
helpText="The model to generate embeddings."
fullWidth={true}
showError={true}
Expand Down
63 changes: 42 additions & 21 deletions public/utils/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -160,27 +160,39 @@ export function isValidWorkflow(workflowObj: any): boolean {

// Determines if a file used for import workflow is compatible with the current data source version.
export async function isCompatibleWorkflow(
workflowObj: any,
workflowObj: any,
dataSourceId?: string | undefined
): Promise<boolean> {
const compatibility = workflowObj?.version?.compatibility;

// Default to true when compatibility cannot be assessed (empty/invalid compatibility array or MDS disabled.)
if (!Array.isArray(compatibility) || compatibility.length === 0 || dataSourceId === undefined) {
if (
!Array.isArray(compatibility) ||
compatibility.length === 0 ||
dataSourceId === undefined
) {
return true;
}

const dataSourceVersion = await getEffectiveVersion(dataSourceId);
const [effectiveMajorVersion, effectiveMinorVersion] = dataSourceVersion.split('.').map(Number);

const dataSourceVersion =
(await getDataSourceVersion(dataSourceId)) || MIN_SUPPORTED_VERSION;
const [
effectiveMajorVersion,
effectiveMinorVersion,
] = dataSourceVersion.split('.').map(Number);

// Checks if any version in compatibility array matches the current dataSourceVersion (major.minor)
return compatibility.some(compatibleVersion => {
const [compatibleMajor, compatibleMinor] = compatibleVersion.split('.').map(Number);
return effectiveMajorVersion === compatibleMajor && effectiveMinorVersion === compatibleMinor;
return compatibility.some((compatibleVersion) => {
const [compatibleMajor, compatibleMinor] = compatibleVersion
.split('.')
.map(Number);
return (
effectiveMajorVersion === compatibleMajor &&
effectiveMinorVersion === compatibleMinor
);
});
}


export function isValidUiWorkflow(workflowObj: any): boolean {
return (
isValidWorkflow(workflowObj) &&
Expand Down Expand Up @@ -561,7 +573,7 @@ export function useDataSourceVersion(
useEffect(() => {
async function getVersion() {
if (dataSourceId !== undefined) {
setDataSourceVersion(await getEffectiveVersion(dataSourceId));
setDataSourceVersion(await getDataSourceVersion(dataSourceId));
}
}
getVersion();
Expand Down Expand Up @@ -933,13 +945,13 @@ export function getFieldValue(jsonObj: {}, fieldName: string): any | undefined {
return undefined;
}

// Get the version from the selected data source
export const getEffectiveVersion = async (
// Get the version from the selected data source, if found
export const getDataSourceVersion = async (
dataSourceId: string | undefined
): Promise<string> => {
): Promise<string | undefined> => {
try {
if (dataSourceId === undefined) {
throw new Error('Data source is required');
throw new Error();
}

if (dataSourceId === '') {
Expand All @@ -951,16 +963,26 @@ export const getEffectiveVersion = async (
'data-source',
dataSourceId
);
const version =
dataSource?.attributes?.dataSourceVersion || MIN_SUPPORTED_VERSION;
return version;
return dataSource?.attributes?.dataSourceVersion;
} catch (error) {
console.error('Error getting version:', error);
return MIN_SUPPORTED_VERSION;
console.error('Error getting version: ', error);
return undefined;
}
};


export function useMissingDataSourceVersion(
dataSourceId: string | undefined,
dataSourceVersion: string | undefined
): boolean {
const [missingVersion, setMissingVersion] = useState<boolean>(false);
useEffect(() => {
setMissingVersion(
dataSourceId !== undefined && dataSourceVersion === undefined
);
}, [dataSourceId, dataSourceVersion]);
return missingVersion;
}

/**
* Formats version string to show only major.minor numbers
* Example: "3.0.0-alpha1" -> "3.0"
Expand All @@ -970,4 +992,3 @@ export function formatDisplayVersion(version: string): string {
const [major, minor] = version.split('.');
return `${major}.${minor}`;
}

Loading