import { css } from '@emotion/css'; import { once } from 'lodash'; import React, { useState } from 'react'; import { DropzoneOptions } from 'react-dropzone'; import { DataSourceInstanceSettings, DataSourceRef, GrafanaTheme2 } from '@grafana/data'; import { reportInteraction } from '@grafana/runtime'; import { Modal, FileDropzone, FileDropzoneDefaultChildren, CustomScrollbar, useStyles2, Input, Icon, } from '@grafana/ui'; import * as DFImport from 'app/features/dataframe-import'; import { AddNewDataSourceButton } from './AddNewDataSourceButton'; import { DataSourceList } from './DataSourceList'; import { matchDataSourceWithSearch } from './utils'; const INTERACTION_EVENT_NAME = 'dashboards_dspickermodal_clicked'; const INTERACTION_ITEM = { SELECT_DS: 'select_ds', UPLOAD_FILE: 'upload_file', CONFIG_NEW_DS: 'config_new_ds', CONFIG_NEW_DS_EMPTY_STATE: 'config_new_ds_empty_state', SEARCH: 'search', DISMISS: 'dismiss', }; interface DataSourceModalProps { onChange: (ds: DataSourceInstanceSettings) => void; current: DataSourceRef | string | null | undefined; onDismiss: () => void; recentlyUsed?: string[]; enableFileUpload?: boolean; fileUploadOptions?: DropzoneOptions; reportedInteractionFrom?: string; } export function DataSourceModal({ enableFileUpload, fileUploadOptions, onChange, current, onDismiss, reportedInteractionFrom, }: DataSourceModalProps) { const styles = useStyles2(getDataSourceModalStyles); const [search, setSearch] = useState(''); const analyticsInteractionSrc = reportedInteractionFrom || 'modal'; const onDismissModal = () => { onDismiss(); reportInteraction(INTERACTION_EVENT_NAME, { item: INTERACTION_ITEM.DISMISS, src: analyticsInteractionSrc }); }; const onChangeDataSource = (ds: DataSourceInstanceSettings) => { onChange(ds); reportInteraction(INTERACTION_EVENT_NAME, { item: INTERACTION_ITEM.SELECT_DS, ds_type: ds.type, src: analyticsInteractionSrc, }); }; // Memoizing to keep once() cached so it avoids reporting multiple times const reportSearchUsageOnce = React.useMemo( () => once(() => { reportInteraction(INTERACTION_EVENT_NAME, { item: 'search', src: analyticsInteractionSrc }); }), [analyticsInteractionSrc] ); return (
} placeholder="Search data source" onChange={(e) => { setSearch(e.currentTarget.value); reportSearchUsageOnce(); }} /> matchDataSourceWithSearch(ds, search) && !ds.meta.builtIn} onChange={onChangeDataSource} current={current} onClickEmptyStateCTA={() => reportInteraction(INTERACTION_EVENT_NAME, { item: INTERACTION_ITEM.CONFIG_NEW_DS_EMPTY_STATE, src: analyticsInteractionSrc, }) } />
!!ds.meta.builtIn} dashboard mixed onChange={onChangeDataSource} current={current} /> {enableFileUpload && ( undefined} options={{ maxSize: DFImport.maxFileSize, multiple: false, accept: DFImport.acceptedFiles, ...fileUploadOptions, onDrop: (...args) => { fileUploadOptions?.onDrop?.(...args); onDismiss(); reportInteraction(INTERACTION_EVENT_NAME, { item: INTERACTION_ITEM.UPLOAD_FILE, src: analyticsInteractionSrc, }); }, }} > )}
{ reportInteraction(INTERACTION_EVENT_NAME, { item: INTERACTION_ITEM.CONFIG_NEW_DS, src: analyticsInteractionSrc, }); }} />
); } function getDataSourceModalStyles(theme: GrafanaTheme2) { return { modal: css` width: 80%; height: 80%; max-width: 1200px; max-height: 900px; `, modalContent: css` display: flex; flex-direction: row; height: 100%; `, leftColumn: css` display: flex; flex-direction: column; width: 50%; height: 100%; padding-right: ${theme.spacing(4)}; border-right: 1px solid ${theme.colors.border.weak}; `, rightColumn: css` display: flex; flex-direction: column; width: 50%; height: 100%; justify-items: space-evenly; align-items: stretch; padding-left: ${theme.spacing(4)}; `, builtInDataSources: css` flex: 1; margin-bottom: ${theme.spacing(4)}; `, dataSourceList: css` height: 100%; `, builtInDataSourceList: css` margin-bottom: ${theme.spacing(4)}; `, dsCTAs: css` display: flex; flex-direction: row; width: 100%; justify-content: flex-end; `, searchInput: css` width: 100%; min-height: 32px; margin-bottom: ${theme.spacing(1)}; `, }; }