Provisioning: Update onboarding page (#103436)

* Change feature name

* Update feature list

* Update connect button

* Update enhanced features

* Cleanup
pull/103424/head^2
Alex Khomenko 2 months ago committed by GitHub
parent 49ecd83b87
commit 5e02532073
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 4
      pkg/services/navtree/navtreeimpl/admin.go
  2. 142
      public/app/features/provisioning/GettingStarted/EnhancedFeatures.tsx
  3. 21
      public/app/features/provisioning/GettingStarted/FeatureCard.tsx
  4. 138
      public/app/features/provisioning/GettingStarted/FeaturesList.tsx
  5. 184
      public/app/features/provisioning/GettingStarted/GettingStarted.tsx
  6. 4
      public/app/features/provisioning/GettingStarted/GettingStartedPage.tsx
  7. 32
      public/app/features/provisioning/GettingStarted/IconCircle.tsx
  8. 33
      public/app/features/provisioning/Shared/ConnectRepositoryButton.tsx
  9. 31
      public/locales/en-US/grafana.json

@ -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",
})
}

@ -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) => (
<div
className={css({
background: `${background}`,
borderRadius: `50%`,
padding: `16px`,
width: `fit-content`,
})}
>
<Icon name={icon} size="xxl" color={color} />
</div>
);
import { IconCircle } from './IconCircle';
interface EnhancedFeaturesProps {
hasPublicAccess: boolean;
@ -35,65 +16,68 @@ export const EnhancedFeatures = ({ hasPublicAccess, hasImageRenderer, onSetupPub
const style = useStyles2(getStyles);
return (
<Box marginTop={2}>
<Text variant="h2">
<Trans i18nKey="provisioning.enhanced-features.unlock-enhanced-functionality-for-git-hub">
Unlock enhanced functionality for GitHub
</Trans>
</Text>
<Box marginTop={4}>
<Stack direction="row" gap={2}>
<FeatureCard
title={t(
'provisioning.enhanced-features.title-instant-updates-requests-webhooks',
'Instant updates and pull requests with webhooks'
)}
description={t(
'provisioning.enhanced-features.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.'
)}
icon={<IconCircle icon="sync" color="primary" background="rgba(24, 121, 219, 0.12)" />}
action={
!hasPublicAccess && (
<LinkButton fill="outline" onClick={onSetupPublicAccess}>
<Trans i18nKey="provisioning.enhanced-features.set-up-public-access">Set up public access</Trans>
</LinkButton>
)
}
/>
<Stack direction="column" gap={2}>
<Stack direction="column">
<Text variant="h4">
<Trans i18nKey="provisioning.enhanced-features.header">Enhance your GitHub experience</Trans>
</Text>
<Text color="secondary">
<Trans i18nKey="provisioning.enhanced-features.description">
Get the most out of your GitHub integration with these optional add-ons
</Trans>
</Text>
</Stack>
<Stack gap={2} direction="row" height="100%">
<Box width="40%" height="100%" padding={2} display="flex" direction="column" gap={2} alignItems="flex-start">
<Stack gap={2}>
<IconCircle icon="sync" color="blue" />
<IconCircle icon="code-branch" color="purple" />
</Stack>
<Trans i18nKey="provisioning.enhanced-features.title-instant-updates-requests-webhooks">
Instant updates and pull requests with webhooks.
</Trans>
<Box display="flex" flex="1" minHeight="50px">
<Text variant="body" color="secondary">
<Trans i18nKey="provisioning.enhanced-features.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.
</Trans>
</Text>
</Box>
{!hasPublicAccess && (
<LinkButton fill="outline" variant="secondary" onClick={onSetupPublicAccess}>
<Trans i18nKey="provisioning.enhanced-features.set-up-public-webhooks">Set up public webhooks</Trans>
</LinkButton>
)}
</Box>
<div className={style.separator} />
<div className={style.separator} />
<FeatureCard
title={t(
'provisioning.enhanced-features.title-visual-previews-in-pull-requests',
'Visual previews in pull requests'
)}
description={t(
'provisioning.enhanced-features.description-visual-previews-dashboard-updates-directly-requests',
'See visual previews of dashboard updates 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"
>
<Trans i18nKey="provisioning.enhanced-features.set-up-image-rendering">Set up image rendering</Trans>
</LinkButton>
)
}
/>
</Stack>
</Box>
</Box>
<Box width="40%" height="100%" padding={2} display="flex" direction="column" gap={2} alignItems="flex-start">
<IconCircle icon="camera" color="orange" />
<Trans i18nKey="provisioning.enhanced-features.title-visual-previews-in-pull-requests">
Visual previews in pull requests with image rendering
</Trans>
<Box display="flex" flex="1" minHeight="50px">
<Text variant="body" color="secondary">
<Trans i18nKey="provisioning.enhanced-features.description-visual-previews-dashboard-updates-directly-requests">
See visual previews of dashboard updates directly in pull requests
</Trans>
</Text>
</Box>
{hasImageRenderer && (
<LinkButton
fill="outline"
variant="secondary"
href="https://grafana.com/grafana/plugins/grafana-image-renderer/"
icon="external-link-alt"
>
<Trans i18nKey="provisioning.enhanced-features.set-up-image-rendering">Set up image rendering</Trans>
</LinkButton>
)}
</Box>
</Stack>
</Stack>
);
};

@ -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) => (
<Box width="25%" padding={2}>
<div style={{ 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>
);

@ -1,105 +1,81 @@
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<ReactNode>;
}
const FeatureItem = ({ children }: FeatureItemProps) => {
// We use a stack here to ensure the icon and text are aligned correctly.
return (
<Stack direction="row" gap={1}>
<Icon name="check" className="text-success" />
<Text variant="body">{children}</Text>
</Stack>
);
};
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 (
<Box>
<LinkButton fill="outline" onClick={onSetupFeatures}>
<Trans i18nKey="provisioning.features-list.actions.set-up-required-feature-toggles">
Set up required feature toggles
</Trans>
</LinkButton>
</Box>
);
}
return (
<Stack direction="row" alignItems="center" gap={2}>
<ConnectRepositoryButton items={repos} />
</Stack>
);
};
export const FeaturesList = ({ repos, hasRequiredFeatures, onSetupFeatures }: FeaturesListProps) => {
const styles = useStyles2(getStyles);
return (
<Stack direction="column" gap={2}>
<Stack direction="column" gap={3}>
<Text variant="h2">
<Trans i18nKey="provisioning.features-list.manage-your-dashboards-with-remote-provisioning">
Manage your dashboards with remote provisioning
Get started with GitSync
</Trans>
</Text>
<FeatureItem>
<Trans i18nKey="provisioning.features-list.manage-dashboards-provision-updates-automatically">
Manage dashboards as code and provision updates automatically
</Trans>
</FeatureItem>
<FeatureItem>
<Trans i18nKey="provisioning.features-list.store-dashboards-in-version-controlled-storage">
Store dashboards in version-controlled storage for better organization and history tracking
</Trans>
</FeatureItem>
<FeatureItem>
<Trans i18nKey="provisioning.features-list.migrate-existing-dashboards-storage-provisioning">
Migrate existing dashboards to storage for provisioning
</Trans>
</FeatureItem>
{hasPublicAccess && (
<FeatureItem>
<Trans i18nKey="provisioning.features-list.automatically-provision-and-update-dashboards">
Automatically provision and update your dashboards as soon as changes are pushed to your GitHub repository
<ul className={styles.featuresList}>
<li>
<Trans i18nKey="provisioning.features-list.manage-dashboards-provision-updates-automatically">
Manage dashboards as code in GitHub and provision updates automatically
</Trans>
</FeatureItem>
)}
{hasImageRenderer && hasPublicAccess && (
<FeatureItem>
<Trans i18nKey="provisioning.features-list.visual-previews-in-pull-requests">
Visual previews in pull requests to review your changes before going live
</li>
<li>
<Trans i18nKey="provisioning.features-list.store-dashboards-in-version-controlled-storage">
Store dashboards in version-controlled storage for better organization and history tracking
</Trans>
</FeatureItem>
)}
{false && (
// We haven't gotten the design for this quite yet.
<LinkButton fill="text" href="#" icon="external-link-alt">
<Trans i18nKey="provisioning.features-list.learn-more">Learn more</Trans>
</LinkButton>
</li>
<li>
<Trans i18nKey="provisioning.features-list.migrate-existing-dashboards-storage-provisioning">
Migrate existing dashboards to GitHub for provisioning
</Trans>
</li>
</ul>
{!hasRequiredFeatures ? (
<Box>
<LinkButton fill="outline" onClick={onSetupFeatures}>
<Trans i18nKey="provisioning.features-list.actions.set-up-required-feature-toggles">
Set up required feature toggles
</Trans>
</LinkButton>
</Box>
) : (
<Stack direction="row" alignItems="center" gap={2}>
<ConnectRepositoryButton items={repos} />
</Stack>
)}
{actions()}
</Stack>
);
};
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,
},
},
}),
};
};

@ -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<SetupType>(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) {
</Trans>
</Alert>
)}
<Stack direction="row" gap={2}>
<Box width="50%" marginTop={2} paddingTop={2} paddingBottom={2}>
<Stack direction="column" gap={6} wrap="wrap">
<Stack gap={6} alignItems="center">
<FeaturesList
repos={items}
hasPublicAccess={hasPublicAccess}
hasImageRenderer={hasImageRenderer}
hasRequiredFeatures={hasRequiredFeatures}
onSetupFeatures={() => {
setSetupType('required-features');
setShowModal(true);
}}
/>
</Box>
<Box width="50%">
<div
className={css({
height: `100%`,
height: 360,
width: '50%',
background: `linear-gradient(to right, rgba(255, 179, 102, 0.6), rgba(255, 143, 143, 0.8))`,
borderRadius: `4px`,
padding: `16px`,
@ -177,20 +171,24 @@ export default function GettingStarted({ items }: Props) {
<Trans i18nKey="provisioning.getting-started.engaging-graphic">Engaging graphic</Trans>
</Text>
</div>
</Box>
</Stack>
{(!hasPublicAccess || !hasImageRenderer) && (
<EnhancedFeatures
hasPublicAccess={hasPublicAccess}
hasImageRenderer={hasImageRenderer}
onSetupPublicAccess={() => {
setSetupType('public-access');
setShowModal(true);
}}
/>
)}
</Stack>
{(!hasPublicAccess || !hasImageRenderer) && (
<EnhancedFeatures
hasPublicAccess={hasPublicAccess}
hasImageRenderer={hasImageRenderer}
onSetupPublicAccess={() => {
setSetupType('public-access');
setShowModal(true);
}}
/>
)}
{showInstructionsModal && setupType && (
<SetupModal {...getModalContent()} isOpen={showInstructionsModal} onDismiss={() => setShowModal(false)} />
<SetupModal
{...getModalContent(setupType)}
isOpen={showInstructionsModal}
onDismiss={() => setShowModal(false)}
/>
)}
</>
);

@ -12,10 +12,10 @@ export default function GettingStartedPage({ items }: Props) {
<Page
navId="provisioning"
pageNav={{
text: t('provisioning.getting-started-page.text-remote-provisioning', 'Remote provisioning'),
text: t('provisioning.getting-started-page.header', 'Provisioning'),
subTitle: t(
'provisioning.getting-started-page.subtitle-provisioning-feature',
'Provisioning is a feature that allows you to manage your dashboards using GitHub and other storage systems'
'View and manage your provisioning connections'
),
}}
>

@ -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 (
<div className={styles.iconCircle}>
<Icon name={icon} size="xl" />
</div>
);
};
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),
}),
};
}

@ -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 (
<LinkButton
href={CONNECT_URL}
variant="primary"
icon="plus"
disabled={true}
tooltip={t(
'provisioning.connect-repository-button.tooltip-max-repos',
'Max repositories already created ({{count}})',
{ count: state.repoCount }
)}
>
<Alert title="" severity="info">
<Trans
i18nKey="provisioning.connect-repository-button.max-repositories-exist"
i18nKey="provisioning.connect-repository-button.repository-limit-info-alert"
values={{ count: state.repoCount }}
defaults={'Maximum repositories exist ({{count}})'}
defaults={'Repository limit reached ({{count}})'}
/>
</LinkButton>
</Alert>
);
}
return (
<LinkButton href={CONNECT_URL} variant="primary" icon="plus">
<Trans i18nKey="provisioning.connect-repository-button.connect-to-repository">Connect to repository</Trans>
</LinkButton>
<Stack gap={3}>
<LinkButton href={CONNECT_URL} variant="primary">
<Trans i18nKey="provisioning.connect-repository-button.configure-git-sync">Configure GitSync</Trans>
</LinkButton>
<LinkButton href={CONNECT_URL} variant="secondary">
<Trans i18nKey="provisioning.connect-repository-button.configure-file">Configure file provisioning</Trans>
</LinkButton>
</Stack>
);
}

@ -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"

Loading…
Cancel
Save