mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
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
This commit is contained in:
parent
5416444484
commit
8f4b76a3de
@ -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}
|
||||
/>
|
||||
<div>
|
||||
<FilterInput
|
||||
placeholder={t('recentlyDeleted.filter.placeholder', 'Search for dashboards')}
|
||||
value={searchState.query}
|
||||
escapeRegex={false}
|
||||
onChange={stateManager.onQueryChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<RecentlyDeletedActions />
|
||||
{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…
Reference in New Issue
Block a user