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

feat(canvas): Show placeholder when there are no visible flows #681

Merged
merged 1 commit into from
Jan 22, 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 @@ -23,7 +23,8 @@ describe('Test for Multi route actions from the code editor', () => {
cy.compareFileWithMonacoEditor('flows/malformed/missingIdRoute.yaml');
});

it('User creates kameletBinding with missing kind definition', () => {
// blocked ATM by https://github.com/KaotoIO/kaoto-next/issues/683
it.skip('User creates kameletBinding with missing kind definition', () => {
cy.openSourceCode();
cy.uploadFixture('flows/malformed/missingKindKamelet.yaml');
cy.openDesignPage();
Expand Down
49 changes: 38 additions & 11 deletions packages/ui/src/components/Visualization/Canvas/Canvas.test.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
import { render, waitFor } from '@testing-library/react';
import { CamelRouteVisualEntity } from '../../../models/visualization/flows';
import { CatalogModalContext } from '../../../providers/catalog-modal.provider';
import { VisibleFLowsContextResult } from '../../../providers/visible-flows.provider';
import { TestProvidersWrapper } from '../../../stubs';
import { camelRouteJson } from '../../../stubs/camel-route';
import { Canvas } from './Canvas';
import { VisibleFlowsContext, VisibleFLowsContextResult } from '../../../providers/visible-flows.provider';
import { CatalogModalContext } from '../../../providers/catalog-modal.provider';

describe('Canvas', () => {
const entity = new CamelRouteVisualEntity(camelRouteJson.route);
const entity2 = { ...entity, id: 'route-9999' } as CamelRouteVisualEntity;

it('should render correctly', async () => {
const result = render(
<VisibleFlowsContext.Provider
value={{ visibleFlows: { ['route-8888']: true } } as unknown as VisibleFLowsContextResult}
<TestProvidersWrapper
visibleFlows={{ visibleFlows: { ['route-8888']: true } } as unknown as VisibleFLowsContextResult}
>
<Canvas entities={[entity]} />
</VisibleFlowsContext.Provider>,
</TestProvidersWrapper>,
);

await waitFor(async () => expect(result.container.querySelector('#fit-to-screen')).toBeInTheDocument());
Expand All @@ -24,13 +25,13 @@ describe('Canvas', () => {

it('should render correctly with more routes ', async () => {
const result = render(
<VisibleFlowsContext.Provider
value={
<TestProvidersWrapper
visibleFlows={
{ visibleFlows: { ['route-8888']: true, ['route-9999']: false } } as unknown as VisibleFLowsContextResult
}
>
<Canvas entities={[entity, entity2]} />
</VisibleFlowsContext.Provider>,
</TestProvidersWrapper>,
);

await waitFor(async () => expect(result.container.querySelector('#fit-to-screen')).toBeInTheDocument());
Expand All @@ -40,11 +41,11 @@ describe('Canvas', () => {
it('should render the Catalog button if `CatalogModalContext` is provided', async () => {
const result = render(
<CatalogModalContext.Provider value={{ getNewComponent: jest.fn(), setIsModalOpen: jest.fn() }}>
<VisibleFlowsContext.Provider
value={{ visibleFlows: { ['route-8888']: true } } as unknown as VisibleFLowsContextResult}
<TestProvidersWrapper
visibleFlows={{ visibleFlows: { ['route-8888']: true } } as unknown as VisibleFLowsContextResult}
>
<Canvas entities={[entity]} />
</VisibleFlowsContext.Provider>
</TestProvidersWrapper>
</CatalogModalContext.Provider>,
);

Expand All @@ -53,4 +54,30 @@ describe('Canvas', () => {
);
expect(result.container).toMatchSnapshot();
});

describe('Empty state', () => {
it('should render empty state when there is no visual entity', async () => {
const result = render(
<TestProvidersWrapper visibleFlows={{ visibleFlows: {} } as unknown as VisibleFLowsContextResult}>
<Canvas entities={[]} />
</TestProvidersWrapper>,
);

await waitFor(async () => expect(result.getByTestId('visualization-empty-state')).toBeInTheDocument());
expect(result.container).toMatchSnapshot();
});

it('should render empty state when there is no visible flows', async () => {
const result = render(
<TestProvidersWrapper
visibleFlows={{ visibleFlows: { ['route-8888']: false } } as unknown as VisibleFLowsContextResult}
>
<Canvas entities={[entity]} />
</TestProvidersWrapper>,
);

await waitFor(async () => expect(result.getByTestId('visualization-empty-state')).toBeInTheDocument());
expect(result.container).toMatchSnapshot();
});
});
});
17 changes: 14 additions & 3 deletions packages/ui/src/components/Visualization/Canvas/Canvas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,16 @@ import {
} from 'react';
import layoutHorizontalIcon from '../../../assets/layout-horizontal.png';
import layoutVerticalIcon from '../../../assets/layout-vertical.png';
import { useLocalStorage } from '../../../hooks';
import { LocalStorageKeys } from '../../../models';
import { BaseVisualCamelEntity } from '../../../models/visualization/base-visual-entity';
import { CatalogModalContext } from '../../../providers/catalog-modal.provider';
import { VisibleFlowsContext } from '../../../providers/visible-flows.provider';
import { VisualizationEmptyState } from '../EmptyState';
import { CanvasSideBar } from './CanvasSideBar';
import { CanvasDefaults } from './canvas.defaults';
import { CanvasEdge, CanvasNode, LayoutType } from './canvas.models';
import { CanvasService } from './canvas.service';
import { useLocalStorage } from '../../../hooks';
import { LocalStorageKeys } from '../../../models';

interface CanvasProps {
contextToolbar?: ReactNode;
Expand All @@ -51,6 +52,12 @@ export const Canvas: FunctionComponent<PropsWithChildren<CanvasProps>> = (props)

const controller = useMemo(() => CanvasService.createController(), []);
const { visibleFlows } = useContext(VisibleFlowsContext)!;
const shouldShowEmptyState = useMemo(() => {
const areNoFlows = props.entities.length === 0;
const areAllFlowsHidden = Object.values(visibleFlows).every((visible) => !visible);
return areNoFlows || areAllFlowsHidden;
}, [props.entities.length, visibleFlows]);

const controlButtons = useMemo(() => {
const customButtons = catalogModalContext
? [
Expand Down Expand Up @@ -187,7 +194,11 @@ export const Canvas: FunctionComponent<PropsWithChildren<CanvasProps>> = (props)
controlBar={<TopologyControlBar controlButtons={controlButtons} />}
>
<VisualizationProvider controller={controller}>
<VisualizationSurface state={{ selectedIds }} />
{shouldShowEmptyState ? (
<VisualizationEmptyState data-testid="visualization-empty-state" entitiesNumber={props.entities.length} />
) : (
<VisualizationSurface state={{ selectedIds }} />
)}
</VisualizationProvider>
</TopologyView>
);
Expand Down
Loading
Loading