re-org components
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
import { css } from '@emotion/css';
|
||||
import { memo, useCallback } from 'react';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { Trans } from '@grafana/i18n';
|
||||
import { VizPanel } from '@grafana/scenes';
|
||||
import { Container, ScrollContainer, useStyles2 } from '@grafana/ui';
|
||||
|
||||
import { PanelDataTransformationsTab, PanelDataTransformationsTabRendered } from './PanelDataTransformationsTab';
|
||||
import { QueryDetailView } from './QueryDetailView';
|
||||
import { QueryTransformItem } from './QueryTransformList';
|
||||
import { TabId } from './types';
|
||||
|
||||
interface DetailViewProps {
|
||||
selectedItem: QueryTransformItem | undefined;
|
||||
panel: VizPanel;
|
||||
tabs: Array<{ tabId: TabId }>;
|
||||
}
|
||||
|
||||
export const DetailView = memo(({ selectedItem, panel, tabs }: DetailViewProps) => {
|
||||
const styles = useStyles2(getStyles);
|
||||
|
||||
const renderContent = useCallback(() => {
|
||||
if (!selectedItem) {
|
||||
return (
|
||||
<div className={styles.emptyState}>
|
||||
<p>
|
||||
<Trans i18nKey="dashboard-scene.panel-data-pane.empty-state">
|
||||
Select a query or transformation to edit
|
||||
</Trans>
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (selectedItem.type === 'query' && 'refId' in selectedItem.data) {
|
||||
const query = selectedItem.data;
|
||||
return (
|
||||
<ScrollContainer>
|
||||
<QueryDetailView panel={panel} query={query} queryIndex={selectedItem.index} />
|
||||
</ScrollContainer>
|
||||
);
|
||||
} else {
|
||||
const transformsTab = tabs.find((t) => t.tabId === TabId.Transformations);
|
||||
if (transformsTab instanceof PanelDataTransformationsTab && 'id' in selectedItem.data) {
|
||||
return (
|
||||
<ScrollContainer>
|
||||
<Container>
|
||||
<PanelDataTransformationsTabRendered model={transformsTab} />
|
||||
</Container>
|
||||
</ScrollContainer>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}, [selectedItem, panel, tabs, styles.emptyState]);
|
||||
|
||||
return <div className={styles.container}>{renderContent()}</div>;
|
||||
});
|
||||
|
||||
DetailView.displayName = 'DetailView';
|
||||
|
||||
const getStyles = (theme: GrafanaTheme2) => {
|
||||
return {
|
||||
container: css({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
height: '100%',
|
||||
background: theme.colors.background.primary,
|
||||
}),
|
||||
emptyState: css({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
height: '100%',
|
||||
color: theme.colors.text.secondary,
|
||||
fontSize: theme.typography.h5.fontSize,
|
||||
}),
|
||||
};
|
||||
};
|
||||
@@ -3,7 +3,6 @@ import { useCallback, useMemo, useState } from 'react';
|
||||
|
||||
import { DataTransformerConfig, GrafanaTheme2, SelectableValue } from '@grafana/data';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import { Trans } from '@grafana/i18n';
|
||||
import {
|
||||
SceneComponentProps,
|
||||
SceneObjectBase,
|
||||
@@ -14,7 +13,7 @@ import {
|
||||
VizPanel,
|
||||
SceneDataTransformer,
|
||||
} from '@grafana/scenes';
|
||||
import { Container, ScrollContainer, useStyles2 } from '@grafana/ui';
|
||||
import { useStyles2 } from '@grafana/ui';
|
||||
import { getConfig } from 'app/core/config';
|
||||
import { contextSrv } from 'app/core/services/context_srv';
|
||||
import { getRulesPermissions } from 'app/features/alerting/unified/utils/access-control';
|
||||
@@ -22,11 +21,11 @@ import { GRAFANA_RULES_SOURCE_NAME } from 'app/features/alerting/unified/utils/d
|
||||
|
||||
import { getQueryRunnerFor } from '../../utils/utils';
|
||||
|
||||
import { DetailView } from './DetailView';
|
||||
import { PanelDataAlertingTab } from './PanelDataAlertingTab';
|
||||
import { PanelDataQueriesTab } from './PanelDataQueriesTab';
|
||||
import { PanelDataTransformationsTab, PanelDataTransformationsTabRendered } from './PanelDataTransformationsTab';
|
||||
import { PanelDataTransformationsTab } from './PanelDataTransformationsTab';
|
||||
import { QueryTransformList, QueryTransformItem } from './QueryTransformList';
|
||||
import { SceneQueryDetailView } from './SceneQueryDetailView';
|
||||
import { TransformationsDrawer } from './TransformationsDrawer';
|
||||
import { PanelDataPaneTab, TabId } from './types';
|
||||
|
||||
@@ -286,46 +285,6 @@ function PanelDataPaneRendered({ model }: SceneComponentProps<PanelDataPane>) {
|
||||
[tabs, selectedId]
|
||||
);
|
||||
|
||||
const renderDetailPanel = useCallback(() => {
|
||||
if (!selectedItem) {
|
||||
return (
|
||||
<div className={styles.emptyState}>
|
||||
<p>
|
||||
<Trans i18nKey="dashboard-scene.panel-data-pane.empty-state">
|
||||
Select a query or transformation to edit
|
||||
</Trans>
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (selectedItem.type === 'query' && 'refId' in selectedItem.data) {
|
||||
const query = selectedItem.data;
|
||||
return (
|
||||
<div className={styles.detailContent}>
|
||||
<ScrollContainer>
|
||||
<SceneQueryDetailView panel={panel} query={query} queryIndex={selectedItem.index} />
|
||||
</ScrollContainer>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
const transformsTab = tabs.find((t) => t.tabId === TabId.Transformations);
|
||||
if (transformsTab instanceof PanelDataTransformationsTab && 'id' in selectedItem.data) {
|
||||
return (
|
||||
<div className={styles.detailContent}>
|
||||
<ScrollContainer>
|
||||
<Container>
|
||||
<PanelDataTransformationsTabRendered model={transformsTab} />
|
||||
</Container>
|
||||
</ScrollContainer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}, [selectedItem, tabs, styles, panel]);
|
||||
|
||||
// Get data for transformations drawer
|
||||
const sourceData = queryRunner?.useState();
|
||||
const series = sourceData?.data?.series || [];
|
||||
@@ -347,7 +306,9 @@ function PanelDataPaneRendered({ model }: SceneComponentProps<PanelDataPane>) {
|
||||
onRemoveTransform={handleRemoveTransform}
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.rightPanel}>{renderDetailPanel()}</div>
|
||||
<div className={styles.rightPanel}>
|
||||
<DetailView selectedItem={selectedItem} panel={panel} tabs={tabs} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<TransformationsDrawer
|
||||
@@ -411,40 +372,5 @@ function getStyles(theme: GrafanaTheme2) {
|
||||
minWidth: 0,
|
||||
overflow: 'hidden',
|
||||
}),
|
||||
detailContent: css({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
height: '100%',
|
||||
background: theme.colors.background.primary,
|
||||
}),
|
||||
detailHeader: css({
|
||||
padding: theme.spacing(2),
|
||||
borderBottom: `1px solid ${theme.colors.border.weak}`,
|
||||
background: theme.colors.background.secondary,
|
||||
'& h3': {
|
||||
margin: 0,
|
||||
marginBottom: theme.spacing(0.5),
|
||||
fontSize: theme.typography.h4.fontSize,
|
||||
fontWeight: theme.typography.fontWeightMedium,
|
||||
},
|
||||
}),
|
||||
detailHeaderSubtext: css({
|
||||
margin: 0,
|
||||
fontSize: theme.typography.bodySmall.fontSize,
|
||||
color: theme.colors.text.secondary,
|
||||
}),
|
||||
detailBody: css({
|
||||
flex: 1,
|
||||
overflow: 'auto',
|
||||
minHeight: 0,
|
||||
}),
|
||||
emptyState: css({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
height: '100%',
|
||||
color: theme.colors.text.secondary,
|
||||
fontSize: theme.typography.h5.fontSize,
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
+5
-5
@@ -21,13 +21,13 @@ import { QueryErrorAlert } from 'app/features/query/components/QueryErrorAlert';
|
||||
|
||||
import { getQueryRunnerFor } from '../../utils/utils';
|
||||
|
||||
interface SceneQueryDetailViewProps {
|
||||
interface QueryDetailViewProps {
|
||||
panel: VizPanel;
|
||||
query: SceneDataQuery;
|
||||
queryIndex: number;
|
||||
}
|
||||
|
||||
export function SceneQueryDetailView({ panel, query, queryIndex }: SceneQueryDetailViewProps) {
|
||||
export function QueryDetailView({ panel, query, queryIndex }: QueryDetailViewProps) {
|
||||
const styles = useStyles2(getStyles);
|
||||
const [datasource, setDatasource] = useState<DataSourceApi | null>(null);
|
||||
const [dsSettings, setDsSettings] = useState<DataSourceInstanceSettings | null>(null);
|
||||
@@ -129,7 +129,7 @@ export function SceneQueryDetailView({ panel, query, queryIndex }: SceneQueryDet
|
||||
if (!datasource || !dsSettings) {
|
||||
return (
|
||||
<div className={styles.noEditor}>
|
||||
<Trans i18nKey="dashboard-scene.scene-query-detail-view.loading">Loading data source...</Trans>
|
||||
<Trans i18nKey="dashboard-scene.query-detail-view.loading">Loading data source...</Trans>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -138,7 +138,7 @@ export function SceneQueryDetailView({ panel, query, queryIndex }: SceneQueryDet
|
||||
if (!QueryEditor) {
|
||||
return (
|
||||
<div className={styles.noEditor}>
|
||||
<Trans i18nKey="dashboard-scene.scene-query-detail-view.no-editor">
|
||||
<Trans i18nKey="dashboard-scene.query-detail-view.no-editor">
|
||||
This data source does not have a query editor
|
||||
</Trans>
|
||||
</div>
|
||||
@@ -170,7 +170,7 @@ export function SceneQueryDetailView({ panel, query, queryIndex }: SceneQueryDet
|
||||
<DataSourcePicker
|
||||
current={dsSettings?.uid || query.datasource}
|
||||
onChange={handleDataSourceChange}
|
||||
placeholder={t('dashboard-scene.scene-query-detail-view.select-datasource', 'Select data source')}
|
||||
placeholder={t('dashboard-scene.query-detail-view.select-datasource', 'Select data source')}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -6235,6 +6235,11 @@
|
||||
"see-docs": "See <2>documentation</2> for more information about provisioning.",
|
||||
"title-cannot-delete-provisioned-dashboard": "Cannot delete provisioned dashboard"
|
||||
},
|
||||
"query-detail-view": {
|
||||
"loading": "Loading data source...",
|
||||
"no-editor": "This data source does not have a query editor",
|
||||
"select-datasource": "Select data source"
|
||||
},
|
||||
"query-editor": {
|
||||
"query": "Query"
|
||||
},
|
||||
@@ -6359,11 +6364,6 @@
|
||||
"title-same-as-folder": "Dashboard name cannot be the same as the folder name",
|
||||
"title-validation-failed": "Dashboard title validation failed."
|
||||
},
|
||||
"scene-query-detail-view": {
|
||||
"loading": "Loading data source...",
|
||||
"no-editor": "This data source does not have a query editor",
|
||||
"select-datasource": "Select data source"
|
||||
},
|
||||
"scenes-new-rule-from-panel-button": {
|
||||
"body-no-alerting-capable-query-found": "Cannot create alerts from this panel because no query to an alerting capable datasource is found.",
|
||||
"new-alert-rule": "New alert rule",
|
||||
|
||||
Reference in New Issue
Block a user