|
|
|
@ -3,9 +3,9 @@ import { Link } from 'react-router-dom'; |
|
|
|
|
|
|
|
|
|
import { GrafanaTheme2, Scope, urlUtil } from '@grafana/data'; |
|
|
|
|
import { SceneComponentProps, SceneObjectBase, SceneObjectState } from '@grafana/scenes'; |
|
|
|
|
import { CustomScrollbar, FilterInput, LoadingPlaceholder, useStyles2 } from '@grafana/ui'; |
|
|
|
|
import { Button, CustomScrollbar, FilterInput, LoadingPlaceholder, useStyles2 } from '@grafana/ui'; |
|
|
|
|
import { useQueryParams } from 'app/core/hooks/useQueryParams'; |
|
|
|
|
import { t } from 'app/core/internationalization'; |
|
|
|
|
import { t, Trans } from 'app/core/internationalization'; |
|
|
|
|
|
|
|
|
|
import { fetchSuggestedDashboards } from './api'; |
|
|
|
|
import { SuggestedDashboard } from './types'; |
|
|
|
@ -14,6 +14,7 @@ export interface ScopesDashboardsSceneState extends SceneObjectState { |
|
|
|
|
dashboards: SuggestedDashboard[]; |
|
|
|
|
filteredDashboards: SuggestedDashboard[]; |
|
|
|
|
isLoading: boolean; |
|
|
|
|
scopesSelected: boolean; |
|
|
|
|
searchQuery: string; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -25,13 +26,14 @@ export class ScopesDashboardsScene extends SceneObjectBase<ScopesDashboardsScene |
|
|
|
|
dashboards: [], |
|
|
|
|
filteredDashboards: [], |
|
|
|
|
isLoading: false, |
|
|
|
|
scopesSelected: false, |
|
|
|
|
searchQuery: '', |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public async fetchDashboards(scopes: Scope[]) { |
|
|
|
|
if (scopes.length === 0) { |
|
|
|
|
return this.setState({ dashboards: [], filteredDashboards: [], isLoading: false }); |
|
|
|
|
return this.setState({ dashboards: [], filteredDashboards: [], isLoading: false, scopesSelected: false }); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.setState({ isLoading: true }); |
|
|
|
@ -42,6 +44,7 @@ export class ScopesDashboardsScene extends SceneObjectBase<ScopesDashboardsScene |
|
|
|
|
dashboards, |
|
|
|
|
filteredDashboards: this.filterDashboards(dashboards, this.state.searchQuery), |
|
|
|
|
isLoading: false, |
|
|
|
|
scopesSelected: scopes.length > 0, |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -62,11 +65,29 @@ export class ScopesDashboardsScene extends SceneObjectBase<ScopesDashboardsScene |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
export function ScopesDashboardsSceneRenderer({ model }: SceneComponentProps<ScopesDashboardsScene>) { |
|
|
|
|
const { filteredDashboards, isLoading, searchQuery } = model.useState(); |
|
|
|
|
const { dashboards, filteredDashboards, isLoading, searchQuery, scopesSelected } = model.useState(); |
|
|
|
|
const styles = useStyles2(getStyles); |
|
|
|
|
|
|
|
|
|
const [queryParams] = useQueryParams(); |
|
|
|
|
|
|
|
|
|
if (!isLoading) { |
|
|
|
|
if (!scopesSelected) { |
|
|
|
|
return ( |
|
|
|
|
<p className={styles.noResultsContainer} data-testid="scopes-dashboards-notFoundNoScopes"> |
|
|
|
|
<Trans i18nKey="scopes.suggestedDashboards.noResultsNoScopes">No scopes selected</Trans> |
|
|
|
|
</p> |
|
|
|
|
); |
|
|
|
|
} else if (dashboards.length === 0) { |
|
|
|
|
return ( |
|
|
|
|
<p className={styles.noResultsContainer} data-testid="scopes-dashboards-notFoundForScope"> |
|
|
|
|
<Trans i18nKey="scopes.suggestedDashboards.noResultsForScopes"> |
|
|
|
|
No dashboards found for the selected scopes |
|
|
|
|
</Trans> |
|
|
|
|
</p> |
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
|
<> |
|
|
|
|
<div className={styles.searchInputContainer}> |
|
|
|
@ -85,7 +106,7 @@ export function ScopesDashboardsSceneRenderer({ model }: SceneComponentProps<Sco |
|
|
|
|
text={t('scopes.suggestedDashboards.loading', 'Loading dashboards')} |
|
|
|
|
data-testid="scopes-dashboards-loading" |
|
|
|
|
/> |
|
|
|
|
) : ( |
|
|
|
|
) : filteredDashboards.length > 0 ? ( |
|
|
|
|
<CustomScrollbar> |
|
|
|
|
{filteredDashboards.map(({ dashboard, dashboardTitle }) => ( |
|
|
|
|
<Link |
|
|
|
@ -98,6 +119,18 @@ export function ScopesDashboardsSceneRenderer({ model }: SceneComponentProps<Sco |
|
|
|
|
</Link> |
|
|
|
|
))} |
|
|
|
|
</CustomScrollbar> |
|
|
|
|
) : ( |
|
|
|
|
<p className={styles.noResultsContainer} data-testid="scopes-dashboards-notFoundForFilter"> |
|
|
|
|
<Trans i18nKey="scopes.suggestedDashboards.noResultsForFilter">No results found for your query</Trans> |
|
|
|
|
|
|
|
|
|
<Button |
|
|
|
|
variant="secondary" |
|
|
|
|
onClick={() => model.changeSearchQuery('')} |
|
|
|
|
data-testid="scopes-dashboards-notFoundForFilter-clear" |
|
|
|
|
> |
|
|
|
|
<Trans i18nKey="scopes.suggestedDashboards.noResultsForFilterClear">Clear search</Trans> |
|
|
|
|
</Button> |
|
|
|
|
</p> |
|
|
|
|
)} |
|
|
|
|
</> |
|
|
|
|
); |
|
|
|
@ -105,6 +138,14 @@ export function ScopesDashboardsSceneRenderer({ model }: SceneComponentProps<Sco |
|
|
|
|
|
|
|
|
|
const getStyles = (theme: GrafanaTheme2) => { |
|
|
|
|
return { |
|
|
|
|
noResultsContainer: css({ |
|
|
|
|
alignItems: 'center', |
|
|
|
|
display: 'flex', |
|
|
|
|
flexDirection: 'column', |
|
|
|
|
gap: theme.spacing(1), |
|
|
|
|
justifyContent: 'center', |
|
|
|
|
textAlign: 'center', |
|
|
|
|
}), |
|
|
|
|
searchInputContainer: css({ |
|
|
|
|
flex: '0 1 auto', |
|
|
|
|
}), |
|
|
|
|