Skip to content
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
403a32b
replace useEffect with observables as much as possible
mattkime Oct 1, 2022
27c1b86
Merge branch 'main' into refactor_data_view_create
mattkime Oct 1, 2022
1476c84
cleanup, fix timestamp field / allow hidden bug
mattkime Oct 2, 2022
ab39b4e
cleanup
mattkime Oct 2, 2022
cf2fcc1
Merge branch 'main' into refactor_data_view_create
mattkime Oct 2, 2022
c734834
fix highlighting for comma separated index patterns
mattkime Oct 2, 2022
dbc7d2e
fix jest test
mattkime Oct 2, 2022
32ee139
fix tests
mattkime Oct 2, 2022
3d2890b
getIsRollupIndex cleanup
mattkime Oct 7, 2022
6f771ea
revert showHidden flag for field caps
mattkime Oct 7, 2022
2a12a3e
type fix
mattkime Oct 7, 2022
e2814b4
cleanup, fix timestamp selection
mattkime Oct 7, 2022
989d652
add comments
mattkime Oct 7, 2022
159440e
Merge branch 'main' into refactor_data_view_create
mattkime Oct 7, 2022
c3d7c0f
transition business logic to service
mattkime Oct 7, 2022
30763f8
type fix
mattkime Oct 8, 2022
2d7544b
update limits
mattkime Oct 8, 2022
d8c5bdd
Merge branch 'main' into refactor_data_view_create
mattkime Oct 8, 2022
fc32839
remove comment
mattkime Oct 8, 2022
e350211
Merge branch 'main' into refactor_data_view_create
mattkime Oct 10, 2022
8bd2cd0
Merge branch 'main' into refactor_data_view_create
flash1293 Oct 10, 2022
d612886
reduce limits entry
mattkime Oct 10, 2022
21a5da5
Merge branch 'main' into refactor_data_view_create
mattkime Oct 10, 2022
7059c53
Merge branch 'main' into refactor_data_view_create
mattkime Oct 10, 2022
833ca22
async load service, no stale state, fix timestamp field default
mattkime Oct 10, 2022
5f3ee43
Merge branch 'refactor_data_view_create' of github.com:mattkime/kiban…
mattkime Oct 10, 2022
ae32bf2
debounce network requests
mattkime Oct 11, 2022
418a438
Merge branch 'main' into refactor_data_view_create
mattkime Oct 11, 2022
1015195
remove unneeded use of dedupe
mattkime Oct 12, 2022
06318bc
Merge branch 'refactor_data_view_create' of github.com:mattkime/kiban…
mattkime Oct 12, 2022
180008c
Merge branch 'main' into refactor_data_view_create
mattkime Oct 12, 2022
1a44ee1
account for failed requests, improve async code
mattkime Oct 12, 2022
245559d
Merge branch 'main' into refactor_data_view_create
mattkime Oct 14, 2022
0625a98
Merge branch 'main' into refactor_data_view_create
mattkime Oct 17, 2022
ec81f4b
fix edit data view
mattkime Oct 17, 2022
6f1ef8c
Merge branch 'refactor_data_view_create' of github.com:mattkime/kiban…
mattkime Oct 17, 2022
f109e9e
fix functional test
mattkime Oct 17, 2022
c00ef54
Merge branch 'main' into refactor_data_view_create
mattkime Oct 17, 2022
c1d4964
Merge branch 'main' into refactor_data_view_create
mattkime Oct 18, 2022
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
2 changes: 1 addition & 1 deletion packages/kbn-optimizer/limits.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pageLoadAssetSize:
dashboard: 82025
dashboardEnhanced: 65646
data: 454087
dataViewEditor: 12000
dataViewEditor: 29619
dataViewFieldEditor: 27000
dataViewManagement: 5000
dataViews: 46532
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* Side Public License, v 1.
*/

import React, { useState, useEffect, useCallback, useRef } from 'react';
import React, { useEffect, useCallback, useRef } from 'react';
import {
EuiTitle,
EuiFlexGroup,
Expand All @@ -15,10 +15,12 @@ import {
EuiLoadingSpinner,
EuiLink,
} from '@elastic/eui';

import { i18n } from '@kbn/i18n';
import memoizeOne from 'memoize-one';
import { BehaviorSubject } from 'rxjs';
import useObservable from 'react-use/lib/useObservable';
import {
DataViewField,
DataViewsPublicPluginStart,
INDEX_PATTERN_TYPE,
MatchedItem,
Expand All @@ -31,11 +33,10 @@ import {
useForm,
useFormData,
useKibana,
GetFieldsOptions,
UseField,
} from '../shared_imports';

import { ensureMinimumTime, extractTimeFields, getMatchedIndices } from '../lib';
import { ensureMinimumTime, getMatchedIndices } from '../lib';
import { FlyoutPanels } from './flyout_panels';

import { removeSpaces } from '../lib';
Expand All @@ -46,7 +47,6 @@ import {
IndexPatternConfig,
MatchedIndicesSet,
FormInternal,
TimestampOption,
} from '../types';

import {
Expand Down Expand Up @@ -78,6 +78,13 @@ export interface Props {
allowAdHoc: boolean;
}

export const matchedIndiciesDefault = {
allIndices: [],
exactMatchedIndices: [],
partialMatchedIndices: [],
visibleIndices: [],
};

const editorTitle = i18n.translate('indexPatternEditor.title', {
defaultMessage: 'Create data view',
});
Expand All @@ -96,7 +103,7 @@ const IndexPatternEditorFlyoutContentComponent = ({
showManagementLink,
}: Props) => {
const {
services: { application, http, dataViews, uiSettings, overlays },
services: { application, dataViews, uiSettings, overlays, dataViewEditorService },
} = useKibana<DataViewEditorContext>();

const canSave = dataViews.getCanSaveSync();
Expand Down Expand Up @@ -125,12 +132,15 @@ const IndexPatternEditorFlyoutContentComponent = ({
return;
}

const rollupIndicesCapabilities = dataViewEditorService.rollupIndicesCapabilities$.getValue();

const indexPatternStub: DataViewSpec = {
title: removeSpaces(formData.title),
timeFieldName: formData.timestampField?.value,
id: formData.id,
name: formData.name,
};
const rollupIndex = rollupIndex$.current.getValue();

if (type === INDEX_PATTERN_TYPE.ROLLUP && rollupIndex) {
indexPatternStub.type = INDEX_PATTERN_TYPE.ROLLUP;
Expand All @@ -156,8 +166,6 @@ const IndexPatternEditorFlyoutContentComponent = ({
},
});

const { getFields } = form;

// `useFormData` initially returns `undefined`,
// we override `undefined` with real default values from `schema`
// to get a stable reference to avoid hooks re-run and reduce number of excessive requests
Expand All @@ -168,133 +176,78 @@ const IndexPatternEditorFlyoutContentComponent = ({
type = schema.type.defaultValue,
},
] = useFormData<FormInternal>({ form });
const [isLoadingSources, setIsLoadingSources] = useState<boolean>(true);

const [timestampFieldOptions, setTimestampFieldOptions] = useState<TimestampOption[]>([]);
const [isLoadingTimestampFields, setIsLoadingTimestampFields] = useState<boolean>(false);
const currentLoadingTimestampFieldsRef = useRef(0);
const [isLoadingMatchedIndices, setIsLoadingMatchedIndices] = useState<boolean>(false);
const currentLoadingMatchedIndicesRef = useRef(0);
const [allSources, setAllSources] = useState<MatchedItem[]>([]);
const [isLoadingIndexPatterns, setIsLoadingIndexPatterns] = useState<boolean>(true);
const [existingIndexPatterns, setExistingIndexPatterns] = useState<string[]>([]);
const [rollupIndex, setRollupIndex] = useState<string | undefined>();
const [rollupIndicesCapabilities, setRollupIndicesCapabilities] =
useState<RollupIndicesCapsResponse>({});
const [matchedIndices, setMatchedIndices] = useState<MatchedIndicesSet>({
allIndices: [],
exactMatchedIndices: [],
partialMatchedIndices: [],
visibleIndices: [],
});

// load all data sources and set initial matchedIndices
const loadSources = useCallback(() => {
dataViews
.getIndices({
isRollupIndex: () => false,
pattern: '*',
showAllIndices: allowHidden,
})
.then((dataSources) => {
setAllSources(dataSources);
const matchedSet = getMatchedIndices(dataSources, [], [], allowHidden);
setMatchedIndices(matchedSet);
setIsLoadingSources(false);
});
}, [allowHidden, dataViews]);
const isLoadingSources = useObservable(dataViewEditorService.isLoadingSources$, true);

// loading list of index patterns
useEffect(() => {
loadSources();
const getTitles = async () => {
const dataViewListItems = await dataViews.getIdsWithTitle(editData ? true : false);
const indexPatternNames = dataViewListItems.map((item) => item.name || item.title);
const loadingMatchedIndices$ = useRef(new BehaviorSubject<boolean>(false));

setExistingIndexPatterns(
editData ? indexPatternNames.filter((v) => v !== editData.name) : indexPatternNames
);
setIsLoadingIndexPatterns(false);
};
getTitles();
}, [http, dataViews, editData, loadSources]);
const isLoadingDataViewNames$ = useRef(new BehaviorSubject<boolean>(true));
const existingDataViewNames$ = useRef(new BehaviorSubject<string[]>([]));
const isLoadingDataViewNames = useObservable(isLoadingDataViewNames$.current, true);

// loading rollup info
const rollupIndicesCapabilities = useObservable(
dataViewEditorService.rollupIndicesCapabilities$,
{}
);

const rollupIndex$ = useRef(new BehaviorSubject<string | undefined>(undefined));

// initial loading of indicies and data view names
useEffect(() => {
const getRollups = async () => {
try {
const response = await http.get<RollupIndicesCapsResponse>('/api/rollup/indices');
if (response) {
setRollupIndicesCapabilities(response);
}
} catch (e) {
// Silently swallow failure responses such as expired trials
}
};
const matchedIndiceSub = dataViewEditorService.matchedIndices$.subscribe((matchedIndices) => {
//
Comment thread
mattkime marked this conversation as resolved.
Outdated
const timeFieldQuery = editData ? editData.title : title;
dataViewEditorService.loadTimestampFields(
removeSpaces(timeFieldQuery),
type,
requireTimestampField,
rollupIndex$.current.getValue()
);
});

getRollups();
}, [http, type]);
dataViewEditorService.loadIndices(title, allowHidden).then((matchedIndices) => {
dataViewEditorService.matchedIndices$.next(matchedIndices);
Comment thread
mattkime marked this conversation as resolved.
});

const getRollupIndices = (rollupCaps: RollupIndicesCapsResponse) => Object.keys(rollupCaps);
// todo is this called when the title changes?
Comment thread
mattkime marked this conversation as resolved.
Outdated
dataViewEditorService.loadDataViewNames(title).then((names) => {
existingDataViewNames$.current.next(names);
isLoadingDataViewNames$.current.next(false);
});

const loadTimestampFieldOptions = useCallback(
async (query: string) => {
const currentLoadingTimestampFieldsIdx = ++currentLoadingTimestampFieldsRef.current;
let timestampOptions: TimestampOption[] = [];
const isValidResult =
matchedIndices.exactMatchedIndices.length > 0 && !isLoadingMatchedIndices;
if (isValidResult) {
setIsLoadingTimestampFields(true);
const getFieldsOptions: GetFieldsOptions = {
pattern: query,
};
if (type === INDEX_PATTERN_TYPE.ROLLUP) {
getFieldsOptions.type = INDEX_PATTERN_TYPE.ROLLUP;
getFieldsOptions.rollupIndex = rollupIndex;
}
return () => {
matchedIndiceSub.unsubscribe();
};
}, [editData, type, title, allowHidden, requireTimestampField, dataViewEditorService]);

const fields = await ensureMinimumTime(dataViews.getFieldsForWildcard(getFieldsOptions));
timestampOptions = extractTimeFields(fields as DataViewField[], requireTimestampField);
}
if (currentLoadingTimestampFieldsIdx === currentLoadingTimestampFieldsRef.current) {
setIsLoadingTimestampFields(false);
setTimestampFieldOptions(timestampOptions);
}
return timestampOptions;
},
[
dataViews,
requireTimestampField,
rollupIndex,
type,
matchedIndices.exactMatchedIndices,
isLoadingMatchedIndices,
]
);
const getRollupIndices = (rollupCaps: RollupIndicesCapsResponse) => Object.keys(rollupCaps);

// used in title field validation
const reloadMatchedIndices = useCallback(
async (newTitle: string) => {
const isRollupIndex = (indexName: string) =>
getRollupIndices(rollupIndicesCapabilities).includes(indexName);
const isRollupIndex = await dataViewEditorService.getIsRollupIndex();
let newRollupIndexName: string | undefined;

const fetchIndices = async (query: string = '') => {
const currentLoadingMatchedIndicesIdx = ++currentLoadingMatchedIndicesRef.current;

setIsLoadingMatchedIndices(true);
loadingMatchedIndices$.current.next(true);

const allSrcs = await dataViews.getIndices({
isRollupIndex,
pattern: '*',
showAllIndices: allowHidden,
});

const { matchedIndicesResult, exactMatched } = !isLoadingSources
? await loadMatchedIndices(query, allowHidden, allSources, {
? await loadMatchedIndices(query, allowHidden, allSrcs, {
isRollupIndex,
dataViews,
})
: {
matchedIndicesResult: {
exactMatchedIndices: [],
allIndices: [],
partialMatchedIndices: [],
visibleIndices: [],
},
matchedIndicesResult: matchedIndiciesDefault,
exactMatched: [],
};

Expand All @@ -303,41 +256,31 @@ const IndexPatternEditorFlyoutContentComponent = ({
if (type === INDEX_PATTERN_TYPE.ROLLUP) {
const rollupIndices = exactMatched.filter((index) => isRollupIndex(index.name));
newRollupIndexName = rollupIndices.length === 1 ? rollupIndices[0].name : undefined;
setRollupIndex(newRollupIndexName);
rollupIndex$.current.next(newRollupIndexName);
} else {
setRollupIndex(undefined);
rollupIndex$.current.next(undefined);
}

setMatchedIndices(matchedIndicesResult);
setIsLoadingMatchedIndices(false);
dataViewEditorService.matchedIndices$.next(matchedIndicesResult);
loadingMatchedIndices$.current.next(false);
}

return { matchedIndicesResult, newRollupIndexName };
};

return fetchIndices(newTitle);
},
[dataViews, allowHidden, allSources, type, rollupIndicesCapabilities, isLoadingSources]
[
dataViews,
allowHidden,
type,
dataViewEditorService,
rollupIndex$,
isLoadingSources,
loadingMatchedIndices$,
]
);

// If editData exists, loadSources so that MatchedIndices can be loaded for the Timestampfields
useEffect(() => {
if (editData) {
loadSources();
reloadMatchedIndices(removeSpaces(editData.title));
}
// We use the below eslint-disable as adding 'loadSources' and 'reloadMatchedIndices' as a dependency creates an infinite loop
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [editData]);

useEffect(() => {
const timeFieldQuery = editData ? editData.title : title;
loadTimestampFieldOptions(removeSpaces(timeFieldQuery));
if (!editData) getFields().timestampField?.setValue('');
// We use the below eslint-disable as adding editData as a dependency create an infinite loop
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [loadTimestampFieldOptions, title, getFields]);

const onTypeChange = useCallback(
(newType) => {
form.setFieldValue('title', '');
Expand All @@ -350,7 +293,7 @@ const IndexPatternEditorFlyoutContentComponent = ({
[form]
);

if (isLoadingSources || isLoadingIndexPatterns) {
if (isLoadingSources || isLoadingDataViewNames) {
return <EuiLoadingSpinner size="xl" />;
}

Expand Down Expand Up @@ -404,7 +347,7 @@ const IndexPatternEditorFlyoutContentComponent = ({
<EuiSpacer size="l" />
<EuiFlexGroup>
<EuiFlexItem>
<NameField editData={editData} existingDataViewNames={existingIndexPatterns} />
<NameField existingDataViewNames$={existingDataViewNames$.current} />
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer size="l" />
Expand All @@ -413,7 +356,7 @@ const IndexPatternEditorFlyoutContentComponent = ({
<TitleField
isRollup={form.getFields().type?.value === INDEX_PATTERN_TYPE.ROLLUP}
refreshMatchedIndices={reloadMatchedIndices}
matchedIndices={matchedIndices.exactMatchedIndices}
matchedIndices$={dataViewEditorService.matchedIndices$}
rollupIndicesCapabilities={rollupIndicesCapabilities}
/>
</EuiFlexItem>
Expand All @@ -422,10 +365,10 @@ const IndexPatternEditorFlyoutContentComponent = ({
<EuiFlexGroup>
<EuiFlexItem>
<TimestampField
options={timestampFieldOptions}
isLoadingOptions={isLoadingTimestampFields}
isLoadingMatchedIndices={isLoadingMatchedIndices}
hasMatchedIndices={!!matchedIndices.exactMatchedIndices.length}
options$={dataViewEditorService.timestampFieldOptions$}
isLoadingOptions$={dataViewEditorService.loadingTimestampFields$}
isLoadingMatchedIndices$={loadingMatchedIndices$.current}
matchedIndices$={dataViewEditorService.matchedIndices$}
/>
</EuiFlexItem>
</EuiFlexGroup>
Expand Down Expand Up @@ -460,7 +403,7 @@ const IndexPatternEditorFlyoutContentComponent = ({
type={type}
allowHidden={allowHidden}
title={title}
matched={matchedIndices}
matchedIndices$={dataViewEditorService.matchedIndices$}
/>
)}
</FlyoutPanels.Item>
Expand Down
Loading