initial version of confirm dialog (#117)
* initial version of confirm dialog * introduced helper funciton to toggle dialog * review
This commit is contained in:
parent
7161af82b8
commit
8210ba5ba0
5 changed files with 554 additions and 0 deletions
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
"save": "Save",
|
"save": "Save",
|
||||||
"cancel": "Cancel",
|
"cancel": "Cancel",
|
||||||
|
"continue": "Continue",
|
||||||
"delete": "Delete",
|
"delete": "Delete",
|
||||||
"next": "Next",
|
"next": "Next",
|
||||||
"back": "Back",
|
"back": "Back",
|
||||||
|
|
94
src/components/confirm-dialog/ConfirmDialog.tsx
Normal file
94
src/components/confirm-dialog/ConfirmDialog.tsx
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
import React, { ReactElement, ReactNode, useState } from "react";
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
ButtonVariant,
|
||||||
|
Modal,
|
||||||
|
ModalVariant,
|
||||||
|
} from "@patternfly/react-core";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
|
export const useConfirmDialog = (
|
||||||
|
props: ConfirmDialogProps
|
||||||
|
): [() => void, () => ReactElement] => {
|
||||||
|
const [show, setShow] = useState(false);
|
||||||
|
|
||||||
|
function toggleDialog() {
|
||||||
|
setShow((show) => !show);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Dialog = () => (
|
||||||
|
<ConfirmDialogModal
|
||||||
|
key="confirmDialog"
|
||||||
|
{...props}
|
||||||
|
open={show}
|
||||||
|
toggleDialog={toggleDialog}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
return [toggleDialog, Dialog];
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface ConfirmDialogModalProps extends ConfirmDialogProps {
|
||||||
|
open: boolean;
|
||||||
|
toggleDialog: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ConfirmDialogProps = {
|
||||||
|
titleKey: string;
|
||||||
|
messageKey?: string;
|
||||||
|
cancelButtonLabel?: string;
|
||||||
|
continueButtonLabel?: string;
|
||||||
|
continueButtonVariant?: ButtonVariant;
|
||||||
|
onConfirm: () => void;
|
||||||
|
onCancel?: () => void;
|
||||||
|
children?: ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ConfirmDialogModal = ({
|
||||||
|
titleKey,
|
||||||
|
messageKey,
|
||||||
|
cancelButtonLabel,
|
||||||
|
continueButtonLabel,
|
||||||
|
continueButtonVariant,
|
||||||
|
onConfirm,
|
||||||
|
onCancel,
|
||||||
|
children,
|
||||||
|
open = true,
|
||||||
|
toggleDialog,
|
||||||
|
}: ConfirmDialogModalProps) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
title={t(titleKey)}
|
||||||
|
isOpen={open}
|
||||||
|
onClose={toggleDialog}
|
||||||
|
variant={ModalVariant.small}
|
||||||
|
actions={[
|
||||||
|
<Button
|
||||||
|
id="modal-confirm"
|
||||||
|
key="confirm"
|
||||||
|
variant={continueButtonVariant || ButtonVariant.primary}
|
||||||
|
onClick={() => {
|
||||||
|
onConfirm();
|
||||||
|
toggleDialog();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t(continueButtonLabel || "common:continue")}
|
||||||
|
</Button>,
|
||||||
|
<Button
|
||||||
|
id="modal-cancel"
|
||||||
|
key="cancel"
|
||||||
|
variant={ButtonVariant.secondary}
|
||||||
|
onClick={() => {
|
||||||
|
if (onCancel) onCancel();
|
||||||
|
toggleDialog();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t(cancelButtonLabel || "common:cancel")}
|
||||||
|
</Button>,
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
{!messageKey && children}
|
||||||
|
{messageKey && t(messageKey)}
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,36 @@
|
||||||
|
import React from "react";
|
||||||
|
import { mount } from "enzyme";
|
||||||
|
import { useConfirmDialog } from "../ConfirmDialog";
|
||||||
|
|
||||||
|
describe("Confirmation dialog", () => {
|
||||||
|
it("renders simple confirm dialog", () => {
|
||||||
|
const onConfirm = jest.fn();
|
||||||
|
const Test = () => {
|
||||||
|
const [toggle, ConfirmDialog] = useConfirmDialog({
|
||||||
|
titleKey: "Delete app02?",
|
||||||
|
messageKey:
|
||||||
|
"If you delete this client, all associated data will be removed.",
|
||||||
|
continueButtonLabel: "Delete",
|
||||||
|
onConfirm: onConfirm,
|
||||||
|
});
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<button id="show" onClick={toggle}>
|
||||||
|
Show
|
||||||
|
</button>
|
||||||
|
<ConfirmDialog />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const simple = mount(<Test />);
|
||||||
|
simple.find("#show").simulate("click");
|
||||||
|
expect(simple).toMatchSnapshot();
|
||||||
|
|
||||||
|
const button = simple.find("#modal-confirm").find("button");
|
||||||
|
expect(button).not.toBeNull();
|
||||||
|
|
||||||
|
button!.simulate("click");
|
||||||
|
expect(onConfirm).toBeCalled();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,356 @@
|
||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`Confirmation dialog renders simple confirm dialog 1`] = `
|
||||||
|
<Test>
|
||||||
|
<button
|
||||||
|
id="show"
|
||||||
|
onClick={[Function]}
|
||||||
|
>
|
||||||
|
Show
|
||||||
|
</button>
|
||||||
|
<Dialog>
|
||||||
|
<ConfirmDialogModal
|
||||||
|
continueButtonLabel="Delete"
|
||||||
|
key="confirmDialog"
|
||||||
|
messageKey="If you delete this client, all associated data will be removed."
|
||||||
|
onConfirm={[MockFunction]}
|
||||||
|
open={true}
|
||||||
|
titleKey="Delete app02?"
|
||||||
|
toggleDialog={[Function]}
|
||||||
|
>
|
||||||
|
<Modal
|
||||||
|
actions={
|
||||||
|
Array [
|
||||||
|
<Button
|
||||||
|
id="modal-confirm"
|
||||||
|
onClick={[Function]}
|
||||||
|
variant="primary"
|
||||||
|
>
|
||||||
|
Delete
|
||||||
|
</Button>,
|
||||||
|
<Button
|
||||||
|
id="modal-cancel"
|
||||||
|
onClick={[Function]}
|
||||||
|
variant="secondary"
|
||||||
|
>
|
||||||
|
cancel
|
||||||
|
</Button>,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
appendTo={[Function]}
|
||||||
|
aria-describedby=""
|
||||||
|
aria-label=""
|
||||||
|
aria-labelledby=""
|
||||||
|
className=""
|
||||||
|
hasNoBodyWrapper={false}
|
||||||
|
isOpen={true}
|
||||||
|
onClose={[Function]}
|
||||||
|
ouiaSafe={true}
|
||||||
|
showClose={true}
|
||||||
|
title="Delete app02?"
|
||||||
|
variant="small"
|
||||||
|
>
|
||||||
|
<Portal
|
||||||
|
containerInfo={
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
class="pf-c-backdrop"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="pf-l-bullseye"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
aria-describedby="pf-modal-part-3"
|
||||||
|
aria-labelledby="pf-modal-part-2"
|
||||||
|
aria-modal="true"
|
||||||
|
class="pf-c-modal-box pf-m-sm"
|
||||||
|
data-ouia-component-id="OUIA-Generated-Modal-small-2"
|
||||||
|
data-ouia-component-type="PF4/ModalContent"
|
||||||
|
data-ouia-safe="true"
|
||||||
|
id="pf-modal-part-1"
|
||||||
|
role="dialog"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
aria-disabled="false"
|
||||||
|
aria-label="Close"
|
||||||
|
class="pf-c-button pf-m-plain"
|
||||||
|
data-ouia-component-id="OUIA-Generated-Button-plain-1"
|
||||||
|
data-ouia-component-type="PF4/Button"
|
||||||
|
data-ouia-safe="true"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
fill="currentColor"
|
||||||
|
height="1em"
|
||||||
|
role="img"
|
||||||
|
style="vertical-align: -0.125em;"
|
||||||
|
viewBox="0 0 352 512"
|
||||||
|
width="1em"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M242.72 256l100.07-100.07c12.28-12.28 12.28-32.19 0-44.48l-22.24-22.24c-12.28-12.28-32.19-12.28-44.48 0L176 189.28 75.93 89.21c-12.28-12.28-32.19-12.28-44.48 0L9.21 111.45c-12.28 12.28-12.28 32.19 0 44.48L109.28 256 9.21 356.07c-12.28 12.28-12.28 32.19 0 44.48l22.24 22.24c12.28 12.28 32.2 12.28 44.48 0L176 322.72l100.07 100.07c12.28 12.28 32.2 12.28 44.48 0l22.24-22.24c12.28-12.28 12.28-32.19 0-44.48L242.72 256z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<header
|
||||||
|
class="pf-c-modal-box__header"
|
||||||
|
>
|
||||||
|
<h1
|
||||||
|
class="pf-c-modal-box__title pf-c-modal-box__title"
|
||||||
|
id="pf-modal-part-2"
|
||||||
|
>
|
||||||
|
Delete app02?
|
||||||
|
</h1>
|
||||||
|
</header>
|
||||||
|
<div
|
||||||
|
class="pf-c-modal-box__body"
|
||||||
|
id="pf-modal-part-3"
|
||||||
|
>
|
||||||
|
If you delete this client, all associated data will be removed.
|
||||||
|
</div>
|
||||||
|
<footer
|
||||||
|
class="pf-c-modal-box__footer"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
aria-disabled="false"
|
||||||
|
class="pf-c-button pf-m-primary"
|
||||||
|
data-ouia-component-id="OUIA-Generated-Button-primary-1"
|
||||||
|
data-ouia-component-type="PF4/Button"
|
||||||
|
data-ouia-safe="true"
|
||||||
|
id="modal-confirm"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
Delete
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
aria-disabled="false"
|
||||||
|
class="pf-c-button pf-m-secondary"
|
||||||
|
data-ouia-component-id="OUIA-Generated-Button-secondary-1"
|
||||||
|
data-ouia-component-type="PF4/Button"
|
||||||
|
data-ouia-safe="true"
|
||||||
|
id="modal-cancel"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
cancel
|
||||||
|
</button>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<ModalContent
|
||||||
|
actions={
|
||||||
|
Array [
|
||||||
|
<Button
|
||||||
|
id="modal-confirm"
|
||||||
|
onClick={[Function]}
|
||||||
|
variant="primary"
|
||||||
|
>
|
||||||
|
Delete
|
||||||
|
</Button>,
|
||||||
|
<Button
|
||||||
|
id="modal-cancel"
|
||||||
|
onClick={[Function]}
|
||||||
|
variant="secondary"
|
||||||
|
>
|
||||||
|
cancel
|
||||||
|
</Button>,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
aria-describedby=""
|
||||||
|
aria-label=""
|
||||||
|
aria-labelledby=""
|
||||||
|
boxId="pf-modal-part-1"
|
||||||
|
className=""
|
||||||
|
descriptorId="pf-modal-part-3"
|
||||||
|
hasNoBodyWrapper={false}
|
||||||
|
isOpen={true}
|
||||||
|
labelId="pf-modal-part-2"
|
||||||
|
onClose={[Function]}
|
||||||
|
ouiaId="OUIA-Generated-Modal-small-2"
|
||||||
|
ouiaSafe={true}
|
||||||
|
showClose={true}
|
||||||
|
title="Delete app02?"
|
||||||
|
variant="small"
|
||||||
|
>
|
||||||
|
<Backdrop>
|
||||||
|
<div
|
||||||
|
className="pf-c-backdrop"
|
||||||
|
>
|
||||||
|
<FocusTrap
|
||||||
|
active={true}
|
||||||
|
className="pf-l-bullseye"
|
||||||
|
focusTrapOptions={
|
||||||
|
Object {
|
||||||
|
"clickOutsideDeactivates": true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
paused={false}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="pf-l-bullseye"
|
||||||
|
>
|
||||||
|
<ModalBox
|
||||||
|
aria-describedby="pf-modal-part-3"
|
||||||
|
aria-label=""
|
||||||
|
aria-labelledby="pf-modal-part-2"
|
||||||
|
className=""
|
||||||
|
data-ouia-component-id="OUIA-Generated-Modal-small-2"
|
||||||
|
data-ouia-component-type="PF4/ModalContent"
|
||||||
|
data-ouia-safe={true}
|
||||||
|
id="pf-modal-part-1"
|
||||||
|
style={Object {}}
|
||||||
|
variant="small"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
aria-describedby="pf-modal-part-3"
|
||||||
|
aria-label={null}
|
||||||
|
aria-labelledby="pf-modal-part-2"
|
||||||
|
aria-modal="true"
|
||||||
|
className="pf-c-modal-box pf-m-sm"
|
||||||
|
data-ouia-component-id="OUIA-Generated-Modal-small-2"
|
||||||
|
data-ouia-component-type="PF4/ModalContent"
|
||||||
|
data-ouia-safe={true}
|
||||||
|
id="pf-modal-part-1"
|
||||||
|
role="dialog"
|
||||||
|
style={Object {}}
|
||||||
|
>
|
||||||
|
<ModalBoxCloseButton
|
||||||
|
onClose={[Function]}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
aria-label="Close"
|
||||||
|
className=""
|
||||||
|
onClick={[Function]}
|
||||||
|
variant="plain"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
aria-disabled={false}
|
||||||
|
aria-label="Close"
|
||||||
|
className="pf-c-button pf-m-plain"
|
||||||
|
data-ouia-component-id="OUIA-Generated-Button-plain-1"
|
||||||
|
data-ouia-component-type="PF4/Button"
|
||||||
|
data-ouia-safe={true}
|
||||||
|
disabled={false}
|
||||||
|
onClick={[Function]}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<TimesIcon
|
||||||
|
color="currentColor"
|
||||||
|
noVerticalAlign={false}
|
||||||
|
size="sm"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden={true}
|
||||||
|
aria-labelledby={null}
|
||||||
|
fill="currentColor"
|
||||||
|
height="1em"
|
||||||
|
role="img"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"verticalAlign": "-0.125em",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
viewBox="0 0 352 512"
|
||||||
|
width="1em"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M242.72 256l100.07-100.07c12.28-12.28 12.28-32.19 0-44.48l-22.24-22.24c-12.28-12.28-32.19-12.28-44.48 0L176 189.28 75.93 89.21c-12.28-12.28-32.19-12.28-44.48 0L9.21 111.45c-12.28 12.28-12.28 32.19 0 44.48L109.28 256 9.21 356.07c-12.28 12.28-12.28 32.19 0 44.48l22.24 22.24c12.28 12.28 32.2 12.28 44.48 0L176 322.72l100.07 100.07c12.28 12.28 32.2 12.28 44.48 0l22.24-22.24c12.28-12.28 12.28-32.19 0-44.48L242.72 256z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</TimesIcon>
|
||||||
|
</button>
|
||||||
|
</Button>
|
||||||
|
</ModalBoxCloseButton>
|
||||||
|
<ModalBoxHeader>
|
||||||
|
<header
|
||||||
|
className="pf-c-modal-box__header"
|
||||||
|
>
|
||||||
|
<ModalBoxTitle
|
||||||
|
className="pf-c-modal-box__title"
|
||||||
|
id="pf-modal-part-2"
|
||||||
|
title="Delete app02?"
|
||||||
|
>
|
||||||
|
<h1
|
||||||
|
className="pf-c-modal-box__title pf-c-modal-box__title"
|
||||||
|
id="pf-modal-part-2"
|
||||||
|
>
|
||||||
|
Delete app02?
|
||||||
|
</h1>
|
||||||
|
</ModalBoxTitle>
|
||||||
|
</header>
|
||||||
|
</ModalBoxHeader>
|
||||||
|
<ModalBoxBody
|
||||||
|
id="pf-modal-part-3"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="pf-c-modal-box__body"
|
||||||
|
id="pf-modal-part-3"
|
||||||
|
>
|
||||||
|
If you delete this client, all associated data will be removed.
|
||||||
|
</div>
|
||||||
|
</ModalBoxBody>
|
||||||
|
<ModalBoxFooter>
|
||||||
|
<footer
|
||||||
|
className="pf-c-modal-box__footer"
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
id="modal-confirm"
|
||||||
|
key="confirm"
|
||||||
|
onClick={[Function]}
|
||||||
|
variant="primary"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
aria-disabled={false}
|
||||||
|
aria-label={null}
|
||||||
|
className="pf-c-button pf-m-primary"
|
||||||
|
data-ouia-component-id="OUIA-Generated-Button-primary-1"
|
||||||
|
data-ouia-component-type="PF4/Button"
|
||||||
|
data-ouia-safe={true}
|
||||||
|
disabled={false}
|
||||||
|
id="modal-confirm"
|
||||||
|
onClick={[Function]}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
Delete
|
||||||
|
</button>
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
id="modal-cancel"
|
||||||
|
key="cancel"
|
||||||
|
onClick={[Function]}
|
||||||
|
variant="secondary"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
aria-disabled={false}
|
||||||
|
aria-label={null}
|
||||||
|
className="pf-c-button pf-m-secondary"
|
||||||
|
data-ouia-component-id="OUIA-Generated-Button-secondary-1"
|
||||||
|
data-ouia-component-type="PF4/Button"
|
||||||
|
data-ouia-safe={true}
|
||||||
|
disabled={false}
|
||||||
|
id="modal-cancel"
|
||||||
|
onClick={[Function]}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
cancel
|
||||||
|
</button>
|
||||||
|
</Button>
|
||||||
|
</footer>
|
||||||
|
</ModalBoxFooter>
|
||||||
|
</div>
|
||||||
|
</ModalBox>
|
||||||
|
</div>
|
||||||
|
</FocusTrap>
|
||||||
|
</div>
|
||||||
|
</Backdrop>
|
||||||
|
</ModalContent>
|
||||||
|
</Portal>
|
||||||
|
</Modal>
|
||||||
|
</ConfirmDialogModal>
|
||||||
|
</Dialog>
|
||||||
|
</Test>
|
||||||
|
`;
|
67
src/stories/ConfirmDialog.stories.tsx
Normal file
67
src/stories/ConfirmDialog.stories.tsx
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
import React from "react";
|
||||||
|
import {
|
||||||
|
TextContent,
|
||||||
|
Text,
|
||||||
|
TextVariants,
|
||||||
|
ButtonVariant,
|
||||||
|
} from "@patternfly/react-core";
|
||||||
|
import { Meta, Story } from "@storybook/react";
|
||||||
|
import { action } from "@storybook/addon-actions";
|
||||||
|
|
||||||
|
import {
|
||||||
|
ConfirmDialogModal,
|
||||||
|
ConfirmDialogModalProps,
|
||||||
|
useConfirmDialog,
|
||||||
|
} from "../components/confirm-dialog/ConfirmDialog";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: "Confirmation Dialog",
|
||||||
|
component: ConfirmDialogModal,
|
||||||
|
} as Meta;
|
||||||
|
|
||||||
|
const Template: Story<ConfirmDialogModalProps> = (args) => (
|
||||||
|
<ConfirmDialogModal {...args} />
|
||||||
|
);
|
||||||
|
|
||||||
|
export const Simple = Template.bind({});
|
||||||
|
Simple.args = {
|
||||||
|
titleKey: "Delete app02?",
|
||||||
|
messageKey: "If you delete this client, all associated data will be removed.",
|
||||||
|
continueButtonLabel: "Delete",
|
||||||
|
continueButtonVariant: ButtonVariant.danger,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Children = Template.bind({});
|
||||||
|
Children.args = {
|
||||||
|
titleKey: "Children as content!",
|
||||||
|
continueButtonVariant: ButtonVariant.primary,
|
||||||
|
children: (
|
||||||
|
<>
|
||||||
|
<TextContent>
|
||||||
|
<Text component={TextVariants.h3}>Hello World</Text>
|
||||||
|
</TextContent>
|
||||||
|
<p>Example of some other patternfly components.</p>
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
const Test = () => {
|
||||||
|
const [toggle, Dialog] = useConfirmDialog({
|
||||||
|
titleKey: "Delete app02?",
|
||||||
|
messageKey:
|
||||||
|
"If you delete this client, all associated data will be removed.",
|
||||||
|
continueButtonLabel: "Delete",
|
||||||
|
onConfirm: action("confirm"),
|
||||||
|
onCancel: action("cancel"),
|
||||||
|
});
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<button id="show" onClick={toggle}>
|
||||||
|
Show
|
||||||
|
</button>
|
||||||
|
<Dialog />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Api = () => <Test />;
|
Loading…
Reference in a new issue