Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
ce36dd9
remove check for existing data views
KodeRad Nov 5, 2025
086b4da
Merge branch 'main' into ml-job-upload-missing-indices-fix
KodeRad Nov 6, 2025
72702c0
Merge branch 'main' into ml-job-upload-missing-indices-fix
KodeRad Nov 7, 2025
26ae587
display datafeed preview warnings while importing jobs
KodeRad Nov 7, 2025
2a6f36a
simplify validation
KodeRad Nov 8, 2025
2d0cb73
Merge branch 'main' into ml-job-upload-missing-indices-fix
KodeRad Nov 14, 2025
afa2455
surface backend error when present
KodeRad Nov 17, 2025
2bf9250
add warning for dfa jobs
KodeRad Nov 17, 2025
b127ce7
change the validation for dfa jobs without sourceIndex
KodeRad Nov 17, 2025
baba1ab
check for empty array for sourceIndex
KodeRad Nov 17, 2025
9bb7570
break word for class names in datafeed warnings
KodeRad Nov 18, 2025
8d55f6d
improve source index validation
KodeRad Nov 19, 2025
227344d
minor pr fixes
KodeRad Nov 19, 2025
02d77b6
pass mlApi services in constructor instead of props
KodeRad Nov 19, 2025
341c1e7
add unit tests
KodeRad Nov 19, 2025
dd68adb
improve unit tests
KodeRad Nov 20, 2025
f6d5456
inject getFilters via constructor
KodeRad Nov 20, 2025
47f59a9
return errors from validateJobSourceIndices instead of mutating Map
KodeRad Nov 20, 2025
1148f97
move all validation logic into validateJobs
KodeRad Nov 20, 2025
1342a85
Merge branch 'main' into ml-job-upload-missing-indices-fix
KodeRad Nov 20, 2025
1415d9c
simplify constructor
KodeRad Nov 20, 2025
41b28b1
make validateDatafeeds private and update tests
KodeRad Nov 20, 2025
6f2deac
fix warning message and functional tests
KodeRad Nov 20, 2025
9aab8c1
fix translations
KodeRad Nov 20, 2025
File filter

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 @@ -26550,7 +26550,6 @@
"xpack.ml.importExport.importFlyout.cannotImportJobCallout.jobListAria": "afficher les tâches",
"xpack.ml.importExport.importFlyout.cannotImportJobCallout.jobListButton": "Afficher les tâches",
"xpack.ml.importExport.importFlyout.cannotImportJobCallout.missingFilters": "{num, plural, one {Liste de filtres manquante} other {Listes de filtres manquantes}} : {filters}",
"xpack.ml.importExport.importFlyout.cannotImportJobCallout.missingIndex": "{num, plural, one {Modèle d'indexation manquant} other {Modèles d'indexation manquants}} : {indices}",
"xpack.ml.importExport.importFlyout.cannotReadFileCallout.body": "Veuillez sélectionner un fichier contenant des tâches de Machine Learning qui ont été exportées de Kibana à l'aide de l'option Exporter les tâches",
"xpack.ml.importExport.importFlyout.cannotReadFileCallout.title": "Impossible de lire le fichier",
"xpack.ml.importExport.importFlyout.closeButton": "Fermer",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26582,7 +26582,6 @@
"xpack.ml.importExport.importFlyout.cannotImportJobCallout.jobListAria": "ジョブを表示",
"xpack.ml.importExport.importFlyout.cannotImportJobCallout.jobListButton": "ジョブを表示",
"xpack.ml.importExport.importFlyout.cannotImportJobCallout.missingFilters": "フィル��ー{num, plural, one {list} other {リスト}}がありません:{filters}",
"xpack.ml.importExport.importFlyout.cannotImportJobCallout.missingIndex": "インデックス{num, plural, one {pattern} other {パターン}}がありません: {indices}",
"xpack.ml.importExport.importFlyout.cannotImportJobCallout.title": "{num, plural, one {# job} other {# 件のジョブ}}をインポートできません",
"xpack.ml.importExport.importFlyout.cannotReadFileCallout.body": "ジョブのエクスポートオプションを使用してKibanaからエクスポートされた機械学習ジョブを含むファイルを選択してください。",
"xpack.ml.importExport.importFlyout.cannotReadFileCallout.title": "ファイルを読み取れません",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26567,7 +26567,6 @@
"xpack.ml.importExport.importFlyout.cannotImportJobCallout.jobListAria": "查看作业",
"xpack.ml.importExport.importFlyout.cannotImportJobCallout.jobListButton": "查看作业",
"xpack.ml.importExport.importFlyout.cannotImportJobCallout.missingFilters": "缺失筛选{num, plural, one {列表} other {列表}}:{filters}",
"xpack.ml.importExport.importFlyout.cannotImportJobCallout.missingIndex": "缺失索引{num, plural, one {模式} other {模式}}:{indices}",
"xpack.ml.importExport.importFlyout.cannotImportJobCallout.title": "{num, plural, one {# 个作业} other {# 个作业}}无法导入",
"xpack.ml.importExport.importFlyout.cannotReadFileCallout.body": "请选择包含已使用“导出作业”选项从 Kibana 导出的 Machine Learning 作业的文件",
"xpack.ml.importExport.importFlyout.cannotReadFileCallout.title": "无法读取文件",
Expand Down Expand Up @@ -33491,8 +33490,8 @@
"xpack.securitySolution.appLinks.alerts": "告警",
"xpack.securitySolution.appLinks.attackDiscovery": "Attack Discovery",
"xpack.securitySolution.appLinks.blocklistDescription": "阻止不需要的应用程序在您的主机上运行。",
"xpack.securitySolution.appLinks.category.discover": "发现",
"xpack.securitySolution.appLinks.category.cloudSecurity": "云安全",
"xpack.securitySolution.appLinks.category.discover": "发现",
"xpack.securitySolution.appLinks.category.endpoints": "终端",
"xpack.securitySolution.appLinks.category.entityAnalytics": "实体分析",
"xpack.securitySolution.appLinks.category.investigations": "调查",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,23 +66,32 @@ const SkippedJobList: FC<{ jobs: SkippedJobs[] }> = ({ jobs }) => (
<>
{jobs.length > 0 && (
<>
{jobs.map(({ jobId, missingIndices, missingFilters }) => (
<EuiText size="s">
{jobs.map(({ jobId, missingFilters, sourceIndicesErrors }) => (
<EuiText size="xs" key={jobId}>
<h5>{jobId}</h5>
{missingIndices.length > 0 && (
<FormattedMessage
id="xpack.ml.importExport.importFlyout.cannotImportJobCallout.missingIndex"
defaultMessage="Missing index {num, plural, one {pattern} other {patterns}}: {indices}"
values={{ num: missingIndices.length, indices: missingIndices.join(',') }}
/>
)}
{missingFilters.length > 0 && (
{missingFilters && missingFilters.length > 0 && (
<FormattedMessage
id="xpack.ml.importExport.importFlyout.cannotImportJobCallout.missingFilters"
defaultMessage="Missing filter {num, plural, one {list} other {lists}}: {filters}"
values={{ num: missingFilters.length, filters: missingFilters.join(',') }}
/>
)}
{sourceIndicesErrors && sourceIndicesErrors.length > 0 && (
<>
{sourceIndicesErrors.map(({ index, error }, i) => (
<FormattedMessage
key={`${jobId}-${index ?? 'undefined'}-${error}`}
id="xpack.ml.importExport.importFlyout.cannotImportJobCallout.sourceIndexValidationFailed"
defaultMessage="{index, select, undefined {Source indices validation failed} other {Source index validation failed for {index}}}{reason, select, undefined {} other { Reason: {reason}}}{br}"
values={{
index,
reason: error,
br: i < sourceIndicesErrors.length - 1 ? <br /> : '',
}}
/>
))}
</>
)}
</EuiText>
))}
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
EuiPanel,
EuiFormRow,
EuiFieldText,
EuiCallOut,
} from '@elastic/eui';

import { i18n } from '@kbn/i18n';
Expand All @@ -51,13 +52,12 @@ export interface Props {
export const ImportJobsFlyout: FC<Props> = ({ isDisabled, onImportComplete }) => {
const {
services: {
data: {
dataViews: { getTitles: getDataViewTitles },
},
notifications: { toasts },
mlServices: {
mlUsageCollection,
mlApi: {
validateDatafeedPreview,
esSearch,
jobs: { bulkCreateJobs },
dataFrameAnalytics: { createDataFrameAnalytics },
filters: { filters: getFilters },
Expand All @@ -66,7 +66,10 @@ export const ImportJobsFlyout: FC<Props> = ({ isDisabled, onImportComplete }) =>
},
} = useMlKibana();

const jobImportService = useMemo(() => new JobImportService(), []);
const jobImportService = useMemo(
() => new JobImportService(esSearch, validateDatafeedPreview, getFilters),
[esSearch, validateDatafeedPreview, getFilters]
);

const [showFlyout, setShowFlyout] = useState(false);
const [adJobs, setAdJobs] = useState<ImportedAdJob[]>([]);
Expand Down Expand Up @@ -143,9 +146,7 @@ export const ImportJobsFlyout: FC<Props> = ({ isDisabled, onImportComplete }) =>

const validatedJobs = await jobImportService.validateJobs(
loadedFile.jobs,
loadedFile.jobType,
getDataViewTitles,
getFilters
loadedFile.jobType
);

if (loadedFile.jobType === 'anomaly-detector') {
Expand All @@ -161,19 +162,25 @@ export const ImportJobsFlyout: FC<Props> = ({ isDisabled, onImportComplete }) =>
}

setJobType(loadedFile.jobType);

setJobIdObjects(
validatedJobs.jobs.map(({ jobId, destIndex }) => ({
jobId,
originalId: jobId,
jobIdValid: true,
jobIdInvalidMessage: '',
jobIdValidated: false,
destIndex,
originalDestIndex: destIndex,
destIndexValid: true,
destIndexInvalidMessage: '',
destIndexValidated: false,
}))
validatedJobs.jobs.map(({ jobId, destIndex }) => {
const datafeedValidation = validatedJobs.datafeedValidations.get(jobId);
return {
jobId,
originalId: jobId,
jobIdValid: true,
jobIdInvalidMessage: '',
jobIdValidated: false,
destIndex,
originalDestIndex: destIndex,
destIndexValid: true,
destIndexInvalidMessage: '',
destIndexValidated: false,
datafeedInvalid: datafeedValidation?.hasWarning,
datafeedWarningMessage: datafeedValidation?.warningMessage,
};
})
);

const ids = createIdsMash(validatedJobs.jobs as JobIdObject[], loadedFile.jobType);
Expand Down Expand Up @@ -375,6 +382,9 @@ export const ImportJobsFlyout: FC<Props> = ({ isDisabled, onImportComplete }) =>
hideCloseButton
size="m"
data-test-subj="mlJobMgmtImportJobsFlyout"
aria-label={i18n.translate('xpack.ml.importExport.importFlyout.flyoutAriaLabel', {
defaultMessage: 'Import jobs flyout',
})}
>
<EuiFlyoutHeader hasBorder>
<EuiTitle size="m">
Expand Down Expand Up @@ -469,32 +479,59 @@ export const ImportJobsFlyout: FC<Props> = ({ isDisabled, onImportComplete }) =>
</EuiFormRow>

{jobType === 'data-frame-analytics' && (
<EuiFormRow
helpText={
jobId.destIndexValid === true ? jobId.destIndexInvalidMessage : ''
}
error={
jobId.destIndexValid === false
? jobId.destIndexInvalidMessage
: ''
}
isInvalid={jobId.destIndexValid === false}
>
<EuiFieldText
prepend={i18n.translate(
'xpack.ml.importExport.importFlyout.destIndex',
{
defaultMessage: 'Destination index',
}
)}
disabled={importing}
compressed={true}
value={jobId.destIndex}
onChange={(e) => renameDestIndex(e.target.value, i)}
<>
<EuiFormRow
helpText={
jobId.destIndexValid === true
? jobId.destIndexInvalidMessage
: ''
}
error={
jobId.destIndexValid === false
? jobId.destIndexInvalidMessage
: ''
}
isInvalid={jobId.destIndexValid === false}
/>
</EuiFormRow>
>
<EuiFieldText
prepend={i18n.translate(
'xpack.ml.importExport.importFlyout.destIndex',
{
defaultMessage: 'Destination index',
}
)}
disabled={importing}
compressed={true}
value={jobId.destIndex}
onChange={(e) => renameDestIndex(e.target.value, i)}
isInvalid={jobId.destIndexValid === false}
/>
</EuiFormRow>
</>
)}

{jobType === 'anomaly-detector' &&
jobId.datafeedInvalid === true &&
jobId.datafeedWarningMessage && (
<EuiFormRow>
<EuiCallOut
data-test-subj="mlJobImportJobDatafeedWarning"
title={i18n.translate(
'xpack.ml.importExport.importFlyout.datafeedWarning.title',
{
defaultMessage: 'Datafeed Warning',
}
)}
color="warning"
size="s"
announceOnMount
>
<EuiText size="xs" className="eui-textBreakWord">
{jobId.datafeedWarningMessage}
</EuiText>
</EuiCallOut>
</EuiFormRow>
)}
</EuiFlexItem>
<EuiFlexItem grow={false}>
<DeleteJobButton index={i} />
Expand Down
Loading