Skip to content

Commit

Permalink
ui changes for pipeline summarization using genai
Browse files Browse the repository at this point in the history
  • Loading branch information
GnsP committed Jul 31, 2024
1 parent 23124fb commit e14c948
Show file tree
Hide file tree
Showing 12 changed files with 372 additions and 107 deletions.
2 changes: 2 additions & 0 deletions app/cdap/api/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,6 @@ export const MyAppApi = {
batchStatus: apiCreator(dataSrc, 'POST', 'POLL', '/namespaces/:namespace/status'),
batchAppDetail: apiCreator(dataSrc, 'POST', 'REQUEST', '/namespaces/:namespace/appdetail'),
delete: apiCreator(dataSrc, 'DELETE', 'REQUEST', appPath),
summarize: apiCreator(dataSrc, 'POST', 'REQUEST', `${appPath}/summarize`),
summarizeDraft: apiCreator(dataSrc, 'POST', 'REQUEST', `${basepath}/summarize`),
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* Copyright © 2024 Cask Data, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/

import React, { useEffect, useRef, useState } from 'react';
import classnames from 'classnames';
import GraphicEqIcon from '@material-ui/icons/GraphicEq';
import T from 'i18n-react';
import { PrimaryTextLowercaseButton } from 'components/shared/Buttons/PrimaryTextLowercaseButton';
import styled from 'styled-components';
import { PipelineGenaiSummaryModal } from '../PipelineGenaiSummaryModal';
import { MyAppApi } from 'api/app';
import { getCurrentNamespace } from 'services/NamespaceStore';

const PREFIX = 'features.PipelineDetails.TopPanel';

interface IPipelineGenaiSummaryButtonProps {
pipelineName: string;
}

const StyledSummarizeIcon = styled(GraphicEqIcon)`
margin-bottom: -4px;
`;

const GenaiButton = styled.div`
padding: 0;
`;

export const PipelineGenaiSummaryButton = ({ pipelineName }: IPipelineGenaiSummaryButtonProps) => {
const [isOpen, setIsOpen] = useState(false);
const [summary, setSummary] = useState('');
const buttonRef = useRef(null);

useEffect(() => {
MyAppApi.summarize({
namespace: getCurrentNamespace(),
appId: pipelineName,
}).subscribe((res) => {
setSummary(res);
});
}, []);

const toggleButton = () => {
setIsOpen(!isOpen);
};

const renderPipelineGenaiSummaryBtn = () => {
return (
<GenaiButton className="btn pipeline-action-btn" ref={buttonRef}>
<PrimaryTextLowercaseButton
onClick={toggleButton}
data-cy="pipeline-genai-summary-btn"
data-testid="pipeline-genai-summary-btn"
>
<div className="btn-container">
<StyledSummarizeIcon viewBox="1 1 22 22" />
<div className="button-label">{T.translate(`${PREFIX}.genaiSummarize`)}</div>
</div>
</PrimaryTextLowercaseButton>
</GenaiButton>
);
};

return (
<div
className={classnames('pipeline-action-container pipeline-history-container', {
active: isOpen,
})}
>
{renderPipelineGenaiSummaryBtn()}
<PipelineGenaiSummaryModal
isOpen={isOpen}
onClose={() => setIsOpen(false)}
anchorEl={buttonRef.current}
pipelineName={pipelineName}
summary={summary}
/>
</div>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@ import ApolloClient from 'apollo-boost';
import { InMemoryCache, IntrospectionFragmentMatcher } from 'apollo-cache-inmemory';
import introspectionQueryResultData from '../../../../../../graphql/fragments/fragmentTypes.json';
import SessionTokenStore from 'services/SessionTokenStore';
import { useFeatureFlagDefaultFalse } from 'services/react/customHooks/useFeatureFlag';
import {
useFeatureFlagDefaultFalse,
useFeatureFlagDefaultTrue,
} from 'services/react/customHooks/useFeatureFlag';
import { PipelineGenaiSummaryButton } from './PipelineGenaiSummaryButton';

const fragmentMatcher = new IntrospectionFragmentMatcher({
introspectionQueryResultData,
Expand Down Expand Up @@ -106,6 +110,8 @@ export default function PipelineDetailsButtons({
const lifecycleManagementEditEnabled = useFeatureFlagDefaultFalse(
'lifecycle.management.edit.enabled'
);
// TODO: replace with useFeatureFlagDefaultFalse when productionising
const genaiPipelineSummaryEnabled = useFeatureFlagDefaultTrue('genai.pipeline.summary.enabled');
return (
<ApolloProvider client={client}>
<Provider store={PipelineConfigurationsStore}>
Expand Down Expand Up @@ -142,6 +148,9 @@ export default function PipelineDetailsButtons({
/>
<PipelineSummaryButton pipelineType={pipelineType} pipelineName={pipelineName} />
{lifecycleManagementEditEnabled && <PipelineHistoryButton pipelineName={pipelineName} />}
{genaiPipelineSummaryEnabled && (
<PipelineGenaiSummaryButton pipelineName={pipelineName} />
)}
</div>
</Provider>
</ApolloProvider>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* Copyright © 2024 Cask Data, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/

import React from 'react';
import styled from 'styled-components';
import T from 'i18n-react';
import PipelineModeless from 'components/PipelineDetails/PipelineModeless';
import MarkdownWithStyles from 'components/shared/Markdown';
import LoadingSVG from 'components/shared/LoadingSVG';

const PREFIX = 'features.PipelineDetails.TopPanel';

interface IPipelineGenaiSummaryModalProps {
pipelineName?: string;
summary: string;
anchorEl: any;
onClose: () => void;
isOpen: boolean;
}

const SummaryContainer = styled.div`
height: 100%;
width: 100%;
max-width: 880px;
max-height: min(60vh, 800px);
padding: 0 20px;
overflow: auto;
`;

const PopperClass = styled.div`
max-width: 880px;
`;

const LoadingContainer = styled.div`
width: 100%;
height: 100px;
display: flex;
align-items: center;
justify-content: center;
`;

export const PipelineGenaiSummaryModal = ({
pipelineName,
summary,
anchorEl,
onClose,
isOpen,
}: IPipelineGenaiSummaryModalProps) => {
return (
<PipelineModeless
open={isOpen}
onClose={onClose}
anchorEl={anchorEl}
popoverClassName={String(PopperClass)}
title={
pipelineName
? T.translate(`${PREFIX}.genaiSummaryOfPipeline`, { pipelineName })
: T.translate(`${PREFIX}.genaiSummaryOfUnnamedPipeline`)
}
>
<SummaryContainer>
{summary ? (
<MarkdownWithStyles markdown={summary} />
) : (
<LoadingContainer>
<LoadingSVG />
</LoadingContainer>
)}
</SummaryContainer>
</PipelineModeless>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
*/

import IconSVG from 'components/shared/IconSVG';
import React, { useEffect, useState } from 'react';
import React, { useEffect, useRef, useState } from 'react';
import GraphicEqIcon from '@material-ui/icons/GraphicEq';
import { objectQuery } from 'services/helpers';
import PipelineConfigurationsStore, {
ACTIONS as PipelineConfigurationsActions,
Expand All @@ -24,6 +25,7 @@ import { PipelineConfigure } from '../PipelineConfigure';
import {
ActionButtonsContainer,
BorderRightButton,
BorderRightOnlyButton,
ButtonLabel,
CommonButton,
CustomTooltip,
Expand All @@ -36,6 +38,8 @@ import {
PreviewModeButton,
RunTimeSpan,
} from './styles';
import { useFeatureFlagDefaultTrue } from 'services/react/customHooks/useFeatureFlag';
import { PipelineGenaiSummaryModal } from 'components/PipelineDetails/PipelineDetailsTopPanel/PipelineGenaiSummaryModal';

interface IDuration {
minutes: string;
Expand All @@ -53,6 +57,7 @@ interface IActionButtonsProps {
toggleScheduler: () => void;
hasNodes: boolean;
onSaveDraft: () => void;
onPipelineSummarize: (summarySetter: (string) => void) => void;
onPublish: () => void;
onImport: () => void;
onFileSelect: (files: FileList) => void;
Expand Down Expand Up @@ -90,6 +95,7 @@ export const ActionButtons = ({
toggleScheduler,
hasNodes,
onSaveDraft,
onPipelineSummarize,
onPublish,
onImport,
onFileSelect,
Expand All @@ -116,6 +122,20 @@ export const ActionButtons = ({
getStoreConfig,
}: IActionButtonsProps) => {
const [selectedFile, setSelectedFile] = useState(null);
const [genaiSummary, setGenaiSummary] = useState('');
const [isSummaryModalOpen, setSummaryModalOpen] = useState(false);
const pipelineGenaiSummaryButtonRef = useRef(null);
// TODO: replace with useFeatureFlagDefaultFalse when productionising
const genaiPipelineSummaryEnabled = useFeatureFlagDefaultTrue('genai.pipeline.summary.enabled');

const onGenaiSummary = () => {
if (!genaiPipelineSummaryEnabled) {
return;
}
setGenaiSummary('');
onPipelineSummarize(setGenaiSummary);
setSummaryModalOpen(true);
};

const handleFile = (event) => {
if (!objectQuery(event, 'target', 'files', 0)) {
Expand Down Expand Up @@ -365,6 +385,27 @@ export const ActionButtons = ({
</BorderRightButton>
</span>
</CustomTooltip>
{genaiPipelineSummaryEnabled && (
<CustomTooltip
title={hasNodes ? '' : 'Start building a pipeline before summarizing'}
arrow
placement="bottom"
>
<span>
<BorderRightOnlyButton
disabled={!hasNodes}
onClick={!hasNodes || onGenaiSummary}
data-cy="pipeline-genai-summary-btn"
data-testid="pipeline-genai-summary-btn"
>
<div ref={pipelineGenaiSummaryButtonRef}>
<GraphicEqIcon viewBox="1 1 22 22" fontSize="small" className="icon-svg" />
<ButtonLabel>Summarize</ButtonLabel>
</div>
</BorderRightOnlyButton>
</span>
</CustomTooltip>
)}
</>
)}
</ActionButtonsContainer>
Expand All @@ -384,6 +425,14 @@ export const ActionButtons = ({
validatePluginProperties={validatePluginProperties}
getRuntimeArgs={getRuntimeArgs}
></PipelineConfigure>
{hasNodes && pipelineGenaiSummaryButtonRef.current && (
<PipelineGenaiSummaryModal
isOpen={isSummaryModalOpen}
anchorEl={pipelineGenaiSummaryButtonRef.current}
onClose={() => setSummaryModalOpen(false)}
summary={genaiSummary}
/>
)}
</>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ export const BorderRightButton = styled(BaseButton)`
border-right: 1px solid ${greyBorder};
`;

export const BorderRightOnlyButton = styled(BorderRightButton)`
border-left: none;
position: relative;
`;

export const PreviewModeButton = styled(BaseButton)`
background-color: ${previewActive};
`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ export const DescriptionTextField = styled(TextField)`
`;

export const EditStatus = styled.div`
width: calc(20vw - 110px);
width: calc(20vw - 180px);
flex-wrap: wrap;
display: flex;
background-color: transparent;
Expand Down
Loading

0 comments on commit e14c948

Please sign in to comment.