From 7462baaabf4afff2279569b63690235732876fbe Mon Sep 17 00:00:00 2001
From: scottybollinger
Date: Tue, 24 Nov 2020 12:51:56 -0600
Subject: [PATCH 01/11] Initial copy/paste of components
Changes for pre-commit hooks were:
- Linting
- Lodash imports
- Fixed warnings for `jsx-a11y/mouse-events-have-key-events` with stubbed onFocus and onBlue events with FIXME comments
---
.../display_settings/custom_source_icon.tsx | 36 ++
.../display_settings/display_settings.tsx | 137 ++++++++
.../display_settings_logic.ts | 332 ++++++++++++++++++
.../display_settings_router.tsx | 31 +-
.../example_result_detail_card.tsx | 75 ++++
.../example_search_result_group.tsx | 74 ++++
.../example_standout_result.tsx | 66 ++++
.../display_settings/field_editor_modal.tsx | 101 ++++++
.../components/display_settings/index.ts | 2 +-
.../display_settings/result_detail.tsx | 146 ++++++++
.../display_settings/search_results.tsx | 162 +++++++++
.../display_settings/subtitle_field.tsx | 35 ++
.../display_settings/title_field.tsx | 35 ++
13 files changed, 1230 insertions(+), 2 deletions(-)
create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/custom_source_icon.tsx
create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings.tsx
create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_logic.ts
create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_result_detail_card.tsx
create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_search_result_group.tsx
create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_standout_result.tsx
create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/field_editor_modal.tsx
create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/result_detail.tsx
create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/search_results.tsx
create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/subtitle_field.tsx
create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/title_field.tsx
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/custom_source_icon.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/custom_source_icon.tsx
new file mode 100644
index 0000000000000..16129324b56d1
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/custom_source_icon.tsx
@@ -0,0 +1,36 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+
+const BLACK_RGB = '#000';
+
+interface CustomSourceIconProps {
+ color?: string;
+}
+
+export const CustomSourceIcon: React.FC = ({ color = BLACK_RGB }) => (
+
+);
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings.tsx
new file mode 100644
index 0000000000000..518704acabaaa
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings.tsx
@@ -0,0 +1,137 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React, { useEffect } from 'react';
+
+import { History } from 'history';
+import { useActions, useValues } from 'kea';
+import { useHistory } from 'react-router-dom';
+
+import { EuiButton, EuiEmptyPrompt, EuiTabbedContent, EuiPanel } from '@elastic/eui';
+
+import {
+ DISPLAY_SETTINGS_RESULT_DETAIL_PATH,
+ DISPLAY_SETTINGS_SEARCH_RESULT_PATH,
+ getContentSourcePath,
+} from 'workplace_search/utils/routePaths';
+
+import { AppLogic } from 'workplace_search/App/AppLogic';
+
+import FlashMessages from 'shared/components/FlashMessages';
+
+import { Loading, ViewContentHeader } from 'workplace_search/components';
+import { DisplaySettingsLogic } from './DisplaySettingsLogic';
+
+import { FieldEditorModal } from './FieldEditorModal';
+import { ResultDetail } from './ResultDetail';
+import { SearchResults } from './SearchResults';
+
+const UNSAVED_MESSAGE =
+ 'Your display settings have not been saved. Are you sure you want to leave?';
+
+interface DisplaySettingsProps {
+ tabId: number;
+}
+
+export const DisplaySettings: React.FC = ({ tabId }) => {
+ const history = useHistory() as History;
+ const { initializeDisplaySettings, setServerData, resetDisplaySettingsState } = useActions(
+ DisplaySettingsLogic
+ );
+
+ const {
+ dataLoading,
+ flashMessages,
+ sourceId,
+ addFieldModalVisible,
+ unsavedChanges,
+ exampleDocuments,
+ } = useValues(DisplaySettingsLogic);
+
+ const { isOrganization } = useValues(AppLogic);
+
+ const hasDocuments = exampleDocuments.length > 0;
+
+ useEffect(() => {
+ initializeDisplaySettings();
+ return resetDisplaySettingsState;
+ }, []);
+
+ useEffect(() => {
+ window.onbeforeunload = hasDocuments && unsavedChanges ? () => UNSAVED_MESSAGE : null;
+ return () => {
+ window.onbeforeunload = null;
+ };
+ }, [unsavedChanges]);
+
+ if (dataLoading) return ;
+
+ const tabs = [
+ {
+ id: 'search_results',
+ name: 'Search Results',
+ disabled: false,
+ content: ,
+ },
+ {
+ id: 'result_detail',
+ name: 'Result Detail',
+ disabled: false,
+ content: ,
+ },
+ ];
+
+ const onSelectedTabChanged = (tab) => {
+ const path =
+ tab.id === tabs[1].id
+ ? getContentSourcePath(DISPLAY_SETTINGS_RESULT_DETAIL_PATH, sourceId, isOrganization)
+ : getContentSourcePath(DISPLAY_SETTINGS_SEARCH_RESULT_PATH, sourceId, isOrganization);
+
+ history.push(path);
+ };
+
+ const handleFormSubmit = (e) => {
+ e.preventDefault();
+ setServerData();
+ };
+
+ return (
+ <>
+
+ {addFieldModalVisible && }
+ >
+ );
+};
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_logic.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_logic.ts
new file mode 100644
index 0000000000000..b6d7c20233709
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_logic.ts
@@ -0,0 +1,332 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { cloneDeep, isEqual, differenceBy } from 'lodash';
+import { DropResult } from 'react-beautiful-dnd';
+
+import { kea, MakeLogicType } from 'kea';
+import http from 'shared/http';
+
+import { euiSelectObjectFromValue } from 'shared/utils';
+import routes from 'workplace_search/routes';
+
+import { AppLogic } from 'workplace_search/App/AppLogic';
+import { SourceLogic } from 'workplace_search/ContentSources/SourceLogic';
+
+const SUCCESS_MESSAGE = 'Display Settings have been successfuly updated.';
+
+import { IFlashMessagesProps } from 'shared/types';
+import { IObject, DetailField, SearchResultConfig, OptionValue } from 'workplace_search/types';
+
+export interface DisplaySettingsResponseProps {
+ sourceName: string;
+ searchResultConfig: SearchResultConfig;
+ schemaFields: IObject;
+ exampleDocuments: IObject[];
+}
+
+export interface DisplaySettingsInitialData extends DisplaySettingsResponseProps {
+ sourceId: string;
+ serverRoute: string;
+}
+
+interface DisplaySettingsActions {
+ initializeDisplaySettings(): void;
+ setServerData(): void;
+ onInitializeDisplaySettings(
+ displaySettingsProps: DisplaySettingsInitialData
+ ): DisplaySettingsInitialData;
+ setServerResponseData(
+ displaySettingsProps: DisplaySettingsResponseProps
+ ): DisplaySettingsResponseProps;
+ setFlashMessages(flashMessages: IFlashMessagesProps): { flashMessages: IFlashMessagesProps };
+ setTitleField(titleField: string | null): string | null;
+ setUrlField(urlField: string): string;
+ setSubtitleField(subtitleField: string | null): string | null;
+ setDescriptionField(descriptionField: string | null): string | null;
+ setColorField(hex: string);
+ setDetailFields(result: DropResult);
+ openEditDetailField(editFieldIndex: number | null);
+ removeDetailField(index: number);
+ addDetailField(newField: DetailField);
+ updateDetailField(updatedField: DetailField, index: number | null);
+ toggleFieldEditorModal(): void;
+ toggleTitleFieldHover(): void;
+ toggleSubtitleFieldHover(): void;
+ toggleDescriptionFieldHover(): void;
+ toggleUrlFieldHover(): void;
+ resetDisplaySettingsState(): void;
+}
+
+interface DisplaySettingsValues {
+ sourceName: string;
+ sourceId: string;
+ schemaFields: IObject;
+ exampleDocuments: IObject[];
+ serverSearchResultConfig: SearchResultConfig;
+ searchResultConfig: SearchResultConfig;
+ serverRoute: string;
+ flashMessages: IFlashMessagesProps;
+ editFieldIndex: number | null;
+ dataLoading: boolean;
+ addFieldModalVisible: boolean;
+ titleFieldHover: boolean;
+ urlFieldHover: boolean;
+ subtitleFieldHover: boolean;
+ descriptionFieldHover: boolean;
+ fieldOptions: OptionValue[];
+ optionalFieldOptions: OptionValue[];
+ availableFieldOptions: OptionValue[];
+ unsavedChanges: boolean;
+}
+
+const defaultSearchResultConfig = {
+ titleField: '',
+ subtitleField: '',
+ descriptionField: '',
+ urlField: '',
+ color: '#000000',
+ detailFields: [],
+};
+
+export const DisplaySettingsLogic = kea<
+ MakeLogicType
+>({
+ actions: {
+ onInitializeDisplaySettings: (displaySettingsProps: DisplaySettingsInitialData) =>
+ displaySettingsProps,
+ setServerResponseData: (displaySettingsProps: DisplaySettingsResponseProps) =>
+ displaySettingsProps,
+ setFlashMessages: (flashMessages: IFlashMessagesProps) => ({ flashMessages }),
+ setTitleField: (titleField: string) => titleField,
+ setUrlField: (urlField: string) => urlField,
+ setSubtitleField: (subtitleField: string | null) => subtitleField,
+ setDescriptionField: (descriptionField: string) => descriptionField,
+ setColorField: (hex: string) => hex,
+ setDetailFields: (result: DropResult) => ({ result }),
+ openEditDetailField: (editFieldIndex: number | null) => editFieldIndex,
+ removeDetailField: (index: number) => index,
+ addDetailField: (newField: DetailField) => newField,
+ updateDetailField: (updatedField: DetailField, index: number) => ({ updatedField, index }),
+ toggleFieldEditorModal: () => true,
+ toggleTitleFieldHover: () => true,
+ toggleSubtitleFieldHover: () => true,
+ toggleDescriptionFieldHover: () => true,
+ toggleUrlFieldHover: () => true,
+ resetDisplaySettingsState: () => true,
+ initializeDisplaySettings: () => true,
+ setServerData: () => true,
+ },
+ reducers: {
+ sourceName: [
+ '',
+ {
+ onInitializeDisplaySettings: (_, { sourceName }) => sourceName,
+ },
+ ],
+ sourceId: [
+ '',
+ {
+ onInitializeDisplaySettings: (_, { sourceId }) => sourceId,
+ },
+ ],
+ schemaFields: [
+ {},
+ {
+ onInitializeDisplaySettings: (_, { schemaFields }) => schemaFields,
+ },
+ ],
+ exampleDocuments: [
+ [],
+ {
+ onInitializeDisplaySettings: (_, { exampleDocuments }) => exampleDocuments,
+ },
+ ],
+ serverSearchResultConfig: [
+ defaultSearchResultConfig,
+ {
+ onInitializeDisplaySettings: (_, { searchResultConfig }) =>
+ setDefaultColor(searchResultConfig),
+ setServerResponseData: (_, { searchResultConfig }) => searchResultConfig,
+ },
+ ],
+ searchResultConfig: [
+ defaultSearchResultConfig,
+ {
+ onInitializeDisplaySettings: (_, { searchResultConfig }) =>
+ setDefaultColor(searchResultConfig),
+ setServerResponseData: (_, { searchResultConfig }) => searchResultConfig,
+ setTitleField: (searchResultConfig, titleField) => ({ ...searchResultConfig, titleField }),
+ setSubtitleField: (searchResultConfig, subtitleField) => ({
+ ...searchResultConfig,
+ subtitleField,
+ }),
+ setUrlField: (searchResultConfig, urlField) => ({ ...searchResultConfig, urlField }),
+ setDescriptionField: (searchResultConfig, descriptionField) => ({
+ ...searchResultConfig,
+ descriptionField,
+ }),
+ setColorField: (searchResultConfig, color) => ({ ...searchResultConfig, color }),
+ setDetailFields: (searchResultConfig, { result: { destination, source } }) => {
+ const detailFields = cloneDeep(searchResultConfig.detailFields);
+ const element = detailFields[source.index];
+ detailFields.splice(source.index, 1);
+ detailFields.splice(destination.index, 0, element);
+ return {
+ ...searchResultConfig,
+ detailFields,
+ };
+ },
+ addDetailField: (searchResultConfig, newfield) => {
+ const detailFields = cloneDeep(searchResultConfig.detailFields);
+ detailFields.push(newfield);
+ return {
+ ...searchResultConfig,
+ detailFields,
+ };
+ },
+ removeDetailField: (searchResultConfig, index) => {
+ const detailFields = cloneDeep(searchResultConfig.detailFields);
+ detailFields.splice(index, 1);
+ return {
+ ...searchResultConfig,
+ detailFields,
+ };
+ },
+ updateDetailField: (searchResultConfig, { updatedField, index }) => {
+ const detailFields = cloneDeep(searchResultConfig.detailFields);
+ detailFields[index] = updatedField;
+ return {
+ ...searchResultConfig,
+ detailFields,
+ };
+ },
+ },
+ ],
+ serverRoute: [
+ '',
+ {
+ onInitializeDisplaySettings: (_, { serverRoute }) => serverRoute,
+ },
+ ],
+ flashMessages: [
+ {},
+ {
+ setServerResponseData: () => ({ success: [SUCCESS_MESSAGE] }),
+ setFlashMessages: (_, { flashMessages }) => flashMessages,
+ toggleFieldEditorModal: () => ({}),
+ resetDisplaySettingsState: () => ({}),
+ },
+ ],
+ editFieldIndex: [
+ null,
+ {
+ openEditDetailField: (_, openEditDetailField) => openEditDetailField,
+ toggleFieldEditorModal: () => null,
+ },
+ ],
+ dataLoading: [
+ true,
+ {
+ onInitializeDisplaySettings: () => false,
+ },
+ ],
+ addFieldModalVisible: [
+ false,
+ {
+ toggleFieldEditorModal: (addFieldModalVisible) => !addFieldModalVisible,
+ openEditDetailField: () => true,
+ updateDetailField: () => false,
+ addDetailField: () => false,
+ },
+ ],
+ titleFieldHover: [
+ false,
+ {
+ toggleTitleFieldHover: (titleFieldHover) => !titleFieldHover,
+ },
+ ],
+ urlFieldHover: [
+ false,
+ {
+ toggleUrlFieldHover: (urlFieldHover) => !urlFieldHover,
+ },
+ ],
+ subtitleFieldHover: [
+ false,
+ {
+ toggleSubtitleFieldHover: (subtitleFieldHover) => !subtitleFieldHover,
+ },
+ ],
+ descriptionFieldHover: [
+ false,
+ {
+ toggleDescriptionFieldHover: (addFieldModalVisible) => !addFieldModalVisible,
+ },
+ ],
+ },
+ selectors: ({ selectors }) => ({
+ fieldOptions: [
+ () => [selectors.schemaFields],
+ (schemaFields) => Object.keys(schemaFields).map(euiSelectObjectFromValue),
+ ],
+ optionalFieldOptions: [
+ () => [selectors.fieldOptions],
+ (fieldOptions) => {
+ const optionalFieldOptions = cloneDeep(fieldOptions);
+ optionalFieldOptions.unshift({ value: '', text: '' });
+ return optionalFieldOptions;
+ },
+ ],
+ // We don't want to let the user add a duplicate detailField.
+ availableFieldOptions: [
+ () => [selectors.fieldOptions, selectors.searchResultConfig],
+ (fieldOptions, { detailFields }) => {
+ const usedFields = detailFields.map((usedField) =>
+ euiSelectObjectFromValue(usedField.fieldName)
+ );
+ return differenceBy(fieldOptions, usedFields, 'value');
+ },
+ ],
+ unsavedChanges: [
+ () => [selectors.searchResultConfig, selectors.serverSearchResultConfig],
+ (uiConfig, serverConfig) => !isEqual(uiConfig, serverConfig),
+ ],
+ }),
+ listeners: ({ actions, values }) => ({
+ initializeDisplaySettings: () => {
+ const { isOrganization } = AppLogic.values;
+ const {
+ contentSource: { id: sourceId },
+ } = SourceLogic.values;
+
+ const serverRoute = isOrganization
+ ? routes.fritoPieOrganizationContentSourceDisplaySettingsConfigPath(sourceId)
+ : routes.fritoPieAccountContentSourceDisplaySettingsConfigPath(sourceId);
+
+ http(serverRoute).then(({ data }) =>
+ actions.onInitializeDisplaySettings({ isOrganization, sourceId, serverRoute, ...data })
+ );
+ },
+ setServerData: () => {
+ const { searchResultConfig, serverRoute } = values;
+ http
+ .post(serverRoute, searchResultConfig)
+ .then(({ data }) => actions.setServerResponseData(data))
+ .catch(({ response }) => actions.setFlashMessages({ error: response.data.errors }));
+ },
+ }),
+});
+
+// By default, the color is `null` on the server. The color is a required field and the
+// EuiColorPicker components doesn't allow the field to be required so the form can be
+// submitted with no color and this results in a server error. The default should be black
+// and this allows the `searchResultConfig` and the `serverSearchResultConfig` reducers to
+// stay synced on initialization.
+const setDefaultColor = (searchResultConfig) => ({
+ ...searchResultConfig,
+ color: searchResultConfig.color || '#000000',
+});
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_router.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_router.tsx
index 5cebaad95e3a8..1283b0359adb7 100644
--- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_router.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_router.tsx
@@ -6,4 +6,33 @@
import React from 'react';
-export const DisplaySettingsRouter: React.FC = () => <>Display Settings Placeholder>;
+import { useValues } from 'kea';
+import { Route, Switch } from 'react-router-dom';
+
+import { AppLogic } from 'workplace_search/App/AppLogic';
+
+import {
+ DISPLAY_SETTINGS_RESULT_DETAIL_PATH,
+ DISPLAY_SETTINGS_SEARCH_RESULT_PATH,
+ getSourcesPath,
+} from 'workplace_search/utils/routePaths';
+
+import { DisplaySettings } from './DisplaySettings';
+
+export const DisplaySettingsRouter: React.FC = () => {
+ const { isOrganization } = useValues(AppLogic);
+ return (
+
+ }
+ />
+ }
+ />
+
+ );
+};
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_result_detail_card.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_result_detail_card.tsx
new file mode 100644
index 0000000000000..1a7a6e346fc62
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_result_detail_card.tsx
@@ -0,0 +1,75 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+
+import classNames from 'classnames';
+import { useValues } from 'kea';
+
+import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiText, EuiTitle } from '@elastic/eui';
+
+import { DisplaySettingsLogic } from './DisplaySettingsLogic';
+
+import { CustomSourceIcon } from './CustomSourceIcon';
+import { TitleField } from './TitleField';
+
+export const ExampleResultDetailCard: React.FC = () => {
+ const {
+ sourceName,
+ searchResultConfig: { titleField, urlField, color, detailFields },
+ titleFieldHover,
+ urlFieldHover,
+ exampleDocuments,
+ } = useValues(DisplaySettingsLogic);
+
+ const result = exampleDocuments[0];
+
+ return (
+
+
+
+
+
+
+
+
+ {sourceName}
+
+
+
+
+
+ {urlField ? (
+
{result[urlField]}
+ ) : (
+
URL
+ )}
+
+
+
+
+ {detailFields.length > 0 ? (
+ detailFields.map(({ fieldName, label }, index) => (
+
+
+ {label}
+
+
+ {result[fieldName]}
+
+
+ ))
+ ) : (
+
+ )}
+
+
+ );
+};
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_search_result_group.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_search_result_group.tsx
new file mode 100644
index 0000000000000..0749a7507f09a
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_search_result_group.tsx
@@ -0,0 +1,74 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+
+import { isColorDark, hexToRgb } from '@elastic/eui';
+import classNames from 'classnames';
+import { useValues } from 'kea';
+
+import { DisplaySettingsLogic } from './DisplaySettingsLogic';
+
+import { CustomSourceIcon } from './CustomSourceIcon';
+import { SubtitleField } from './SubtitleField';
+import { TitleField } from './TitleField';
+
+export const ExampleSearchResultGroup: React.FC = () => {
+ const {
+ sourceName,
+ searchResultConfig: { titleField, subtitleField, descriptionField, color },
+ titleFieldHover,
+ subtitleFieldHover,
+ descriptionFieldHover,
+ exampleDocuments,
+ } = useValues(DisplaySettingsLogic);
+
+ return (
+
+
+
+
+ {sourceName}
+
+
+
+
+
+ {exampleDocuments.map((result, id) => (
+
+
+
+
+
+ {descriptionField ? (
+
{result[descriptionField]}
+ ) : (
+
Description
+ )}
+
+
+
+ ))}
+
+
+
+ );
+};
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_standout_result.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_standout_result.tsx
new file mode 100644
index 0000000000000..1d04302aef331
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_standout_result.tsx
@@ -0,0 +1,66 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+
+import classNames from 'classnames';
+import { useValues } from 'kea';
+
+import { isColorDark, hexToRgb } from '@elastic/eui';
+
+import { DisplaySettingsLogic } from './DisplaySettingsLogic';
+
+import { CustomSourceIcon } from './CustomSourceIcon';
+import { SubtitleField } from './SubtitleField';
+import { TitleField } from './TitleField';
+
+export const ExampleStandoutResult: React.FC = () => {
+ const {
+ sourceName,
+ searchResultConfig: { titleField, subtitleField, descriptionField, color },
+ titleFieldHover,
+ subtitleFieldHover,
+ descriptionFieldHover,
+ exampleDocuments,
+ } = useValues(DisplaySettingsLogic);
+
+ const result = exampleDocuments[0];
+
+ return (
+
+
+
+
+ {sourceName}
+
+
+
+
+
+
+
+ {descriptionField ? (
+ {result[descriptionField]}
+ ) : (
+ Description
+ )}
+
+
+
+
+ );
+};
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/field_editor_modal.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/field_editor_modal.tsx
new file mode 100644
index 0000000000000..34d7ff8ecbf97
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/field_editor_modal.tsx
@@ -0,0 +1,101 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React, { useState } from 'react';
+
+import { useActions, useValues } from 'kea';
+
+import {
+ EuiButton,
+ EuiButtonEmpty,
+ EuiFieldText,
+ EuiForm,
+ EuiFormRow,
+ EuiModal,
+ EuiModalBody,
+ EuiModalFooter,
+ EuiModalHeader,
+ EuiModalHeaderTitle,
+ EuiOverlayMask,
+ EuiSelect,
+} from '@elastic/eui';
+
+import { DisplaySettingsLogic } from './DisplaySettingsLogic';
+
+const emptyField = { fieldName: '', label: '' };
+
+export const FieldEditorModal: React.FC = () => {
+ const { toggleFieldEditorModal, addDetailField, updateDetailField } = useActions(
+ DisplaySettingsLogic
+ );
+
+ const {
+ searchResultConfig: { detailFields },
+ availableFieldOptions,
+ fieldOptions,
+ editFieldIndex,
+ } = useValues(DisplaySettingsLogic);
+
+ const isEditing = editFieldIndex || editFieldIndex === 0;
+ const field = isEditing ? detailFields[editFieldIndex || 0] : emptyField;
+ const [fieldName, setName] = useState(field.fieldName || '');
+ const [label, setLabel] = useState(field.label || '');
+
+ const handleSubmit = (e) => {
+ e.preventDefault();
+ if (isEditing) {
+ updateDetailField({ fieldName, label }, editFieldIndex);
+ } else {
+ addDetailField({ fieldName, label });
+ }
+ };
+
+ const ACTION_LABEL = isEditing ? 'Update' : 'Add';
+
+ return (
+
+
+
+ );
+};
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/index.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/index.ts
index f8c6834db7805..cbe699af22d61 100644
--- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/index.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/index.ts
@@ -4,4 +4,4 @@
* you may not use this file except in compliance with the Elastic License.
*/
-export { DisplaySettingsRouter } from './display_settings_router';
+export { DisplaySettingsRouter } from './DisplaySettingsRouter';
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/result_detail.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/result_detail.tsx
new file mode 100644
index 0000000000000..0bf48bce755e2
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/result_detail.tsx
@@ -0,0 +1,146 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+
+import { useActions, useValues } from 'kea';
+
+import {
+ EuiButtonEmpty,
+ EuiButtonIcon,
+ EuiDragDropContext,
+ EuiDraggable,
+ EuiDroppable,
+ EuiFlexGrid,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiForm,
+ EuiFormRow,
+ EuiIcon,
+ EuiPanel,
+ EuiSpacer,
+ EuiTextColor,
+ EuiTitle,
+} from '@elastic/eui';
+
+import { DisplaySettingsLogic } from './DisplaySettingsLogic';
+
+import { ExampleResultDetailCard } from './ExampleResultDetailCard';
+
+export const ResultDetail: React.FC = () => {
+ const {
+ toggleFieldEditorModal,
+ setDetailFields,
+ openEditDetailField,
+ removeDetailField,
+ } = useActions(DisplaySettingsLogic);
+
+ const {
+ searchResultConfig: { detailFields },
+ availableFieldOptions,
+ } = useValues(DisplaySettingsLogic);
+
+ return (
+ <>
+
+
+
+
+
+
+ <>
+
+
+
+ Visible Fields
+
+
+
+
+ Add Field
+
+
+
+
+ {detailFields.length > 0 ? (
+
+
+ <>
+ {detailFields.map(({ fieldName, label }, index) => (
+
+ {(provided) => (
+
+
+
+
+
+
+
+
+
+ {fieldName}
+
+
+ “{label || ''}”
+
+
+
+
+ openEditDetailField(index)}
+ />
+ removeDetailField(index)}
+ />
+
+
+
+
+ )}
+
+ ))}
+ >
+
+
+ ) : (
+ Add fields and move them into the order you want them to appear.
+ )}
+ >
+
+
+
+
+
+
+ Preview
+
+
+
+
+
+
+ >
+ );
+};
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/search_results.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/search_results.tsx
new file mode 100644
index 0000000000000..0ca96daef0eb9
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/search_results.tsx
@@ -0,0 +1,162 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+
+import { useActions, useValues } from 'kea';
+
+import {
+ EuiColorPicker,
+ EuiFlexGrid,
+ EuiFlexItem,
+ EuiForm,
+ EuiFormRow,
+ EuiPanel,
+ EuiSelect,
+ EuiSpacer,
+ EuiTitle,
+} from '@elastic/eui';
+
+import { DisplaySettingsLogic } from './DisplaySettingsLogic';
+
+import { ExampleSearchResultGroup } from './ExampleSearchResultGroup';
+import { ExampleStandoutResult } from './ExampleStandoutResult';
+
+export const SearchResults: React.FC = () => {
+ const {
+ toggleTitleFieldHover,
+ toggleSubtitleFieldHover,
+ toggleDescriptionFieldHover,
+ setTitleField,
+ setSubtitleField,
+ setDescriptionField,
+ setUrlField,
+ setColorField,
+ } = useActions(DisplaySettingsLogic);
+
+ const {
+ searchResultConfig: { titleField, descriptionField, subtitleField, urlField, color },
+ fieldOptions,
+ optionalFieldOptions,
+ } = useValues(DisplaySettingsLogic);
+
+ return (
+ <>
+
+
+
+
+
+ Search Result Settings
+
+
+
+ null} // FIXME
+ onBlur={() => null} // FIXME
+ >
+ setTitleField(e.target.value)}
+ />
+
+
+ setUrlField(e.target.value)}
+ />
+
+
+ null} // FIXME
+ onBlur={() => null} // FIXME
+ />
+
+ null} // FIXME
+ onBlur={() => null} // FIXME
+ >
+ setSubtitleField(value === '' ? null : value)}
+ />
+
+ null} // FIXME
+ onBlur={() => null} // FIXME
+ >
+
+ setDescriptionField(value === '' ? null : value)
+ }
+ />
+
+
+
+
+
+
+ Preview
+
+
+
+
+ Featured Results
+
+
+ A matching document will appear as a single bold card.
+
+
+
+
+
+
+ Standard Results
+
+
+ Somewhat matching documents will appear as a set.
+
+
+
+
+
+
+ >
+ );
+};
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/subtitle_field.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/subtitle_field.tsx
new file mode 100644
index 0000000000000..7376e0df6374a
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/subtitle_field.tsx
@@ -0,0 +1,35 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+
+import classNames from 'classnames';
+
+import { IObject } from 'workplace_search/types';
+
+interface SubtitleFieldProps {
+ result: IObject;
+ subtitleField: string | null;
+ subtitleFieldHover: boolean;
+}
+
+export const SubtitleField: React.FC = ({
+ result,
+ subtitleField,
+ subtitleFieldHover,
+}) => (
+
+ {subtitleField ? (
+
{result[subtitleField]}
+ ) : (
+
Subtitle
+ )}
+
+);
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/title_field.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/title_field.tsx
new file mode 100644
index 0000000000000..234bedf3db29d
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/title_field.tsx
@@ -0,0 +1,35 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+
+import classNames from 'classnames';
+
+import { IObject } from 'workplace_search/types';
+
+interface TitleFieldProps {
+ result: IObject;
+ titleField: string | null;
+ titleFieldHover: boolean;
+}
+
+export const TitleField: React.FC = ({ result, titleField, titleFieldHover }) => {
+ const title = titleField ? result[titleField] : '';
+ const titleDisplay = Array.isArray(title) ? title.join(', ') : title;
+ return (
+
+ {titleField ? (
+
{titleDisplay}
+ ) : (
+
Title
+ )}
+
+ );
+};
From 3a08fa75599ca346189c07315f03713aa71757a0 Mon Sep 17 00:00:00 2001
From: scottybollinger
Date: Tue, 24 Nov 2020 13:49:34 -0600
Subject: [PATCH 02/11] Add server routes
---
.../routes/workplace_search/sources.test.ts | 152 ++++++++++++++++++
.../server/routes/workplace_search/sources.ts | 100 ++++++++++++
2 files changed, 252 insertions(+)
diff --git a/x-pack/plugins/enterprise_search/server/routes/workplace_search/sources.test.ts b/x-pack/plugins/enterprise_search/server/routes/workplace_search/sources.test.ts
index 22e2deaace1dc..62f4dceeac363 100644
--- a/x-pack/plugins/enterprise_search/server/routes/workplace_search/sources.test.ts
+++ b/x-pack/plugins/enterprise_search/server/routes/workplace_search/sources.test.ts
@@ -18,6 +18,7 @@ import {
registerAccountPreSourceRoute,
registerAccountPrepareSourcesRoute,
registerAccountSourceSearchableRoute,
+ registerAccountSourceDisplaySettingsConfig,
registerOrgSourcesRoute,
registerOrgSourcesStatusRoute,
registerOrgSourceRoute,
@@ -29,6 +30,7 @@ import {
registerOrgPreSourceRoute,
registerOrgPrepareSourcesRoute,
registerOrgSourceSearchableRoute,
+ registerOrgSourceDisplaySettingsConfig,
registerOrgSourceOauthConfigurationsRoute,
registerOrgSourceOauthConfigurationRoute,
} from './sources';
@@ -446,6 +448,81 @@ describe('sources routes', () => {
});
});
+ describe('GET /api/workplace_search/account/sources/{id}/display_settings/config', () => {
+ let mockRouter: MockRouter;
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ it('creates a request handler', () => {
+ mockRouter = new MockRouter({
+ method: 'get',
+ path: '/api/workplace_search/account/sources/{id}/display_settings/config',
+ payload: 'params',
+ });
+
+ registerAccountSourceDisplaySettingsConfig({
+ ...mockDependencies,
+ router: mockRouter.router,
+ });
+
+ const mockRequest = {
+ params: {
+ id: '123',
+ },
+ };
+
+ mockRouter.callRoute(mockRequest);
+
+ expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({
+ path: '/ws/sources/123/display_settings/config',
+ });
+ });
+ });
+
+ describe('POST /api/workplace_search/account/sources/{id}/display_settings/config', () => {
+ let mockRouter: MockRouter;
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ mockRouter = new MockRouter({
+ method: 'post',
+ path: '/api/workplace_search/account/sources/{id}/display_settings/config',
+ payload: 'body',
+ });
+
+ registerAccountSourceDisplaySettingsConfig({
+ ...mockDependencies,
+ router: mockRouter.router,
+ });
+ });
+
+ it('creates a request handler', () => {
+ const mockRequest = {
+ params: { id: '123' },
+ body: {
+ titleField: 'foo',
+ subtitleField: 'bar',
+ descriptionField: 'this is a thing',
+ urlField: 'http://youknowfor.search',
+ color: '#aaa',
+ detailFields: {
+ fieldName: 'myField',
+ label: 'My Field',
+ },
+ },
+ };
+
+ mockRouter.callRoute(mockRequest);
+
+ expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({
+ path: '/ws/sources/123/display_settings/config',
+ body: mockRequest.body,
+ });
+ });
+ });
+
describe('GET /api/workplace_search/org/sources', () => {
let mockRouter: MockRouter;
@@ -848,6 +925,81 @@ describe('sources routes', () => {
});
});
+ describe('GET /api/workplace_search/org/sources/{id}/display_settings/config', () => {
+ let mockRouter: MockRouter;
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ it('creates a request handler', () => {
+ mockRouter = new MockRouter({
+ method: 'get',
+ path: '/api/workplace_search/org/sources/{id}/display_settings/config',
+ payload: 'params',
+ });
+
+ registerOrgSourceDisplaySettingsConfig({
+ ...mockDependencies,
+ router: mockRouter.router,
+ });
+
+ const mockRequest = {
+ params: {
+ id: '123',
+ },
+ };
+
+ mockRouter.callRoute(mockRequest);
+
+ expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({
+ path: '/ws/org/sources/123/display_settings/config',
+ });
+ });
+ });
+
+ describe('POST /api/workplace_search/org/sources/{id}/display_settings/config', () => {
+ let mockRouter: MockRouter;
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ mockRouter = new MockRouter({
+ method: 'post',
+ path: '/api/workplace_search/org/sources/{id}/display_settings/config',
+ payload: 'body',
+ });
+
+ registerOrgSourceDisplaySettingsConfig({
+ ...mockDependencies,
+ router: mockRouter.router,
+ });
+ });
+
+ it('creates a request handler', () => {
+ const mockRequest = {
+ params: { id: '123' },
+ body: {
+ titleField: 'foo',
+ subtitleField: 'bar',
+ descriptionField: 'this is a thing',
+ urlField: 'http://youknowfor.search',
+ color: '#aaa',
+ detailFields: {
+ fieldName: 'myField',
+ label: 'My Field',
+ },
+ },
+ };
+
+ mockRouter.callRoute(mockRequest);
+
+ expect(mockRequestHandler.createRequest).toHaveBeenCalledWith({
+ path: '/ws/org/sources/123/display_settings/config',
+ body: mockRequest.body,
+ });
+ });
+ });
+
describe('GET /api/workplace_search/org/settings/connectors', () => {
let mockRouter: MockRouter;
diff --git a/x-pack/plugins/enterprise_search/server/routes/workplace_search/sources.ts b/x-pack/plugins/enterprise_search/server/routes/workplace_search/sources.ts
index 24473388c03b1..1bc0edb34a65c 100644
--- a/x-pack/plugins/enterprise_search/server/routes/workplace_search/sources.ts
+++ b/x-pack/plugins/enterprise_search/server/routes/workplace_search/sources.ts
@@ -285,6 +285,55 @@ export function registerAccountSourceSearchableRoute({
);
}
+export function registerAccountSourceDisplaySettingsConfig({
+ router,
+ enterpriseSearchRequestHandler,
+}: RouteDependencies) {
+ router.get(
+ {
+ path: '/api/workplace_search/account/sources/{id}/display_settings/config',
+ validate: {
+ params: schema.object({
+ id: schema.string(),
+ }),
+ },
+ },
+ async (context, request, response) => {
+ return enterpriseSearchRequestHandler.createRequest({
+ path: `/ws/sources/${request.params.id}/display_settings/config`,
+ })(context, request, response);
+ }
+ );
+
+ router.post(
+ {
+ path: '/api/workplace_search/account/sources/{id}/display_settings/config',
+ validate: {
+ body: schema.object({
+ titleField: schema.maybe(schema.string()),
+ subtitleField: schema.maybe(schema.string()),
+ descriptionField: schema.maybe(schema.string()),
+ urlField: schema.maybe(schema.string()),
+ color: schema.string(),
+ detailFields: schema.object({
+ fieldName: schema.string(),
+ label: schema.string(),
+ }),
+ }),
+ params: schema.object({
+ id: schema.string(),
+ }),
+ },
+ },
+ async (context, request, response) => {
+ return enterpriseSearchRequestHandler.createRequest({
+ path: `/ws/sources/${request.params.id}/display_settings/config`,
+ body: request.body,
+ })(context, request, response);
+ }
+ );
+}
+
export function registerOrgSourcesRoute({
router,
enterpriseSearchRequestHandler,
@@ -545,6 +594,55 @@ export function registerOrgSourceSearchableRoute({
);
}
+export function registerOrgSourceDisplaySettingsConfig({
+ router,
+ enterpriseSearchRequestHandler,
+}: RouteDependencies) {
+ router.get(
+ {
+ path: '/api/workplace_search/org/sources/{id}/display_settings/config',
+ validate: {
+ params: schema.object({
+ id: schema.string(),
+ }),
+ },
+ },
+ async (context, request, response) => {
+ return enterpriseSearchRequestHandler.createRequest({
+ path: `/ws/org/sources/${request.params.id}/display_settings/config`,
+ })(context, request, response);
+ }
+ );
+
+ router.post(
+ {
+ path: '/api/workplace_search/org/sources/{id}/display_settings/config',
+ validate: {
+ body: schema.object({
+ titleField: schema.maybe(schema.string()),
+ subtitleField: schema.maybe(schema.string()),
+ descriptionField: schema.maybe(schema.string()),
+ urlField: schema.maybe(schema.string()),
+ color: schema.string(),
+ detailFields: schema.object({
+ fieldName: schema.string(),
+ label: schema.string(),
+ }),
+ }),
+ params: schema.object({
+ id: schema.string(),
+ }),
+ },
+ },
+ async (context, request, response) => {
+ return enterpriseSearchRequestHandler.createRequest({
+ path: `/ws/org/sources/${request.params.id}/display_settings/config`,
+ body: request.body,
+ })(context, request, response);
+ }
+ );
+}
+
export function registerOrgSourceOauthConfigurationsRoute({
router,
enterpriseSearchRequestHandler,
@@ -647,6 +745,7 @@ export const registerSourcesRoutes = (dependencies: RouteDependencies) => {
registerAccountPreSourceRoute(dependencies);
registerAccountPrepareSourcesRoute(dependencies);
registerAccountSourceSearchableRoute(dependencies);
+ registerAccountSourceDisplaySettingsConfig(dependencies);
registerOrgSourcesRoute(dependencies);
registerOrgSourcesStatusRoute(dependencies);
registerOrgSourceRoute(dependencies);
@@ -658,6 +757,7 @@ export const registerSourcesRoutes = (dependencies: RouteDependencies) => {
registerOrgPreSourceRoute(dependencies);
registerOrgPrepareSourcesRoute(dependencies);
registerOrgSourceSearchableRoute(dependencies);
+ registerOrgSourceDisplaySettingsConfig(dependencies);
registerOrgSourceOauthConfigurationsRoute(dependencies);
registerOrgSourceOauthConfigurationRoute(dependencies);
};
From d839e1624f6f67477e2879f6846b58e3329b037b Mon Sep 17 00:00:00 2001
From: scottybollinger
Date: Tue, 24 Nov 2020 13:53:07 -0600
Subject: [PATCH 03/11] Remove reference to shared lib
This one-liner appears only once in ent-search so adding it here in the logic file`
---
.../components/display_settings/display_settings_logic.ts | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_logic.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_logic.ts
index b6d7c20233709..f6a0d00f120b1 100644
--- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_logic.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_logic.ts
@@ -10,7 +10,6 @@ import { DropResult } from 'react-beautiful-dnd';
import { kea, MakeLogicType } from 'kea';
import http from 'shared/http';
-import { euiSelectObjectFromValue } from 'shared/utils';
import routes from 'workplace_search/routes';
import { AppLogic } from 'workplace_search/App/AppLogic';
@@ -321,6 +320,8 @@ export const DisplaySettingsLogic = kea<
}),
});
+const euiSelectObjectFromValue = (value: string) => ({ text: value, value });
+
// By default, the color is `null` on the server. The color is a required field and the
// EuiColorPicker components doesn't allow the field to be required so the form can be
// submitted with no color and this results in a server error. The default should be black
From 0103582f7978208d5aa5cfe61424fd0238225fc2 Mon Sep 17 00:00:00 2001
From: scottybollinger
Date: Tue, 24 Nov 2020 14:02:56 -0600
Subject: [PATCH 04/11] Fix paths
---
.../display_settings/display_settings.tsx | 17 +++++++++--------
.../display_settings/display_settings_logic.ts | 9 +++++----
.../display_settings_router.tsx | 6 +++---
.../example_result_detail_card.tsx | 6 +++---
.../example_search_result_group.tsx | 8 ++++----
.../example_standout_result.tsx | 8 ++++----
.../display_settings/field_editor_modal.tsx | 2 +-
.../components/display_settings/index.ts | 2 +-
.../display_settings/result_detail.tsx | 4 ++--
.../display_settings/search_results.tsx | 6 +++---
10 files changed, 35 insertions(+), 33 deletions(-)
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings.tsx
index 518704acabaaa..2f4165e485090 100644
--- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings.tsx
@@ -12,22 +12,23 @@ import { useHistory } from 'react-router-dom';
import { EuiButton, EuiEmptyPrompt, EuiTabbedContent, EuiPanel } from '@elastic/eui';
+import FlashMessages from 'shared/components/FlashMessages';
import {
DISPLAY_SETTINGS_RESULT_DETAIL_PATH,
DISPLAY_SETTINGS_SEARCH_RESULT_PATH,
getContentSourcePath,
-} from 'workplace_search/utils/routePaths';
+} from '../../../../routes';
-import { AppLogic } from 'workplace_search/App/AppLogic';
+import { AppLogic } from '../../../../app_logic';
-import FlashMessages from 'shared/components/FlashMessages';
+import { Loading } from '../../../../../shared/loading';
+import { ViewContentHeader } from '../../../../components/shared/view_content_header';
-import { Loading, ViewContentHeader } from 'workplace_search/components';
-import { DisplaySettingsLogic } from './DisplaySettingsLogic';
+import { DisplaySettingsLogic } from './display_settings_logic';
-import { FieldEditorModal } from './FieldEditorModal';
-import { ResultDetail } from './ResultDetail';
-import { SearchResults } from './SearchResults';
+import { FieldEditorModal } from './field_editor_modal';
+import { ResultDetail } from './result_detail';
+import { SearchResults } from './search_results';
const UNSAVED_MESSAGE =
'Your display settings have not been saved. Are you sure you want to leave?';
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_logic.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_logic.ts
index f6a0d00f120b1..77c98f37f297a 100644
--- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_logic.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_logic.ts
@@ -9,16 +9,17 @@ import { DropResult } from 'react-beautiful-dnd';
import { kea, MakeLogicType } from 'kea';
import http from 'shared/http';
+import { IFlashMessagesProps } from 'shared/types';
+
import routes from 'workplace_search/routes';
-import { AppLogic } from 'workplace_search/App/AppLogic';
-import { SourceLogic } from 'workplace_search/ContentSources/SourceLogic';
+import { AppLogic } from '../../../../app_logic';
+import { SourceLogic } from '../../source_logic';
const SUCCESS_MESSAGE = 'Display Settings have been successfuly updated.';
-import { IFlashMessagesProps } from 'shared/types';
-import { IObject, DetailField, SearchResultConfig, OptionValue } from 'workplace_search/types';
+import { IObject, DetailField, SearchResultConfig, OptionValue } from '../../../../types';
export interface DisplaySettingsResponseProps {
sourceName: string;
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_router.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_router.tsx
index 1283b0359adb7..01ac93735b8a8 100644
--- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_router.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_router.tsx
@@ -9,15 +9,15 @@ import React from 'react';
import { useValues } from 'kea';
import { Route, Switch } from 'react-router-dom';
-import { AppLogic } from 'workplace_search/App/AppLogic';
+import { AppLogic } from '../../../../app_logic';
import {
DISPLAY_SETTINGS_RESULT_DETAIL_PATH,
DISPLAY_SETTINGS_SEARCH_RESULT_PATH,
getSourcesPath,
-} from 'workplace_search/utils/routePaths';
+} from '../../../../routes';
-import { DisplaySettings } from './DisplaySettings';
+import { DisplaySettings } from './display_settings';
export const DisplaySettingsRouter: React.FC = () => {
const { isOrganization } = useValues(AppLogic);
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_result_detail_card.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_result_detail_card.tsx
index 1a7a6e346fc62..468f7d2f7ad05 100644
--- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_result_detail_card.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_result_detail_card.tsx
@@ -11,10 +11,10 @@ import { useValues } from 'kea';
import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiText, EuiTitle } from '@elastic/eui';
-import { DisplaySettingsLogic } from './DisplaySettingsLogic';
+import { DisplaySettingsLogic } from './display_settings_logic';
-import { CustomSourceIcon } from './CustomSourceIcon';
-import { TitleField } from './TitleField';
+import { CustomSourceIcon } from './custom_source_icon';
+import { TitleField } from './title_field';
export const ExampleResultDetailCard: React.FC = () => {
const {
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_search_result_group.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_search_result_group.tsx
index 0749a7507f09a..14239b1654308 100644
--- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_search_result_group.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_search_result_group.tsx
@@ -10,11 +10,11 @@ import { isColorDark, hexToRgb } from '@elastic/eui';
import classNames from 'classnames';
import { useValues } from 'kea';
-import { DisplaySettingsLogic } from './DisplaySettingsLogic';
+import { DisplaySettingsLogic } from './display_settings_logic';
-import { CustomSourceIcon } from './CustomSourceIcon';
-import { SubtitleField } from './SubtitleField';
-import { TitleField } from './TitleField';
+import { CustomSourceIcon } from './custom_source_icon';
+import { SubtitleField } from './subtitle_field';
+import { TitleField } from './title_field';
export const ExampleSearchResultGroup: React.FC = () => {
const {
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_standout_result.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_standout_result.tsx
index 1d04302aef331..4ef3b1fe14b93 100644
--- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_standout_result.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/example_standout_result.tsx
@@ -11,11 +11,11 @@ import { useValues } from 'kea';
import { isColorDark, hexToRgb } from '@elastic/eui';
-import { DisplaySettingsLogic } from './DisplaySettingsLogic';
+import { DisplaySettingsLogic } from './display_settings_logic';
-import { CustomSourceIcon } from './CustomSourceIcon';
-import { SubtitleField } from './SubtitleField';
-import { TitleField } from './TitleField';
+import { CustomSourceIcon } from './custom_source_icon';
+import { SubtitleField } from './subtitle_field';
+import { TitleField } from './title_field';
export const ExampleStandoutResult: React.FC = () => {
const {
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/field_editor_modal.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/field_editor_modal.tsx
index 34d7ff8ecbf97..6211fd3acd6a9 100644
--- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/field_editor_modal.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/field_editor_modal.tsx
@@ -23,7 +23,7 @@ import {
EuiSelect,
} from '@elastic/eui';
-import { DisplaySettingsLogic } from './DisplaySettingsLogic';
+import { DisplaySettingsLogic } from './display_settings_logic';
const emptyField = { fieldName: '', label: '' };
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/index.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/index.ts
index cbe699af22d61..f8c6834db7805 100644
--- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/index.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/index.ts
@@ -4,4 +4,4 @@
* you may not use this file except in compliance with the Elastic License.
*/
-export { DisplaySettingsRouter } from './DisplaySettingsRouter';
+export { DisplaySettingsRouter } from './display_settings_router';
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/result_detail.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/result_detail.tsx
index 0bf48bce755e2..cb65d8ef671e6 100644
--- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/result_detail.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/result_detail.tsx
@@ -26,9 +26,9 @@ import {
EuiTitle,
} from '@elastic/eui';
-import { DisplaySettingsLogic } from './DisplaySettingsLogic';
+import { DisplaySettingsLogic } from './display_settings_logic';
-import { ExampleResultDetailCard } from './ExampleResultDetailCard';
+import { ExampleResultDetailCard } from './example_result_detail_card';
export const ResultDetail: React.FC = () => {
const {
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/search_results.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/search_results.tsx
index 0ca96daef0eb9..ffffc79481041 100644
--- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/search_results.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/search_results.tsx
@@ -20,10 +20,10 @@ import {
EuiTitle,
} from '@elastic/eui';
-import { DisplaySettingsLogic } from './DisplaySettingsLogic';
+import { DisplaySettingsLogic } from './display_settings_logic';
-import { ExampleSearchResultGroup } from './ExampleSearchResultGroup';
-import { ExampleStandoutResult } from './ExampleStandoutResult';
+import { ExampleSearchResultGroup } from './example_search_result_group';
+import { ExampleStandoutResult } from './example_standout_result';
export const SearchResults: React.FC = () => {
const {
From 78f5f0a465e8c3496607d74f50b0f3f5070410cb Mon Sep 17 00:00:00 2001
From: scottybollinger
Date: Tue, 24 Nov 2020 14:07:37 -0600
Subject: [PATCH 05/11] Add types and fix TypeScript issues
---
.../applications/workplace_search/types.ts | 23 +++++++++++++
.../display_settings/display_settings.tsx | 18 +++++++----
.../display_settings_logic.ts | 32 ++++++++++---------
.../display_settings/field_editor_modal.tsx | 4 +--
.../display_settings/subtitle_field.tsx | 4 +--
.../display_settings/title_field.tsx | 4 +--
6 files changed, 57 insertions(+), 28 deletions(-)
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/types.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/types.ts
index 73e7f7ed701d8..9bda686ebbf00 100644
--- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/types.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/types.ts
@@ -181,3 +181,26 @@ export interface CustomSource {
name: string;
id: string;
}
+
+export interface Result {
+ [key: string]: string;
+}
+
+export interface OptionValue {
+ value: string;
+ text: string;
+}
+
+export interface DetailField {
+ fieldName: string;
+ label: string;
+}
+
+export interface SearchResultConfig {
+ titleField: string | null;
+ subtitleField: string | null;
+ descriptionField: string | null;
+ urlField: string | null;
+ color: string;
+ detailFields: DetailField[];
+}
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings.tsx
index 2f4165e485090..d8be8834268ad 100644
--- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings.tsx
@@ -4,13 +4,19 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import React, { useEffect } from 'react';
+import React, { FormEvent, useEffect } from 'react';
import { History } from 'history';
import { useActions, useValues } from 'kea';
import { useHistory } from 'react-router-dom';
-import { EuiButton, EuiEmptyPrompt, EuiTabbedContent, EuiPanel } from '@elastic/eui';
+import {
+ EuiButton,
+ EuiEmptyPrompt,
+ EuiTabbedContent,
+ EuiPanel,
+ EuiTabbedContentTab,
+} from '@elastic/eui';
import FlashMessages from 'shared/components/FlashMessages';
import {
@@ -74,18 +80,16 @@ export const DisplaySettings: React.FC = ({ tabId }) => {
{
id: 'search_results',
name: 'Search Results',
- disabled: false,
content: ,
},
{
id: 'result_detail',
name: 'Result Detail',
- disabled: false,
content: ,
},
- ];
+ ] as EuiTabbedContentTab[];
- const onSelectedTabChanged = (tab) => {
+ const onSelectedTabChanged = (tab: EuiTabbedContentTab) => {
const path =
tab.id === tabs[1].id
? getContentSourcePath(DISPLAY_SETTINGS_RESULT_DETAIL_PATH, sourceId, isOrganization)
@@ -94,7 +98,7 @@ export const DisplaySettings: React.FC = ({ tabId }) => {
history.push(path);
};
- const handleFormSubmit = (e) => {
+ const handleFormSubmit = (e: FormEvent) => {
e.preventDefault();
setServerData();
};
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_logic.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_logic.ts
index 77c98f37f297a..474cdc889a925 100644
--- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_logic.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_logic.ts
@@ -11,7 +11,6 @@ import { kea, MakeLogicType } from 'kea';
import http from 'shared/http';
import { IFlashMessagesProps } from 'shared/types';
-
import routes from 'workplace_search/routes';
import { AppLogic } from '../../../../app_logic';
@@ -19,13 +18,13 @@ import { SourceLogic } from '../../source_logic';
const SUCCESS_MESSAGE = 'Display Settings have been successfuly updated.';
-import { IObject, DetailField, SearchResultConfig, OptionValue } from '../../../../types';
+import { DetailField, SearchResultConfig, OptionValue } from '../../../../types';
export interface DisplaySettingsResponseProps {
sourceName: string;
searchResultConfig: SearchResultConfig;
- schemaFields: IObject;
- exampleDocuments: IObject[];
+ schemaFields: object;
+ exampleDocuments: object[];
}
export interface DisplaySettingsInitialData extends DisplaySettingsResponseProps {
@@ -47,12 +46,15 @@ interface DisplaySettingsActions {
setUrlField(urlField: string): string;
setSubtitleField(subtitleField: string | null): string | null;
setDescriptionField(descriptionField: string | null): string | null;
- setColorField(hex: string);
- setDetailFields(result: DropResult);
- openEditDetailField(editFieldIndex: number | null);
- removeDetailField(index: number);
- addDetailField(newField: DetailField);
- updateDetailField(updatedField: DetailField, index: number | null);
+ setColorField(hex: string): string;
+ setDetailFields(result: DropResult): { result: DropResult };
+ openEditDetailField(editFieldIndex: number | null): number | null;
+ removeDetailField(index: number): number;
+ addDetailField(newField: DetailField): DetailField;
+ updateDetailField(
+ updatedField: DetailField,
+ index: number | null
+ ): { updatedField: DetailField; index: number };
toggleFieldEditorModal(): void;
toggleTitleFieldHover(): void;
toggleSubtitleFieldHover(): void;
@@ -64,8 +66,8 @@ interface DisplaySettingsActions {
interface DisplaySettingsValues {
sourceName: string;
sourceId: string;
- schemaFields: IObject;
- exampleDocuments: IObject[];
+ schemaFields: object;
+ exampleDocuments: object[];
serverSearchResultConfig: SearchResultConfig;
searchResultConfig: SearchResultConfig;
serverRoute: string;
@@ -174,7 +176,7 @@ export const DisplaySettingsLogic = kea<
const detailFields = cloneDeep(searchResultConfig.detailFields);
const element = detailFields[source.index];
detailFields.splice(source.index, 1);
- detailFields.splice(destination.index, 0, element);
+ detailFields.splice(destination!.index, 0, element);
return {
...searchResultConfig,
detailFields,
@@ -285,7 +287,7 @@ export const DisplaySettingsLogic = kea<
availableFieldOptions: [
() => [selectors.fieldOptions, selectors.searchResultConfig],
(fieldOptions, { detailFields }) => {
- const usedFields = detailFields.map((usedField) =>
+ const usedFields = detailFields.map((usedField: DetailField) =>
euiSelectObjectFromValue(usedField.fieldName)
);
return differenceBy(fieldOptions, usedFields, 'value');
@@ -328,7 +330,7 @@ const euiSelectObjectFromValue = (value: string) => ({ text: value, value });
// submitted with no color and this results in a server error. The default should be black
// and this allows the `searchResultConfig` and the `serverSearchResultConfig` reducers to
// stay synced on initialization.
-const setDefaultColor = (searchResultConfig) => ({
+const setDefaultColor = (searchResultConfig: SearchResultConfig) => ({
...searchResultConfig,
color: searchResultConfig.color || '#000000',
});
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/field_editor_modal.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/field_editor_modal.tsx
index 6211fd3acd6a9..587916a741d66 100644
--- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/field_editor_modal.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/field_editor_modal.tsx
@@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import React, { useState } from 'react';
+import React, { FormEvent, useState } from 'react';
import { useActions, useValues } from 'kea';
@@ -44,7 +44,7 @@ export const FieldEditorModal: React.FC = () => {
const [fieldName, setName] = useState(field.fieldName || '');
const [label, setLabel] = useState(field.label || '');
- const handleSubmit = (e) => {
+ const handleSubmit = (e: FormEvent) => {
e.preventDefault();
if (isEditing) {
updateDetailField({ fieldName, label }, editFieldIndex);
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/subtitle_field.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/subtitle_field.tsx
index 7376e0df6374a..e27052ddffc04 100644
--- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/subtitle_field.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/subtitle_field.tsx
@@ -8,10 +8,10 @@ import React from 'react';
import classNames from 'classnames';
-import { IObject } from 'workplace_search/types';
+import { Result } from '../../../../types';
interface SubtitleFieldProps {
- result: IObject;
+ result: Result;
subtitleField: string | null;
subtitleFieldHover: boolean;
}
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/title_field.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/title_field.tsx
index 234bedf3db29d..a54c0977b464f 100644
--- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/title_field.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/title_field.tsx
@@ -8,10 +8,10 @@ import React from 'react';
import classNames from 'classnames';
-import { IObject } from 'workplace_search/types';
+import { Result } from '../../../../types';
interface TitleFieldProps {
- result: IObject;
+ result: Result;
titleField: string | null;
titleFieldHover: boolean;
}
From cb2a799644b5a3da6d4a8e1795e46a8483b710c1 Mon Sep 17 00:00:00 2001
From: scottybollinger
Date: Tue, 24 Nov 2020 14:24:34 -0600
Subject: [PATCH 06/11] Replace FlashMessages with global component
---
.../display_settings/display_settings.tsx | 3 ---
.../display_settings_logic.ts | 23 ++++++++-----------
2 files changed, 10 insertions(+), 16 deletions(-)
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings.tsx
index d8be8834268ad..1d51c3521c81d 100644
--- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings.tsx
@@ -18,7 +18,6 @@ import {
EuiTabbedContentTab,
} from '@elastic/eui';
-import FlashMessages from 'shared/components/FlashMessages';
import {
DISPLAY_SETTINGS_RESULT_DETAIL_PATH,
DISPLAY_SETTINGS_SEARCH_RESULT_PATH,
@@ -51,7 +50,6 @@ export const DisplaySettings: React.FC = ({ tabId }) => {
const {
dataLoading,
- flashMessages,
sourceId,
addFieldModalVisible,
unsavedChanges,
@@ -117,7 +115,6 @@ export const DisplaySettings: React.FC = ({ tabId }) => {
) : null
}
/>
- {!!flashMessages && }
{hasDocuments ? (
displaySettingsProps,
- setFlashMessages: (flashMessages: IFlashMessagesProps) => ({ flashMessages }),
setTitleField: (titleField: string) => titleField,
setUrlField: (urlField: string) => urlField,
setSubtitleField: (subtitleField: string | null) => subtitleField,
@@ -214,15 +211,6 @@ export const DisplaySettingsLogic = kea<
onInitializeDisplaySettings: (_, { serverRoute }) => serverRoute,
},
],
- flashMessages: [
- {},
- {
- setServerResponseData: () => ({ success: [SUCCESS_MESSAGE] }),
- setFlashMessages: (_, { flashMessages }) => flashMessages,
- toggleFieldEditorModal: () => ({}),
- resetDisplaySettingsState: () => ({}),
- },
- ],
editFieldIndex: [
null,
{
@@ -320,6 +308,15 @@ export const DisplaySettingsLogic = kea<
.then(({ data }) => actions.setServerResponseData(data))
.catch(({ response }) => actions.setFlashMessages({ error: response.data.errors }));
},
+ setServerResponseData: () => {
+ setSuccessMessage(SUCCESS_MESSAGE);
+ },
+ toggleFieldEditorModal: () => {
+ FlashMessagesLogic.actions.clearFlashMessages();
+ },
+ resetDisplaySettingsState: () => {
+ FlashMessagesLogic.actions.clearFlashMessages();
+ },
}),
});
From 9d9c6527c76c3fc653f2cf10449052c05dad7f4b Mon Sep 17 00:00:00 2001
From: scottybollinger
Date: Tue, 24 Nov 2020 14:27:55 -0600
Subject: [PATCH 07/11] More explicit Result type
---
.../components/display_settings/display_settings_logic.ts | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_logic.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_logic.ts
index cb3f5e23aa2ce..ceea681c95ac7 100644
--- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_logic.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_logic.ts
@@ -18,13 +18,13 @@ import { SourceLogic } from '../../source_logic';
const SUCCESS_MESSAGE = 'Display Settings have been successfuly updated.';
-import { DetailField, SearchResultConfig, OptionValue } from '../../../../types';
+import { DetailField, SearchResultConfig, OptionValue, Result } from '../../../../types';
export interface DisplaySettingsResponseProps {
sourceName: string;
searchResultConfig: SearchResultConfig;
schemaFields: object;
- exampleDocuments: object[];
+ exampleDocuments: Result[];
}
export interface DisplaySettingsInitialData extends DisplaySettingsResponseProps {
@@ -66,7 +66,7 @@ interface DisplaySettingsValues {
sourceName: string;
sourceId: string;
schemaFields: object;
- exampleDocuments: object[];
+ exampleDocuments: Result[];
serverSearchResultConfig: SearchResultConfig;
searchResultConfig: SearchResultConfig;
serverRoute: string;
From c51bd322af2936167437dd3248f4f2f1dfb1eeb0 Mon Sep 17 00:00:00 2001
From: scottybollinger
Date: Tue, 24 Nov 2020 14:33:01 -0600
Subject: [PATCH 08/11] Remove routes/http in favor of HttpLogic
---
.../display_settings_logic.ts | 47 +++++++++++++------
1 file changed, 32 insertions(+), 15 deletions(-)
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_logic.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_logic.ts
index ceea681c95ac7..c52665524f566 100644
--- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_logic.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings_logic.ts
@@ -8,10 +8,14 @@ import { cloneDeep, isEqual, differenceBy } from 'lodash';
import { DropResult } from 'react-beautiful-dnd';
import { kea, MakeLogicType } from 'kea';
-import http from 'shared/http';
-import routes from 'workplace_search/routes';
-import { setSuccessMessage, FlashMessagesLogic } from '../../../../../shared/flash_messages';
+import { HttpLogic } from '../../../../../shared/http';
+
+import {
+ setSuccessMessage,
+ FlashMessagesLogic,
+ flashAPIErrors,
+} from '../../../../../shared/flash_messages';
import { AppLogic } from '../../../../app_logic';
import { SourceLogic } from '../../source_logic';
@@ -287,26 +291,39 @@ export const DisplaySettingsLogic = kea<
],
}),
listeners: ({ actions, values }) => ({
- initializeDisplaySettings: () => {
+ initializeDisplaySettings: async () => {
const { isOrganization } = AppLogic.values;
const {
contentSource: { id: sourceId },
} = SourceLogic.values;
- const serverRoute = isOrganization
- ? routes.fritoPieOrganizationContentSourceDisplaySettingsConfigPath(sourceId)
- : routes.fritoPieAccountContentSourceDisplaySettingsConfigPath(sourceId);
+ const route = isOrganization
+ ? `/api/workplace_search/org/sources/${sourceId}/display_settings/config`
+ : `/api/workplace_search/account/sources/${sourceId}/display_settings/config`;
- http(serverRoute).then(({ data }) =>
- actions.onInitializeDisplaySettings({ isOrganization, sourceId, serverRoute, ...data })
- );
+ try {
+ const response = await HttpLogic.values.http.get(route);
+ actions.onInitializeDisplaySettings({
+ isOrganization,
+ sourceId,
+ serverRoute: route,
+ ...response,
+ });
+ } catch (e) {
+ flashAPIErrors(e);
+ }
},
- setServerData: () => {
+ setServerData: async () => {
const { searchResultConfig, serverRoute } = values;
- http
- .post(serverRoute, searchResultConfig)
- .then(({ data }) => actions.setServerResponseData(data))
- .catch(({ response }) => actions.setFlashMessages({ error: response.data.errors }));
+
+ try {
+ const response = await HttpLogic.values.http.post(serverRoute, {
+ body: JSON.stringify({ ...searchResultConfig }),
+ });
+ actions.setServerResponseData(response);
+ } catch (e) {
+ flashAPIErrors(e);
+ }
},
setServerResponseData: () => {
setSuccessMessage(SUCCESS_MESSAGE);
From 2a5bdba876feb0251243b5a533a2f64ba859a563 Mon Sep 17 00:00:00 2001
From: scottybollinger
Date: Tue, 24 Nov 2020 15:58:48 -0600
Subject: [PATCH 09/11] Fix server routes
`urlFieldIsLinkable` was missing and `detailFields` can either be an object or an array of objects
---
.../server/routes/workplace_search/sources.ts | 39 ++++++++-----------
1 file changed, 17 insertions(+), 22 deletions(-)
diff --git a/x-pack/plugins/enterprise_search/server/routes/workplace_search/sources.ts b/x-pack/plugins/enterprise_search/server/routes/workplace_search/sources.ts
index 1bc0edb34a65c..d43a4252c7e1f 100644
--- a/x-pack/plugins/enterprise_search/server/routes/workplace_search/sources.ts
+++ b/x-pack/plugins/enterprise_search/server/routes/workplace_search/sources.ts
@@ -25,6 +25,21 @@ const oAuthConfigSchema = schema.object({
consumer_key: schema.string(),
});
+const displayFieldSchema = schema.object({
+ fieldName: schema.string(),
+ label: schema.string(),
+});
+
+const displaySettingsSchema = schema.object({
+ titleField: schema.maybe(schema.string()),
+ subtitleField: schema.maybe(schema.string()),
+ descriptionField: schema.maybe(schema.string()),
+ urlField: schema.maybe(schema.string()),
+ color: schema.string(),
+ urlFieldIsLinkable: schema.boolean(),
+ detailFields: schema.oneOf([schema.arrayOf(displayFieldSchema), displayFieldSchema]),
+});
+
export function registerAccountSourcesRoute({
router,
enterpriseSearchRequestHandler,
@@ -309,17 +324,7 @@ export function registerAccountSourceDisplaySettingsConfig({
{
path: '/api/workplace_search/account/sources/{id}/display_settings/config',
validate: {
- body: schema.object({
- titleField: schema.maybe(schema.string()),
- subtitleField: schema.maybe(schema.string()),
- descriptionField: schema.maybe(schema.string()),
- urlField: schema.maybe(schema.string()),
- color: schema.string(),
- detailFields: schema.object({
- fieldName: schema.string(),
- label: schema.string(),
- }),
- }),
+ body: displaySettingsSchema,
params: schema.object({
id: schema.string(),
}),
@@ -618,17 +623,7 @@ export function registerOrgSourceDisplaySettingsConfig({
{
path: '/api/workplace_search/org/sources/{id}/display_settings/config',
validate: {
- body: schema.object({
- titleField: schema.maybe(schema.string()),
- subtitleField: schema.maybe(schema.string()),
- descriptionField: schema.maybe(schema.string()),
- urlField: schema.maybe(schema.string()),
- color: schema.string(),
- detailFields: schema.object({
- fieldName: schema.string(),
- label: schema.string(),
- }),
- }),
+ body: displaySettingsSchema,
params: schema.object({
id: schema.string(),
}),
From e3d851d909adc961c11d6c603c611be26d172143 Mon Sep 17 00:00:00 2001
From: scottybollinger
Date: Tue, 24 Nov 2020 15:59:31 -0600
Subject: [PATCH 10/11] Add base styles
These were ported from ent-search. Decided to use spacers where some global styles were missing.
---
.../display_settings/display_settings.scss | 206 ++++++++++++++++++
.../display_settings/display_settings.tsx | 2 +
.../display_settings/search_results.tsx | 2 +
3 files changed, 210 insertions(+)
create mode 100644 x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings.scss
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings.scss b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings.scss
new file mode 100644
index 0000000000000..27935104f4ef6
--- /dev/null
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings.scss
@@ -0,0 +1,206 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+// --------------------------------------------------
+// Custom Source display settings
+// --------------------------------------------------
+
+@mixin source_name {
+ font-size: .6875em;
+ text-transform: uppercase;
+ font-weight: 600;
+ letter-spacing: 0.06em;
+}
+
+@mixin example_result_box_shadow {
+ box-shadow:
+ 0 1px 3px rgba(black, 0.1),
+ 0 0 20px $euiColorLightestShade;
+}
+
+// Wrapper
+.custom-source-display-settings {
+ font-size: 16px;
+}
+
+// Example result content
+.example-result-content {
+ & > * {
+ line-height: 1.5em;
+ }
+
+ &__title {
+ font-size: 1em;
+ font-weight: 600;
+ color: $euiColorPrimary;
+
+ .example-result-detail-card & {
+ font-size: 20px;
+ }
+ }
+
+ &__subtitle,
+ &__description {
+ font-size: .875;
+ }
+
+ &__subtitle {
+ color: $euiColorDarkestShade;
+ }
+
+ &__description {
+ padding: .1rem 0 .125rem .35rem;
+ border-left: 3px solid $euiColorLightShade;
+ color: $euiColorDarkShade;
+ line-height: 1.8;
+ word-break: break-word;
+
+ @supports (display: -webkit-box) {
+ display: -webkit-box;
+ -webkit-box-orient: vertical;
+ -webkit-line-clamp: 3;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+ }
+
+ &__url {
+ .example-result-detail-card & {
+ color: $euiColorDarkShade;
+ }
+ }
+}
+
+.example-result-content-placeholder {
+ color: $euiColorMediumShade;
+}
+
+// Example standout result
+.example-standout-result {
+ border-radius: 4px;
+ overflow: hidden;
+ @include example_result_box_shadow;
+
+ &__header,
+ &__content {
+ padding-left: 1em;
+ padding-right: 1em;
+ }
+
+ &__content {
+ padding-top: 1em;
+ padding-bottom: 1em;
+ }
+
+ &__source-name {
+ line-height: 34px;
+ @include source_name;
+ }
+}
+
+// Example result group
+.example-result-group {
+ &__header {
+ padding: 0 .5em;
+ border-radius: 4px;
+ display: inline-flex;
+ align-items: center;
+
+ .euiIcon {
+ margin-right: .25rem;
+ }
+ }
+
+ &__source-name {
+ line-height: 1.75em;
+ @include source_name;
+ }
+
+ &__content {
+ display: flex;
+ align-items: stretch;
+ padding: .75em 0;
+ }
+
+ &__border {
+ width: 4px;
+ border-radius: 2px;
+ flex-shrink: 0;
+ margin-left: .875rem;
+ }
+
+ &__results {
+ flex: 1;
+ max-width: 100%;
+ }
+}
+
+.example-grouped-result {
+ padding: 1em;
+}
+
+.example-result-field-hover {
+ background: lighten($euiColorVis1_behindText, 30%);
+ position: relative;
+
+ &:before,
+ &:after {
+ content: '';
+ position: absolute;
+ height: 100%;
+ width: 4px;
+ background: lighten($euiColorVis1_behindText, 30%);
+ }
+
+ &:before {
+ right: 100%;
+ border-radius: 2px 0 0 2px;
+ }
+
+ &:after {
+ left: 100%;
+ border-radius: 0 2px 2px 0;
+ }
+
+ .example-result-content-placeholder {
+ color: $euiColorFullShade;
+ }
+}
+
+.example-result-detail-card {
+ @include example_result_box_shadow;
+
+ &__header {
+ position: relative;
+ padding: 1.25em 1em 0;
+ }
+
+ &__border {
+ height: 4px;
+ position: absolute;
+ top: 0;
+ right: 0;
+ left: 0;
+ }
+
+ &__source-name {
+ margin-bottom: 1em;
+ font-weight: 500;
+ }
+
+ &__field {
+ padding: 1em;
+
+ & + & {
+ border-top: 1px solid $euiColorLightShade;
+ }
+ }
+}
+
+.visible-fields-container {
+ background: $euiColorLightestShade;
+ border-color: transparent;
+}
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings.tsx
index 1d51c3521c81d..e34728beef5e5 100644
--- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/display_settings.tsx
@@ -10,6 +10,8 @@ import { History } from 'history';
import { useActions, useValues } from 'kea';
import { useHistory } from 'react-router-dom';
+import './display_settings.scss';
+
import {
EuiButton,
EuiEmptyPrompt,
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/search_results.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/search_results.tsx
index ffffc79481041..cfe0ddb1533ec 100644
--- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/search_results.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/content_sources/components/display_settings/search_results.tsx
@@ -143,6 +143,7 @@ export const SearchResults: React.FC = () => {
A matching document will appear as a single bold card.
+
@@ -153,6 +154,7 @@ export const SearchResults: React.FC = () => {
Somewhat matching documents will appear as a set.
+
From 5d08fe93facfea3008f6d8b6519d7b45e77c87f3 Mon Sep 17 00:00:00 2001
From: scottybollinger
Date: Tue, 24 Nov 2020 16:17:01 -0600
Subject: [PATCH 11/11] Kibana prefers underscores in URLs
Was only going to do display-settings and result-details but decided to YOLO all of them
---
.../applications/workplace_search/routes.ts | 36 +++++++++----------
1 file changed, 18 insertions(+), 18 deletions(-)
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/routes.ts b/x-pack/plugins/enterprise_search/public/applications/workplace_search/routes.ts
index 3ec22ede888ab..14c288de5a0c8 100644
--- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/routes.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/routes.ts
@@ -46,7 +46,7 @@ export const ENT_SEARCH_LICENSE_MANAGEMENT = `${ENT_SEARCH_DOCS_PREFIX}/license-
export const PERSONAL_PATH = '/p';
-export const ROLE_MAPPINGS_PATH = '/role-mappings';
+export const ROLE_MAPPINGS_PATH = '/role_mappings';
export const ROLE_MAPPING_PATH = `${ROLE_MAPPINGS_PATH}/:roleId`;
export const ROLE_MAPPING_NEW_PATH = `${ROLE_MAPPINGS_PATH}/new`;
@@ -63,18 +63,18 @@ export const PERSONAL_SOURCES_PATH = `${PERSONAL_PATH}${SOURCES_PATH}`;
export const SOURCE_ADDED_PATH = `${SOURCES_PATH}/added`;
export const ADD_SOURCE_PATH = `${SOURCES_PATH}/add`;
export const ADD_BOX_PATH = `${SOURCES_PATH}/add/box`;
-export const ADD_CONFLUENCE_PATH = `${SOURCES_PATH}/add/confluence-cloud`;
-export const ADD_CONFLUENCE_SERVER_PATH = `${SOURCES_PATH}/add/confluence-server`;
+export const ADD_CONFLUENCE_PATH = `${SOURCES_PATH}/add/confluence_cloud`;
+export const ADD_CONFLUENCE_SERVER_PATH = `${SOURCES_PATH}/add/confluence_server`;
export const ADD_DROPBOX_PATH = `${SOURCES_PATH}/add/dropbox`;
-export const ADD_GITHUB_ENTERPRISE_PATH = `${SOURCES_PATH}/add/github-enterprise-server`;
+export const ADD_GITHUB_ENTERPRISE_PATH = `${SOURCES_PATH}/add/github_enterprise_server`;
export const ADD_GITHUB_PATH = `${SOURCES_PATH}/add/github`;
export const ADD_GMAIL_PATH = `${SOURCES_PATH}/add/gmail`;
-export const ADD_GOOGLE_DRIVE_PATH = `${SOURCES_PATH}/add/google-drive`;
-export const ADD_JIRA_PATH = `${SOURCES_PATH}/add/jira-cloud`;
-export const ADD_JIRA_SERVER_PATH = `${SOURCES_PATH}/add/jira-server`;
+export const ADD_GOOGLE_DRIVE_PATH = `${SOURCES_PATH}/add/google_drive`;
+export const ADD_JIRA_PATH = `${SOURCES_PATH}/add/jira_cloud`;
+export const ADD_JIRA_SERVER_PATH = `${SOURCES_PATH}/add/jira_server`;
export const ADD_ONEDRIVE_PATH = `${SOURCES_PATH}/add/onedrive`;
export const ADD_SALESFORCE_PATH = `${SOURCES_PATH}/add/salesforce`;
-export const ADD_SALESFORCE_SANDBOX_PATH = `${SOURCES_PATH}/add/salesforce-sandbox`;
+export const ADD_SALESFORCE_SANDBOX_PATH = `${SOURCES_PATH}/add/salesforce_sandbox`;
export const ADD_SERVICENOW_PATH = `${SOURCES_PATH}/add/servicenow`;
export const ADD_SHAREPOINT_PATH = `${SOURCES_PATH}/add/sharepoint`;
export const ADD_SLACK_PATH = `${SOURCES_PATH}/add/slack`;
@@ -86,30 +86,30 @@ export const PERSONAL_SETTINGS_PATH = `${PERSONAL_PATH}/settings`;
export const SOURCE_DETAILS_PATH = `${SOURCES_PATH}/:sourceId`;
export const SOURCE_CONTENT_PATH = `${SOURCES_PATH}/:sourceId/content`;
export const SOURCE_SCHEMAS_PATH = `${SOURCES_PATH}/:sourceId/schemas`;
-export const SOURCE_DISPLAY_SETTINGS_PATH = `${SOURCES_PATH}/:sourceId/display-settings`;
+export const SOURCE_DISPLAY_SETTINGS_PATH = `${SOURCES_PATH}/:sourceId/display_settings`;
export const SOURCE_SETTINGS_PATH = `${SOURCES_PATH}/:sourceId/settings`;
-export const REINDEX_JOB_PATH = `${SOURCES_PATH}/:sourceId/schema-errors/:activeReindexJobId`;
+export const REINDEX_JOB_PATH = `${SOURCES_PATH}/:sourceId/schema_errors/:activeReindexJobId`;
export const DISPLAY_SETTINGS_SEARCH_RESULT_PATH = `${SOURCE_DISPLAY_SETTINGS_PATH}/`;
-export const DISPLAY_SETTINGS_RESULT_DETAIL_PATH = `${SOURCE_DISPLAY_SETTINGS_PATH}/result-detail`;
+export const DISPLAY_SETTINGS_RESULT_DETAIL_PATH = `${SOURCE_DISPLAY_SETTINGS_PATH}/result_detail`;
export const ORG_SETTINGS_PATH = '/settings';
export const ORG_SETTINGS_CUSTOMIZE_PATH = `${ORG_SETTINGS_PATH}/customize`;
export const ORG_SETTINGS_CONNECTORS_PATH = `${ORG_SETTINGS_PATH}/connectors`;
export const ORG_SETTINGS_OAUTH_APPLICATION_PATH = `${ORG_SETTINGS_PATH}/oauth`;
export const EDIT_BOX_PATH = `${ORG_SETTINGS_CONNECTORS_PATH}/box/edit`;
-export const EDIT_CONFLUENCE_PATH = `${ORG_SETTINGS_CONNECTORS_PATH}/confluence-cloud/edit`;
-export const EDIT_CONFLUENCE_SERVER_PATH = `${ORG_SETTINGS_CONNECTORS_PATH}/confluence-server/edit`;
+export const EDIT_CONFLUENCE_PATH = `${ORG_SETTINGS_CONNECTORS_PATH}/confluence_cloud/edit`;
+export const EDIT_CONFLUENCE_SERVER_PATH = `${ORG_SETTINGS_CONNECTORS_PATH}/confluence_server/edit`;
export const EDIT_DROPBOX_PATH = `${ORG_SETTINGS_CONNECTORS_PATH}/dropbox/edit`;
-export const EDIT_GITHUB_ENTERPRISE_PATH = `${ORG_SETTINGS_CONNECTORS_PATH}/github-enterprise-server/edit`;
+export const EDIT_GITHUB_ENTERPRISE_PATH = `${ORG_SETTINGS_CONNECTORS_PATH}/github_enterprise_server/edit`;
export const EDIT_GITHUB_PATH = `${ORG_SETTINGS_CONNECTORS_PATH}/github/edit`;
export const EDIT_GMAIL_PATH = `${ORG_SETTINGS_CONNECTORS_PATH}/gmail/edit`;
-export const EDIT_GOOGLE_DRIVE_PATH = `${ORG_SETTINGS_CONNECTORS_PATH}/google-drive/edit`;
-export const EDIT_JIRA_PATH = `${ORG_SETTINGS_CONNECTORS_PATH}/jira-cloud/edit`;
-export const EDIT_JIRA_SERVER_PATH = `${ORG_SETTINGS_CONNECTORS_PATH}/jira-server/edit`;
+export const EDIT_GOOGLE_DRIVE_PATH = `${ORG_SETTINGS_CONNECTORS_PATH}/google_drive/edit`;
+export const EDIT_JIRA_PATH = `${ORG_SETTINGS_CONNECTORS_PATH}/jira_cloud/edit`;
+export const EDIT_JIRA_SERVER_PATH = `${ORG_SETTINGS_CONNECTORS_PATH}/jira_server/edit`;
export const EDIT_ONEDRIVE_PATH = `${ORG_SETTINGS_CONNECTORS_PATH}/onedrive/edit`;
export const EDIT_SALESFORCE_PATH = `${ORG_SETTINGS_CONNECTORS_PATH}/salesforce/edit`;
-export const EDIT_SALESFORCE_SANDBOX_PATH = `${ORG_SETTINGS_CONNECTORS_PATH}/salesforce-sandbox/edit`;
+export const EDIT_SALESFORCE_SANDBOX_PATH = `${ORG_SETTINGS_CONNECTORS_PATH}/salesforce_sandbox/edit`;
export const EDIT_SERVICENOW_PATH = `${ORG_SETTINGS_CONNECTORS_PATH}/servicenow/edit`;
export const EDIT_SHAREPOINT_PATH = `${ORG_SETTINGS_CONNECTORS_PATH}/sharepoint/edit`;
export const EDIT_SLACK_PATH = `${ORG_SETTINGS_CONNECTORS_PATH}/slack/edit`;