mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Chore: Remove previews crawler UI (and feature flag) (#62906)
This commit is contained in:
@@ -103,7 +103,6 @@ The following toggles require explicitly setting Grafana's [app mode]({{< relref
|
|||||||
|
|
||||||
| Feature toggle name | Description |
|
| Feature toggle name | Description |
|
||||||
| ------------------------------ | ----------------------------------------------------------------------- |
|
| ------------------------------ | ----------------------------------------------------------------------- |
|
||||||
| `dashboardPreviewsAdmin` | Manage the dashboard previews crawler process from the UI |
|
|
||||||
| `showFeatureFlagsInUI` | Show feature flags in the settings UI |
|
| `showFeatureFlagsInUI` | Show feature flags in the settings UI |
|
||||||
| `publicDashboardsEmailSharing` | Allows public dashboard sharing to be restricted to only allowed emails |
|
| `publicDashboardsEmailSharing` | Allows public dashboard sharing to be restricted to only allowed emails |
|
||||||
| `k8s` | Explore native k8s integrations |
|
| `k8s` | Explore native k8s integrations |
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ export interface FeatureToggles {
|
|||||||
disableEnvelopeEncryption?: boolean;
|
disableEnvelopeEncryption?: boolean;
|
||||||
database_metrics?: boolean;
|
database_metrics?: boolean;
|
||||||
dashboardPreviews?: boolean;
|
dashboardPreviews?: boolean;
|
||||||
dashboardPreviewsAdmin?: boolean;
|
|
||||||
['live-pipeline']?: boolean;
|
['live-pipeline']?: boolean;
|
||||||
['live-service-web-worker']?: boolean;
|
['live-service-web-worker']?: boolean;
|
||||||
queryOverLive?: boolean;
|
queryOverLive?: boolean;
|
||||||
|
|||||||
@@ -486,10 +486,6 @@ func (hs *HTTPServer) registerRoutes() {
|
|||||||
dashboardRoute.Group("/uid/:uid", func(dashUidRoute routing.RouteRegister) {
|
dashboardRoute.Group("/uid/:uid", func(dashUidRoute routing.RouteRegister) {
|
||||||
if hs.ThumbService != nil {
|
if hs.ThumbService != nil {
|
||||||
dashUidRoute.Get("/img/:kind/:theme", hs.ThumbService.GetImage)
|
dashUidRoute.Get("/img/:kind/:theme", hs.ThumbService.GetImage)
|
||||||
if hs.Features.IsEnabled(featuremgmt.FlagDashboardPreviewsAdmin) {
|
|
||||||
dashUidRoute.Post("/img/:kind/:theme", reqGrafanaAdmin, hs.ThumbService.SetImage)
|
|
||||||
dashUidRoute.Put("/img/:kind/:theme", reqGrafanaAdmin, hs.ThumbService.UpdateThumbnailState)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -639,12 +635,6 @@ func (hs *HTTPServer) registerRoutes() {
|
|||||||
adminRoute.Get("/stats", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionServerStatsRead)), routing.Wrap(hs.AdminGetStats))
|
adminRoute.Get("/stats", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionServerStatsRead)), routing.Wrap(hs.AdminGetStats))
|
||||||
adminRoute.Post("/pause-all-alerts", reqGrafanaAdmin, routing.Wrap(hs.PauseAllAlerts(setting.AlertingEnabled)))
|
adminRoute.Post("/pause-all-alerts", reqGrafanaAdmin, routing.Wrap(hs.PauseAllAlerts(setting.AlertingEnabled)))
|
||||||
|
|
||||||
if hs.ThumbService != nil && hs.Features.IsEnabled(featuremgmt.FlagDashboardPreviewsAdmin) {
|
|
||||||
adminRoute.Post("/crawler/start", reqGrafanaAdmin, routing.Wrap(hs.ThumbService.StartCrawler))
|
|
||||||
adminRoute.Post("/crawler/stop", reqGrafanaAdmin, routing.Wrap(hs.ThumbService.StopCrawler))
|
|
||||||
adminRoute.Get("/crawler/status", reqGrafanaAdmin, routing.Wrap(hs.ThumbService.CrawlerStatus))
|
|
||||||
}
|
|
||||||
|
|
||||||
if hs.Features.IsEnabled(featuremgmt.FlagExport) {
|
if hs.Features.IsEnabled(featuremgmt.FlagExport) {
|
||||||
adminRoute.Get("/export", reqGrafanaAdmin, routing.Wrap(hs.ExportService.HandleGetStatus))
|
adminRoute.Get("/export", reqGrafanaAdmin, routing.Wrap(hs.ExportService.HandleGetStatus))
|
||||||
adminRoute.Post("/export", reqGrafanaAdmin, routing.Wrap(hs.ExportService.HandleRequestExport))
|
adminRoute.Post("/export", reqGrafanaAdmin, routing.Wrap(hs.ExportService.HandleRequestExport))
|
||||||
|
|||||||
@@ -39,12 +39,6 @@ var (
|
|||||||
Description: "Create and show thumbnails for dashboard search results",
|
Description: "Create and show thumbnails for dashboard search results",
|
||||||
State: FeatureStateAlpha,
|
State: FeatureStateAlpha,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
Name: "dashboardPreviewsAdmin",
|
|
||||||
Description: "Manage the dashboard previews crawler process from the UI",
|
|
||||||
State: FeatureStateAlpha,
|
|
||||||
RequiresDevMode: true,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
Name: "live-pipeline",
|
Name: "live-pipeline",
|
||||||
Description: "Enable a generic live processing pipeline",
|
Description: "Enable a generic live processing pipeline",
|
||||||
|
|||||||
@@ -31,10 +31,6 @@ const (
|
|||||||
// Create and show thumbnails for dashboard search results
|
// Create and show thumbnails for dashboard search results
|
||||||
FlagDashboardPreviews = "dashboardPreviews"
|
FlagDashboardPreviews = "dashboardPreviews"
|
||||||
|
|
||||||
// FlagDashboardPreviewsAdmin
|
|
||||||
// Manage the dashboard previews crawler process from the UI
|
|
||||||
FlagDashboardPreviewsAdmin = "dashboardPreviewsAdmin"
|
|
||||||
|
|
||||||
// FlagLivePipeline
|
// FlagLivePipeline
|
||||||
// Enable a generic live processing pipeline
|
// Enable a generic live processing pipeline
|
||||||
FlagLivePipeline = "live-pipeline"
|
FlagLivePipeline = "live-pipeline"
|
||||||
|
|||||||
@@ -1,64 +0,0 @@
|
|||||||
import { css } from '@emotion/css';
|
|
||||||
import React, { useState } from 'react';
|
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
|
||||||
import { getBackendSrv, config } from '@grafana/runtime';
|
|
||||||
import { Button, CodeEditor, Modal, useTheme2 } from '@grafana/ui';
|
|
||||||
|
|
||||||
export const CrawlerStartButton = () => {
|
|
||||||
const styles = getStyles(useTheme2());
|
|
||||||
const [open, setOpen] = useState(false);
|
|
||||||
const [body, setBody] = useState({
|
|
||||||
mode: 'thumbs',
|
|
||||||
theme: config.theme2.isLight ? 'light' : 'dark',
|
|
||||||
});
|
|
||||||
const onDismiss = () => setOpen(false);
|
|
||||||
const doStart = () => {
|
|
||||||
getBackendSrv()
|
|
||||||
.post('/api/admin/crawler/start', body)
|
|
||||||
.then((v) => {
|
|
||||||
console.log('GOT', v);
|
|
||||||
onDismiss();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Modal title={'Start crawler'} isOpen={open} onDismiss={onDismiss}>
|
|
||||||
<div className={styles.wrap}>
|
|
||||||
<CodeEditor
|
|
||||||
height={200}
|
|
||||||
value={JSON.stringify(body, null, 2) ?? ''}
|
|
||||||
showLineNumbers={false}
|
|
||||||
readOnly={false}
|
|
||||||
language="json"
|
|
||||||
showMiniMap={false}
|
|
||||||
onBlur={(text: string) => {
|
|
||||||
setBody(JSON.parse(text)); // force JSON?
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<Modal.ButtonRow>
|
|
||||||
<Button type="submit" onClick={doStart}>
|
|
||||||
Start
|
|
||||||
</Button>
|
|
||||||
<Button variant="secondary" onClick={onDismiss}>
|
|
||||||
Cancel
|
|
||||||
</Button>
|
|
||||||
</Modal.ButtonRow>
|
|
||||||
</Modal>
|
|
||||||
|
|
||||||
<Button onClick={() => setOpen(true)} variant="primary">
|
|
||||||
Start
|
|
||||||
</Button>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const getStyles = (theme: GrafanaTheme2) => {
|
|
||||||
return {
|
|
||||||
wrap: css`
|
|
||||||
border: 2px solid #111;
|
|
||||||
`,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
import { css } from '@emotion/css';
|
|
||||||
import React, { useEffect, useState } from 'react';
|
|
||||||
|
|
||||||
import { GrafanaTheme2, isLiveChannelMessageEvent, isLiveChannelStatusEvent, LiveChannelScope } from '@grafana/data';
|
|
||||||
import { getBackendSrv, getGrafanaLiveSrv } from '@grafana/runtime';
|
|
||||||
import { Button, useTheme2 } from '@grafana/ui';
|
|
||||||
|
|
||||||
import { CrawlerStartButton } from './CrawlerStartButton';
|
|
||||||
|
|
||||||
interface CrawlerStatusMessage {
|
|
||||||
state: string;
|
|
||||||
started: string;
|
|
||||||
finished: string;
|
|
||||||
complete: number;
|
|
||||||
queue: number;
|
|
||||||
last: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const CrawlerStatus = () => {
|
|
||||||
const styles = getStyles(useTheme2());
|
|
||||||
const [status, setStatus] = useState<CrawlerStatusMessage>();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const subscription = getGrafanaLiveSrv()
|
|
||||||
.getStream<CrawlerStatusMessage>({
|
|
||||||
scope: LiveChannelScope.Grafana,
|
|
||||||
namespace: 'broadcast',
|
|
||||||
path: 'crawler',
|
|
||||||
})
|
|
||||||
.subscribe({
|
|
||||||
next: (evt) => {
|
|
||||||
if (isLiveChannelMessageEvent(evt)) {
|
|
||||||
setStatus(evt.message);
|
|
||||||
} else if (isLiveChannelStatusEvent(evt)) {
|
|
||||||
setStatus(evt.message);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
return () => {
|
|
||||||
subscription.unsubscribe();
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
if (!status) {
|
|
||||||
return (
|
|
||||||
<div className={styles.wrap}>
|
|
||||||
No status (never run)
|
|
||||||
<br />
|
|
||||||
<CrawlerStartButton />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={styles.wrap}>
|
|
||||||
<pre>{JSON.stringify(status, null, 2)}</pre>
|
|
||||||
{status.state !== 'running' && <CrawlerStartButton />}
|
|
||||||
{status.state !== 'stopped' && (
|
|
||||||
<Button
|
|
||||||
variant="secondary"
|
|
||||||
onClick={() => {
|
|
||||||
getBackendSrv().post('/api/admin/crawler/stop');
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Stop
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const getStyles = (theme: GrafanaTheme2) => {
|
|
||||||
return {
|
|
||||||
wrap: css`
|
|
||||||
border: 4px solid red;
|
|
||||||
`,
|
|
||||||
running: css`
|
|
||||||
border: 4px solid green;
|
|
||||||
`,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@@ -2,14 +2,12 @@ import { css } from '@emotion/css';
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import { config } from '@grafana/runtime';
|
|
||||||
import { CardContainer, LinkButton, useStyles2 } from '@grafana/ui';
|
import { CardContainer, LinkButton, useStyles2 } from '@grafana/ui';
|
||||||
import { AccessControlAction } from 'app/types';
|
import { AccessControlAction } from 'app/types';
|
||||||
|
|
||||||
import { contextSrv } from '../../core/services/context_srv';
|
import { contextSrv } from '../../core/services/context_srv';
|
||||||
import { Loader } from '../plugins/admin/components/Loader';
|
import { Loader } from '../plugins/admin/components/Loader';
|
||||||
|
|
||||||
import { CrawlerStatus } from './CrawlerStatus';
|
|
||||||
import { getServerStats, ServerStat } from './state/apis';
|
import { getServerStats, ServerStat } from './state/apis';
|
||||||
|
|
||||||
export const ServerStats = () => {
|
export const ServerStats = () => {
|
||||||
@@ -96,8 +94,6 @@ export const ServerStats = () => {
|
|||||||
) : (
|
) : (
|
||||||
<p className={styles.notFound}>No stats found.</p>
|
<p className={styles.notFound}>No stats found.</p>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{config.featureToggles.dashboardPreviews && config.featureToggles.dashboardPreviewsAdmin && <CrawlerStatus />}
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import React, { useState } from 'react';
|
|||||||
import { connect, ConnectedProps } from 'react-redux';
|
import { connect, ConnectedProps } from 'react-redux';
|
||||||
|
|
||||||
import { TimeZone } from '@grafana/data';
|
import { TimeZone } from '@grafana/data';
|
||||||
import { config } from '@grafana/runtime';
|
|
||||||
import { CollapsableSection, Field, Input, RadioButtonGroup, TagsInput } from '@grafana/ui';
|
import { CollapsableSection, Field, Input, RadioButtonGroup, TagsInput } from '@grafana/ui';
|
||||||
import { Page } from 'app/core/components/PageNew/Page';
|
import { Page } from 'app/core/components/PageNew/Page';
|
||||||
import { FolderPicker } from 'app/core/components/Select/FolderPicker';
|
import { FolderPicker } from 'app/core/components/Select/FolderPicker';
|
||||||
@@ -10,7 +9,6 @@ import { updateTimeZoneDashboard, updateWeekStartDashboard } from 'app/features/
|
|||||||
|
|
||||||
import { DeleteDashboardButton } from '../DeleteDashboard/DeleteDashboardButton';
|
import { DeleteDashboardButton } from '../DeleteDashboard/DeleteDashboardButton';
|
||||||
|
|
||||||
import { PreviewSettings } from './PreviewSettings';
|
|
||||||
import { TimePickerSettings } from './TimePickerSettings';
|
import { TimePickerSettings } from './TimePickerSettings';
|
||||||
import { SettingsPageProps } from './types';
|
import { SettingsPageProps } from './types';
|
||||||
|
|
||||||
@@ -125,10 +123,6 @@ export function GeneralSettingsUnconnected({
|
|||||||
</Field>
|
</Field>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{config.featureToggles.dashboardPreviews && config.featureToggles.dashboardPreviewsAdmin && (
|
|
||||||
<PreviewSettings uid={dashboard.uid} />
|
|
||||||
)}
|
|
||||||
|
|
||||||
<TimePickerSettings
|
<TimePickerSettings
|
||||||
onTimeZoneChange={onTimeZoneChange}
|
onTimeZoneChange={onTimeZoneChange}
|
||||||
onWeekStartChange={onWeekStartChange}
|
onWeekStartChange={onWeekStartChange}
|
||||||
|
|||||||
@@ -1,102 +0,0 @@
|
|||||||
import React, { PureComponent } from 'react';
|
|
||||||
|
|
||||||
import { Button, CollapsableSection, FileUpload } from '@grafana/ui';
|
|
||||||
import { getBackendSrv } from 'app/core/services/backend_srv';
|
|
||||||
import { getThumbnailURL } from 'app/features/search/components/SearchCard';
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
uid: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface State {}
|
|
||||||
|
|
||||||
export class PreviewSettings extends PureComponent<Props, State> {
|
|
||||||
state: State = {};
|
|
||||||
|
|
||||||
doUpload = (evt: EventTarget & HTMLInputElement, isLight?: boolean) => {
|
|
||||||
const file = evt?.files && evt.files[0];
|
|
||||||
if (!file) {
|
|
||||||
console.log('NOPE!', evt);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const url = getThumbnailURL(this.props.uid, isLight);
|
|
||||||
const formData = new FormData();
|
|
||||||
formData.append('file', file);
|
|
||||||
|
|
||||||
fetch(url, {
|
|
||||||
method: 'POST',
|
|
||||||
body: formData,
|
|
||||||
})
|
|
||||||
.then((response) => response.json())
|
|
||||||
.then((result) => {
|
|
||||||
console.log('Success:', result);
|
|
||||||
location.reload(); //HACK
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.error('Error:', error);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
markAsStale = (isLight: boolean) => async () => {
|
|
||||||
return getBackendSrv().put(getThumbnailURL(this.props.uid, isLight), { state: 'stale' });
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { uid } = this.props;
|
|
||||||
const imgstyle = { maxWidth: 300, maxHeight: 300 };
|
|
||||||
return (
|
|
||||||
<CollapsableSection label="Preview settings" isOpen={true}>
|
|
||||||
<div>DUMMY UI just so we have an upload button!</div>
|
|
||||||
<table cellSpacing="4">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<td>[DARK]</td>
|
|
||||||
<td>[LIGHT]</td>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<Button type="button" variant="primary" onClick={this.markAsStale(false)} fill="outline">
|
|
||||||
Mark as stale
|
|
||||||
</Button>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<Button type="button" variant="primary" onClick={this.markAsStale(true)} fill="outline">
|
|
||||||
Mark as stale
|
|
||||||
</Button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<img src={getThumbnailURL(uid, false)} alt="Preview of dashboard in dark theme" style={imgstyle} />
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<img src={getThumbnailURL(uid, true)} alt="Preview of dashboard in light theme" style={imgstyle} />
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<FileUpload
|
|
||||||
accept="image/png, image/webp"
|
|
||||||
onFileUpload={({ currentTarget }) => this.doUpload(currentTarget, false)}
|
|
||||||
>
|
|
||||||
Upload dark
|
|
||||||
</FileUpload>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<FileUpload
|
|
||||||
accept="image/png, image/webp"
|
|
||||||
onFileUpload={({ currentTarget }) => this.doUpload(currentTarget, true)}
|
|
||||||
>
|
|
||||||
Upload light
|
|
||||||
</FileUpload>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</CollapsableSection>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user