export default function DataSourcePanel()

in superset-frontend/src/explore/components/DatasourcePanel/index.tsx [138:342]


export default function DataSourcePanel({
  datasource,
  formData,
  controls: { datasource: datasourceControl },
  actions,
  width,
}: Props) {
  const [dropzones] = useContext(DropzoneContext);
  const { columns: _columns, metrics, folders: _folders } = datasource;

  const allowedColumns = useMemo(() => {
    const validators = Object.values(dropzones);
    if (!Array.isArray(_columns)) return [];
    return _columns.filter(column =>
      validators.some(validator =>
        validator({
          value: column as DndItemValue,
          type: DndItemType.Column,
        }),
      ),
    );
  }, [dropzones, _columns]);

  const allowedMetrics = useMemo(() => {
    const validators = Object.values(dropzones);
    return metrics.filter(metric =>
      validators.some(validator =>
        validator({ value: metric, type: DndItemType.Metric }),
      ),
    );
  }, [dropzones, metrics]);

  const [showSaveDatasetModal, setShowSaveDatasetModal] = useState(false);
  const [inputValue, setInputValue] = useState('');
  const searchKeyword = useDebounceValue(inputValue, FAST_DEBOUNCE);

  const filteredColumns = useMemo(() => {
    if (!searchKeyword) {
      return allowedColumns ?? [];
    }
    return matchSorter(allowedColumns, searchKeyword, {
      keys: [
        {
          key: 'verbose_name',
          threshold: rankings.CONTAINS,
        },
        {
          key: 'column_name',
          threshold: rankings.CONTAINS,
        },
        {
          key: item =>
            [item?.description ?? '', item?.expression ?? ''].map(
              x => x?.replace(/[_\n\s]+/g, ' ') || '',
            ),
          threshold: rankings.CONTAINS,
          maxRanking: rankings.CONTAINS,
        },
      ],
      keepDiacritics: true,
    });
  }, [allowedColumns, searchKeyword]);

  const filteredMetrics = useMemo(() => {
    if (!searchKeyword) {
      return allowedMetrics ?? [];
    }
    return matchSorter(allowedMetrics, searchKeyword, {
      keys: [
        {
          key: 'verbose_name',
          threshold: rankings.CONTAINS,
        },
        {
          key: 'metric_name',
          threshold: rankings.CONTAINS,
        },
        {
          key: item =>
            [item?.description ?? '', item?.expression ?? ''].map(
              x => x?.replace(/[_\n\s]+/g, ' ') || '',
            ),
          threshold: rankings.CONTAINS,
          maxRanking: rankings.CONTAINS,
        },
      ],
      keepDiacritics: true,
      baseSort: (a, b) =>
        Number(b?.item?.is_certified ?? 0) -
          Number(a?.item?.is_certified ?? 0) ||
        String(a?.rankedValue ?? '').localeCompare(b?.rankedValue ?? ''),
    });
  }, [allowedMetrics, searchKeyword]);

  const sortedColumns = useMemo(
    () => sortColumns(filteredColumns),
    [filteredColumns],
  );

  const folders = useMemo(
    () =>
      transformDatasourceWithFolders(
        filteredMetrics,
        sortedColumns,
        _folders,
        allowedMetrics,
        allowedColumns,
      ),
    [_folders, filteredMetrics, sortedColumns],
  );

  const showInfoboxCheck = () => {
    try {
      if (sessionStorage.getItem('showInfobox') === 'false') return false;
    } catch (error) {
      // continue regardless of error
    }
    return true;
  };

  const saveableDatasets = {
    query: DatasourceType.Query,
    saved_query: DatasourceType.SavedQuery,
  };

  const datasourceIsSaveable =
    datasource.type &&
    saveableDatasets[datasource.type as keyof typeof saveableDatasets];

  const mainBody = useMemo(
    () => (
      <>
        <Input
          allowClear
          onChange={evt => {
            setInputValue(evt.target.value);
          }}
          value={inputValue}
          className="form-control input-md"
          placeholder={t('Search Metrics & Columns')}
        />
        <div className="field-selections" data-test="fieldSelections">
          {datasourceIsSaveable && showInfoboxCheck() && (
            <StyledInfoboxWrapper>
              <Alert
                closable
                onClose={() => {
                  try {
                    sessionStorage.setItem('showInfobox', 'false');
                  } catch (error) {
                    // continue regardless of error
                  }
                }}
                type="info"
                message=""
                description={
                  <>
                    <span
                      role="button"
                      tabIndex={0}
                      onClick={() => setShowSaveDatasetModal(true)}
                      className="add-dataset-alert-description"
                    >
                      {t('Create a dataset')}
                    </span>
                    {t(' to edit or add columns and metrics.')}
                  </>
                }
              />
            </StyledInfoboxWrapper>
          )}
          <AutoSizer>
            {({ height }: { height: number }) => (
              <DatasourceItems
                width={width - BORDER_WIDTH}
                height={height}
                folders={folders}
              />
            )}
          </AutoSizer>
        </div>
      </>
    ),
    [inputValue, datasourceIsSaveable, width, folders],
  );

  return (
    <DatasourceContainer>
      {datasourceIsSaveable && showSaveDatasetModal && (
        <SaveDatasetModal
          visible={showSaveDatasetModal}
          onHide={() => setShowSaveDatasetModal(false)}
          buttonTextOnSave={t('Save')}
          buttonTextOnOverwrite={t('Overwrite')}
          datasource={getDatasourceAsSaveableDataset(datasource)}
          openWindow={false}
          formData={formData}
        />
      )}
      {/* @ts-ignore */}
      <Control {...datasourceControl} name="datasource" actions={actions} />
      {datasource.id != null && mainBody}
    </DatasourceContainer>
  );
}