Skip to content

Commit

Permalink
Simplify export flow; improve form state (#284)
Browse files Browse the repository at this point in the history
Signed-off-by: Tyler Ohlsen <[email protected]>
  • Loading branch information
ohltyler committed Aug 15, 2024
1 parent f0552d7 commit ad86b00
Show file tree
Hide file tree
Showing 15 changed files with 374 additions and 255 deletions.
2 changes: 2 additions & 0 deletions common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ export const ML_CHOOSE_MODEL_LINK =
'https://opensearch.org/docs/latest/ml-commons-plugin/integrating-ml-models/#choosing-a-model';
export const TEXT_CHUNKING_PROCESSOR_LINK =
'https://opensearch.org/docs/latest/ingest-pipelines/processors/text-chunking/';
export const CREATE_WORKFLOW_LINK =
'https://opensearch.org/docs/latest/automating-configurations/api/create-workflow/';

/**
* Text chunking algorithm constants
Expand Down
10 changes: 4 additions & 6 deletions common/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -260,14 +260,14 @@ export type CreateIngestPipelineNode = TemplateNode & {
model_id?: string;
input_field?: string;
output_field?: string;
configurations: IngestPipelineConfig;
configurations: string;
};
};

export type CreateSearchPipelineNode = TemplateNode & {
user_inputs: {
pipeline_id: string;
configurations: SearchPipelineConfig;
configurations: string;
};
};

Expand All @@ -277,10 +277,7 @@ export type CreateIndexNode = TemplateNode & {
};
user_inputs: {
index_name: string;
configurations: {
settings: {};
mappings: {};
};
configurations: string;
};
};

Expand All @@ -292,6 +289,7 @@ export type TemplateEdge = {
export type TemplateFlow = {
nodes: TemplateNode[];
edges?: TemplateEdge[];
user_params?: {};
};

export type TemplateFlows = {
Expand Down
6 changes: 3 additions & 3 deletions public/component_types/indexer/base_indexer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ import { BaseComponent } from '../base_component';
/**
* A base indexer UI component
*/
export abstract class BaseIndexer extends BaseComponent {
export class BaseIndexer extends BaseComponent {
constructor() {
super();
this.type = COMPONENT_CLASS.INDEXER;
this.label = 'Indexer';
this.description = 'A general indexer';
this.label = 'Index';
this.description = 'An OpenSearch index';
this.inputs = [
{
id: 'input',
Expand Down
1 change: 1 addition & 0 deletions public/component_types/indexer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
* SPDX-License-Identifier: Apache-2.0
*/

export * from './base_indexer';
export * from './knn_indexer';
114 changes: 114 additions & 0 deletions public/pages/workflow_detail/components/export_modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import React, { useEffect, useState } from 'react';
import yaml from 'js-yaml';
import {
EuiCodeBlock,
EuiFlexGroup,
EuiFlexItem,
EuiCompressedRadioGroup,
EuiText,
EuiLink,
EuiModal,
EuiModalHeader,
EuiModalHeaderTitle,
EuiModalBody,
EuiModalFooter,
EuiSmallButtonEmpty,
} from '@elastic/eui';
import { CREATE_WORKFLOW_LINK, Workflow } from '../../../../common';
import { reduceToTemplate } from '../../../utils';

interface ExportModalProps {
workflow?: Workflow;
setIsExportModalOpen(isOpen: boolean): void;
}

enum EXPORT_OPTION {
JSON = 'json',
YAML = 'yaml',
}

const exportOptions = [
{
id: EXPORT_OPTION.JSON,
label: 'JSON',
},
{
id: EXPORT_OPTION.YAML,
label: 'YAML',
},
];

/**
* Modal containing all of the export options
*/
export function ExportModal(props: ExportModalProps) {
// format type state
const [selectedOption, setSelectedOption] = useState<EXPORT_OPTION>(
EXPORT_OPTION.JSON
);

// formatted string state
const [formattedConfig, setFormattedConfig] = useState<string>('');
useEffect(() => {
if (props.workflow) {
const workflowTemplate = reduceToTemplate(props.workflow);
if (selectedOption === EXPORT_OPTION.JSON) {
setFormattedConfig(JSON.stringify(workflowTemplate, undefined, 2));
} else if (selectedOption === EXPORT_OPTION.YAML) {
setFormattedConfig(yaml.dump(workflowTemplate));
}
}
}, [props.workflow, selectedOption]);

return (
<EuiModal onClose={() => props.setIsExportModalOpen(false)}>
<EuiModalHeader>
<EuiModalHeaderTitle>
<p>{`Export ${props.workflow?.name}`}</p>
</EuiModalHeaderTitle>
</EuiModalHeader>
<EuiModalBody>
<EuiFlexGroup direction="column">
<EuiFlexItem grow={false}>
<EuiText>
Copy the below workflow templates to use in other clusters.
</EuiText>
<EuiLink href={CREATE_WORKFLOW_LINK} target="_blank">
Learn more
</EuiLink>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiCompressedRadioGroup
options={exportOptions}
idSelected={selectedOption}
onChange={(option) => {
setSelectedOption(option as EXPORT_OPTION);
}}
/>
</EuiFlexItem>
{props.workflow !== undefined && (
<EuiFlexItem grow={false}>
<EuiCodeBlock
language={selectedOption}
fontSize="m"
isCopyable={true}
>
{formattedConfig}
</EuiCodeBlock>
</EuiFlexItem>
)}
</EuiFlexGroup>
</EuiModalBody>
<EuiModalFooter>
<EuiSmallButtonEmpty onClick={() => props.setIsExportModalOpen(false)}>
Close
</EuiSmallButtonEmpty>
</EuiModalFooter>
</EuiModal>
);
}
73 changes: 47 additions & 26 deletions public/pages/workflow_detail/components/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
EuiFlexItem,
EuiText,
EuiSmallButtonEmpty,
EuiSmallButton,
} from '@elastic/eui';
import {
DEFAULT_NEW_WORKFLOW_STATE,
Expand All @@ -19,6 +20,7 @@ import {
toFormattedDate,
} from '../../../../common';
import { APP_PATH } from '../../../utils';
import { ExportModal } from './export_modal';

interface WorkflowDetailHeaderProps {
workflow?: Workflow;
Expand All @@ -31,6 +33,9 @@ export function WorkflowDetailHeader(props: WorkflowDetailHeaderProps) {
const [workflowState, setWorkflowState] = useState<WORKFLOW_STATE>('');
const [workflowLastUpdated, setWorkflowLastUpdated] = useState<string>('');

// export modal state
const [isExportModalOpen, setIsExportModalOpen] = useState<boolean>(false);

useEffect(() => {
if (props.workflow) {
setWorkflowName(props.workflow.name);
Expand All @@ -48,31 +53,47 @@ export function WorkflowDetailHeader(props: WorkflowDetailHeaderProps) {
}, [props.workflow]);

return (
<EuiPageHeader
style={{ marginTop: '-8px' }}
pageTitle={
<EuiFlexGroup direction="row" alignItems="flexEnd" gutterSize="m">
<EuiFlexItem grow={false}>{workflowName}</EuiFlexItem>
<EuiFlexItem grow={false} style={{ marginBottom: '10px' }}>
<EuiText size="m">{workflowState}</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
}
rightSideItems={[
<EuiSmallButtonEmpty
style={{ marginTop: '8px' }}
onClick={() => {
// TODO: add lightweight save here when available
history.replace(APP_PATH.WORKFLOWS);
}}
>
Close
</EuiSmallButtonEmpty>,
<EuiText style={{ marginTop: '16px' }} color="subdued" size="s">
{`Last updated: ${workflowLastUpdated}`}
</EuiText>,
]}
bottomBorder={false}
/>
<>
{isExportModalOpen && (
<ExportModal
workflow={props.workflow}
setIsExportModalOpen={setIsExportModalOpen}
/>
)}
<EuiPageHeader
style={{ marginTop: '-8px' }}
pageTitle={
<EuiFlexGroup direction="row" alignItems="flexEnd" gutterSize="m">
<EuiFlexItem grow={false}>{workflowName}</EuiFlexItem>
<EuiFlexItem grow={false} style={{ marginBottom: '10px' }}>
<EuiText size="m">{workflowState}</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
}
rightSideItems={[
<EuiSmallButton
style={{ marginTop: '8px' }}
fill={true}
onClick={() => {
setIsExportModalOpen(true);
}}
>
Export
</EuiSmallButton>,
<EuiSmallButtonEmpty
style={{ marginTop: '8px' }}
onClick={() => {
history.replace(APP_PATH.WORKFLOWS);
}}
>
Close
</EuiSmallButtonEmpty>,
<EuiText style={{ marginTop: '16px' }} color="subdued" size="s">
{`Last updated: ${workflowLastUpdated}`}
</EuiText>,
]}
bottomBorder={false}
/>
</>
);
}

This file was deleted.

This file was deleted.

Loading

0 comments on commit ad86b00

Please sign in to comment.