import withMetricsContext from '../../../app/components/metrics/withMetricsContext';
import { Location, Router, withRouter } from '../../../components/hoc/withRouter';
import { CodeScope, getCodeUrl, getProjectUrl } from '../../../helpers/urls';
-import { useBranchesQuery } from '../../../queries/branch';
-import { BranchLike } from '../../../types/branch-like';
+import { WithBranchLikesProps, useBranchesQuery } from '../../../queries/branch';
import { ComponentQualifier, isPortfolioLike } from '../../../types/component';
import { Breadcrumb, Component, ComponentMeasure, Dict, Metric } from '../../../types/types';
import { addComponent, addComponentBreadcrumbs, clearBucket } from '../bucket';
}
}
-interface WithBranchLikesProps {
- branchLikes?: BranchLike[];
- branchLike?: BranchLike;
-}
-
function withBranchLikes<P extends { component?: Component }>(
WrappedComponent: React.ComponentType<React.PropsWithChildren<P & WithBranchLikesProps>>,
): React.ComponentType<React.PropsWithChildren<Omit<P, 'branchLike' | 'branchLikes'>>> {
import '../../../components/search-navigator.css';
import { getBranchLikeQuery, isPullRequest, isSameBranchLike } from '../../../helpers/branch-like';
import { translate } from '../../../helpers/l10n';
-import { useBranchesQuery } from '../../../queries/branch';
-import { BranchLike } from '../../../types/branch-like';
+import { WithBranchLikesProps, useBranchesQuery } from '../../../queries/branch';
import { ComponentQualifier, isPortfolioLike } from '../../../types/component';
import { MeasurePageView } from '../../../types/measures';
import { MetricKey } from '../../../types/metrics';
import MeasureOverviewContainer from './MeasureOverviewContainer';
import MeasuresEmpty from './MeasuresEmpty';
-interface Props {
- branchLike?: BranchLike;
+interface Props extends WithBranchLikesProps {
component: ComponentMeasure;
location: Location;
router: Router;
isCustomGraph,
} from '../../../components/activity-graph/utils';
import { Location, Router, withRouter } from '../../../components/hoc/withRouter';
-import { getBranchLikeQuery } from '../../../helpers/branch-like';
+import { getBranchLikeQuery, isSameBranchLike } from '../../../helpers/branch-like';
import { parseDate } from '../../../helpers/dates';
import { serializeStringArray } from '../../../helpers/query';
-import { withBranchLikes } from '../../../queries/branch';
-import { BranchLike } from '../../../types/branch-like';
+import { WithBranchLikesProps, withBranchLikes } from '../../../queries/branch';
import {
ComponentQualifier,
isApplication,
} from '../utils';
import ProjectActivityAppRenderer from './ProjectActivityAppRenderer';
-interface Props {
- branchLike?: BranchLike;
+interface Props extends WithBranchLikesProps {
component: Component;
location: Location;
metrics: Dict<Metric>;
componentDidMount() {
this.mounted = true;
- this.firstLoadData(this.state.query, this.props.component);
+ if (this.isBranchReady()) {
+ this.firstLoadData(this.state.query, this.props.component);
+ }
}
componentDidUpdate(prevProps: Props) {
- if (prevProps.location.query !== this.props.location.query) {
- const query = parseQuery(this.props.location.query);
- if (query.graph !== this.state.query.graph || customMetricsChanged(this.state.query, query)) {
+ const unparsedQuery = this.props.location.query;
+
+ const hasQueryChanged = prevProps.location.query !== unparsedQuery;
+
+ const hasBranchChanged = !isSameBranchLike(prevProps.branchLike, this.props.branchLike);
+
+ if (this.isBranchReady() && (hasBranchChanged || hasQueryChanged)) {
+ const query = parseQuery(unparsedQuery);
+
+ if (
+ query.graph !== this.state.query.graph ||
+ customMetricsChanged(this.state.query, query) ||
+ hasBranchChanged
+ ) {
if (this.state.initialized) {
this.updateGraphData(query.graph || DEFAULT_GRAPH, query.customMetrics);
} else {
this.mounted = false;
}
+ isBranchReady = () =>
+ isPortfolioLike(this.props.component.qualifier) ||
+ (this.props.branchLike !== undefined && !this.props.isFetchingBranch);
+
handleAddCustomEvent = (analysisKey: string, name: string, category?: string) => {
return createEvent(analysisKey, name, category).then(({ analysis, ...event }) => {
if (this.mounted) {
import ApplicationServiceMock from '../../../../api/mocks/ApplicationServiceMock';
import { ProjectActivityServiceMock } from '../../../../api/mocks/ProjectActivityServiceMock';
import { TimeMachineServiceMock } from '../../../../api/mocks/TimeMachineServiceMock';
+import { mockBranchList } from '../../../../api/mocks/data/branches';
import { parseDate } from '../../../../helpers/dates';
import { mockComponent } from '../../../../helpers/mocks/component';
import {
save: jest.fn(),
}));
+jest.mock('../../../../api/branches', () => ({
+ getBranches: () => {
+ isBranchReady = true;
+ return Promise.resolve(mockBranchList());
+ },
+}));
+
const applicationHandler = new ApplicationServiceMock();
const projectActivityHandler = new ProjectActivityServiceMock();
const timeMachineHandler = new TimeMachineServiceMock();
+let isBranchReady = false;
+
beforeEach(() => {
+ isBranchReady = false;
+
jest.clearAllMocks();
applicationHandler.reset();
projectActivityHandler.reset();
breadcrumbs: [{ key: 'breadcrumb', name: 'breadcrumb', qualifier }],
}),
);
- await ui.appLoaded();
+
+ await ui.appLoaded({ doNotWaitForBranch: true });
expect(ui.newCodeLegend.query()).not.toBeInTheDocument();
},
}),
);
- await ui.appLoaded();
+ await ui.appLoaded({ doNotWaitForBranch: true });
// If it didn't fail, it means we correctly queried for project "foo".
expect(ui.activityItem.getAll().length).toBe(4);
deleteBtn: byRole('button', { name: 'delete' }),
// Misc.
- loading: byLabelText('loading'),
+ loading: byText('loading'),
baseline: byText('project_activity.new_code_period_start'),
bugsPopupCell: byRole('cell', { name: MetricKey.bugs }),
monthSelector: byTestId('month-select'),
user,
ui: {
...ui,
- async appLoaded() {
+ async appLoaded({ doNotWaitForBranch }: { doNotWaitForBranch?: boolean } = {}) {
await waitFor(() => {
expect(ui.loading.query()).not.toBeInTheDocument();
});
+
+ if (!doNotWaitForBranch) {
+ await waitFor(() => {
+ expect(isBranchReady).toBe(true);
+ });
+ }
},
async changeGraphType(type: GraphType) {
}),
) {
return renderAppWithComponentContext(
- 'project/activity',
+ `project/activity?id=${component.key}`,
() => <Route path="*" element={<ProjectActivityAppContainer />} />,
{
metrics: keyBy(
};
}
+export interface WithBranchLikesProps {
+ branchLikes?: BranchLike[];
+ branchLike?: BranchLike;
+ isFetchingBranch?: boolean;
+}
+
export function withBranchLikes<P extends { component?: Component }>(
- WrappedComponent: React.ComponentType<
- P & { branchLikes?: BranchLike[]; branchLike?: BranchLike; isFetchingBranch?: boolean }
- >,
-): React.ComponentType<Omit<P, 'branchLike' | 'branchLikes'>> {
+ WrappedComponent: React.ComponentType<React.PropsWithChildren<P & WithBranchLikesProps>>,
+): React.ComponentType<React.PropsWithChildren<Omit<P, 'branchLike' | 'branchLikes'>>> {
return function WithBranchLike(p: P) {
const { data, isFetching } = useBranchesQuery(p.component);
return (