NestedFolders: Add invalid state to NestedFolderPicker (#72175)

* chore: add invalid state to NestedFolderPicker

* NestedFolderPicker: pass invalid state to trigger

* fix: remove redundant sharedInputStyle
This commit is contained in:
Karol Stawowski 2023-07-26 12:47:58 +02:00 committed by GitHub
parent 7a97bf7f15
commit 600b930c47
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 19 additions and 6 deletions

View File

@ -31,6 +31,9 @@ export interface NestedFolderPickerProps {
/* Folder UID to show as selected */ /* Folder UID to show as selected */
value?: string; value?: string;
/** Show an invalid state around the folder picker */
invalid?: boolean;
/* Whether to show the root 'Dashboards' (formally General) folder as selectable */ /* Whether to show the root 'Dashboards' (formally General) folder as selectable */
showRootFolder?: boolean; showRootFolder?: boolean;
@ -43,7 +46,13 @@ export interface NestedFolderPickerProps {
const EXCLUDED_KINDS = ['empty-folder' as const, 'dashboard' as const]; const EXCLUDED_KINDS = ['empty-folder' as const, 'dashboard' as const];
export function NestedFolderPicker({ value, showRootFolder = true, excludeUIDs, onChange }: NestedFolderPickerProps) { export function NestedFolderPicker({
value,
invalid,
showRootFolder = true,
excludeUIDs,
onChange,
}: NestedFolderPickerProps) {
const styles = useStyles2(getStyles); const styles = useStyles2(getStyles);
const dispatch = useDispatch(); const dispatch = useDispatch();
const selectedFolder = useGetFolderQuery(value || skipToken); const selectedFolder = useGetFolderQuery(value || skipToken);
@ -212,6 +221,7 @@ export function NestedFolderPicker({ value, showRootFolder = true, excludeUIDs,
return ( return (
<Trigger <Trigger
label={label} label={label}
invalid={invalid}
isLoading={selectedFolder.isLoading} isLoading={selectedFolder.isLoading}
autoFocus={autoFocusButton} autoFocus={autoFocusButton}
ref={setTriggerRef} ref={setTriggerRef}
@ -234,6 +244,7 @@ export function NestedFolderPicker({ value, showRootFolder = true, excludeUIDs,
prefix={label ? <Icon name="folder" /> : null} prefix={label ? <Icon name="folder" /> : null}
placeholder={label ?? t('browse-dashboards.folder-picker.search-placeholder', 'Search folders')} placeholder={label ?? t('browse-dashboards.folder-picker.search-placeholder', 'Search folders')}
value={search} value={search}
invalid={invalid}
className={styles.search} className={styles.search}
onKeyDown={handleKeyDown} onKeyDown={handleKeyDown}
onChange={(e) => setSearch(e.currentTarget.value)} onChange={(e) => setSearch(e.currentTarget.value)}

View File

@ -3,18 +3,20 @@ import React, { forwardRef, ReactNode, ButtonHTMLAttributes } from 'react';
import Skeleton from 'react-loading-skeleton'; import Skeleton from 'react-loading-skeleton';
import { GrafanaTheme2 } from '@grafana/data'; import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2, Icon, getInputStyles } from '@grafana/ui'; import { Icon, getInputStyles, useTheme2 } from '@grafana/ui';
import { focusCss } from '@grafana/ui/src/themes/mixins'; import { focusCss } from '@grafana/ui/src/themes/mixins';
import { Text } from '@grafana/ui/src/unstable'; import { Text } from '@grafana/ui/src/unstable';
import { Trans } from 'app/core/internationalization'; import { Trans } from 'app/core/internationalization';
interface TriggerProps extends ButtonHTMLAttributes<HTMLButtonElement> { interface TriggerProps extends ButtonHTMLAttributes<HTMLButtonElement> {
isLoading: boolean; isLoading: boolean;
invalid?: boolean;
label?: ReactNode; label?: ReactNode;
} }
function Trigger({ isLoading, label, ...rest }: TriggerProps, ref: React.ForwardedRef<HTMLButtonElement>) { function Trigger({ isLoading, invalid, label, ...rest }: TriggerProps, ref: React.ForwardedRef<HTMLButtonElement>) {
const styles = useStyles2(getStyles); const theme = useTheme2();
const styles = getStyles(theme, invalid);
return ( return (
<div className={styles.wrapper}> <div className={styles.wrapper}>
@ -52,8 +54,8 @@ function Trigger({ isLoading, label, ...rest }: TriggerProps, ref: React.Forward
export default forwardRef(Trigger); export default forwardRef(Trigger);
const getStyles = (theme: GrafanaTheme2) => { const getStyles = (theme: GrafanaTheme2, invalid = false) => {
const baseStyles = getInputStyles({ theme }); const baseStyles = getInputStyles({ theme, invalid });
return { return {
wrapper: baseStyles.wrapper, wrapper: baseStyles.wrapper,