Submit
Path:
~
/
/
usr
/
share
/
grafana
/
public
/
app
/
features
/
transformers
/
editors
/
File Content:
OrganizeFieldsTransformerEditor.tsx
import { css } from '@emotion/css'; import React, { useCallback, useMemo } from 'react'; import { DragDropContext, Draggable, Droppable, DropResult } from 'react-beautiful-dnd'; import { DataTransformerID, GrafanaTheme2, standardTransformers, TransformerRegistryItem, TransformerUIProps, TransformerCategory, } from '@grafana/data'; import { createOrderFieldsComparer } from '@grafana/data/src/transformations/transformers/order'; import { OrganizeFieldsTransformerOptions } from '@grafana/data/src/transformations/transformers/organize'; import { Input, IconButton, Icon, FieldValidationMessage, useStyles2 } from '@grafana/ui'; import { getTransformationContent } from '../docs/getTransformationContent'; import { useAllFieldNamesFromDataFrames } from '../utils'; interface OrganizeFieldsTransformerEditorProps extends TransformerUIProps<OrganizeFieldsTransformerOptions> {} const OrganizeFieldsTransformerEditor = ({ options, input, onChange }: OrganizeFieldsTransformerEditorProps) => { const { indexByName, excludeByName, renameByName, includeByName } = options; const fieldNames = useAllFieldNamesFromDataFrames(input); const orderedFieldNames = useMemo(() => orderFieldNamesByIndex(fieldNames, indexByName), [fieldNames, indexByName]); const filterType = includeByName && Object.keys(includeByName).length > 0 ? 'include' : 'exclude'; const onToggleVisibility = useCallback( (field: string, shouldExclude: boolean) => { onChange({ ...options, excludeByName: { ...excludeByName, [field]: shouldExclude, }, }); }, [onChange, options, excludeByName] ); const onToggleVisibilityInclude = useCallback( (field: string, shouldInclude: boolean) => { const pendingState = { ...options, includeByName: { ...includeByName, [field]: !shouldInclude, }, }; onChange(pendingState); }, [onChange, options, includeByName] ); const onDragEnd = useCallback( (result: DropResult) => { if (!result || !result.destination) { return; } const startIndex = result.source.index; const endIndex = result.destination.index; if (startIndex === endIndex) { return; } onChange({ ...options, indexByName: reorderToIndex(fieldNames, startIndex, endIndex), }); }, [onChange, options, fieldNames] ); const onRenameField = useCallback( (from: string, to: string) => { onChange({ ...options, renameByName: { ...options.renameByName, [from]: to, }, }); }, [onChange, options] ); // Show warning that we only apply the first frame if (input.length > 1) { return ( <FieldValidationMessage> Organize fields only works with a single frame. Consider applying a join transformation or filtering the input first. </FieldValidationMessage> ); } return ( <DragDropContext onDragEnd={onDragEnd}> <Droppable droppableId="sortable-fields-transformer" direction="vertical"> {(provided) => ( <div ref={provided.innerRef} {...provided.droppableProps}> {orderedFieldNames.map((fieldName, index) => { const isIncludeFilter = includeByName && fieldName in includeByName ? includeByName[fieldName] : false; const isVisible = filterType === 'include' ? isIncludeFilter : !excludeByName[fieldName]; const onToggleFunction = filterType === 'include' ? onToggleVisibilityInclude : onToggleVisibility; return ( <DraggableFieldName fieldName={fieldName} renamedFieldName={renameByName[fieldName]} index={index} onToggleVisibility={onToggleFunction} onRenameField={onRenameField} visible={isVisible} key={fieldName} /> ); })} {provided.placeholder} </div> )} </Droppable> </DragDropContext> ); }; OrganizeFieldsTransformerEditor.displayName = 'OrganizeFieldsTransformerEditor'; interface DraggableFieldProps { fieldName: string; renamedFieldName?: string; index: number; visible: boolean; onToggleVisibility: (fieldName: string, isVisible: boolean) => void; onRenameField: (from: string, to: string) => void; } const DraggableFieldName = ({ fieldName, renamedFieldName, index, visible, onToggleVisibility, onRenameField, }: DraggableFieldProps) => { const styles = useStyles2(getFieldNameStyles); return ( <Draggable draggableId={fieldName} index={index}> {(provided) => ( <div className="gf-form-inline" ref={provided.innerRef} {...provided.draggableProps}> <div className="gf-form gf-form--grow"> <div className="gf-form-label gf-form-label--justify-left width-30"> <span {...provided.dragHandleProps}> <Icon name="draggabledots" title="Drag and drop to reorder" size="lg" className={styles.draggable} /> </span> <IconButton className={styles.toggle} size="md" name={visible ? 'eye' : 'eye-slash'} onClick={() => onToggleVisibility(fieldName, visible)} tooltip={visible ? 'Disable' : 'Enable'} /> <span className={styles.name} title={fieldName}> {fieldName} </span> </div> <Input className="flex-grow-1" defaultValue={renamedFieldName || ''} placeholder={`Rename ${fieldName}`} onBlur={(event) => onRenameField(fieldName, event.currentTarget.value)} /> </div> </div> )} </Draggable> ); }; DraggableFieldName.displayName = 'DraggableFieldName'; const getFieldNameStyles = (theme: GrafanaTheme2) => ({ toggle: css` margin: 0 8px; color: ${theme.colors.text.secondary}; `, draggable: css` opacity: 0.4; &:hover { color: ${theme.colors.text.maxContrast}; } `, name: css` overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: ${theme.typography.bodySmall.fontSize}; font-weight: ${theme.typography.fontWeightMedium}; `, }); const reorderToIndex = (fieldNames: string[], startIndex: number, endIndex: number) => { const result = Array.from(fieldNames); const [removed] = result.splice(startIndex, 1); result.splice(endIndex, 0, removed); return result.reduce<Record<string, number>>((nameByIndex, fieldName, index) => { nameByIndex[fieldName] = index; return nameByIndex; }, {}); }; const orderFieldNamesByIndex = (fieldNames: string[], indexByName: Record<string, number> = {}): string[] => { if (!indexByName || Object.keys(indexByName).length === 0) { return fieldNames; } const comparer = createOrderFieldsComparer(indexByName); return fieldNames.sort(comparer); }; export const organizeFieldsTransformRegistryItem: TransformerRegistryItem<OrganizeFieldsTransformerOptions> = { id: DataTransformerID.organize, editor: OrganizeFieldsTransformerEditor, transformation: standardTransformers.organizeFieldsTransformer, name: standardTransformers.organizeFieldsTransformer.name, description: "Allows the user to re-order, hide, or rename fields / columns. Useful when data source doesn't allow overrides for visualizing data.", categories: new Set([TransformerCategory.ReorderAndRename]), help: getTransformationContent(DataTransformerID.organize).helperDocs, };
Edit
Rename
Chmod
Delete
FILE
FOLDER
INFO
Name
Size
Permission
Action
CalculateFieldTransformerEditor
---
0755
ConcatenateTransformerEditor.tsx
3017 bytes
0644
ConvertFieldTypeTransformerEditor.tsx
8038 bytes
0644
EnumMappingEditor.tsx
5939 bytes
0644
EnumMappingRow.tsx
4111 bytes
0644
FilterByNameTransformerEditor.tsx
7668 bytes
0644
FilterByRefIdTransformerEditor.tsx
4453 bytes
0644
FormatStringTransformerEditor.tsx
3574 bytes
0644
FormatTimeTransformerEditor.tsx
3406 bytes
0644
GroupByTransformerEditor.tsx
4547 bytes
0644
GroupToNestedTableTransformerEditor.tsx
5589 bytes
0644
GroupingToMatrixTransformerEditor.tsx
3322 bytes
0644
HistogramTransformerEditor.tsx
7595 bytes
0644
JoinByFieldTransformerEditor.tsx
3056 bytes
0644
LabelsToFieldsTransformerEditor.tsx
4372 bytes
0644
LimitTransformerEditor.tsx
2766 bytes
0644
MergeTransformerEditor.tsx
1392 bytes
0644
OrganizeFieldsTransformerEditor.tsx
7743 bytes
0644
ReduceTransformerEditor.tsx
3650 bytes
0644
RenameByRegexTransformer.tsx
3659 bytes
0644
SeriesToRowsTransformerEditor.tsx
1156 bytes
0644
SortByTransformerEditor.tsx
2652 bytes
0644
N4ST4R_ID | Naxtarrr