Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added warning if flow is not published #3142

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 43 additions & 13 deletions src/components/floweditor/FlowEditor.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { BrowserRouter as Router } from 'react-router-dom';
import { MemoryRouter, Route, Routes } from 'react-router-dom';
import { MockedProvider } from '@apollo/client/testing';
import { render, waitFor, fireEvent, screen } from '@testing-library/react';
import { vi } from 'vitest';
Expand All @@ -15,6 +15,7 @@ import {
resetFlowCount,
getFlowTranslations,
getTemplateFlow,
unsavedFlow,
} from 'mocks/Flow';
import { conversationQuery } from 'mocks/Chat';
import {
Expand All @@ -29,20 +30,19 @@ import * as Notification from 'common/notification';

window.location = { assign: vi.fn() } as any;

vi.mock('react-router-dom', async () => {
return {
...(await vi.importActual<any>('react-router-dom')),
useParams: () => ({ uuid: 'b050c652-65b5-4ccf-b62b-1e8b3f328676' }),
};
});

vi.mock('axios');
const mockedAxios = axios as any;

vi.mock('../simulator/Simulator', () => ({
default: ({ message }: { message: string }) => <div data-testid="simulator">{message}</div>, // Mocking the component's behavior
}));

const mockedUsedNavigate = vi.fn();
vi.mock('react-router-dom', async () => ({
...(await vi.importActual('react-router-dom')),
useNavigate: () => mockedUsedNavigate,
}));

const mocks = [
messageReceivedSubscription({ organizationId: null }),
messageSendSubscription({ organizationId: null }),
Expand All @@ -60,16 +60,19 @@ const mocks = [
getFlowTranslations,
];

const activeFlowMocks = [...mocks, getActiveFlow];
const activeFlowMocks = [...mocks, getActiveFlow, getActiveFlow];
const inActiveFlowMocks = [...mocks, getInactiveFlow];
const noKeywordMocks = [...mocks, getFlowWithoutKeyword, resetFlowCount];
const templateFlowMocks = [...mocks, getTemplateFlow, resetFlowCount];
const flowWithUnsavedChanges = [...mocks, unsavedFlow, unsavedFlow];

const wrapperFunction = (mocks: any) => (
const wrapperFunction = (mocks: any, uuid: string = 'b050c652-65b5-4ccf-b62b-1e8b3f328676') => (
<MockedProvider mocks={mocks} addTypename={false}>
<Router>
<FlowEditor />
</Router>
<MemoryRouter initialEntries={[`/flow/configure/${uuid}`]}>
<Routes>
<Route path="flow/configure/:uuid" element={<FlowEditor />} />
</Routes>
</MemoryRouter>
</MockedProvider>
);

Expand All @@ -95,6 +98,12 @@ test('it should have a back button that redirects to flow page', async () => {
await waitFor(() => {
expect(getByTestId('back-button')).toBeInTheDocument();
});

fireEvent.click(getByTestId('back-button'));

await waitFor(() => {
expect(mockedUsedNavigate).toHaveBeenCalled();
});
});

test('it should display name of the flow', async () => {
Expand Down Expand Up @@ -313,4 +322,25 @@ test('template words should have template: prefix', async () => {
await waitFor(() => {
expect(screen.getByTestId('simulator')).toHaveTextContent('template:help workflow');
});

fireEvent.click(screen.getByTestId('back-button'));

await waitFor(() => {
expect(mockedUsedNavigate).toHaveBeenCalled();
});
});

test('if flow is not published it should show warning', async () => {
const { getByTestId } = render(wrapperFunction(flowWithUnsavedChanges, '63397051-789d-418d-9388-2ef7eb1268bb'));

await waitFor(() => {
expect(getByTestId('back-button')).toBeInTheDocument();
});

fireEvent.click(getByTestId('back-button'));

await waitFor(() => {
expect(screen.getByTestId('dialogBox')).toBeInTheDocument();
});
fireEvent.click(getByTestId('cancel-button'));
});
86 changes: 45 additions & 41 deletions src/components/floweditor/FlowEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
const params = useParams();
const { uuid } = params;
const navigate = useNavigate();
const [publishDialog, setPublishDialog] = useState(false);
const [publishDialog, setPublishDialog] = useState<string | null>(null);
const [loading, setLoading] = useState(true);
const [flowEditorLoaded, setFlowEditorLoaded] = useState(false);
const [flowId, setFlowId] = useState();
Expand Down Expand Up @@ -127,7 +127,7 @@
},
});

const { data: flowName } = useQuery(GET_FLOW_DETAILS, {
const { data: flowData, refetch } = useQuery(GET_FLOW_DETAILS, {
fetchPolicy: 'network-only',
variables: {
filter: {
Expand All @@ -138,15 +138,15 @@
});

useEffect(() => {
if (flowName && flowName.flows.length > 0) {
setFlowId(flowName.flows[0].id);
setIsTemplate(flowName.flows[0].isTemplate);
if (flowData && flowData.flows.length > 0) {
setFlowId(flowData.flows[0].id);
setIsTemplate(flowData.flows[0].isTemplate);
}
}, [flowName]);
}, [flowData]);

if (flowName && flowName.flows.length > 0) {
flowTitle = flowName.flows[0].name;
flowKeywords = flowName.flows[0].keywords.join(', ');
if (flowData && flowData.flows.length > 0) {
flowTitle = flowData.flows[0].name;
flowKeywords = flowData.flows[0].keywords.join(', ');
}

const handleResetFlowCount = () => {
Expand All @@ -167,31 +167,25 @@
additionalTitleStyles={styles.DialogTitle}
>
<div className={styles.DialogContent}>
Please be careful, this cannot be undone. Once you reset the flow counts you will lose
tracking of how many times a node was triggered for users.
Please be careful, this cannot be undone. Once you reset the flow counts you will lose tracking of how many
times a node was triggered for users.
</div>
</DialogBox>
);
}

if (showTranslateFlowModal) {
modal = (
<FlowTranslation
loadFlowEditor={loadFlowEditor}
flowId={flowId}
setDialog={setShowTranslateFlowModal}
/>
);
modal = <FlowTranslation loadFlowEditor={loadFlowEditor} flowId={flowId} setDialog={setShowTranslateFlowModal} />;
}

useEffect(() => {
if (flowName) {
if (flowData) {
document.title = flowTitle;
}
return () => {
document.title = APP_NAME;
};
}, [flowName]);
}, [flowData]);

useEffect(() => {
if (flowId) {
Expand Down Expand Up @@ -234,7 +228,7 @@
};

const handleCancelFlow = () => {
setPublishDialog(false);
setPublishDialog(null);
setIsError(false);
setFlowValidation('');
};
Expand Down Expand Up @@ -267,8 +261,7 @@
}}
>
<p className={styles.DialogDescription}>
You can either go back and edit it later or <br /> &lsquo;Take Over&rsquo; this flow to
start editing now.
You can either go back and edit it later or <br /> &lsquo;Take Over&rsquo; this flow to start editing now.
</p>
</DialogBox>
);
Expand All @@ -277,7 +270,7 @@
if (publishDialog) {
dialog = (
<DialogBox
title="Ready to publish?"
title={publishDialog === 'publish' ? 'Publish flow' : 'Unsaved changes.'}
buttonOk="Publish & stay"
titleAlign="center"
buttonOkLoading={publishLoading}
Expand All @@ -296,7 +289,11 @@
buttonCancel="Cancel"
additionalTitleStyles={styles.PublishDialogTitle}
>
<p className={styles.DialogDescription}>New changes will be activated for the users</p>
<p className={styles.DialogDescription}>
{publishDialog === 'publish'
? 'New changes will be activated for the users'
: 'You have unsaved changes. Do you want to publish the flow before exiting?'}
</p>
</DialogBox>
);
}
Expand All @@ -307,7 +304,7 @@
title="Errors were detected in the flow. Would you like to continue modifying?"
buttonOk="Publish"
handleOk={() => {
setPublishDialog(false);
setPublishDialog(null);

Check warning on line 307 in src/components/floweditor/FlowEditor.tsx

View check run for this annotation

Codecov / codecov/patch

src/components/floweditor/FlowEditor.tsx#L307

Added line #L307 was not covered by tests
setIsError(false);
setPublished(true);
}}
Expand All @@ -325,12 +322,12 @@
if (!stayOnPublish) {
return <Navigate to="/flow" />;
}
setPublishDialog(false);
setPublishDialog(null);

Check warning on line 325 in src/components/floweditor/FlowEditor.tsx

View check run for this annotation

Codecov / codecov/patch

src/components/floweditor/FlowEditor.tsx#L325

Added line #L325 was not covered by tests
setPublished(false);
}

const getFlowKeyword = () => {
const flows = flowName ? flowName.flows : null;
const flows = flowData ? flowData.flows : null;
if (flows && flows.length > 0) {
const { isActive, keywords, isTemplate, name } = flows[0];
if (isTemplate) {
Expand All @@ -345,20 +342,32 @@
}
};

const handleBack = async () => {
if (isTemplate) {
navigate('/flow?isTemplate=true');
return;
}

refetch().then(({ data }) => {
const isFlowPublished = data.flows[0].lastChangedAt === null;
if (isFlowPublished) {
navigate('/flow');
} else {
setPublishDialog('unsaved');
}
});
};

return (
<>
{exportFlowloading && <BackdropLoader />}
{dialog}
<div className={styles.Header}>
<div className={styles.Title}>
<BackIconFlow
onClick={() => (isTemplate ? navigate('/flow?isTemplate=true') : navigate('/flow'))}
className={styles.BackIcon}
data-testid="back-button"
/>
<BackIconFlow onClick={handleBack} className={styles.BackIcon} data-testid="back-button" />
<div>
<Typography variant="h6" data-testid="flowName">
{flowName ? flowTitle : 'Flow'}
{flowData ? flowTitle : 'Flow'}
</Typography>
<div>{flowKeywords}</div>
</div>
Expand Down Expand Up @@ -436,7 +445,7 @@
color="primary"
data-testid="button"
disabled={isTemplate}
onClick={() => setPublishDialog(true)}
onClick={() => setPublishDialog('publish')}
>
<PublishIcon className={styles.Icon} />
Publish
Expand All @@ -445,12 +454,7 @@
</div>

{showSimulator && (
<Simulator
setShowSimulator={setShowSimulator}
hasResetButton
flowSimulator
message={getFlowKeyword()}
/>
<Simulator setShowSimulator={setShowSimulator} hasResetButton flowSimulator message={getFlowKeyword()} />
)}
{modal}
<div className={styles.FlowContainer}>
Expand Down
2 changes: 2 additions & 0 deletions src/graphql/queries/Flow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ export const GET_FLOW_DETAILS = gql`
name
keywords
isTemplate
lastPublishedAt
lastChangedAt
}
}
`;
Expand Down
25 changes: 16 additions & 9 deletions src/mocks/Flow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -268,12 +268,12 @@ export const filterFlowWithNameOrKeywordOrTagQuery = {
},
};

const getFlowDetails = (isActive = true, keywords = ['help'], isTemplate = false) => ({
const getFlowDetails = (data?: any, uuid: string = 'b050c652-65b5-4ccf-b62b-1e8b3f328676') => ({
request: {
query: GET_FLOW_DETAILS,
variables: {
filter: {
uuid: 'b050c652-65b5-4ccf-b62b-1e8b3f328676',
uuid,
},
opts: {},
},
Expand All @@ -284,20 +284,27 @@ const getFlowDetails = (isActive = true, keywords = ['help'], isTemplate = false
flows: [
{
id: '1',
isActive,
name: 'help workflow',
keywords,
isTemplate,
isActive: true,
keywords: ['keyword'],
isTemplate: false,
lastPublishedAt: '2021-03-05T04:32:23Z',
lastChangedAt: null,
...data,
},
],
},
},
});

export const getActiveFlow = getFlowDetails();
export const getInactiveFlow = getFlowDetails(false);
export const getFlowWithoutKeyword = getFlowDetails(true, []);
export const getTemplateFlow = getFlowDetails(true, [], true);
export const getActiveFlow = getFlowDetails({ keywords: ['help'] });
export const getInactiveFlow = getFlowDetails({ isActive: false });
export const getFlowWithoutKeyword = getFlowDetails({ isActive: true, keywords: [] });
export const getTemplateFlow = getFlowDetails({ isActive: true, keywords: [], isTemplate: true });
export const unsavedFlow = getFlowDetails(
{ lastChangedAt: '2021-04-05T04:32:23Z' },
'63397051-789d-418d-9388-2ef7eb1268bb'
);

export const getFlowCountQuery = (filter: any) => ({
request: {
Expand Down
Loading