Provisioning: Only show setup page when feature toggles are missing (#101502)

This commit is contained in:
Ryan McKinley authored and GitHub committed 2025-03-04 09:58:47 +03:00
1 parent 30387bdc0f
commit 222d896db6
13 files changed
+121 -49

No files matched your search

+20 -8
View File
@@ -5608,11 +5608,23 @@ exports[`better eslint`] = {
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "19"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "20"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "21"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "22"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "23"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "24"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "25"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "26"]
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "22"]
],
"public/app/features/provisioning/ConfigFormGithubCollapse.tsx:5381": [
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "1"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "2"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "3"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "4"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "5"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "6"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "7"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "8"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "9"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "10"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "11"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "12"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "13"]
],
"public/app/features/provisioning/DeleteRepositoryButton.tsx:5381": [
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"],
@@ -5788,8 +5800,7 @@ exports[`better eslint`] = {
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "8"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "9"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "10"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "11"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "12"]
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "11"]
],
"public/app/features/provisioning/Wizard/ConnectionStep.tsx:5381": [
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"],
@@ -5833,7 +5844,8 @@ exports[`better eslint`] = {
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "14"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "15"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "16"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "17"]
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "17"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "18"]
],
"public/app/features/provisioning/Wizard/Stepper.tsx:5381": [
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"]
+15 -20
View File
@@ -8,8 +8,8 @@ import {
Button,
Combobox,
ComboboxOption,
ControlledCollapse,
Field,
FieldSet,
Input,
MultiCombobox,
RadioButtonGroup,
@@ -19,6 +19,7 @@ import {
} from '@grafana/ui';
import { FormPrompt } from 'app/core/components/FormPrompt/FormPrompt';
import { ConfigFormGithubCollpase } from './ConfigFormGithubCollapse';
import { TokenPermissionsInfo } from './TokenPermissionsInfo';
import { Repository, RepositorySpec } from './api';
import { useCreateOrUpdateRepository } from './hooks';
@@ -53,7 +54,7 @@ export function getDefaultValues(repository?: RepositorySpec): RepositoryFormDat
url: '',
branch: 'main',
generateDashboardPreviews: true,
workflows: ['write', 'branch'],
workflows: ['branch', 'write'],
sync: {
enabled: true,
target: 'instance',
@@ -139,8 +140,8 @@ export function ConfigForm({ data }: ConfigFormProps) {
<Input {...register('title', { required: 'This field is required.' })} placeholder={'My config'} />
</Field>
{type === 'github' && (
<FieldSet label="GitHub">
<Field label={'Token'} required error={errors?.token?.message} invalid={!!errors.token}>
<>
<Field label={'GitHub token'} required error={errors?.token?.message} invalid={!!errors.token}>
<Controller
name={'token'}
control={control}
@@ -183,20 +184,7 @@ export function ConfigForm({ data }: ConfigFormProps) {
<Field label={'Branch'}>
<Input {...register('branch')} placeholder={'main'} />
</Field>
<Field
label={'Attach dashboard previews to pull requests'}
description={
<span>
Render before/after images and link them to the pull request.
<br />
NOTE! these will be public URLs!!!"
</span>
}
>
<Switch {...register('generateDashboardPreviews')} id={'generateDashboardPreviews'} />
</Field>
{/* The lint option is intentionally not presented here, as it's an experimental feature. */}
</FieldSet>
</>
)}
{type === 'local' && (
@@ -229,7 +217,13 @@ export function ConfigForm({ data }: ConfigFormProps) {
/>
</Field>
<FieldSet label="Sync Settings">
{type === 'github' && (
<ConfigFormGithubCollpase
previews={<Switch {...register('generateDashboardPreviews')} id={'generateDashboardPreviews'} />}
/>
)}
<ControlledCollapse label="Sync Settings" isOpen={false}>
<Field label={'Enabled'} description={'Once sync is enabled, the target cannot be changed.'}>
<Switch {...register('sync.enabled')} id={'sync.enabled'} />
</Field>
@@ -253,7 +247,8 @@ export function ConfigForm({ data }: ConfigFormProps) {
<Field label={'Interval (seconds)'}>
<Input {...register('sync.intervalSeconds', { valueAsNumber: true })} type={'number'} placeholder={'60'} />
</Field>
</FieldSet>
</ControlledCollapse>
<Stack gap={2}>
<Button type={'submit'} disabled={request.isLoading}>
{request.isLoading ? 'Saving...' : 'Save'}
@@ -0,0 +1,62 @@
import { useNavigate } from 'react-router-dom-v5-compat';
import { config } from '@grafana/runtime';
import { Alert, ControlledCollapse, Field } from '@grafana/ui';
import { checkPublicAccess } from './Setup/utils';
import { PROVISIONING_URL } from './constants';
export interface ConfigFormGithubCollpaseProps {
previews: React.ReactElement;
}
export function ConfigFormGithubCollpase({ previews }: ConfigFormGithubCollpaseProps) {
const navigate = useNavigate();
return (
<ControlledCollapse label="GitHub features" isOpen={true}>
<h3>Realtime feedback</h3>
{checkPublicAccess() ? (
<div>
<Alert title={'Webhook will be created'} severity={'info'}>
Changes in git will be quickly pulled into grafana. Pull requests can be processed.
</Alert>
</div>
) : (
<Alert
title={'Public URL not configured'}
severity={'warning'}
buttonContent={<span>Instructions</span>}
onRemove={() => navigate(`${PROVISIONING_URL}/setup`)}
>
Changes in git will eventually be pulled depending on the synchronization interval. Pull requests will not be
proccessed
</Alert>
)}
<h3>Pull Request image previews</h3>
{!config.rendererAvailable && (
<Alert
title={'Image renderer not configured'}
severity={'warning'}
buttonContent={<span>Instructions</span>}
onRemove={() => window.open('https://grafana.com/grafana/plugins/grafana-image-renderer/', '_blank')}
>
When the image renderer is configured, pull requests can see preview images
</Alert>
)}
<Field
label={'Attach dashboard previews to pull requests'}
description={
<span>
Render before/after images and link them to the pull request.
<br />
NOTE! this will render dashboards into an image that can be access by a public URL
</span>
}
>
{previews}
</Field>
</ControlledCollapse>
);
}
@@ -1,7 +1,6 @@
import { Page } from 'app/core/components/Page/Page';
import { ConfigForm } from './ConfigForm';
import { StatusAlerts } from './Setup/StatusAlerts';
export default function NewRepositoryPage() {
return (
@@ -10,7 +9,6 @@ export default function NewRepositoryPage() {
pageNav={{ text: 'Configure repository', subTitle: 'Configure a repository for storing your resources.' }}
>
<Page.Contents>
<StatusAlerts />
<ConfigForm />
</Page.Contents>
</Page>
@@ -4,7 +4,6 @@ import { useNavigate } from 'react-router-dom-v5-compat';
import { EmptyState, LinkButton, Alert, Stack, Text, Button } from '@grafana/ui';
import { Page } from 'app/core/components/Page/Page';
import { StatusAlerts } from './Setup/StatusAlerts';
import { useGetFrontendSettingsQuery } from './api';
import { NEW_URL, MIGRATE_URL } from './constants';
@@ -17,7 +16,6 @@ export default function OnboardingPage({ legacyStorage }: { legacyStorage?: bool
pageNav={{ text: 'Setup provisioning', subTitle: 'Configure this instance to use provisioning' }}
>
<Page.Contents>
<StatusAlerts />
{legacyStorage ? (
<>
<Alert severity="info" title="Setting up this connection could cause a temporary outage">
@@ -20,7 +20,6 @@ import { Page } from 'app/core/components/Page/Page';
import { DeleteRepositoryButton } from './DeleteRepositoryButton';
import OnboardingPage from './OnboardingPage';
import { StatusAlerts } from './Setup/StatusAlerts';
import { StatusBadge } from './StatusBadge';
import { SyncRepository } from './SyncRepository';
import { Repository, ResourceCount, useDeletecollectionRepositoryMutation, useGetFrontendSettingsQuery } from './api';
@@ -56,7 +55,6 @@ export default function RepositoryListPage() {
return (
<Page navId="provisioning" subTitle="View and manage your configured repositories">
<Page.Contents isLoading={isLoading}>
<StatusAlerts />
{settings.data?.legacyStorage && (
<Alert
title="Legacy storage detected"
@@ -23,17 +23,16 @@ export const requiredFeatureToggles: Array<keyof FeatureToggles> = [
'kubernetesDashboards',
'kubernetesClientDashboardsFolders',
'unifiedStorageSearch',
'unifiedStorageSearchUI',
];
// Configuration examples
export const feature_ini = `# In your custom.ini file
app_mode = development
[feature_toggles]
provisioning = true
kubernetesDashboards = true
unifiedStorageSearch = true
unifiedStorageSearchUI = true
kubernetesClientDashboardsFolders = true
# If you want easy kubectl setup development mode
@@ -42,11 +41,11 @@ grafanaAPIServerEnsureKubectlAccess = true`;
// Configuration examples
export const custom_ini = `# In your custom.ini file
app_mode = development
[feature_toggles]
provisioning = true
kubernetesDashboards = true
unifiedStorageSearch = true
unifiedStorageSearchUI = true
kubernetesClientDashboardsFolders = true
# If you want easy kubectl setup development mode
@@ -16,7 +16,7 @@ export const checkRequiredFeatures = (): boolean => {
* @returns true if the app URL is configured for external access
*/
export const checkPublicAccess = (): boolean => {
return Boolean(config.appUrl && config.appUrl !== 'http://localhost:3000/');
return Boolean(config.appUrl && config.appUrl.indexOf('://localhost') < 0);
};
/**
@@ -11,7 +11,7 @@ export function TokenPermissionsInfo() {
</div>
<p>Select the appropriate owner and repository. Then expand Repository permissions, granting</p>
<table>
<table style={{ fontSize: '2em' }}>
<tr>
<td>Content</td>
<td>Read and write</td>
@@ -21,13 +21,12 @@ export function TokenPermissionsInfo() {
<td>Read only</td>
</tr>
<tr>
<td>Pull requests&nbsp;</td>
<td>Pull requests&nbsp;&nbsp;</td>
<td>Read and write</td>
</tr>
<tr>
<td>Webhooks</td>
<td>Read and write &nbsp;&nbsp;</td>
<td>If this instance has a public URL, and should be notified of changes</td>
</tr>
</table>
</ControlledCollapse>
@@ -3,7 +3,6 @@ import { useNavigate } from 'react-router-dom-v5-compat';
import { Page } from 'app/core/components/Page/Page';
import { StatusAlerts } from '../Setup/StatusAlerts';
import { useGetFrontendSettingsQuery } from '../api';
import { PROVISIONING_URL } from '../constants';
@@ -37,7 +36,6 @@ export default function MigrateToProvisioningPage() {
pageNav={{ text: 'Migrate to Provisioning', subTitle: 'Manage this instance from provisioning' }}
>
<Page.Contents>
<StatusAlerts />
<ProvisioningWizard />
</Page.Contents>
</Page>
@@ -16,6 +16,7 @@ import {
} from '@grafana/ui';
import { getWorkflowOptions } from '../ConfigForm';
import { ConfigFormGithubCollpase } from '../ConfigFormGithubCollapse';
import { TokenPermissionsInfo } from '../TokenPermissionsInfo';
import { useCreateRepositoryTestMutation } from '../api';
import { useCreateOrUpdateRepository } from '../hooks';
@@ -178,8 +179,19 @@ export function RepositoryStep({ onStatusChange }: Props) {
/>
</Field>
<ControlledCollapse label="Advanced settings" isOpen={true}>
<Field label={'Enable sync'}>
{type === 'github' && (
<ConfigFormGithubCollpase
previews={
<Switch
{...register('repository.generateDashboardPreviews')}
id={'repository.generateDashboardPreviews'}
/>
}
/>
)}
<ControlledCollapse label="Advanced settings" isOpen={false}>
<Field label={'Enable sync'} description="The repository will periodically pull changes">
<Switch {...register('repository.sync.enabled')} />
</Field>
<Field label={'Sync interval (seconds)'}>
+3 -3
View File
@@ -1,8 +1,8 @@
import { GitHubRepositoryConfig, LocalRepositoryConfig, RepositorySpec } from './api';
export type RepositoryFormData = GitHubRepositoryConfig &
LocalRepositoryConfig &
Omit<RepositorySpec, 'github' | 'local'>;
export type RepositoryFormData = Omit<RepositorySpec, 'github' | 'local'> &
GitHubRepositoryConfig &
LocalRepositoryConfig;
// Added to DashboardDTO to help editor
export interface ProvisioningPreview {
@@ -3,10 +3,11 @@ import { SafeDynamicImport } from 'app/core/components/DynamicImports/SafeDynami
import { RouteDescriptor } from 'app/core/navigation/types';
import { DashboardRoutes } from 'app/types';
import { requiredFeatureToggles } from '../Setup/types';
import { PROVISIONING_URL } from '../constants';
export function getProvisioningRoutes(): RouteDescriptor[] {
if (!config.featureToggles.provisioning) {
if (!requiredFeatureToggles.every((toggle) => config.featureToggles[toggle])) {
return [
{
path: PROVISIONING_URL,