Skip to content

Commit

Permalink
Merge branch '2.x' into backport/backport-6385-to-2.x
Browse files Browse the repository at this point in the history
  • Loading branch information
ZilongX committed Apr 18, 2024
2 parents 087dd16 + b79135f commit ef9c3c0
Show file tree
Hide file tree
Showing 65 changed files with 3,385 additions and 58 deletions.
2 changes: 2 additions & 0 deletions changelogs/fragments/6477.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
refactor:
- Refactor dev tool to use dataSourceManagement.ui API to get DataSourceSelector ([#6477](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6477))
4 changes: 3 additions & 1 deletion src/core/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ export type { Logos } from '../common';
export { PackageInfo, EnvironmentMode } from '../server/types';
/** @interal */
export { CoreContext, CoreSystem } from './core_system';
export { DEFAULT_APP_CATEGORIES, WORKSPACE_TYPE } from '../utils';
export { DEFAULT_APP_CATEGORIES, WORKSPACE_TYPE, cleanWorkspaceId } from '../utils';
export {
AppCategory,
UiSettingsParams,
Expand Down Expand Up @@ -358,3 +358,5 @@ export {
export { __osdBootstrap__ } from './osd_bootstrap';

export { WorkspacesStart, WorkspacesSetup, WorkspacesService, WorkspaceObject } from './workspace';

export { debounce } from './utils';
55 changes: 55 additions & 0 deletions src/core/public/utils/debounce.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/
import { debounce } from './debounce';

describe('debounce', () => {
let fn: Function;
beforeEach(() => {
fn = jest.fn();
jest.useFakeTimers();
});
afterEach(() => {
jest.clearAllTimers();
});

test('it should call the debounced fn once at the end of the quiet time', () => {
const debounced = debounce(fn, 1000);

for (let i = 0; i < 100; i++) {
debounced(i);
}

jest.advanceTimersByTime(1001);
expect(fn).toBeCalledTimes(1);
expect(fn).toBeCalledWith(99);
});

test("with a leading invocation, it should call the debounced fn once, if the time doens't pass", () => {
const debounced = debounce(fn, 1000, true);

for (let i = 0; i < 100; i++) {
debounced(i);
}

jest.advanceTimersByTime(999);

expect(fn).toBeCalledTimes(1);
expect(fn).toBeCalledWith(0);
});

test('with a leading invocation, it should call the debounced fn twice (at the beginning and at the end)', () => {
const debounced = debounce(fn, 1000, true);

for (let i = 0; i < 100; i++) {
debounced(i);
}

jest.advanceTimersByTime(1500);

expect(fn).toBeCalledTimes(2);
expect(fn).toBeCalledWith(0);
expect(fn).toBeCalledWith(99);
});
});
23 changes: 23 additions & 0 deletions src/core/public/utils/debounce.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

/**
* @param func The function to be debounced.
* @param delay The time in milliseconds to wait before invoking the function again after the last invocation.
* @param leading An optional parameter that, when true, allows the function to be invoked immediately upon the first call.
*/
export const debounce = (func: Function, delay: number, leading?: boolean) => {
let timerId: NodeJS.Timeout;

return (...args: any) => {
if (!timerId && leading) {
func(...args);
}
clearTimeout(timerId);

timerId = setTimeout(() => func(...args), delay);
};
};
1 change: 1 addition & 0 deletions src/core/public/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,4 @@ export {
getWorkspaceIdFromUrl,
cleanWorkspaceId,
} from '../../utils';
export { debounce } from './debounce';
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.dataSourceComponentButtonTitle {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
width: auto;
max-width: 16ch;
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { SavedObjectsClientContract, ToastsStart } from 'opensearch-dashboards/p
import { getDataSourcesWithFields, handleDataSourceFetchError } from '../utils';
import { SavedObject } from '../../../../../core/public';
import { DataSourceAttributes } from '../../types';
import { NoDataSource } from '../no_data_source';
import { DataSourceErrorMenu } from '../data_source_error_menu';
import { DataSourceBaseState } from '../data_source_menu/types';

Expand Down Expand Up @@ -46,6 +47,7 @@ export class DataSourceAggregatedView extends React.Component<
this.state = {
isPopoverOpen: false,
allDataSourcesIdToTitleMap: new Map(),
showEmptyState: false,
showError: false,
};
}
Expand Down Expand Up @@ -73,7 +75,6 @@ export class DataSourceAggregatedView extends React.Component<
this.props.dataSourceFilter!(ds)
);
}

const allDataSourcesIdToTitleMap = new Map();

filteredDataSources.forEach((ds) => {
Expand Down Expand Up @@ -101,6 +102,9 @@ export class DataSourceAggregatedView extends React.Component<
}

render() {
if (this.state.showEmptyState) {
return <NoDataSource />;
}
if (this.state.showError) {
return <DataSourceErrorMenu />;
}
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 @@ -20,6 +20,7 @@ import { DataSourceSelectable } from '../data_source_selectable';

export function DataSourceMenu<T>(props: DataSourceMenuProps<T>): ReactElement | null {
const { componentType, componentConfig, uiSettings, hideLocalCluster, application } = props;

function renderDataSourceView(config: DataSourceViewConfig): ReactElement | null {
const {
activeOption,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export interface DataSourceBaseConfig {
}

export interface DataSourceBaseState {
showEmptyState: boolean;
showError: boolean;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import React from 'react';
import { SavedObjectsClientContract, ToastsStart } from 'opensearch-dashboards/public';
import { IUiSettingsClient } from 'src/core/public';
import { DataSourceFilterGroup, SelectedDataSourceOption } from './data_source_filter_group';
import { NoDataSource } from '../no_data_source';
import { getDataSourcesWithFields, handleDataSourceFetchError } from '../utils';
import { DataSourceBaseState } from '../data_source_menu/types';
import { DataSourceErrorMenu } from '../data_source_error_menu';
Expand Down Expand Up @@ -39,6 +40,7 @@ export class DataSourceMultiSelectable extends React.Component<
dataSourceOptions: [],
selectedOptions: [],
defaultDataSource: null,
showEmptyState: false,
showError: false,
};
}
Expand Down Expand Up @@ -82,6 +84,7 @@ export class DataSourceMultiSelectable extends React.Component<
...this.state,
selectedOptions,
defaultDataSource,
showEmptyState: (fetchedDataSources?.length === 0 && this.props.hideLocalCluster) || false,
});

this.props.onSelectedDataSources(selectedOptions);
Expand All @@ -107,6 +110,9 @@ export class DataSourceMultiSelectable extends React.Component<
}

render() {
if (this.state.showEmptyState) {
return <NoDataSource />;
}
if (this.state.showError) {
return <DataSourceErrorMenu />;
}
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 @@ -139,6 +139,7 @@ describe('DataSourceSelectable', () => {
],
defaultDataSource: null,
isPopoverOpen: false,
showEmptyState: false,
selectedOption: [
{
id: 'test2',
Expand All @@ -159,6 +160,7 @@ describe('DataSourceSelectable', () => {
],
defaultDataSource: null,
isPopoverOpen: false,
showEmptyState: false,
selectedOption: [
{
checked: 'on',
Expand Down Expand Up @@ -337,6 +339,7 @@ describe('DataSourceSelectable', () => {
],
defaultDataSource: null,
isPopoverOpen: false,
showEmptyState: false,
selectedOption: [
{
id: 'test2',
Expand Down Expand Up @@ -371,6 +374,7 @@ describe('DataSourceSelectable', () => {
defaultDataSource: null,
isPopoverOpen: false,
selectedOption: [],
showEmptyState: false,
showError: true,
});

Expand All @@ -385,6 +389,7 @@ describe('DataSourceSelectable', () => {
],
defaultDataSource: null,
isPopoverOpen: false,
showEmptyState: false,
selectedOption: [
{
checked: 'on',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,11 @@ import {
} from '../data_source_menu/types';
import { DataSourceErrorMenu } from '../data_source_error_menu';
import { DataSourceItem } from '../data_source_item';
import { NoDataSource } from '../no_data_source';
import './data_source_selectable.scss';
import { DataSourceDropDownHeader } from '../drop_down_header';
import '../button_title.scss';
import './data_source_selectable.scss';

interface DataSourceSelectableProps {
savedObjectsClient: SavedObjectsClientContract;
Expand Down Expand Up @@ -80,6 +83,7 @@ export class DataSourceSelectable extends React.Component<
isPopoverOpen: false,
selectedOption: [],
defaultDataSource: null,
showEmptyState: false,
showError: false,
};

Expand Down Expand Up @@ -185,6 +189,10 @@ export class DataSourceSelectable extends React.Component<
this.props.dataSourceFilter
);

if (dataSourceOptions.length === 0 && this.props.hideLocalCluster) {
this.setState({ showEmptyState: true });
}

if (!this.props.hideLocalCluster) {
dataSourceOptions.unshift(LocalCluster);
}
Expand Down Expand Up @@ -242,13 +250,16 @@ export class DataSourceSelectable extends React.Component<
};

render() {
if (this.state.showEmptyState) {
return <NoDataSource />;
}
if (this.state.showError) {
return <DataSourceErrorMenu />;
}
const button = (
<>
<EuiButtonEmpty
className="euiHeaderLink"
className={'euiHeaderLink dataSourceComponentButtonTitle'}
onClick={this.onClick.bind(this)}
data-test-subj="dataSourceSelectableContextMenuHeaderLink"
aria-label={i18n.translate('dataSourceSelectable.dataSourceOptionsButtonAriaLabel', {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
handleNoAvailableDataSourceError,
} from '../utils';
import { LocalCluster } from '../constants';
import { NoDataSource } from '../no_data_source';

interface DataSourceViewProps {
fullWidth: boolean;
Expand All @@ -43,6 +44,7 @@ export class DataSourceView extends React.Component<DataSourceViewProps, DataSou
this.state = {
isPopoverOpen: false,
selectedOption: this.props.selectedOption ? this.props.selectedOption : [],
showEmptyState: !this.props.selectedOption?.length && this.props.hideLocalCluster,
showError: false,
};
}
Expand Down Expand Up @@ -138,6 +140,9 @@ export class DataSourceView extends React.Component<DataSourceViewProps, DataSou
}

render() {
if (this.state.showEmptyState) {
return <NoDataSource />;
}
if (this.state.showError) {
return <DataSourceErrorMenu />;
}
Expand Down

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

Loading

0 comments on commit ef9c3c0

Please sign in to comment.