From 69c04f97f0f130017422e7e65a3b3974d521ce22 Mon Sep 17 00:00:00 2001 From: adamviktora Date: Tue, 17 Sep 2024 18:28:29 +0200 Subject: [PATCH 01/11] feat(DeleteModal): first version --- .../content/examples/Basic.tsx | 140 +++++++++++++++- .../patternfly-docs/content/examples/basic.md | 3 +- .../ai-infra-ui-components/react.js | 41 ++++- packages/module/release.config.js | 4 +- .../module/src/DeleteModal/DeleteModal.tsx | 156 ++++++++++++++++++ packages/module/src/DeleteModal/index.ts | 1 + packages/module/src/index.ts | 1 + 7 files changed, 338 insertions(+), 8 deletions(-) create mode 100644 packages/module/src/DeleteModal/DeleteModal.tsx create mode 100644 packages/module/src/DeleteModal/index.ts diff --git a/packages/module/patternfly-docs/content/examples/Basic.tsx b/packages/module/patternfly-docs/content/examples/Basic.tsx index b532338..cbd78fc 100644 --- a/packages/module/patternfly-docs/content/examples/Basic.tsx +++ b/packages/module/patternfly-docs/content/examples/Basic.tsx @@ -1,4 +1,140 @@ import React from 'react'; -import { ExtendedButton } from '@patternfly/ai-infra-ui-components'; +import { Button, Stack, StackItem } from '@patternfly/react-core'; +import { DeleteModal } from '@patternfly/ai-infra-ui-components'; -export const BasicExample: React.FunctionComponent = () => My custom extension button; +export const DeleteModalBasic: React.FunctionComponent = () => { + const [isModalRecoverableOpen, setIsModalRecoverableOpen] = React.useState(false); + const [isModalDestructiveOpen, setIsModalDestructiveOpen] = React.useState(false); + const [isModalExtraDestructiveOpen, setIsModalExtraDestructiveOpen] = React.useState(false); + + const [isModalMultiExtraDestructiveOpen, setIsModalMultiExtraDestructiveOpen] = React.useState(false); + + const [isModalModelRegistryOpen, setIsModalModelRegistryOpen] = React.useState(false); + const [isModalPipelineServerOpen, setIsModalPipelineServerOpen] = React.useState(false); + + const handleModalRecoverableToggle = (_event: KeyboardEvent | React.MouseEvent) => { + setIsModalRecoverableOpen(!isModalRecoverableOpen); + }; + + const handleModalDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent) => { + setIsModalDestructiveOpen(!isModalDestructiveOpen); + }; + + const handleModalExtraDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent) => { + setIsModalExtraDestructiveOpen(!isModalExtraDestructiveOpen); + }; + + const handleModalMultiExtraDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent) => { + setIsModalMultiExtraDestructiveOpen(!isModalMultiExtraDestructiveOpen); + }; + + const handleModalModelRegistryToggle = (_event: KeyboardEvent | React.MouseEvent) => { + setIsModalModelRegistryOpen(!isModalModelRegistryOpen); + }; + + const handleModalPipelineServerToggle = (_event: KeyboardEvent | React.MouseEvent) => { + setIsModalPipelineServerOpen(!isModalPipelineServerOpen); + }; + + return ( + <> + +
Modals with one item to delete
+ + + + + + + + + +
+ + +
Modals with multiple items to delete
+ + + +
+ + +
Modals with custom delete messages
+ + + + + + +
+ + + + + + {/* Modals with multiple items to delete */} + + + {/* Modals with custom delete messages */} + + + + ); +}; diff --git a/packages/module/patternfly-docs/content/examples/basic.md b/packages/module/patternfly-docs/content/examples/basic.md index fc7958b..31e66de 100644 --- a/packages/module/patternfly-docs/content/examples/basic.md +++ b/packages/module/patternfly-docs/content/examples/basic.md @@ -9,10 +9,11 @@ id: AI-infra-ui-components source: react # If you use typescript, the name of the interface to display props for # These are found through the sourceProps function provided in patternfly-docs.source.js -propComponents: ['ExtendedButton'] +propComponents: ['ExtendedButton', 'DeleteModal'] --- import { ExtendedButton } from "@patternfly/ai-infra-ui-components"; +import { DeleteModal } from "@patternfly/ai-infra-ui-components"; ## Basic usage diff --git a/packages/module/patternfly-docs/generated/extensions/ai-infra-ui-components/react.js b/packages/module/patternfly-docs/generated/extensions/ai-infra-ui-components/react.js index f157536..2f20f82 100644 --- a/packages/module/patternfly-docs/generated/extensions/ai-infra-ui-components/react.js +++ b/packages/module/patternfly-docs/generated/extensions/ai-infra-ui-components/react.js @@ -1,6 +1,7 @@ import React from 'react'; import { AutoLinkHeader, Example, Link as PatternflyThemeLink } from '@patternfly/documentation-framework/components'; import { ExtendedButton } from "@patternfly/ai-infra-ui-components"; +import { DeleteModal } from "@patternfly/ai-infra-ui-components"; const pageData = { "id": "AI-infra-ui-components", "section": "extensions", @@ -26,6 +27,39 @@ const pageData = { "description": "Content to render inside the extended button component" } ] + }, + { + "name": "DeleteModal", + "description": "", + "props": [ + { + "name": "deleteVariant", + "type": "'extra-destructive' | 'destructive' | 'easily-recoverable'", + "description": "Delete variant. Destructive and extra-destructive variants will show a warning icon and danger button. For extra-destructive variant, text input confirmation is needed.", + "defaultValue": "'destructive'" + }, + { + "name": "error", + "type": "Error", + "description": "Error indicating deletion has failed" + }, + { + "name": "message", + "type": "{\n toDelete?: string;\n resourcesToDelete?: string;\n endNote?: string;\n}", + "description": "Message describing what will deleted", + "defaultValue": "{\n resourcesToDelete: '',\n endNote: ''\n}" + }, + { + "name": "onCancel", + "type": "() => void", + "description": "Callback on clicking the cancel button" + }, + { + "name": "onDelete", + "type": "() => void", + "description": "Callback on clicking the delete button" + } + ] } ], "examples": [ @@ -36,15 +70,16 @@ const pageData = { ] }; pageData.liveContext = { - ExtendedButton + ExtendedButton, + DeleteModal }; pageData.examples = { 'Example': props => - My custom extension button;\n","title":"Example","lang":"js","className":""}}> + {\n const [isModalRecoverableOpen, setIsModalRecoverableOpen] = React.useState(false);\n const [isModalDestructiveOpen, setIsModalDestructiveOpen] = React.useState(false);\n const [isModalExtraDestructiveOpen, setIsModalExtraDestructiveOpen] = React.useState(false);\n\n const [isModalMultiExtraDestructiveOpen, setIsModalMultiExtraDestructiveOpen] = React.useState(false);\n\n const [isModalModelRegistryOpen, setIsModalModelRegistryOpen] = React.useState(false);\n const [isModalPipelineServerOpen, setIsModalPipelineServerOpen] = React.useState(false);\n\n const handleModalRecoverableToggle = (_event: KeyboardEvent | React.MouseEvent) => {\n setIsModalRecoverableOpen(!isModalRecoverableOpen);\n };\n\n const handleModalDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent) => {\n setIsModalDestructiveOpen(!isModalDestructiveOpen);\n };\n\n const handleModalExtraDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent) => {\n setIsModalExtraDestructiveOpen(!isModalExtraDestructiveOpen);\n };\n\n const handleModalMultiExtraDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent) => {\n setIsModalMultiExtraDestructiveOpen(!isModalMultiExtraDestructiveOpen);\n };\n\n const handleModalModelRegistryToggle = (_event: KeyboardEvent | React.MouseEvent) => {\n setIsModalModelRegistryOpen(!isModalModelRegistryOpen);\n };\n\n const handleModalPipelineServerToggle = (_event: KeyboardEvent | React.MouseEvent) => {\n setIsModalPipelineServerOpen(!isModalPipelineServerOpen);\n };\n\n return (\n <>\n \n
Modals with one item to delete
\n \n \n \n \n \n \n \n \n \n
\n\n \n
Modals with multiple items to delete
\n \n \n \n
\n\n \n
Modals with custom delete messages
\n \n \n \n \n \n \n
\n\n \n \n \n\n {/* Modals with multiple items to delete */}\n \n\n {/* Modals with custom delete messages */}\n \n \n \n );\n};\n","title":"Example","lang":"js","className":""}}>
, 'Fullscreen example': props => - My custom extension button;\n","title":"Fullscreen example","lang":"js","isFullscreen":true,"className":""}}> + {\n const [isModalRecoverableOpen, setIsModalRecoverableOpen] = React.useState(false);\n const [isModalDestructiveOpen, setIsModalDestructiveOpen] = React.useState(false);\n const [isModalExtraDestructiveOpen, setIsModalExtraDestructiveOpen] = React.useState(false);\n\n const [isModalMultiExtraDestructiveOpen, setIsModalMultiExtraDestructiveOpen] = React.useState(false);\n\n const [isModalModelRegistryOpen, setIsModalModelRegistryOpen] = React.useState(false);\n const [isModalPipelineServerOpen, setIsModalPipelineServerOpen] = React.useState(false);\n\n const handleModalRecoverableToggle = (_event: KeyboardEvent | React.MouseEvent) => {\n setIsModalRecoverableOpen(!isModalRecoverableOpen);\n };\n\n const handleModalDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent) => {\n setIsModalDestructiveOpen(!isModalDestructiveOpen);\n };\n\n const handleModalExtraDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent) => {\n setIsModalExtraDestructiveOpen(!isModalExtraDestructiveOpen);\n };\n\n const handleModalMultiExtraDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent) => {\n setIsModalMultiExtraDestructiveOpen(!isModalMultiExtraDestructiveOpen);\n };\n\n const handleModalModelRegistryToggle = (_event: KeyboardEvent | React.MouseEvent) => {\n setIsModalModelRegistryOpen(!isModalModelRegistryOpen);\n };\n\n const handleModalPipelineServerToggle = (_event: KeyboardEvent | React.MouseEvent) => {\n setIsModalPipelineServerOpen(!isModalPipelineServerOpen);\n };\n\n return (\n <>\n \n
Modals with one item to delete
\n \n \n \n \n \n \n \n \n \n
\n\n \n
Modals with multiple items to delete
\n \n \n \n
\n\n \n
Modals with custom delete messages
\n \n \n \n \n \n \n
\n\n \n \n \n\n {/* Modals with multiple items to delete */}\n \n\n {/* Modals with custom delete messages */}\n \n \n \n );\n};\n","title":"Fullscreen example","lang":"js","isFullscreen":true,"className":""}}>
}; diff --git a/packages/module/release.config.js b/packages/module/release.config.js index 99445eb..dd7bc86 100644 --- a/packages/module/release.config.js +++ b/packages/module/release.config.js @@ -10,5 +10,5 @@ module.exports = { '@semantic-release/npm' ], tagFormat: 'v${version}', - dryRun: true -}; \ No newline at end of file + dryRun: false +}; diff --git a/packages/module/src/DeleteModal/DeleteModal.tsx b/packages/module/src/DeleteModal/DeleteModal.tsx new file mode 100644 index 0000000..17acee1 --- /dev/null +++ b/packages/module/src/DeleteModal/DeleteModal.tsx @@ -0,0 +1,156 @@ +import React from 'react'; +import { + Alert, + Button, + FormGroup, + List, + ListItem, + Modal, + ModalBody, + ModalFooter, + ModalHeader, + ModalProps, + Stack, + StackItem, + TextInput +} from '@patternfly/react-core'; + +/** Props specifying either one item or a list of items to delete */ +type ItemProps = + | { + /** Type of item to delete (e.g. project, pipeline server, model registry) */ + item: string; + /** Name of the item to delete */ + itemName: string; + items?: never; + itemNames?: never; + } + | { + /** Type of items to delete in plural (e.g. projects, pipeline servers, model registries) */ + items: string; + /** List of names of the items to delete */ + itemNames: string[]; + item?: never; + itemName?: never; + }; + +export type DeleteModalProps = Omit & + ItemProps & { + /** Delete variant. Destructive and extra-destructive variants will show a warning icon and danger button. For extra-destructive variant, text input confirmation is needed. */ + deleteVariant?: 'extra-destructive' | 'destructive' | 'easily-recoverable'; + /** Message describing what will deleted */ + message?: { + toDelete?: string; + resourcesToDelete?: string; + endNote?: string; + }; + /** Callback on clicking the delete button */ + onDelete?: () => void; + /** Callback on clicking the cancel button */ + onCancel?: () => void; + /** Error indicating deletion has failed */ + error?: Error; + /** Modal ref */ + ref: React.RefObject; + }; + +export const DeleteModal: React.FunctionComponent = ({ + item, + items, + itemName, + itemNames, + deleteVariant = 'destructive', + onDelete, + onCancel, + message = { + resourcesToDelete: '', + endNote: '' + }, + error, + ...props +}: DeleteModalProps) => { + const isPlural = item === undefined; + + const [confirmationText, setConfirmationText] = React.useState(''); + const expectedConfirmationText = isPlural ? `delete ${itemNames.length} ${items}` : itemName; + + const confirmed = deleteVariant === 'extra-destructive' ? confirmationText === expectedConfirmationText : true; + + const toDeleteMessage = message.toDelete ?? ` and all of ${isPlural ? 'their' : 'its'} resources`; + + const itemToDelete = `${itemNames ? `${itemNames.length} ` : ''}${item ?? items}`; + const modalHeaderTitle = `Delete ${itemToDelete}?`; + + return ( + + + + + + The{' '} + {isPlural ? ( + `following ${items}` + ) : ( + <> + {itemName} {item} + + )} + {toDeleteMessage} + {message.resourcesToDelete} will be deleted{isPlural && !message.endNote ? ':' : '.'} {message.endNote} + {isPlural && ( + + {itemNames.map((name) => ( + + {name} + + ))} + + )} + + {deleteVariant === 'extra-destructive' && ( + + + Type {expectedConfirmationText} to confirm deletion: + + } + > + setConfirmationText(value)} + // validated={confirmed ? 'success' : 'default'} + /> + + + )} + + + + + + {error && ( + + {error.message} + + )} + + + ); +}; diff --git a/packages/module/src/DeleteModal/index.ts b/packages/module/src/DeleteModal/index.ts new file mode 100644 index 0000000..2d52cdf --- /dev/null +++ b/packages/module/src/DeleteModal/index.ts @@ -0,0 +1 @@ +export * from './DeleteModal'; diff --git a/packages/module/src/index.ts b/packages/module/src/index.ts index 03c57e3..81d39ab 100644 --- a/packages/module/src/index.ts +++ b/packages/module/src/index.ts @@ -1 +1,2 @@ +export * from './DeleteModal'; export * from './ExtendedButton'; From 3de93ef2fec6f31511010c916f4f1f97db6d1f7a Mon Sep 17 00:00:00 2001 From: adamviktora Date: Thu, 26 Sep 2024 11:10:12 +0200 Subject: [PATCH 02/11] feat(DeleteModal): make more general and reflect current DeleteModal usage --- .../content/examples/Basic.tsx | 108 ++-------- .../patternfly-docs/content/examples/basic.md | 140 ++++++++++++ .../ai-infra-ui-components/react.js | 75 +++++-- .../module/patternfly-docs/generated/index.js | 4 +- .../module/src/DeleteModal/DeleteModal.tsx | 202 ++++++++---------- 5 files changed, 316 insertions(+), 213 deletions(-) diff --git a/packages/module/patternfly-docs/content/examples/Basic.tsx b/packages/module/patternfly-docs/content/examples/Basic.tsx index cbd78fc..513eede 100644 --- a/packages/module/patternfly-docs/content/examples/Basic.tsx +++ b/packages/module/patternfly-docs/content/examples/Basic.tsx @@ -7,39 +7,21 @@ export const DeleteModalBasic: React.FunctionComponent = () => { const [isModalDestructiveOpen, setIsModalDestructiveOpen] = React.useState(false); const [isModalExtraDestructiveOpen, setIsModalExtraDestructiveOpen] = React.useState(false); - const [isModalMultiExtraDestructiveOpen, setIsModalMultiExtraDestructiveOpen] = React.useState(false); - - const [isModalModelRegistryOpen, setIsModalModelRegistryOpen] = React.useState(false); - const [isModalPipelineServerOpen, setIsModalPipelineServerOpen] = React.useState(false); - - const handleModalRecoverableToggle = (_event: KeyboardEvent | React.MouseEvent) => { + const handleModalRecoverableToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => { setIsModalRecoverableOpen(!isModalRecoverableOpen); }; - const handleModalDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent) => { + const handleModalDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => { setIsModalDestructiveOpen(!isModalDestructiveOpen); }; - const handleModalExtraDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent) => { + const handleModalExtraDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => { setIsModalExtraDestructiveOpen(!isModalExtraDestructiveOpen); }; - const handleModalMultiExtraDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent) => { - setIsModalMultiExtraDestructiveOpen(!isModalMultiExtraDestructiveOpen); - }; - - const handleModalModelRegistryToggle = (_event: KeyboardEvent | React.MouseEvent) => { - setIsModalModelRegistryOpen(!isModalModelRegistryOpen); - }; - - const handleModalPipelineServerToggle = (_event: KeyboardEvent | React.MouseEvent) => { - setIsModalPipelineServerOpen(!isModalPipelineServerOpen); - }; - return ( <> -
Modals with one item to delete
- -
- - -
Modals with custom delete messages
- - - - - - -
- handleModalRecoverableToggle(undefined)} deleteVariant="easily-recoverable" - item="user group" - itemName="my-team-abc" isOpen={isModalRecoverableOpen} onClose={handleModalRecoverableToggle} - /> + > + User group 123 will be deleted. + handleModalDestructiveToggle(undefined)} deleteVariant="destructive" - item="pipeline" - itemName="pipeline_456" isOpen={isModalDestructiveOpen} onClose={handleModalDestructiveToggle} - /> + > + Experiment cool-exp will be deleted. + handleModalExtraDestructiveToggle(undefined)} deleteVariant="extra-destructive" - item="project" - itemName="super-123-project" isOpen={isModalExtraDestructiveOpen} onClose={handleModalExtraDestructiveToggle} - /> - - {/* Modals with multiple items to delete */} - - - {/* Modals with custom delete messages */} - - + > + Project RedHatAwesome will be deleted. + ); }; diff --git a/packages/module/patternfly-docs/content/examples/basic.md b/packages/module/patternfly-docs/content/examples/basic.md index 31e66de..db04270 100644 --- a/packages/module/patternfly-docs/content/examples/basic.md +++ b/packages/module/patternfly-docs/content/examples/basic.md @@ -28,3 +28,143 @@ import { DeleteModal } from "@patternfly/ai-infra-ui-components"; ```js file="./Basic.tsx" isFullscreen ``` + +### DeleteModal implementation + +```ts +import React from 'react'; +import { + Alert, + AlertProps, + Button, + Flex, + FlexItem, + Modal, + ModalBody, + ModalFooter, + ModalHeader, + ModalProps, + Stack, + StackItem, + TextInput, + TextInputProps +} from '@patternfly/react-core'; + +export type DeleteModalProps = ModalProps & { + /** Content rendered inside the modal header title. */ + title: React.ReactNode; + /** Delete variant. Destructive and extra-destructive variants will show a warning icon and danger button. For extra-destructive variant, text input confirmation is needed. */ + deleteVariant?: 'extra-destructive' | 'destructive' | 'easily-recoverable'; + /** Text which the user should type in to confirm deletion (only for extra-destructive delete variant) */ + deleteName: string; + /** Message describing what should the user type in to confirm deletion (only for extra-destructive delete variant) */ + confirmationMessage?: (deleteName: string) => React.ReactNode; + /** Text of the delete button */ + deleteButtonText?: string; + /** Text of the cancel button */ + cancelButtonText?: string; + /** Callback on clicking the delete button */ + onDelete: () => void; + /** Flag indicating that deletion is currently in progress */ + isDeleting?: boolean; + /** Error indicating deletion has failed */ + error?: Error; + /** Id of the modal for testing purposes (defaults to "delete-modal") */ + testId?: string; + /** Additional props for confirmation text input (only for extra-destructive delete variant) */ + textInputProps?: TextInputProps; + /** Additional props for error alert */ + errorAlertProps?: AlertProps; + /** Modal ref */ + ref?: React.RefObject; +}; + +export const DeleteModal: React.FunctionComponent = ({ + children, + title, + deleteVariant = 'extra-destructive', + deleteName, + confirmationMessage = (deleteName) => ( + <> + Type {deleteName} to confirm deletion: + + ), + deleteButtonText = 'Delete', + cancelButtonText = 'Cancel', + onDelete, + isDeleting, + error, + testId, + textInputProps, + errorAlertProps, + onClose, + isOpen, + ...props +}: DeleteModalProps) => { + const [confirmationText, setConfirmationText] = React.useState(''); + const confirmed = deleteVariant === 'extra-destructive' ? confirmationText.trim() === deleteName : true; + + React.useEffect(() => { + if (!isOpen) { + setConfirmationText(''); + } + }, [isOpen]); + + return ( + + + + + {children} + {deleteVariant === 'extra-destructive' && ( + + + {confirmationMessage(deleteName)} + setConfirmationText(value)} + onKeyDown={(event) => { + if (event.key === 'Enter' && confirmed && !isDeleting) { + event.preventDefault(); + onDelete(); + } + }} + /> + + + )} + {error && ( + + + {error.message} + + + )} + + + + + + + + ); +}; + +``` diff --git a/packages/module/patternfly-docs/generated/extensions/ai-infra-ui-components/react.js b/packages/module/patternfly-docs/generated/extensions/ai-infra-ui-components/react.js index 2f20f82..d06d9a3 100644 --- a/packages/module/patternfly-docs/generated/extensions/ai-infra-ui-components/react.js +++ b/packages/module/patternfly-docs/generated/extensions/ai-infra-ui-components/react.js @@ -32,11 +32,35 @@ const pageData = { "name": "DeleteModal", "description": "", "props": [ + { + "name": "cancelButtonText", + "type": "string", + "description": "Text of the cancel button", + "defaultValue": "'Cancel'" + }, + { + "name": "confirmationMessage", + "type": "(deleteName: string) => React.ReactNode", + "description": "Message describing what should the user type in to confirm deletion (only for extra-destructive delete variant)", + "defaultValue": "(deleteName) => (\n <>\n Type {deleteName} to confirm deletion:\n \n)" + }, + { + "name": "deleteButtonText", + "type": "string", + "description": "Text of the delete button", + "defaultValue": "'Delete'" + }, + { + "name": "deleteName", + "type": "string", + "description": "Text which the user should type in to confirm deletion (only for extra-destructive delete variant)", + "required": true + }, { "name": "deleteVariant", "type": "'extra-destructive' | 'destructive' | 'easily-recoverable'", "description": "Delete variant. Destructive and extra-destructive variants will show a warning icon and danger button. For extra-destructive variant, text input confirmation is needed.", - "defaultValue": "'destructive'" + "defaultValue": "'extra-destructive'" }, { "name": "error", @@ -44,26 +68,48 @@ const pageData = { "description": "Error indicating deletion has failed" }, { - "name": "message", - "type": "{\n toDelete?: string;\n resourcesToDelete?: string;\n endNote?: string;\n}", - "description": "Message describing what will deleted", - "defaultValue": "{\n resourcesToDelete: '',\n endNote: ''\n}" + "name": "errorAlertProps", + "type": "AlertProps", + "description": "Additional props for error alert" }, { - "name": "onCancel", - "type": "() => void", - "description": "Callback on clicking the cancel button" + "name": "isDeleting", + "type": "boolean", + "description": "Flag indicating that deletion is currently in progress" }, { "name": "onDelete", "type": "() => void", - "description": "Callback on clicking the delete button" + "description": "Callback on clicking the delete button", + "required": true + }, + { + "name": "ref", + "type": "React.RefObject", + "description": "Modal ref" + }, + { + "name": "testId", + "type": "string", + "description": "Id of the modal for testing purposes (defaults to \"delete-modal\")" + }, + { + "name": "textInputProps", + "type": "TextInputProps", + "description": "Additional props for confirmation text input (only for extra-destructive delete variant)" + }, + { + "name": "title", + "type": "React.ReactNode", + "description": "Content rendered inside the modal header title.", + "required": true } ] } ], "examples": [ - "Example" + "Example", + "DeleteModal implementation" ], "fullscreenExamples": [ "Fullscreen example" @@ -75,11 +121,15 @@ pageData.liveContext = { }; pageData.examples = { 'Example': props => - {\n const [isModalRecoverableOpen, setIsModalRecoverableOpen] = React.useState(false);\n const [isModalDestructiveOpen, setIsModalDestructiveOpen] = React.useState(false);\n const [isModalExtraDestructiveOpen, setIsModalExtraDestructiveOpen] = React.useState(false);\n\n const [isModalMultiExtraDestructiveOpen, setIsModalMultiExtraDestructiveOpen] = React.useState(false);\n\n const [isModalModelRegistryOpen, setIsModalModelRegistryOpen] = React.useState(false);\n const [isModalPipelineServerOpen, setIsModalPipelineServerOpen] = React.useState(false);\n\n const handleModalRecoverableToggle = (_event: KeyboardEvent | React.MouseEvent) => {\n setIsModalRecoverableOpen(!isModalRecoverableOpen);\n };\n\n const handleModalDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent) => {\n setIsModalDestructiveOpen(!isModalDestructiveOpen);\n };\n\n const handleModalExtraDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent) => {\n setIsModalExtraDestructiveOpen(!isModalExtraDestructiveOpen);\n };\n\n const handleModalMultiExtraDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent) => {\n setIsModalMultiExtraDestructiveOpen(!isModalMultiExtraDestructiveOpen);\n };\n\n const handleModalModelRegistryToggle = (_event: KeyboardEvent | React.MouseEvent) => {\n setIsModalModelRegistryOpen(!isModalModelRegistryOpen);\n };\n\n const handleModalPipelineServerToggle = (_event: KeyboardEvent | React.MouseEvent) => {\n setIsModalPipelineServerOpen(!isModalPipelineServerOpen);\n };\n\n return (\n <>\n \n
Modals with one item to delete
\n \n \n \n \n \n \n \n \n \n
\n\n \n
Modals with multiple items to delete
\n \n \n \n
\n\n \n
Modals with custom delete messages
\n \n \n \n \n \n \n
\n\n \n \n \n\n {/* Modals with multiple items to delete */}\n \n\n {/* Modals with custom delete messages */}\n \n \n \n );\n};\n","title":"Example","lang":"js","className":""}}> + {\n const [isModalRecoverableOpen, setIsModalRecoverableOpen] = React.useState(false);\n const [isModalDestructiveOpen, setIsModalDestructiveOpen] = React.useState(false);\n const [isModalExtraDestructiveOpen, setIsModalExtraDestructiveOpen] = React.useState(false);\n\n const handleModalRecoverableToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalRecoverableOpen(!isModalRecoverableOpen);\n };\n\n const handleModalDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalDestructiveOpen(!isModalDestructiveOpen);\n };\n\n const handleModalExtraDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalExtraDestructiveOpen(!isModalExtraDestructiveOpen);\n };\n\n return (\n <>\n \n \n \n \n \n \n \n \n \n \n \n\n handleModalRecoverableToggle(undefined)}\n deleteVariant=\"easily-recoverable\"\n isOpen={isModalRecoverableOpen}\n onClose={handleModalRecoverableToggle}\n >\n User group 123 will be deleted.\n
\n handleModalDestructiveToggle(undefined)}\n deleteVariant=\"destructive\"\n isOpen={isModalDestructiveOpen}\n onClose={handleModalDestructiveToggle}\n >\n Experiment cool-exp will be deleted.\n
\n handleModalExtraDestructiveToggle(undefined)}\n deleteVariant=\"extra-destructive\"\n isOpen={isModalExtraDestructiveOpen}\n onClose={handleModalExtraDestructiveToggle}\n >\n Project RedHatAwesome will be deleted.\n
\n \n );\n};\n","title":"Example","lang":"js","className":""}}>
, 'Fullscreen example': props => - {\n const [isModalRecoverableOpen, setIsModalRecoverableOpen] = React.useState(false);\n const [isModalDestructiveOpen, setIsModalDestructiveOpen] = React.useState(false);\n const [isModalExtraDestructiveOpen, setIsModalExtraDestructiveOpen] = React.useState(false);\n\n const [isModalMultiExtraDestructiveOpen, setIsModalMultiExtraDestructiveOpen] = React.useState(false);\n\n const [isModalModelRegistryOpen, setIsModalModelRegistryOpen] = React.useState(false);\n const [isModalPipelineServerOpen, setIsModalPipelineServerOpen] = React.useState(false);\n\n const handleModalRecoverableToggle = (_event: KeyboardEvent | React.MouseEvent) => {\n setIsModalRecoverableOpen(!isModalRecoverableOpen);\n };\n\n const handleModalDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent) => {\n setIsModalDestructiveOpen(!isModalDestructiveOpen);\n };\n\n const handleModalExtraDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent) => {\n setIsModalExtraDestructiveOpen(!isModalExtraDestructiveOpen);\n };\n\n const handleModalMultiExtraDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent) => {\n setIsModalMultiExtraDestructiveOpen(!isModalMultiExtraDestructiveOpen);\n };\n\n const handleModalModelRegistryToggle = (_event: KeyboardEvent | React.MouseEvent) => {\n setIsModalModelRegistryOpen(!isModalModelRegistryOpen);\n };\n\n const handleModalPipelineServerToggle = (_event: KeyboardEvent | React.MouseEvent) => {\n setIsModalPipelineServerOpen(!isModalPipelineServerOpen);\n };\n\n return (\n <>\n \n
Modals with one item to delete
\n \n \n \n \n \n \n \n \n \n
\n\n \n
Modals with multiple items to delete
\n \n \n \n
\n\n \n
Modals with custom delete messages
\n \n \n \n \n \n \n
\n\n \n \n \n\n {/* Modals with multiple items to delete */}\n \n\n {/* Modals with custom delete messages */}\n \n \n \n );\n};\n","title":"Fullscreen example","lang":"js","isFullscreen":true,"className":""}}> + {\n const [isModalRecoverableOpen, setIsModalRecoverableOpen] = React.useState(false);\n const [isModalDestructiveOpen, setIsModalDestructiveOpen] = React.useState(false);\n const [isModalExtraDestructiveOpen, setIsModalExtraDestructiveOpen] = React.useState(false);\n\n const handleModalRecoverableToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalRecoverableOpen(!isModalRecoverableOpen);\n };\n\n const handleModalDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalDestructiveOpen(!isModalDestructiveOpen);\n };\n\n const handleModalExtraDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalExtraDestructiveOpen(!isModalExtraDestructiveOpen);\n };\n\n return (\n <>\n \n \n \n \n \n \n \n \n \n \n \n\n handleModalRecoverableToggle(undefined)}\n deleteVariant=\"easily-recoverable\"\n isOpen={isModalRecoverableOpen}\n onClose={handleModalRecoverableToggle}\n >\n User group 123 will be deleted.\n
\n handleModalDestructiveToggle(undefined)}\n deleteVariant=\"destructive\"\n isOpen={isModalDestructiveOpen}\n onClose={handleModalDestructiveToggle}\n >\n Experiment cool-exp will be deleted.\n
\n handleModalExtraDestructiveToggle(undefined)}\n deleteVariant=\"extra-destructive\"\n isOpen={isModalExtraDestructiveOpen}\n onClose={handleModalExtraDestructiveToggle}\n >\n Project RedHatAwesome will be deleted.\n
\n \n );\n};\n","title":"Fullscreen example","lang":"js","isFullscreen":true,"className":""}}> + + , + 'DeleteModal implementation': props => + React.ReactNode;\n /** Text of the delete button */\n deleteButtonText?: string;\n /** Text of the cancel button */\n cancelButtonText?: string;\n /** Callback on clicking the delete button */\n onDelete: () => void;\n /** Flag indicating that deletion is currently in progress */\n isDeleting?: boolean;\n /** Error indicating deletion has failed */\n error?: Error;\n /** Id of the modal for testing purposes (defaults to \"delete-modal\") */\n testId?: string;\n /** Additional props for confirmation text input (only for extra-destructive delete variant) */\n textInputProps?: TextInputProps;\n /** Additional props for error alert */\n errorAlertProps?: AlertProps;\n /** Modal ref */\n ref?: React.RefObject;\n};\n\nexport const DeleteModal: React.FunctionComponent = ({\n children,\n title,\n deleteVariant = 'extra-destructive',\n deleteName,\n confirmationMessage = (deleteName) => (\n <>\n Type {deleteName} to confirm deletion:\n \n ),\n deleteButtonText = 'Delete',\n cancelButtonText = 'Cancel',\n onDelete,\n isDeleting,\n error,\n testId,\n textInputProps,\n errorAlertProps,\n onClose,\n isOpen,\n ...props\n}: DeleteModalProps) => {\n const [confirmationText, setConfirmationText] = React.useState('');\n const confirmed = deleteVariant === 'extra-destructive' ? confirmationText.trim() === deleteName : true;\n\n React.useEffect(() => {\n if (!isOpen) {\n setConfirmationText('');\n }\n }, [isOpen]);\n\n return (\n \n \n \n \n {children}\n {deleteVariant === 'extra-destructive' && (\n \n \n {confirmationMessage(deleteName)}\n setConfirmationText(value)}\n onKeyDown={(event) => {\n if (event.key === 'Enter' && confirmed && !isDeleting) {\n event.preventDefault();\n onDelete();\n }\n }}\n />\n \n \n )}\n {error && (\n \n \n {error.message}\n \n \n )}\n \n \n \n onDelete()}\n >\n {deleteButtonText}\n \n \n \n \n );\n};","title":"DeleteModal implementation","lang":"ts","className":""}}> }; @@ -91,6 +141,7 @@ const Component = () => ( {React.createElement(pageData.examples["Example"])} {React.createElement(pageData.examples["Fullscreen example"])} + {React.createElement(pageData.examples["DeleteModal implementation"])} ); Component.displayName = 'ExtensionsAiInfraUiComponentsReactDocs'; diff --git a/packages/module/patternfly-docs/generated/index.js b/packages/module/patternfly-docs/generated/index.js index 61e8536..db67d53 100644 --- a/packages/module/patternfly-docs/generated/index.js +++ b/packages/module/patternfly-docs/generated/index.js @@ -2,8 +2,8 @@ module.exports = { '/extensions/ai-infra-ui-components/react': { id: "AI-infra-ui-components", title: "AI-infra-ui-components", - toc: [{"text":"Basic usage"},[{"text":"Example"},{"text":"Fullscreen example"}]], - examples: ["Example"], + toc: [{"text":"Basic usage"},[{"text":"Example"},{"text":"Fullscreen example"},{"text":"DeleteModal implementation"}]], + examples: ["Example","DeleteModal implementation"], fullscreenExamples: ["Fullscreen example"], section: "extensions", subsection: "", diff --git a/packages/module/src/DeleteModal/DeleteModal.tsx b/packages/module/src/DeleteModal/DeleteModal.tsx index 17acee1..1099ff0 100644 --- a/packages/module/src/DeleteModal/DeleteModal.tsx +++ b/packages/module/src/DeleteModal/DeleteModal.tsx @@ -1,10 +1,10 @@ import React from 'react'; import { Alert, + AlertProps, Button, - FormGroup, - List, - ListItem, + Flex, + FlexItem, Modal, ModalBody, ModalFooter, @@ -12,144 +12,122 @@ import { ModalProps, Stack, StackItem, - TextInput + TextInput, + TextInputProps } from '@patternfly/react-core'; -/** Props specifying either one item or a list of items to delete */ -type ItemProps = - | { - /** Type of item to delete (e.g. project, pipeline server, model registry) */ - item: string; - /** Name of the item to delete */ - itemName: string; - items?: never; - itemNames?: never; - } - | { - /** Type of items to delete in plural (e.g. projects, pipeline servers, model registries) */ - items: string; - /** List of names of the items to delete */ - itemNames: string[]; - item?: never; - itemName?: never; - }; - -export type DeleteModalProps = Omit & - ItemProps & { - /** Delete variant. Destructive and extra-destructive variants will show a warning icon and danger button. For extra-destructive variant, text input confirmation is needed. */ - deleteVariant?: 'extra-destructive' | 'destructive' | 'easily-recoverable'; - /** Message describing what will deleted */ - message?: { - toDelete?: string; - resourcesToDelete?: string; - endNote?: string; - }; - /** Callback on clicking the delete button */ - onDelete?: () => void; - /** Callback on clicking the cancel button */ - onCancel?: () => void; - /** Error indicating deletion has failed */ - error?: Error; - /** Modal ref */ - ref: React.RefObject; - }; +export type DeleteModalProps = ModalProps & { + /** Content rendered inside the modal header title. */ + title: React.ReactNode; + /** Delete variant. Destructive and extra-destructive variants will show a warning icon and danger button. For extra-destructive variant, text input confirmation is needed. */ + deleteVariant?: 'extra-destructive' | 'destructive' | 'easily-recoverable'; + /** Text which the user should type in to confirm deletion (only for extra-destructive delete variant) */ + deleteName: string; + /** Message describing what should the user type in to confirm deletion (only for extra-destructive delete variant) */ + confirmationMessage?: (deleteName: string) => React.ReactNode; + /** Text of the delete button */ + deleteButtonText?: string; + /** Text of the cancel button */ + cancelButtonText?: string; + /** Callback on clicking the delete button */ + onDelete: () => void; + /** Flag indicating that deletion is currently in progress */ + isDeleting?: boolean; + /** Error indicating deletion has failed */ + error?: Error; + /** Id of the modal for testing purposes (defaults to "delete-modal") */ + testId?: string; + /** Additional props for confirmation text input (only for extra-destructive delete variant) */ + textInputProps?: TextInputProps; + /** Additional props for error alert */ + errorAlertProps?: AlertProps; + /** Modal ref */ + ref?: React.RefObject; +}; export const DeleteModal: React.FunctionComponent = ({ - item, - items, - itemName, - itemNames, - deleteVariant = 'destructive', + children, + title, + deleteVariant = 'extra-destructive', + deleteName, + confirmationMessage = (deleteName) => ( + <> + Type {deleteName} to confirm deletion: + + ), + deleteButtonText = 'Delete', + cancelButtonText = 'Cancel', onDelete, - onCancel, - message = { - resourcesToDelete: '', - endNote: '' - }, + isDeleting, error, + testId, + textInputProps, + errorAlertProps, + onClose, + isOpen, ...props }: DeleteModalProps) => { - const isPlural = item === undefined; - const [confirmationText, setConfirmationText] = React.useState(''); - const expectedConfirmationText = isPlural ? `delete ${itemNames.length} ${items}` : itemName; - - const confirmed = deleteVariant === 'extra-destructive' ? confirmationText === expectedConfirmationText : true; - - const toDeleteMessage = message.toDelete ?? ` and all of ${isPlural ? 'their' : 'its'} resources`; + const confirmed = deleteVariant === 'extra-destructive' ? confirmationText.trim() === deleteName : true; - const itemToDelete = `${itemNames ? `${itemNames.length} ` : ''}${item ?? items}`; - const modalHeaderTitle = `Delete ${itemToDelete}?`; + React.useEffect(() => { + if (!isOpen) { + setConfirmationText(''); + } + }, [isOpen]); return ( - - + + - - The{' '} - {isPlural ? ( - `following ${items}` - ) : ( - <> - {itemName} {item} - - )} - {toDeleteMessage} - {message.resourcesToDelete} will be deleted{isPlural && !message.endNote ? ':' : '.'} {message.endNote} - {isPlural && ( - - {itemNames.map((name) => ( - - {name} - - ))} - - )} - + {children} {deleteVariant === 'extra-destructive' && ( - - Type {expectedConfirmationText} to confirm deletion: - - } - > + + {confirmationMessage(deleteName)} setConfirmationText(value)} - // validated={confirmed ? 'success' : 'default'} + onKeyDown={(event) => { + if (event.key === 'Enter' && confirmed && !isDeleting) { + event.preventDefault(); + onDelete(); + } + }} /> - + + + )} + {error && ( + + + {error.message} + )} - - {error && ( - - {error.message} - - )} ); From 7fd529c96687df43a76dea6452f5de6889b73646 Mon Sep 17 00:00:00 2001 From: adamviktora Date: Tue, 8 Oct 2024 15:14:54 +0200 Subject: [PATCH 03/11] fix: PR review --- .../patternfly-docs/content/examples/Basic.tsx | 18 +++++++++--------- .../extensions/ai-infra-ui-components/react.js | 4 ++-- .../module/src/DeleteModal/DeleteModal.tsx | 16 ++++++++-------- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/packages/module/patternfly-docs/content/examples/Basic.tsx b/packages/module/patternfly-docs/content/examples/Basic.tsx index 513eede..2b47c25 100644 --- a/packages/module/patternfly-docs/content/examples/Basic.tsx +++ b/packages/module/patternfly-docs/content/examples/Basic.tsx @@ -40,34 +40,34 @@ export const DeleteModalBasic: React.FunctionComponent = () => { handleModalRecoverableToggle(undefined)} deleteVariant="easily-recoverable" isOpen={isModalRecoverableOpen} onClose={handleModalRecoverableToggle} > - User group 123 will be deleted. + The item-name item will be deleted. handleModalDestructiveToggle(undefined)} deleteVariant="destructive" isOpen={isModalDestructiveOpen} onClose={handleModalDestructiveToggle} > - Experiment cool-exp will be deleted. + The item-name item will be deleted. [Brief sentence describing consequence of action]. handleModalExtraDestructiveToggle(undefined)} deleteVariant="extra-destructive" isOpen={isModalExtraDestructiveOpen} onClose={handleModalExtraDestructiveToggle} > - Project RedHatAwesome will be deleted. + The item-name item will be deleted. [Brief sentence describing consequence of action]. ); diff --git a/packages/module/patternfly-docs/generated/extensions/ai-infra-ui-components/react.js b/packages/module/patternfly-docs/generated/extensions/ai-infra-ui-components/react.js index d06d9a3..11d4e4d 100644 --- a/packages/module/patternfly-docs/generated/extensions/ai-infra-ui-components/react.js +++ b/packages/module/patternfly-docs/generated/extensions/ai-infra-ui-components/react.js @@ -121,11 +121,11 @@ pageData.liveContext = { }; pageData.examples = { 'Example': props => - {\n const [isModalRecoverableOpen, setIsModalRecoverableOpen] = React.useState(false);\n const [isModalDestructiveOpen, setIsModalDestructiveOpen] = React.useState(false);\n const [isModalExtraDestructiveOpen, setIsModalExtraDestructiveOpen] = React.useState(false);\n\n const handleModalRecoverableToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalRecoverableOpen(!isModalRecoverableOpen);\n };\n\n const handleModalDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalDestructiveOpen(!isModalDestructiveOpen);\n };\n\n const handleModalExtraDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalExtraDestructiveOpen(!isModalExtraDestructiveOpen);\n };\n\n return (\n <>\n \n \n \n \n \n \n \n \n \n \n \n\n handleModalRecoverableToggle(undefined)}\n deleteVariant=\"easily-recoverable\"\n isOpen={isModalRecoverableOpen}\n onClose={handleModalRecoverableToggle}\n >\n User group 123 will be deleted.\n
\n handleModalDestructiveToggle(undefined)}\n deleteVariant=\"destructive\"\n isOpen={isModalDestructiveOpen}\n onClose={handleModalDestructiveToggle}\n >\n Experiment cool-exp will be deleted.\n
\n handleModalExtraDestructiveToggle(undefined)}\n deleteVariant=\"extra-destructive\"\n isOpen={isModalExtraDestructiveOpen}\n onClose={handleModalExtraDestructiveToggle}\n >\n Project RedHatAwesome will be deleted.\n
\n \n );\n};\n","title":"Example","lang":"js","className":""}}> + {\n const [isModalRecoverableOpen, setIsModalRecoverableOpen] = React.useState(false);\n const [isModalDestructiveOpen, setIsModalDestructiveOpen] = React.useState(false);\n const [isModalExtraDestructiveOpen, setIsModalExtraDestructiveOpen] = React.useState(false);\n\n const handleModalRecoverableToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalRecoverableOpen(!isModalRecoverableOpen);\n };\n\n const handleModalDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalDestructiveOpen(!isModalDestructiveOpen);\n };\n\n const handleModalExtraDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalExtraDestructiveOpen(!isModalExtraDestructiveOpen);\n };\n\n return (\n <>\n \n \n \n \n \n \n \n \n \n \n \n\n handleModalRecoverableToggle(undefined)}\n deleteVariant=\"easily-recoverable\"\n isOpen={isModalRecoverableOpen}\n onClose={handleModalRecoverableToggle}\n >\n The item-name item will be deleted.\n \n handleModalDestructiveToggle(undefined)}\n deleteVariant=\"destructive\"\n isOpen={isModalDestructiveOpen}\n onClose={handleModalDestructiveToggle}\n >\n The item-name item will be deleted. [Brief sentence describing consequence of action].\n \n handleModalExtraDestructiveToggle(undefined)}\n deleteVariant=\"extra-destructive\"\n isOpen={isModalExtraDestructiveOpen}\n onClose={handleModalExtraDestructiveToggle}\n >\n The item-name item will be deleted. [Brief sentence describing consequence of action].\n \n \n );\n};\n","title":"Example","lang":"js","className":""}}> , 'Fullscreen example': props => - {\n const [isModalRecoverableOpen, setIsModalRecoverableOpen] = React.useState(false);\n const [isModalDestructiveOpen, setIsModalDestructiveOpen] = React.useState(false);\n const [isModalExtraDestructiveOpen, setIsModalExtraDestructiveOpen] = React.useState(false);\n\n const handleModalRecoverableToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalRecoverableOpen(!isModalRecoverableOpen);\n };\n\n const handleModalDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalDestructiveOpen(!isModalDestructiveOpen);\n };\n\n const handleModalExtraDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalExtraDestructiveOpen(!isModalExtraDestructiveOpen);\n };\n\n return (\n <>\n \n \n \n \n \n \n \n \n \n \n \n\n handleModalRecoverableToggle(undefined)}\n deleteVariant=\"easily-recoverable\"\n isOpen={isModalRecoverableOpen}\n onClose={handleModalRecoverableToggle}\n >\n User group 123 will be deleted.\n \n handleModalDestructiveToggle(undefined)}\n deleteVariant=\"destructive\"\n isOpen={isModalDestructiveOpen}\n onClose={handleModalDestructiveToggle}\n >\n Experiment cool-exp will be deleted.\n \n handleModalExtraDestructiveToggle(undefined)}\n deleteVariant=\"extra-destructive\"\n isOpen={isModalExtraDestructiveOpen}\n onClose={handleModalExtraDestructiveToggle}\n >\n Project RedHatAwesome will be deleted.\n \n \n );\n};\n","title":"Fullscreen example","lang":"js","isFullscreen":true,"className":""}}> + {\n const [isModalRecoverableOpen, setIsModalRecoverableOpen] = React.useState(false);\n const [isModalDestructiveOpen, setIsModalDestructiveOpen] = React.useState(false);\n const [isModalExtraDestructiveOpen, setIsModalExtraDestructiveOpen] = React.useState(false);\n\n const handleModalRecoverableToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalRecoverableOpen(!isModalRecoverableOpen);\n };\n\n const handleModalDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalDestructiveOpen(!isModalDestructiveOpen);\n };\n\n const handleModalExtraDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalExtraDestructiveOpen(!isModalExtraDestructiveOpen);\n };\n\n return (\n <>\n \n \n \n \n \n \n \n \n \n \n \n\n handleModalRecoverableToggle(undefined)}\n deleteVariant=\"easily-recoverable\"\n isOpen={isModalRecoverableOpen}\n onClose={handleModalRecoverableToggle}\n >\n The item-name item will be deleted.\n \n handleModalDestructiveToggle(undefined)}\n deleteVariant=\"destructive\"\n isOpen={isModalDestructiveOpen}\n onClose={handleModalDestructiveToggle}\n >\n The item-name item will be deleted. [Brief sentence describing consequence of action].\n \n handleModalExtraDestructiveToggle(undefined)}\n deleteVariant=\"extra-destructive\"\n isOpen={isModalExtraDestructiveOpen}\n onClose={handleModalExtraDestructiveToggle}\n >\n The item-name item will be deleted. [Brief sentence describing consequence of action].\n \n \n );\n};\n","title":"Fullscreen example","lang":"js","isFullscreen":true,"className":""}}> , 'DeleteModal implementation': props => diff --git a/packages/module/src/DeleteModal/DeleteModal.tsx b/packages/module/src/DeleteModal/DeleteModal.tsx index 1099ff0..aa15d28 100644 --- a/packages/module/src/DeleteModal/DeleteModal.tsx +++ b/packages/module/src/DeleteModal/DeleteModal.tsx @@ -67,17 +67,17 @@ export const DeleteModal: React.FunctionComponent = ({ isOpen, ...props }: DeleteModalProps) => { - const [confirmationText, setConfirmationText] = React.useState(''); - const confirmed = deleteVariant === 'extra-destructive' ? confirmationText.trim() === deleteName : true; + const [inputValue, setInputValue] = React.useState(''); + const confirmed = deleteVariant === 'extra-destructive' ? inputValue.trim() === deleteName : true; React.useEffect(() => { if (!isOpen) { - setConfirmationText(''); + setInputValue(''); } }, [isOpen]); return ( - + @@ -85,13 +85,13 @@ export const DeleteModal: React.FunctionComponent = ({ {deleteVariant === 'extra-destructive' && ( - {confirmationMessage(deleteName)} + {confirmationMessage(deleteName)} setConfirmationText(value)} + aria-labelledby="confirmation-message" + value={inputValue} + onChange={(_e, value) => setInputValue(value)} onKeyDown={(event) => { if (event.key === 'Enter' && confirmed && !isDeleting) { event.preventDefault(); From fd6fe51527d37eaffd741a7136b844741d70b796 Mon Sep 17 00:00:00 2001 From: adamviktora Date: Tue, 8 Oct 2024 15:29:42 +0200 Subject: [PATCH 04/11] update docs to show DeleteModal tab --- .../design-guidelines/design-guidelines.md | 2 +- .../patternfly-docs/content/examples/basic.md | 7 +- .../deletemodal/design-guidelines.js | 56 +++++++ .../deletemodal/react.js | 144 ++++++++++++++++++ .../deletemodal/design-guidelines.js | 56 +++++++ .../generated/extensions/deletemodal/react.js | 144 ++++++++++++++++++ .../module/patternfly-docs/generated/index.js | 16 +- 7 files changed, 413 insertions(+), 12 deletions(-) create mode 100644 packages/module/patternfly-docs/generated/ai-infra-ui-components/deletemodal/design-guidelines.js create mode 100644 packages/module/patternfly-docs/generated/ai-infra-ui-components/deletemodal/react.js create mode 100644 packages/module/patternfly-docs/generated/extensions/deletemodal/design-guidelines.js create mode 100644 packages/module/patternfly-docs/generated/extensions/deletemodal/react.js diff --git a/packages/module/patternfly-docs/content/design-guidelines/design-guidelines.md b/packages/module/patternfly-docs/content/design-guidelines/design-guidelines.md index b1a1956..3d6fcf3 100644 --- a/packages/module/patternfly-docs/content/design-guidelines/design-guidelines.md +++ b/packages/module/patternfly-docs/content/design-guidelines/design-guidelines.md @@ -4,7 +4,7 @@ section: extensions # Sidenav secondary level section # should be the same for all markdown files for each extension -id: AI-infra-ui-components +id: DeleteModal # Tab (react | react-demos | html | html-demos | design-guidelines | accessibility) source: design-guidelines --- diff --git a/packages/module/patternfly-docs/content/examples/basic.md b/packages/module/patternfly-docs/content/examples/basic.md index db04270..c47664f 100644 --- a/packages/module/patternfly-docs/content/examples/basic.md +++ b/packages/module/patternfly-docs/content/examples/basic.md @@ -4,17 +4,18 @@ section: extensions # Sidenav secondary level section # should be the same for all markdown files -id: AI-infra-ui-components +id: DeleteModal # Tab (react | react-demos | html | html-demos | design-guidelines | accessibility) source: react # If you use typescript, the name of the interface to display props for # These are found through the sourceProps function provided in patternfly-docs.source.js -propComponents: ['ExtendedButton', 'DeleteModal'] +propComponents: ['DeleteModal'] --- -import { ExtendedButton } from "@patternfly/ai-infra-ui-components"; import { DeleteModal } from "@patternfly/ai-infra-ui-components"; +Note: this component is an upgrade of an [existing DeleteModal](https://github.com/opendatahub-io/odh-dashboard/blob/main/frontend/src/pages/projects/components/DeleteModal.tsx) in odh-dashboard + ## Basic usage ### Example diff --git a/packages/module/patternfly-docs/generated/ai-infra-ui-components/deletemodal/design-guidelines.js b/packages/module/patternfly-docs/generated/ai-infra-ui-components/deletemodal/design-guidelines.js new file mode 100644 index 0000000..b0244c9 --- /dev/null +++ b/packages/module/patternfly-docs/generated/ai-infra-ui-components/deletemodal/design-guidelines.js @@ -0,0 +1,56 @@ +import React from 'react'; +import { AutoLinkHeader, Example, Link as PatternflyThemeLink } from '@patternfly/documentation-framework/components'; + +const pageData = { + "id": "DeleteModal", + "section": "AI-infra-ui-components", + "subsection": "", + "deprecated": false, + "template": false, + "beta": false, + "demo": false, + "newImplementationLink": false, + "source": "design-guidelines", + "tabName": null, + "slug": "/ai-infra-ui-components/deletemodal/design-guidelines", + "sourceLink": "https://github.com/patternfly/patternfly-org/blob/main/packages/module/patternfly-docs/content/design-guidelines/design-guidelines.md", + "relPath": "packages/module/patternfly-docs/content/design-guidelines/design-guidelines.md" +}; +pageData.examples = { + +}; + +const Component = () => ( + +

+ {`Design guidelines intro`} +

+ + {`Header`} + + + {`Sub-header`} + +

+ {`Guidelines:`} +

+
    +
  1. + {`A`} +
  2. +
  3. + {`list`} +
  4. +
  5. + {`using`} +
  6. +
  7. + {`markdown`} +
  8. +
+
+); +Component.displayName = 'AiInfraUiComponentsDeletemodalDesignGuidelinesDocs'; +Component.pageData = pageData; + +export default Component; diff --git a/packages/module/patternfly-docs/generated/ai-infra-ui-components/deletemodal/react.js b/packages/module/patternfly-docs/generated/ai-infra-ui-components/deletemodal/react.js new file mode 100644 index 0000000..ef0bdc8 --- /dev/null +++ b/packages/module/patternfly-docs/generated/ai-infra-ui-components/deletemodal/react.js @@ -0,0 +1,144 @@ +import React from 'react'; +import { AutoLinkHeader, Example, Link as PatternflyThemeLink } from '@patternfly/documentation-framework/components'; +import { DeleteModal } from "@patternfly/ai-infra-ui-components"; +const pageData = { + "id": "DeleteModal", + "section": "AI-infra-ui-components", + "subsection": "", + "deprecated": false, + "template": false, + "beta": false, + "demo": false, + "newImplementationLink": false, + "source": "react", + "tabName": null, + "slug": "/ai-infra-ui-components/deletemodal/react", + "sourceLink": "https://github.com/patternfly/patternfly-react/blob/main/packages/module/patternfly-docs/content/examples/basic.md", + "relPath": "packages/module/patternfly-docs/content/examples/basic.md", + "propComponents": [ + { + "name": "DeleteModal", + "description": "", + "props": [ + { + "name": "cancelButtonText", + "type": "string", + "description": "Text of the cancel button", + "defaultValue": "'Cancel'" + }, + { + "name": "confirmationMessage", + "type": "(deleteName: string) => React.ReactNode", + "description": "Message describing what should the user type in to confirm deletion (only for extra-destructive delete variant)", + "defaultValue": "(deleteName) => (\n <>\n Type {deleteName} to confirm deletion:\n \n)" + }, + { + "name": "deleteButtonText", + "type": "string", + "description": "Text of the delete button", + "defaultValue": "'Delete'" + }, + { + "name": "deleteName", + "type": "string", + "description": "Text which the user should type in to confirm deletion (only for extra-destructive delete variant)", + "required": true + }, + { + "name": "deleteVariant", + "type": "'extra-destructive' | 'destructive' | 'easily-recoverable'", + "description": "Delete variant. Destructive and extra-destructive variants will show a warning icon and danger button. For extra-destructive variant, text input confirmation is needed.", + "defaultValue": "'extra-destructive'" + }, + { + "name": "error", + "type": "Error", + "description": "Error indicating deletion has failed" + }, + { + "name": "errorAlertProps", + "type": "AlertProps", + "description": "Additional props for error alert" + }, + { + "name": "isDeleting", + "type": "boolean", + "description": "Flag indicating that deletion is currently in progress" + }, + { + "name": "onDelete", + "type": "() => void", + "description": "Callback on clicking the delete button", + "required": true + }, + { + "name": "ref", + "type": "React.RefObject", + "description": "Modal ref" + }, + { + "name": "testId", + "type": "string", + "description": "Id of the modal for testing purposes (defaults to \"delete-modal\")" + }, + { + "name": "textInputProps", + "type": "TextInputProps", + "description": "Additional props for confirmation text input (only for extra-destructive delete variant)" + }, + { + "name": "title", + "type": "React.ReactNode", + "description": "Content rendered inside the modal header title.", + "required": true + } + ] + } + ], + "examples": [ + "Example", + "DeleteModal implementation" + ], + "fullscreenExamples": [ + "Fullscreen example" + ] +}; +pageData.liveContext = { + DeleteModal +}; +pageData.examples = { + 'Example': props => + {\n const [isModalRecoverableOpen, setIsModalRecoverableOpen] = React.useState(false);\n const [isModalDestructiveOpen, setIsModalDestructiveOpen] = React.useState(false);\n const [isModalExtraDestructiveOpen, setIsModalExtraDestructiveOpen] = React.useState(false);\n\n const handleModalRecoverableToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalRecoverableOpen(!isModalRecoverableOpen);\n };\n\n const handleModalDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalDestructiveOpen(!isModalDestructiveOpen);\n };\n\n const handleModalExtraDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalExtraDestructiveOpen(!isModalExtraDestructiveOpen);\n };\n\n return (\n <>\n \n \n \n \n \n \n \n \n \n \n \n\n handleModalRecoverableToggle(undefined)}\n deleteVariant=\"easily-recoverable\"\n isOpen={isModalRecoverableOpen}\n onClose={handleModalRecoverableToggle}\n >\n The item-name item will be deleted.\n \n handleModalDestructiveToggle(undefined)}\n deleteVariant=\"destructive\"\n isOpen={isModalDestructiveOpen}\n onClose={handleModalDestructiveToggle}\n >\n The item-name item will be deleted. [Brief sentence describing consequence of action].\n \n handleModalExtraDestructiveToggle(undefined)}\n deleteVariant=\"extra-destructive\"\n isOpen={isModalExtraDestructiveOpen}\n onClose={handleModalExtraDestructiveToggle}\n >\n The item-name item will be deleted. [Brief sentence describing consequence of action].\n \n \n );\n};\n","title":"Example","lang":"js","className":""}}> + + , + 'Fullscreen example': props => + {\n const [isModalRecoverableOpen, setIsModalRecoverableOpen] = React.useState(false);\n const [isModalDestructiveOpen, setIsModalDestructiveOpen] = React.useState(false);\n const [isModalExtraDestructiveOpen, setIsModalExtraDestructiveOpen] = React.useState(false);\n\n const handleModalRecoverableToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalRecoverableOpen(!isModalRecoverableOpen);\n };\n\n const handleModalDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalDestructiveOpen(!isModalDestructiveOpen);\n };\n\n const handleModalExtraDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalExtraDestructiveOpen(!isModalExtraDestructiveOpen);\n };\n\n return (\n <>\n \n \n \n \n \n \n \n \n \n \n \n\n handleModalRecoverableToggle(undefined)}\n deleteVariant=\"easily-recoverable\"\n isOpen={isModalRecoverableOpen}\n onClose={handleModalRecoverableToggle}\n >\n The item-name item will be deleted.\n \n handleModalDestructiveToggle(undefined)}\n deleteVariant=\"destructive\"\n isOpen={isModalDestructiveOpen}\n onClose={handleModalDestructiveToggle}\n >\n The item-name item will be deleted. [Brief sentence describing consequence of action].\n \n handleModalExtraDestructiveToggle(undefined)}\n deleteVariant=\"extra-destructive\"\n isOpen={isModalExtraDestructiveOpen}\n onClose={handleModalExtraDestructiveToggle}\n >\n The item-name item will be deleted. [Brief sentence describing consequence of action].\n \n \n );\n};\n","title":"Fullscreen example","lang":"js","isFullscreen":true,"className":""}}> + + , + 'DeleteModal implementation': props => + React.ReactNode;\n /** Text of the delete button */\n deleteButtonText?: string;\n /** Text of the cancel button */\n cancelButtonText?: string;\n /** Callback on clicking the delete button */\n onDelete: () => void;\n /** Flag indicating that deletion is currently in progress */\n isDeleting?: boolean;\n /** Error indicating deletion has failed */\n error?: Error;\n /** Id of the modal for testing purposes (defaults to \"delete-modal\") */\n testId?: string;\n /** Additional props for confirmation text input (only for extra-destructive delete variant) */\n textInputProps?: TextInputProps;\n /** Additional props for error alert */\n errorAlertProps?: AlertProps;\n /** Modal ref */\n ref?: React.RefObject;\n};\n\nexport const DeleteModal: React.FunctionComponent = ({\n children,\n title,\n deleteVariant = 'extra-destructive',\n deleteName,\n confirmationMessage = (deleteName) => (\n <>\n Type {deleteName} to confirm deletion:\n \n ),\n deleteButtonText = 'Delete',\n cancelButtonText = 'Cancel',\n onDelete,\n isDeleting,\n error,\n testId,\n textInputProps,\n errorAlertProps,\n onClose,\n isOpen,\n ...props\n}: DeleteModalProps) => {\n const [confirmationText, setConfirmationText] = React.useState('');\n const confirmed = deleteVariant === 'extra-destructive' ? confirmationText.trim() === deleteName : true;\n\n React.useEffect(() => {\n if (!isOpen) {\n setConfirmationText('');\n }\n }, [isOpen]);\n\n return (\n \n \n \n \n {children}\n {deleteVariant === 'extra-destructive' && (\n \n \n {confirmationMessage(deleteName)}\n setConfirmationText(value)}\n onKeyDown={(event) => {\n if (event.key === 'Enter' && confirmed && !isDeleting) {\n event.preventDefault();\n onDelete();\n }\n }}\n />\n \n \n )}\n {error && (\n \n \n {error.message}\n \n \n )}\n \n \n \n onDelete()}\n >\n {deleteButtonText}\n \n \n \n \n );\n};","title":"DeleteModal implementation","lang":"ts","className":""}}> + + +}; + +const Component = () => ( + +

+ {`Note: this component is an upgrade of an `} + + {`existing DeleteModal`} + + {` in odh-dashboard`} +

+ + {`Basic usage`} + + {React.createElement(pageData.examples["Example"])} + {React.createElement(pageData.examples["Fullscreen example"])} + {React.createElement(pageData.examples["DeleteModal implementation"])} +
+); +Component.displayName = 'AiInfraUiComponentsDeletemodalReactDocs'; +Component.pageData = pageData; + +export default Component; diff --git a/packages/module/patternfly-docs/generated/extensions/deletemodal/design-guidelines.js b/packages/module/patternfly-docs/generated/extensions/deletemodal/design-guidelines.js new file mode 100644 index 0000000..540e07a --- /dev/null +++ b/packages/module/patternfly-docs/generated/extensions/deletemodal/design-guidelines.js @@ -0,0 +1,56 @@ +import React from 'react'; +import { AutoLinkHeader, Example, Link as PatternflyThemeLink } from '@patternfly/documentation-framework/components'; + +const pageData = { + "id": "DeleteModal", + "section": "extensions", + "subsection": "", + "deprecated": false, + "template": false, + "beta": false, + "demo": false, + "newImplementationLink": false, + "source": "design-guidelines", + "tabName": null, + "slug": "/extensions/deletemodal/design-guidelines", + "sourceLink": "https://github.com/patternfly/patternfly-org/blob/main/packages/module/patternfly-docs/content/design-guidelines/design-guidelines.md", + "relPath": "packages/module/patternfly-docs/content/design-guidelines/design-guidelines.md" +}; +pageData.examples = { + +}; + +const Component = () => ( + +

+ {`Design guidelines intro`} +

+ + {`Header`} + + + {`Sub-header`} + +

+ {`Guidelines:`} +

+
    +
  1. + {`A`} +
  2. +
  3. + {`list`} +
  4. +
  5. + {`using`} +
  6. +
  7. + {`markdown`} +
  8. +
+
+); +Component.displayName = 'ExtensionsDeletemodalDesignGuidelinesDocs'; +Component.pageData = pageData; + +export default Component; diff --git a/packages/module/patternfly-docs/generated/extensions/deletemodal/react.js b/packages/module/patternfly-docs/generated/extensions/deletemodal/react.js new file mode 100644 index 0000000..b5469f2 --- /dev/null +++ b/packages/module/patternfly-docs/generated/extensions/deletemodal/react.js @@ -0,0 +1,144 @@ +import React from 'react'; +import { AutoLinkHeader, Example, Link as PatternflyThemeLink } from '@patternfly/documentation-framework/components'; +import { DeleteModal } from "@patternfly/ai-infra-ui-components"; +const pageData = { + "id": "DeleteModal", + "section": "extensions", + "subsection": "", + "deprecated": false, + "template": false, + "beta": false, + "demo": false, + "newImplementationLink": false, + "source": "react", + "tabName": null, + "slug": "/extensions/deletemodal/react", + "sourceLink": "https://github.com/patternfly/patternfly-react/blob/main/packages/module/patternfly-docs/content/examples/basic.md", + "relPath": "packages/module/patternfly-docs/content/examples/basic.md", + "propComponents": [ + { + "name": "DeleteModal", + "description": "", + "props": [ + { + "name": "cancelButtonText", + "type": "string", + "description": "Text of the cancel button", + "defaultValue": "'Cancel'" + }, + { + "name": "confirmationMessage", + "type": "(deleteName: string) => React.ReactNode", + "description": "Message describing what should the user type in to confirm deletion (only for extra-destructive delete variant)", + "defaultValue": "(deleteName) => (\n <>\n Type {deleteName} to confirm deletion:\n \n)" + }, + { + "name": "deleteButtonText", + "type": "string", + "description": "Text of the delete button", + "defaultValue": "'Delete'" + }, + { + "name": "deleteName", + "type": "string", + "description": "Text which the user should type in to confirm deletion (only for extra-destructive delete variant)", + "required": true + }, + { + "name": "deleteVariant", + "type": "'extra-destructive' | 'destructive' | 'easily-recoverable'", + "description": "Delete variant. Destructive and extra-destructive variants will show a warning icon and danger button. For extra-destructive variant, text input confirmation is needed.", + "defaultValue": "'extra-destructive'" + }, + { + "name": "error", + "type": "Error", + "description": "Error indicating deletion has failed" + }, + { + "name": "errorAlertProps", + "type": "AlertProps", + "description": "Additional props for error alert" + }, + { + "name": "isDeleting", + "type": "boolean", + "description": "Flag indicating that deletion is currently in progress" + }, + { + "name": "onDelete", + "type": "() => void", + "description": "Callback on clicking the delete button", + "required": true + }, + { + "name": "ref", + "type": "React.RefObject", + "description": "Modal ref" + }, + { + "name": "testId", + "type": "string", + "description": "Id of the modal for testing purposes (defaults to \"delete-modal\")" + }, + { + "name": "textInputProps", + "type": "TextInputProps", + "description": "Additional props for confirmation text input (only for extra-destructive delete variant)" + }, + { + "name": "title", + "type": "React.ReactNode", + "description": "Content rendered inside the modal header title.", + "required": true + } + ] + } + ], + "examples": [ + "Example", + "DeleteModal implementation" + ], + "fullscreenExamples": [ + "Fullscreen example" + ] +}; +pageData.liveContext = { + DeleteModal +}; +pageData.examples = { + 'Example': props => + {\n const [isModalRecoverableOpen, setIsModalRecoverableOpen] = React.useState(false);\n const [isModalDestructiveOpen, setIsModalDestructiveOpen] = React.useState(false);\n const [isModalExtraDestructiveOpen, setIsModalExtraDestructiveOpen] = React.useState(false);\n\n const handleModalRecoverableToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalRecoverableOpen(!isModalRecoverableOpen);\n };\n\n const handleModalDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalDestructiveOpen(!isModalDestructiveOpen);\n };\n\n const handleModalExtraDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalExtraDestructiveOpen(!isModalExtraDestructiveOpen);\n };\n\n return (\n <>\n \n \n \n \n \n \n \n \n \n \n \n\n handleModalRecoverableToggle(undefined)}\n deleteVariant=\"easily-recoverable\"\n isOpen={isModalRecoverableOpen}\n onClose={handleModalRecoverableToggle}\n >\n The item-name item will be deleted.\n \n handleModalDestructiveToggle(undefined)}\n deleteVariant=\"destructive\"\n isOpen={isModalDestructiveOpen}\n onClose={handleModalDestructiveToggle}\n >\n The item-name item will be deleted. [Brief sentence describing consequence of action].\n \n handleModalExtraDestructiveToggle(undefined)}\n deleteVariant=\"extra-destructive\"\n isOpen={isModalExtraDestructiveOpen}\n onClose={handleModalExtraDestructiveToggle}\n >\n The item-name item will be deleted. [Brief sentence describing consequence of action].\n \n \n );\n};\n","title":"Example","lang":"js","className":""}}> + + , + 'Fullscreen example': props => + {\n const [isModalRecoverableOpen, setIsModalRecoverableOpen] = React.useState(false);\n const [isModalDestructiveOpen, setIsModalDestructiveOpen] = React.useState(false);\n const [isModalExtraDestructiveOpen, setIsModalExtraDestructiveOpen] = React.useState(false);\n\n const handleModalRecoverableToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalRecoverableOpen(!isModalRecoverableOpen);\n };\n\n const handleModalDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalDestructiveOpen(!isModalDestructiveOpen);\n };\n\n const handleModalExtraDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalExtraDestructiveOpen(!isModalExtraDestructiveOpen);\n };\n\n return (\n <>\n \n \n \n \n \n \n \n \n \n \n \n\n handleModalRecoverableToggle(undefined)}\n deleteVariant=\"easily-recoverable\"\n isOpen={isModalRecoverableOpen}\n onClose={handleModalRecoverableToggle}\n >\n The item-name item will be deleted.\n \n handleModalDestructiveToggle(undefined)}\n deleteVariant=\"destructive\"\n isOpen={isModalDestructiveOpen}\n onClose={handleModalDestructiveToggle}\n >\n The item-name item will be deleted. [Brief sentence describing consequence of action].\n \n handleModalExtraDestructiveToggle(undefined)}\n deleteVariant=\"extra-destructive\"\n isOpen={isModalExtraDestructiveOpen}\n onClose={handleModalExtraDestructiveToggle}\n >\n The item-name item will be deleted. [Brief sentence describing consequence of action].\n \n \n );\n};\n","title":"Fullscreen example","lang":"js","isFullscreen":true,"className":""}}> + + , + 'DeleteModal implementation': props => + React.ReactNode;\n /** Text of the delete button */\n deleteButtonText?: string;\n /** Text of the cancel button */\n cancelButtonText?: string;\n /** Callback on clicking the delete button */\n onDelete: () => void;\n /** Flag indicating that deletion is currently in progress */\n isDeleting?: boolean;\n /** Error indicating deletion has failed */\n error?: Error;\n /** Id of the modal for testing purposes (defaults to \"delete-modal\") */\n testId?: string;\n /** Additional props for confirmation text input (only for extra-destructive delete variant) */\n textInputProps?: TextInputProps;\n /** Additional props for error alert */\n errorAlertProps?: AlertProps;\n /** Modal ref */\n ref?: React.RefObject;\n};\n\nexport const DeleteModal: React.FunctionComponent = ({\n children,\n title,\n deleteVariant = 'extra-destructive',\n deleteName,\n confirmationMessage = (deleteName) => (\n <>\n Type {deleteName} to confirm deletion:\n \n ),\n deleteButtonText = 'Delete',\n cancelButtonText = 'Cancel',\n onDelete,\n isDeleting,\n error,\n testId,\n textInputProps,\n errorAlertProps,\n onClose,\n isOpen,\n ...props\n}: DeleteModalProps) => {\n const [confirmationText, setConfirmationText] = React.useState('');\n const confirmed = deleteVariant === 'extra-destructive' ? confirmationText.trim() === deleteName : true;\n\n React.useEffect(() => {\n if (!isOpen) {\n setConfirmationText('');\n }\n }, [isOpen]);\n\n return (\n \n \n \n \n {children}\n {deleteVariant === 'extra-destructive' && (\n \n \n {confirmationMessage(deleteName)}\n setConfirmationText(value)}\n onKeyDown={(event) => {\n if (event.key === 'Enter' && confirmed && !isDeleting) {\n event.preventDefault();\n onDelete();\n }\n }}\n />\n \n \n )}\n {error && (\n \n \n {error.message}\n \n \n )}\n \n \n \n onDelete()}\n >\n {deleteButtonText}\n \n \n \n \n );\n};","title":"DeleteModal implementation","lang":"ts","className":""}}> + + +}; + +const Component = () => ( + +

+ {`Note: this component is an upgrade of an `} + + {`existing DeleteModal`} + + {` in odh-dashboard`} +

+ + {`Basic usage`} + + {React.createElement(pageData.examples["Example"])} + {React.createElement(pageData.examples["Fullscreen example"])} + {React.createElement(pageData.examples["DeleteModal implementation"])} +
+); +Component.displayName = 'ExtensionsDeletemodalReactDocs'; +Component.pageData = pageData; + +export default Component; diff --git a/packages/module/patternfly-docs/generated/index.js b/packages/module/patternfly-docs/generated/index.js index db67d53..3b28f61 100644 --- a/packages/module/patternfly-docs/generated/index.js +++ b/packages/module/patternfly-docs/generated/index.js @@ -1,7 +1,7 @@ module.exports = { - '/extensions/ai-infra-ui-components/react': { - id: "AI-infra-ui-components", - title: "AI-infra-ui-components", + '/extensions/deletemodal/react': { + id: "DeleteModal", + title: "DeleteModal", toc: [{"text":"Basic usage"},[{"text":"Example"},{"text":"Fullscreen example"},{"text":"DeleteModal implementation"}]], examples: ["Example","DeleteModal implementation"], fullscreenExamples: ["Fullscreen example"], @@ -9,16 +9,16 @@ module.exports = { subsection: "", source: "react", tabName: null, - Component: () => import(/* webpackChunkName: "extensions/ai-infra-ui-components/react/index" */ './extensions/ai-infra-ui-components/react') + Component: () => import(/* webpackChunkName: "extensions/deletemodal/react/index" */ './extensions/deletemodal/react') }, - '/extensions/ai-infra-ui-components/design-guidelines': { - id: "AI-infra-ui-components", - title: "AI-infra-ui-components", + '/extensions/deletemodal/design-guidelines': { + id: "DeleteModal", + title: "DeleteModal", toc: [{"text":"Header"},[{"text":"Sub-header"}]], section: "extensions", subsection: "", source: "design-guidelines", tabName: null, - Component: () => import(/* webpackChunkName: "extensions/ai-infra-ui-components/design-guidelines/index" */ './extensions/ai-infra-ui-components/design-guidelines') + Component: () => import(/* webpackChunkName: "extensions/deletemodal/design-guidelines/index" */ './extensions/deletemodal/design-guidelines') } }; \ No newline at end of file From 6754f0b410d8019f02570f0e34641b3b65b01978 Mon Sep 17 00:00:00 2001 From: adamviktora Date: Tue, 8 Oct 2024 16:08:28 +0200 Subject: [PATCH 05/11] fix(DeleteModal): match props of RHOAI DeleteModal exactly --- .../content/examples/Basic.tsx | 32 +++++++------------ .../generated/extensions/deletemodal/react.js | 28 +++++++++------- .../module/src/DeleteModal/DeleteModal.tsx | 23 +++++++------ 3 files changed, 42 insertions(+), 41 deletions(-) diff --git a/packages/module/patternfly-docs/content/examples/Basic.tsx b/packages/module/patternfly-docs/content/examples/Basic.tsx index 2b47c25..d117bf2 100644 --- a/packages/module/patternfly-docs/content/examples/Basic.tsx +++ b/packages/module/patternfly-docs/content/examples/Basic.tsx @@ -7,33 +7,21 @@ export const DeleteModalBasic: React.FunctionComponent = () => { const [isModalDestructiveOpen, setIsModalDestructiveOpen] = React.useState(false); const [isModalExtraDestructiveOpen, setIsModalExtraDestructiveOpen] = React.useState(false); - const handleModalRecoverableToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => { - setIsModalRecoverableOpen(!isModalRecoverableOpen); - }; - - const handleModalDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => { - setIsModalDestructiveOpen(!isModalDestructiveOpen); - }; - - const handleModalExtraDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => { - setIsModalExtraDestructiveOpen(!isModalExtraDestructiveOpen); - }; - return ( <> - - - @@ -42,30 +30,32 @@ export const DeleteModalBasic: React.FunctionComponent = () => { handleModalRecoverableToggle(undefined)} + onDelete={() => {}} deleteVariant="easily-recoverable" isOpen={isModalRecoverableOpen} - onClose={handleModalRecoverableToggle} + onClose={() => setIsModalRecoverableOpen(false)} > The item-name item will be deleted. + handleModalDestructiveToggle(undefined)} + onDelete={() => {}} deleteVariant="destructive" isOpen={isModalDestructiveOpen} - onClose={handleModalDestructiveToggle} + onClose={() => setIsModalDestructiveOpen(false)} > The item-name item will be deleted. [Brief sentence describing consequence of action]. + handleModalExtraDestructiveToggle(undefined)} + onDelete={() => {}} deleteVariant="extra-destructive" isOpen={isModalExtraDestructiveOpen} - onClose={handleModalExtraDestructiveToggle} + onClose={() => setIsModalExtraDestructiveOpen(false)} > The item-name item will be deleted. [Brief sentence describing consequence of action]. diff --git a/packages/module/patternfly-docs/generated/extensions/deletemodal/react.js b/packages/module/patternfly-docs/generated/extensions/deletemodal/react.js index b5469f2..43a0574 100644 --- a/packages/module/patternfly-docs/generated/extensions/deletemodal/react.js +++ b/packages/module/patternfly-docs/generated/extensions/deletemodal/react.js @@ -32,12 +32,6 @@ const pageData = { "description": "Message describing what should the user type in to confirm deletion (only for extra-destructive delete variant)", "defaultValue": "(deleteName) => (\n <>\n Type {deleteName} to confirm deletion:\n \n)" }, - { - "name": "deleteButtonText", - "type": "string", - "description": "Text of the delete button", - "defaultValue": "'Delete'" - }, { "name": "deleteName", "type": "string", @@ -50,6 +44,11 @@ const pageData = { "description": "Delete variant. Destructive and extra-destructive variants will show a warning icon and danger button. For extra-destructive variant, text input confirmation is needed.", "defaultValue": "'extra-destructive'" }, + { + "name": "deleting", + "type": "boolean", + "description": "Flag indicating that deletion is currently in progress" + }, { "name": "error", "type": "Error", @@ -61,9 +60,10 @@ const pageData = { "description": "Additional props for error alert" }, { - "name": "isDeleting", - "type": "boolean", - "description": "Flag indicating that deletion is currently in progress" + "name": "onClose", + "type": "() => void", + "description": "Callback on clicking the close button", + "required": true }, { "name": "onDelete", @@ -76,6 +76,12 @@ const pageData = { "type": "React.RefObject", "description": "Modal ref" }, + { + "name": "submitButtonLabel", + "type": "string", + "description": "Text of the delete button", + "defaultValue": "'Delete'" + }, { "name": "testId", "type": "string", @@ -108,11 +114,11 @@ pageData.liveContext = { }; pageData.examples = { 'Example': props => - {\n const [isModalRecoverableOpen, setIsModalRecoverableOpen] = React.useState(false);\n const [isModalDestructiveOpen, setIsModalDestructiveOpen] = React.useState(false);\n const [isModalExtraDestructiveOpen, setIsModalExtraDestructiveOpen] = React.useState(false);\n\n const handleModalRecoverableToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalRecoverableOpen(!isModalRecoverableOpen);\n };\n\n const handleModalDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalDestructiveOpen(!isModalDestructiveOpen);\n };\n\n const handleModalExtraDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalExtraDestructiveOpen(!isModalExtraDestructiveOpen);\n };\n\n return (\n <>\n \n \n \n \n \n \n \n \n \n \n \n\n handleModalRecoverableToggle(undefined)}\n deleteVariant=\"easily-recoverable\"\n isOpen={isModalRecoverableOpen}\n onClose={handleModalRecoverableToggle}\n >\n The item-name item will be deleted.\n \n handleModalDestructiveToggle(undefined)}\n deleteVariant=\"destructive\"\n isOpen={isModalDestructiveOpen}\n onClose={handleModalDestructiveToggle}\n >\n The item-name item will be deleted. [Brief sentence describing consequence of action].\n \n handleModalExtraDestructiveToggle(undefined)}\n deleteVariant=\"extra-destructive\"\n isOpen={isModalExtraDestructiveOpen}\n onClose={handleModalExtraDestructiveToggle}\n >\n The item-name item will be deleted. [Brief sentence describing consequence of action].\n \n \n );\n};\n","title":"Example","lang":"js","className":""}}> + {\n const [isModalRecoverableOpen, setIsModalRecoverableOpen] = React.useState(false);\n const [isModalDestructiveOpen, setIsModalDestructiveOpen] = React.useState(false);\n const [isModalExtraDestructiveOpen, setIsModalExtraDestructiveOpen] = React.useState(false);\n\n return (\n <>\n \n \n \n \n \n \n \n \n \n \n \n\n {}}\n deleteVariant=\"easily-recoverable\"\n isOpen={isModalRecoverableOpen}\n onClose={() => setIsModalRecoverableOpen(false)}\n >\n The item-name item will be deleted.\n \n\n {}}\n deleteVariant=\"destructive\"\n isOpen={isModalDestructiveOpen}\n onClose={() => setIsModalDestructiveOpen(false)}\n >\n The item-name item will be deleted. [Brief sentence describing consequence of action].\n \n\n {}}\n deleteVariant=\"extra-destructive\"\n isOpen={isModalExtraDestructiveOpen}\n onClose={() => setIsModalExtraDestructiveOpen(false)}\n >\n The item-name item will be deleted. [Brief sentence describing consequence of action].\n \n \n );\n};\n","title":"Example","lang":"js","className":""}}> , 'Fullscreen example': props => - {\n const [isModalRecoverableOpen, setIsModalRecoverableOpen] = React.useState(false);\n const [isModalDestructiveOpen, setIsModalDestructiveOpen] = React.useState(false);\n const [isModalExtraDestructiveOpen, setIsModalExtraDestructiveOpen] = React.useState(false);\n\n const handleModalRecoverableToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalRecoverableOpen(!isModalRecoverableOpen);\n };\n\n const handleModalDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalDestructiveOpen(!isModalDestructiveOpen);\n };\n\n const handleModalExtraDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalExtraDestructiveOpen(!isModalExtraDestructiveOpen);\n };\n\n return (\n <>\n \n \n \n \n \n \n \n \n \n \n \n\n handleModalRecoverableToggle(undefined)}\n deleteVariant=\"easily-recoverable\"\n isOpen={isModalRecoverableOpen}\n onClose={handleModalRecoverableToggle}\n >\n The item-name item will be deleted.\n \n handleModalDestructiveToggle(undefined)}\n deleteVariant=\"destructive\"\n isOpen={isModalDestructiveOpen}\n onClose={handleModalDestructiveToggle}\n >\n The item-name item will be deleted. [Brief sentence describing consequence of action].\n \n handleModalExtraDestructiveToggle(undefined)}\n deleteVariant=\"extra-destructive\"\n isOpen={isModalExtraDestructiveOpen}\n onClose={handleModalExtraDestructiveToggle}\n >\n The item-name item will be deleted. [Brief sentence describing consequence of action].\n \n \n );\n};\n","title":"Fullscreen example","lang":"js","isFullscreen":true,"className":""}}> + {\n const [isModalRecoverableOpen, setIsModalRecoverableOpen] = React.useState(false);\n const [isModalDestructiveOpen, setIsModalDestructiveOpen] = React.useState(false);\n const [isModalExtraDestructiveOpen, setIsModalExtraDestructiveOpen] = React.useState(false);\n\n return (\n <>\n \n \n \n \n \n \n \n \n \n \n \n\n {}}\n deleteVariant=\"easily-recoverable\"\n isOpen={isModalRecoverableOpen}\n onClose={() => setIsModalRecoverableOpen(false)}\n >\n The item-name item will be deleted.\n \n\n {}}\n deleteVariant=\"destructive\"\n isOpen={isModalDestructiveOpen}\n onClose={() => setIsModalDestructiveOpen(false)}\n >\n The item-name item will be deleted. [Brief sentence describing consequence of action].\n \n\n {}}\n deleteVariant=\"extra-destructive\"\n isOpen={isModalExtraDestructiveOpen}\n onClose={() => setIsModalExtraDestructiveOpen(false)}\n >\n The item-name item will be deleted. [Brief sentence describing consequence of action].\n \n \n );\n};\n","title":"Fullscreen example","lang":"js","isFullscreen":true,"className":""}}> , 'DeleteModal implementation': props => diff --git a/packages/module/src/DeleteModal/DeleteModal.tsx b/packages/module/src/DeleteModal/DeleteModal.tsx index aa15d28..4fa856a 100644 --- a/packages/module/src/DeleteModal/DeleteModal.tsx +++ b/packages/module/src/DeleteModal/DeleteModal.tsx @@ -16,7 +16,7 @@ import { TextInputProps } from '@patternfly/react-core'; -export type DeleteModalProps = ModalProps & { +export type DeleteModalProps = Omit & { /** Content rendered inside the modal header title. */ title: React.ReactNode; /** Delete variant. Destructive and extra-destructive variants will show a warning icon and danger button. For extra-destructive variant, text input confirmation is needed. */ @@ -26,13 +26,15 @@ export type DeleteModalProps = ModalProps & { /** Message describing what should the user type in to confirm deletion (only for extra-destructive delete variant) */ confirmationMessage?: (deleteName: string) => React.ReactNode; /** Text of the delete button */ - deleteButtonText?: string; + submitButtonLabel?: string; /** Text of the cancel button */ cancelButtonText?: string; /** Callback on clicking the delete button */ onDelete: () => void; + /** Callback on clicking the close button */ + onClose: () => void; /** Flag indicating that deletion is currently in progress */ - isDeleting?: boolean; + deleting?: boolean; /** Error indicating deletion has failed */ error?: Error; /** Id of the modal for testing purposes (defaults to "delete-modal") */ @@ -55,10 +57,10 @@ export const DeleteModal: React.FunctionComponent = ({ Type {deleteName} to confirm deletion: ), - deleteButtonText = 'Delete', + submitButtonLabel: deleteButtonText = 'Delete', cancelButtonText = 'Cancel', onDelete, - isDeleting, + deleting: isDeleting, error, testId, textInputProps, @@ -68,7 +70,10 @@ export const DeleteModal: React.FunctionComponent = ({ ...props }: DeleteModalProps) => { const [inputValue, setInputValue] = React.useState(''); - const confirmed = deleteVariant === 'extra-destructive' ? inputValue.trim() === deleteName : true; + + const deleteNameSanitized = React.useMemo(() => deleteName.trim().replace(/\s+/g, ' '), [deleteName]); + + const confirmed = deleteVariant === 'extra-destructive' ? inputValue.trim() === deleteNameSanitized : true; React.useEffect(() => { if (!isOpen) { @@ -85,7 +90,7 @@ export const DeleteModal: React.FunctionComponent = ({ {deleteVariant === 'extra-destructive' && ( - {confirmationMessage(deleteName)} + {confirmationMessage(deleteNameSanitized)} = ({ {error && ( From 139b6a113ce424021449d79fbec15e595ebcdf1b Mon Sep 17 00:00:00 2001 From: adamviktora Date: Tue, 8 Oct 2024 16:28:28 +0200 Subject: [PATCH 06/11] fix(DeleteModal): don't use isOpen, conditionally render instead --- .../{Basic.tsx => DeleteModalBasic.tsx} | 63 ++++---- .../patternfly-docs/content/examples/basic.md | 146 +----------------- .../generated/extensions/deletemodal/react.js | 12 +- .../module/patternfly-docs/generated/index.js | 4 +- .../module/src/DeleteModal/DeleteModal.tsx | 11 +- 5 files changed, 43 insertions(+), 193 deletions(-) rename packages/module/patternfly-docs/content/examples/{Basic.tsx => DeleteModalBasic.tsx} (50%) diff --git a/packages/module/patternfly-docs/content/examples/Basic.tsx b/packages/module/patternfly-docs/content/examples/DeleteModalBasic.tsx similarity index 50% rename from packages/module/patternfly-docs/content/examples/Basic.tsx rename to packages/module/patternfly-docs/content/examples/DeleteModalBasic.tsx index d117bf2..b8813dc 100644 --- a/packages/module/patternfly-docs/content/examples/Basic.tsx +++ b/packages/module/patternfly-docs/content/examples/DeleteModalBasic.tsx @@ -27,38 +27,41 @@ export const DeleteModalBasic: React.FunctionComponent = () => { - {}} - deleteVariant="easily-recoverable" - isOpen={isModalRecoverableOpen} - onClose={() => setIsModalRecoverableOpen(false)} - > - The item-name item will be deleted. - + {isModalRecoverableOpen && ( + {}} + deleteVariant="easily-recoverable" + onClose={() => setIsModalRecoverableOpen(false)} + > + The item-name item will be deleted. + + )} - {}} - deleteVariant="destructive" - isOpen={isModalDestructiveOpen} - onClose={() => setIsModalDestructiveOpen(false)} - > - The item-name item will be deleted. [Brief sentence describing consequence of action]. - + {isModalDestructiveOpen && ( + {}} + deleteVariant="destructive" + onClose={() => setIsModalDestructiveOpen(false)} + > + The item-name item will be deleted. [Brief sentence describing consequence of action]. + + )} - {}} - deleteVariant="extra-destructive" - isOpen={isModalExtraDestructiveOpen} - onClose={() => setIsModalExtraDestructiveOpen(false)} - > - The item-name item will be deleted. [Brief sentence describing consequence of action]. - + {isModalExtraDestructiveOpen && ( + {}} + deleteVariant="extra-destructive" + onClose={() => setIsModalExtraDestructiveOpen(false)} + > + The item-name item will be deleted. [Brief sentence describing consequence of action]. + + )} ); }; diff --git a/packages/module/patternfly-docs/content/examples/basic.md b/packages/module/patternfly-docs/content/examples/basic.md index c47664f..47959df 100644 --- a/packages/module/patternfly-docs/content/examples/basic.md +++ b/packages/module/patternfly-docs/content/examples/basic.md @@ -14,158 +14,18 @@ propComponents: ['DeleteModal'] import { DeleteModal } from "@patternfly/ai-infra-ui-components"; -Note: this component is an upgrade of an [existing DeleteModal](https://github.com/opendatahub-io/odh-dashboard/blob/main/frontend/src/pages/projects/components/DeleteModal.tsx) in odh-dashboard +Note: this component is an upgrade of an [existing DeleteModal](https://github.com/opendatahub-io/odh-dashboard/blob/main/frontend/src/pages/projects/components/DeleteModal.tsx) in odh-dashboard ## Basic usage ### Example -```js file="./Basic.tsx" +```js file="./DeleteModalBasic.tsx" ``` ### Fullscreen example -```js file="./Basic.tsx" isFullscreen - -``` - -### DeleteModal implementation - -```ts -import React from 'react'; -import { - Alert, - AlertProps, - Button, - Flex, - FlexItem, - Modal, - ModalBody, - ModalFooter, - ModalHeader, - ModalProps, - Stack, - StackItem, - TextInput, - TextInputProps -} from '@patternfly/react-core'; - -export type DeleteModalProps = ModalProps & { - /** Content rendered inside the modal header title. */ - title: React.ReactNode; - /** Delete variant. Destructive and extra-destructive variants will show a warning icon and danger button. For extra-destructive variant, text input confirmation is needed. */ - deleteVariant?: 'extra-destructive' | 'destructive' | 'easily-recoverable'; - /** Text which the user should type in to confirm deletion (only for extra-destructive delete variant) */ - deleteName: string; - /** Message describing what should the user type in to confirm deletion (only for extra-destructive delete variant) */ - confirmationMessage?: (deleteName: string) => React.ReactNode; - /** Text of the delete button */ - deleteButtonText?: string; - /** Text of the cancel button */ - cancelButtonText?: string; - /** Callback on clicking the delete button */ - onDelete: () => void; - /** Flag indicating that deletion is currently in progress */ - isDeleting?: boolean; - /** Error indicating deletion has failed */ - error?: Error; - /** Id of the modal for testing purposes (defaults to "delete-modal") */ - testId?: string; - /** Additional props for confirmation text input (only for extra-destructive delete variant) */ - textInputProps?: TextInputProps; - /** Additional props for error alert */ - errorAlertProps?: AlertProps; - /** Modal ref */ - ref?: React.RefObject; -}; - -export const DeleteModal: React.FunctionComponent = ({ - children, - title, - deleteVariant = 'extra-destructive', - deleteName, - confirmationMessage = (deleteName) => ( - <> - Type {deleteName} to confirm deletion: - - ), - deleteButtonText = 'Delete', - cancelButtonText = 'Cancel', - onDelete, - isDeleting, - error, - testId, - textInputProps, - errorAlertProps, - onClose, - isOpen, - ...props -}: DeleteModalProps) => { - const [confirmationText, setConfirmationText] = React.useState(''); - const confirmed = deleteVariant === 'extra-destructive' ? confirmationText.trim() === deleteName : true; - - React.useEffect(() => { - if (!isOpen) { - setConfirmationText(''); - } - }, [isOpen]); - - return ( - - - - - {children} - {deleteVariant === 'extra-destructive' && ( - - - {confirmationMessage(deleteName)} - setConfirmationText(value)} - onKeyDown={(event) => { - if (event.key === 'Enter' && confirmed && !isDeleting) { - event.preventDefault(); - onDelete(); - } - }} - /> - - - )} - {error && ( - - - {error.message} - - - )} - - - - - - - - ); -}; +```js file="./DeleteModalBasic.tsx" isFullscreen ``` diff --git a/packages/module/patternfly-docs/generated/extensions/deletemodal/react.js b/packages/module/patternfly-docs/generated/extensions/deletemodal/react.js index 43a0574..bcb0e65 100644 --- a/packages/module/patternfly-docs/generated/extensions/deletemodal/react.js +++ b/packages/module/patternfly-docs/generated/extensions/deletemodal/react.js @@ -102,8 +102,7 @@ const pageData = { } ], "examples": [ - "Example", - "DeleteModal implementation" + "Example" ], "fullscreenExamples": [ "Fullscreen example" @@ -114,15 +113,11 @@ pageData.liveContext = { }; pageData.examples = { 'Example': props => - {\n const [isModalRecoverableOpen, setIsModalRecoverableOpen] = React.useState(false);\n const [isModalDestructiveOpen, setIsModalDestructiveOpen] = React.useState(false);\n const [isModalExtraDestructiveOpen, setIsModalExtraDestructiveOpen] = React.useState(false);\n\n return (\n <>\n \n \n \n \n \n \n \n \n \n \n \n\n {}}\n deleteVariant=\"easily-recoverable\"\n isOpen={isModalRecoverableOpen}\n onClose={() => setIsModalRecoverableOpen(false)}\n >\n The item-name item will be deleted.\n \n\n {}}\n deleteVariant=\"destructive\"\n isOpen={isModalDestructiveOpen}\n onClose={() => setIsModalDestructiveOpen(false)}\n >\n The item-name item will be deleted. [Brief sentence describing consequence of action].\n \n\n {}}\n deleteVariant=\"extra-destructive\"\n isOpen={isModalExtraDestructiveOpen}\n onClose={() => setIsModalExtraDestructiveOpen(false)}\n >\n The item-name item will be deleted. [Brief sentence describing consequence of action].\n \n \n );\n};\n","title":"Example","lang":"js","className":""}}> + {\n const [isModalRecoverableOpen, setIsModalRecoverableOpen] = React.useState(false);\n const [isModalDestructiveOpen, setIsModalDestructiveOpen] = React.useState(false);\n const [isModalExtraDestructiveOpen, setIsModalExtraDestructiveOpen] = React.useState(false);\n\n return (\n <>\n \n \n \n \n \n \n \n \n \n \n \n\n {isModalRecoverableOpen && (\n {}}\n deleteVariant=\"easily-recoverable\"\n onClose={() => setIsModalRecoverableOpen(false)}\n >\n The item-name item will be deleted.\n \n )}\n\n {isModalDestructiveOpen && (\n {}}\n deleteVariant=\"destructive\"\n onClose={() => setIsModalDestructiveOpen(false)}\n >\n The item-name item will be deleted. [Brief sentence describing consequence of action].\n \n )}\n\n {isModalExtraDestructiveOpen && (\n {}}\n deleteVariant=\"extra-destructive\"\n onClose={() => setIsModalExtraDestructiveOpen(false)}\n >\n The item-name item will be deleted. [Brief sentence describing consequence of action].\n \n )}\n \n );\n};\n","title":"Example","lang":"js","className":""}}> , 'Fullscreen example': props => - {\n const [isModalRecoverableOpen, setIsModalRecoverableOpen] = React.useState(false);\n const [isModalDestructiveOpen, setIsModalDestructiveOpen] = React.useState(false);\n const [isModalExtraDestructiveOpen, setIsModalExtraDestructiveOpen] = React.useState(false);\n\n return (\n <>\n \n \n \n \n \n \n \n \n \n \n \n\n {}}\n deleteVariant=\"easily-recoverable\"\n isOpen={isModalRecoverableOpen}\n onClose={() => setIsModalRecoverableOpen(false)}\n >\n The item-name item will be deleted.\n \n\n {}}\n deleteVariant=\"destructive\"\n isOpen={isModalDestructiveOpen}\n onClose={() => setIsModalDestructiveOpen(false)}\n >\n The item-name item will be deleted. [Brief sentence describing consequence of action].\n \n\n {}}\n deleteVariant=\"extra-destructive\"\n isOpen={isModalExtraDestructiveOpen}\n onClose={() => setIsModalExtraDestructiveOpen(false)}\n >\n The item-name item will be deleted. [Brief sentence describing consequence of action].\n \n \n );\n};\n","title":"Fullscreen example","lang":"js","isFullscreen":true,"className":""}}> - - , - 'DeleteModal implementation': props => - React.ReactNode;\n /** Text of the delete button */\n deleteButtonText?: string;\n /** Text of the cancel button */\n cancelButtonText?: string;\n /** Callback on clicking the delete button */\n onDelete: () => void;\n /** Flag indicating that deletion is currently in progress */\n isDeleting?: boolean;\n /** Error indicating deletion has failed */\n error?: Error;\n /** Id of the modal for testing purposes (defaults to \"delete-modal\") */\n testId?: string;\n /** Additional props for confirmation text input (only for extra-destructive delete variant) */\n textInputProps?: TextInputProps;\n /** Additional props for error alert */\n errorAlertProps?: AlertProps;\n /** Modal ref */\n ref?: React.RefObject;\n};\n\nexport const DeleteModal: React.FunctionComponent = ({\n children,\n title,\n deleteVariant = 'extra-destructive',\n deleteName,\n confirmationMessage = (deleteName) => (\n <>\n Type {deleteName} to confirm deletion:\n \n ),\n deleteButtonText = 'Delete',\n cancelButtonText = 'Cancel',\n onDelete,\n isDeleting,\n error,\n testId,\n textInputProps,\n errorAlertProps,\n onClose,\n isOpen,\n ...props\n}: DeleteModalProps) => {\n const [confirmationText, setConfirmationText] = React.useState('');\n const confirmed = deleteVariant === 'extra-destructive' ? confirmationText.trim() === deleteName : true;\n\n React.useEffect(() => {\n if (!isOpen) {\n setConfirmationText('');\n }\n }, [isOpen]);\n\n return (\n \n \n \n \n {children}\n {deleteVariant === 'extra-destructive' && (\n \n \n {confirmationMessage(deleteName)}\n setConfirmationText(value)}\n onKeyDown={(event) => {\n if (event.key === 'Enter' && confirmed && !isDeleting) {\n event.preventDefault();\n onDelete();\n }\n }}\n />\n \n \n )}\n {error && (\n \n \n {error.message}\n \n \n )}\n \n \n \n onDelete()}\n >\n {deleteButtonText}\n \n \n \n \n );\n};","title":"DeleteModal implementation","lang":"ts","className":""}}> + {\n const [isModalRecoverableOpen, setIsModalRecoverableOpen] = React.useState(false);\n const [isModalDestructiveOpen, setIsModalDestructiveOpen] = React.useState(false);\n const [isModalExtraDestructiveOpen, setIsModalExtraDestructiveOpen] = React.useState(false);\n\n return (\n <>\n \n \n \n \n \n \n \n \n \n \n \n\n {isModalRecoverableOpen && (\n {}}\n deleteVariant=\"easily-recoverable\"\n onClose={() => setIsModalRecoverableOpen(false)}\n >\n The item-name item will be deleted.\n \n )}\n\n {isModalDestructiveOpen && (\n {}}\n deleteVariant=\"destructive\"\n onClose={() => setIsModalDestructiveOpen(false)}\n >\n The item-name item will be deleted. [Brief sentence describing consequence of action].\n \n )}\n\n {isModalExtraDestructiveOpen && (\n {}}\n deleteVariant=\"extra-destructive\"\n onClose={() => setIsModalExtraDestructiveOpen(false)}\n >\n The item-name item will be deleted. [Brief sentence describing consequence of action].\n \n )}\n \n );\n};\n","title":"Fullscreen example","lang":"js","isFullscreen":true,"className":""}}> }; @@ -141,7 +136,6 @@ const Component = () => ( {React.createElement(pageData.examples["Example"])} {React.createElement(pageData.examples["Fullscreen example"])} - {React.createElement(pageData.examples["DeleteModal implementation"])} ); Component.displayName = 'ExtensionsDeletemodalReactDocs'; diff --git a/packages/module/patternfly-docs/generated/index.js b/packages/module/patternfly-docs/generated/index.js index 3b28f61..ed12c2c 100644 --- a/packages/module/patternfly-docs/generated/index.js +++ b/packages/module/patternfly-docs/generated/index.js @@ -2,8 +2,8 @@ module.exports = { '/extensions/deletemodal/react': { id: "DeleteModal", title: "DeleteModal", - toc: [{"text":"Basic usage"},[{"text":"Example"},{"text":"Fullscreen example"},{"text":"DeleteModal implementation"}]], - examples: ["Example","DeleteModal implementation"], + toc: [{"text":"Basic usage"},[{"text":"Example"},{"text":"Fullscreen example"}]], + examples: ["Example"], fullscreenExamples: ["Fullscreen example"], section: "extensions", subsection: "", diff --git a/packages/module/src/DeleteModal/DeleteModal.tsx b/packages/module/src/DeleteModal/DeleteModal.tsx index 4fa856a..f452b3a 100644 --- a/packages/module/src/DeleteModal/DeleteModal.tsx +++ b/packages/module/src/DeleteModal/DeleteModal.tsx @@ -16,7 +16,7 @@ import { TextInputProps } from '@patternfly/react-core'; -export type DeleteModalProps = Omit & { +export type DeleteModalProps = Omit & { /** Content rendered inside the modal header title. */ title: React.ReactNode; /** Delete variant. Destructive and extra-destructive variants will show a warning icon and danger button. For extra-destructive variant, text input confirmation is needed. */ @@ -66,7 +66,6 @@ export const DeleteModal: React.FunctionComponent = ({ textInputProps, errorAlertProps, onClose, - isOpen, ...props }: DeleteModalProps) => { const [inputValue, setInputValue] = React.useState(''); @@ -75,14 +74,8 @@ export const DeleteModal: React.FunctionComponent = ({ const confirmed = deleteVariant === 'extra-destructive' ? inputValue.trim() === deleteNameSanitized : true; - React.useEffect(() => { - if (!isOpen) { - setInputValue(''); - } - }, [isOpen]); - return ( - + From 5abda37f17b1e433fe6891c3ceb355f460a5824f Mon Sep 17 00:00:00 2001 From: adamviktora Date: Tue, 8 Oct 2024 16:38:08 +0200 Subject: [PATCH 07/11] remove generated docs --- .gitignore | 1 + .../deletemodal/design-guidelines.js | 56 ------- .../deletemodal/react.js | 144 ----------------- .../generated/design-guidelines.js | 51 ------ .../design-guidelines.js | 56 ------- .../ai-infra-ui-components/react.js | 150 ------------------ .../deletemodal/design-guidelines.js | 56 ------- .../generated/extensions/deletemodal/react.js | 144 ----------------- .../module/patternfly-docs/generated/index.js | 24 --- .../module/patternfly-docs/generated/react.js | 59 ------- 10 files changed, 1 insertion(+), 740 deletions(-) delete mode 100644 packages/module/patternfly-docs/generated/ai-infra-ui-components/deletemodal/design-guidelines.js delete mode 100644 packages/module/patternfly-docs/generated/ai-infra-ui-components/deletemodal/react.js delete mode 100644 packages/module/patternfly-docs/generated/design-guidelines.js delete mode 100644 packages/module/patternfly-docs/generated/extensions/ai-infra-ui-components/design-guidelines.js delete mode 100644 packages/module/patternfly-docs/generated/extensions/ai-infra-ui-components/react.js delete mode 100644 packages/module/patternfly-docs/generated/extensions/deletemodal/design-guidelines.js delete mode 100644 packages/module/patternfly-docs/generated/extensions/deletemodal/react.js delete mode 100644 packages/module/patternfly-docs/generated/index.js delete mode 100644 packages/module/patternfly-docs/generated/react.js diff --git a/.gitignore b/.gitignore index e61a201..a628326 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ coverage .cache .tmp .eslintcache +generated # package managers yarn-error.log diff --git a/packages/module/patternfly-docs/generated/ai-infra-ui-components/deletemodal/design-guidelines.js b/packages/module/patternfly-docs/generated/ai-infra-ui-components/deletemodal/design-guidelines.js deleted file mode 100644 index b0244c9..0000000 --- a/packages/module/patternfly-docs/generated/ai-infra-ui-components/deletemodal/design-guidelines.js +++ /dev/null @@ -1,56 +0,0 @@ -import React from 'react'; -import { AutoLinkHeader, Example, Link as PatternflyThemeLink } from '@patternfly/documentation-framework/components'; - -const pageData = { - "id": "DeleteModal", - "section": "AI-infra-ui-components", - "subsection": "", - "deprecated": false, - "template": false, - "beta": false, - "demo": false, - "newImplementationLink": false, - "source": "design-guidelines", - "tabName": null, - "slug": "/ai-infra-ui-components/deletemodal/design-guidelines", - "sourceLink": "https://github.com/patternfly/patternfly-org/blob/main/packages/module/patternfly-docs/content/design-guidelines/design-guidelines.md", - "relPath": "packages/module/patternfly-docs/content/design-guidelines/design-guidelines.md" -}; -pageData.examples = { - -}; - -const Component = () => ( - -

- {`Design guidelines intro`} -

- - {`Header`} - - - {`Sub-header`} - -

- {`Guidelines:`} -

-
    -
  1. - {`A`} -
  2. -
  3. - {`list`} -
  4. -
  5. - {`using`} -
  6. -
  7. - {`markdown`} -
  8. -
-
-); -Component.displayName = 'AiInfraUiComponentsDeletemodalDesignGuidelinesDocs'; -Component.pageData = pageData; - -export default Component; diff --git a/packages/module/patternfly-docs/generated/ai-infra-ui-components/deletemodal/react.js b/packages/module/patternfly-docs/generated/ai-infra-ui-components/deletemodal/react.js deleted file mode 100644 index ef0bdc8..0000000 --- a/packages/module/patternfly-docs/generated/ai-infra-ui-components/deletemodal/react.js +++ /dev/null @@ -1,144 +0,0 @@ -import React from 'react'; -import { AutoLinkHeader, Example, Link as PatternflyThemeLink } from '@patternfly/documentation-framework/components'; -import { DeleteModal } from "@patternfly/ai-infra-ui-components"; -const pageData = { - "id": "DeleteModal", - "section": "AI-infra-ui-components", - "subsection": "", - "deprecated": false, - "template": false, - "beta": false, - "demo": false, - "newImplementationLink": false, - "source": "react", - "tabName": null, - "slug": "/ai-infra-ui-components/deletemodal/react", - "sourceLink": "https://github.com/patternfly/patternfly-react/blob/main/packages/module/patternfly-docs/content/examples/basic.md", - "relPath": "packages/module/patternfly-docs/content/examples/basic.md", - "propComponents": [ - { - "name": "DeleteModal", - "description": "", - "props": [ - { - "name": "cancelButtonText", - "type": "string", - "description": "Text of the cancel button", - "defaultValue": "'Cancel'" - }, - { - "name": "confirmationMessage", - "type": "(deleteName: string) => React.ReactNode", - "description": "Message describing what should the user type in to confirm deletion (only for extra-destructive delete variant)", - "defaultValue": "(deleteName) => (\n <>\n Type {deleteName} to confirm deletion:\n \n)" - }, - { - "name": "deleteButtonText", - "type": "string", - "description": "Text of the delete button", - "defaultValue": "'Delete'" - }, - { - "name": "deleteName", - "type": "string", - "description": "Text which the user should type in to confirm deletion (only for extra-destructive delete variant)", - "required": true - }, - { - "name": "deleteVariant", - "type": "'extra-destructive' | 'destructive' | 'easily-recoverable'", - "description": "Delete variant. Destructive and extra-destructive variants will show a warning icon and danger button. For extra-destructive variant, text input confirmation is needed.", - "defaultValue": "'extra-destructive'" - }, - { - "name": "error", - "type": "Error", - "description": "Error indicating deletion has failed" - }, - { - "name": "errorAlertProps", - "type": "AlertProps", - "description": "Additional props for error alert" - }, - { - "name": "isDeleting", - "type": "boolean", - "description": "Flag indicating that deletion is currently in progress" - }, - { - "name": "onDelete", - "type": "() => void", - "description": "Callback on clicking the delete button", - "required": true - }, - { - "name": "ref", - "type": "React.RefObject", - "description": "Modal ref" - }, - { - "name": "testId", - "type": "string", - "description": "Id of the modal for testing purposes (defaults to \"delete-modal\")" - }, - { - "name": "textInputProps", - "type": "TextInputProps", - "description": "Additional props for confirmation text input (only for extra-destructive delete variant)" - }, - { - "name": "title", - "type": "React.ReactNode", - "description": "Content rendered inside the modal header title.", - "required": true - } - ] - } - ], - "examples": [ - "Example", - "DeleteModal implementation" - ], - "fullscreenExamples": [ - "Fullscreen example" - ] -}; -pageData.liveContext = { - DeleteModal -}; -pageData.examples = { - 'Example': props => - {\n const [isModalRecoverableOpen, setIsModalRecoverableOpen] = React.useState(false);\n const [isModalDestructiveOpen, setIsModalDestructiveOpen] = React.useState(false);\n const [isModalExtraDestructiveOpen, setIsModalExtraDestructiveOpen] = React.useState(false);\n\n const handleModalRecoverableToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalRecoverableOpen(!isModalRecoverableOpen);\n };\n\n const handleModalDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalDestructiveOpen(!isModalDestructiveOpen);\n };\n\n const handleModalExtraDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalExtraDestructiveOpen(!isModalExtraDestructiveOpen);\n };\n\n return (\n <>\n \n \n \n \n \n \n \n \n \n \n \n\n handleModalRecoverableToggle(undefined)}\n deleteVariant=\"easily-recoverable\"\n isOpen={isModalRecoverableOpen}\n onClose={handleModalRecoverableToggle}\n >\n The item-name item will be deleted.\n \n handleModalDestructiveToggle(undefined)}\n deleteVariant=\"destructive\"\n isOpen={isModalDestructiveOpen}\n onClose={handleModalDestructiveToggle}\n >\n The item-name item will be deleted. [Brief sentence describing consequence of action].\n \n handleModalExtraDestructiveToggle(undefined)}\n deleteVariant=\"extra-destructive\"\n isOpen={isModalExtraDestructiveOpen}\n onClose={handleModalExtraDestructiveToggle}\n >\n The item-name item will be deleted. [Brief sentence describing consequence of action].\n \n \n );\n};\n","title":"Example","lang":"js","className":""}}> - - , - 'Fullscreen example': props => - {\n const [isModalRecoverableOpen, setIsModalRecoverableOpen] = React.useState(false);\n const [isModalDestructiveOpen, setIsModalDestructiveOpen] = React.useState(false);\n const [isModalExtraDestructiveOpen, setIsModalExtraDestructiveOpen] = React.useState(false);\n\n const handleModalRecoverableToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalRecoverableOpen(!isModalRecoverableOpen);\n };\n\n const handleModalDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalDestructiveOpen(!isModalDestructiveOpen);\n };\n\n const handleModalExtraDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalExtraDestructiveOpen(!isModalExtraDestructiveOpen);\n };\n\n return (\n <>\n \n \n \n \n \n \n \n \n \n \n \n\n handleModalRecoverableToggle(undefined)}\n deleteVariant=\"easily-recoverable\"\n isOpen={isModalRecoverableOpen}\n onClose={handleModalRecoverableToggle}\n >\n The item-name item will be deleted.\n \n handleModalDestructiveToggle(undefined)}\n deleteVariant=\"destructive\"\n isOpen={isModalDestructiveOpen}\n onClose={handleModalDestructiveToggle}\n >\n The item-name item will be deleted. [Brief sentence describing consequence of action].\n \n handleModalExtraDestructiveToggle(undefined)}\n deleteVariant=\"extra-destructive\"\n isOpen={isModalExtraDestructiveOpen}\n onClose={handleModalExtraDestructiveToggle}\n >\n The item-name item will be deleted. [Brief sentence describing consequence of action].\n \n \n );\n};\n","title":"Fullscreen example","lang":"js","isFullscreen":true,"className":""}}> - - , - 'DeleteModal implementation': props => - React.ReactNode;\n /** Text of the delete button */\n deleteButtonText?: string;\n /** Text of the cancel button */\n cancelButtonText?: string;\n /** Callback on clicking the delete button */\n onDelete: () => void;\n /** Flag indicating that deletion is currently in progress */\n isDeleting?: boolean;\n /** Error indicating deletion has failed */\n error?: Error;\n /** Id of the modal for testing purposes (defaults to \"delete-modal\") */\n testId?: string;\n /** Additional props for confirmation text input (only for extra-destructive delete variant) */\n textInputProps?: TextInputProps;\n /** Additional props for error alert */\n errorAlertProps?: AlertProps;\n /** Modal ref */\n ref?: React.RefObject;\n};\n\nexport const DeleteModal: React.FunctionComponent = ({\n children,\n title,\n deleteVariant = 'extra-destructive',\n deleteName,\n confirmationMessage = (deleteName) => (\n <>\n Type {deleteName} to confirm deletion:\n \n ),\n deleteButtonText = 'Delete',\n cancelButtonText = 'Cancel',\n onDelete,\n isDeleting,\n error,\n testId,\n textInputProps,\n errorAlertProps,\n onClose,\n isOpen,\n ...props\n}: DeleteModalProps) => {\n const [confirmationText, setConfirmationText] = React.useState('');\n const confirmed = deleteVariant === 'extra-destructive' ? confirmationText.trim() === deleteName : true;\n\n React.useEffect(() => {\n if (!isOpen) {\n setConfirmationText('');\n }\n }, [isOpen]);\n\n return (\n \n \n \n \n {children}\n {deleteVariant === 'extra-destructive' && (\n \n \n {confirmationMessage(deleteName)}\n setConfirmationText(value)}\n onKeyDown={(event) => {\n if (event.key === 'Enter' && confirmed && !isDeleting) {\n event.preventDefault();\n onDelete();\n }\n }}\n />\n \n \n )}\n {error && (\n \n \n {error.message}\n \n \n )}\n \n \n \n onDelete()}\n >\n {deleteButtonText}\n \n \n \n \n );\n};","title":"DeleteModal implementation","lang":"ts","className":""}}> - - -}; - -const Component = () => ( - -

- {`Note: this component is an upgrade of an `} - - {`existing DeleteModal`} - - {` in odh-dashboard`} -

- - {`Basic usage`} - - {React.createElement(pageData.examples["Example"])} - {React.createElement(pageData.examples["Fullscreen example"])} - {React.createElement(pageData.examples["DeleteModal implementation"])} -
-); -Component.displayName = 'AiInfraUiComponentsDeletemodalReactDocs'; -Component.pageData = pageData; - -export default Component; diff --git a/packages/module/patternfly-docs/generated/design-guidelines.js b/packages/module/patternfly-docs/generated/design-guidelines.js deleted file mode 100644 index 318789f..0000000 --- a/packages/module/patternfly-docs/generated/design-guidelines.js +++ /dev/null @@ -1,51 +0,0 @@ -import React from 'react'; -import { AutoLinkHeader, Example, Link as PatternflyThemeLink } from '@patternfly/documentation-framework/components'; - -const pageData = { - "id": "AI-infra-ui-components", - "section": "extensions", - "source": "design-guidelines", - "slug": "/extensions/ai-infra-ui-components/design-guidelines", - "sourceLink": "https://github.com/patternfly/patternfly-org/blob/main/packages/module/patternfly-docs/content/extensions/ai-infra-ui-components/design-guidelines/design-guidelines.md" -}; -pageData.relativeImports = { - -}; -pageData.examples = { - -}; - -const Component = () => ( - -

- {`Design guidelines intro`} -

- - {`Header`} - - - {`Sub-header`} - -

- {`Guidelines:`} -

-
    -
  1. - {`A`} -
  2. -
  3. - {`list`} -
  4. -
  5. - {`using`} -
  6. -
  7. - {`markdown`} -
  8. -
-
-); -Component.displayName = 'ExtensionsPatternflyExtensionSeedDesignGuidelinesDocs'; -Component.pageData = pageData; - -export default Component; diff --git a/packages/module/patternfly-docs/generated/extensions/ai-infra-ui-components/design-guidelines.js b/packages/module/patternfly-docs/generated/extensions/ai-infra-ui-components/design-guidelines.js deleted file mode 100644 index f9946d4..0000000 --- a/packages/module/patternfly-docs/generated/extensions/ai-infra-ui-components/design-guidelines.js +++ /dev/null @@ -1,56 +0,0 @@ -import React from 'react'; -import { AutoLinkHeader, Example, Link as PatternflyThemeLink } from '@patternfly/documentation-framework/components'; - -const pageData = { - "id": "AI-infra-ui-components", - "section": "extensions", - "subsection": "", - "deprecated": false, - "template": false, - "beta": false, - "demo": false, - "newImplementationLink": false, - "source": "design-guidelines", - "tabName": null, - "slug": "/extensions/ai-infra-ui-components/design-guidelines", - "sourceLink": "https://github.com/patternfly/patternfly-org/blob/main/packages/module/patternfly-docs/content/design-guidelines/design-guidelines.md", - "relPath": "packages/module/patternfly-docs/content/design-guidelines/design-guidelines.md" -}; -pageData.examples = { - -}; - -const Component = () => ( - -

- {`Design guidelines intro`} -

- - {`Header`} - - - {`Sub-header`} - -

- {`Guidelines:`} -

-
    -
  1. - {`A`} -
  2. -
  3. - {`list`} -
  4. -
  5. - {`using`} -
  6. -
  7. - {`markdown`} -
  8. -
-
-); -Component.displayName = 'ExtensionsAiInfraUiComponentsDesignGuidelinesDocs'; -Component.pageData = pageData; - -export default Component; diff --git a/packages/module/patternfly-docs/generated/extensions/ai-infra-ui-components/react.js b/packages/module/patternfly-docs/generated/extensions/ai-infra-ui-components/react.js deleted file mode 100644 index 11d4e4d..0000000 --- a/packages/module/patternfly-docs/generated/extensions/ai-infra-ui-components/react.js +++ /dev/null @@ -1,150 +0,0 @@ -import React from 'react'; -import { AutoLinkHeader, Example, Link as PatternflyThemeLink } from '@patternfly/documentation-framework/components'; -import { ExtendedButton } from "@patternfly/ai-infra-ui-components"; -import { DeleteModal } from "@patternfly/ai-infra-ui-components"; -const pageData = { - "id": "AI-infra-ui-components", - "section": "extensions", - "subsection": "", - "deprecated": false, - "template": false, - "beta": false, - "demo": false, - "newImplementationLink": false, - "source": "react", - "tabName": null, - "slug": "/extensions/ai-infra-ui-components/react", - "sourceLink": "https://github.com/patternfly/patternfly-react/blob/main/packages/module/patternfly-docs/content/examples/basic.md", - "relPath": "packages/module/patternfly-docs/content/examples/basic.md", - "propComponents": [ - { - "name": "ExtendedButton", - "description": "", - "props": [ - { - "name": "children", - "type": "React.ReactNode", - "description": "Content to render inside the extended button component" - } - ] - }, - { - "name": "DeleteModal", - "description": "", - "props": [ - { - "name": "cancelButtonText", - "type": "string", - "description": "Text of the cancel button", - "defaultValue": "'Cancel'" - }, - { - "name": "confirmationMessage", - "type": "(deleteName: string) => React.ReactNode", - "description": "Message describing what should the user type in to confirm deletion (only for extra-destructive delete variant)", - "defaultValue": "(deleteName) => (\n <>\n Type {deleteName} to confirm deletion:\n \n)" - }, - { - "name": "deleteButtonText", - "type": "string", - "description": "Text of the delete button", - "defaultValue": "'Delete'" - }, - { - "name": "deleteName", - "type": "string", - "description": "Text which the user should type in to confirm deletion (only for extra-destructive delete variant)", - "required": true - }, - { - "name": "deleteVariant", - "type": "'extra-destructive' | 'destructive' | 'easily-recoverable'", - "description": "Delete variant. Destructive and extra-destructive variants will show a warning icon and danger button. For extra-destructive variant, text input confirmation is needed.", - "defaultValue": "'extra-destructive'" - }, - { - "name": "error", - "type": "Error", - "description": "Error indicating deletion has failed" - }, - { - "name": "errorAlertProps", - "type": "AlertProps", - "description": "Additional props for error alert" - }, - { - "name": "isDeleting", - "type": "boolean", - "description": "Flag indicating that deletion is currently in progress" - }, - { - "name": "onDelete", - "type": "() => void", - "description": "Callback on clicking the delete button", - "required": true - }, - { - "name": "ref", - "type": "React.RefObject", - "description": "Modal ref" - }, - { - "name": "testId", - "type": "string", - "description": "Id of the modal for testing purposes (defaults to \"delete-modal\")" - }, - { - "name": "textInputProps", - "type": "TextInputProps", - "description": "Additional props for confirmation text input (only for extra-destructive delete variant)" - }, - { - "name": "title", - "type": "React.ReactNode", - "description": "Content rendered inside the modal header title.", - "required": true - } - ] - } - ], - "examples": [ - "Example", - "DeleteModal implementation" - ], - "fullscreenExamples": [ - "Fullscreen example" - ] -}; -pageData.liveContext = { - ExtendedButton, - DeleteModal -}; -pageData.examples = { - 'Example': props => - {\n const [isModalRecoverableOpen, setIsModalRecoverableOpen] = React.useState(false);\n const [isModalDestructiveOpen, setIsModalDestructiveOpen] = React.useState(false);\n const [isModalExtraDestructiveOpen, setIsModalExtraDestructiveOpen] = React.useState(false);\n\n const handleModalRecoverableToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalRecoverableOpen(!isModalRecoverableOpen);\n };\n\n const handleModalDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalDestructiveOpen(!isModalDestructiveOpen);\n };\n\n const handleModalExtraDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalExtraDestructiveOpen(!isModalExtraDestructiveOpen);\n };\n\n return (\n <>\n \n \n \n \n \n \n \n \n \n \n \n\n handleModalRecoverableToggle(undefined)}\n deleteVariant=\"easily-recoverable\"\n isOpen={isModalRecoverableOpen}\n onClose={handleModalRecoverableToggle}\n >\n The item-name item will be deleted.\n \n handleModalDestructiveToggle(undefined)}\n deleteVariant=\"destructive\"\n isOpen={isModalDestructiveOpen}\n onClose={handleModalDestructiveToggle}\n >\n The item-name item will be deleted. [Brief sentence describing consequence of action].\n \n handleModalExtraDestructiveToggle(undefined)}\n deleteVariant=\"extra-destructive\"\n isOpen={isModalExtraDestructiveOpen}\n onClose={handleModalExtraDestructiveToggle}\n >\n The item-name item will be deleted. [Brief sentence describing consequence of action].\n \n \n );\n};\n","title":"Example","lang":"js","className":""}}> - - , - 'Fullscreen example': props => - {\n const [isModalRecoverableOpen, setIsModalRecoverableOpen] = React.useState(false);\n const [isModalDestructiveOpen, setIsModalDestructiveOpen] = React.useState(false);\n const [isModalExtraDestructiveOpen, setIsModalExtraDestructiveOpen] = React.useState(false);\n\n const handleModalRecoverableToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalRecoverableOpen(!isModalRecoverableOpen);\n };\n\n const handleModalDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalDestructiveOpen(!isModalDestructiveOpen);\n };\n\n const handleModalExtraDestructiveToggle = (_event: KeyboardEvent | React.MouseEvent | undefined) => {\n setIsModalExtraDestructiveOpen(!isModalExtraDestructiveOpen);\n };\n\n return (\n <>\n \n \n \n \n \n \n \n \n \n \n \n\n handleModalRecoverableToggle(undefined)}\n deleteVariant=\"easily-recoverable\"\n isOpen={isModalRecoverableOpen}\n onClose={handleModalRecoverableToggle}\n >\n The item-name item will be deleted.\n \n handleModalDestructiveToggle(undefined)}\n deleteVariant=\"destructive\"\n isOpen={isModalDestructiveOpen}\n onClose={handleModalDestructiveToggle}\n >\n The item-name item will be deleted. [Brief sentence describing consequence of action].\n \n handleModalExtraDestructiveToggle(undefined)}\n deleteVariant=\"extra-destructive\"\n isOpen={isModalExtraDestructiveOpen}\n onClose={handleModalExtraDestructiveToggle}\n >\n The item-name item will be deleted. [Brief sentence describing consequence of action].\n \n \n );\n};\n","title":"Fullscreen example","lang":"js","isFullscreen":true,"className":""}}> - - , - 'DeleteModal implementation': props => - React.ReactNode;\n /** Text of the delete button */\n deleteButtonText?: string;\n /** Text of the cancel button */\n cancelButtonText?: string;\n /** Callback on clicking the delete button */\n onDelete: () => void;\n /** Flag indicating that deletion is currently in progress */\n isDeleting?: boolean;\n /** Error indicating deletion has failed */\n error?: Error;\n /** Id of the modal for testing purposes (defaults to \"delete-modal\") */\n testId?: string;\n /** Additional props for confirmation text input (only for extra-destructive delete variant) */\n textInputProps?: TextInputProps;\n /** Additional props for error alert */\n errorAlertProps?: AlertProps;\n /** Modal ref */\n ref?: React.RefObject;\n};\n\nexport const DeleteModal: React.FunctionComponent = ({\n children,\n title,\n deleteVariant = 'extra-destructive',\n deleteName,\n confirmationMessage = (deleteName) => (\n <>\n Type {deleteName} to confirm deletion:\n \n ),\n deleteButtonText = 'Delete',\n cancelButtonText = 'Cancel',\n onDelete,\n isDeleting,\n error,\n testId,\n textInputProps,\n errorAlertProps,\n onClose,\n isOpen,\n ...props\n}: DeleteModalProps) => {\n const [confirmationText, setConfirmationText] = React.useState('');\n const confirmed = deleteVariant === 'extra-destructive' ? confirmationText.trim() === deleteName : true;\n\n React.useEffect(() => {\n if (!isOpen) {\n setConfirmationText('');\n }\n }, [isOpen]);\n\n return (\n \n \n \n \n {children}\n {deleteVariant === 'extra-destructive' && (\n \n \n {confirmationMessage(deleteName)}\n setConfirmationText(value)}\n onKeyDown={(event) => {\n if (event.key === 'Enter' && confirmed && !isDeleting) {\n event.preventDefault();\n onDelete();\n }\n }}\n />\n \n \n )}\n {error && (\n \n \n {error.message}\n \n \n )}\n \n \n \n onDelete()}\n >\n {deleteButtonText}\n \n \n \n \n );\n};","title":"DeleteModal implementation","lang":"ts","className":""}}> - - -}; - -const Component = () => ( - - - {`Basic usage`} - - {React.createElement(pageData.examples["Example"])} - {React.createElement(pageData.examples["Fullscreen example"])} - {React.createElement(pageData.examples["DeleteModal implementation"])} - -); -Component.displayName = 'ExtensionsAiInfraUiComponentsReactDocs'; -Component.pageData = pageData; - -export default Component; diff --git a/packages/module/patternfly-docs/generated/extensions/deletemodal/design-guidelines.js b/packages/module/patternfly-docs/generated/extensions/deletemodal/design-guidelines.js deleted file mode 100644 index 540e07a..0000000 --- a/packages/module/patternfly-docs/generated/extensions/deletemodal/design-guidelines.js +++ /dev/null @@ -1,56 +0,0 @@ -import React from 'react'; -import { AutoLinkHeader, Example, Link as PatternflyThemeLink } from '@patternfly/documentation-framework/components'; - -const pageData = { - "id": "DeleteModal", - "section": "extensions", - "subsection": "", - "deprecated": false, - "template": false, - "beta": false, - "demo": false, - "newImplementationLink": false, - "source": "design-guidelines", - "tabName": null, - "slug": "/extensions/deletemodal/design-guidelines", - "sourceLink": "https://github.com/patternfly/patternfly-org/blob/main/packages/module/patternfly-docs/content/design-guidelines/design-guidelines.md", - "relPath": "packages/module/patternfly-docs/content/design-guidelines/design-guidelines.md" -}; -pageData.examples = { - -}; - -const Component = () => ( - -

- {`Design guidelines intro`} -

- - {`Header`} - - - {`Sub-header`} - -

- {`Guidelines:`} -

-
    -
  1. - {`A`} -
  2. -
  3. - {`list`} -
  4. -
  5. - {`using`} -
  6. -
  7. - {`markdown`} -
  8. -
-
-); -Component.displayName = 'ExtensionsDeletemodalDesignGuidelinesDocs'; -Component.pageData = pageData; - -export default Component; diff --git a/packages/module/patternfly-docs/generated/extensions/deletemodal/react.js b/packages/module/patternfly-docs/generated/extensions/deletemodal/react.js deleted file mode 100644 index bcb0e65..0000000 --- a/packages/module/patternfly-docs/generated/extensions/deletemodal/react.js +++ /dev/null @@ -1,144 +0,0 @@ -import React from 'react'; -import { AutoLinkHeader, Example, Link as PatternflyThemeLink } from '@patternfly/documentation-framework/components'; -import { DeleteModal } from "@patternfly/ai-infra-ui-components"; -const pageData = { - "id": "DeleteModal", - "section": "extensions", - "subsection": "", - "deprecated": false, - "template": false, - "beta": false, - "demo": false, - "newImplementationLink": false, - "source": "react", - "tabName": null, - "slug": "/extensions/deletemodal/react", - "sourceLink": "https://github.com/patternfly/patternfly-react/blob/main/packages/module/patternfly-docs/content/examples/basic.md", - "relPath": "packages/module/patternfly-docs/content/examples/basic.md", - "propComponents": [ - { - "name": "DeleteModal", - "description": "", - "props": [ - { - "name": "cancelButtonText", - "type": "string", - "description": "Text of the cancel button", - "defaultValue": "'Cancel'" - }, - { - "name": "confirmationMessage", - "type": "(deleteName: string) => React.ReactNode", - "description": "Message describing what should the user type in to confirm deletion (only for extra-destructive delete variant)", - "defaultValue": "(deleteName) => (\n <>\n Type {deleteName} to confirm deletion:\n \n)" - }, - { - "name": "deleteName", - "type": "string", - "description": "Text which the user should type in to confirm deletion (only for extra-destructive delete variant)", - "required": true - }, - { - "name": "deleteVariant", - "type": "'extra-destructive' | 'destructive' | 'easily-recoverable'", - "description": "Delete variant. Destructive and extra-destructive variants will show a warning icon and danger button. For extra-destructive variant, text input confirmation is needed.", - "defaultValue": "'extra-destructive'" - }, - { - "name": "deleting", - "type": "boolean", - "description": "Flag indicating that deletion is currently in progress" - }, - { - "name": "error", - "type": "Error", - "description": "Error indicating deletion has failed" - }, - { - "name": "errorAlertProps", - "type": "AlertProps", - "description": "Additional props for error alert" - }, - { - "name": "onClose", - "type": "() => void", - "description": "Callback on clicking the close button", - "required": true - }, - { - "name": "onDelete", - "type": "() => void", - "description": "Callback on clicking the delete button", - "required": true - }, - { - "name": "ref", - "type": "React.RefObject", - "description": "Modal ref" - }, - { - "name": "submitButtonLabel", - "type": "string", - "description": "Text of the delete button", - "defaultValue": "'Delete'" - }, - { - "name": "testId", - "type": "string", - "description": "Id of the modal for testing purposes (defaults to \"delete-modal\")" - }, - { - "name": "textInputProps", - "type": "TextInputProps", - "description": "Additional props for confirmation text input (only for extra-destructive delete variant)" - }, - { - "name": "title", - "type": "React.ReactNode", - "description": "Content rendered inside the modal header title.", - "required": true - } - ] - } - ], - "examples": [ - "Example" - ], - "fullscreenExamples": [ - "Fullscreen example" - ] -}; -pageData.liveContext = { - DeleteModal -}; -pageData.examples = { - 'Example': props => - {\n const [isModalRecoverableOpen, setIsModalRecoverableOpen] = React.useState(false);\n const [isModalDestructiveOpen, setIsModalDestructiveOpen] = React.useState(false);\n const [isModalExtraDestructiveOpen, setIsModalExtraDestructiveOpen] = React.useState(false);\n\n return (\n <>\n \n \n \n \n \n \n \n \n \n \n \n\n {isModalRecoverableOpen && (\n {}}\n deleteVariant=\"easily-recoverable\"\n onClose={() => setIsModalRecoverableOpen(false)}\n >\n The item-name item will be deleted.\n \n )}\n\n {isModalDestructiveOpen && (\n {}}\n deleteVariant=\"destructive\"\n onClose={() => setIsModalDestructiveOpen(false)}\n >\n The item-name item will be deleted. [Brief sentence describing consequence of action].\n \n )}\n\n {isModalExtraDestructiveOpen && (\n {}}\n deleteVariant=\"extra-destructive\"\n onClose={() => setIsModalExtraDestructiveOpen(false)}\n >\n The item-name item will be deleted. [Brief sentence describing consequence of action].\n \n )}\n \n );\n};\n","title":"Example","lang":"js","className":""}}> - - , - 'Fullscreen example': props => - {\n const [isModalRecoverableOpen, setIsModalRecoverableOpen] = React.useState(false);\n const [isModalDestructiveOpen, setIsModalDestructiveOpen] = React.useState(false);\n const [isModalExtraDestructiveOpen, setIsModalExtraDestructiveOpen] = React.useState(false);\n\n return (\n <>\n \n \n \n \n \n \n \n \n \n \n \n\n {isModalRecoverableOpen && (\n {}}\n deleteVariant=\"easily-recoverable\"\n onClose={() => setIsModalRecoverableOpen(false)}\n >\n The item-name item will be deleted.\n \n )}\n\n {isModalDestructiveOpen && (\n {}}\n deleteVariant=\"destructive\"\n onClose={() => setIsModalDestructiveOpen(false)}\n >\n The item-name item will be deleted. [Brief sentence describing consequence of action].\n \n )}\n\n {isModalExtraDestructiveOpen && (\n {}}\n deleteVariant=\"extra-destructive\"\n onClose={() => setIsModalExtraDestructiveOpen(false)}\n >\n The item-name item will be deleted. [Brief sentence describing consequence of action].\n \n )}\n \n );\n};\n","title":"Fullscreen example","lang":"js","isFullscreen":true,"className":""}}> - - -}; - -const Component = () => ( - -

- {`Note: this component is an upgrade of an `} - - {`existing DeleteModal`} - - {` in odh-dashboard`} -

- - {`Basic usage`} - - {React.createElement(pageData.examples["Example"])} - {React.createElement(pageData.examples["Fullscreen example"])} -
-); -Component.displayName = 'ExtensionsDeletemodalReactDocs'; -Component.pageData = pageData; - -export default Component; diff --git a/packages/module/patternfly-docs/generated/index.js b/packages/module/patternfly-docs/generated/index.js deleted file mode 100644 index ed12c2c..0000000 --- a/packages/module/patternfly-docs/generated/index.js +++ /dev/null @@ -1,24 +0,0 @@ -module.exports = { - '/extensions/deletemodal/react': { - id: "DeleteModal", - title: "DeleteModal", - toc: [{"text":"Basic usage"},[{"text":"Example"},{"text":"Fullscreen example"}]], - examples: ["Example"], - fullscreenExamples: ["Fullscreen example"], - section: "extensions", - subsection: "", - source: "react", - tabName: null, - Component: () => import(/* webpackChunkName: "extensions/deletemodal/react/index" */ './extensions/deletemodal/react') - }, - '/extensions/deletemodal/design-guidelines': { - id: "DeleteModal", - title: "DeleteModal", - toc: [{"text":"Header"},[{"text":"Sub-header"}]], - section: "extensions", - subsection: "", - source: "design-guidelines", - tabName: null, - Component: () => import(/* webpackChunkName: "extensions/deletemodal/design-guidelines/index" */ './extensions/deletemodal/design-guidelines') - } -}; \ No newline at end of file diff --git a/packages/module/patternfly-docs/generated/react.js b/packages/module/patternfly-docs/generated/react.js deleted file mode 100644 index 6cbee92..0000000 --- a/packages/module/patternfly-docs/generated/react.js +++ /dev/null @@ -1,59 +0,0 @@ -import React from 'react'; -import { AutoLinkHeader, Example } from '@patternfly/documentation-framework/components'; -import { ExtendedButton } from "@patternfly/ai-infra-ui-components"; -const pageData = { - "id": "AI-infra-ui-components", - "section": "extensions", - "source": "react", - "slug": "/extensions/ai-infra-ui-components/react", - "sourceLink": "https://github.com/patternfly/patternfly-react/blob/main/packages/module/patternfly-docs/content/extensions/ai-infra-ui-components/examples/basic.md", - "propComponents": [ - { - "name": "ExtendedButton", - "description": "", - "props": [ - { - "name": "children", - "type": "React.ReactNode", - "description": "Content to render inside the extended button component" - } - ] - } - ], - "examples": [ - "Example" - ], - "fullscreenExamples": [ - "Fullscreen example" - ] -}; -pageData.liveContext = { - ExtendedButton -}; -pageData.relativeImports = { - -}; -pageData.examples = { - 'Example': props => - My custom extension button;\n","title":"Example","lang":"js"}}> - - , - 'Fullscreen example': props => - My custom extension button;\n","title":"Fullscreen example","lang":"js","isFullscreen":true}}> - - -}; - -const Component = () => ( - - - {`Basic usage`} - - {React.createElement(pageData.examples["Example"])} - {React.createElement(pageData.examples["Fullscreen example"])} - -); -Component.displayName = 'ExtensionsPatternflyExtensionSeedReactDocs'; -Component.pageData = pageData; - -export default Component; From 57c5af0647d53214d7f55dcba08fa00059c74588 Mon Sep 17 00:00:00 2001 From: adamviktora Date: Wed, 9 Oct 2024 10:01:20 +0200 Subject: [PATCH 08/11] fix: remove ExtendedButton --- .../src/ExtendedButton/ExtendedButton.tsx | 30 -------- .../__tests__/ExtendedButton.test.tsx | 72 ------------------- .../ExtendedButton.test.tsx.snap | 20 ------ packages/module/src/ExtendedButton/index.ts | 1 - packages/module/src/index.ts | 1 - 5 files changed, 124 deletions(-) delete mode 100644 packages/module/src/ExtendedButton/ExtendedButton.tsx delete mode 100644 packages/module/src/ExtendedButton/__tests__/ExtendedButton.test.tsx delete mode 100644 packages/module/src/ExtendedButton/__tests__/__snapshots__/ExtendedButton.test.tsx.snap delete mode 100644 packages/module/src/ExtendedButton/index.ts diff --git a/packages/module/src/ExtendedButton/ExtendedButton.tsx b/packages/module/src/ExtendedButton/ExtendedButton.tsx deleted file mode 100644 index b8119e9..0000000 --- a/packages/module/src/ExtendedButton/ExtendedButton.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import React from 'react'; -import { Button, ButtonProps } from '@patternfly/react-core'; - -export interface ExtendedButtonProps extends ButtonProps { - /** Content to render inside the extended button component */ - children?: React.ReactNode; -} - -export const ExtendedButton: React.FunctionComponent = ({ - children, - ...props -}: ExtendedButtonProps) => { - const [currentVariantIndex, setCurrentVariantIndex] = React.useState(0); - - const buttonVariants: ButtonProps['variant'][] = [ - 'primary', - 'secondary', - 'tertiary' - ]; - - const handleClick = () => { - setCurrentVariantIndex((previousVariantIndex) => (previousVariantIndex + 1) % buttonVariants.length); - }; - - return ( - - ); -}; diff --git a/packages/module/src/ExtendedButton/__tests__/ExtendedButton.test.tsx b/packages/module/src/ExtendedButton/__tests__/ExtendedButton.test.tsx deleted file mode 100644 index 3a8b357..0000000 --- a/packages/module/src/ExtendedButton/__tests__/ExtendedButton.test.tsx +++ /dev/null @@ -1,72 +0,0 @@ -import React from 'react'; -import { render, screen, waitFor } from '@testing-library/react'; -import '@testing-library/jest-dom'; -import userEvent from '@testing-library/user-event'; -import { ExtendedButton } from '../ExtendedButton'; - -test('Renders without children', () => { - render( -
- -
- ); - - expect(screen.getByTestId('container').firstChild).toBeVisible(); -}); - -test('Renders children', () => { - render(Test); - - expect(screen.getByRole('button', { name: 'Test' })).toBeVisible(); -}); - -test('Passes inherited props to the returned component', () => { - render(Test); - - expect(screen.getByRole('button')).toHaveAccessibleName('Test label'); -}); - -test('Renders as a primary button initially', () => { - render(Test); - - expect(screen.getByRole('button')).toHaveClass('pf-v6-c-button pf-m-primary', { exact: true }); -}); - -test('Renders as a secondary button once it has been clicked once', () => { - render(Test); - const button = screen.getByRole('button'); - userEvent.click(screen.getByRole('button')); - - waitFor(() => { - expect(button).toHaveClass('pf-v6-c-button pf-m-secondary', { exact: true }); - }); -}); - -test('Renders as a tertiary button once it has been clicked twice', () => { - render(Test); - - const button = screen.getByRole('button'); - userEvent.click(button); - userEvent.click(button); - - waitFor(() => { - expect(button).toHaveClass('pf-v6-c-button pf-m-tertiary', { exact: true }); - }); -}); - -test('Loops back to rendering a primary button again after being clicked three times', () => { - render(Test); - - const button = screen.getByRole('button'); - userEvent.click(button); - userEvent.click(button); - userEvent.click(button); - - expect(button).toHaveClass('pf-v6-c-button pf-m-primary', { exact: true }); -}); - -test('Matches expected default snapshot', () => { - const { asFragment } = render(Test); - - expect(asFragment()).toMatchSnapshot(); -}); diff --git a/packages/module/src/ExtendedButton/__tests__/__snapshots__/ExtendedButton.test.tsx.snap b/packages/module/src/ExtendedButton/__tests__/__snapshots__/ExtendedButton.test.tsx.snap deleted file mode 100644 index 17f6559..0000000 --- a/packages/module/src/ExtendedButton/__tests__/__snapshots__/ExtendedButton.test.tsx.snap +++ /dev/null @@ -1,20 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Matches expected default snapshot 1`] = ` - - - -`; diff --git a/packages/module/src/ExtendedButton/index.ts b/packages/module/src/ExtendedButton/index.ts deleted file mode 100644 index 03c57e3..0000000 --- a/packages/module/src/ExtendedButton/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './ExtendedButton'; diff --git a/packages/module/src/index.ts b/packages/module/src/index.ts index 81d39ab..2d52cdf 100644 --- a/packages/module/src/index.ts +++ b/packages/module/src/index.ts @@ -1,2 +1 @@ export * from './DeleteModal'; -export * from './ExtendedButton'; From ae6615afc0adabf70ad96d7762a122c72f910c84 Mon Sep 17 00:00:00 2001 From: adamviktora Date: Wed, 9 Oct 2024 10:15:25 +0200 Subject: [PATCH 09/11] docs: DeleteModal updates --- .../content/design-guidelines/design-guidelines.md | 2 +- .../content/examples/{basic.md => DeleteModal.md} | 12 ++---------- .../module/patternfly-docs/patternfly-docs.config.js | 2 +- .../module/patternfly-docs/patternfly-docs.source.js | 2 +- 4 files changed, 5 insertions(+), 13 deletions(-) rename packages/module/patternfly-docs/content/examples/{basic.md => DeleteModal.md} (54%) diff --git a/packages/module/patternfly-docs/content/design-guidelines/design-guidelines.md b/packages/module/patternfly-docs/content/design-guidelines/design-guidelines.md index 3d6fcf3..d8bb2f3 100644 --- a/packages/module/patternfly-docs/content/design-guidelines/design-guidelines.md +++ b/packages/module/patternfly-docs/content/design-guidelines/design-guidelines.md @@ -1,7 +1,7 @@ --- # Sidenav top-level section # should be the same for all markdown files for each extension -section: extensions +section: AI-infra-ui-components # Sidenav secondary level section # should be the same for all markdown files for each extension id: DeleteModal diff --git a/packages/module/patternfly-docs/content/examples/basic.md b/packages/module/patternfly-docs/content/examples/DeleteModal.md similarity index 54% rename from packages/module/patternfly-docs/content/examples/basic.md rename to packages/module/patternfly-docs/content/examples/DeleteModal.md index 47959df..7c96ae0 100644 --- a/packages/module/patternfly-docs/content/examples/basic.md +++ b/packages/module/patternfly-docs/content/examples/DeleteModal.md @@ -1,7 +1,7 @@ --- # Sidenav top-level section # should be the same for all markdown files -section: extensions +section: AI-infra-ui-components # Sidenav secondary level section # should be the same for all markdown files id: DeleteModal @@ -14,18 +14,10 @@ propComponents: ['DeleteModal'] import { DeleteModal } from "@patternfly/ai-infra-ui-components"; -Note: this component is an upgrade of an [existing DeleteModal](https://github.com/opendatahub-io/odh-dashboard/blob/main/frontend/src/pages/projects/components/DeleteModal.tsx) in odh-dashboard - -## Basic usage +Note: this component documents the API and enhances the [existing DeleteModal](https://github.com/opendatahub-io/odh-dashboard/blob/main/frontend/src/pages/projects/components/DeleteModal.tsx) component from odh-dashboard. It can be imported from [@patternfly/ai-infra-ui-components](https://www.npmjs.com/package/@patternfly/AI-infra-ui-components). Alternatively, it can be used within the odh-dashboard via the import: `~/pages/projects/components/DeleteModal` ### Example ```js file="./DeleteModalBasic.tsx" ``` - -### Fullscreen example - -```js file="./DeleteModalBasic.tsx" isFullscreen - -``` diff --git a/packages/module/patternfly-docs/patternfly-docs.config.js b/packages/module/patternfly-docs/patternfly-docs.config.js index 7a4cdb6..4db7142 100644 --- a/packages/module/patternfly-docs/patternfly-docs.config.js +++ b/packages/module/patternfly-docs/patternfly-docs.config.js @@ -1,6 +1,6 @@ // This module is shared between NodeJS and babelled ES5 module.exports = { - sideNavItems: [{ section: 'extensions' }], + sideNavItems: [{ section: 'AI-infra-ui-components' }], topNavItems: [], port: 8006 }; diff --git a/packages/module/patternfly-docs/patternfly-docs.source.js b/packages/module/patternfly-docs/patternfly-docs.source.js index 5ae9c80..e1b1ab0 100644 --- a/packages/module/patternfly-docs/patternfly-docs.source.js +++ b/packages/module/patternfly-docs/patternfly-docs.source.js @@ -8,7 +8,7 @@ module.exports = (sourceMD, sourceProps) => { // Parse md files const contentBase = path.join(__dirname, './content'); - sourceMD(path.join(contentBase, '/**/*.md'), 'extensions'); + sourceMD(path.join(contentBase, '/**/*.md'), 'AI-infra-ui-components'); /** If you want to parse content from node_modules instead of providing a relative/absolute path, From a95538c447bcb9b70b4cf064e9be4a30e5870bc2 Mon Sep 17 00:00:00 2001 From: adamviktora Date: Wed, 9 Oct 2024 10:20:14 +0200 Subject: [PATCH 10/11] fix: show testId prop default value in docs --- packages/module/src/DeleteModal/DeleteModal.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/module/src/DeleteModal/DeleteModal.tsx b/packages/module/src/DeleteModal/DeleteModal.tsx index f452b3a..3a62c5d 100644 --- a/packages/module/src/DeleteModal/DeleteModal.tsx +++ b/packages/module/src/DeleteModal/DeleteModal.tsx @@ -37,7 +37,7 @@ export type DeleteModalProps = Omit & { deleting?: boolean; /** Error indicating deletion has failed */ error?: Error; - /** Id of the modal for testing purposes (defaults to "delete-modal") */ + /** Id of the modal for testing purposes */ testId?: string; /** Additional props for confirmation text input (only for extra-destructive delete variant) */ textInputProps?: TextInputProps; @@ -62,7 +62,7 @@ export const DeleteModal: React.FunctionComponent = ({ onDelete, deleting: isDeleting, error, - testId, + testId = 'delete-modal', textInputProps, errorAlertProps, onClose, @@ -75,7 +75,7 @@ export const DeleteModal: React.FunctionComponent = ({ const confirmed = deleteVariant === 'extra-destructive' ? inputValue.trim() === deleteNameSanitized : true; return ( - + From b0dd0b19de07110ee8751ffe8278b5000534bf05 Mon Sep 17 00:00:00 2001 From: adamviktora Date: Wed, 9 Oct 2024 10:33:49 +0200 Subject: [PATCH 11/11] test: add DeleteModal test --- .../src/DeleteModal/__tests__/DeleteModal.test.tsx | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 packages/module/src/DeleteModal/__tests__/DeleteModal.test.tsx diff --git a/packages/module/src/DeleteModal/__tests__/DeleteModal.test.tsx b/packages/module/src/DeleteModal/__tests__/DeleteModal.test.tsx new file mode 100644 index 0000000..7c7546b --- /dev/null +++ b/packages/module/src/DeleteModal/__tests__/DeleteModal.test.tsx @@ -0,0 +1,14 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import '@testing-library/jest-dom'; +import { DeleteModal } from '../DeleteModal'; + +test('Renders with confirmation text input by default', () => { + render( + {}} onClose={() => {}}> + Message + + ); + + expect(screen.getByRole('textbox')).toBeVisible(); +});