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

[cherry-pick] feat: add the downloading sub-step (#1221) #1223

Merged
merged 1 commit into from
Oct 14, 2024
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@

import React from 'react';
import { Provider } from 'react-redux';
import renderer from 'react-test-renderer';

import Head from '@/components/Head';
import getComponentRenderer from '@/services/__mocks__/getComponentRenderer';
import { BrandingData } from '@/services/bootstrap/branding.constant';
import { FakeStoreBuilder } from '@/store/__mocks__/storeBuilder';

import Head from '..';
const { createSnapshot } = getComponentRenderer(getComponent);

jest.mock('react-helmet', () => {
const Helmet = (props: { children: React.ReactElement[] }) => {
Expand All @@ -28,27 +29,29 @@ jest.mock('react-helmet', () => {
});

describe('The head component for setting document title', () => {
const store = new FakeStoreBuilder()
.withBranding({ title: 'Dummy product title' } as BrandingData)
.build();
afterEach(() => {
jest.clearAllMocks();
});

it('should render default title correctly', () => {
const element = (
<Provider store={store}>
<Head />
</Provider>
);

expect(renderer.create(element).toJSON()).toMatchSnapshot();
const snapshot = createSnapshot();
expect(snapshot.toJSON()).toMatchSnapshot();
});

it('should render Quick Add page title correctly', () => {
const element = (
<Provider store={store}>
<Head pageName="Quick Add" />
</Provider>
);

expect(renderer.create(element).toJSON()).toMatchSnapshot();
const snapshot = createSnapshot('Quick Add');
expect(snapshot.toJSON()).toMatchSnapshot();
});
});

function getComponent(pageName?: string): React.ReactElement {
const store = new FakeStoreBuilder()
.withBranding({ title: 'Dummy product title' } as BrandingData)
.build();

return (
<Provider store={store}>
<Head pageName={pageName} />
</Provider>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright (c) 2018-2024 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/

import React from 'react';

import { ProgressStepTitle } from '@/components/WorkspaceProgress/StepTitle';

export type Props = {
distance: -1 | 0 | 1 | undefined;
title: string | undefined;
};

export class PureSubCondition extends React.PureComponent<Props> {
public render(): React.ReactElement {
const { distance, title } = this.props;

if (!title) {
return <></>;
}

return (
<ol className="pf-c-wizard__nav-list">
<li className="pf-c-wizard__nav-item">
<div className="pf-c-wizard__nav-link">
<ProgressStepTitle distance={distance}>{title}</ProgressStepTitle>
</div>
</li>
</ol>
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* Copyright (c) 2018-2024 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/

import React from 'react';

import { PureSubCondition } from '@/components/WorkspaceProgress/StartingSteps/WorkspaceConditions/PureSubCondition';
import getComponentRenderer, { screen } from '@/services/__mocks__/getComponentRenderer';

const { createSnapshot, renderComponent } = getComponentRenderer(getComponent);

jest.mock('@/components/WorkspaceProgress/StepTitle');

describe('Starting sub-steps, checking rendering', () => {
afterEach(() => {
jest.clearAllMocks();
});

test('snapshot with no title', () => {
expect(createSnapshot(undefined)).toMatchSnapshot();
});

test('snapshot with a title', () => {
expect(createSnapshot('sub-step test', 1)).toMatchSnapshot();
});

it('should show the title and a proper icon(depends on the distance value)', () => {
let distanceElement: HTMLElement | null;
let stepTitle: HTMLElement | null;

const { reRenderComponent } = renderComponent('sub-step test 1', -1);

distanceElement = screen.queryByTestId('distance');
expect(distanceElement).not.toBeNull();
expect(distanceElement).toHaveTextContent('-1');

stepTitle = screen.queryByTestId('step-title');
expect(stepTitle).not.toBeNull();
expect(stepTitle).toHaveTextContent('sub-step test 1');

reRenderComponent('sub-step test 2', 0);

distanceElement = screen.queryByTestId('distance');
expect(distanceElement).not.toBeNull();
expect(distanceElement).toHaveTextContent('0');

stepTitle = screen.queryByTestId('step-title');
expect(stepTitle).not.toBeNull();
expect(stepTitle).toHaveTextContent('sub-step test 2');

reRenderComponent('sub-step test 3', 1);

distanceElement = screen.queryByTestId('distance');
expect(distanceElement).not.toBeNull();
expect(distanceElement).toHaveTextContent('1');

stepTitle = screen.queryByTestId('step-title');
expect(stepTitle).not.toBeNull();
expect(stepTitle).toHaveTextContent('sub-step test 3');

reRenderComponent(undefined, 1);

distanceElement = screen.queryByTestId('distance');
expect(distanceElement).toBeNull();

stepTitle = screen.queryByTestId('step-title');
expect(stepTitle).toBeNull();
});
});

function getComponent(title: string | undefined, distance?: -1 | 0 | 1): React.ReactElement {
return <PureSubCondition title={title} distance={distance} />;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Starting sub-steps, checking rendering snapshot with a title 1`] = `
<ol
className="pf-c-wizard__nav-list"
>
<li
className="pf-c-wizard__nav-item"
>
<div
className="pf-c-wizard__nav-link"
>
<div>
<div
data-testid="distance"
>
1
</div>
<span
className="done"
data-testid="step-title"
>
sub-step test
</span>
</div>
</div>
</li>
</ol>
`;

exports[`Starting sub-steps, checking rendering snapshot with no title 1`] = `null`;
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
ProgressStepState,
} from '@/components/WorkspaceProgress/ProgressStep';
import styles from '@/components/WorkspaceProgress/StartingSteps/WorkspaceConditions/index.module.css';
import { PureSubCondition } from '@/components/WorkspaceProgress/StartingSteps/WorkspaceConditions/PureSubCondition';
import { ProgressStepTitle } from '@/components/WorkspaceProgress/StepTitle';
import {
ConditionType,
Expand All @@ -38,9 +39,12 @@ export type State = ProgressStepState & {
isWarning: boolean;
isReady: boolean;
condition: ConditionType;
subConditionTitle: string;
};

export default class StartingStepWorkspaceConditions extends ProgressStep<Props, State> {
private timerId: number | undefined;

constructor(props: Props) {
super(props);

Expand All @@ -56,36 +60,67 @@ export default class StartingStepWorkspaceConditions extends ProgressStep<Props,
const prevCondition = prevProps?.condition;

let name: string;
let subConditionTitle: string;
if (state === undefined) {
name = condition.message || condition.type;
subConditionTitle = '';
} else {
name = condition.message || state.name;
subConditionTitle = state.subConditionTitle;
}

return {
isReady: isConditionReady(condition, prevCondition),
isWarning: isConditionError(condition, prevCondition),
name,
condition,
subConditionTitle,
};
}

private checkForSubCondition(condition: ConditionType): void {
if (this.timerId !== undefined || condition.status !== 'False') {
return;
}

// Show sub-condition only for DeploymentReady
if (condition.type === 'DeploymentReady') {
// Show sub-condition after 20 seconds
this.timerId = window.setTimeout(() => {
this.setState({
subConditionTitle:
'Downloading IDE binaries... (it can take a few minutes depending on your internet connection)',
});
}, 20000);
}
}

public componentDidMount() {
const state = this.buildState(this.props, undefined, this.state);
this.setState(state);

this.checkForSubCondition(state.condition);
}

public async componentDidUpdate(prevProps: Props) {
const state = this.buildState(this.props, prevProps, this.state);
this.setState(state);

if (state.subConditionTitle === '') {
this.checkForSubCondition(state.condition);
}
}

public shouldComponentUpdate(nextProps: Props, nextState: State): boolean {
if (isEqual(this.props.condition, nextProps.condition) === false) {
if (!isEqual(this.props.condition, nextProps.condition)) {
return true;
}

if (!isEqual(this.state.condition, nextState.condition)) {
return true;
}

if (isEqual(this.state.condition, nextState.condition) === false) {
if (this.state.subConditionTitle !== nextState.subConditionTitle) {
return true;
}

Expand Down Expand Up @@ -123,8 +158,8 @@ export default class StartingStepWorkspaceConditions extends ProgressStep<Props,
}

render() {
const { hasChildren } = this.props;
const { isWarning: isWarning, isReady } = this.state;
const { isWarning: isWarning, isReady, subConditionTitle } = this.state;
const hasChildren = this.props.hasChildren || !!subConditionTitle;

const distance = isReady ? 1 : 0;
const isError = false;
Expand All @@ -139,6 +174,7 @@ export default class StartingStepWorkspaceConditions extends ProgressStep<Props,
isWarning={isWarning}
>
{this.name}
<PureSubCondition distance={distance} title={subConditionTitle} />
</ProgressStepTitle>
</React.Fragment>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ import styles from '@/components/WorkspaceProgress/StepTitle/index.module.css';
export type Props = PropsWithChildren<{
className?: string;
distance: -1 | 0 | 1 | undefined;
hasChildren: boolean;
isError: boolean;
isWarning: boolean;
hasChildren?: boolean;
isError?: boolean;
isWarning?: boolean;
}>;

export class ProgressStepTitle extends React.Component<Props> {
Expand All @@ -41,7 +41,11 @@ export class ProgressStepTitle extends React.Component<Props> {

return (
<>
<ProgressStepTitleIcon distance={dist} isError={isError} isWarning={isWarning} />
<ProgressStepTitleIcon
distance={dist}
isError={isError === true}
isWarning={isWarning === true}
/>
<span data-testid="step-title" className={fullClassName}>
{children}
</span>
Expand Down
2 changes: 1 addition & 1 deletion run/local-run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ if [ ! -d $DASHBOARD_FRONTEND/lib/public/dashboard/devfile-registry ]; then
-i "packages/devfile-registry/air-gap/index.json"

if [ -s "$DASHBOARD_FRONTEND/lib/public/dashboard/devfile-registry/air-gap/index.json" ]; then
scripts/sed_in_place 's|CHE_DASHBOARD_INTERNAL_URL|http://localhost:8080|g' "$DASHBOARD_FRONTEND/lib/public/dashboard/devfile-registry/air-gap/index.json"
$(pwd)/scripts/sed_in_place.sh 's|CHE_DASHBOARD_INTERNAL_URL|http://localhost:8080|g' "$DASHBOARD_FRONTEND/lib/public/dashboard/devfile-registry/air-gap/index.json"
fi
fi

Expand Down
Loading