Skip to content

Commit

Permalink
Add Drag & Drop Across Axis Functionality to Vis Builder (#7107) (#7266)
Browse files Browse the repository at this point in the history
* Add Drag Across Axis Functionality to Vis Builder



* Changeset file for PR #7107 created/updated

---------



(cherry picked from commit 27669cf)

Signed-off-by: Suchit Sahoo <[email protected]>
Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com>
  • Loading branch information
3 people committed Jul 22, 2024
1 parent d89447b commit b1e5237
Show file tree
Hide file tree
Showing 20 changed files with 855 additions and 186 deletions.
2 changes: 2 additions & 0 deletions changelogs/fragments/7107.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
feat:
- Enhance Drag & Drop functionality in Vis Builder ([#7107](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7107))
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,49 @@

import { EuiForm } from '@elastic/eui';
import React from 'react';
import { useVisualizationType } from '../../utils/use';
import { useTypedSelector } from '../../utils/state_management';

import './config_panel.scss';
import { mapSchemaToAggPanel } from './schema_to_dropbox';
import { SecondaryPanel } from './secondary_panel';
import { Schemas } from '../../../../../vis_default_editor/public';
import {
AggConfig,
AggConfigs,
CreateAggConfigParams,
} from '../../../../../data/common/search/aggs';
import { IndexPattern, TimeRange } from '../../../../../data/public';
import { SchemaDisplayStates } from '.';

export function ConfigPanel() {
const vizType = useVisualizationType();
const editingState = useTypedSelector(
(state) => state.visualization.activeVisualization?.draftAgg
);
const schemas = vizType.ui.containerConfig.data.schemas;
export interface AggProps {
indexPattern: IndexPattern | undefined;
aggConfigs: AggConfigs | undefined;
aggs: AggConfig[];
timeRange: TimeRange;
}

export interface ConfigPanelProps {
schemas: Schemas;
editingState?: CreateAggConfigParams;
aggProps: AggProps;
activeSchemaFields: SchemaDisplayStates;
setActiveSchemaFields: React.Dispatch<React.SetStateAction<SchemaDisplayStates>>;
}

export function ConfigPanel({
schemas,
editingState,
aggProps,
activeSchemaFields,
setActiveSchemaFields,
}: ConfigPanelProps) {
if (!schemas) return null;

const mainPanel = mapSchemaToAggPanel(schemas);
const mainPanel = mapSchemaToAggPanel(
schemas,
aggProps,
activeSchemaFields,
setActiveSchemaFields
);

return (
<EuiForm className={`vbConfig ${editingState ? 'showSecondary' : ''}`}>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

export enum FIELD_SELECTOR_ID {
COUNT = 'preDefinedCountMetric',
CATEGORICAL = 'categoricalFields',
NUMERICAL = 'numericalFields',
META = 'metaFields',
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { DropResult } from '@elastic/eui';
import { AnyAction } from 'redux';
import { createNewAggConfig } from '../utils/get_valid_aggregations';
import { updateAggConfigParams } from '../../../utils/state_management/visualization_slice';
import { Schemas } from '../../../../../../vis_default_editor/public';
import { AggProps } from '../config_panel';
import { SchemaDisplayStates } from '../index';
import { Dispatch } from '../../../../../../opensearch_dashboards_utils/common/state_containers/types';
import { AggsStart } from '../../../../../../data/common';

export interface DragDropProperties {
dropResult: DropResult;
schemas: Schemas;
aggProps: AggProps;
aggService: AggsStart;
activeSchemaFields: SchemaDisplayStates;
dispatch: Dispatch<AnyAction>;
}

export function addFieldToConfiguration({
dropResult,
schemas,
aggProps,
aggService,
activeSchemaFields,
dispatch,
}: DragDropProperties) {
const { source, destination, combine, draggableId } = dropResult;

const destinationSchemaName = destination?.droppableId;
const destinationSchema = schemas.all.find((schema) => schema.name === destinationSchemaName);

const newFieldToAdd = draggableId;

if (!destinationSchema || !destinationSchemaName) {
// Invalid drop target selected
return;
}

const destinationFields = activeSchemaFields[destinationSchemaName];

if (!combine && destination && destinationFields.length > destinationSchema?.max) {
// Can't Add additional Fields
return;
}

// Adding the new field
createNewAggConfig({
fieldName: newFieldToAdd,
sourceGroup: source.droppableId,
destinationSchema,
aggProps,
aggService,
sourceAgg: null,
});

const updatedAggConfigs = aggProps.aggConfigs?.aggs;

if (updatedAggConfigs) {
dispatch(updateAggConfigParams(updatedAggConfigs.map((agg) => agg.serialize())));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { updateAggConfigParams } from '../../../utils/state_management/visualization_slice';
import { createNewAggConfig } from '../utils/get_valid_aggregations';
import { DragDropProperties } from './add_field_to_configuration';

export function moveFieldBetweenSchemas({
dropResult,
schemas,
aggProps,
aggService,
activeSchemaFields,
dispatch,
}: DragDropProperties) {
const { source, destination, combine, draggableId } = dropResult;

const destinationSchemaName = destination?.droppableId;
if (!destinationSchemaName) {
// Invalid Transition
return;
}
const sourceAggId = draggableId;

const destinationSchema = schemas.all.find(
(schema) => schema.name === (destination?.droppableId || combine?.droppableId)
);

if (!destinationSchema) {
// Invalid Transition
return;
}

const sourceAgg = aggProps.aggConfigs?.aggs.find((agg) => agg.id === sourceAggId);
const sourceFieldName = sourceAgg?.fieldName();

const destinationAggFields = activeSchemaFields[destinationSchemaName];

const destinationLimit = destinationSchema?.max;

if (destinationLimit && destinationAggFields.length <= destinationLimit) {
// destination schema has space for more items to be added
// We Need to update sourceAgg

createNewAggConfig({
fieldName: sourceFieldName,
sourceGroup: source.droppableId,
destinationSchema,
aggProps,
aggService,
sourceAgg,
});

// Remove the sourceAggConfig from the updated Config
const updatedAggConfig = aggProps.aggConfigs?.aggs.filter((agg) => agg.id !== sourceAggId);

if (updatedAggConfig?.length) {
dispatch(updateAggConfigParams(updatedAggConfig.map((agg) => agg.serialize())));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { reorderAgg } from '../../../utils/state_management/visualization_slice';
import { DragDropProperties } from './add_field_to_configuration';

export function reorderFieldsWithinSchema({
dropResult,
schemas,
activeSchemaFields,
dispatch,
}: DragDropProperties) {
const { destination, draggableId } = dropResult;

const destinationSchemaName = destination?.droppableId;
if (!destinationSchemaName) {
// Invalid Transition
return;
}
const destinationAggFields = activeSchemaFields[destinationSchemaName];

const sourceAggId = draggableId;
const destinationAggId = destinationAggFields[destination?.index].id;

const destinationSchema = schemas.all.find((schema) => schema.name === destination?.droppableId);

if (!destinationSchema) {
// Invalid Transition
return;
}

dispatch(
reorderAgg({
sourceId: sourceAggId,
destinationId: destinationAggId,
})
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { updateAggConfigParams } from '../../../utils/state_management/visualization_slice';
import { FIELD_SELECTOR_ID } from '../constants';
import { createNewAggConfig } from '../utils/get_valid_aggregations';
import { DragDropProperties } from './add_field_to_configuration';

export function replaceFieldInConfiguration({
dropResult,
schemas,
aggProps,
aggService,
dispatch,
}: DragDropProperties) {
const { source, combine, draggableId } = dropResult;

const destinationSchemaName = combine?.droppableId;
if (!destinationSchemaName) {
return;
}

const sourceAggId = draggableId;
const destinationAggId = combine?.draggableId;

const destinationSchema = schemas.all.find((schema) => schema.name === combine?.droppableId);

if (!destinationSchema) {
// Invalid Transition
return;
}

const sourceSchema = source.droppableId;

if (Object.values(FIELD_SELECTOR_ID).includes(sourceSchema as FIELD_SELECTOR_ID)) {
// Replacing an exisitng configuration with a new field from field selector panel

const newFieldToAdd = draggableId;
createNewAggConfig({
fieldName: newFieldToAdd,
sourceGroup: source.droppableId,
destinationSchema,
aggProps,
aggService,
sourceAgg: null,
});

// Removing the exisiting destination Aggregation
const updatedAggConfig = aggProps.aggConfigs?.aggs.filter((agg) => agg.id !== destinationAggId);

if (updatedAggConfig) {
dispatch(updateAggConfigParams(updatedAggConfig.map((agg) => agg.serialize())));
}
} else {
// Replacing an existing configuration with another exisiting configuration

const sourceAgg = aggProps.aggConfigs?.aggs.find((agg) => agg.id === sourceAggId);
const sourceFieldName = sourceAgg?.fieldName();

createNewAggConfig({
fieldName: sourceFieldName,
sourceGroup: source.droppableId,
destinationSchema,
aggProps,
aggService,
sourceAgg,
});

// Removing the exisiting destination and source Aggregation
const updatedAggConfig = aggProps.aggConfigs?.aggs.filter(
(agg) => agg.id !== destinationAggId && agg.id !== sourceAggId
);

if (updatedAggConfig) {
dispatch(updateAggConfigParams(updatedAggConfig.map((agg) => agg.serialize())));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
border-bottom: none;
}

&__droppable {
min-height: 1px;
}

&__container {
display: grid;
grid-gap: calc($euiSizeXS / 2);
Expand Down
Loading

0 comments on commit b1e5237

Please sign in to comment.