RestoreDashboards: Hide restore/delete actions when no items are selected (#90431)

* RecentlyDeleted: Only show actions when items selected

* RestoreDashboards: Hide actions when no items are selected
pull/90002/head
Josh Hunt 12 months ago committed by GitHub
parent 5416444484
commit 8f4b76a3de
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 4
      .betterer.results
  2. 36
      public/app/features/browse-dashboards/BrowseDashboardsPage.tsx
  3. 64
      public/app/features/browse-dashboards/RecentlyDeletedPage.tsx
  4. 18
      public/app/features/browse-dashboards/components/BrowseActions/BrowseActions.tsx
  5. 32
      public/app/features/browse-dashboards/components/BrowseFilters.tsx
  6. 23
      public/app/features/browse-dashboards/components/RecentlyDeletedActions.tsx
  7. 25
      public/app/features/search/page/components/ActionRow.tsx

@ -5231,9 +5231,7 @@ exports[`better eslint`] = {
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "2"]
],
"public/app/features/search/page/components/ActionRow.tsx:5381": [
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"],
[0, 0, 0, "Styles should be written using objects.", "1"],
[0, 0, 0, "Styles should be written using objects.", "2"]
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"]
],
"public/app/features/search/page/components/SearchResultsTable.tsx:5381": [
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"],

@ -130,14 +130,22 @@ const BrowseDashboardsPage = memo(({ match }: Props) => {
}
>
<Page.Contents className={styles.pageContents}>
<FilterInput
placeholder={getSearchPlaceholder(searchState.includePanels)}
value={searchState.query}
escapeRegex={false}
onChange={(e) => stateManager.onQueryChange(e)}
/>
<div>
<FilterInput
placeholder={getSearchPlaceholder(searchState.includePanels)}
value={searchState.query}
escapeRegex={false}
onChange={(e) => stateManager.onQueryChange(e)}
/>
</div>
{hasSelection ? <BrowseActions /> : <BrowseFilters />}
{hasSelection ? (
<BrowseActions />
) : (
<div className={styles.filters}>
<BrowseFilters />
</div>
)}
<div className={styles.subView}>
<AutoSizer>
@ -163,16 +171,24 @@ const BrowseDashboardsPage = memo(({ match }: Props) => {
const getStyles = (theme: GrafanaTheme2) => ({
pageContents: css({
display: 'grid',
gridTemplateRows: 'auto auto 1fr',
display: 'flex',
flexDirection: 'column',
gap: theme.spacing(1),
height: '100%',
rowGap: theme.spacing(1),
}),
// AutoSizer needs an element to measure the full height available
subView: css({
height: '100%',
}),
filters: css({
display: 'none',
[theme.breakpoints.up('md')]: {
display: 'block',
},
}),
});
BrowseDashboardsPage.displayName = 'BrowseDashboardsPage';

@ -16,13 +16,14 @@ import { RecentlyDeletedActions } from './components/RecentlyDeletedActions';
import { RecentlyDeletedEmptyState } from './components/RecentlyDeletedEmptyState';
import { SearchView } from './components/SearchView';
import { getFolderPermissions } from './permissions';
import { setAllSelection } from './state';
import { setAllSelection, useHasSelection } from './state';
const RecentlyDeletedPage = memo(() => {
const dispatch = useDispatch();
const styles = useStyles2(getStyles);
const [searchState, stateManager] = useRecentlyDeletedStateManager();
const hasSelection = useHasSelection();
const { canEditFolders, canEditDashboards } = getFolderPermissions();
const canSelect = canEditFolders || canEditDashboards;
@ -42,26 +43,33 @@ const RecentlyDeletedPage = memo(() => {
return (
<Page navId="dashboards/recently-deleted">
<Page.Contents className={styles.pageContents}>
<FilterInput
placeholder={t('recentlyDeleted.filter.placeholder', 'Search for dashboards')}
value={searchState.query}
escapeRegex={false}
onChange={stateManager.onQueryChange}
/>
<ActionRow
state={searchState}
getTagOptions={stateManager.getTagOptions}
getSortOptions={getGrafanaSearcher().getSortOptions}
sortPlaceholder={getGrafanaSearcher().sortPlaceholder}
onLayoutChange={stateManager.onLayoutChange}
onSortChange={stateManager.onSortChange}
onTagFilterChange={stateManager.onTagFilterChange}
onDatasourceChange={stateManager.onDatasourceChange}
onPanelTypeChange={stateManager.onPanelTypeChange}
onSetIncludePanels={stateManager.onSetIncludePanels}
/>
<RecentlyDeletedActions />
<div>
<FilterInput
placeholder={t('recentlyDeleted.filter.placeholder', 'Search for dashboards')}
value={searchState.query}
escapeRegex={false}
onChange={stateManager.onQueryChange}
/>
</div>
{hasSelection ? (
<RecentlyDeletedActions />
) : (
<div className={styles.filters}>
<ActionRow
state={searchState}
getTagOptions={stateManager.getTagOptions}
getSortOptions={getGrafanaSearcher().getSortOptions}
sortPlaceholder={getGrafanaSearcher().sortPlaceholder}
onLayoutChange={stateManager.onLayoutChange}
onSortChange={stateManager.onSortChange}
onTagFilterChange={stateManager.onTagFilterChange}
onDatasourceChange={stateManager.onDatasourceChange}
onPanelTypeChange={stateManager.onPanelTypeChange}
onSetIncludePanels={stateManager.onSetIncludePanels}
/>
</div>
)}
<div className={styles.subView}>
<AutoSizer>
@ -84,16 +92,24 @@ const RecentlyDeletedPage = memo(() => {
const getStyles = (theme: GrafanaTheme2) => ({
pageContents: css({
display: 'grid',
gridTemplateRows: 'auto auto auto 1fr',
display: 'flex',
flexDirection: 'column',
gap: theme.spacing(1),
height: '100%',
rowGap: theme.spacing(1),
}),
// AutoSizer needs an element to measure the full height available
subView: css({
height: '100%',
}),
filters: css({
display: 'none',
[theme.breakpoints.up('md')]: {
display: 'block',
},
}),
});
RecentlyDeletedPage.displayName = 'RecentlyDeletedPage';

@ -1,9 +1,7 @@
import { css } from '@emotion/css';
import { useMemo } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { config, reportInteraction } from '@grafana/runtime';
import { Button, Tooltip, useStyles2 } from '@grafana/ui';
import { Button, Stack, Tooltip } from '@grafana/ui';
import appEvents from 'app/core/app_events';
import { t, Trans } from 'app/core/internationalization';
import { useSearchStateManager } from 'app/features/search/state/SearchStateManager';
@ -20,7 +18,6 @@ import { MoveModal } from './MoveModal';
export interface Props {}
export function BrowseActions() {
const styles = useStyles2(getStyles);
const dispatch = useDispatch();
const selectedItems = useActionSelectionState();
const [deleteItems] = useDeleteItemsMutation();
@ -87,7 +84,7 @@ export function BrowseActions() {
);
return (
<div className={styles.row} data-testid="manage-actions">
<Stack gap={1} data-testid="manage-actions">
{moveIsInvalid ? (
<Tooltip content={t('browse-dashboards.action.cannot-move-folders', 'Folders cannot be moved')}>
{moveButton}
@ -99,19 +96,10 @@ export function BrowseActions() {
<Button onClick={showDeleteModal} variant="destructive">
<Trans i18nKey="browse-dashboards.action.delete-button">Delete</Trans>
</Button>
</div>
</Stack>
);
}
const getStyles = (theme: GrafanaTheme2) => ({
row: css({
display: 'flex',
flexDirection: 'row',
gap: theme.spacing(1),
marginBottom: theme.spacing(2),
}),
});
const actionMap = {
move: 'grafana_manage_dashboards_item_moved',
delete: 'grafana_manage_dashboards_item_deleted',

@ -6,22 +6,20 @@ export function BrowseFilters() {
const [searchState, stateManager] = useSearchStateManager();
return (
<div>
<ActionRow
showStarredFilter
showLayout
state={searchState}
getTagOptions={stateManager.getTagOptions}
getSortOptions={getGrafanaSearcher().getSortOptions}
sortPlaceholder={getGrafanaSearcher().sortPlaceholder}
onLayoutChange={stateManager.onLayoutChange}
onStarredFilterChange={stateManager.onStarredFilterChange}
onSortChange={stateManager.onSortChange}
onTagFilterChange={stateManager.onTagFilterChange}
onDatasourceChange={stateManager.onDatasourceChange}
onPanelTypeChange={stateManager.onPanelTypeChange}
onSetIncludePanels={stateManager.onSetIncludePanels}
/>
</div>
<ActionRow
showStarredFilter
showLayout
state={searchState}
getTagOptions={stateManager.getTagOptions}
getSortOptions={getGrafanaSearcher().getSortOptions}
sortPlaceholder={getGrafanaSearcher().sortPlaceholder}
onLayoutChange={stateManager.onLayoutChange}
onStarredFilterChange={stateManager.onStarredFilterChange}
onSortChange={stateManager.onSortChange}
onTagFilterChange={stateManager.onTagFilterChange}
onDatasourceChange={stateManager.onDatasourceChange}
onPanelTypeChange={stateManager.onPanelTypeChange}
onSetIncludePanels={stateManager.onSetIncludePanels}
/>
);
}

@ -1,9 +1,7 @@
import { css } from '@emotion/css';
import { useMemo } from 'react';
import { GrafanaTheme2 } from '@grafana/data/';
import { reportInteraction } from '@grafana/runtime';
import { Button, useStyles2 } from '@grafana/ui';
import { Button, Stack } from '@grafana/ui';
import { GENERAL_FOLDER_UID } from 'app/features/search/constants';
import appEvents from '../../../core/app_events';
@ -18,8 +16,6 @@ import { PermanentlyDeleteModal } from './PermanentlyDeleteModal';
import { RestoreModal } from './RestoreModal';
export function RecentlyDeletedActions() {
const styles = useStyles2(getStyles);
const dispatch = useDispatch();
const selectedItemsState = useActionSelectionState();
const [, stateManager] = useRecentlyDeletedStateManager();
@ -112,26 +108,13 @@ export function RecentlyDeletedActions() {
};
return (
<div className={styles.row}>
<Stack gap={1}>
<Button onClick={showRestoreModal} variant="secondary">
<Trans i18nKey="recently-deleted.buttons.restore">Restore</Trans>
</Button>
<Button onClick={showDeleteModal} variant="destructive">
<Trans i18nKey="recently-deleted.buttons.delete">Delete permanently</Trans>
</Button>
</div>
</Stack>
);
}
const getStyles = (theme: GrafanaTheme2) => ({
row: css({
display: 'flex',
flexDirection: 'row',
gap: theme.spacing(1),
margin: theme.spacing(2, 0),
[theme.breakpoints.up('md')]: {
marginTop: 0,
},
}),
});

@ -76,7 +76,7 @@ export const ActionRow = ({
: [];
return (
<div className={styles.actionRow}>
<Stack justifyContent="space-between" alignItems="center">
<Stack gap={2} alignItems="center">
<TagFilter isClearable={false} tags={state.tag} tagOptions={getTagOptions} onChange={onTagFilterChange} />
{config.featureToggles.panelTitleSearch && (
@ -129,7 +129,7 @@ export const ActionRow = ({
isClearable
/>
</Stack>
</div>
</Stack>
);
};
@ -137,21 +137,10 @@ ActionRow.displayName = 'ActionRow';
export const getStyles = (theme: GrafanaTheme2) => {
return {
actionRow: css`
display: none;
${theme.breakpoints.up('md')} {
display: flex;
justify-content: space-between;
align-items: center;
padding-bottom: ${theme.spacing(2)};
width: 100%;
}
`,
checkboxWrapper: css`
label {
line-height: 1.2;
}
`,
checkboxWrapper: css({
label: {
lineHeight: '1.2',
},
}),
};
};

Loading…
Cancel
Save