Repository: grafana/grafana
Pull request #101701: [Provisioning] Getting Started Page and Tab
Author: login: MissingRoberto
Labels: name: area/frontend
name: no-backport
description: Skip backport of PR
name: no-changelog
description: Skip including change in changelog/release notes
Created: 2025-03-06T13:01:47Z | Merged: 2025-03-06T21:45:27Z

# Why?

We want an unified experience for landing into the feature, set up and start the first connection.

# How?

- Move everything to GettingStarted Package.
- Consolidate GettingStarted for Setup, Onboarding and dealing with empty state.
- Getting started tab in home so that people can look at the documentation and setup status.
- Don't use feature in setup modal.
- Remove `FeatureList`, `Feature` and `FeatureCard`.
- Extract getting started into separate component
- Use the style provided by Patrick.

# Screenshots


![Screenshot 2025-03-06 at 13 50 57](https://github.com/user-attachments/assets/635128ed-a92f-4fad-88c8-8173af058e96)
![Screenshot 2025-03-06 at 13 52 00](https://github.com/user-attachments/assets/bb132dc8-778f-4809-94c5-fa10459b66e5)
![Screenshot 2025-03-06 at 13 53 06](https://github.com/user-attachments/assets/1f099efa-fcaa-4d1c-aa6f-c81cae6517bb)
![Screenshot 2025-03-06 at 13 54 05](https://github.com/user-attachments/assets/2be9b198-1c70-4317-8985-0a467b37d431)
![Screenshot 2025-03-06 at 13 54 06](https://github.com/user-attachments/assets/65075844-c9a9-4609-9125-8bb62c459fca)
![Screenshot 2025-03-06 at 13 54 10](https://github.com/user-attachments/assets/f7c78e06-cd11-4bb8-8b8f-f94c02567ea0)
![Screenshot 2025-03-06 at 13 54 18](https://github.com/user-attachments/assets/fdaabac8-4a48-48f3-8667-ab1dcedd2b38)
![Screenshot 2025-03-06 at 13 56 20](https://github.com/user-attachments/assets/451f6592-1234-482f-be24-c4ec307dab01)



Diff:
diff --git a/.betterer.results b/.betterer.results
index b441dfcfe6c92..feebda97797b4 100644
--- a/.betterer.results
+++ b/.betterer.results
@@ -5681,6 +5681,41 @@ 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"]
     ],
+    "public/app/features/provisioning/GettingStarted/EnhancedFeatures.tsx:5381": [
+      [0, 0, 0, "Do not use any type assertions.", "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"]
+    ],
+    "public/app/features/provisioning/GettingStarted/FeaturesList.tsx:5381": [
+      [0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"],
+      [0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "1"],
+      [0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "2"],
+      [0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "3"],
+      [0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "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"]
+    ],
+    "public/app/features/provisioning/GettingStarted/GettingStarted.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. Wrap text with <Trans />", "1"],
+      [0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "2"]
+    ],
+    "public/app/features/provisioning/GettingStarted/SetupModal.tsx:5381": [
+      [0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"],
+      [0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "1"],
+      [0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "2"]
+    ],
     "public/app/features/provisioning/JobStatus.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"],
@@ -5700,15 +5735,6 @@ exports[`better eslint`] = {
       [0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "6"],
       [0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "7"]
     ],
-    "public/app/features/provisioning/OnboardingPage.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. Wrap text with <Trans />", "1"],
-      [0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "2"],
-      [0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "3"],
-      [0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "4"],
-      [0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "5"],
-      [0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "6"]
-    ],
     "public/app/features/provisioning/RecentJobs.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"],
@@ -5783,25 +5809,6 @@ exports[`better eslint`] = {
       [0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "14"],
       [0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "15"]
     ],
-    "public/app/features/provisioning/Setup/FeatureCard.tsx:5381": [
-      [0, 0, 0, "Do not use any type assertions.", "0"],
-      [0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "1"],
-      [0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "2"]
-    ],
-    "public/app/features/provisioning/Setup/SetupModal.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. Wrap text with <Trans />", "1"],
-      [0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "2"],
-      [0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "3"]
-    ],
-    "public/app/features/provisioning/Setup/StatusAlerts.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. Wrap text with <Trans />", "3"],
-      [0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "4"],
-      [0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "5"]
-    ],
     "public/app/features/provisioning/SyncRepository.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. Wrap text with <Trans />", "1"]
diff --git a/public/app/features/provisioning/ConfigFormGithubCollapse.tsx b/public/app/features/provisioning/ConfigFormGithubCollapse.tsx
index a8eb122290be1..ec55df5e1c635 100644
--- a/public/app/features/provisioning/ConfigFormGithubCollapse.tsx
+++ b/public/app/features/provisioning/ConfigFormGithubCollapse.tsx
@@ -3,7 +3,7 @@ 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 { checkPublicAccess } from './GettingStarted/features';
 import { PROVISIONING_URL } from './constants';
 
 export interface ConfigFormGithubCollpaseProps {
diff --git a/public/app/features/provisioning/GettingStarted/EnhancedFeatures.tsx b/public/app/features/provisioning/GettingStarted/EnhancedFeatures.tsx
new file mode 100644
index 0000000000000..5b1f961345b32
--- /dev/null
+++ b/public/app/features/provisioning/GettingStarted/EnhancedFeatures.tsx
@@ -0,0 +1,74 @@
+import { css } from '@emotion/css';
+
+import { Box, Stack, Text, LinkButton, Icon, IconName } from '@grafana/ui';
+
+import { FeatureCard } from './FeatureCard';
+
+interface IconCircleProps {
+  icon: string;
+  color: string;
+  background: string;
+}
+
+const IconCircle = ({ icon, color, background }: IconCircleProps) => (
+  <div
+    className={css({
+      background: `${background}`,
+      borderRadius: `50%`,
+      padding: `16px`,
+      width: `fit-content`,
+    })}
+  >
+    <Icon name={icon as IconName} size="xxl" color={color} />
+  </div>
+);
+
+interface EnhancedFeaturesProps {
+  hasPublicAccess: boolean;
+  hasImageRenderer: boolean;
+  onSetupPublicAccess: () => void;
+}
+
+export const EnhancedFeatures = ({ hasPublicAccess, hasImageRenderer, onSetupPublicAccess }: EnhancedFeaturesProps) => (
+  <Box marginTop={2}>
+    <Text variant="h2">Unlock enhanced functionality for GitHub</Text>
+    <Box marginTop={4}>
+      <Stack direction="row" gap={2}>
+        <FeatureCard
+          title="Instantenous provisioning"
+          description="Automatically provision and update your dashboards as soon as changes are pushed to your GitHub repository"
+          icon={<IconCircle icon="sync" color="primary" background="rgba(24, 121, 219, 0.12)" />}
+          action={
+            !hasPublicAccess && (
+              <LinkButton fill="outline" onClick={onSetupPublicAccess}>
+                Set up public access
+              </LinkButton>
+            )
+          }
+          showBorder
+        />
+        <FeatureCard
+          title="Visual previews in pull requests"
+          description="Review how your changes look like before going live in Grafana and directly in pull requests"
+          icon={
+            <Stack direction="row" gap={2}>
+              <IconCircle icon="camera" color="orange" background="rgba(255, 120, 10, 0.12)" />
+              <IconCircle icon="code-branch" color="purple" background="rgba(135, 73, 237, 0.12)" />
+            </Stack>
+          }
+          action={
+            !hasImageRenderer && (
+              <LinkButton
+                fill="outline"
+                href="https://grafana.com/grafana/plugins/grafana-image-renderer/"
+                icon="external-link-alt"
+              >
+                Set up image rendering
+              </LinkButton>
+            )
+          }
+        />
+      </Stack>
+    </Box>
+  </Box>
+);
diff --git a/public/app/features/provisioning/GettingStarted/FeatureCard.tsx b/public/app/features/provisioning/GettingStarted/FeatureCard.tsx
new file mode 100644
index 0000000000000..92db7ac7609a1
--- /dev/null
+++ b/public/app/features/provisioning/GettingStarted/FeatureCard.tsx
@@ -0,0 +1,29 @@
+import { css } from '@emotion/css';
+
+import { Box, Stack, Text } from '@grafana/ui';
+
+interface FeatureCardProps {
+  title: string;
+  description: string;
+  icon?: React.ReactNode;
+  action?: React.ReactNode;
+  showBorder?: boolean;
+}
+
+export const FeatureCard = ({ title, description, icon, action, showBorder = false }: FeatureCardProps) => (
+  <Box width="25%" padding={2}>
+    <div
+      className={css({
+        borderRight: showBorder ? ': 1px solid rgba(204, 204, 220, 0.15);' : undefined,
+        height: `100%`,
+      })}
+    >
+      <Stack direction="column" gap={2}>
+        {icon}
+        <Text variant="h3">{title}</Text>
+        <Text variant="body">{description}</Text>
+        {action && <Box>{action}</Box>}
+      </Stack>
+    </div>
+  </Box>
+);
diff --git a/public/app/features/provisioning/GettingStarted/FeaturesList.tsx b/public/app/features/provisioning/GettingStarted/FeaturesList.tsx
new file mode 100644
index 0000000000000..78dcef76ca6b9
--- /dev/null
+++ b/public/app/features/provisioning/GettingStarted/FeaturesList.tsx
@@ -0,0 +1,113 @@
+import { Stack, Text, Box, LinkButton, Icon } from '@grafana/ui';
+
+import { RepositoryViewList } from '../api';
+import { CONNECT_URL, MIGRATE_URL } from '../constants';
+
+interface FeatureItemProps {
+  children: React.ReactNode;
+}
+
+const FeatureItem = ({ children }: FeatureItemProps) => (
+  <Text variant="body">
+    <Icon name="check" className="text-success" /> {children}
+  </Text>
+);
+
+interface FeaturesListProps {
+  settings?: RepositoryViewList;
+  hasPublicAccess: boolean;
+  hasImageRenderer: boolean;
+  hasRequiredFeatures: boolean;
+  onSetupFeatures: () => void;
+}
+
+export const FeaturesList = ({
+  settings,
+  hasPublicAccess,
+  hasImageRenderer,
+  hasRequiredFeatures,
+  onSetupFeatures,
+}: FeaturesListProps) => {
+  const actions = () => {
+    if (!hasRequiredFeatures) {
+      return (
+        <Box>
+          <LinkButton fill="outline" onClick={onSetupFeatures}>
+            Set up required feature toggles
+          </LinkButton>
+        </Box>
+      );
+    }
+
+    const isInstance = Boolean(settings?.items.some((item) => item.target === 'instance'));
+    if (isInstance || !settings) {
+      return null; // already setup and can not add more
+    }
+
+    // When legacy you can only migrate
+    if (settings.legacyStorage) {
+      return (
+        <Stack>
+          <LinkButton size="md" icon="plus" href={MIGRATE_URL}>
+            Migrate Grafana to repository
+          </LinkButton>
+        </Stack>
+      );
+    }
+
+    // Repos are already setup (and not targeting instance)
+    if (settings.items.length) {
+      // or instance is empty?
+      return (
+        <Stack>
+          <LinkButton fill="outline" icon="plus" href={CONNECT_URL}>
+            Connect Grafana to repository
+          </LinkButton>
+        </Stack>
+      );
+    }
+
+    // Could choose either
+    return (
+      <Stack direction="row" alignItems="center" gap={2}>
+        <LinkButton size="md" icon="plus" href={MIGRATE_URL}>
+          Migrate Grafana to repository
+        </LinkButton>
+        <Text variant="body">or</Text>
+        <LinkButton fill="outline" icon="plus" href={CONNECT_URL}>
+          Connect Grafana to repository
+        </LinkButton>
+      </Stack>
+    );
+  };
+
+  return (
+    <Stack direction="column" gap={2}>
+      <Text variant="h2">Provisioning as-code directly from Grafana</Text>
+      <FeatureItem>
+        Manage your dashboards as code and deploy them automatically from your GitHub repository or local storage
+      </FeatureItem>
+      <FeatureItem>
+        Review, discuss, and approve dashboard changes with your team before they go live using GitHub pull requests
+      </FeatureItem>
+      <FeatureItem>
+        Export your existing dashboards as code and store them in GitHub repositories for version control and
+        collaboration
+      </FeatureItem>
+      {hasPublicAccess && (
+        <FeatureItem>
+          Automatically provision and update your dashboards as soon as changes are pushed to your GitHub repository
+        </FeatureItem>
+      )}
+      {hasImageRenderer && hasPublicAccess && (
+        <FeatureItem>Visual previews in pull requests to review your changes before going live</FeatureItem>
+      )}
+
+      <LinkButton fill="text" href="#" icon="external-link-alt">
+        Learn more
+      </LinkButton>
+
+      {actions()}
+    </Stack>
+  );
+};
diff --git a/public/app/features/provisioning/GettingStarted/GettingStarted.tsx b/public/app/features/provisioning/GettingStarted/GettingStarted.tsx
new file mode 100644
index 0000000000000..bfad586ca2323
--- /dev/null
+++ b/public/app/features/provisioning/GettingStarted/GettingStarted.tsx
@@ -0,0 +1,157 @@
+import { css } from '@emotion/css';
+import { useState } from 'react';
+
+import { Alert, Stack, Text, Box } from '@grafana/ui';
+
+import { useGetFrontendSettingsQuery } from '../api';
+
+import { EnhancedFeatures } from './EnhancedFeatures';
+import { FeaturesList } from './FeaturesList';
+import { SetupModal } from './SetupModal';
+import { getConfigurationStatus } from './features';
+
+type SetupType = 'public-access' | 'required-features' | null;
+
+// Configuration examples
+const featureIni = `# In your custom.ini file
+app_mode = development
+
+[feature_toggles]
+provisioning = true
+kubernetesDashboards = true
+unifiedStorageSearch = true
+kubernetesClientDashboardsFolders = true
+
+# If you want easy kubectl setup development mode
+grafanaAPIServerEnsureKubectlAccess = true`;
+
+const ngrokExample = `ngrok http 3000
+
+Help shape K8s Bindings https://ngrok.com/new-features-update?ref=k8s
+
+Session Status                online
+Account                       Roberto Jiménez Sánchez (Plan: Free)
+Version                       3.18.4
+Region                        Europe (eu)
+Latency                       44ms
+Web Interface                 http://127.0.0.1:4040
+Forwarding                    https://d60d-83-33-235-27.ngrok-free.app -> http://localhost:3000
+Connections                   ttl     opn     rt1     rt5     p50     p90
+                              50      2       0.00    0.00    83.03   90.56
+
+HTTP Requests
+-------------
+
+09:18:46.147 CET             GET  /favicon.ico                   302 Found
+09:18:46.402 CET             GET  /login`;
+
+const rootUrlExample = `[server]
+root_url = https://d60d-83-33-235-27.ngrok-free.app`;
+
+export default function GettingStarted() {
+  const settingsQuery = useGetFrontendSettingsQuery();
+  const legacyStorage = settingsQuery.data?.legacyStorage;
+
+  const { hasPublicAccess, hasImageRenderer, hasRequiredFeatures } = getConfigurationStatus();
+  const [showInstructionsModal, setShowModal] = useState(false);
+  const [setupType, setSetupType] = useState<SetupType>(null);
+
+  const getModalContent = () => {
+    switch (setupType) {
+      case 'public-access':
+        return {
+          title: 'Set up public access',
+          description: 'Set up public access to your Grafana instance to enable GitHub integration',
+          steps: [
+            {
+              title: 'Start ngrok for temporary public access',
+              description: 'Run this command to create a secure tunnel to your local Grafana:',
+              code: 'ngrok http 3000',
+            },
+            {
+              title: 'Copy your public URL',
+              description: 'From the ngrok output, copy the https:// forwarding URL that looks like this:',
+              code: ngrokExample,
+              copyCode: false,
+            },
+            {
+              title: 'Update your Grafana configuration',
+              description: 'Add this to your custom.ini file, replacing the URL with your actual ngrok URL:',
+              code: rootUrlExample,
+            },
+          ],
+        };
+      case 'required-features':
+        return {
+          title: 'Set up required features',
+          description: 'Enable required Grafana features for provisioning',
+          steps: [
+            {
+              title: 'Enable Required Feature Toggles',
+              description: 'Add these settings to your custom.ini file to enable necessary features:',
+              code: featureIni,
+            },
+          ],
+        };
+      default:
+        return {
+          title: '',
+          description: '',
+          steps: [],
+        };
+    }
+  };
+
+  return (
+    <>
+      {legacyStorage && (
+        <Alert severity="info" title="Setting up this connection could cause a temporary outage">
+          When you connect your whole instance, dashboards will be unavailable while running the migration. We recommend
+          warning your users before starting the process.
+        </Alert>
+      )}
+      <Stack direction="row" gap={2}>
+        <Box width="50%" marginTop={2} paddingTop={2} paddingBottom={2}>
+          <FeaturesList
+            settings={settingsQuery.data}
+            hasPublicAccess={hasPublicAccess}
+            hasImageRenderer={hasImageRenderer}
+            hasRequiredFeatures={hasRequiredFeatures}
+            onSetupFeatures={() => {
+              setSetupType('required-features');
+              setShowModal(true);
+            }}
+          />
+        </Box>
+        <Box width="50%">
+          <div
+            className={css({
+              height: `100%`,
+              background: `linear-gradient(to right, rgba(255, 179, 102, 0.6), rgba(255, 143, 143, 0.8))`,
+              borderRadius: `4px`,
+              padding: `16px`,
+              display: `flex`,
+              alignItems: `center`,
+              justifyContent: `center`,
+            })}
+          >
+            <Text variant="h2">Engaging graphic</Text>
+          </div>
+        </Box>
+      </Stack>
+      {(!hasPublicAccess || !hasImageRenderer) && (
+        <EnhancedFeatures
+          hasPublicAccess={hasPublicAccess}
+          hasImageRenderer={hasImageRenderer}
+          onSetupPublicAccess={() => {
+            setSetupType('public-access');
+            setShowModal(true);
+          }}
+        />
+      )}
+      {showInstructionsModal && setupType && (
+        <SetupModal {...getModalContent()} isOpen={showInstructionsModal} onDismiss={() => setShowModal(false)} />
+      )}
+    </>
+  );
+}
diff --git a/public/app/features/provisioning/GettingStarted/GettingStartedPage.tsx b/public/app/features/provisioning/GettingStarted/GettingStartedPage.tsx
new file mode 100644
index 0000000000000..cee8e4abad37c
--- /dev/null
+++ b/public/app/features/provisioning/GettingStarted/GettingStartedPage.tsx
@@ -0,0 +1,20 @@
+import { Page } from 'app/core/components/Page/Page';
+
+import GettingStarted from './GettingStarted';
+
+export default function GettingStartedPage() {
+  return (
+    <Page
+      navId="provisioning"
+      pageNav={{
+        text: 'Getting started with Provisioning',
+        subTitle:
+          'Provisioning is a feature that allows you to manage your dashboards using GitHub and other storage systems',
+      }}
+    >
+      <Page.Contents>
+        <GettingStarted />
+      </Page.Contents>
+    </Page>
+  );
+}
diff --git a/public/app/features/provisioning/Setup/SetupModal.tsx b/public/app/features/provisioning/GettingStarted/SetupModal.tsx
similarity index 81%
rename from public/app/features/provisioning/Setup/SetupModal.tsx
rename to public/app/features/provisioning/GettingStarted/SetupModal.tsx
index 7e1f5953afad6..d9eadb7b5a0dc 100644
--- a/public/app/features/provisioning/Setup/SetupModal.tsx
+++ b/public/app/features/provisioning/GettingStarted/SetupModal.tsx
@@ -6,38 +6,40 @@ import { Modal, Button, useStyles2, Stack, Text } from '@grafana/ui';
 
 import { SetupStep } from './SetupStep';
 import { Sidebar } from './Sidebar';
-import { Feature } from './types';
+import { Step } from './types';
 
 export interface Props {
-  feature: Feature;
+  title: string;
+  description: string;
+  steps: Step[];
 
   isOpen: boolean;
   onDismiss: () => void;
 }
 
-export const SetupModal = ({ feature, isOpen, onDismiss }: Props) => {
+export const SetupModal = ({ title, description, steps, isOpen, onDismiss }: Props) => {
   const styles = useStyles2(getStyles);
 
   const [currentStep, setCurrentStep] = useState(0);
 
   const isFirstStep = currentStep === 0;
-  const isLastStep = currentStep === feature.setupSteps.length - 1;
-  const stepTitles = feature.setupSteps.map((step) => step.title);
+  const isLastStep = currentStep === steps.length - 1;
+  const stepTitles = steps.map((step) => step.title);
 
   const handleNext = () => !isLastStep && setCurrentStep(currentStep + 1);
   const handlePrevious = () => !isFirstStep && setCurrentStep(currentStep - 1);
 
   return (
-    <Modal isOpen={isOpen} title={`Setup ${feature.title}`} onDismiss={onDismiss} className={styles.modal}>
+    <Modal isOpen={isOpen} title={title} onDismiss={onDismiss} className={styles.modal}>
       <Stack direction={'column'} gap={4}>
         <Text variant="body" color="secondary">
-          {feature.description}
+          {description}
         </Text>
         <Stack direction="row" height="100%">
           <Sidebar steps={stepTitles} currentStep={currentStep} onStepClick={setCurrentStep} />
 
           <div className={styles.contentWrapper}>
-            <SetupStep step={feature.setupSteps[currentStep]} />
+            <SetupStep step={steps[currentStep]} />
           </div>
         </Stack>
       </Stack>
diff --git a/public/app/features/provisioning/Setup/SetupStep.tsx b/public/app/features/provisioning/GettingStarted/SetupStep.tsx
similarity index 100%
rename from public/app/features/provisioning/Setup/SetupStep.tsx
rename to public/app/features/provisioning/GettingStarted/SetupStep.tsx
diff --git a/public/app/features/provisioning/Setup/Sidebar.tsx b/public/app/features/provisioning/GettingStarted/Sidebar.tsx
similarity index 100%
rename from public/app/features/provisioning/Setup/Sidebar.tsx
rename to public/app/features/provisioning/GettingStarted/Sidebar.tsx
diff --git a/public/app/features/provisioning/Setup/SidebarItem.tsx b/public/app/features/provisioning/GettingStarted/SidebarItem.tsx
similarity index 100%
rename from public/app/features/provisioning/Setup/SidebarItem.tsx
rename to public/app/features/provisioning/GettingStarted/SidebarItem.tsx
diff --git a/public/app/features/provisioning/Setup/utils.ts b/public/app/features/provisioning/GettingStarted/features.ts
similarity index 86%
rename from public/app/features/provisioning/Setup/utils.ts
rename to public/app/features/provisioning/GettingStarted/features.ts
index fc81bf4ad4baf..80bb1ef3c8847 100644
--- a/public/app/features/provisioning/Setup/utils.ts
+++ b/public/app/features/provisioning/GettingStarted/features.ts
@@ -1,6 +1,12 @@
+import { FeatureToggles } from '@grafana/data';
 import { config } from '@grafana/runtime';
 
-import { requiredFeatureToggles } from './types';
+export const requiredFeatureToggles: Array<keyof FeatureToggles> = [
+  'provisioning',
+  'kubernetesDashboards',
+  'kubernetesClientDashboardsFolders',
+  'unifiedStorageSearch',
+];
 
 /**
  * Checks if all required feature toggles are enabled
diff --git a/public/app/features/provisioning/GettingStarted/types.ts b/public/app/features/provisioning/GettingStarted/types.ts
new file mode 100644
index 0000000000000..4df5ccf2c792b
--- /dev/null
+++ b/public/app/features/provisioning/GettingStarted/types.ts
@@ -0,0 +1,6 @@
+export interface Step {
+  title: string;
+  description?: string;
+  code?: string;
+  copyCode?: boolean;
+}
diff --git a/public/app/features/provisioning/OnboardingPage.tsx b/public/app/features/provisioning/OnboardingPage.tsx
deleted file mode 100644
index f5e4f439199cc..0000000000000
--- a/public/app/features/provisioning/OnboardingPage.tsx
+++ /dev/null
@@ -1,81 +0,0 @@
-import SVG from 'react-inlinesvg';
-import { useNavigate } from 'react-router-dom-v5-compat';
-
-import { EmptyState, LinkButton, Alert, Stack, Text, Button, Box, Card } from '@grafana/ui';
-import { Page } from 'app/core/components/Page/Page';
-
-import { FeatureList } from './Setup/FeatureList';
-import { useGetFrontendSettingsQuery } from './api';
-import { CONNECT_URL, MIGRATE_URL } from './constants';
-
-export default function OnboardingPage({ legacyStorage }: { legacyStorage?: boolean }) {
-  const settingsQuery = useGetFrontendSettingsQuery();
-  const navigate = useNavigate();
-
-  return (
-    <Page
-      navId="provisioning"
-      pageNav={{
-        text: 'Setup provisioning',
-        subTitle:
-          'Configure your Grafana instance to use provisioning to manage your dashboards using GitHub and other storage systems',
-      }}
-    >
-      <Page.Contents>
-        {legacyStorage && (
-          <Alert severity="info" title="Setting up this connection could cause a temporary outage">
-            When you connect your whole instance, dashboards will be unavailable while running the migration. We
-            recommend warning your users before starting the process.
-          </Alert>
-        )}
-        <EmptyState
-          variant="call-to-action"
-          message="Set up your provisioning connection!"
-          image={<SVG src="public/img/provisioning-empty.svg" width={300} />}
-          button={
-            <Button
-              size="lg"
-              icon="plus"
-              onClick={async () => {
-                await settingsQuery.refetch();
-                navigate(MIGRATE_URL);
-              }}
-            >
-              Migrate Grafana to repository
-            </Button>
-          }
-        >
-          <Stack direction="column" alignItems="center">
-            <Text>Store and provision your Grafana resources externally by connecting to a repository.</Text>
-            <LinkButton fill="text" href="#" icon="external-link-alt">
-              Learn more
-            </LinkButton>
-          </Stack>
-        </EmptyState>
-        <Stack direction="column" gap={2} alignItems="center" justifyContent="center">
-          <Box padding={2}>
-            <Card>
-              <Card.Description>
-                Alternatively, connect to repository and add more repositories for other folders as needed
-              </Card.Description>
-              <Card.Actions>
-                <Button
-                  size="md"
-                  variant="secondary"
-                  icon="plus"
-                  onClick={async () => {
-                    await settingsQuery.refetch();
-                    navigate(CONNECT_URL);
-                  }}
-                >
-                  Connect Grafana to repository
-                </Button>
-              </Card.Actions>
-            </Card>
-          </Box>
-        </Stack>
-        <FeatureList />
-      </Page.Contents>
-    </Page>
-  );
-}
diff --git a/public/app/features/provisioning/RepositoryListPage.tsx b/public/app/features/provisioning/RepositoryListPage.tsx
index c44c0dbd5bbc5..a9684916ee2fc 100644
--- a/public/app/features/provisioning/RepositoryListPage.tsx
+++ b/public/app/features/provisioning/RepositoryListPage.tsx
@@ -21,8 +21,8 @@ import {
 import { Page } from 'app/core/components/Page/Page';
 
 import { DeleteRepositoryButton } from './DeleteRepositoryButton';
-import OnboardingPage from './OnboardingPage';
-import { FeatureList } from './Setup/FeatureList';
+import GettingStarted from './GettingStarted/GettingStarted';
+import GettingStartedPage from './GettingStarted/GettingStartedPage';
 import { StatusBadge } from './StatusBadge';
 import { SyncRepository } from './SyncRepository';
 import { Repository, ResourceCount, useDeletecollectionRepositoryMutation, useGetFrontendSettingsQuery } from './api';
@@ -49,7 +49,7 @@ export default function RepositoryListPage() {
   }, [deleteAllResult.isSuccess]);
 
   if (!items?.length && !isLoading) {
-    return <OnboardingPage legacyStorage={settings.data?.legacyStorage} />;
+    return <GettingStartedPage />;
   }
 
   const onConfirmDelete = () => {
@@ -61,8 +61,8 @@ export default function RepositoryListPage() {
     switch (activeTab) {
       case 'repositories':
         return <RepositoryListPageContent items={items ?? []} />;
-      case 'features':
-        return <FeatureList />;
+      case 'getting-started':
+        return <GettingStarted />;
       default:
         return null;
     }
@@ -98,7 +98,11 @@ export default function RepositoryListPage() {
               active={activeTab === 'repositories'}
               onChangeTab={() => setActiveTab('repositories')}
             />
-            <Tab label="Features" active={activeTab === 'features'} onChangeTab={() => setActiveTab('features')} />
+            <Tab
+              label="Getting started"
+              active={activeTab === 'getting-started'}
+              onChangeTab={() => setActiveTab('getting-started')}
+            />
           </TabsBar>
           {renderTabContent()}
         </Stack>
diff --git a/public/app/features/provisioning/Setup/FeatureCard.tsx b/public/app/features/provisioning/Setup/FeatureCard.tsx
deleted file mode 100644
index bc6ec9967a570..0000000000000
--- a/public/app/features/provisioning/Setup/FeatureCard.tsx
+++ /dev/null
@@ -1,56 +0,0 @@
-import { Button, Icon, IconName, Text, Card, Stack, LinkButton } from '@grafana/ui';
-
-import { Feature } from './types';
-
-interface Props {
-  feature: Feature;
-  onSetup: () => void;
-  showSetupButton?: boolean;
-}
-
-export const FeatureCard = ({ feature, onSetup, showSetupButton = true }: Props) => {
-  const isConfigured = feature.isConfigured;
-  const iconName = (feature.icon || 'apps') as IconName;
-
-  return (
-    <Card>
-      <Card.Heading>
-        <Stack justifyContent="center" width="100%">
-          <Text element="h2" variant="h2">
-            {feature.title}
-          </Text>
-        </Stack>
-      </Card.Heading>
-
-      <Card.Description>
-        <Stack direction="column" gap={2} justifyContent="center" alignItems="center">
-          <Icon name={iconName} size="xxxl" />
-          <Text color="secondary">{feature.description}</Text>
-        </Stack>
-      </Card.Description>
-      {(feature.docsLink || showSetupButton) && (
-        <Card.Actions>
-          <Stack justifyContent="center" width="100%">
-            {showSetupButton && !isConfigured && onSetup && feature.setupSteps.length > 0 && (
-              <Button variant="primary" onClick={onSetup}>
-                Set Up Now
-              </Button>
-            )}
-            {feature.docsLink && (
-              <LinkButton fill="text" href={feature.docsLink} icon="external-link-alt">
-                Learn more
-              </LinkButton>
-            )}
-          </Stack>
-        </Card.Actions>
-      )}
-      <Card.SecondaryActions>
-        {isConfigured ? (
-          <Icon name="check-circle" color="green" size="lg" />
-        ) : (
-          <Icon name="exclamation-triangle" size="lg" color={feature.additional ? 'orange' : 'red'} />
-        )}
-      </Card.SecondaryActions>
-    </Card>
-  );
-};
diff --git a/public/app/features/provisioning/Setup/FeatureList.tsx b/public/app/features/provisioning/Setup/FeatureList.tsx
deleted file mode 100644
index 462119cab4ea8..0000000000000
--- a/public/app/features/provisioning/Setup/FeatureList.tsx
+++ /dev/null
@@ -1,156 +0,0 @@
-import { useState, useEffect } from 'react';
-
-import { Stack } from '@grafana/ui';
-
-import { FeatureCard } from './FeatureCard';
-import { SetupModal } from './SetupModal';
-import { Feature, feature_ini, ngrok_example, root_url_ini } from './types';
-import { getConfigurationStatus } from './utils';
-
-export const FeatureList = () => {
-  const [features, setFeatures] = useState<Feature[]>([]);
-  const [showInstructionsModal, setShowModal] = useState(false);
-  const [activeFeature, setActiveFeature] = useState<Feature | null>(null);
-  const { hasPublicAccess, hasImageRenderer, hasRequiredFeatures } = getConfigurationStatus();
-
-  useEffect(() => {
-    const enableFeatureSteps = [
-      {
-        title: 'Enable Required Feature Toggles',
-        description: 'Add these settings to your custom.ini file to enable necessary features:',
-        code: feature_ini,
-      },
-    ];
-    // Initialize features with their current status
-    const featuresList: Feature[] = [
-      {
-        title: 'Provision As-Code',
-        description:
-          'Manage your dashboards as code and deploy them automatically from your GitHub repository or local storage',
-        additional: false,
-        setupSteps: enableFeatureSteps,
-        isConfigured: hasRequiredFeatures,
-        docsLink: 'https://grafana.com/docs/grafana/latest/setup-grafana/configure-grafana/feature-toggles',
-        icon: 'sync',
-      },
-      {
-        title: 'Pull Requests',
-        description:
-          'Review, discuss, and approve dashboard changes with your team before they go live using GitHub pull requests',
-        additional: false,
-        setupSteps: enableFeatureSteps,
-        icon: 'code-branch',
-        isConfigured: hasRequiredFeatures,
-        docsLink: 'https://grafana.com/docs/grafana/latest/setup-grafana/configure-grafana/feature-toggles',
-      },
-      {
-        title: 'Export As-Code',
-        description:
-          'Export your existing dashboards as code and store them in GitHub repositories for version control and collaboration',
-        additional: false,
-        setupSteps: enableFeatureSteps,
-        icon: 'cloud-upload',
-        isConfigured: hasRequiredFeatures,
-        docsLink: 'https://grafana.com/docs/grafana/latest/setup-grafana/configure-grafana/feature-toggles',
-      },
-      {
-        title: 'GitHub Webhooks',
-        description:
-          'Automatically provision and update your dashboards as soon as changes are pushed to your GitHub repository',
-        additional: true,
-        icon: 'github',
-        isConfigured: hasPublicAccess && hasRequiredFeatures,
-        setupSteps: [
-          {
-            title: 'Start ngrok for temporary public access',
-            description: 'Run this command to create a secure tunnel to your local Grafana:',
-            code: 'ngrok http 3000',
-          },
-          {
-            title: 'Copy your public URL',
-            description: 'From the ngrok output, copy the https:// forwarding URL that looks like this:',
-            code: ngrok_example,
-            copyCode: false,
-          },
-          {
-            title: 'Update your Grafana configuration',
-            description: 'Add this to your custom.ini file, replacing the URL with your actual ngrok URL:',
-            code: root_url_ini,
-          },
-        ],
-      },
-      {
-        title: 'Previews',
-        description:
-          'Preview dashboard changes visually in pull requests before they go live, making team reviews faster and more effective',
-        icon: 'camera',
-        additional: true,
-        isConfigured: hasImageRenderer && hasPublicAccess && hasRequiredFeatures,
-        docsLink: 'https://grafana.com/grafana/plugins/grafana-image-renderer/',
-        setupSteps: [],
-      },
-    ];
-
-    setFeatures(featuresList);
-  }, [hasImageRenderer, hasPublicAccess, hasRequiredFeatures]);
-
-  // Add a state variable to store the basic setup
-  const [basicSetup] = useState<Feature>({
-    title: 'Provisioning',
-    description: 'Enable required Grafana features for provisioning',
-    additional: false,
-    icon: 'cog',
-    isConfigured: hasRequiredFeatures,
-    setupSteps: [
-      {
-        title: 'Enable Required Feature Toggles',
-        description: 'Add these settings to your custom.ini file to enable necessary features:',
-        code: feature_ini,
-      },
-    ],
-  });
-
-  const showModal = (feature: Feature) => {
-    // only show modal if feature is not configured
-    if (!feature.isConfigured) {
-      setActiveFeature(feature);
-      setShowModal(true);
-    }
-  };
-
-  const onDismiss = () => {
-    setShowModal(false);
-    setActiveFeature(null);
-  };
-
-  // Separate required and optional features
-  const requiredFeatures = features.filter((feature) => !feature.additional);
-  const optionalFeatures = features.filter((feature) => feature.additional);
-
-  return (
-    <Stack direction="column" gap={4}>
-      <Stack direction="row" gap={2} justifyContent="center">
-        {requiredFeatures.map((feature, index) => (
-          <FeatureCard
-            key={index}
-            feature={feature}
-            onSetup={() => showModal(basicSetup)}
-            showSetupButton={!feature.isConfigured}
-          />
-        ))}
-        {optionalFeatures.map((feature, index) => (
-          <FeatureCard
-            key={index}
-            feature={feature}
-            onSetup={() => showModal(feature)}
-            showSetupButton={!feature.isConfigured}
-          />
-        ))}
-      </Stack>
-
-      {showInstructionsModal && activeFeature && (
-        <SetupModal feature={activeFeature} isOpen={true} onDismiss={onDismiss} />
-      )}
-    </Stack>
-  );
-};
diff --git a/public/app/features/provisioning/Setup/SetupPage.tsx b/public/app/features/provisioning/Setup/SetupPage.tsx
deleted file mode 100644
index 4df1883ba72aa..0000000000000
--- a/public/app/features/provisioning/Setup/SetupPage.tsx
+++ /dev/null
@@ -1,18 +0,0 @@
-import { Page } from 'app/core/components/Page/Page';
-
-import { FeatureList } from './FeatureList';
-import { StatusAlerts } from './StatusAlerts';
-
-export default function SetupPage() {
-  return (
-    <Page
-      navModel={{ main: { text: '' }, node: { text: 'Provisioning Setup' } }}
-      subTitle="Configure your Grafana instance to use provisioning to manage your dashboards using GitHub and other storage systems."
-    >
-      <Page.Contents>
-        <StatusAlerts showSetupButton={false} showSuccessBanner={true} />
-        <FeatureList />
-      </Page.Contents>
-    </Page>
-  );
-}
diff --git a/public/app/features/provisioning/Setup/StatusAlerts.tsx b/public/app/features/provisioning/Setup/StatusAlerts.tsx
deleted file mode 100644
index 8384d015b9deb..0000000000000
--- a/public/app/features/provisioning/Setup/StatusAlerts.tsx
+++ /dev/null
@@ -1,65 +0,0 @@
-import { locationService } from '@grafana/runtime';
-import { Alert } from '@grafana/ui';
-
-import { getConfigurationStatus } from './utils';
-
-interface Props {
-  /**
-   * Whether to show the "Setup Now" button
-   * @default true
-   */
-  showSetupButton?: boolean;
-
-  /**
-   * Whether to show a success banner when everything is configured
-   * @default false
-   */
-  showSuccessBanner?: boolean;
-}
-
-export function StatusAlerts({ showSetupButton = true, showSuccessBanner = false }: Props) {
-  const { everythingConfigured, missingRequiredFeatures } = getConfigurationStatus();
-
-  // Early return if everything is configured and we don't want to show success banner
-  if (everythingConfigured && !showSuccessBanner) {
-    return null;
-  }
-
-  // Handle success case
-  if (everythingConfigured) {
-    return (
-      <Alert severity="success" title="All Features Configured">
-        All required and optional features are properly configured. Your system is ready to use.
-      </Alert>
-    );
-  }
-
-  const handleSetupClick = () => {
-    locationService.push('/admin/provisioning/setup');
-  };
-
-  const commonSetupButtonProps = showSetupButton
-    ? {
-        buttonContent: 'Set Up Now',
-        onRemove: handleSetupClick,
-      }
-    : {};
-
-  // Required features missing - show error alert
-  if (missingRequiredFeatures) {
-    return (
-      <Alert severity="error" title="Required Features Not Configured" {...commonSetupButtonProps}>
-        Some required features are not properly configured. Please complete the setup for these features to ensure the
-        system runs properly.
-      </Alert>
-    );
-  }
-
-  // Only optional features missing - show info alert
-  return (
-    <Alert severity="info" title="Additional Features Not Configured" {...commonSetupButtonProps}>
-      Some additional features like GitHub webhook integration or Previews are not configured. These features can
-      enhance your experience.
-    </Alert>
-  );
-}
diff --git a/public/app/features/provisioning/Setup/types.ts b/public/app/features/provisioning/Setup/types.ts
deleted file mode 100644
index 8c3af526b952a..0000000000000
--- a/public/app/features/provisioning/Setup/types.ts
+++ /dev/null
@@ -1,85 +0,0 @@
-import { FeatureToggles } from '@grafana/data';
-
-export interface Step {
-  title: string;
-  description?: string;
-  code?: string;
-  copyCode?: boolean;
-}
-
-export interface Feature {
-  title: string;
-  description: string;
-  additional: boolean;
-  icon?: string; // Optional icon name for the feature
-  setupSteps: Step[];
-  isConfigured: boolean;
-  docsLink?: string;
-}
-
-// List of required feature toggles
-export const requiredFeatureToggles: Array<keyof FeatureToggles> = [
-  'provisioning',
-  'kubernetesDashboards',
-  'kubernetesClientDashboardsFolders',
-  'unifiedStorageSearch',
-];
-
-// Configuration examples
-export const feature_ini = `# In your custom.ini file
-app_mode = development
-
-[feature_toggles]
-provisioning = true
-kubernetesDashboards = true
-unifiedStorageSearch = true
-kubernetesClientDashboardsFolders = true
-
-# If you want easy kubectl setup development mode
-grafanaAPIServerEnsureKubectlAccess = true`;
-
-// Configuration examples
-export const custom_ini = `# In your custom.ini file
-app_mode = development
-
-[feature_toggles]
-provisioning = true
-kubernetesDashboards = true
-unifiedStorageSearch = true
-kubernetesClientDashboardsFolders = true
-
-# If you want easy kubectl setup development mode
-grafanaAPIServerEnsureKubectlAccess = true
-
-# For Github webhook support, you will need something like:
-[server]
-root_url = https://supreme-exact-beetle.ngrok-free.app
-
-# For dashboard preview generation, you will need something like:
-[rendering]
-server_url = http://localhost:8081/render
-callback_url = http://localhost:3000/
- `;
-
-export const ngrok_example = `ngrok http 3000
-
-Help shape K8s Bindings https://ngrok.com/new-features-update?ref=k8s
-
-Session Status                online
-Account                       Roberto Jiménez Sánchez (Plan: Free)
-Version                       3.18.4
-Region                        Europe (eu)
-Latency                       44ms
-Web Interface                 http://127.0.0.1:4040
-Forwarding                    https://d60d-83-33-235-27.ngrok-free.app -> http://localhost:3000
-Connections                   ttl     opn     rt1     rt5     p50     p90
-                              50      2       0.00    0.00    83.03   90.56
-
-HTTP Requests
--------------
-
-09:18:46.147 CET             GET  /favicon.ico                   302 Found
-09:18:46.402 CET             GET  /login`;
-
-export const root_url_ini = `[server]
-root_url = https://d60d-83-33-235-27.ngrok-free.app`;
diff --git a/public/app/features/provisioning/Wizard/ConnectionStep.tsx b/public/app/features/provisioning/Wizard/ConnectionStep.tsx
index c6afc04160295..c2f4ab00e94c8 100644
--- a/public/app/features/provisioning/Wizard/ConnectionStep.tsx
+++ b/public/app/features/provisioning/Wizard/ConnectionStep.tsx
@@ -1,12 +1,13 @@
-import { Controller, useFormContext } from 'react-hook-form';
 import { useEffect } from 'react';
+import { Controller, useFormContext } from 'react-hook-form';
 
 import { Field, Input, Combobox, Stack, FieldSet, Card, Alert } from '@grafana/ui';
 
-import { WizardFormData } from './types';
 import { useGetFrontendSettingsQuery } from '../api';
 import { checkSyncSettings } from '../utils';
 
+import { WizardFormData } from './types';
+
 const typeOptions = [
   { label: 'GitHub', value: 'github' },
   { label: 'Local', value: 'local' },
@@ -15,9 +16,8 @@ const typeOptions = [
 const modeOptions = [
   {
     value: 'instance',
-    label: 'Connect your entire Grafana instance to an empty repository',
-    description:
-      'Export all dashboards from this instance to a new, empty repository. After setup, all dashboards in this instance will be saved and managed exclusively through this repository.',
+    label: 'Connect your entire Grafana instance to an external repository',
+    description: 'Read all dashboards from an external repository',
   },
   {
     value: 'folder',
diff --git a/public/app/features/provisioning/constants.ts b/public/app/features/provisioning/constants.ts
index 572df0e945b68..9855c0251445e 100644
--- a/public/app/features/provisioning/constants.ts
+++ b/public/app/features/provisioning/constants.ts
@@ -1,3 +1,4 @@
 export const PROVISIONING_URL = '/admin/provisioning';
 export const CONNECT_URL = `${PROVISIONING_URL}/connect`;
 export const MIGRATE_URL = `${PROVISIONING_URL}/migrate`;
+export const GETTING_STARTED_URL = `${PROVISIONING_URL}/getting-started`;
diff --git a/public/app/features/provisioning/utils/routes.ts b/public/app/features/provisioning/utils/routes.ts
index 4e7fe11b0561a..396761c5d10b7 100644
--- a/public/app/features/provisioning/utils/routes.ts
+++ b/public/app/features/provisioning/utils/routes.ts
@@ -1,18 +1,20 @@
-import { config } from '@grafana/runtime';
 import { SafeDynamicImport } from 'app/core/components/DynamicImports/SafeDynamicImport';
 import { RouteDescriptor } from 'app/core/navigation/types';
 import { DashboardRoutes } from 'app/types';
 
-import { requiredFeatureToggles } from '../Setup/types';
-import { PROVISIONING_URL, CONNECT_URL, MIGRATE_URL } from '../constants';
+import { checkRequiredFeatures } from '../GettingStarted/features';
+import { PROVISIONING_URL, CONNECT_URL, MIGRATE_URL, GETTING_STARTED_URL } from '../constants';
 
 export function getProvisioningRoutes(): RouteDescriptor[] {
-  if (!requiredFeatureToggles.every((toggle) => config.featureToggles[toggle])) {
+  if (!checkRequiredFeatures()) {
     return [
       {
         path: PROVISIONING_URL,
         component: SafeDynamicImport(
-          () => import(/* webpackChunkName: "SetupPage"*/ 'app/features/provisioning/Setup/SetupPage')
+          () =>
+            import(
+              /* webpackChunkName: "GettingStartedPage"*/ 'app/features/provisioning/GettingStarted/GettingStartedPage'
+            )
         ),
       },
     ];
@@ -26,9 +28,12 @@ export function getProvisioningRoutes(): RouteDescriptor[] {
       ),
     },
     {
-      path: PROVISIONING_URL + '/setup',
+      path: GETTING_STARTED_URL,
       component: SafeDynamicImport(
-        () => import(/* webpackChunkName: "SetupPage"*/ 'app/features/provisioning/Setup/SetupPage')
+        () =>
+          import(
+            /* webpackChunkName: "GettingStartedPage"*/ 'app/features/provisioning/GettingStarted/GettingStartedPage'
+          )
       ),
     },
     {


Reviews:
user: login: Clarity-89
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-06T13:36:47Z
user: login: ryantxu
body: merging...
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-06T21:50:49Z

Review comments:
diff_hunk: @@ -0,0 +1,270 @@
+import { useNavigate } from 'react-router-dom-v5-compat';
+
+import { LinkButton, Alert, Stack, Text, Button, Box, Icon } from '@grafana/ui';
+
+import { useGetFrontendSettingsQuery } from '../api';
+import { CONNECT_URL, MIGRATE_URL } from '../constants';
+import { css } from '@emotion/css';
+import { getConfigurationStatus } from './utils';
+import { useState } from 'react';
+import { SetupModal } from './SetupModal';
+import { feature_ini, ngrok_example, root_url_ini } from './types';
path: public/app/features/provisioning/GettingStarted/GettingStarted.tsx
user: login: Clarity-89
body: All the FE code should use camel case. Also these don't look like types, so shouldn't be in the `types` file.
created_at: 2025-03-06T13:32:41Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,270 @@
+import { useNavigate } from 'react-router-dom-v5-compat';
+
+import { LinkButton, Alert, Stack, Text, Button, Box, Icon } from '@grafana/ui';
+
+import { useGetFrontendSettingsQuery } from '../api';
+import { CONNECT_URL, MIGRATE_URL } from '../constants';
+import { css } from '@emotion/css';
+import { getConfigurationStatus } from './utils';
+import { useState } from 'react';
+import { SetupModal } from './SetupModal';
+import { feature_ini, ngrok_example, root_url_ini } from './types';
+
+type SetupType = 'public-access' | 'required-features' | null;
+
+export default function GettingStarted() {
+  const settingsQuery = useGetFrontendSettingsQuery();
+  const legacyStorage = settingsQuery.data?.legacyStorage;
+  const navigate = useNavigate();
+
+  const { hasPublicAccess, hasImageRenderer, hasRequiredFeatures } = getConfigurationStatus();
+  const [showInstructionsModal, setShowModal] = useState(false);
+  const [setupType, setSetupType] = useState<SetupType>(null);
+
+  const getModalContent = () => {
+    switch (setupType) {
+      case 'public-access':
+        return {
+          title: 'Set up public access',
+          description: 'Set up public access to your Grafana instance to enable GitHub integration',
+          steps: [
+            {
+              title: 'Start ngrok for temporary public access',
+              description: 'Run this command to create a secure tunnel to your local Grafana:',
+              code: 'ngrok http 3000',
+            },
+            {
+              title: 'Copy your public URL',
+              description: 'From the ngrok output, copy the https:// forwarding URL that looks like this:',
+              code: ngrok_example,
+              copyCode: false,
+            },
+            {
+              title: 'Update your Grafana configuration',
+              description: 'Add this to your custom.ini file, replacing the URL with your actual ngrok URL:',
+              code: root_url_ini,
+            },
+          ],
+        };
+      case 'required-features':
+        return {
+          title: 'Set up required features',
+          description: 'Enable required Grafana features for provisioning',
+          steps: [
+            {
+              title: 'Enable Required Feature Toggles',
+              description: 'Add these settings to your custom.ini file to enable necessary features:',
+              code: feature_ini,
+            },
+          ],
+        };
+      default:
+        return {
+          title: '',
+          description: '',
+          steps: [],
+        };
+    }
+  };
+
+  return (
+    <>
+      {legacyStorage && (
+        <Alert severity="info" title="Setting up this connection could cause a temporary outage">
+          When you connect your whole instance, dashboards will be unavailable while running the migration. We recommend
+          warning your users before starting the process.
+        </Alert>
+      )}
+      <Stack direction="row" gap={2}>
+        <Box width="50%" marginTop={2} paddingTop={2} paddingBottom={2}>
+          <Stack direction="column" gap={2}>
+            <Stack direction="column" gap={2}>
+              <Text variant="h2">Provisioning as-code directly from Grafana</Text>
+              <Text variant="body">
+                <Icon name="check" className="text-success" /> Manage your dashboards as code and deploy them
+                automatically from your GitHub repository or local storage
+              </Text>
+              <Text variant="body">
+                <Icon name="check" className="text-success" /> Review, discuss, and approve dashboard changes with your
+                team before they go live using GitHub pull requests
+              </Text>
+              <Text variant="body">
+                <Icon name="check" className="text-success" /> Export your existing dashboards as code and store them in
+                GitHub repositories for version control and collaboration
+              </Text>
+              {hasPublicAccess && (
+                <Text variant="body">
+                  <Icon name="check" className="text-success" /> Automatically provision and update your dashboards as
+                  soon as changes are pushed to your GitHub repository
+                </Text>
+              )}
+              {hasImageRenderer && hasPublicAccess && (
+                <Text variant="body">
+                  <Icon name="check" className="text-success" /> Visual previews in pull requests to review your changes
+                  before going live
+                </Text>
+              )}
+
+              <LinkButton fill="text" href="#" icon="external-link-alt">
+                Learn more
+              </LinkButton>
+            </Stack>
+            <Stack direction="column" gap={2}>
+              {hasRequiredFeatures ? (
+                <>
+                  <Text variant="h2">Migrate Or Connect</Text>
path: public/app/features/provisioning/GettingStarted/GettingStarted.tsx
user: login: Clarity-89
body: ```suggestion
                  <Text variant="h2">Migrate or connect</Text>
```
created_at: 2025-03-06T13:34:15Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,270 @@
+import { useNavigate } from 'react-router-dom-v5-compat';
+
+import { LinkButton, Alert, Stack, Text, Button, Box, Icon } from '@grafana/ui';
+
+import { useGetFrontendSettingsQuery } from '../api';
+import { CONNECT_URL, MIGRATE_URL } from '../constants';
+import { css } from '@emotion/css';
+import { getConfigurationStatus } from './utils';
+import { useState } from 'react';
+import { SetupModal } from './SetupModal';
+import { feature_ini, ngrok_example, root_url_ini } from './types';
+
+type SetupType = 'public-access' | 'required-features' | null;
+
+export default function GettingStarted() {
+  const settingsQuery = useGetFrontendSettingsQuery();
+  const legacyStorage = settingsQuery.data?.legacyStorage;
+  const navigate = useNavigate();
+
+  const { hasPublicAccess, hasImageRenderer, hasRequiredFeatures } = getConfigurationStatus();
+  const [showInstructionsModal, setShowModal] = useState(false);
+  const [setupType, setSetupType] = useState<SetupType>(null);
+
+  const getModalContent = () => {
+    switch (setupType) {
+      case 'public-access':
+        return {
+          title: 'Set up public access',
+          description: 'Set up public access to your Grafana instance to enable GitHub integration',
+          steps: [
+            {
+              title: 'Start ngrok for temporary public access',
+              description: 'Run this command to create a secure tunnel to your local Grafana:',
+              code: 'ngrok http 3000',
+            },
+            {
+              title: 'Copy your public URL',
+              description: 'From the ngrok output, copy the https:// forwarding URL that looks like this:',
+              code: ngrok_example,
+              copyCode: false,
+            },
+            {
+              title: 'Update your Grafana configuration',
+              description: 'Add this to your custom.ini file, replacing the URL with your actual ngrok URL:',
+              code: root_url_ini,
+            },
+          ],
+        };
+      case 'required-features':
+        return {
+          title: 'Set up required features',
+          description: 'Enable required Grafana features for provisioning',
+          steps: [
+            {
+              title: 'Enable Required Feature Toggles',
+              description: 'Add these settings to your custom.ini file to enable necessary features:',
+              code: feature_ini,
+            },
+          ],
+        };
+      default:
+        return {
+          title: '',
+          description: '',
+          steps: [],
+        };
+    }
+  };
+
+  return (
+    <>
+      {legacyStorage && (
+        <Alert severity="info" title="Setting up this connection could cause a temporary outage">
+          When you connect your whole instance, dashboards will be unavailable while running the migration. We recommend
+          warning your users before starting the process.
+        </Alert>
+      )}
+      <Stack direction="row" gap={2}>
+        <Box width="50%" marginTop={2} paddingTop={2} paddingBottom={2}>
+          <Stack direction="column" gap={2}>
+            <Stack direction="column" gap={2}>
+              <Text variant="h2">Provisioning as-code directly from Grafana</Text>
+              <Text variant="body">
+                <Icon name="check" className="text-success" /> Manage your dashboards as code and deploy them
+                automatically from your GitHub repository or local storage
+              </Text>
+              <Text variant="body">
+                <Icon name="check" className="text-success" /> Review, discuss, and approve dashboard changes with your
+                team before they go live using GitHub pull requests
+              </Text>
+              <Text variant="body">
+                <Icon name="check" className="text-success" /> Export your existing dashboards as code and store them in
+                GitHub repositories for version control and collaboration
+              </Text>
+              {hasPublicAccess && (
+                <Text variant="body">
+                  <Icon name="check" className="text-success" /> Automatically provision and update your dashboards as
+                  soon as changes are pushed to your GitHub repository
+                </Text>
+              )}
+              {hasImageRenderer && hasPublicAccess && (
+                <Text variant="body">
+                  <Icon name="check" className="text-success" /> Visual previews in pull requests to review your changes
+                  before going live
+                </Text>
+              )}
+
+              <LinkButton fill="text" href="#" icon="external-link-alt">
+                Learn more
+              </LinkButton>
+            </Stack>
+            <Stack direction="column" gap={2}>
+              {hasRequiredFeatures ? (
+                <>
+                  <Text variant="h2">Migrate Or Connect</Text>
+                  <Text variant="body">Migrate your existing dashboards and manage the entire instance as code:</Text>
+                  <Box>
+                    <Button
+                      size="md"
+                      icon="plus"
+                      onClick={async () => {
+                        await settingsQuery.refetch();
+                        navigate(MIGRATE_URL);
+                      }}
+                    >
+                      Migrate Grafana to repository
+                    </Button>
+                  </Box>
+                  <Text variant="body">
+                    Alternatively, connect to repository and add more repositories for other folders as needed:
+                  </Text>
+                  <Box>
+                    <LinkButton
+                      fill="outline"
+                      icon="plus"
+                      onClick={async () => {
+                        await settingsQuery.refetch();
+                        navigate(CONNECT_URL);
+                      }}
+                    >
+                      Connect Grafana to repository
+                    </LinkButton>
+                  </Box>
+                </>
+              ) : (
+                <Box>
+                  <LinkButton
+                    fill="outline"
+                    onClick={() => {
+                      setSetupType('required-features');
+                      setShowModal(true);
+                    }}
+                  >
+                    Set up required features
+                  </LinkButton>
+                </Box>
+              )}
+            </Stack>
+          </Stack>
+        </Box>
+        <Box width="50%">
+          <div
+            className={css`
+              height: 100%;
+              background: linear-gradient(to right, rgba(255, 179, 102, 0.6), rgba(255, 143, 143, 0.8));
+              border-radius: 4px;
+              padding: 16px;
+              display: flex;
+              align-items: center;
+              justify-content: center;
+            `}
+          >
+            <Text variant="h2">Engaging Graphic</Text>
+          </div>
+        </Box>
+      </Stack>
+      {(!hasPublicAccess || !hasImageRenderer) && (
+        <Box marginTop={2}>
+          <Text variant="h2">Unlock enhanced functionality for Github</Text>
path: public/app/features/provisioning/GettingStarted/GettingStarted.tsx
user: login: Clarity-89
body: ```suggestion
          <Text variant="h2">Unlock enhanced functionality for GitHub</Text>
```
created_at: 2025-03-06T13:34:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,270 @@
+import { useNavigate } from 'react-router-dom-v5-compat';
+
+import { LinkButton, Alert, Stack, Text, Button, Box, Icon } from '@grafana/ui';
+
+import { useGetFrontendSettingsQuery } from '../api';
+import { CONNECT_URL, MIGRATE_URL } from '../constants';
+import { css } from '@emotion/css';
+import { getConfigurationStatus } from './utils';
+import { useState } from 'react';
+import { SetupModal } from './SetupModal';
+import { feature_ini, ngrok_example, root_url_ini } from './types';
+
+type SetupType = 'public-access' | 'required-features' | null;
+
+export default function GettingStarted() {
+  const settingsQuery = useGetFrontendSettingsQuery();
+  const legacyStorage = settingsQuery.data?.legacyStorage;
+  const navigate = useNavigate();
+
+  const { hasPublicAccess, hasImageRenderer, hasRequiredFeatures } = getConfigurationStatus();
+  const [showInstructionsModal, setShowModal] = useState(false);
+  const [setupType, setSetupType] = useState<SetupType>(null);
+
+  const getModalContent = () => {
+    switch (setupType) {
+      case 'public-access':
+        return {
+          title: 'Set up public access',
+          description: 'Set up public access to your Grafana instance to enable GitHub integration',
+          steps: [
+            {
+              title: 'Start ngrok for temporary public access',
+              description: 'Run this command to create a secure tunnel to your local Grafana:',
+              code: 'ngrok http 3000',
+            },
+            {
+              title: 'Copy your public URL',
+              description: 'From the ngrok output, copy the https:// forwarding URL that looks like this:',
+              code: ngrok_example,
+              copyCode: false,
+            },
+            {
+              title: 'Update your Grafana configuration',
+              description: 'Add this to your custom.ini file, replacing the URL with your actual ngrok URL:',
+              code: root_url_ini,
+            },
+          ],
+        };
+      case 'required-features':
+        return {
+          title: 'Set up required features',
+          description: 'Enable required Grafana features for provisioning',
+          steps: [
+            {
+              title: 'Enable Required Feature Toggles',
+              description: 'Add these settings to your custom.ini file to enable necessary features:',
+              code: feature_ini,
+            },
+          ],
+        };
+      default:
+        return {
+          title: '',
+          description: '',
+          steps: [],
+        };
+    }
+  };
+
+  return (
+    <>
+      {legacyStorage && (
+        <Alert severity="info" title="Setting up this connection could cause a temporary outage">
+          When you connect your whole instance, dashboards will be unavailable while running the migration. We recommend
+          warning your users before starting the process.
+        </Alert>
+      )}
+      <Stack direction="row" gap={2}>
+        <Box width="50%" marginTop={2} paddingTop={2} paddingBottom={2}>
+          <Stack direction="column" gap={2}>
+            <Stack direction="column" gap={2}>
+              <Text variant="h2">Provisioning as-code directly from Grafana</Text>
+              <Text variant="body">
+                <Icon name="check" className="text-success" /> Manage your dashboards as code and deploy them
+                automatically from your GitHub repository or local storage
+              </Text>
+              <Text variant="body">
+                <Icon name="check" className="text-success" /> Review, discuss, and approve dashboard changes with your
+                team before they go live using GitHub pull requests
+              </Text>
+              <Text variant="body">
+                <Icon name="check" className="text-success" /> Export your existing dashboards as code and store them in
+                GitHub repositories for version control and collaboration
+              </Text>
+              {hasPublicAccess && (
+                <Text variant="body">
+                  <Icon name="check" className="text-success" /> Automatically provision and update your dashboards as
+                  soon as changes are pushed to your GitHub repository
+                </Text>
+              )}
+              {hasImageRenderer && hasPublicAccess && (
+                <Text variant="body">
+                  <Icon name="check" className="text-success" /> Visual previews in pull requests to review your changes
+                  before going live
+                </Text>
+              )}
+
+              <LinkButton fill="text" href="#" icon="external-link-alt">
+                Learn more
+              </LinkButton>
+            </Stack>
+            <Stack direction="column" gap={2}>
+              {hasRequiredFeatures ? (
+                <>
+                  <Text variant="h2">Migrate Or Connect</Text>
+                  <Text variant="body">Migrate your existing dashboards and manage the entire instance as code:</Text>
+                  <Box>
+                    <Button
+                      size="md"
+                      icon="plus"
+                      onClick={async () => {
+                        await settingsQuery.refetch();
+                        navigate(MIGRATE_URL);
+                      }}
+                    >
+                      Migrate Grafana to repository
+                    </Button>
+                  </Box>
+                  <Text variant="body">
+                    Alternatively, connect to repository and add more repositories for other folders as needed:
+                  </Text>
+                  <Box>
+                    <LinkButton
+                      fill="outline"
+                      icon="plus"
+                      onClick={async () => {
+                        await settingsQuery.refetch();
+                        navigate(CONNECT_URL);
+                      }}
+                    >
+                      Connect Grafana to repository
+                    </LinkButton>
+                  </Box>
+                </>
+              ) : (
+                <Box>
+                  <LinkButton
+                    fill="outline"
+                    onClick={() => {
+                      setSetupType('required-features');
+                      setShowModal(true);
+                    }}
+                  >
+                    Set up required features
+                  </LinkButton>
+                </Box>
+              )}
+            </Stack>
+          </Stack>
+        </Box>
+        <Box width="50%">
+          <div
+            className={css`
+              height: 100%;
+              background: linear-gradient(to right, rgba(255, 179, 102, 0.6), rgba(255, 143, 143, 0.8));
+              border-radius: 4px;
+              padding: 16px;
+              display: flex;
+              align-items: center;
+              justify-content: center;
+            `}
+          >
+            <Text variant="h2">Engaging Graphic</Text>
+          </div>
+        </Box>
+      </Stack>
+      {(!hasPublicAccess || !hasImageRenderer) && (
+        <Box marginTop={2}>
+          <Text variant="h2">Unlock enhanced functionality for Github</Text>
+          <Box marginTop={4}>
+            <Stack direction="row" gap={2}>
+              <Box width="25%" padding={2}>
+                <div
+                  className={css`
+                    border-right: 1px solid rgba(204, 204, 220, 0.15);
+                  `}
+                >
+                  <Stack direction="column" gap={2}>
+                    <div
+                      className={css`
+                        background: rgba(24, 121, 219, 0.12);
+                        border-radius: 50%;
+                        padding: 16px;
+                        width: fit-content;
+                      `}
+                    >
+                      <Icon name="sync" size="xxl" color="primary" />
+                    </div>
+                    <Text variant="h3">Instantenous Provisioning</Text>
+                    <Text variant="body">
+                      Automatically provision and update your dashboards as soon as changes are pushed to your GitHub
+                      repository
+                    </Text>
+                    {!hasPublicAccess && (
+                      <Box>
+                        <LinkButton
+                          fill="outline"
+                          onClick={() => {
+                            setSetupType('public-access');
+                            setShowModal(true);
+                          }}
+                        >
+                          Set up public access
+                        </LinkButton>
+                      </Box>
+                    )}
+                  </Stack>
+                </div>
+              </Box>
+              <Box width="25%" padding={4}>
+                <Stack direction="column" gap={2}>
+                  <Stack direction="row" gap={2}>
+                    <div
+                      className={css`
+                        background: rgba(255, 120, 10, 0.12);
+                        border-radius: 50%;
+                        padding: 16px;
+                        width: fit-content;
+                      `}
+                    >
+                      <Icon name="camera" size="xxl" color="orange" />
+                    </div>
+                    <div
+                      className={css`
+                        background: rgba(135, 73, 237, 0.12);
+                        border-radius: 50%;
+                        padding: 16px;
+                        width: fit-content;
+                      `}
+                    >
+                      <Icon name="code-branch" size="xxl" color="purple" />
+                    </div>
+                  </Stack>
+                  <Text variant="h3">Visual Previews in Pull Requests</Text>
path: public/app/features/provisioning/GettingStarted/GettingStarted.tsx
user: login: Clarity-89
body: ```suggestion
                  <Text variant="h3">Visual previews in pull requests</Text>
```
created_at: 2025-03-06T13:36:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,270 @@
+import { useNavigate } from 'react-router-dom-v5-compat';
+
+import { LinkButton, Alert, Stack, Text, Button, Box, Icon } from '@grafana/ui';
+
+import { useGetFrontendSettingsQuery } from '../api';
+import { CONNECT_URL, MIGRATE_URL } from '../constants';
+import { css } from '@emotion/css';
+import { getConfigurationStatus } from './utils';
+import { useState } from 'react';
+import { SetupModal } from './SetupModal';
+import { feature_ini, ngrok_example, root_url_ini } from './types';
+
+type SetupType = 'public-access' | 'required-features' | null;
+
+export default function GettingStarted() {
+  const settingsQuery = useGetFrontendSettingsQuery();
+  const legacyStorage = settingsQuery.data?.legacyStorage;
+  const navigate = useNavigate();
+
+  const { hasPublicAccess, hasImageRenderer, hasRequiredFeatures } = getConfigurationStatus();
+  const [showInstructionsModal, setShowModal] = useState(false);
+  const [setupType, setSetupType] = useState<SetupType>(null);
+
+  const getModalContent = () => {
+    switch (setupType) {
+      case 'public-access':
+        return {
+          title: 'Set up public access',
+          description: 'Set up public access to your Grafana instance to enable GitHub integration',
+          steps: [
+            {
+              title: 'Start ngrok for temporary public access',
+              description: 'Run this command to create a secure tunnel to your local Grafana:',
+              code: 'ngrok http 3000',
+            },
+            {
+              title: 'Copy your public URL',
+              description: 'From the ngrok output, copy the https:// forwarding URL that looks like this:',
+              code: ngrok_example,
+              copyCode: false,
+            },
+            {
+              title: 'Update your Grafana configuration',
+              description: 'Add this to your custom.ini file, replacing the URL with your actual ngrok URL:',
+              code: root_url_ini,
+            },
+          ],
+        };
+      case 'required-features':
+        return {
+          title: 'Set up required features',
+          description: 'Enable required Grafana features for provisioning',
+          steps: [
+            {
+              title: 'Enable Required Feature Toggles',
+              description: 'Add these settings to your custom.ini file to enable necessary features:',
+              code: feature_ini,
+            },
+          ],
+        };
+      default:
+        return {
+          title: '',
+          description: '',
+          steps: [],
+        };
+    }
+  };
+
+  return (
+    <>
+      {legacyStorage && (
+        <Alert severity="info" title="Setting up this connection could cause a temporary outage">
+          When you connect your whole instance, dashboards will be unavailable while running the migration. We recommend
+          warning your users before starting the process.
+        </Alert>
+      )}
+      <Stack direction="row" gap={2}>
+        <Box width="50%" marginTop={2} paddingTop={2} paddingBottom={2}>
+          <Stack direction="column" gap={2}>
+            <Stack direction="column" gap={2}>
+              <Text variant="h2">Provisioning as-code directly from Grafana</Text>
+              <Text variant="body">
+                <Icon name="check" className="text-success" /> Manage your dashboards as code and deploy them
+                automatically from your GitHub repository or local storage
+              </Text>
+              <Text variant="body">
+                <Icon name="check" className="text-success" /> Review, discuss, and approve dashboard changes with your
+                team before they go live using GitHub pull requests
+              </Text>
+              <Text variant="body">
+                <Icon name="check" className="text-success" /> Export your existing dashboards as code and store them in
+                GitHub repositories for version control and collaboration
+              </Text>
+              {hasPublicAccess && (
+                <Text variant="body">
+                  <Icon name="check" className="text-success" /> Automatically provision and update your dashboards as
+                  soon as changes are pushed to your GitHub repository
+                </Text>
+              )}
+              {hasImageRenderer && hasPublicAccess && (
+                <Text variant="body">
+                  <Icon name="check" className="text-success" /> Visual previews in pull requests to review your changes
+                  before going live
+                </Text>
+              )}
+
+              <LinkButton fill="text" href="#" icon="external-link-alt">
+                Learn more
+              </LinkButton>
+            </Stack>
+            <Stack direction="column" gap={2}>
+              {hasRequiredFeatures ? (
+                <>
+                  <Text variant="h2">Migrate Or Connect</Text>
+                  <Text variant="body">Migrate your existing dashboards and manage the entire instance as code:</Text>
+                  <Box>
+                    <Button
+                      size="md"
+                      icon="plus"
+                      onClick={async () => {
+                        await settingsQuery.refetch();
+                        navigate(MIGRATE_URL);
+                      }}
+                    >
+                      Migrate Grafana to repository
+                    </Button>
+                  </Box>
+                  <Text variant="body">
+                    Alternatively, connect to repository and add more repositories for other folders as needed:
+                  </Text>
+                  <Box>
+                    <LinkButton
+                      fill="outline"
+                      icon="plus"
+                      onClick={async () => {
+                        await settingsQuery.refetch();
+                        navigate(CONNECT_URL);
+                      }}
+                    >
+                      Connect Grafana to repository
+                    </LinkButton>
+                  </Box>
+                </>
+              ) : (
+                <Box>
+                  <LinkButton
+                    fill="outline"
+                    onClick={() => {
+                      setSetupType('required-features');
+                      setShowModal(true);
+                    }}
+                  >
+                    Set up required features
+                  </LinkButton>
+                </Box>
+              )}
+            </Stack>
+          </Stack>
+        </Box>
+        <Box width="50%">
+          <div
+            className={css`
+              height: 100%;
+              background: linear-gradient(to right, rgba(255, 179, 102, 0.6), rgba(255, 143, 143, 0.8));
+              border-radius: 4px;
+              padding: 16px;
+              display: flex;
+              align-items: center;
+              justify-content: center;
+            `}
+          >
+            <Text variant="h2">Engaging Graphic</Text>
+          </div>
+        </Box>
+      </Stack>
+      {(!hasPublicAccess || !hasImageRenderer) && (
+        <Box marginTop={2}>
+          <Text variant="h2">Unlock enhanced functionality for Github</Text>
+          <Box marginTop={4}>
+            <Stack direction="row" gap={2}>
+              <Box width="25%" padding={2}>
+                <div
+                  className={css`
+                    border-right: 1px solid rgba(204, 204, 220, 0.15);
+                  `}
+                >
+                  <Stack direction="column" gap={2}>
+                    <div
+                      className={css`
+                        background: rgba(24, 121, 219, 0.12);
+                        border-radius: 50%;
+                        padding: 16px;
+                        width: fit-content;
+                      `}
+                    >
+                      <Icon name="sync" size="xxl" color="primary" />
+                    </div>
+                    <Text variant="h3">Instantenous Provisioning</Text>
+                    <Text variant="body">
+                      Automatically provision and update your dashboards as soon as changes are pushed to your GitHub
+                      repository
+                    </Text>
+                    {!hasPublicAccess && (
+                      <Box>
+                        <LinkButton
+                          fill="outline"
+                          onClick={() => {
+                            setSetupType('public-access');
+                            setShowModal(true);
+                          }}
+                        >
+                          Set up public access
+                        </LinkButton>
+                      </Box>
+                    )}
+                  </Stack>
+                </div>
+              </Box>
+              <Box width="25%" padding={4}>
+                <Stack direction="column" gap={2}>
+                  <Stack direction="row" gap={2}>
+                    <div
+                      className={css`
+                        background: rgba(255, 120, 10, 0.12);
+                        border-radius: 50%;
+                        padding: 16px;
+                        width: fit-content;
+                      `}
+                    >
+                      <Icon name="camera" size="xxl" color="orange" />
+                    </div>
+                    <div
+                      className={css`
+                        background: rgba(135, 73, 237, 0.12);
+                        border-radius: 50%;
+                        padding: 16px;
+                        width: fit-content;
+                      `}
+                    >
+                      <Icon name="code-branch" size="xxl" color="purple" />
+                    </div>
+                  </Stack>
+                  <Text variant="h3">Visual Previews in Pull Requests</Text>
+                  <Text variant="body">
+                    Review how your changes look like before going live in Grafana and directly in Pull Requests
path: public/app/features/provisioning/GettingStarted/GettingStarted.tsx
user: login: Clarity-89
body: ```suggestion
                    Review how your changes look like before going live in Grafana and directly in pull requests
```
created_at: 2025-03-06T13:36:15Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,20 @@
+import { Page } from 'app/core/components/Page/Page';
+
+import GettingStarted from './GettingStarted';
+
+export default function GettingStartedPage() {
+  return (
+    <Page
+      navId="provisioning"
+      pageNav={{
+        text: 'Getting started with Provisioning',
path: public/app/features/provisioning/GettingStarted/GettingStartedPage.tsx
user: login: Clarity-89
body: ```suggestion
        text: 'Getting started with provisioning',
```
created_at: 2025-03-06T13:36:31Z
author_association: CONTRIBUTOR

PR comments:
user: login: MissingRoberto
created_at: 2025-03-06T15:15:10Z
body: @Clarity-89 Addressed your comments and also structured the code into more components to improve the readability and disposability :) 
author_association: CONTRIBUTOR
user: login: MissingRoberto
created_at: 2025-03-06T15:19:29Z
body: ![image](https://github.com/user-attachments/assets/42447594-6c0a-410d-9c48-1fa83b686b7d)

author_association: CONTRIBUTOR
user: login: Clarity-89
created_at: 2025-03-06T16:17:08Z
body: > @Clarity-89 Addressed your comments and also structured the code into more components to improve the readability and disposability :)

There seem to be quite a few FE lint errors, mostly related to imports. You'd be able to fix those with prettier and eslint `fix on save` flag:
<img width="978" alt="Screenshot 2025-03-06 at 17 16 48" src="https://github.com/user-attachments/assets/bb511b51-6e11-4244-a512-66eeb8ba051a" />

author_association: CONTRIBUTOR
user: login: MissingRoberto
created_at: 2025-03-07T08:08:39Z
body: @Clarity-89 thank you for pointing that out and sorry for that. I've just started using Cursor and I didn't spend time configuring ESLint and I don't see the issues also on build on my end. Let me configure that. 

Please, raise the flag again if you see me adding those kind of errors. I know it's kind of annoying :) 


On the other hand, is there a way to make the linting in CI fail to catch those? I was trusting the CI on that. 


cc @ryantxu 

author_association: CONTRIBUTOR
user: login: Clarity-89
created_at: 2025-03-07T08:14:35Z
body: 
> On the other hand, is there a way to make the linting in CI fail to catch those? I was trusting the CI on that.

The CI does fail on those, the checks are just not blocking when not targeting main. 


author_association: CONTRIBUTOR