Skip to content

Commit

Permalink
a
Browse files Browse the repository at this point in the history
Signed-off-by: ananzh <ananzh@amazon.com>
  • Loading branch information
ananzh committed Nov 21, 2023
1 parent a9d098a commit f19a9ca
Show file tree
Hide file tree
Showing 15 changed files with 1,127 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/
.dropBox {
margin-top: $euiSize;
border-bottom: $euiBorderThin;
padding-bottom: $euiSize;

&:first-child {
margin-top: 0;
}

&:last-child {
border-bottom: none;
}

&__container {
display: grid;
grid-gap: calc($euiSizeXS / 2);
padding: calc($euiSizeS - ($euiSizeXS / 2)) $euiSizeS $euiSizeS $euiSizeS;
background-color: $euiColorLightShade;
border-radius: $euiBorderRadius;
}

&__field {
display: grid;
grid-template-columns: 1fr auto;
grid-gap: $euiSizeS;
padding: $euiSizeS $euiSizeM;
align-items: center;
}

&__draggable {
padding: calc($euiSizeXS / 2) 0;
animation: pop-in $euiAnimSpeedSlow $euiAnimSlightResistance forwards;
transform-origin: bottom;

&.closing {
animation: pop-out $euiAnimSpeedSlow $euiAnimSlightResistance forwards; // Also update speed in dropbox.tsx
}
}

&__field_text {
text-overflow: ellipsis;
overflow: hidden;
}

&__dropTarget {
color: $euiColorDarkShade;
grid-template-columns: 1fr auto;
transform-origin: top;
animation: pop-in $euiAnimSpeedFast $euiAnimSlightResistance forwards;

&.validField {
background-color: tintOrShade($euiColorPrimary, 80%, 70%);
border-color: tintOrShade($euiColorPrimary, 80%, 70%);

&.canDrop {
background-color: tintOrShade($euiColorPrimary, 60%, 40%);
border-color: tintOrShade($euiColorPrimary, 30%, 20%);
border-style: dashed;
}
}
}
}

@keyframes pop-in {
from {
max-height: 0;
opacity: 0;
}

to {
max-height: 1000px;
opacity: 1;
}
}

@keyframes pop-out {
from {
max-height: 1000px;
opacity: 1;
}

to {
max-height: 0;
opacity: 0;
}
}

@media (prefers-reduced-motion) {
.dropBox {
&__draggable {
animation: none;

&.closing {
animation: none;
}
}

&__dropTarget {
animation: none;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { i18n } from '@osd/i18n';
import {
EuiButtonIcon,
EuiDragDropContext,
EuiDraggable,
EuiDroppable,
EuiFormRow,
EuiPanel,
EuiText,
DropResult,
} from '@elastic/eui';
import React, { useCallback, useState } from 'react';
import { IDropAttributes, IDropState } from '../../utils/drag_drop';
import './dropbox.scss';
import { useDropbox } from './use';
import { UseDropboxProps } from './use/use_dropbox';
import { usePrefersReducedMotion } from './use/use_prefers_reduced_motion';

export interface DropboxDisplay {
label: string;
id: string;
}

interface DropboxProps extends IDropState {
id: string;
label: string;
fields: DropboxDisplay[];
limit?: number;
onAddField: () => void;
onEditField: (id: string) => void;
onDeleteField: (id: string) => void;
onReorderField: ({
sourceAggId,
destinationAggId,
}: {
sourceAggId: string;
destinationAggId: string;
}) => void;
dropProps: IDropAttributes;
}

const DropboxComponent = ({
id: dropboxId,
label: boxLabel,
fields,
onAddField,
onDeleteField,
onEditField,
onReorderField,
limit = 1,
isValidDropTarget,
canDrop,
dropProps,
}: DropboxProps) => {
const prefersReducedMotion = usePrefersReducedMotion();
const [closing, setClosing] = useState<boolean | string>(false);
const handleDragEnd = useCallback(
({ source, destination }: DropResult) => {
if (!destination) return;

onReorderField({
sourceAggId: fields[source.index].id,
destinationAggId: fields[destination.index].id,
});
},
[fields, onReorderField]
);

const animateDelete = useCallback(
(id: string) => {
setClosing(id);
setTimeout(
() => {
onDeleteField(id);
setClosing(false);
},
prefersReducedMotion ? 0 : 350 // Also update speed in dropbox.scss
);
},
[onDeleteField, prefersReducedMotion]
);

return (
<EuiDragDropContext onDragEnd={handleDragEnd}>
<EuiFormRow label={boxLabel} className="dropBox" fullWidth>
<div className="dropBox__container">
<EuiDroppable droppableId={dropboxId}>
{fields.map(({ id, label }, index) => (
<EuiDraggable
className={`dropBox__draggable ${id === closing && 'closing'}`}
key={id}
draggableId={id}
index={index}
>
<EuiPanel
key={index}
paddingSize="s"
className="dropBox__field"
data-test-subj={`dropBoxField-${dropboxId}-${index}`}
>
<EuiText size="s" className="dropBox__field_text" onClick={() => onEditField(id)}>
<a role="button" tabIndex={0}>
{label}
</a>
</EuiText>
<EuiButtonIcon
color="subdued"
iconType="cross"
aria-label="clear-field"
iconSize="s"
onClick={() => animateDelete(id)}
data-test-subj="dropBoxRemoveBtn"
/>
</EuiPanel>
</EuiDraggable>
))}
</EuiDroppable>
{fields.length < limit && (
<EuiPanel
data-test-subj={`dropBoxAddField-${dropboxId}`}
className={`dropBox__field dropBox__dropTarget ${
isValidDropTarget ? 'validField' : ''
} ${canDrop ? 'canDrop' : ''}`}
{...(isValidDropTarget && dropProps)}
>
<EuiText size="s">
{i18n.translate('visBuilder.dropbox.addField.title', {
defaultMessage: 'Click or drop to add',
})}
</EuiText>
<EuiButtonIcon
iconType="plusInCircle"
aria-label="clear-field"
iconSize="s"
onClick={() => onAddField()}
data-test-subj="dropBoxAddBtn"
/>
</EuiPanel>
)}
</div>
</EuiFormRow>
</EuiDragDropContext>
);
};

const Dropbox = React.memo((dropBox: UseDropboxProps) => {
const props = useDropbox(dropBox);

return <DropboxComponent {...props} />;
});

export { Dropbox, DropboxComponent, DropboxProps };
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/
.vbConfig {
@include euiYScrollWithShadows;

background: $euiColorLightestShade;
border-left: $euiBorderThin;
position: relative;
overflow-x: hidden;

&__section {
width: 100%;
transition: transform $euiAnimSpeedNormal 0s $euiAnimSlightResistance;
}

&__title {
padding: $euiSizeS;
padding-bottom: 0;

&.showDivider {
border-bottom: 1px solid $euiColorLightShade;
}
}

&__content {
padding: $euiSizeS;
}

&__aggEditor {
padding: 0 $euiSizeM;
}

&--secondary {
position: absolute;
top: 0;
left: 100%;

.visEditorAggParam--half {
margin: $euiSize 0;
}
}

&.showSecondary > .vbConfig__section {
transform: translateX(-100%);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { EuiForm } from '@elastic/eui';
import React from 'react';
import { useVisualizationType } from '../../utils/use';
import { useSelector } from '../../utils/state_management';
import { mapSchemaToAggPanel } from './schema_to_dropbox';
import { SecondaryPanel } from './secondary_panel';

import './index.scss';

export function ConfigPanel() {
const vizType = useVisualizationType();
const editingState = useSelector((state) => state.vbVisualization.activeVisualization?.draftAgg);
const schemas = vizType.ui.containerConfig.data.schemas;

if (!schemas) return null;

const mainPanel = mapSchemaToAggPanel(schemas);

return (
<EuiForm className={`vbConfig ${editingState ? 'showSecondary' : ''}`}>
<div className="vbConfig__section">{mainPanel}</div>
<SecondaryPanel />
</EuiForm>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import React from 'react';
import { Schemas } from '../../../../../vis_default_editor/public';
import { Dropbox } from './dropbox';
import { Title } from './title';

export const mapSchemaToAggPanel = (schemas: Schemas) => {
const panelComponents = schemas.all.map((schema) => {
return <Dropbox key={schema.name} id={schema.name} label={schema.title} schema={schema} />;
});

return (
<>
<Title title="Configuration" />
<div className="vbConfig__content">{panelComponents}</div>
</>
);
};
Loading

0 comments on commit f19a9ca

Please sign in to comment.