Skip to content

Commit

Permalink
Refactor association modal
Browse files Browse the repository at this point in the history
Signed-off-by: Kapian1234 <[email protected]>
  • Loading branch information
Kapian1234 committed Aug 27, 2024
1 parent 0ef40b6 commit 810651c
Showing 1 changed file with 175 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* SPDX-License-Identifier: Apache-2.0
*/

import { Fragment, useEffect, useMemo, useState } from 'react';
import { Fragment, useEffect, useMemo, useState, useCallback } from 'react';
import React from 'react';
import {
EuiText,
Expand All @@ -15,17 +15,43 @@ import {
EuiModalHeader,
EuiModalHeaderTitle,
EuiSelectableOption,
EuiSpacer,
EuiButtonGroup,
EuiButtonGroupOptionProps,
EuiBadge,
} from '@elastic/eui';
import { FormattedMessage } from 'react-intl';
import { i18n } from '@osd/i18n';
import { getDataSourcesList } from '../../utils';
import { DataSource } from '../../../common/types';
import { DataSourceConnection, DataSourceConnectionType } from '../../../common/types';
import { SavedObjectsStart } from '../../../../../core/public';

const tabOptions: EuiButtonGroupOptionProps[] = [
{
id: 'all',
label: i18n.translate('workspace.form.selectDataSource.subTitle', {
defaultMessage: 'All',
}),
},
{
id: 'opensearch-connections',
label: i18n.translate('workspace.form.selectDataSource.subTitle', {
defaultMessage: 'OpenSearch connections',
}),
},
{
id: 'direct-query-connections',
label: i18n.translate('workspace.form.selectDataSource.subTitle', {
defaultMessage: 'Direct query connections',
}),
},
];

export interface AssociationDataSourceModalProps {
savedObjects: SavedObjectsStart;
assignedDataSources: DataSource[];
assignedDataSources: DataSourceConnection[];
closeModal: () => void;
handleAssignDataSources: (dataSources: DataSource[]) => Promise<void>;
handleAssignDataSources: (dataSources: DataSourceConnection[]) => Promise<void>;
}

export const AssociationDataSourceModal = ({
Expand All @@ -34,60 +60,184 @@ export const AssociationDataSourceModal = ({
assignedDataSources,
handleAssignDataSources,
}: AssociationDataSourceModalProps) => {
const [options, setOptions] = useState<EuiSelectableOption[]>([]);
const [allDataSources, setAllDataSources] = useState<DataSource[]>([]);
// const [options, setOptions] = useState<Array<EuiSelectableOption<any>>>([]);
// const [allOptions, setAlloptions] = useState<EuiSelectableOption[]>([]);
const [allDataSources, setAllDataSources] = useState<DataSourceConnection[]>([]);
const [currentTab, setCurrentTab] = useState('all');
const [allOptions, setAllOptions] = useState<Array<EuiSelectableOption<any>>>([]);

useEffect(() => {
getDataSourcesList(savedObjects.client, ['*']).then((result) => {
const filteredDataSources = result.filter(
({ id }: DataSource) => !assignedDataSources.some((ds) => ds.id === id)
);
const filteredDataSources: DataSourceConnection[] = result
.filter(({ id }) => !assignedDataSources.some((ds) => ds.id === id))
.map((datasource) => {
return {
...datasource,
name: datasource.title,
type: datasource.dataSourceEngineType,
connectionType: DataSourceConnectionType.OpenSearchConnection,
};
});

// dqc
filteredDataSources.push({
name: 's3 connection1',
description: 'this is a s3',
id: filteredDataSources[0].id + '-' + 's3 connection1',
parentId: filteredDataSources[0].id,
type: 's3',
connectionType: DataSourceConnectionType.DirectQueryConnection,
});
filteredDataSources.push({
name: 's3 connection2',
description: 'this is a s3',
id: filteredDataSources[0].id + '-' + 's3 connection2',
parentId: filteredDataSources[0].id,
type: 's3',
connectionType: DataSourceConnectionType.DirectQueryConnection,
});
filteredDataSources[0].relatedConnections = [
filteredDataSources[filteredDataSources.length - 1],
filteredDataSources[filteredDataSources.length - 2],
];

setAllDataSources(filteredDataSources);
setOptions(
setAllOptions(
filteredDataSources.map((dataSource) => ({
label: dataSource.title,
...dataSource,
label: dataSource.name,
key: dataSource.id,
append: dataSource.relatedConnections ? (
<EuiBadge>
{i18n.translate('workspace.form.selectDataSource.optionBadge', {
defaultMessage: '+' + dataSource.relatedConnections.length + ' related',
})}
</EuiBadge>
) : undefined,
}))
);
});
}, [assignedDataSources, savedObjects]);

const selectedDataSources = useMemo(() => {
const selectedIds = options
const selectedIds = allOptions
.filter((option: EuiSelectableOption) => option.checked)
.map((option: EuiSelectableOption) => option.key);

return allDataSources.filter((ds) => selectedIds.includes(ds.id));
}, [options, allDataSources]);
}, [allOptions, allDataSources]);

const options = useMemo(() => {
if (currentTab === 'all') {
return allOptions;
}
if (currentTab === 'opensearch-connections') {
return allOptions.filter(
(dataSource) => dataSource.connectionType === DataSourceConnectionType.OpenSearchConnection
);
}
if (currentTab === 'direct-query-connections') {
return allOptions.filter(
(dataSource) => dataSource.connectionType === DataSourceConnectionType.DirectQueryConnection
);
}
}, [allOptions, currentTab]);

const handleSelectionChange = useCallback(
(newOptions: Array<EuiSelectableOption<any>>) => {
const newCheckedOptionIds = newOptions
.filter(({ checked }) => checked === 'on')
.map(({ value }) => value);

setAllOptions((prevOptions) => {
return prevOptions.map((option) => {
const checkedInNewOptions = newCheckedOptionIds.includes(option.value);
const connection = allDataSources.find(({ id }) => id === option.value);
option.checked = checkedInNewOptions ? 'on' : undefined;

if (!connection) {
return option;
}

if (connection.type === 'DS') {
const childDQCIds = allDataSources
.find(({ parentId }) => parentId === connection.id)
?.relatedConnections?.map(({ id }) => id);
// Check if there any DQC change to checked status this time, set to "on" if exists.
if (
newCheckedOptionIds.some(
(id) =>
childDQCIds.includes(id) &&
// This child DQC not checked before
!prevOptions.find(({ value, checked }) => value === id && checked === 'on')
)
) {
option.checked = 'on';
}
}

if (connection.type === 'DQC') {
const parentConnection = allDataSources.find(({ id }) => id === connection.id);
if (parentConnection) {
const isParentCheckedLastTime = prevOptions.find(
({ value, checked }) => value === parentConnection.id && checked === 'on'
);
const isParentCheckedThisTime = newCheckedOptionIds.includes(parentConnection.id);

// Parent change to checked this time
if (!isParentCheckedLastTime && isParentCheckedThisTime) {
option.checked = 'on';
}

if (isParentCheckedLastTime && isParentCheckedThisTime) {
option.checked = undefined;
}
}
}

return option;
});
});
},
[allDataSources]
);

return (
<EuiModal onClose={closeModal}>
<EuiModal onClose={closeModal} style={{ width: 900 }}>
<EuiModalHeader>
<EuiModalHeaderTitle>
<h1>
<FormattedMessage
id="workspace.detail.dataSources.associateModal.title"
defaultMessage="Associate OpenSearch connections"
/>
</h1>
<FormattedMessage
id="workspace.detail.dataSources.associateModal.title"
defaultMessage="Associate OpenSearch connections"
/>
</EuiModalHeaderTitle>
</EuiModalHeader>
<EuiModalBody>
<EuiText size="s" color="subdued">
<EuiText size="xs" color="subdued">
<FormattedMessage
id="workspace.detail.dataSources.associateModal.message"
defaultMessage="Add OpenSearch connections that will be available in the workspace."
/>
</EuiText>
<EuiSpacer />
<EuiButtonGroup
legend="Data source tab"
options={tabOptions}
idSelected={currentTab}
onChange={(id) => setCurrentTab(id)}
buttonSize="compressed"
// isFullWidth={true}
/>
<EuiSpacer size="s" />
<EuiSelectable
aria-label="Searchable"
searchable
listProps={{ bordered: true }}
listProps={{ bordered: true, onFocusBadge: false }}
searchProps={{
'data-test-subj': 'workspace-detail-dataSources-associateModal-search',
}}
options={options}
onChange={(newOptions) => setOptions(newOptions)}
onChange={handleSelectionChange}
>
{(list, search) => (
<Fragment>
Expand All @@ -99,7 +249,7 @@ export const AssociationDataSourceModal = ({
</EuiModalBody>

<EuiModalFooter>
<EuiButton onClick={closeModal} fill>
<EuiButton onClick={closeModal}>
<FormattedMessage
id="workspace.detail.dataSources.associateModal.close.button"
defaultMessage="Close"
Expand All @@ -112,7 +262,7 @@ export const AssociationDataSourceModal = ({
>
<FormattedMessage
id="workspace.detail.dataSources.associateModal.save.button"
defaultMessage="Save changes"
defaultMessage="Associate data sources"
/>
</EuiButton>
</EuiModalFooter>
Expand Down

0 comments on commit 810651c

Please sign in to comment.