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

issue 1651: progress bar error state #1673

Merged
merged 15 commits into from
Mar 26, 2024
Merged
Show file tree
Hide file tree
Changes from 12 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
71 changes: 36 additions & 35 deletions src/features/locators/components/LocatorsProgress.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
selectDeletedByPageObj,
selectFailedByPageObject,
} from '../selectors/locatorsFiltered.selectors';
import cn from 'classnames';

let timer: NodeJS.Timeout;

Expand Down Expand Up @@ -55,41 +56,41 @@ export const LocatorsProgress = () => {
return () => clearTimeout(timer);
}, [generated, inProgress, deleted]);

const className = cn({
'jdn__progress_hide-info': readinessPercentage !== 100 && generationStatus !== LocatorsGenerationStatus.failed,
});

if (!isProgressActive) {
return null;
}

return (
<>
{isProgressActive ? (
<div className="jdn__locator-list-progress">
<div className="jdn__locator-list-progress-text">
{generationStatus === LocatorsGenerationStatus.failed ? (
<>
<Footnote>{LocatorGenerationMessage.failed}</Footnote>
<span className="ant-notification-notice-btn">
<Button type="text" size="small" onClick={handleRetry}>
Retry
</Button>
</span>
</>
) : (
<Footnote>
{size(inProgress)
? `${LocatorGenerationMessage.started} (${calculationReady}/${total})`
: size(failed)
? `${LocatorGenerationMessage.completeWithErrors} (${calculationReady}/${total})`
: `${LocatorGenerationMessage.complete}`}
</Footnote>
)}
</div>
<Progress
status={generationStatus === LocatorsGenerationStatus.failed ? 'exception' : undefined}
percent={readinessPercentage}
className={
readinessPercentage !== 100 && generationStatus !== LocatorsGenerationStatus.failed
? 'jdn__progress_hide-info'
: ''
}
/>
</div>
) : null}
</>
<div className="jdn__locator-list-progress">
<div className="jdn__locator-list-progress-text">
{generationStatus === LocatorsGenerationStatus.failed ? (
<>
<Footnote>{LocatorGenerationMessage.failed}</Footnote>
<span className="ant-notification-notice-btn">
<Button type="text" size="small" onClick={handleRetry}>
Retry
</Button>
</span>
</>
) : (
<Footnote>
{size(inProgress)
? `${LocatorGenerationMessage.started} (${calculationReady}/${total})`
: size(failed)
? `${LocatorGenerationMessage.completeWithErrors} (${calculationReady}/${total})`
: `${LocatorGenerationMessage.complete}`}
</Footnote>
)}
</div>
<Progress
status={generationStatus === LocatorsGenerationStatus.failed ? 'exception' : undefined}
percent={readinessPercentage}
className={className}
/>
</div>
);
};
28 changes: 18 additions & 10 deletions src/features/locators/reducers/identifyElements.thunk.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,23 @@
import type { ActionReducerMapBuilder, Middleware } from '@reduxjs/toolkit';
import { createAsyncThunk } from '@reduxjs/toolkit';
import { predictElements } from '../../../pageServices/pageDataHandlers';
import { findByRules, predictElements } from '../../../pageServices/pageDataHandlers';
import { IdentificationStatus, LocatorsState, PredictedEntity } from '../../locators/types/locator.types';
import { setCurrentPageObj, setPageData } from '../../pageObjects/pageObject.slice';
import { setFilter } from '../../filter/filter.slice';
import { PageObjectId } from '../../pageObjects/types/pageObjectSlice.types';
import { defaultLibrary, ElementLibrary, predictEndpoints } from '../types/generationClasses.types';

import { createLocators } from './createLocators.thunk';
import { findByRules } from '../utils/generationButton';
import { getLocalStorage, LocalStorageKey } from '../../../common/utils/localStorage';
import { selectAutoGeneratingLocatorTypes, selectPageObjById } from '../../pageObjects/selectors/pageObjects.selectors';
import { RootState } from '../../../app/store/store';
import { runLocatorsGeneration } from './runLocatorsGeneration.thunk';
import { finishProgressBar } from '../../pageObjects/progressBar.slice';
import { finishProgressBar, setProgressError } from '../../pageObjects/progressBar.slice';
import { delay } from '../utils/delay';
import { fetchPageDocument } from '../../../services/pageDocument/fetchPageDocument.thunk';
import { createDocumentForRobula } from '../../../services/pageDocument/pageDocument.slice';

interface Meta {
library: ElementLibrary;
pageObj: PageObjectId;
}

Expand All @@ -40,8 +38,17 @@ export const identifyElements = createAsyncThunk('locators/identifyElements', as
Then adds needed locators to state and runs locator value generation. */
try {
const endpoint = predictEndpoints[library];
const { data, pageData } =
library !== ElementLibrary.Vuetify ? await predictElements(endpoint) : await findByRules();
const { data, pageData, error } =
library === ElementLibrary.Vuetify ? await findByRules() : await predictElements(endpoint);

if (error) {
throw new Error(error);
}

if (!data) {
throw new Error('No data received from server');
}

const locators = data
.filter((el: PredictedEntity) => el.is_shown)
.map((el: PredictedEntity) => {
Expand All @@ -60,13 +67,15 @@ export const identifyElements = createAsyncThunk('locators/identifyElements', as
/* progress-bar finish animation delay: */
await delay(2000);

thunkAPI.dispatch(setPageData({ id: pageObj, pageData }));
if (pageData) {
thunkAPI.dispatch(setPageData({ id: pageObj, pageData }));
}

thunkAPI.dispatch(createLocators({ predictedElements: locators, library }));

return thunkAPI.fulfillWithValue(locators);
} catch (error) {
// can use params in the function so that when the progress bar is finished there will be information about errors
thunkAPI.dispatch(finishProgressBar());
thunkAPI.dispatch(setProgressError(error.message));
return thunkAPI.rejectWithValue(null);
}
});
Expand All @@ -77,7 +86,6 @@ export const identifyElementsReducer = (builder: ActionReducerMapBuilder<Locator
state.status = IdentificationStatus.loading;
})
.addCase(identifyElements.fulfilled, (state, { payload }) => {
// @ts-ignore
if (payload.length) state.status = IdentificationStatus.preparing;
else state.status = IdentificationStatus.noElements;
})
Expand Down
12 changes: 0 additions & 12 deletions src/features/locators/utils/generationButton.ts

This file was deleted.

34 changes: 9 additions & 25 deletions src/features/pageObjects/components/PageObjGenerationSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,10 @@ import { IN_DEVELOPMENT_TITLE } from '../../../common/constants/constants';

import { useOnboardingContext } from '../../onboarding/OnboardingProvider';
import { OnboardingStep } from '../../onboarding/constants';
import { useOnboarding } from '../../onboarding/useOnboarding';
import { resetProgressBar, startProgressBar } from '../progressBar.slice';
import { selectIsPageObjectsListUIEnabled } from '../selectors/pageObjectsListUI.selectors';
import { disablePageObjectsListUI } from '../pageObjectsListUI.slice';
import { OnboardingTooltip } from '../../onboarding/components/OnboardingTooltip';
import PageObjSettingsItem from './PageObjSettingsItem';

interface Props {
pageObj: PageObjectId;
library: ElementLibrary;
url: string;
}

// ToDo move to constants
const libraryOptions = [
{
Expand Down Expand Up @@ -98,27 +89,20 @@ const locatorTypeOptions = [
},
];

export const PageObjGenerationSettings: React.FC<Props> = ({ pageObj, library, url }) => {
interface Props {
pageObj: PageObjectId;
url: string;
isOnboardingOpen: boolean;
handleGenerate: () => void;
}

export const PageObjGenerationSettings: React.FC<Props> = ({ pageObj, url, handleGenerate, isOnboardingOpen }) => {
const status = useSelector((state: RootState) => state.locators.present.status);
const currentPageObject = useSelector(selectCurrentPageObject);
const pageObjects = useSelector(selectPageObjects);

const { isOnboardingOpen, handleOnChangeStep } = useOnboarding();

const dispatch = useDispatch<AppDispatch>();

const handleGenerate = () => {
if (isOnboardingOpen) handleOnChangeStep(OnboardingStep.Generating);
dispatch(setHideUnadded({ id: pageObj, hideUnadded: false }));
dispatch(identifyElements({ library, pageObj }));
// disable UI for PageObjList settings:
dispatch(disablePageObjectsListUI());
// reset to default progress bar:
dispatch(resetProgressBar());
// show and start progress bar:
dispatch(startProgressBar());
};

const refSettings = useRef<HTMLElement | null>(null);
const generationButtonRef = useRef<HTMLElement | null>(null);
const { updateStepRefs } = useOnboardingContext();
Expand Down Expand Up @@ -164,7 +148,7 @@ export const PageObjGenerationSettings: React.FC<Props> = ({ pageObj, library, u

const handleEmptyPO = () => {
dispatch(setHideUnadded({ id: pageObj, hideUnadded: true }));
dispatch(identifyElements({ library, pageObj }));
dispatch(identifyElements({ pageObj }));
};

const isLoading = () => isIdentificationLoading(status) && currentPageObject?.id === pageObj;
Expand Down
56 changes: 32 additions & 24 deletions src/features/pageObjects/components/PageObjList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Icon from '@ant-design/icons';
import { Collapse, Tooltip, Typography } from 'antd';
import { isNil, size } from 'lodash';
import React, { useEffect, useRef, useState } from 'react';
import { useSelector } from 'react-redux';
import { useDispatch, useSelector } from 'react-redux';

import { CaretDown } from '@phosphor-icons/react';
import PageSvg from '../assets/page.svg';
Expand All @@ -14,15 +14,19 @@ import { Locator } from '../../locators/Locator';
import { PageObjMenu } from './PageObjMenu';
import { PageObjListHeader } from './PageObjListHeader';
import { useNotifications } from '../../../common/components/notification/useNotifications';
import { RootState } from '../../../app/store/store';
import { ILocator } from '../../locators/types/locator.types';
import { PageObject, PageObjectId } from '../types/pageObjectSlice.types';
import { ElementLibrary } from '../../locators/types/generationClasses.types';
import { AppDispatch, RootState } from '../../../app/store/store';
import { PageObject } from '../types/pageObjectSlice.types';
import { PageType } from '../../../app/types/mainSlice.types';
import { selectConfirmedLocators } from '../../locators/selectors/locatorsFiltered.selectors';
import { FrameworkType } from '../../../common/types/common';
import ProgressBar from './ProgressBar';
import { selectIsProgressBarFinished } from '../selectors/progressBar.selector';
import { identifyElements } from '../../locators/reducers/identifyElements.thunk';
import { OnboardingStep } from '../../onboarding/constants';
import { setHideUnadded } from '../pageObject.slice';
import { disablePageObjectsListUI } from '../pageObjectsListUI.slice';
import { resetProgressBar, startProgressBar } from '../progressBar.slice';
import { useOnboarding } from '../../onboarding/useOnboarding';

interface Props {
jdiTemplate?: Blob;
Expand All @@ -43,6 +47,10 @@ export const PageObjList: React.FC<Props> = ({ jdiTemplate, vividusTemplate }) =
const pageObjects: PageObject[] = useSelector(selectPageObjects);
const [activePanel, setActivePanel] = useState<string[] | undefined>([DEFAULT_ACTIVE_KEY]);

const { isOnboardingOpen, handleOnChangeStep } = useOnboarding();

const dispatch = useDispatch<AppDispatch>();

const contentRef = useRef<HTMLDivElement>(null);
useNotifications(contentRef?.current);

Expand All @@ -56,24 +64,18 @@ export const PageObjList: React.FC<Props> = ({ jdiTemplate, vividusTemplate }) =
}
}, [currentPageObjectIndex]);

const renderLocators = (elements: ILocator[], library: ElementLibrary) => {
return elements.map((element) => (
<Locator {...{ element, library }} key={element.element_id} currentPage={PageType.PageObject} />
));
};
const handleGenerate = () => {
const pageObj = Number(activePanel?.[0]) || 0;

const renderContent = (
pageObjId: PageObjectId,
url: string,
elements: ILocator[],
library: ElementLibrary,
isPageObjectNotEmpty: boolean,
) => {
if (isPageObjectNotEmpty && isProgressBarFinished && elements.length) {
return renderLocators(elements, library);
} else {
return <PageObjGenerationSettings pageObj={pageObjId} {...{ library, url }} />;
}
if (isOnboardingOpen) handleOnChangeStep(OnboardingStep.Generating);
dispatch(setHideUnadded({ id: pageObj, hideUnadded: false }));
dispatch(identifyElements({ pageObj }));
// disable UI for PageObjList settings:
dispatch(disablePageObjectsListUI());
// reset to default progress bar:
dispatch(resetProgressBar());
// show and start progress bar:
dispatch(startProgressBar());
};

const toggleExpand = () => {
Expand Down Expand Up @@ -145,12 +147,18 @@ export const PageObjList: React.FC<Props> = ({ jdiTemplate, vividusTemplate }) =
</>
}
>
{renderContent(id, url, elements, library, isPageObjectNotEmpty)}
{isPageObjectNotEmpty && isProgressBarFinished && elements.length ? (
elements.map((element) => (
<Locator {...{ element, library }} key={element.element_id} currentPage={PageType.PageObject} />
))
) : (
<PageObjGenerationSettings pageObj={id} {...{ url, isOnboardingOpen, handleGenerate }} />
)}
</Collapse.Panel>
);
})}
</Collapse>
<ProgressBar />
<ProgressBar onRetry={handleGenerate} />
</>
) : (
<PageObjectPlaceholder addPageObjectCallback={setActivePanel} />
Expand Down
Loading
Loading