Cleanup: Remove CSV drag-and-drop snapshot query feature (#113645)

* Chore: Remove editPanelCSVDragAndDrop feature

* update i18n

* fix issues from PR
This commit is contained in:
Paul Marbach
2025-11-12 09:47:44 -05:00
committed by GitHub
parent d83c35fd71
commit 4b1fbcbd04
15 changed files with 17 additions and 334 deletions
-4
View File
@@ -84,10 +84,6 @@ export interface FeatureToggles {
*/
alertingBacktesting?: boolean;
/**
* Enables drag and drop for CSV and Excel files
*/
editPanelCSVDragAndDrop?: boolean;
/**
* Allow datasource to provide custom UI for context view
* @default true
*/
-7
View File
@@ -124,13 +124,6 @@ var (
Stage: FeatureStageExperimental,
Owner: grafanaAlertingSquad,
},
{
Name: "editPanelCSVDragAndDrop",
Description: "Enables drag and drop for CSV and Excel files",
FrontendOnly: true,
Stage: FeatureStageExperimental,
Owner: grafanaDatavizSquad,
},
{
Name: "logsContextDatasourceUi",
Description: "Allow datasource to provide custom UI for context view",
-1
View File
@@ -14,7 +14,6 @@ cloudWatchCrossAccountQuerying,GA,@grafana/aws-datasources,false,false,false
showDashboardValidationWarnings,experimental,@grafana/dashboards-squad,false,false,false
mysqlAnsiQuotes,experimental,@grafana/search-and-storage,false,false,false
alertingBacktesting,experimental,@grafana/alerting-squad,false,false,false
editPanelCSVDragAndDrop,experimental,@grafana/dataviz-squad,false,false,true
logsContextDatasourceUi,GA,@grafana/observability-logs,false,false,true
lokiShardSplitting,experimental,@grafana/observability-logs,false,false,true
lokiQuerySplitting,GA,@grafana/observability-logs,false,false,true
1 Name Stage Owner requiresDevMode RequiresRestart FrontendOnly
14 showDashboardValidationWarnings experimental @grafana/dashboards-squad false false false
15 mysqlAnsiQuotes experimental @grafana/search-and-storage false false false
16 alertingBacktesting experimental @grafana/alerting-squad false false false
editPanelCSVDragAndDrop experimental @grafana/dataviz-squad false false true
17 logsContextDatasourceUi GA @grafana/observability-logs false false true
18 lokiShardSplitting experimental @grafana/observability-logs false false true
19 lokiQuerySplitting GA @grafana/observability-logs false false true
-4
View File
@@ -67,10 +67,6 @@ const (
// Rule backtesting API for alerting
FlagAlertingBacktesting = "alertingBacktesting"
// FlagEditPanelCSVDragAndDrop
// Enables drag and drop for CSV and Excel files
FlagEditPanelCSVDragAndDrop = "editPanelCSVDragAndDrop"
// FlagLogsContextDatasourceUi
// Allow datasource to provide custom UI for context view
FlagLogsContextDatasourceUi = "logsContextDatasourceUi"
@@ -1357,6 +1357,7 @@
"name": "editPanelCSVDragAndDrop",
"resourceVersion": "1762783224740",
"creationTimestamp": "2023-01-24T09:43:44Z",
"deletionTimestamp": "2025-11-10T16:31:10Z",
"annotations": {
"grafana.app/updatedTimestamp": "2025-11-10 14:00:24.740459 +0000 UTC"
}
@@ -1,9 +0,0 @@
import { Accept } from 'react-dropzone';
export const acceptedFiles: Accept = {
'text/plain': ['.csv', '.txt'],
'application/json': ['.json'],
};
//This should probably set from grafana conf
export const maxFileSize = 500000;
@@ -1,4 +1,4 @@
import { queryByTestId, render, screen } from '@testing-library/react';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import {
@@ -9,7 +9,6 @@ import {
PluginType,
locationUtil,
} from '@grafana/data';
import { config } from '@grafana/runtime';
import { DataSourceModal, DataSourceModalProps } from './DataSourceModal';
@@ -106,44 +105,6 @@ describe('DataSourceDropdown', () => {
});
});
it('only displays the file drop area when the ff is enabled', async () => {
const defaultValue = config.featureToggles.editPanelCSVDragAndDrop;
config.featureToggles.editPanelCSVDragAndDrop = true;
setup({ uploadFile: true });
expect(await screen.queryByTestId('file-drop-zone-default-children')).toBeInTheDocument();
config.featureToggles.editPanelCSVDragAndDrop = defaultValue;
});
it('does not show the file drop area when the ff is disabled', async () => {
const defaultValue = config.featureToggles.editPanelCSVDragAndDrop;
config.featureToggles.editPanelCSVDragAndDrop = false;
setup({ uploadFile: true });
expect(await screen.queryByTestId('file-drop-zone-default-children')).toBeNull();
config.featureToggles.editPanelCSVDragAndDrop = defaultValue;
});
it('should not display the drop zone by default', async () => {
const defaultValue = config.featureToggles.editPanelCSVDragAndDrop;
config.featureToggles.editPanelCSVDragAndDrop = true;
const component = setup();
expect(queryByTestId(component.container, 'file-drop-zone-default-children')).toBeNull();
config.featureToggles.editPanelCSVDragAndDrop = defaultValue;
});
it('should display the drop zone when uploadFile is enabled', async () => {
const defaultValue = config.featureToggles.editPanelCSVDragAndDrop;
config.featureToggles.editPanelCSVDragAndDrop = true;
setup({ uploadFile: true });
expect(await screen.queryByTestId('file-drop-zone-default-children')).toBeInTheDocument();
config.featureToggles.editPanelCSVDragAndDrop = defaultValue;
});
it('should fetch the DS applying the correct filters consistently across lists', async () => {
const filters = {
mixed: true,
@@ -197,29 +158,6 @@ describe('DataSourceDropdown', () => {
expect(await screen.findByText('No data sources found')).toBeInTheDocument();
});
//Skipping this test as it's flaky on drone
it.skip('calls the onChange with the default query containing the file', async () => {
const user = userEvent.setup();
config.featureToggles.editPanelCSVDragAndDrop = true;
const onChange = jest.fn();
setup({ onChange, uploadFile: true });
const fileInput = (
await screen.queryByTestId('file-drop-zone-default-children')!
).parentElement!.parentElement!.querySelector('input');
const file = new File([''], 'test.csv', { type: 'text/plain' });
expect(fileInput).toBeInTheDocument();
await user.upload(fileInput!, file);
const defaultQuery = onChange.mock.lastCall[1][0];
expect(defaultQuery).toMatchObject({
refId: 'A',
datasource: { type: 'grafana', uid: 'grafana' },
queryType: 'snapshot',
file: { path: 'test.csv' },
});
config.featureToggles.editPanelCSVDragAndDrop = false;
});
it('should call the onChange handler with the correct datasource', async () => {
const user = userEvent.setup();
const onChange = jest.fn();
@@ -4,22 +4,12 @@ import { useEffect, useMemo, useState } from 'react';
import { DataSourceInstanceSettings, DataSourceRef, GrafanaTheme2 } from '@grafana/data';
import { Trans, t } from '@grafana/i18n';
import { config, reportInteraction, useFavoriteDatasources } from '@grafana/runtime';
import { reportInteraction, useFavoriteDatasources } from '@grafana/runtime';
import { DataQuery } from '@grafana/schema';
import {
Modal,
FileDropzone,
FileDropzoneDefaultChildren,
useStyles2,
Input,
Icon,
ScrollContainer,
} from '@grafana/ui';
import { acceptedFiles, maxFileSize } from 'app/features/dataframe-import/constants';
import { Modal, useStyles2, Input, Icon, ScrollContainer } from '@grafana/ui';
import { GrafanaQuery } from 'app/plugins/datasource/grafana/types';
import { getFileDropToQueryHandler } from 'app/plugins/datasource/grafana/utils';
import { useDatasource, useDatasources } from '../../hooks';
import { useDatasources } from '../../hooks';
import { AddNewDataSourceButton } from './AddNewDataSourceButton';
import { BuiltInDataSourceList } from './BuiltInDataSourceList';
@@ -29,7 +19,6 @@ import { matchDataSourceWithSearch } from './utils';
const INTERACTION_EVENT_NAME = 'dashboards_dspickermodal_clicked';
const INTERACTION_ITEM = {
SELECT_DS: 'select_ds',
UPLOAD_FILE: 'upload_file',
CONFIG_NEW_DS: 'config_new_ds',
CONFIG_NEW_DS_EMPTY_STATE: 'config_new_ds_empty_state',
SEARCH: 'search',
@@ -56,7 +45,6 @@ export interface DataSourceModalProps {
alerting?: boolean;
pluginId?: string;
logs?: boolean;
uploadFile?: boolean;
}
export function DataSourceModal({
@@ -70,7 +58,6 @@ export function DataSourceModal({
alerting,
pluginId,
logs,
uploadFile,
filter,
onChange,
current,
@@ -96,8 +83,6 @@ export function DataSourceModal({
});
};
const grafanaDS = useDatasource('-- Grafana --');
// Get all datasources to report total_configured count
const dataSources = useDatasources({
tracing,
@@ -134,22 +119,6 @@ export function DataSourceModal({
[analyticsInteractionSrc]
);
const onFileDrop = getFileDropToQueryHandler((query, fileRejections) => {
if (!grafanaDS) {
return;
}
onChange(grafanaDS, [query]);
reportInteraction(INTERACTION_EVENT_NAME, {
item: INTERACTION_ITEM.UPLOAD_FILE,
src: analyticsInteractionSrc,
});
if (fileRejections.length < 1) {
onDismiss();
}
});
// Built-in data sources used twice because of mobile layout adjustments
// In movile the list is appended to the bottom of the DS list
const BuiltInList = ({ className }: { className?: string }) => {
@@ -231,20 +200,6 @@ export function DataSourceModal({
<BuiltInList />
</ScrollContainer>
</div>
{uploadFile && config.featureToggles.editPanelCSVDragAndDrop && (
<FileDropzone
readAs="readAsArrayBuffer"
fileListRenderer={() => undefined}
options={{
maxSize: maxFileSize,
multiple: false,
accept: acceptedFiles,
onDrop: onFileDrop,
}}
>
<FileDropzoneDefaultChildren />
</FileDropzone>
)}
</div>
<div className={styles.newDSSection}>
<span className={styles.newDSDescription}>
@@ -11,8 +11,6 @@ import {
} from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { ModalRoot, ModalsProvider } from '@grafana/ui';
import config from 'app/core/config';
import { defaultFileUploadQuery } from 'app/plugins/datasource/grafana/types';
import { DataSourcePicker, DataSourcePickerProps } from './DataSourcePicker';
import * as utils from './utils';
@@ -290,18 +288,6 @@ describe('DataSourcePicker', () => {
expect(screen.getByRole('link')).toHaveAttribute('href', '/my-sub-path/connections/datasources/new');
});
it('should call onChange with the default query when add csv is clicked', async () => {
config.featureToggles.editPanelCSVDragAndDrop = true;
const onChange = jest.fn();
await setupOpenDropdown(user, { onChange, uploadFile: true });
await user.click(await screen.findByText('Add csv or spreadsheet'));
expect(onChange.mock.lastCall[1]).toEqual([defaultFileUploadQuery]);
expect(screen.queryByText('Open advanced data source picker')).toBeNull(); //Drop down is closed
config.featureToggles.editPanelCSVDragAndDrop = false;
});
it('should open the modal when open advanced is clicked', async () => {
const props = { onChange: jest.fn(), current: mockDS1.name };
render(
@@ -14,9 +14,8 @@ import { Trans, t } from '@grafana/i18n';
import { FavoriteDatasources, reportInteraction, useFavoriteDatasources } from '@grafana/runtime';
import { DataQuery, DataSourceJsonData, DataSourceRef } from '@grafana/schema';
import { Button, floatingUtils, Icon, Input, ModalsController, Portal, ScrollContainer, useStyles2 } from '@grafana/ui';
import config from 'app/core/config';
import { useKeyNavigationListener } from 'app/features/search/hooks/useSearchKeyboardSelection';
import { defaultFileUploadQuery, GrafanaQuery } from 'app/plugins/datasource/grafana/types';
import { GrafanaQuery } from 'app/plugins/datasource/grafana/types';
import { useDatasource, useDatasources } from '../../hooks';
@@ -30,7 +29,6 @@ export const INTERACTION_ITEM = {
SEARCH: 'search',
OPEN_DROPDOWN: 'open_dspicker',
SELECT_DS: 'select_ds',
ADD_FILE: 'add_file',
OPEN_ADVANCED_DS_PICKER: 'open_advanced_ds_picker',
CONFIG_NEW_DS_EMPTY_STATE: 'config_new_ds_empty_state',
TOGGLE_FAVORITE: 'toggle_favorite',
@@ -58,7 +56,6 @@ export interface DataSourcePickerProps {
alerting?: boolean;
pluginId?: string;
logs?: boolean;
uploadFile?: boolean;
filter?: (ds: DataSourceInstanceSettings) => boolean;
}
@@ -99,7 +96,6 @@ export function DataSourcePicker(props: DataSourcePickerProps) {
// Used to move the focus to the footer when tabbing from the input
const [footerRef, setFooterRef] = useState<HTMLElement | null>();
const currentDataSourceInstanceSettings = useDatasource(current);
const grafanaDS = useDatasource('-- Grafana --');
const currentValue = Boolean(!current && noDefault) ? undefined : currentDataSourceInstanceSettings;
const prefixIcon =
filterTerm && isOpen ? <DataSourceLogoPlaceHolder /> : <DataSourceLogo dataSource={currentValue} />;
@@ -178,14 +174,6 @@ export function DataSourcePicker(props: DataSourcePickerProps) {
markerElement?.focus();
}
function onClickAddCSV() {
if (!grafanaDS) {
return;
}
onChange(grafanaDS, [defaultFileUploadQuery]);
}
function onKeyDownInput(keyEvent: React.KeyboardEvent<HTMLInputElement>) {
// From the input, it navigates to the footer
if (keyEvent.key === 'Tab' && !keyEvent.shiftKey && isOpen) {
@@ -302,7 +290,6 @@ export function DataSourcePicker(props: DataSourcePickerProps) {
}
}}
onClose={onClose}
onClickAddCSV={onClickAddCSV}
onDismiss={onClose}
onNavigateOutsiteFooter={onNavigateOutsiteFooter}
dataSources={dataSources}
@@ -335,7 +322,6 @@ function getStylesDropdown(theme: GrafanaTheme2, props: DataSourcePickerProps) {
}
export interface PickerContentProps extends DataSourcePickerProps {
onClickAddCSV?: () => void;
keyboardEvents: Observable<React.KeyboardEvent>;
style: React.CSSProperties;
filterTerm?: string;
@@ -348,7 +334,7 @@ export interface PickerContentProps extends DataSourcePickerProps {
}
const PickerContent = React.forwardRef<HTMLDivElement, PickerContentProps>((props, ref) => {
const { filterTerm, onChange, onClose, onClickAddCSV, current, filter, dataSources, favoriteDataSources } = props;
const { filterTerm, onChange, current, filter, dataSources, favoriteDataSources } = props;
const changeCallback = useCallback(
(ds: DataSourceInstanceSettings) => {
@@ -357,12 +343,6 @@ const PickerContent = React.forwardRef<HTMLDivElement, PickerContentProps>((prop
[onChange]
);
const clickAddCSVCallback = useCallback(() => {
onClickAddCSV?.();
onClose();
reportInteraction(INTERACTION_EVENT_NAME, { item: INTERACTION_ITEM.ADD_FILE });
}, [onClickAddCSV, onClose]);
const styles = useStyles2(getStylesPickerContent);
return (
@@ -385,12 +365,7 @@ const PickerContent = React.forwardRef<HTMLDivElement, PickerContentProps>((prop
></DataSourceList>
</ScrollContainer>
<FocusScope>
<Footer
{...props}
onClickAddCSV={clickAddCSVCallback}
onChange={changeCallback}
onNavigateOutsiteFooter={props.onNavigateOutsiteFooter}
/>
<Footer {...props} onChange={changeCallback} onNavigateOutsiteFooter={props.onNavigateOutsiteFooter} />
</FocusScope>
</div>
);
@@ -427,20 +402,14 @@ function getStylesPickerContent(theme: GrafanaTheme2) {
export interface FooterProps extends PickerContentProps {}
function Footer({ onClose, onChange, onClickAddCSV, ...props }: FooterProps) {
function Footer({ onClose, onChange, ...props }: FooterProps) {
const styles = useStyles2(getStylesFooter);
const isUploadFileEnabled = props.uploadFile && config.featureToggles.editPanelCSVDragAndDrop;
const onKeyDownLastButton = (e: React.KeyboardEvent<HTMLButtonElement>) => {
if (e.key === 'Tab') {
props.onNavigateOutsiteFooter(e);
}
};
const onKeyDownFirstButton = (e: React.KeyboardEvent<HTMLButtonElement>) => {
if (e.key === 'Tab' && e.shiftKey) {
props.onNavigateOutsiteFooter(e);
}
};
return (
<div className={styles.footer}>
@@ -465,7 +434,6 @@ function Footer({ onClose, onChange, onClickAddCSV, ...props }: FooterProps) {
pluginId: props.pluginId,
logs: props.logs,
filter: props.filter,
uploadFile: props.uploadFile,
current: props.current,
onDismiss: hideModal,
onChange: (ds, defaultQueries) => {
@@ -477,18 +445,13 @@ function Footer({ onClose, onChange, onClickAddCSV, ...props }: FooterProps) {
reportInteraction(INTERACTION_EVENT_NAME, { item: INTERACTION_ITEM.OPEN_ADVANCED_DS_PICKER });
}}
ref={props.footerRef}
onKeyDown={isUploadFileEnabled ? onKeyDownFirstButton : onKeyDownLastButton}
onKeyDown={onKeyDownLastButton}
>
<Trans i18nKey="data-source-picker.open-advanced-button">Open advanced data source picker</Trans>
<Icon name="arrow-right" />
</Button>
)}
</ModalsController>
{isUploadFileEnabled && (
<Button variant="secondary" size="sm" onClick={onClickAddCSV} onKeyDown={onKeyDownLastButton}>
<Trans i18nKey="datasources.footer.add-csv-or-spreadsheet">Add csv or spreadsheet</Trans>
</Button>
)}
</div>
);
}
@@ -499,7 +499,6 @@ function DataSourcePickerWithPrompt({ options, onChange, ...otherProps }: DataSo
dashboard: true,
variables: true,
current: options.dataSource,
uploadFile: true,
onChange: async (ds: DataSourceInstanceSettings, defaultQueries?: DataQuery[] | GrafanaQuery[]) => {
await onChange(ds, defaultQueries);
setIsDataSourceModalOpen(false);
@@ -1,39 +1,20 @@
import { css } from '@emotion/css';
import pluralize from 'pluralize';
import { PureComponent } from 'react';
import * as React from 'react';
import { DropEvent, FileRejection } from 'react-dropzone';
import {
QueryEditorProps,
SelectableValue,
rangeUtil,
DataQueryRequest,
DataFrameJSON,
dataFrameToJSON,
GrafanaTheme2,
getValueFormat,
formattedValueToString,
Field,
} from '@grafana/data';
import { config, getDataSourceSrv, reportInteraction } from '@grafana/runtime';
import { QueryEditorProps, SelectableValue, rangeUtil, DataQueryRequest, Field } from '@grafana/data';
import { config, getDataSourceSrv } from '@grafana/runtime';
import {
InlineField,
Select,
Alert,
Input,
InlineFieldRow,
InlineLabel,
FileDropzone,
FileDropzoneDefaultChildren,
DropzoneFile,
Themeable2,
withTheme2,
Stack,
InlineLabel,
} from '@grafana/ui';
import { hasAlphaPanels } from 'app/core/config';
import { acceptedFiles, maxFileSize } from 'app/features/dataframe-import/constants';
import { filesToDataframes } from 'app/features/dataframe-import/utils';
import { getManagedChannelInfo } from 'app/features/live/info';
import { SearchQuery } from 'app/features/search/service/types';
@@ -53,7 +34,7 @@ interface State {
folders?: Array<SelectableValue<string>>;
}
export class UnthemedQueryEditor extends PureComponent<Props, State> {
export class UnthemedQueryEditor extends React.PureComponent<Props, State> {
state: State = { channels: [], channelFields: {} };
queryTypes: Array<SelectableValue<GrafanaQueryType>> = [
@@ -91,13 +72,6 @@ export class UnthemedQueryEditor extends PureComponent<Props, State> {
description: 'Search for grafana resources',
});
}
if (config.featureToggles.editPanelCSVDragAndDrop) {
this.queryTypes.push({
label: 'Spreadsheet or snapshot',
value: GrafanaQueryType.Snapshot,
description: 'Query an uploaded spreadsheet or a snapshot',
});
}
}
loadChannelInfo() {
@@ -356,43 +330,8 @@ export class UnthemedQueryEditor extends PureComponent<Props, State> {
);
}
// Skip rendering the file list as we're handling that in this component instead.
fileListRenderer = (file: DropzoneFile, removeFile: (file: DropzoneFile) => void) => {
return null;
};
onFileDrop = (acceptedFiles: File[], fileRejections: FileRejection[], event: DropEvent) => {
filesToDataframes(acceptedFiles).subscribe((next) => {
const snapshot: DataFrameJSON[] = [];
next.dataFrames.forEach((df) => {
const dataframeJson = dataFrameToJSON(df);
snapshot.push(dataframeJson);
});
this.props.onChange({
...this.props.query,
file: { name: next.file.name, size: next.file.size },
queryType: GrafanaQueryType.Snapshot,
snapshot,
});
this.props.onRunQuery();
reportInteraction('grafana_datasource_drop_files', {
number_of_files: fileRejections.length + acceptedFiles.length,
accepted_files: acceptedFiles.map((a) => {
return { type: a.type, size: a.size };
}),
rejected_files: fileRejections.map((r) => {
return { type: r.file.type, size: r.file.size };
}),
});
});
};
renderSnapshotQuery() {
const { query, theme } = this.props;
const file = query.file;
const styles = getStyles(theme);
const fileSize = getValueFormat('decbytes')(file ? file.size : 0);
const { query } = this.props;
return (
<>
@@ -401,32 +340,6 @@ export class UnthemedQueryEditor extends PureComponent<Props, State> {
<InlineLabel>{pluralize('frame', query.snapshot?.length ?? 0, true)}</InlineLabel>
</InlineField>
</InlineFieldRow>
{config.featureToggles.editPanelCSVDragAndDrop && (
<>
<FileDropzone
readAs="readAsArrayBuffer"
fileListRenderer={this.fileListRenderer}
options={{
onDrop: this.onFileDrop,
maxSize: maxFileSize,
multiple: false,
accept: acceptedFiles,
}}
>
<FileDropzoneDefaultChildren
primaryText={this.props?.query?.file ? 'Replace file' : 'Drop file here or click to upload'}
/>
</FileDropzone>
{file && (
<div className={styles.file}>
<span>{file?.name}</span>
<span>
<span>{formattedValueToString(fileSize)}</span>
</span>
</div>
)}
</>
)}
</>
);
}
@@ -466,7 +379,7 @@ export class UnthemedQueryEditor extends PureComponent<Props, State> {
// Only show "snapshot" when it already exists
let queryTypes = this.queryTypes;
if (queryType === GrafanaQueryType.Snapshot && !config.featureToggles.editPanelCSVDragAndDrop) {
if (queryType === GrafanaQueryType.Snapshot) {
queryTypes = [
...this.queryTypes,
{
@@ -511,19 +424,3 @@ export class UnthemedQueryEditor extends PureComponent<Props, State> {
}
export const QueryEditor = withTheme2(UnthemedQueryEditor);
function getStyles(theme: GrafanaTheme2) {
return {
file: css({
width: '100%',
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
padding: theme.spacing(2),
border: `1px dashed ${theme.colors.border.medium}`,
backgroundColor: theme.colors.background.secondary,
marginTop: theme.spacing(1),
}),
};
}
@@ -53,16 +53,6 @@ export const defaultQuery: GrafanaQuery = {
queryType: GrafanaQueryType.RandomWalk,
};
export const defaultFileUploadQuery: GrafanaQuery = {
refId: 'A',
datasource: {
type: 'grafana',
uid: 'grafana',
},
queryType: GrafanaQueryType.Snapshot,
snapshot: [],
};
//----------------------------------------------
// Annotations
//----------------------------------------------
+1 -19
View File
@@ -1,13 +1,10 @@
import { DropEvent, FileRejection } from 'react-dropzone';
import { DataFrame, DataFrameJSON, dataFrameToJSON } from '@grafana/data';
import appEvents from 'app/core/app_events';
import { GRAFANA_DATASOURCE_NAME } from 'app/features/alerting/unified/utils/datasource';
import { PanelModel } from 'app/features/dashboard/state/PanelModel';
import { filesToDataframes } from 'app/features/dataframe-import/utils';
import { ShowConfirmModalEvent } from 'app/types/events';
import { defaultFileUploadQuery, GrafanaQuery, GrafanaQueryType } from './types';
import { GrafanaQuery, GrafanaQueryType } from './types';
/**
* Will show a confirm modal if the current panel does not have a snapshot query.
@@ -57,18 +54,3 @@ function updateSnapshotData(frames: DataFrame[], panel: PanelModel) {
panel.refresh();
}
export function getFileDropToQueryHandler(
onFileLoaded: (query: GrafanaQuery, fileRejections: FileRejection[]) => void
) {
return (acceptedFiles: File[], fileRejections: FileRejection[], event: DropEvent) => {
filesToDataframes(acceptedFiles).subscribe(async (next) => {
const snapshot: DataFrameJSON[] = [];
next.dataFrames.forEach((df: DataFrame) => {
const dataframeJson = dataFrameToJSON(df);
snapshot.push(dataframeJson);
});
onFileLoaded({ ...defaultFileUploadQuery, ...{ snapshot: snapshot, file: next.file } }, fileRejections);
});
};
}
-3
View File
@@ -6750,9 +6750,6 @@
"error-details-link": {
"aria-label-more-details-about-the-error": "More details about the error"
},
"footer": {
"add-csv-or-spreadsheet": "Add csv or spreadsheet"
},
"get-enterprise-phantom-plugins": {
"description": {
"adobe-analytics-datasource": "Adobe Analytics datasource",