From 8028bb3ae303ef6cfeb5657f59e4dbbb20a4090c Mon Sep 17 00:00:00 2001 From: adamviktora Date: Wed, 23 Oct 2024 13:55:06 +0200 Subject: [PATCH 1/2] feat: K8sNameDescriptionField and related components --- .eslintrc.json | 1 - .../FieldGroupHelpLabelIcon.md | 26 ++++++ .../FieldGroupHelpLabelIconBasic.tsx | 24 ++++++ .../K8sNameDescriptionField.md | 33 ++++++++ .../K8sNameDescriptionFieldBasic.tsx | 48 +++++++++++ .../NameWithResourceNameFieldBasic.tsx | 44 +++++++++++ .../FieldGroupHelpLabelIcon.tsx | 19 +++++ .../src/FieldGroupHelpLabelIcon/index.ts | 1 + .../HelperTextItemVariants.tsx | 35 ++++++++ .../K8sNameDescriptionField.tsx | 54 +++++++++++++ .../NameWithResourceNameField.tsx | 79 +++++++++++++++++++ .../ResourceNameDefinitionPopover.tsx | 14 ++++ .../ResourceNameField.tsx | 59 ++++++++++++++ .../src/K8sNameDescriptionField/index.tsx | 3 + .../src/K8sNameDescriptionField/types.ts | 39 +++++++++ packages/module/src/index.ts | 2 + 16 files changed, 480 insertions(+), 1 deletion(-) create mode 100644 packages/module/patternfly-docs/content/examples/FieldGroupHelpLabelIcon/FieldGroupHelpLabelIcon.md create mode 100644 packages/module/patternfly-docs/content/examples/FieldGroupHelpLabelIcon/FieldGroupHelpLabelIconBasic.tsx create mode 100644 packages/module/patternfly-docs/content/examples/K8sNameDescriptionField/K8sNameDescriptionField.md create mode 100644 packages/module/patternfly-docs/content/examples/K8sNameDescriptionField/K8sNameDescriptionFieldBasic.tsx create mode 100644 packages/module/patternfly-docs/content/examples/K8sNameDescriptionField/NameWithResourceNameFieldBasic.tsx create mode 100644 packages/module/src/FieldGroupHelpLabelIcon/FieldGroupHelpLabelIcon.tsx create mode 100644 packages/module/src/FieldGroupHelpLabelIcon/index.ts create mode 100644 packages/module/src/K8sNameDescriptionField/HelperTextItemVariants.tsx create mode 100644 packages/module/src/K8sNameDescriptionField/K8sNameDescriptionField.tsx create mode 100644 packages/module/src/K8sNameDescriptionField/NameWithResourceNameField.tsx create mode 100644 packages/module/src/K8sNameDescriptionField/ResourceNameDefinitionPopover.tsx create mode 100644 packages/module/src/K8sNameDescriptionField/ResourceNameField.tsx create mode 100644 packages/module/src/K8sNameDescriptionField/index.tsx create mode 100644 packages/module/src/K8sNameDescriptionField/types.ts diff --git a/.eslintrc.json b/.eslintrc.json index a6dcec8..b910b7d 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -84,7 +84,6 @@ ], "no-unused-labels": "error", "no-var": "error", - "object-shorthand": "error", "one-var": ["error", "never"], "prefer-const": "error", "radix": ["error", "as-needed"], diff --git a/packages/module/patternfly-docs/content/examples/FieldGroupHelpLabelIcon/FieldGroupHelpLabelIcon.md b/packages/module/patternfly-docs/content/examples/FieldGroupHelpLabelIcon/FieldGroupHelpLabelIcon.md new file mode 100644 index 0000000..65aa3ea --- /dev/null +++ b/packages/module/patternfly-docs/content/examples/FieldGroupHelpLabelIcon/FieldGroupHelpLabelIcon.md @@ -0,0 +1,26 @@ +--- +# Sidenav top-level section +# should be the same for all markdown files +section: AI-infra-ui-components +# Sidenav secondary level section +# should be the same for all markdown files +id: FieldGroupHelpLabelIcon +# 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: ['FieldGroupHelpLabelIcon'] +--- + +import { FieldGroupHelpLabelIcon } from "@patternfly/ai-infra-ui-components"; + +Note: this component documents the API and enhances the [existing FieldGroupHelpLabelIcon](https://github.com/opendatahub-io/odh-dashboard/blob/main/frontend/src/components/FieldGroupHelpLabelIcon.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: `~/components/FieldGroupHelpLabelIcon` + +This AI-infra-ui-components version of `FieldGroupHelpLabelIcon` uses internally a new PatternFly's `FormGroupLabelHelp` component instead of odh-dasboard's `DashboardPopupIconButton`. +**We recommend** replacing occurences of `} aria-label="More info"/>` with ``. + +### Example + +```js file="./FieldGroupHelpLabelIconBasic.tsx" + +``` diff --git a/packages/module/patternfly-docs/content/examples/FieldGroupHelpLabelIcon/FieldGroupHelpLabelIconBasic.tsx b/packages/module/patternfly-docs/content/examples/FieldGroupHelpLabelIcon/FieldGroupHelpLabelIconBasic.tsx new file mode 100644 index 0000000..cc68d4f --- /dev/null +++ b/packages/module/patternfly-docs/content/examples/FieldGroupHelpLabelIcon/FieldGroupHelpLabelIconBasic.tsx @@ -0,0 +1,24 @@ +import React from 'react'; +import { FieldGroupHelpLabelIcon } from '@patternfly/ai-infra-ui-components'; +import { Form, FormGroup, TextInput } from '@patternfly/react-core'; + +export const FieldGroupHelpLabelIconBasic: React.FunctionComponent = () => { + const [name, setName] = React.useState(''); + + const handleNameChange = (_event, name: string) => { + setName(name); + }; + + return ( +
+ } + isRequired + fieldId="simple-form-name" + > + + +
+ ); +}; diff --git a/packages/module/patternfly-docs/content/examples/K8sNameDescriptionField/K8sNameDescriptionField.md b/packages/module/patternfly-docs/content/examples/K8sNameDescriptionField/K8sNameDescriptionField.md new file mode 100644 index 0000000..c57c528 --- /dev/null +++ b/packages/module/patternfly-docs/content/examples/K8sNameDescriptionField/K8sNameDescriptionField.md @@ -0,0 +1,33 @@ +--- +# Sidenav top-level section +# should be the same for all markdown files +section: AI-infra-ui-components +# Sidenav secondary level section +# should be the same for all markdown files +id: K8sNameDescriptionField +# 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: ['K8sNameDescriptionField', 'NameWithResourceNameField'] +--- + +import { K8sNameDescriptionField, NameWithResourceNameField } from "@patternfly/ai-infra-ui-components"; + +Note: this component documents the API and enhances the [existing K8sNameDescriptionField](https://github.com/opendatahub-io/odh-dashboard/blob/main/frontend/src/concepts/k8s/K8sNameDescriptionField/K8sNameDescriptionField.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: `~/concepts/k8s/K8sNameDescriptionField/K8sNameDescriptionField` + +In the following examples, sample `data` and `onDataChange` props are provided. To obtain these props properly, you should use the [useK8sNameDescriptionFieldData hook](https://github.com/opendatahub-io/odh-dashboard/blob/main/frontend/src/concepts/k8s/K8sNameDescriptionField/K8sNameDescriptionField.tsx#L23). + +### Example + +```js file="./K8sNameDescriptionFieldBasic.tsx" + +``` + +### Example without description + +Internally in ai-infra-ui-components the `K8sNameDescriptionField` is built out of `NameWithResourceNameField` component, which encapsulates only the Name and Resource name fields - it has been created for future use cases where the "Description" field won't occur. + +```js file="./NameWithResourceNameFieldBasic.tsx" + +``` diff --git a/packages/module/patternfly-docs/content/examples/K8sNameDescriptionField/K8sNameDescriptionFieldBasic.tsx b/packages/module/patternfly-docs/content/examples/K8sNameDescriptionField/K8sNameDescriptionFieldBasic.tsx new file mode 100644 index 0000000..1bb9218 --- /dev/null +++ b/packages/module/patternfly-docs/content/examples/K8sNameDescriptionField/K8sNameDescriptionFieldBasic.tsx @@ -0,0 +1,48 @@ +import React from 'react'; +import { + K8sNameDescriptionField, + K8sNameDescriptionFieldData, + UseK8sNameDescriptionFieldData +} from '@patternfly/ai-infra-ui-components'; +import { Form } from '@patternfly/react-core'; + +export const K8sNameDescriptionFieldBasic: React.FunctionComponent = () => { + const [name, setName] = React.useState(''); + const [resourceName, setResourceName] = React.useState(null); + const [description, setDescription] = React.useState(''); + + const createResourceName = (name: string) => name.toLowerCase().replaceAll(' ', '-'); + const RESOURCE_NAME_MAX_LENGTH = 30; + + const data: K8sNameDescriptionFieldData = { + name: name, + description: description, + k8sName: { + value: resourceName ?? createResourceName(name), + state: { + immutable: false, + invalidCharacters: resourceName !== null && resourceName.includes(' '), + invalidLength: resourceName !== null && resourceName.length > RESOURCE_NAME_MAX_LENGTH, + safePrefix: undefined, + maxLength: RESOURCE_NAME_MAX_LENGTH, + touched: false + } + } + }; + + const onDataChange: UseK8sNameDescriptionFieldData['onDataChange'] = (key, value) => { + if (key === 'name') { + setName(value); + } else if (key === 'k8sName') { + setResourceName(value); + } else if (key === 'description') { + setDescription(value); + } + }; + + return ( +
+ + + ); +}; diff --git a/packages/module/patternfly-docs/content/examples/K8sNameDescriptionField/NameWithResourceNameFieldBasic.tsx b/packages/module/patternfly-docs/content/examples/K8sNameDescriptionField/NameWithResourceNameFieldBasic.tsx new file mode 100644 index 0000000..88d1509 --- /dev/null +++ b/packages/module/patternfly-docs/content/examples/K8sNameDescriptionField/NameWithResourceNameFieldBasic.tsx @@ -0,0 +1,44 @@ +import React from 'react'; +import { + NameWithResourceNameField, + NameWithResourceNameFieldData, + UseK8sNameDescriptionFieldData +} from '@patternfly/ai-infra-ui-components'; +import { Form } from '@patternfly/react-core'; + +export const NameWithResourceNameFieldBasic: React.FunctionComponent = () => { + const [name, setName] = React.useState(''); + const [resourceName, setResourceName] = React.useState(null); + + const createResourceName = (name: string) => name.toLowerCase().replaceAll(' ', '-'); + const RESOURCE_NAME_MAX_LENGTH = 30; + + const data: NameWithResourceNameFieldData = { + name: name, + k8sName: { + value: resourceName ?? createResourceName(name), + state: { + immutable: false, + invalidCharacters: resourceName !== null && resourceName.includes(' '), + invalidLength: resourceName !== null && resourceName.length > RESOURCE_NAME_MAX_LENGTH, + safePrefix: undefined, + maxLength: RESOURCE_NAME_MAX_LENGTH, + touched: false + } + } + }; + + const onDataChange: UseK8sNameDescriptionFieldData['onDataChange'] = (key, value) => { + if (key === 'name') { + setName(value); + } else if (key === 'k8sName') { + setResourceName(value); + } + }; + + return ( +
+ + + ); +}; diff --git a/packages/module/src/FieldGroupHelpLabelIcon/FieldGroupHelpLabelIcon.tsx b/packages/module/src/FieldGroupHelpLabelIcon/FieldGroupHelpLabelIcon.tsx new file mode 100644 index 0000000..2a9bc23 --- /dev/null +++ b/packages/module/src/FieldGroupHelpLabelIcon/FieldGroupHelpLabelIcon.tsx @@ -0,0 +1,19 @@ +import * as React from 'react'; +import { Popover, FormGroupLabelHelp } from '@patternfly/react-core'; + +export type FieldGroupHelpLabelIconProps = { + /** Body content of the popover. Should provide additional context for a form field. + * If you want to close the popover after an action within the body content, you can provide a function which will receive a callback as an argument to hide the popover, i.e. bodyContent={hide =>