From 96cebc2e4553628a8ceab6786f8f26793c86f4ff Mon Sep 17 00:00:00 2001 From: Ashwin Pc Date: Wed, 17 Nov 2021 00:49:32 +0000 Subject: [PATCH 1/2] Initial Drag and Drop plugin code Signed-off-by: Ashwin Pc --- src/plugins/wizard/.i18nrc.json | 7 + src/plugins/wizard/README.md | 11 ++ src/plugins/wizard/common/index.ts | 9 ++ .../common/wizard_saved_object_attributes.ts | 14 ++ src/plugins/wizard/opensearch_dashboards.json | 16 +++ .../wizard/public/application/_variables.scss | 3 + .../wizard/public/application/app.scss | 13 ++ src/plugins/wizard/public/application/app.tsx | 54 ++++++++ .../public/application/components/_util.scss | 8 ++ .../components/data_tab/config_panel.scss | 9 ++ .../components/data_tab/config_panel.tsx | 43 ++++++ .../components/data_tab/config_section.scss | 23 ++++ .../components/data_tab/config_section.tsx | 62 +++++++++ .../components/data_tab/field_selector.scss | 10 ++ .../components/data_tab/field_selector.tsx | 113 +++++++++++++++ .../data_tab/field_selector_field.scss | 12 ++ .../data_tab/field_selector_field.tsx | 85 ++++++++++++ .../components/data_tab/index.scss | 7 + .../application/components/data_tab/index.tsx | 24 ++++ .../application/components/side_nav.scss | 18 +++ .../application/components/side_nav.tsx | 110 +++++++++++++++ .../application/components/style_tab.tsx | 10 ++ .../application/components/top_nav.scss | 4 + .../public/application/components/top_nav.tsx | 41 ++++++ .../application/components/workspace.scss | 12 ++ .../application/components/workspace.tsx | 37 +++++ .../wizard/public/application/index.tsx | 30 ++++ .../application/utils/async_search/index.ts | 48 +++++++ .../utils/drag_drop/drag_drop_context.tsx | 113 +++++++++++++++ .../application/utils/drag_drop/index.ts | 6 + .../application/utils/get_top_nav_config.tsx | 129 ++++++++++++++++++ src/plugins/wizard/public/index.ts | 13 ++ src/plugins/wizard/public/plugin.ts | 55 ++++++++ src/plugins/wizard/public/types.ts | 29 ++++ .../wizard/public/visualizations/xy_chart.tsx | 6 + src/plugins/wizard/server/index.ts | 16 +++ src/plugins/wizard/server/plugin.ts | 44 ++++++ src/plugins/wizard/server/routes/index.ts | 22 +++ .../wizard/server/saved_objects/index.ts | 6 + .../wizard/server/saved_objects/wizard_app.ts | 36 +++++ src/plugins/wizard/server/types.ts | 9 ++ 41 files changed, 1317 insertions(+) create mode 100644 src/plugins/wizard/.i18nrc.json create mode 100755 src/plugins/wizard/README.md create mode 100644 src/plugins/wizard/common/index.ts create mode 100644 src/plugins/wizard/common/wizard_saved_object_attributes.ts create mode 100644 src/plugins/wizard/opensearch_dashboards.json create mode 100644 src/plugins/wizard/public/application/_variables.scss create mode 100644 src/plugins/wizard/public/application/app.scss create mode 100644 src/plugins/wizard/public/application/app.tsx create mode 100644 src/plugins/wizard/public/application/components/_util.scss create mode 100644 src/plugins/wizard/public/application/components/data_tab/config_panel.scss create mode 100644 src/plugins/wizard/public/application/components/data_tab/config_panel.tsx create mode 100644 src/plugins/wizard/public/application/components/data_tab/config_section.scss create mode 100644 src/plugins/wizard/public/application/components/data_tab/config_section.tsx create mode 100644 src/plugins/wizard/public/application/components/data_tab/field_selector.scss create mode 100644 src/plugins/wizard/public/application/components/data_tab/field_selector.tsx create mode 100644 src/plugins/wizard/public/application/components/data_tab/field_selector_field.scss create mode 100644 src/plugins/wizard/public/application/components/data_tab/field_selector_field.tsx create mode 100644 src/plugins/wizard/public/application/components/data_tab/index.scss create mode 100644 src/plugins/wizard/public/application/components/data_tab/index.tsx create mode 100644 src/plugins/wizard/public/application/components/side_nav.scss create mode 100644 src/plugins/wizard/public/application/components/side_nav.tsx create mode 100644 src/plugins/wizard/public/application/components/style_tab.tsx create mode 100644 src/plugins/wizard/public/application/components/top_nav.scss create mode 100644 src/plugins/wizard/public/application/components/top_nav.tsx create mode 100644 src/plugins/wizard/public/application/components/workspace.scss create mode 100644 src/plugins/wizard/public/application/components/workspace.tsx create mode 100644 src/plugins/wizard/public/application/index.tsx create mode 100644 src/plugins/wizard/public/application/utils/async_search/index.ts create mode 100644 src/plugins/wizard/public/application/utils/drag_drop/drag_drop_context.tsx create mode 100644 src/plugins/wizard/public/application/utils/drag_drop/index.ts create mode 100644 src/plugins/wizard/public/application/utils/get_top_nav_config.tsx create mode 100644 src/plugins/wizard/public/index.ts create mode 100644 src/plugins/wizard/public/plugin.ts create mode 100644 src/plugins/wizard/public/types.ts create mode 100644 src/plugins/wizard/public/visualizations/xy_chart.tsx create mode 100644 src/plugins/wizard/server/index.ts create mode 100644 src/plugins/wizard/server/plugin.ts create mode 100644 src/plugins/wizard/server/routes/index.ts create mode 100644 src/plugins/wizard/server/saved_objects/index.ts create mode 100644 src/plugins/wizard/server/saved_objects/wizard_app.ts create mode 100644 src/plugins/wizard/server/types.ts diff --git a/src/plugins/wizard/.i18nrc.json b/src/plugins/wizard/.i18nrc.json new file mode 100644 index 00000000000..2b511494a46 --- /dev/null +++ b/src/plugins/wizard/.i18nrc.json @@ -0,0 +1,7 @@ +{ + "prefix": "wizard", + "paths": { + "wizard": "." + }, + "translations": ["translations/ja-JP.json"] +} diff --git a/src/plugins/wizard/README.md b/src/plugins/wizard/README.md new file mode 100755 index 00000000000..bcb362b374c --- /dev/null +++ b/src/plugins/wizard/README.md @@ -0,0 +1,11 @@ +# wizard + +A OpenSearch Dashboards plugin + +--- + +## Development + +See the [OpenSearch Dashboards contributing +guide](https://github.com/opensearch-project/OpenSearch-Dashboards/blob/master/CONTRIBUTING.md) for instructions +setting up your development environment. diff --git a/src/plugins/wizard/common/index.ts b/src/plugins/wizard/common/index.ts new file mode 100644 index 00000000000..4b3522fec70 --- /dev/null +++ b/src/plugins/wizard/common/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export const PLUGIN_ID = 'wizard'; +export const PLUGIN_NAME = 'Wizard'; + +export { WizardSavedObjectAttributes, WIZARD_SAVED_OBJECT } from './wizard_saved_object_attributes'; diff --git a/src/plugins/wizard/common/wizard_saved_object_attributes.ts b/src/plugins/wizard/common/wizard_saved_object_attributes.ts new file mode 100644 index 00000000000..ff6c12417d2 --- /dev/null +++ b/src/plugins/wizard/common/wizard_saved_object_attributes.ts @@ -0,0 +1,14 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { SavedObjectAttributes } from 'opensearch-dashboards/public'; + +export const WIZARD_SAVED_OBJECT = 'wizard'; + +export interface WizardSavedObjectAttributes extends SavedObjectAttributes { + title: string; + description?: string; + state: string; +} diff --git a/src/plugins/wizard/opensearch_dashboards.json b/src/plugins/wizard/opensearch_dashboards.json new file mode 100644 index 00000000000..93eb9d9a040 --- /dev/null +++ b/src/plugins/wizard/opensearch_dashboards.json @@ -0,0 +1,16 @@ +{ + "id": "wizard", + "version": "1.0.0", + "opensearchDashboardsVersion": "opensearchDashboards", + "server": true, + "ui": true, + "requiredPlugins": [ + "navigation", + "data", + "opensearchDashboardsReact", + "savedObjects", + "embeddable", + "dashboard" + ], + "optionalPlugins": [] +} diff --git a/src/plugins/wizard/public/application/_variables.scss b/src/plugins/wizard/public/application/_variables.scss new file mode 100644 index 00000000000..c1b3646e8e4 --- /dev/null +++ b/src/plugins/wizard/public/application/_variables.scss @@ -0,0 +1,3 @@ +@import '@elastic/eui/src/global_styling/variables/header'; + +$osdHeaderOffset: $euiHeaderHeightCompensation * 2; \ No newline at end of file diff --git a/src/plugins/wizard/public/application/app.scss b/src/plugins/wizard/public/application/app.scss new file mode 100644 index 00000000000..2e1e93f4431 --- /dev/null +++ b/src/plugins/wizard/public/application/app.scss @@ -0,0 +1,13 @@ +@import "variables"; + +.wizLayout { + padding: 0; + display: grid; + grid-template-rows: min-content 1fr; + grid-template-columns: 420px 1fr; + grid-template-areas: + "topNav topNav" + "sideNav workspace" + ; + height: calc(100vh - #{$osdHeaderOffset}); // TODO: update 190px to correct offset variable +} diff --git a/src/plugins/wizard/public/application/app.tsx b/src/plugins/wizard/public/application/app.tsx new file mode 100644 index 00000000000..37244f16ca5 --- /dev/null +++ b/src/plugins/wizard/public/application/app.tsx @@ -0,0 +1,54 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React, { useState, useEffect } from 'react'; +import { I18nProvider } from '@osd/i18n/react'; +import { EuiPage } from '@elastic/eui'; +import { DataPublicPluginStart, IndexPattern } from '../../../data/public'; +import { SideNav } from './components/side_nav'; +import { DragDropProvider } from './utils/drag_drop/drag_drop_context'; +import { useOpenSearchDashboards } from '../../../opensearch_dashboards_react/public'; +import { WizardServices } from '../types'; +import { Workspace } from './components/workspace'; + +import './app.scss'; +import { TopNav } from './components/top_nav'; + +export const WizardApp = () => { + const { + services: { data }, + } = useOpenSearchDashboards(); + + const [indexPattern, setIndexPattern] = useIndexPattern(data); + + // Render the application DOM. + return ( + + + + + + + + + + ); +}; + +// TODO: Temporary. Need to update it fetch the index pattern cohesively +function useIndexPattern(data: DataPublicPluginStart) { + const [indexPattern, setIndexPattern] = useState(null); + useEffect(() => { + const fetchIndexPattern = async () => { + const defaultIndexPattern = await data.indexPatterns.getDefault(); + if (defaultIndexPattern) { + setIndexPattern(defaultIndexPattern); + } + }; + fetchIndexPattern(); + }, [data.indexPatterns]); + + return [indexPattern, setIndexPattern] as const; +} diff --git a/src/plugins/wizard/public/application/components/_util.scss b/src/plugins/wizard/public/application/components/_util.scss new file mode 100644 index 00000000000..9a444c1fe09 --- /dev/null +++ b/src/plugins/wizard/public/application/components/_util.scss @@ -0,0 +1,8 @@ +@mixin scrollNavParent ($template-row: none) { + display: grid; + min-height: 0; + + @if $template-row != 'none' { + grid-template-rows: $template-row; + } +} \ No newline at end of file diff --git a/src/plugins/wizard/public/application/components/data_tab/config_panel.scss b/src/plugins/wizard/public/application/components/data_tab/config_panel.scss new file mode 100644 index 00000000000..7477dcfca81 --- /dev/null +++ b/src/plugins/wizard/public/application/components/data_tab/config_panel.scss @@ -0,0 +1,9 @@ +.wizConfigPanel { + background: #f0f1f3; + border-left: $euiBorderThin; + padding: $euiSizeS; +} + +.wizConfigPanel__title { + margin-left: $euiSizeS; +} diff --git a/src/plugins/wizard/public/application/components/data_tab/config_panel.tsx b/src/plugins/wizard/public/application/components/data_tab/config_panel.tsx new file mode 100644 index 00000000000..262fd4c06e4 --- /dev/null +++ b/src/plugins/wizard/public/application/components/data_tab/config_panel.tsx @@ -0,0 +1,43 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { EuiForm, EuiTitle } from '@elastic/eui'; +import React from 'react'; +import { i18n } from '@osd/i18n'; +import { BUCKET_TYPES, METRIC_TYPES } from '../../../../../data/public'; +import { ConfigSection } from './config_section'; + +import './config_panel.scss'; + +// TODO: Temp. Remove once visualizations can be refgistered and editor configs can be passed along +const CONFIG = { + x: { + title: 'X Axis', + allowedAggregation: BUCKET_TYPES.TERMS, + }, + y: { + title: 'Y Axis', + allowedAggregation: METRIC_TYPES.AVG, + }, +}; + +export function ConfigPanel() { + const sections = CONFIG; + + return ( + + +

+ {i18n.translate('wizard.nav.dataTab.configPanel.title', { + defaultMessage: 'Configuration', + })} +

+
+ {Object.entries(sections).map(([sectionId, sectionProps], index) => ( + {}} /> + ))} +
+ ); +} diff --git a/src/plugins/wizard/public/application/components/data_tab/config_section.scss b/src/plugins/wizard/public/application/components/data_tab/config_section.scss new file mode 100644 index 00000000000..79d0d3a913f --- /dev/null +++ b/src/plugins/wizard/public/application/components/data_tab/config_section.scss @@ -0,0 +1,23 @@ +.wizConfigSection { + margin-top: $euiSize; + border-bottom: $euiBorderThin; + padding-bottom: $euiSize; + + &:last-child { + border-bottom: none; + } + + & .euiFormRow__labelWrapper { + margin-left: $euiSizeS; + } +} + +.wizConfigSection__dropTarget { + @include euiSlightShadow; + background: $euiColorEmptyShade; + border: $euiBorderThin; + box-shadow: 0px 2px 2px rgba(152, 162, 179, 0.15); + border-radius: $euiBorderRadius; + padding: $euiSizeS $euiSizeM; + color: $euiColorDarkShade; +} diff --git a/src/plugins/wizard/public/application/components/data_tab/config_section.tsx b/src/plugins/wizard/public/application/components/data_tab/config_section.tsx new file mode 100644 index 00000000000..88511756222 --- /dev/null +++ b/src/plugins/wizard/public/application/components/data_tab/config_section.tsx @@ -0,0 +1,62 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { EuiButtonIcon, EuiFormRow, EuiPanel, EuiText } from '@elastic/eui'; +import { i18n } from '@osd/i18n'; +import React, { useCallback, useEffect, useState } from 'react'; +import { IndexPatternField } from 'src/plugins/data/common'; +import { useDrop } from '../../utils/drag_drop'; + +import './config_section.scss'; + +interface ConfigSectionProps { + id: string; + title: string; + onChange: Function; +} + +export const ConfigSection = ({ title, id, onChange }: ConfigSectionProps) => { + const [currentField, setCurrentField] = useState(); + + const dropHandler = useCallback((field: IndexPatternField) => { + setCurrentField(field); + }, []); + const [dropProps, { isValidDropTarget, dragData }] = useDrop('dataPlane', dropHandler); + + const dropTargetString = dragData + ? dragData.type + : i18n.translate('wizard.nav.dataTab.configPanel.dropTarget.placeholder', { + defaultMessage: 'Click or drop to add', + }); + + useEffect(() => { + onChange(id, currentField); + }, [id, currentField, onChange]); + + return ( + + {currentField ? ( + + + {currentField.displayName} + + setCurrentField(undefined)} + /> + + ) : ( +
+ {dropTargetString} +
+ )} +
+ ); +}; diff --git a/src/plugins/wizard/public/application/components/data_tab/field_selector.scss b/src/plugins/wizard/public/application/components/data_tab/field_selector.scss new file mode 100644 index 00000000000..fc6749215e6 --- /dev/null +++ b/src/plugins/wizard/public/application/components/data_tab/field_selector.scss @@ -0,0 +1,10 @@ +@import "../util"; + +.wizFieldSelector { + @include scrollNavParent; + padding: $euiSizeS; +} + +.wizFieldSelector__fieldGroups { + overflow-y: auto; +} diff --git a/src/plugins/wizard/public/application/components/data_tab/field_selector.tsx b/src/plugins/wizard/public/application/components/data_tab/field_selector.tsx new file mode 100644 index 00000000000..53d38594496 --- /dev/null +++ b/src/plugins/wizard/public/application/components/data_tab/field_selector.tsx @@ -0,0 +1,113 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; + +import { + EuiFormLabel, + EuiFlexItem, + EuiAccordion, + EuiSpacer, + EuiNotificationBadge, + EuiTitle, +} from '@elastic/eui'; + +import { + IndexPatternField, + OPENSEARCH_FIELD_TYPES, + OSD_FIELD_TYPES, +} from '../../../../../data/public'; +import { FieldSelectorField } from './field_selector_field'; + +import './field_selector.scss'; + +interface FieldSelectorDeps { + indexFields: IndexPatternField[]; +} + +interface IFieldCategories { + categorical: IndexPatternField[]; + numerical: IndexPatternField[]; + meta: IndexPatternField[]; +} + +const META_FIELDS: string[] = [ + OPENSEARCH_FIELD_TYPES._ID, + OPENSEARCH_FIELD_TYPES._INDEX, + OPENSEARCH_FIELD_TYPES._SOURCE, + OPENSEARCH_FIELD_TYPES._TYPE, +]; + +export const FieldSelector = ({ indexFields }: FieldSelectorDeps) => { + const fields = indexFields?.reduce( + (fieldGroups, currentField) => { + const category = getFieldCategory(currentField); + fieldGroups[category].push(currentField); + + return fieldGroups; + }, + { + categorical: [], + numerical: [], + meta: [], + } + ); + + return ( +
+
+ TODO: Search goes here +
+
+ + + +
+
+ ); +}; + +interface FieldGroupProps { + fields?: IndexPatternField[]; + header: string; + id: string; +} + +const FieldGroup = ({ fields, header, id }: FieldGroupProps) => ( + <> + + {header} + + } + extraAction={ + + {fields?.length || 0} + + } + initialIsOpen + > + {fields?.map((field, i) => ( + + + + ))} + + + +); + +function getFieldCategory(field: IndexPatternField): keyof IFieldCategories { + if (META_FIELDS.includes(field.name)) return 'meta'; + if (field.type === OSD_FIELD_TYPES.NUMBER) return 'numerical'; + + return 'categorical'; +} diff --git a/src/plugins/wizard/public/application/components/data_tab/field_selector_field.scss b/src/plugins/wizard/public/application/components/data_tab/field_selector_field.scss new file mode 100644 index 00000000000..0ace9a914b3 --- /dev/null +++ b/src/plugins/wizard/public/application/components/data_tab/field_selector_field.scss @@ -0,0 +1,12 @@ +.wizFieldSelectorField { + @include euiBottomShadowSmall; + padding: $euiSizeXS; + background-color: $euiColorEmptyShade; + border: $euiBorderThin; + margin-top: $euiSizeS; + + & > button { + align-items: center; + gap: 4px; + } +} diff --git a/src/plugins/wizard/public/application/components/data_tab/field_selector_field.tsx b/src/plugins/wizard/public/application/components/data_tab/field_selector_field.tsx new file mode 100644 index 00000000000..396b89c0bb9 --- /dev/null +++ b/src/plugins/wizard/public/application/components/data_tab/field_selector_field.tsx @@ -0,0 +1,85 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* + * Modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +import React, { useState } from 'react'; +import { IndexPatternField } from 'src/plugins/data/public'; +import { FieldButton, FieldIcon } from '../../../../../opensearch_dashboards_react/public'; +import { useDrag } from '../../utils/drag_drop/drag_drop_context'; + +import './field_selector_field.scss'; + +export interface FieldSelectorFieldProps { + field: IndexPatternField; +} + +// TODO: +// 1. Add field sections (Available fields, popular fields from src/plugins/discover/public/application/components/sidebar/discover_sidebar.tsx) +// 2. Add popover for fields stats from discover as well +export const FieldSelectorField = ({ field }: FieldSelectorFieldProps) => { + const [infoIsOpen, setOpen] = useState(false); + const [dragProps] = useDrag(field, `dataPlane`); + + function togglePopover() { + setOpen(!infoIsOpen); + } + + function wrapOnDot(str?: string) { + // u200B is a non-width white-space character, which allows + // the browser to efficiently word-wrap right after the dot + // without us having to draw a lot of extra DOM elements, etc + return str ? str.replace(/\./g, '.\u200B') : ''; + } + + const fieldName = ( + + {wrapOnDot(field.displayName)} + + ); + + return ( + } + // fieldAction={actionButton} + fieldName={fieldName} + {...dragProps} + /> + ); +}; diff --git a/src/plugins/wizard/public/application/components/data_tab/index.scss b/src/plugins/wizard/public/application/components/data_tab/index.scss new file mode 100644 index 00000000000..1ba02bcc987 --- /dev/null +++ b/src/plugins/wizard/public/application/components/data_tab/index.scss @@ -0,0 +1,7 @@ +@import "../util"; + +.wizDataTab { + @include scrollNavParent; + display: grid; + grid-template-columns: 50% 50%; +} diff --git a/src/plugins/wizard/public/application/components/data_tab/index.tsx b/src/plugins/wizard/public/application/components/data_tab/index.tsx new file mode 100644 index 00000000000..e7e5f02e6d0 --- /dev/null +++ b/src/plugins/wizard/public/application/components/data_tab/index.tsx @@ -0,0 +1,24 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { IndexPatternField } from '../../../../../data/public'; +import { FieldSelector } from './field_selector'; +import { ConfigPanel } from './config_panel'; + +import './index.scss'; + +interface DataTabDeps { + indexFields: IndexPatternField[]; +} + +export const DataTab = ({ indexFields }: DataTabDeps) => { + return ( +
+ + +
+ ); +}; diff --git a/src/plugins/wizard/public/application/components/side_nav.scss b/src/plugins/wizard/public/application/components/side_nav.scss new file mode 100644 index 00000000000..88ff7ffb0e4 --- /dev/null +++ b/src/plugins/wizard/public/application/components/side_nav.scss @@ -0,0 +1,18 @@ +@import "util"; + +.wizSidenav { + @include scrollNavParent(auto 1fr); + grid-area: sideNav; + border-right: $euiBorderThin; +} + +.wizDatasourceSelector { + padding: $euiSize $euiSize 0 $euiSize; +} + +.wizSidenavTabs { + @include scrollNavParent(min-content 1fr); + &>[role="tabpanel"] { + @include scrollNavParent; + } +} diff --git a/src/plugins/wizard/public/application/components/side_nav.tsx b/src/plugins/wizard/public/application/components/side_nav.tsx new file mode 100644 index 00000000000..a35c039e57f --- /dev/null +++ b/src/plugins/wizard/public/application/components/side_nav.tsx @@ -0,0 +1,110 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React, { useState, useEffect } from 'react'; +import { i18n } from '@osd/i18n'; + +import { + EuiFormLabel, + EuiFlexGroup, + EuiFlexItem, + EuiTabbedContent, + EuiTabbedContentTab, +} from '@elastic/eui'; + +import { IndexPattern, IndexPatternField, OSD_FIELD_TYPES } from '../../../../data/public'; +import { DataTab } from './data_tab'; +import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; +import { WizardServices } from '../../types'; +import { StyleTab } from './style_tab'; + +import './side_nav.scss'; + +interface SideNavDeps { + indexPattern: IndexPattern | null; + setIndexPattern: React.Dispatch>; +} + +const ALLOWED_FIELDS: string[] = [OSD_FIELD_TYPES.STRING, OSD_FIELD_TYPES.NUMBER]; + +export const SideNav = ({ indexPattern, setIndexPattern }: SideNavDeps) => { + const { + services: { + data, + savedObjects: { client: savedObjectsClient }, + }, + } = useOpenSearchDashboards(); + const { IndexPatternSelect } = data.ui; + const [indexFields, setIndexFields] = useState([]); + + // Fetch the default index pattern using the `data.indexPatterns` service, as the component is mounted. + useEffect(() => { + const setDefaultIndexPattern = async () => { + const defaultIndexPattern = await data.indexPatterns.getDefault(); + setIndexPattern(defaultIndexPattern); + }; + + setDefaultIndexPattern(); + }, [data, setIndexPattern]); + + // Update the fields list every time the index pattern is modified. + useEffect(() => { + const fields = indexPattern?.fields; + + setIndexFields(fields?.filter(isValidField) || []); + }, [indexPattern]); + + const tabs: EuiTabbedContentTab[] = [ + { + id: 'data-tab', + name: i18n.translate('wizard.nav.dataTab.title', { + defaultMessage: 'Data', + }), + content: , + }, + { + id: 'style-tab', + name: i18n.translate('wizard.nav.styleTab.title', { + defaultMessage: 'Style', + }), + content: , + }, + ]; + + return ( +
+
+ + {i18n.translate('wizard.nav.dataSource.selector.title', { + defaultMessage: 'Index Pattern', + })} + + { + const newIndexPattern = await data.indexPatterns.get(newIndexPatternId); + setIndexPattern(newIndexPattern); + }} + isClearable={false} + /> +
+ +
+ ); +}; + +// TODO: Temporary validate function +// Need to identify hopw to get fieldCounts to use the standard filter and group functions +function isValidField(field: IndexPatternField): boolean { + const isAggregatable = field.aggregatable === true; + const isNotScripted = !field.scripted; + const isAllowed = ALLOWED_FIELDS.includes(field.type); + + return isAggregatable && isNotScripted && isAllowed; +} diff --git a/src/plugins/wizard/public/application/components/style_tab.tsx b/src/plugins/wizard/public/application/components/style_tab.tsx new file mode 100644 index 00000000000..3d1eb0d98b3 --- /dev/null +++ b/src/plugins/wizard/public/application/components/style_tab.tsx @@ -0,0 +1,10 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; + +export const StyleTab = () => { + return
TODO: Layout styles come here.
; +}; diff --git a/src/plugins/wizard/public/application/components/top_nav.scss b/src/plugins/wizard/public/application/components/top_nav.scss new file mode 100644 index 00000000000..f8e1d1d6cfa --- /dev/null +++ b/src/plugins/wizard/public/application/components/top_nav.scss @@ -0,0 +1,4 @@ +.wizTopNav { + grid-area: topNav; + border-bottom: $euiBorderThin; +} \ No newline at end of file diff --git a/src/plugins/wizard/public/application/components/top_nav.tsx b/src/plugins/wizard/public/application/components/top_nav.tsx new file mode 100644 index 00000000000..e0c9d47efef --- /dev/null +++ b/src/plugins/wizard/public/application/components/top_nav.tsx @@ -0,0 +1,41 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React, { useMemo, useState } from 'react'; +import { IndexPattern } from '../../../../data/public'; +import { PLUGIN_ID } from '../../../common'; +import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; +import { getTopNavconfig } from '../utils/get_top_nav_config'; +import { WizardServices } from '../../types'; + +import './top_nav.scss'; + +export const TopNav = () => { + const { services } = useOpenSearchDashboards(); + const { + setHeaderActionMenu, + navigation: { + ui: { TopNavMenu }, + }, + } = services; + + const config = useMemo(() => getTopNavconfig(services), [services]); + // TODO: Set index pattern/data source here. Filters wont show up until you do + const [indexPatterns, setIndexPatterns] = useState([]); + + return ( +
+ +
+ ); +}; diff --git a/src/plugins/wizard/public/application/components/workspace.scss b/src/plugins/wizard/public/application/components/workspace.scss new file mode 100644 index 00000000000..94a97e881bf --- /dev/null +++ b/src/plugins/wizard/public/application/components/workspace.scss @@ -0,0 +1,12 @@ +.wizWorkspace { + display: grid; + grid-template-rows: auto 1fr; + grid-area: workspace; + grid-gap: $euiSizeM; + padding: $euiSizeM; + background-color: $euiColorEmptyShade; +} + +.wizWorkspace__empty { + height: 100%; +} diff --git a/src/plugins/wizard/public/application/components/workspace.tsx b/src/plugins/wizard/public/application/components/workspace.tsx new file mode 100644 index 00000000000..b944682db56 --- /dev/null +++ b/src/plugins/wizard/public/application/components/workspace.tsx @@ -0,0 +1,37 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { EuiButton, EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem, EuiPanel } from '@elastic/eui'; +import React, { FC } from 'react'; + +import './workspace.scss'; + +export const Workspace: FC = ({ children }) => { + return ( +
+ + + {/* TODO: This is the teporary view of the selected chard, should be replaced by dropdown */} + + Bar + + + + + {children ? ( + children + ) : ( + + Welcome to the wizard!} + body={

Drag some fileds onto the panel to visualize some data.

} + /> +
+ )} +
+
+ ); +}; diff --git a/src/plugins/wizard/public/application/index.tsx b/src/plugins/wizard/public/application/index.tsx new file mode 100644 index 00000000000..b778d2e139d --- /dev/null +++ b/src/plugins/wizard/public/application/index.tsx @@ -0,0 +1,30 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import ReactDOM from 'react-dom'; +import { BrowserRouter as Router } from 'react-router-dom'; +import { AppMountParameters } from '../../../../core/public'; +import { WizardServices } from '../types'; +import { WizardApp } from './app'; +import { OpenSearchDashboardsContextProvider } from '../../../opensearch_dashboards_react/public'; + +export const renderApp = ( + { appBasePath, element }: AppMountParameters, + services: WizardServices +) => { + ReactDOM.render( + + + + + + + , + element + ); + + return () => ReactDOM.unmountComponentAtNode(element); +}; diff --git a/src/plugins/wizard/public/application/utils/async_search/index.ts b/src/plugins/wizard/public/application/utils/async_search/index.ts new file mode 100644 index 00000000000..9746cde24e4 --- /dev/null +++ b/src/plugins/wizard/public/application/utils/async_search/index.ts @@ -0,0 +1,48 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { CreateAggConfigParams } from 'src/plugins/data/common'; +import { DataPublicPluginStart, IndexPattern } from 'src/plugins/data/public'; + +interface IDoAsyncSearch { + data: DataPublicPluginStart; + indexPattern: IndexPattern | null; + aggs?: CreateAggConfigParams[]; +} + +export const doAsyncSearch = async ({ data, indexPattern, aggs }: IDoAsyncSearch) => { + if (!indexPattern || !aggs || !aggs.length) return; + + // Constuct the query portion of the search request + const query = data.query.getOpenSearchQuery(indexPattern); + + // Constuct the aggregations portion of the search request by using the `data.search.aggs` service. + // const aggs = [{ type: 'avg', params: { field: field.name } }]; + // const aggs = [ + // { type: 'terms', params: { field: 'day_of_week' } }, + // { type: 'avg', params: { field: field.name } }, + // { type: 'terms', params: { field: 'customer_gender' } }, + // ]; + const aggConfigs = data.search.aggs.createAggConfigs(indexPattern, aggs); + const aggsDsl = aggConfigs.toDsl(); + + const request = { + params: { + index: indexPattern.title, + body: { + aggs: aggsDsl, + query, + }, + }, + }; + + // Submit the search request using the `data.search` service. + const { rawResponse } = await data.search.search(request).toPromise(); + + return { + rawResponse, + aggConfigs, + }; +}; diff --git a/src/plugins/wizard/public/application/utils/drag_drop/drag_drop_context.tsx b/src/plugins/wizard/public/application/utils/drag_drop/drag_drop_context.tsx new file mode 100644 index 00000000000..a89226885d5 --- /dev/null +++ b/src/plugins/wizard/public/application/utils/drag_drop/drag_drop_context.tsx @@ -0,0 +1,113 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React, { createContext, DragEvent, FC, ReactNode, useContext, useState } from 'react'; + +interface DrapDataType { + namespace: string; + value: any; +} + +// TODO: Replace any with corret type +// TODO: Split into separate files +interface IDragDropContext { + data?: DrapDataType; + setData?: any; + isDragging: boolean; + setIsDragging?: any; +} + +const defaultContextProps = { + isDragging: false, +}; + +const DragDropContext = createContext(defaultContextProps); + +const DragDropProvider: FC = ({ children }) => { + const [isDragging, setIsDragging] = useState(false); + const [data, setData] = useState(); + return ( + + {children} + + ); +}; + +const useDragDropContext = () => useContext(DragDropContext); + +const useDrag = (dragData: any, namespace: string) => { + const { setData, setIsDragging } = useDragDropContext(); + const dragElementProps = { + draggable: true, + onDragStart: (event: DragEvent) => { + setIsDragging(true); + setData({ + namespace, + value: dragData, + }); + }, + onDragEnd: (event: DragEvent) => { + setIsDragging(false); + setData(null); + }, + }; + return [dragElementProps]; +}; + +interface IDropAttributes { + onDragOver: (event: DragEvent) => void; + onDrop: (event: DragEvent) => void; + onDragEnter: (event: DragEvent) => void; + onDragLeave: (event: DragEvent) => void; +} + +interface IDropState { + isDragging: boolean; + canDrop: boolean; + isValidDropTarget: boolean; + dragData: any; +} +const useDrop = (namespace: string, onDropCallback: Function): [IDropAttributes, IDropState] => { + const { data, isDragging, setIsDragging, setData } = useDragDropContext(); + const [canDrop, setCanDrop] = useState(false); + + const dropAttributes: IDropAttributes = { + onDragOver: (event) => { + event.preventDefault(); + }, + onDrop: (event) => { + setIsDragging(false); + onDropCallback(data?.value); + setData(null); + }, + onDragEnter: (event) => { + if (data?.namespace === namespace) { + setCanDrop(true); + } + }, + onDragLeave: (event) => { + setCanDrop(false); + }, + }; + return [ + dropAttributes, + { + isDragging, + canDrop, + isValidDropTarget: isDragging && data?.namespace === namespace, + dragData: data?.value, + }, + ]; +}; + +export { DragDropContext, DragDropProvider, useDragDropContext, useDrag, useDrop }; diff --git a/src/plugins/wizard/public/application/utils/drag_drop/index.ts b/src/plugins/wizard/public/application/utils/drag_drop/index.ts new file mode 100644 index 00000000000..3799a2eb605 --- /dev/null +++ b/src/plugins/wizard/public/application/utils/drag_drop/index.ts @@ -0,0 +1,6 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export * from './drag_drop_context'; diff --git a/src/plugins/wizard/public/application/utils/get_top_nav_config.tsx b/src/plugins/wizard/public/application/utils/get_top_nav_config.tsx new file mode 100644 index 00000000000..4d7c10d49e7 --- /dev/null +++ b/src/plugins/wizard/public/application/utils/get_top_nav_config.tsx @@ -0,0 +1,129 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* + * Modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +import React from 'react'; +import { i18n } from '@osd/i18n'; +import { TopNavMenuData } from '../../../../navigation/public'; +import { + OnSaveProps, + SavedObjectSaveModalOrigin, + showSaveModal, +} from '../../../../saved_objects/public'; +import { WizardServices } from '../..'; + +export const getTopNavconfig = ({ + savedObjects: { client: savedObjectsClient }, + toastNotifications, + i18n: { Context: I18nContext }, +}: WizardServices) => { + const topNavConfig: TopNavMenuData[] = [ + { + id: 'save', + iconType: 'save', + emphasize: true, + label: 'Save', + testId: 'wizardSaveButton', + run: (anchorElement) => { + const onSave = async ({ + // TODO: Figure out what the other props here do + newTitle, + newCopyOnSave, + isTitleDuplicateConfirmed, + onTitleDuplicate, + newDescription, + returnToOrigin, + }: OnSaveProps & { returnToOrigin: boolean }) => { + // TODO: Save the actual state of the wizard + const wizardSavedObject = await savedObjectsClient.create('wizard', { + title: newTitle, + description: newDescription, + state: JSON.stringify({}), + }); + + try { + const id = await wizardSavedObject.save(); + + if (id) { + toastNotifications.addSuccess({ + title: i18n.translate( + 'wizard.topNavMenu.saveVisualization.successNotificationText', + { + defaultMessage: `Saved '{visTitle}'`, + values: { + visTitle: newTitle, + }, + } + ), + 'data-test-subj': 'saveVisualizationSuccess', + }); + + return { id }; + } + + throw new Error('Saved but no id returned'); + } catch (error: any) { + // eslint-disable-next-line no-console + console.error(error); + + toastNotifications.addDanger({ + title: i18n.translate( + 'visualize.topNavMenu.saveVisualization.failureNotificationText', + { + defaultMessage: `Error on saving '{visTitle}'`, + values: { + visTitle: newTitle, + }, + } + ), + text: error.message, + 'data-test-subj': 'saveVisualizationError', + }); + return { error }; + } + }; + + const saveModal = ( + {}} + /> + ); + + showSaveModal(saveModal, I18nContext); + }, + }, + ]; + + return topNavConfig; +}; diff --git a/src/plugins/wizard/public/index.ts b/src/plugins/wizard/public/index.ts new file mode 100644 index 00000000000..884b83e7765 --- /dev/null +++ b/src/plugins/wizard/public/index.ts @@ -0,0 +1,13 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { WizardPlugin } from './plugin'; + +// This exports static code and TypeScript types, +// as well as, OpenSearch Dashboards Platform `plugin()` initializer. +export function plugin() { + return new WizardPlugin(); +} +export { WizardServices, WizardPluginStartDependencies } from './types'; diff --git a/src/plugins/wizard/public/plugin.ts b/src/plugins/wizard/public/plugin.ts new file mode 100644 index 00000000000..e8cbcbcac22 --- /dev/null +++ b/src/plugins/wizard/public/plugin.ts @@ -0,0 +1,55 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + AppMountParameters, + CoreSetup, + CoreStart, + DEFAULT_APP_CATEGORIES, + Plugin, +} from '../../../core/public'; +import { WizardPluginStartDependencies, WizardServices } from './types'; +import { PLUGIN_NAME } from '../common'; + +export class WizardPlugin implements Plugin { + public setup(core: CoreSetup) { + // Register an application into the side navigation menu + core.application.register({ + id: 'wizard', + title: PLUGIN_NAME, + euiIconType: 'inputOutput', + defaultPath: '#/', + category: DEFAULT_APP_CATEGORIES.opensearchDashboards, + async mount(params: AppMountParameters) { + // Load application bundle + const { renderApp } = await import('./application'); + // Get start services as specified in opensearch_dashboards.json + const [coreStart, pluginsStart] = await core.getStartServices(); + + const services: WizardServices = { + ...coreStart, + toastNotifications: coreStart.notifications.toasts, + data: pluginsStart.data, + savedObjectsPublic: pluginsStart.savedObjects, + navigation: pluginsStart.navigation, + setHeaderActionMenu: params.setHeaderActionMenu, + }; + + // make sure the index pattern list is up to date + pluginsStart.data.indexPatterns.clearCache(); + // make sure a default index pattern exists + // if not, the page will be redirected to management and visualize won't be rendered + await pluginsStart.data.indexPatterns.ensureDefaultIndexPattern(); + + // Render the application + return renderApp(params, services); + }, + }); + } + + public start(core: CoreStart) {} + + public stop() {} +} diff --git a/src/plugins/wizard/public/types.ts b/src/plugins/wizard/public/types.ts new file mode 100644 index 00000000000..f65246aeb1d --- /dev/null +++ b/src/plugins/wizard/public/types.ts @@ -0,0 +1,29 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { SavedObjectsStart } from 'src/plugins/saved_objects/public'; +import { AppMountParameters, CoreStart, ToastsStart } from 'opensearch-dashboards/public'; +import { EmbeddableSetup } from 'src/plugins/embeddable/public'; +import { DashboardStart } from 'src/plugins/dashboard/public'; +import { NavigationPublicPluginStart } from '../../navigation/public'; +import { DataPublicPluginStart } from '../../data/public'; + +export interface WizardPluginSetupDependencies { + embeddable: EmbeddableSetup; +} +export interface WizardPluginStartDependencies { + navigation: NavigationPublicPluginStart; + data: DataPublicPluginStart; + savedObjects: SavedObjectsStart; + dashboard: DashboardStart; +} + +export interface WizardServices extends CoreStart { + setHeaderActionMenu: AppMountParameters['setHeaderActionMenu']; + toastNotifications: ToastsStart; + savedObjectsPublic: SavedObjectsStart; + navigation: NavigationPublicPluginStart; + data: DataPublicPluginStart; +} diff --git a/src/plugins/wizard/public/visualizations/xy_chart.tsx b/src/plugins/wizard/public/visualizations/xy_chart.tsx new file mode 100644 index 00000000000..0215b31b2b4 --- /dev/null +++ b/src/plugins/wizard/public/visualizations/xy_chart.tsx @@ -0,0 +1,6 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +// TODO: This is where we register the visualizations using a registration service provided by the plugin diff --git a/src/plugins/wizard/server/index.ts b/src/plugins/wizard/server/index.ts new file mode 100644 index 00000000000..e995ea17b4a --- /dev/null +++ b/src/plugins/wizard/server/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { PluginInitializerContext } from '../../../core/server'; +import { WizardPlugin } from './plugin'; + +// This exports static code and TypeScript types, +// as well as, OpenSearch Dashboards Platform `plugin()` initializer. + +export function plugin(initializerContext: PluginInitializerContext) { + return new WizardPlugin(initializerContext); +} + +export { WizardPluginSetup, WizardPluginStart } from './types'; diff --git a/src/plugins/wizard/server/plugin.ts b/src/plugins/wizard/server/plugin.ts new file mode 100644 index 00000000000..d45e4081cce --- /dev/null +++ b/src/plugins/wizard/server/plugin.ts @@ -0,0 +1,44 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + PluginInitializerContext, + CoreSetup, + CoreStart, + Plugin, + Logger, +} from '../../../core/server'; + +import { WizardPluginSetup, WizardPluginStart } from './types'; +import { defineRoutes } from './routes'; +import { wizardApp } from './saved_objects'; + +export class WizardPlugin implements Plugin { + private readonly logger: Logger; + + constructor(initializerContext: PluginInitializerContext) { + this.logger = initializerContext.logger.get(); + } + + public setup({ http, savedObjects }: CoreSetup) { + this.logger.debug('wizard: Setup'); + const router = http.createRouter(); + + // Register server side APIs + defineRoutes(router); + + // Register saved object types + savedObjects.registerType(wizardApp); + + return {}; + } + + public start(core: CoreStart) { + this.logger.debug('wizard: Started'); + return {}; + } + + public stop() {} +} diff --git a/src/plugins/wizard/server/routes/index.ts b/src/plugins/wizard/server/routes/index.ts new file mode 100644 index 00000000000..f6268695e83 --- /dev/null +++ b/src/plugins/wizard/server/routes/index.ts @@ -0,0 +1,22 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { IRouter } from '../../../../core/server'; + +export function defineRoutes(router: IRouter) { + router.get( + { + path: '/api/wizard/example', + validate: false, + }, + async (context, request, response) => { + return response.ok({ + body: { + time: new Date().toISOString(), + }, + }); + } + ); +} diff --git a/src/plugins/wizard/server/saved_objects/index.ts b/src/plugins/wizard/server/saved_objects/index.ts new file mode 100644 index 00000000000..aa90fcea911 --- /dev/null +++ b/src/plugins/wizard/server/saved_objects/index.ts @@ -0,0 +1,6 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export { wizardApp } from './wizard_app'; diff --git a/src/plugins/wizard/server/saved_objects/wizard_app.ts b/src/plugins/wizard/server/saved_objects/wizard_app.ts new file mode 100644 index 00000000000..138bea03b22 --- /dev/null +++ b/src/plugins/wizard/server/saved_objects/wizard_app.ts @@ -0,0 +1,36 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { SavedObjectsType } from 'src/core/server'; +import { WIZARD_SAVED_OBJECT } from '../../common'; + +export const wizardApp: SavedObjectsType = { + name: WIZARD_SAVED_OBJECT, + hidden: false, + namespaceType: 'single', + management: { + icon: 'visVisualBuilder', // TODO: Need a custom icon here + defaultSearchField: 'title', + importableAndExportable: true, + getTitle: (obj: { attributes: { title: string } }) => obj.attributes.title, + // getInAppUrl: TODO: Enable once editing is supported + }, + migrations: {}, + mappings: { + properties: { + title: { + type: 'text', + }, + description: { + type: 'text', + }, + // TODO: Determine what needs to be pulled out of state and added directly into the mapping + state: { + type: 'text', + index: false, + }, + }, + }, +}; diff --git a/src/plugins/wizard/server/types.ts b/src/plugins/wizard/server/types.ts new file mode 100644 index 00000000000..5d26185a037 --- /dev/null +++ b/src/plugins/wizard/server/types.ts @@ -0,0 +1,9 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface WizardPluginSetup {} +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface WizardPluginStart {} From 5b1d2f76de485dd62074793b9c63d2a8c5344f42 Mon Sep 17 00:00:00 2001 From: Ashwin Pc Date: Tue, 23 Nov 2021 18:34:19 +0000 Subject: [PATCH 2/2] Fixes typos and layout css Signed-off-by: Ashwin Pc --- .../application/components/data_tab/field_selector.scss | 2 +- .../wizard/public/application/components/workspace.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/wizard/public/application/components/data_tab/field_selector.scss b/src/plugins/wizard/public/application/components/data_tab/field_selector.scss index fc6749215e6..c05f75457b0 100644 --- a/src/plugins/wizard/public/application/components/data_tab/field_selector.scss +++ b/src/plugins/wizard/public/application/components/data_tab/field_selector.scss @@ -1,7 +1,7 @@ @import "../util"; .wizFieldSelector { - @include scrollNavParent; + @include scrollNavParent(auto 1fr); padding: $euiSizeS; } diff --git a/src/plugins/wizard/public/application/components/workspace.tsx b/src/plugins/wizard/public/application/components/workspace.tsx index b944682db56..a83201be4cc 100644 --- a/src/plugins/wizard/public/application/components/workspace.tsx +++ b/src/plugins/wizard/public/application/components/workspace.tsx @@ -13,7 +13,7 @@ export const Workspace: FC = ({ children }) => {
- {/* TODO: This is the teporary view of the selected chard, should be replaced by dropdown */} + {/* TODO: This is the temporary view of the selected chard, should be replaced by dropdown */} Bar @@ -27,7 +27,7 @@ export const Workspace: FC = ({ children }) => { Welcome to the wizard!} - body={

Drag some fileds onto the panel to visualize some data.

} + body={

Drag some fields onto the panel to visualize some data.

} />
)}