@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import { EntityContext } from '../../hooks/useEntity';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import { EntitySwitch } from './EntitySwitch';
|
||||
import { isKind } from './conditions';
|
||||
|
||||
describe('EntitySwitch', () => {
|
||||
it('should switch child when entity switches', () => {
|
||||
const content = (
|
||||
<EntitySwitch>
|
||||
<EntitySwitch.Case if={isKind('component')} children="A" />
|
||||
<EntitySwitch.Case if={isKind('template')} children="B" />
|
||||
<EntitySwitch.Case children="C" />
|
||||
</EntitySwitch>
|
||||
);
|
||||
|
||||
const rendered = render(
|
||||
<EntityContext.Provider
|
||||
value={{
|
||||
entity: { kind: 'component' } as Entity,
|
||||
loading: false,
|
||||
error: undefined,
|
||||
}}
|
||||
>
|
||||
{content}
|
||||
</EntityContext.Provider>,
|
||||
);
|
||||
|
||||
expect(rendered.queryByText('A')).toBeInTheDocument();
|
||||
expect(rendered.queryByText('B')).not.toBeInTheDocument();
|
||||
expect(rendered.queryByText('C')).not.toBeInTheDocument();
|
||||
|
||||
rendered.rerender(
|
||||
<EntityContext.Provider
|
||||
value={{
|
||||
entity: { kind: 'template' } as Entity,
|
||||
loading: false,
|
||||
error: undefined,
|
||||
}}
|
||||
>
|
||||
{content}
|
||||
</EntityContext.Provider>,
|
||||
);
|
||||
|
||||
expect(rendered.queryByText('A')).not.toBeInTheDocument();
|
||||
expect(rendered.queryByText('B')).toBeInTheDocument();
|
||||
expect(rendered.queryByText('C')).not.toBeInTheDocument();
|
||||
|
||||
rendered.rerender(
|
||||
<EntityContext.Provider
|
||||
value={{
|
||||
entity: { kind: 'derp' } as Entity,
|
||||
loading: false,
|
||||
error: undefined,
|
||||
}}
|
||||
>
|
||||
{content}
|
||||
</EntityContext.Provider>,
|
||||
);
|
||||
|
||||
expect(rendered.queryByText('A')).not.toBeInTheDocument();
|
||||
expect(rendered.queryByText('B')).not.toBeInTheDocument();
|
||||
expect(rendered.queryByText('C')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should switch child when filters switch', () => {
|
||||
const entityContextValue = {
|
||||
entity: { kind: 'component' } as Entity,
|
||||
loading: false,
|
||||
error: undefined,
|
||||
};
|
||||
|
||||
const rendered = render(
|
||||
<EntityContext.Provider value={entityContextValue}>
|
||||
<EntitySwitch>
|
||||
<EntitySwitch.Case if={isKind('component')} children="A" />
|
||||
<EntitySwitch.Case children="B" />
|
||||
</EntitySwitch>
|
||||
</EntityContext.Provider>,
|
||||
);
|
||||
|
||||
expect(rendered.queryByText('A')).toBeInTheDocument();
|
||||
expect(rendered.queryByText('B')).not.toBeInTheDocument();
|
||||
|
||||
rendered.rerender(
|
||||
<EntityContext.Provider value={entityContextValue}>
|
||||
<EntitySwitch>
|
||||
<EntitySwitch.Case if={isKind('template')} children="A" />
|
||||
<EntitySwitch.Case children="B" />
|
||||
</EntitySwitch>
|
||||
</EntityContext.Provider>,
|
||||
);
|
||||
|
||||
expect(rendered.queryByText('A')).not.toBeInTheDocument();
|
||||
expect(rendered.queryByText('B')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
ReactNode,
|
||||
PropsWithChildren,
|
||||
Children,
|
||||
Fragment,
|
||||
useMemo,
|
||||
isValidElement,
|
||||
} from 'react';
|
||||
import { useEntity } from '../../hooks/useEntity';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
|
||||
const EntitySwitchCase = (_: {
|
||||
if?: (entity: Entity) => boolean;
|
||||
children: ReactNode;
|
||||
}) => null;
|
||||
|
||||
type SwitchCase = {
|
||||
if?: (entity: Entity) => boolean;
|
||||
children: JSX.Element;
|
||||
};
|
||||
|
||||
function createSwitchCasesFromChildren(children: ReactNode): SwitchCase[] {
|
||||
return Children.toArray(children).flatMap(child => {
|
||||
if (!isValidElement(child)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (child.type === Fragment) {
|
||||
return createSwitchCasesFromChildren(child.props.children);
|
||||
}
|
||||
|
||||
if (child.type !== EntitySwitchCase) {
|
||||
throw new Error(`Child of EntitySwitch is not an EntitySwitch.Case`);
|
||||
}
|
||||
|
||||
const { if: condition, children } = child.props;
|
||||
return [{ if: condition, children }];
|
||||
});
|
||||
}
|
||||
|
||||
export const EntitySwitch = ({ children }: PropsWithChildren<{}>) => {
|
||||
const { entity } = useEntity();
|
||||
const switchCases = useMemo(() => createSwitchCasesFromChildren(children), [
|
||||
children,
|
||||
]);
|
||||
|
||||
const matchingCase = switchCases.find(switchCase =>
|
||||
switchCase.if ? switchCase.if(entity) : true,
|
||||
);
|
||||
return matchingCase?.children ?? null;
|
||||
};
|
||||
|
||||
EntitySwitch.Case = EntitySwitchCase;
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Entity, ComponentEntity } from '@backstage/catalog-model';
|
||||
|
||||
function strCmp(a: string | undefined, b: string | undefined): boolean {
|
||||
return Boolean(a && a?.toLowerCase() === b?.toLowerCase());
|
||||
}
|
||||
|
||||
export function isKind(kind: string) {
|
||||
return (entity: Entity) => strCmp(entity?.kind, kind);
|
||||
}
|
||||
|
||||
export function isComponentType(type: string) {
|
||||
return (entity: Entity) => {
|
||||
if (!strCmp(entity?.kind, 'component')) {
|
||||
return false;
|
||||
}
|
||||
const componentEntity = entity as ComponentEntity;
|
||||
return strCmp(componentEntity.spec.type, type);
|
||||
};
|
||||
}
|
||||
|
||||
export function isNamespace(namespace: string) {
|
||||
return (entity: Entity) => strCmp(entity?.metadata?.namespace, namespace);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { EntitySwitch } from './EntitySwitch';
|
||||
Reference in New Issue
Block a user