Skip to content

Commit cc06f23

Browse files
committed
Get multi resource flyout working and entrypoints in main flow
Signed-off-by: Tyler Ohlsen <ohltyler@amazon.com>
1 parent 9a75401 commit cc06f23

File tree

2 files changed

+161
-54
lines changed

2 files changed

+161
-54
lines changed

public/pages/workflow_detail/tools/resources/resources_flyout.tsx

+135-41
Original file line numberDiff line numberDiff line change
@@ -3,49 +3,140 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
import React, { useState } from 'react';
6+
import React, { useEffect, useState } from 'react';
7+
import { useSelector } from 'react-redux';
8+
import { get } from 'lodash';
79
import {
810
EuiFlexItem,
911
EuiFlyout,
1012
EuiFlyoutBody,
1113
EuiFlyoutHeader,
14+
EuiSpacer,
1215
EuiTab,
1316
EuiTabs,
1417
EuiTitle,
1518
} from '@elastic/eui';
1619
import {
20+
CONFIG_STEP,
21+
customStringify,
1722
WORKFLOW_RESOURCE_TYPE,
23+
WORKFLOW_STEP_TYPE,
1824
WorkflowResource,
1925
} from '../../../../../common';
2026
import { ResourceFlyoutContent } from './resource_flyout_content';
21-
import { get } from 'lodash';
27+
import { extractIdsByStepType, getDataSourceId } from '../../../../utils';
28+
import {
29+
AppState,
30+
getIndex,
31+
getIngestPipeline,
32+
getSearchPipeline,
33+
useAppDispatch,
34+
} from '../../../../store';
2235

2336
interface ResourcesFlyoutProps {
2437
resources: WorkflowResource[];
25-
resourceDetails: string[];
38+
selectedStep: CONFIG_STEP;
2639
onClose: () => void;
27-
errorMessage?: string;
2840
}
2941

3042
/**
31-
* A simple flyout to display details for multiple workflow resources nested
32-
* under tabs.
43+
* Flyout to display details for multiple workflow resources, depending on the context (ingest or search).
44+
* Dynamically render data nested under tabs if there are multiple - e.g., an index and ingest pipeline under the ingest context.
3345
*/
3446
export function ResourcesFlyout(props: ResourcesFlyoutProps) {
47+
const dispatch = useAppDispatch();
48+
const dataSourceId = getDataSourceId();
49+
50+
const {
51+
getIndexErrorMessage,
52+
getIngestPipelineErrorMessage,
53+
getSearchPipelineErrorMessage,
54+
indexDetails,
55+
ingestPipelineDetails,
56+
searchPipelineDetails,
57+
} = useSelector((state: AppState) => state.opensearch);
58+
59+
// Fetch the filtered resource(s) based on ingest or search context
60+
const [allResources, setAllResources] = useState<WorkflowResource[]>([]);
61+
useEffect(() => {
62+
if (props.resources) {
63+
const resourcesMap = {} as { [id: string]: WorkflowResource };
64+
props.resources.forEach((resource) => {
65+
if (
66+
(props.selectedStep === CONFIG_STEP.INGEST &&
67+
(resource.stepType === WORKFLOW_STEP_TYPE.CREATE_INDEX_STEP_TYPE ||
68+
resource.stepType ===
69+
WORKFLOW_STEP_TYPE.CREATE_INGEST_PIPELINE_STEP_TYPE)) ||
70+
(props.selectedStep === CONFIG_STEP.SEARCH &&
71+
resource.stepType ===
72+
WORKFLOW_STEP_TYPE.CREATE_SEARCH_PIPELINE_STEP_TYPE)
73+
) {
74+
resourcesMap[resource.id] = resource;
75+
}
76+
});
77+
setAllResources(Object.values(resourcesMap || {}));
78+
}
79+
}, [props.resources]);
80+
81+
// fetch details for each resource type
82+
useEffect(() => {
83+
const {
84+
indexIds,
85+
ingestPipelineIds,
86+
searchPipelineIds,
87+
} = extractIdsByStepType(allResources);
88+
if (indexIds) {
89+
try {
90+
dispatch(getIndex({ index: indexIds, dataSourceId }));
91+
} catch {}
92+
}
93+
if (ingestPipelineIds) {
94+
try {
95+
dispatch(
96+
getIngestPipeline({ pipelineId: ingestPipelineIds, dataSourceId })
97+
);
98+
} catch {}
99+
}
100+
if (searchPipelineIds) {
101+
try {
102+
dispatch(
103+
getSearchPipeline({ pipelineId: searchPipelineIds, dataSourceId })
104+
);
105+
} catch {}
106+
}
107+
}, [allResources]);
108+
109+
// keep state for the resource index, and the selected tab ID (if applicable)
35110
const [selectedResourceIdx, setSelectedResourceIdx] = useState<number>(0);
36-
const [selectedTabId, setSelectedTabId] = useState<string>(
37-
get(props, `resources.${selectedResourceIdx}.id`)
38-
);
39-
const selectedResource = get(
40-
props,
41-
`resources.${selectedResourceIdx}`,
42-
undefined
43-
) as WorkflowResource | undefined;
44-
const selectedResourceDetails = get(
45-
props,
46-
`resourceDetails.${selectedResourceIdx}`,
47-
undefined
48-
) as string | undefined;
111+
const [selectedTabId, setSelectedTabId] = useState<string>('');
112+
useEffect(() => {
113+
if (allResources) {
114+
setSelectedTabId(get(allResources, `0.id`));
115+
}
116+
}, [allResources]);
117+
118+
// get the resource details, and any error message, based on the selected resource index
119+
const selectedResource = get(allResources, selectedResourceIdx, undefined) as
120+
| WorkflowResource
121+
| undefined;
122+
const selectedResourceDetailsObj =
123+
indexDetails[selectedResource?.id || ''] ??
124+
ingestPipelineDetails[selectedResource?.id || ''] ??
125+
searchPipelineDetails[selectedResource?.id || ''] ??
126+
'';
127+
const selectedResourceDetails = customStringify({
128+
[selectedResource?.id || '']: selectedResourceDetailsObj,
129+
});
130+
const selectedResourceErrorMessage =
131+
selectedResource?.stepType === WORKFLOW_STEP_TYPE.CREATE_INDEX_STEP_TYPE
132+
? getIndexErrorMessage
133+
: selectedResource?.stepType ===
134+
WORKFLOW_STEP_TYPE.CREATE_INGEST_PIPELINE_STEP_TYPE
135+
? getIngestPipelineErrorMessage
136+
: selectedResource?.stepType ===
137+
WORKFLOW_STEP_TYPE.CREATE_SEARCH_PIPELINE_STEP_TYPE
138+
? getSearchPipelineErrorMessage
139+
: (undefined as string | undefined);
49140

50141
return (
51142
<EuiFlyout onClose={props.onClose}>
@@ -55,33 +146,36 @@ export function ResourcesFlyout(props: ResourcesFlyoutProps) {
55146
</EuiTitle>
56147
</EuiFlyoutHeader>
57148
<EuiFlyoutBody>
58-
<EuiFlexItem grow={false}>
59-
<EuiTabs size="s" expand={false}>
60-
{props.resources?.map((tab, idx) => {
61-
return (
62-
<EuiTab
63-
onClick={() => {
64-
setSelectedTabId(tab.id);
65-
setSelectedResourceIdx(idx);
66-
}}
67-
isSelected={tab.id === selectedTabId}
68-
disabled={false}
69-
key={idx}
70-
>
71-
{tab?.type === WORKFLOW_RESOURCE_TYPE.INDEX_NAME
72-
? 'Index'
73-
: 'Pipeline'}
74-
</EuiTab>
75-
);
76-
})}
77-
</EuiTabs>
78-
</EuiFlexItem>
149+
{allResources.length > 1 && (
150+
<EuiFlexItem grow={false}>
151+
<EuiTabs size="s" expand={false}>
152+
{allResources?.map((tab, idx) => {
153+
return (
154+
<EuiTab
155+
onClick={() => {
156+
setSelectedTabId(tab.id);
157+
setSelectedResourceIdx(idx);
158+
}}
159+
isSelected={tab.id === selectedTabId}
160+
disabled={false}
161+
key={idx}
162+
>
163+
{tab?.type === WORKFLOW_RESOURCE_TYPE.INDEX_NAME
164+
? 'Index'
165+
: 'Pipeline'}
166+
</EuiTab>
167+
);
168+
})}
169+
</EuiTabs>
170+
<EuiSpacer size="m" />
171+
</EuiFlexItem>
172+
)}
79173
{selectedResource !== undefined &&
80174
selectedResourceDetails !== undefined && (
81175
<ResourceFlyoutContent
82176
resource={selectedResource}
83177
resourceDetails={selectedResourceDetails}
84-
errorMessage={props.errorMessage}
178+
errorMessage={selectedResourceErrorMessage}
85179
/>
86180
)}
87181
</EuiFlyoutBody>

public/pages/workflow_detail/workflow_inputs/workflow_inputs.tsx

+26-13
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ import {
6363
} from '../../../utils';
6464
import { BooleanField } from './input_fields';
6565
import '../workspace/workspace-styles.scss';
66+
import { ResourcesFlyout } from '../tools/resources/resources_flyout';
6667

6768
interface WorkflowInputsProps {
6869
workflow: Workflow | undefined;
@@ -118,6 +119,11 @@ export function WorkflowInputs(props: WorkflowInputsProps) {
118119
undefined
119120
);
120121

122+
// resource details state
123+
const [resourcesFlyoutOpen, setResourcesFlyoutOpen] = useState<boolean>(
124+
false
125+
);
126+
121127
// maintain global states
122128
const onIngest = props.selectedStep === CONFIG_STEP.INGEST;
123129
const onSearch = props.selectedStep === CONFIG_STEP.SEARCH;
@@ -684,6 +690,13 @@ export function WorkflowInputs(props: WorkflowInputsProps) {
684690
className="workspace-panel"
685691
borderRadius="l"
686692
>
693+
{resourcesFlyoutOpen && (
694+
<ResourcesFlyout
695+
resources={props.workflow?.resourcesCreated || []}
696+
selectedStep={props.selectedStep}
697+
onClose={() => setResourcesFlyoutOpen(false)}
698+
/>
699+
)}
687700
{props.uiConfig === undefined ? (
688701
<EuiLoadingSpinner size="xl" />
689702
) : (
@@ -725,19 +738,19 @@ export function WorkflowInputs(props: WorkflowInputsProps) {
725738
</EuiButtonEmpty>
726739
</EuiFlexItem>
727740
)}
728-
{onIngest && ingestProvisioned && (
729-
<EuiFlexItem grow={false} style={{ marginTop: '20px' }}>
730-
<EuiButtonEmpty
731-
iconSide="left"
732-
iconType="inspect"
733-
onClick={() => {
734-
console.log('clicking details...');
735-
}}
736-
>
737-
Details
738-
</EuiButtonEmpty>
739-
</EuiFlexItem>
740-
)}
741+
{((onIngest && ingestProvisioned) ||
742+
(onSearch && searchProvisioned)) &&
743+
props.workflow?.resourcesCreated !== undefined && (
744+
<EuiFlexItem grow={false} style={{ marginTop: '20px' }}>
745+
<EuiButtonEmpty
746+
iconSide="left"
747+
iconType="inspect"
748+
onClick={() => setResourcesFlyoutOpen(true)}
749+
>
750+
Details
751+
</EuiButtonEmpty>
752+
</EuiFlexItem>
753+
)}
741754
</EuiFlexGroup>
742755
</EuiFlexItem>
743756
</EuiFlexGroup>

0 commit comments

Comments
 (0)