briangann/grafana-datatable-panel

View on GitHub
src/components/options/ColumnAliasesEditor.tsx

Summary

Maintainability
D
2 days
Test Coverage
F
0%
import { SelectableValue, StandardEditorProps } from '@grafana/data';
import { Box, Button, IconButton, InlineField, Input, Select, Stack } from '@grafana/ui';
import React, { FormEvent } from 'react';
import { getDataFramesFields } from 'transformations';
import { ColumnAliasField } from 'types';

export function ColumnAliasesEditor(props: StandardEditorProps<ColumnAliasField[]>) {
  const { onChange, value = [] } = props;
  const dataFields = getDataFramesFields(props.context.data);
  const availableFields = dataFields.reduce<SelectableValue[]>((acc, field) => {
    // Filter out fields that already have an alias
    if (value.find((alias) => alias.name === field)) {
      return acc;
    }
    acc.push({ value: field, label: field });
    return acc;
  }, []);

  function handleNewColumnAlias() {
    onChange([...value, { name: '', alias: '' }]);
  }

  function handleRemoveColumnAlias(index: number) {
    onChange([...value.slice(0, index), ...value.slice(index + 1)]);
  }

  function handleSelectChange(event: SelectableValue, selectIndex: number) {
    const newAliases = value.map((alias: ColumnAliasField, index: number) => {
      if (index === selectIndex) {
        return { name: event.value, alias: alias.alias };
      }
      return alias;
    });
    onChange(newAliases);
  }

  function handleAliasChange(event: FormEvent<HTMLInputElement>, selectIndex: number) {
    const target = event.target as HTMLInputElement;
    const newAliases = value.map((alias: ColumnAliasField, index: number) => {
      if (index === selectIndex) {
        return { name: alias.name, alias: target.value };
      }
      return alias;
    });
    onChange(newAliases);
  }

  const currentAliases = value.map((alias: ColumnAliasField, index: number) => {
    const options =
      alias.name === '' ? availableFields : [...availableFields, { value: alias.name, label: alias.name }];
    // TODO: fix the styling so all fields align. Currently
    return (
      <div key={index} style={{ width: '100%' }}>
        <Stack justifyContent="start" direction="row" alignItems="start">
          <InlineField label="Column">
            <Select
              // TODO: We don't want this width here. it should be somehow auto
              width={15}
              options={options}
              aria-label={`Current selected column ${alias.name}`}
              value={alias.name || ''}
              onChange={(event) => handleSelectChange(event, index)}
            />
          </InlineField>
          <InlineField label="Alias">
            <Input
              value={alias.alias || ''}
              onChange={(event) => {
                handleAliasChange(event, index);
              }}
            />
          </InlineField>
          <IconButton name="trash-alt" aria-label="Remove column" onClick={() => handleRemoveColumnAlias(index)} />
        </Stack>
      </div>
    );
  });

  return (
    <div>
      {currentAliases}
      <Box marginTop={1}>
        <Button variant="secondary" icon="plus" onClick={handleNewColumnAlias}>
          Add Column Alias
        </Button>
      </Box>
    </div>
  );
}