diff --git a/pkg/services/navtree/navtreeimpl/admin.go b/pkg/services/navtree/navtreeimpl/admin.go index dfeacca9d5f..700fc8323f9 100644 --- a/pkg/services/navtree/navtreeimpl/admin.go +++ b/pkg/services/navtree/navtreeimpl/admin.go @@ -62,9 +62,9 @@ func (s *ServiceImpl) getAdminNode(c *contextmodel.ReqContext) (*navtree.NavLink } if hasAccess(ac.EvalPermission(ac.ActionSettingsRead, ac.ScopeSettingsAll)) { generalNodeLinks = append(generalNodeLinks, &navtree.NavLink{ - Text: "Remote provisioning", + Text: "Provisioning", Id: "provisioning", - SubTitle: "Manage resources from remote repositories", + SubTitle: "View and manage your provisioning connections", Url: s.cfg.AppSubURL + "/admin/provisioning", }) } diff --git a/public/app/features/provisioning/GettingStarted/EnhancedFeatures.tsx b/public/app/features/provisioning/GettingStarted/EnhancedFeatures.tsx index 33cbcb232ef..d6d40fcf8b6 100644 --- a/public/app/features/provisioning/GettingStarted/EnhancedFeatures.tsx +++ b/public/app/features/provisioning/GettingStarted/EnhancedFeatures.tsx @@ -1,29 +1,10 @@ import { css } from '@emotion/css'; import { GrafanaTheme2 } from '@grafana/data'; -import { Box, Stack, Text, LinkButton, Icon, IconName, useStyles2 } from '@grafana/ui'; -import { Trans, t } from 'app/core/internationalization'; +import { Box, Stack, Text, LinkButton, useStyles2 } from '@grafana/ui'; +import { Trans } from 'app/core/internationalization'; -import { FeatureCard } from './FeatureCard'; - -interface IconCircleProps { - icon: IconName; - color: string; - background: string; -} - -const IconCircle = ({ icon, color, background }: IconCircleProps) => ( -
- -
-); +import { IconCircle } from './IconCircle'; interface EnhancedFeaturesProps { hasPublicAccess: boolean; @@ -35,65 +16,68 @@ export const EnhancedFeatures = ({ hasPublicAccess, hasImageRenderer, onSetupPub const style = useStyles2(getStyles); return ( - - - - Unlock enhanced functionality for GitHub - - - - - } - action={ - !hasPublicAccess && ( - - Set up public access - - ) - } - /> + + + + Enhance your GitHub experience + + + + Get the most out of your GitHub integration with these optional add-ons + + + + + + + + + + + Instant updates and pull requests with webhooks. + + + + + Get instant updates in Grafana as soon as changes are committed. Review and approve changes using pull + requests before they go live. + + + + {!hasPublicAccess && ( + + Set up public webhooks + + )} + -
+
- - - - - } - action={ - !hasImageRenderer && ( - - Set up image rendering - - ) - } - /> - - - + + + + Visual previews in pull requests with image rendering + + + + + See visual previews of dashboard updates directly in pull requests + + + + {hasImageRenderer && ( + + Set up image rendering + + )} + + + ); }; diff --git a/public/app/features/provisioning/GettingStarted/FeatureCard.tsx b/public/app/features/provisioning/GettingStarted/FeatureCard.tsx deleted file mode 100644 index b70ad55d880..00000000000 --- a/public/app/features/provisioning/GettingStarted/FeatureCard.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { Box, Stack, Text } from '@grafana/ui'; - -interface FeatureCardProps { - title: string; - description: string; - icon?: React.ReactNode; - action?: React.ReactNode; -} - -export const FeatureCard = ({ title, description, icon, action }: FeatureCardProps) => ( - -
- - {icon} - {title} - {description} - {action && {action}} - -
-
-); diff --git a/public/app/features/provisioning/GettingStarted/FeaturesList.tsx b/public/app/features/provisioning/GettingStarted/FeaturesList.tsx index 1ba201ff814..17eeedf1270 100644 --- a/public/app/features/provisioning/GettingStarted/FeaturesList.tsx +++ b/public/app/features/provisioning/GettingStarted/FeaturesList.tsx @@ -1,43 +1,46 @@ -import { ReactNode } from 'react'; +import { css } from '@emotion/css'; -import { Stack, Text, Box, LinkButton, Icon } from '@grafana/ui'; +import { GrafanaTheme2 } from '@grafana/data'; +import { Stack, Text, Box, LinkButton, useStyles2 } from '@grafana/ui'; import { Repository } from 'app/api/clients/provisioning'; import { Trans } from 'app/core/internationalization'; import { ConnectRepositoryButton } from '../Shared/ConnectRepositoryButton'; -interface FeatureItemProps { - children: NonNullable; -} - -const FeatureItem = ({ children }: FeatureItemProps) => { - // We use a stack here to ensure the icon and text are aligned correctly. - return ( - - - {children} - - ); -}; - interface FeaturesListProps { repos?: Repository[]; - hasPublicAccess: boolean; - hasImageRenderer: boolean; hasRequiredFeatures: boolean; onSetupFeatures: () => void; } -export const FeaturesList = ({ - repos, - hasPublicAccess, - hasImageRenderer, - hasRequiredFeatures, - onSetupFeatures, -}: FeaturesListProps) => { - const actions = () => { - if (!hasRequiredFeatures) { - return ( +export const FeaturesList = ({ repos, hasRequiredFeatures, onSetupFeatures }: FeaturesListProps) => { + const styles = useStyles2(getStyles); + + return ( + + + + Get started with GitSync + + +
    +
  • + + Manage dashboards as code in GitHub and provision updates automatically + +
  • +
  • + + Store dashboards in version-controlled storage for better organization and history tracking + +
  • +
  • + + Migrate existing dashboards to GitHub for provisioning + +
  • +
+ {!hasRequiredFeatures ? ( @@ -45,61 +48,34 @@ export const FeaturesList = ({ - ); - } - - return ( - - - - ); - }; - - return ( - - - - Manage your dashboards with remote provisioning - - - - - Manage dashboards as code and provision updates automatically - - - - - Store dashboards in version-controlled storage for better organization and history tracking - - - - - Migrate existing dashboards to storage for provisioning - - - {hasPublicAccess && ( - - - Automatically provision and update your dashboards as soon as changes are pushed to your GitHub repository - - + ) : ( + + + )} - {hasImageRenderer && hasPublicAccess && ( - - - Visual previews in pull requests to review your changes before going live - - - )} - - {false && ( - // We haven't gotten the design for this quite yet. - - Learn more - - )} - - {actions()} ); }; + +const getStyles = (theme: GrafanaTheme2) => { + return { + featuresList: css({ + listStyleType: 'none', + paddingLeft: 0, + marginLeft: theme.spacing(-1), + '& li': { + position: 'relative', + paddingLeft: theme.spacing(4), + marginBottom: theme.spacing(1), + '&:before': { + content: '"✓"', + position: 'absolute', + left: theme.spacing(1), + top: '0', + color: theme.colors.text.secondary, + fontWeight: theme.typography.fontWeightBold, + }, + }, + }), + }; +}; diff --git a/public/app/features/provisioning/GettingStarted/GettingStarted.tsx b/public/app/features/provisioning/GettingStarted/GettingStarted.tsx index a39fd510fb2..881f7e02590 100644 --- a/public/app/features/provisioning/GettingStarted/GettingStarted.tsx +++ b/public/app/features/provisioning/GettingStarted/GettingStarted.tsx @@ -1,7 +1,7 @@ import { css } from '@emotion/css'; import { useState } from 'react'; -import { Alert, Stack, Text, Box } from '@grafana/ui'; +import { Alert, Stack, Text } from '@grafana/ui'; import { useGetFrontendSettingsQuery, Repository } from 'app/api/clients/provisioning'; import { t, Trans } from 'app/core/internationalization'; @@ -47,6 +47,76 @@ HTTP Requests const rootUrlExample = `[server] root_url = https://d60d-83-33-235-27.ngrok-free.app`; +const getModalContent = (setupType: SetupType) => { + switch (setupType) { + case 'public-access': + return { + title: t('provisioning.getting-started.modal-title-set-up-public-access', 'Set up public access'), + description: t( + 'provisioning.getting-started.modal-description-public-access', + 'Set up public access to your Grafana instance to enable GitHub integration' + ), + steps: [ + { + title: t('provisioning.getting-started.step-title-start-ngrok', 'Start ngrok for temporary public access'), + description: t( + 'provisioning.getting-started.step-description-start-ngrok', + 'Run this command to create a secure tunnel to your local Grafana:' + ), + code: 'ngrok http 3000', + }, + { + title: t('provisioning.getting-started.step-title-copy-url', 'Copy your public URL'), + description: t( + 'provisioning.getting-started.step-description-copy-url', + 'From the ngrok output, copy the https:// forwarding URL that looks like this:' + ), + code: ngrokExample, + copyCode: false, + }, + { + title: t( + 'provisioning.getting-started.step-title-update-grafana-config', + 'Update your Grafana configuration' + ), + description: t( + 'provisioning.getting-started.step-description-update-grafana-config', + 'Add this to your custom.ini file, replacing the URL with your actual ngrok URL:' + ), + code: rootUrlExample, + }, + ], + }; + case 'required-features': + return { + title: t('provisioning.getting-started.modal-title-set-up-required-features', 'Set up required features'), + description: t( + 'provisioning.getting-started.modal-description-required-features', + 'Enable required Grafana features for provisioning' + ), + steps: [ + { + title: t( + 'provisioning.getting-started.step-title-enable-feature-toggles', + 'Enable Required Feature Toggles' + ), + description: t( + 'provisioning.getting-started.step-description-enable-feature-toggles', + 'Add these settings to your custom.ini file to enable necessary features:' + ), + code: featureIni, + }, + ], + }; + default: + return { + title: '', + description: '', + steps: [], + }; + } +}; + interface Props { items: Repository[]; } @@ -59,79 +129,6 @@ export default function GettingStarted({ items }: Props) { const [showInstructionsModal, setShowModal] = useState(false); const [setupType, setSetupType] = useState(null); - const getModalContent = () => { - switch (setupType) { - case 'public-access': - return { - title: t('provisioning.getting-started.modal-title-set-up-public-access', 'Set up public access'), - description: t( - 'provisioning.getting-started.modal-description-public-access', - 'Set up public access to your Grafana instance to enable GitHub integration' - ), - steps: [ - { - title: t( - 'provisioning.getting-started.step-title-start-ngrok', - 'Start ngrok for temporary public access' - ), - description: t( - 'provisioning.getting-started.step-description-start-ngrok', - 'Run this command to create a secure tunnel to your local Grafana:' - ), - code: 'ngrok http 3000', - }, - { - title: t('provisioning.getting-started.step-title-copy-url', 'Copy your public URL'), - description: t( - 'provisioning.getting-started.step-description-copy-url', - 'From the ngrok output, copy the https:// forwarding URL that looks like this:' - ), - code: ngrokExample, - copyCode: false, - }, - { - title: t( - 'provisioning.getting-started.step-title-update-grafana-config', - 'Update your Grafana configuration' - ), - description: t( - 'provisioning.getting-started.step-description-update-grafana-config', - 'Add this to your custom.ini file, replacing the URL with your actual ngrok URL:' - ), - code: rootUrlExample, - }, - ], - }; - case 'required-features': - return { - title: t('provisioning.getting-started.modal-title-set-up-required-features', 'Set up required features'), - description: t( - 'provisioning.getting-started.modal-description-required-features', - 'Enable required Grafana features for provisioning' - ), - steps: [ - { - title: t( - 'provisioning.getting-started.step-title-enable-feature-toggles', - 'Enable Required Feature Toggles' - ), - description: t( - 'provisioning.getting-started.step-description-enable-feature-toggles', - 'Add these settings to your custom.ini file to enable necessary features:' - ), - code: featureIni, - }, - ], - }; - default: - return { - title: '', - description: '', - steps: [], - }; - } - }; - return ( <> {legacyStorage && ( @@ -148,23 +145,20 @@ export default function GettingStarted({ items }: Props) { )} - - + + { setSetupType('required-features'); setShowModal(true); }} /> - -
Engaging graphic
-
+
+ {(!hasPublicAccess || !hasImageRenderer) && ( + { + setSetupType('public-access'); + setShowModal(true); + }} + /> + )}
- {(!hasPublicAccess || !hasImageRenderer) && ( - { - setSetupType('public-access'); - setShowModal(true); - }} - /> - )} {showInstructionsModal && setupType && ( - setShowModal(false)} /> + setShowModal(false)} + /> )} ); diff --git a/public/app/features/provisioning/GettingStarted/GettingStartedPage.tsx b/public/app/features/provisioning/GettingStarted/GettingStartedPage.tsx index 552e2589ffc..ed8a1e3e06f 100644 --- a/public/app/features/provisioning/GettingStarted/GettingStartedPage.tsx +++ b/public/app/features/provisioning/GettingStarted/GettingStartedPage.tsx @@ -12,10 +12,10 @@ export default function GettingStartedPage({ items }: Props) { diff --git a/public/app/features/provisioning/GettingStarted/IconCircle.tsx b/public/app/features/provisioning/GettingStarted/IconCircle.tsx new file mode 100644 index 00000000000..adfa0cdb115 --- /dev/null +++ b/public/app/features/provisioning/GettingStarted/IconCircle.tsx @@ -0,0 +1,32 @@ +import { css } from '@emotion/css'; + +import { GrafanaTheme2, colorManipulator } from '@grafana/data'; +import { Icon, IconName, useStyles2 } from '@grafana/ui'; + +export interface IconCircleProps { + icon: IconName; + color: 'blue' | 'orange' | 'purple'; +} + +export const IconCircle = ({ icon, color }: IconCircleProps) => { + const styles = useStyles2(getStyles, color); + + return ( +
+ +
+ ); +}; + +function getStyles(theme: GrafanaTheme2, color: IconCircleProps['color']) { + const resolvedColor = theme.visualization.getColorByName(color); + + return { + iconCircle: css({ + borderRadius: theme.shape.radius.circle, + padding: theme.spacing(1), + color: resolvedColor, + backgroundColor: colorManipulator.alpha(resolvedColor, 0.2), + }), + }; +} diff --git a/public/app/features/provisioning/Shared/ConnectRepositoryButton.tsx b/public/app/features/provisioning/Shared/ConnectRepositoryButton.tsx index 5bbe5596496..e1df0c2e83c 100644 --- a/public/app/features/provisioning/Shared/ConnectRepositoryButton.tsx +++ b/public/app/features/provisioning/Shared/ConnectRepositoryButton.tsx @@ -1,6 +1,6 @@ -import { LinkButton } from '@grafana/ui'; +import { Alert, LinkButton, Stack } from '@grafana/ui'; import { Repository } from 'app/api/clients/provisioning'; -import { Trans, t } from 'app/core/internationalization'; +import { Trans } from 'app/core/internationalization'; import { CONNECT_URL } from '../constants'; import { checkSyncSettings } from '../utils/checkSyncSettings'; @@ -18,29 +18,24 @@ export function ConnectRepositoryButton({ items }: Props) { if (state.maxReposReached) { return ( - + - + ); } return ( - - Connect to repository - + + + Configure GitSync + + + Configure file provisioning + + ); } diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json index 10b1c45a9e0..d10c187f2b8 100644 --- a/public/locales/en-US/grafana.json +++ b/public/locales/en-US/grafana.json @@ -5158,10 +5158,9 @@ "title-webhook-will-be-created": "Webhook will be created" }, "connect-repository-button": { - "connect-to-repository": "Connect to repository", - "max-repositories-exist": "Maximum repositories exist ({{count}})", - "tooltip-max-repos_one": "Max repositories already created ({{count}})", - "tooltip-max-repos_other": "Max repositories already created ({{count}})" + "configure-file": "Configure file provisioning", + "configure-git-sync": "Configure GitSync", + "repository-limit-info-alert": "Repository limit reached ({{count}})" }, "connect-step": { "description-choose-storage-resources": "Choose the type of storage for your resources", @@ -5200,13 +5199,14 @@ "no-jobs": "No jobs..." }, "enhanced-features": { + "description": "Get the most out of your GitHub integration with these optional add-ons", "description-instant-updates": "Get instant updates in Grafana as soon as changes are committed. Review and approve changes using pull requests before they go live.", "description-visual-previews-dashboard-updates-directly-requests": "See visual previews of dashboard updates directly in pull requests", + "header": "Enhance your GitHub experience", "set-up-image-rendering": "Set up image rendering", - "set-up-public-access": "Set up public access", - "title-instant-updates-requests-webhooks": "Instant updates and pull requests with webhooks", - "title-visual-previews-in-pull-requests": "Visual previews in pull requests", - "unlock-enhanced-functionality-for-git-hub": "Unlock enhanced functionality for GitHub" + "set-up-public-webhooks": "Set up public webhooks", + "title-instant-updates-requests-webhooks": "Instant updates and pull requests with webhooks.", + "title-visual-previews-in-pull-requests": "Visual previews in pull requests with image rendering" }, "expanded-row": { "job-specification": "Job Specification", @@ -5217,13 +5217,10 @@ "actions": { "set-up-required-feature-toggles": "Set up required feature toggles" }, - "automatically-provision-and-update-dashboards": "Automatically provision and update your dashboards as soon as changes are pushed to your GitHub repository", - "learn-more": "Learn more", - "manage-dashboards-provision-updates-automatically": "Manage dashboards as code and provision updates automatically", - "manage-your-dashboards-with-remote-provisioning": "Manage your dashboards with remote provisioning", - "migrate-existing-dashboards-storage-provisioning": "Migrate existing dashboards to storage for provisioning", - "store-dashboards-in-version-controlled-storage": "Store dashboards in version-controlled storage for better organization and history tracking", - "visual-previews-in-pull-requests": "Visual previews in pull requests to review your changes before going live" + "manage-dashboards-provision-updates-automatically": "Manage dashboards as code in GitHub and provision updates automatically", + "manage-your-dashboards-with-remote-provisioning": "Get started with GitSync", + "migrate-existing-dashboards-storage-provisioning": "Migrate existing dashboards to GitHub for provisioning", + "store-dashboards-in-version-controlled-storage": "Store dashboards in version-controlled storage for better organization and history tracking" }, "file-history-page": { "back-to-repositories": "Back to repositories", @@ -5276,8 +5273,8 @@ "title-setting-connection-could-cause-temporary-outage": "Setting up this connection could cause a temporary outage" }, "getting-started-page": { - "subtitle-provisioning-feature": "Provisioning is a feature that allows you to manage your dashboards using GitHub and other storage systems", - "text-remote-provisioning": "Remote provisioning" + "header": "Provisioning", + "subtitle-provisioning-feature": "View and manage your provisioning connections" }, "history-view": { "not-found": "Not found"