Skip to content

Commit

Permalink
Add column service to index pattern & Register data source column
Browse files Browse the repository at this point in the history
Signed-off-by: Kristen Tian <[email protected]>
  • Loading branch information
kristenTian committed Oct 10, 2022
1 parent ac07159 commit b49c6e0
Show file tree
Hide file tree
Showing 15 changed files with 190 additions and 15 deletions.
6 changes: 3 additions & 3 deletions src/plugins/data_source/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
* SPDX-License-Identifier: Apache-2.0
*/

import { DataSourcePublicPlugin } from './plugin';
import { DataSourcePlugin } from './plugin';

// This exports static code and TypeScript types,
// as well as, OpenSearch Dashboards Platform `plugin()` initializer.
export function plugin() {
return new DataSourcePublicPlugin();
return new DataSourcePlugin();
}

export { DataSourcePublicPluginSetup, DataSourcePublicPluginStart } from './types';
export { DataSourcePluginSetup, DataSourcePluginStart } from './types';
9 changes: 4 additions & 5 deletions src/plugins/data_source/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@
*/

import { CoreSetup, CoreStart, Plugin } from '../../../core/public';
import { DataSourcePublicPluginSetup, DataSourcePublicPluginStart } from './types';
import { DataSourcePluginSetup, DataSourcePluginStart } from './types';

export class DataSourcePublicPlugin
implements Plugin<DataSourcePublicPluginSetup, DataSourcePublicPluginStart> {
public setup(core: CoreSetup): DataSourcePublicPluginSetup {
export class DataSourcePlugin implements Plugin<DataSourcePluginSetup, DataSourcePluginStart> {
public setup(core: CoreSetup): DataSourcePluginSetup {
return {};
}

public start(core: CoreStart): DataSourcePublicPluginStart {
public start(core: CoreStart): DataSourcePluginStart {
return {};
}

Expand Down
4 changes: 2 additions & 2 deletions src/plugins/data_source/public/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*/

// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface DataSourcePublicPluginSetup {}
export interface DataSourcePluginSetup {}

// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface DataSourcePublicPluginStart {}
export interface DataSourcePluginStart {}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"version": "opensearchDashboards",
"server": false,
"ui": true,
"requiredPlugins": ["management", "dataSource"],
"requiredPlugins": ["management", "dataSource", "indexPatternManagement"],
"optionalPlugins": [],
"requiredBundles": ["opensearchDashboardsReact"]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { i18n } from '@osd/i18n';
import { HttpStart, SavedObjectsStart } from 'opensearch-dashboards/public';
import { EuiBadge, EuiLink } from '@elastic/eui';
import React from 'react';
import {
IndexPatternTableColumn,
IndexPatternTableRecord,
} from '../../../../index_pattern_management/public';
import { getDataSources } from '../utils';
import { DataSourceTableItem } from '../../types';

type DataSourceColumnItem = DataSourceTableItem & { relativeUrl: string };
type DataSourceMap = Map<string, DataSourceColumnItem> | undefined;

export class DataSourceColumn implements IndexPatternTableColumn<DataSourceMap> {
public readonly id: string = 'data_source';
public data: DataSourceMap;

public euiColumn = {
field: 'referenceId',
name: i18n.translate('dataSource.management.dataSourceColumn', {
defaultMessage: 'Data Source',
}),
render: (referenceId: string, index: IndexPatternTableRecord) => {
if (!referenceId) {
return null;
}

const dataSource = this.data?.get(referenceId);
if (!dataSource) {
// Index pattern has the referenceId but data source not found.
return <EuiBadge color="danger">Deleted</EuiBadge>;
}

const { title, relativeUrl } = dataSource;
return <EuiLink href={relativeUrl}>{title}</EuiLink>;
},
};

constructor(
private readonly savedObjectPromise: Promise<SavedObjectsStart>,
private readonly httpPromise: Promise<HttpStart>
) {}

public loadData = async () => {
const savedObject = await this.savedObjectPromise;
const { basePath } = await this.httpPromise;

return getDataSources(savedObject.client).then((dataSources?: DataSourceTableItem[]) => {
this.data = dataSources
?.map((dataSource) => {
return {
...dataSource,
relativeUrl: basePath.prepend(
`/app/management/opensearch-dashboards/dataSources/${encodeURIComponent(
dataSource.id
)}`
),
};
})
?.reduce(
(map, dataSource) => map.set(dataSource.id, dataSource),
new Map<string, DataSourceColumnItem>()
);
return this.data;
});
};
}
15 changes: 14 additions & 1 deletion src/plugins/data_source_management/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,35 @@ import { CoreSetup, CoreStart, Plugin } from '../../../core/public';
import { PLUGIN_NAME } from '../common';

import { ManagementSetup } from '../../management/public';
import { IndexPatternManagementSetup } from '../../index_pattern_management/public';
import { DataSourceColumn } from './components/data_source_column/data_source_column';

export interface DataSourceManagementSetupDependencies {
management: ManagementSetup;
indexPatternManagement: IndexPatternManagementSetup;
}

const DSM_APP_ID = 'dataSources';

export class DataSourceManagementPlugin
implements Plugin<void, void, DataSourceManagementSetupDependencies> {
public setup(core: CoreSetup, { management }: DataSourceManagementSetupDependencies) {
public setup(
core: CoreSetup,
{ management, indexPatternManagement }: DataSourceManagementSetupDependencies
) {
const opensearchDashboardsSection = management.sections.section.opensearchDashboards;

if (!opensearchDashboardsSection) {
throw new Error('`opensearchDashboards` management section not found.');
}

const savedObjectPromise = core
.getStartServices()
.then(([coreStart]) => coreStart.savedObjects);
const httpPromise = core.getStartServices().then(([coreStart]) => coreStart.http);
const column = new DataSourceColumn(savedObjectPromise, httpPromise);
indexPatternManagement.columns.register(column);

opensearchDashboardsSection.registerApp({
id: DSM_APP_ID,
title: PLUGIN_NAME,
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ import { FormattedMessage } from '@osd/i18n/react';
import { withRouter, RouteComponentProps } from 'react-router-dom';
import React, { useState, useEffect } from 'react';
import { i18n } from '@osd/i18n';
import { useMount } from 'react-use';
import { useEffectOnce, useMount } from 'react-use';
import {
reactRouterNavigate,
useOpenSearchDashboards,
Expand Down Expand Up @@ -112,6 +112,9 @@ export const IndexPatternTable = ({ canSave, history }: Props) => {
const [remoteClustersExist, setRemoteClustersExist] = useState<boolean>(false);
const [isLoadingSources, setIsLoadingSources] = useState<boolean>(!dataSourceEnabled);
const [isLoadingIndexPatterns, setIsLoadingIndexPatterns] = useState<boolean>(true);
const [isColumnDataLoaded, setIsColumnDataLoaded] = useState(false);

const { columns: columnRegistry } = indexPatternManagementStart;

useMount(() => {
setBreadcrumbs(getListBreadcrumbs());
Expand Down Expand Up @@ -153,6 +156,11 @@ export const IndexPatternTable = ({ canSave, history }: Props) => {
);
};

const loadColumnData = async () => {
await Promise.all(columnRegistry.getAll().map((column) => column.loadData()));
setIsColumnDataLoaded(true);
};

useEffect(() => {
if (!dataSourceEnabled) {
getIndices({ http, pattern: '*', searchClient }).then((dataSources) => {
Expand All @@ -165,6 +173,10 @@ export const IndexPatternTable = ({ canSave, history }: Props) => {
}
}, [http, creationOptions, searchClient, dataSourceEnabled]);

useEffectOnce(() => {
loadColumnData();
});

chrome.docTitle.change(title);

const columns = [
Expand Down Expand Up @@ -197,6 +209,13 @@ export const IndexPatternTable = ({ canSave, history }: Props) => {
dataType: 'string' as const,
sortable: ({ sort }: { sort: string }) => sort,
},
...columnRegistry.getAll().map((column) => {
return {
...column.euiColumn,
sortable: false,
'data-test-subj': `indexPatternTableColumn-${column.id}`,
};
}),
];

const createButton = canSave ? (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,18 +50,22 @@ export async function getIndexPatterns(
.map((pattern) => {
const id = pattern.id;
const title = pattern.get('title');
const references = pattern.references;
const isDefault = defaultIndex === id;

const tags = (indexPatternManagementStart as IndexPatternManagementStart).list.getIndexPatternTags(
pattern,
isDefault
);
const reference = Array.isArray(references) ? references[0] : undefined;
const referenceId = reference?.id;

return {
id,
title,
default: isDefault,
tags,
referenceId,
// the prepending of 0 at the default pattern takes care of prioritization
// so the sorting will but the default index on top
// or on bottom of a the table
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/index_pattern_management/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,4 @@ export {

export { DefaultFormatEditor } from './components/field_editor/components/field_format_editor';

export { MlCardState } from './types';
export { MlCardState, IndexPatternTableColumn, IndexPatternTableRecord } from './types';
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ import { i18n } from '@osd/i18n';
import { I18nProvider } from '@osd/i18n/react';
import { StartServicesAccessor } from 'src/core/public';

import { EuiIconType } from '@elastic/eui/src/components/icon/icon';
import { OpenSearchDashboardsContextProvider } from '../../../opensearch_dashboards_react/public';
import { ManagementAppMountParams } from '../../../management/public';
import {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { IndexPatternTableColumn } from '../../types';

export interface IndexPatternTableColumnServiceSetup {
/**
* register given column in the registry.
*/
register: (column: IndexPatternTableColumn<unknown>) => void;
}

export interface IndexPatternTableColumnServiceStart {
/**
* return all {@link IndexPatternTableColumn | columns} currently registered.
*/
getAll: () => Array<IndexPatternTableColumn<unknown>>;
}

export class IndexPatternTableColumnService {
private readonly columns = new Map<string, IndexPatternTableColumn<unknown>>();

setup(): IndexPatternTableColumnServiceSetup {
return {
register: (column) => {
if (this.columns.has(column.id)) {
throw new Error(`Index Pattern Table Column with id '${column.id}' already exists`);
}
this.columns.set(column.id, column);
},
};
}

start(): IndexPatternTableColumnServiceStart {
return {
getAll: () => [...this.columns.values()],
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

export * from './column_service';
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import {
TruncateFormatEditor,
UrlFormatEditor,
} from '../components/field_editor/components/field_format_editor';
import { IndexPatternTableColumnService } from './column_service';

interface SetupDependencies {
httpClient: HttpSetup;
Expand All @@ -62,12 +63,14 @@ export class IndexPatternManagementService {
indexPatternListConfig: IndexPatternListManager;
fieldFormatEditors: FieldFormatEditors;
environmentService: EnvironmentService;
columnService: IndexPatternTableColumnService;

constructor() {
this.indexPatternCreationManager = new IndexPatternCreationManager();
this.indexPatternListConfig = new IndexPatternListManager();
this.fieldFormatEditors = new FieldFormatEditors();
this.environmentService = new EnvironmentService();
this.columnService = new IndexPatternTableColumnService();
}

public setup({ httpClient }: SetupDependencies) {
Expand Down Expand Up @@ -98,6 +101,7 @@ export class IndexPatternManagementService {
list: indexPatternListConfigSetup,
fieldFormatEditors: fieldFormatEditorsSetup,
environment: this.environmentService.setup(),
columns: this.columnService.setup(),
};
}

Expand All @@ -106,6 +110,7 @@ export class IndexPatternManagementService {
creation: this.indexPatternCreationManager.start(),
list: this.indexPatternListConfig.start(),
fieldFormatEditors: this.fieldFormatEditors.start(),
columns: this.columnService.start(),
};
}

Expand Down
14 changes: 14 additions & 0 deletions src/plugins/index_pattern_management/public/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import {
SavedObjectReference,
} from 'src/core/public';
import { DataPublicPluginStart } from 'src/plugins/data/public';
import { EuiTableFieldDataColumnType } from '@elastic/eui';
import { ManagementAppMountParams } from '../../management/public';
import { IndexPatternManagementStart } from './index';
import { OpenSearchDashboardsReactContextValue } from '../../opensearch_dashboards_react/public';
Expand Down Expand Up @@ -71,3 +72,16 @@ export enum MlCardState {
}

export type DataSourceRef = { title: string } & Pick<SavedObjectReference, 'type' | 'id'>;

export interface IndexPatternTableRecord {
type: string;
id: string;
referenceId?: string;
}

export interface IndexPatternTableColumn<T> {
id: string;
euiColumn: Omit<EuiTableFieldDataColumnType<IndexPatternTableRecord>, 'sortable'>;
data?: T;
loadData: () => Promise<T>;
}

0 comments on commit b49c6e0

Please sign in to comment.