briangann/grafana-datatable-panel

View on GitHub
src/components/options/ColumnWidthHintsEditor.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 { ColumnWidthHint } from 'types';

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

  function handleNewColumnWidth() {
    onChange([...value, { name: '', width: '' }]);
  }

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

  function handleSelectChange(event: SelectableValue, selectIndex: number) {
    const newWidths = value.map((item: ColumnWidthHint, index: number) => {
      if (index === selectIndex) {
        return { name: event.value, width: item.width };
      }
      return item;
    });
    onChange(newWidths);
  }

  function handleWidthChange(event: FormEvent<HTMLInputElement>, selectIndex: number) {
    const target = event.target as HTMLInputElement;
    const newWidths = value.map((item: ColumnWidthHint, index: number) => {
      if (index === selectIndex) {
        return { name: item.name, width: target.value };
      }
      return item;
    });
    onChange(newWidths);
  }

  const currentWidths = value.map((item: ColumnWidthHint, index: number) => {
    const options = item.name === '' ? availableFields : [...availableFields, { value: item.name, label: item.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" tooltip="The column to apply width hints to">
            <Select
              // TODO: We don't want this width here. it should be somehow auto
              width={15}
              options={options}
              aria-label={`Current selected column ${item.name}`}
              value={item.name || ''}
              onChange={(event) => handleSelectChange(event, index)}
            />
          </InlineField>
          <InlineField label="Width" tooltip="The width hint to apply. (add % or px)">
            <Input
              value={item.width || ''}
              onChange={(event) => {
                handleWidthChange(event, index);
              }}
            />
          </InlineField>
          <IconButton name="trash-alt" aria-label="Remove column" onClick={() => handleRemoveColumnWidth(index)} />
        </Stack>
      </div>
    );
  });

  return (
    <div>
      {currentWidths}
      <Box marginTop={1}>
        <Button variant="secondary" icon="plus" onClick={handleNewColumnWidth}>
          Add Column Width
        </Button>
      </Box>
    </div>
  );
}