mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Nested folders: Empty state for nested folder picker (#71464)
* add empty state to nestedfolderpicker, add translations * run i18n:extract * rename i18n key --------- Co-authored-by: joshhunt <josh@trtr.co>
This commit is contained in:
@@ -6,6 +6,7 @@ import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { IconButton, useStyles2 } from '@grafana/ui';
|
||||
import { getSvgSize } from '@grafana/ui/src/components/Icon/utils';
|
||||
import { Text } from '@grafana/ui/src/components/Text/Text';
|
||||
import { Trans } from 'app/core/internationalization';
|
||||
import { Indent } from 'app/features/browse-dashboards/components/Indent';
|
||||
import { DashboardsTreeItem } from 'app/features/browse-dashboards/types';
|
||||
import { DashboardViewItem } from 'app/features/search/types';
|
||||
@@ -39,15 +40,21 @@ export function NestedFolderList({
|
||||
|
||||
return (
|
||||
<div className={styles.table}>
|
||||
<List
|
||||
height={ROW_HEIGHT * Math.min(6.5, items.length)}
|
||||
width="100%"
|
||||
itemData={virtualData}
|
||||
itemSize={ROW_HEIGHT}
|
||||
itemCount={items.length}
|
||||
>
|
||||
{Row}
|
||||
</List>
|
||||
{items.length > 0 ? (
|
||||
<List
|
||||
height={ROW_HEIGHT * Math.min(6.5, items.length)}
|
||||
width="100%"
|
||||
itemData={virtualData}
|
||||
itemSize={ROW_HEIGHT}
|
||||
itemCount={items.length}
|
||||
>
|
||||
{Row}
|
||||
</List>
|
||||
) : (
|
||||
<div className={styles.emptyMessage}>
|
||||
<Trans i18nKey="browse-dashboards.folder-picker.empty-message">No folders found</Trans>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -132,7 +139,6 @@ function Row({ index, style: virtualStyles, data }: RowProps) {
|
||||
)}
|
||||
|
||||
<label className={styles.label} htmlFor={id}>
|
||||
{/* TODO: text is not truncated properly, it still overflows the container */}
|
||||
<Text as="span" truncate>
|
||||
{item.title}
|
||||
</Text>
|
||||
@@ -159,6 +165,12 @@ const getStyles = (theme: GrafanaTheme2) => {
|
||||
background: theme.components.input.background,
|
||||
}),
|
||||
|
||||
emptyMessage: css({
|
||||
padding: theme.spacing(1),
|
||||
textAlign: 'center',
|
||||
width: '100%',
|
||||
}),
|
||||
|
||||
// Should be the same size as the <IconButton /> for proper alignment
|
||||
folderButtonSpacer: css({
|
||||
paddingLeft: `calc(${getSvgSize(CHEVRON_SIZE)}px + ${theme.spacing(0.5)})`,
|
||||
|
||||
@@ -86,7 +86,7 @@ describe('NestedFolderPicker', () => {
|
||||
expect(screen.queryByRole('button', { name: 'Select folder' })).not.toBeInTheDocument();
|
||||
|
||||
// Search input and folder tree are visible
|
||||
expect(screen.getByPlaceholderText('Search folder')).toBeInTheDocument();
|
||||
expect(screen.getByPlaceholderText('Search folders')).toBeInTheDocument();
|
||||
expect(screen.getByLabelText('Dashboards')).toBeInTheDocument();
|
||||
expect(screen.getByLabelText(folderA.item.title)).toBeInTheDocument();
|
||||
expect(screen.getByLabelText(folderB.item.title)).toBeInTheDocument();
|
||||
|
||||
@@ -5,8 +5,9 @@ import { usePopperTooltip } from 'react-popper-tooltip';
|
||||
import { useAsync } from 'react-use';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { Alert, Button, FilterInput, LoadingBar, useStyles2 } from '@grafana/ui';
|
||||
import { Alert, Button, Icon, Input, LoadingBar, useStyles2 } from '@grafana/ui';
|
||||
import { Text } from '@grafana/ui/src/components/Text/Text';
|
||||
import { Trans, t } from 'app/core/internationalization';
|
||||
import { skipToken, useGetFolderQuery } from 'app/features/browse-dashboards/api/browseDashboardsAPI';
|
||||
import { listFolders, PAGE_SIZE } from 'app/features/browse-dashboards/api/services';
|
||||
import { createFlatTree } from 'app/features/browse-dashboards/state';
|
||||
@@ -172,7 +173,7 @@ export function NestedFolderPicker({ value, onChange }: NestedFolderPickerProps)
|
||||
<Skeleton width={100} />
|
||||
) : (
|
||||
<Text as="span" truncate>
|
||||
{label ?? 'Select folder'}
|
||||
{label ?? <Trans i18nKey="browse-dashboards.folder-picker.button-label">Select folder</Trans>}
|
||||
</Text>
|
||||
)}
|
||||
</Button>
|
||||
@@ -181,14 +182,15 @@ export function NestedFolderPicker({ value, onChange }: NestedFolderPickerProps)
|
||||
|
||||
return (
|
||||
<>
|
||||
<FilterInput
|
||||
<Input
|
||||
ref={setTriggerRef}
|
||||
autoFocus
|
||||
placeholder={label ?? 'Search folder'}
|
||||
placeholder={label ?? t('browse-dashboards.folder-picker.search-placeholder', 'Search folders')}
|
||||
value={search}
|
||||
escapeRegex={false}
|
||||
className={styles.search}
|
||||
onChange={(val) => setSearch(val)}
|
||||
onChange={(e) => setSearch(e.currentTarget.value)}
|
||||
role="combobox"
|
||||
suffix={<Icon name="search" />}
|
||||
/>
|
||||
<fieldset
|
||||
ref={setTooltipRef}
|
||||
@@ -200,8 +202,12 @@ export function NestedFolderPicker({ value, onChange }: NestedFolderPickerProps)
|
||||
})}
|
||||
>
|
||||
{error ? (
|
||||
<Alert className={styles.error} severity="warning" title="Error loading folders">
|
||||
{error.message || error.toString?.() || 'Unknown error'}
|
||||
<Alert
|
||||
className={styles.error}
|
||||
severity="warning"
|
||||
title={t('browse-dashboards.folder-picker.error-title', 'Error loading folders')}
|
||||
>
|
||||
{error.message || error.toString?.() || t('browse-dashboards.folder-picker.unknown-error', 'Unknown error')}
|
||||
</Alert>
|
||||
) : (
|
||||
<div>
|
||||
|
||||
@@ -61,6 +61,13 @@
|
||||
"manage-permissions": "",
|
||||
"move": ""
|
||||
},
|
||||
"folder-picker": {
|
||||
"button-label": "",
|
||||
"empty-message": "",
|
||||
"error-title": "",
|
||||
"search-placeholder": "",
|
||||
"unknown-error": ""
|
||||
},
|
||||
"manage-folder-nav": {
|
||||
"alert-rules": "",
|
||||
"dashboards": "",
|
||||
|
||||
@@ -61,6 +61,13 @@
|
||||
"manage-permissions": "Manage permissions",
|
||||
"move": "Move"
|
||||
},
|
||||
"folder-picker": {
|
||||
"button-label": "Select folder",
|
||||
"empty-message": "No folders found",
|
||||
"error-title": "Error loading folders",
|
||||
"search-placeholder": "Search folders",
|
||||
"unknown-error": "Unknown error"
|
||||
},
|
||||
"manage-folder-nav": {
|
||||
"alert-rules": "Alert rules",
|
||||
"dashboards": "Dashboards",
|
||||
|
||||
@@ -66,6 +66,13 @@
|
||||
"manage-permissions": "",
|
||||
"move": ""
|
||||
},
|
||||
"folder-picker": {
|
||||
"button-label": "",
|
||||
"empty-message": "",
|
||||
"error-title": "",
|
||||
"search-placeholder": "",
|
||||
"unknown-error": ""
|
||||
},
|
||||
"manage-folder-nav": {
|
||||
"alert-rules": "",
|
||||
"dashboards": "",
|
||||
|
||||
@@ -66,6 +66,13 @@
|
||||
"manage-permissions": "",
|
||||
"move": ""
|
||||
},
|
||||
"folder-picker": {
|
||||
"button-label": "",
|
||||
"empty-message": "",
|
||||
"error-title": "",
|
||||
"search-placeholder": "",
|
||||
"unknown-error": ""
|
||||
},
|
||||
"manage-folder-nav": {
|
||||
"alert-rules": "",
|
||||
"dashboards": "",
|
||||
|
||||
@@ -61,6 +61,13 @@
|
||||
"manage-permissions": "Mäʼnäģę pęřmįşşįőʼnş",
|
||||
"move": "Mővę"
|
||||
},
|
||||
"folder-picker": {
|
||||
"button-label": "Ŝęľęčŧ ƒőľđęř",
|
||||
"empty-message": "Ńő ƒőľđęřş ƒőūʼnđ",
|
||||
"error-title": "Ēřřőř ľőäđįʼnģ ƒőľđęřş",
|
||||
"search-placeholder": "Ŝęäřčĥ ƒőľđęřş",
|
||||
"unknown-error": "Ůʼnĸʼnőŵʼn ęřřőř"
|
||||
},
|
||||
"manage-folder-nav": {
|
||||
"alert-rules": "Åľęřŧ řūľęş",
|
||||
"dashboards": "Đäşĥþőäřđş",
|
||||
|
||||
@@ -56,6 +56,13 @@
|
||||
"manage-permissions": "",
|
||||
"move": ""
|
||||
},
|
||||
"folder-picker": {
|
||||
"button-label": "",
|
||||
"empty-message": "",
|
||||
"error-title": "",
|
||||
"search-placeholder": "",
|
||||
"unknown-error": ""
|
||||
},
|
||||
"manage-folder-nav": {
|
||||
"alert-rules": "",
|
||||
"dashboards": "",
|
||||
|
||||
Reference in New Issue
Block a user