mirror of https://github.com/grafana/grafana.git
TokenPermissionsInfo: Add token information for GitLab and Bitbucket (#109158)
* TokenPermissionsInfo: add token information for gitlab and bitbucket
This commit is contained in:
parent
1b244cd036
commit
1f76765ed7
|
|
@ -22,6 +22,7 @@ import { getGitProviderFields, getLocalProviderFields } from '../Wizard/fields';
|
|||
import { useCreateOrUpdateRepository } from '../hooks/useCreateOrUpdateRepository';
|
||||
import { RepositoryFormData } from '../types';
|
||||
import { dataToSpec } from '../utils/data';
|
||||
import { getHasTokenInstructions } from '../utils/git';
|
||||
import { getRepositoryTypeConfig, isGitProvider } from '../utils/repositoryTypes';
|
||||
|
||||
import { ConfigFormGithubCollapse } from './ConfigFormGithubCollapse';
|
||||
|
|
@ -62,6 +63,7 @@ export function ConfigForm({ data }: ConfigFormProps) {
|
|||
// Get field configurations based on provider type
|
||||
const gitFields = isGitBased ? getGitProviderFields(type) : null;
|
||||
const localFields = type === 'local' ? getLocalProviderFields(type) : null;
|
||||
const hasTokenInstructions = getHasTokenInstructions(type);
|
||||
|
||||
useEffect(() => {
|
||||
if (request.isSuccess) {
|
||||
|
|
@ -153,7 +155,7 @@ export function ConfigForm({ data }: ConfigFormProps) {
|
|||
/>
|
||||
</Field>
|
||||
)}
|
||||
{type === 'github' && <TokenPermissionsInfo />}
|
||||
{hasTokenInstructions && <TokenPermissionsInfo type={type} />}
|
||||
<Field
|
||||
noMargin
|
||||
label={gitFields.urlConfig.label}
|
||||
|
|
|
|||
|
|
@ -1,44 +1,31 @@
|
|||
import { css } from '@emotion/css';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { Trans } from '@grafana/i18n';
|
||||
import { t, Trans } from '@grafana/i18n';
|
||||
import { Stack, TextLink, useStyles2 } from '@grafana/ui';
|
||||
|
||||
export function TokenPermissionsInfo() {
|
||||
import { InstructionAvailability } from '../Wizard/types';
|
||||
|
||||
export function TokenPermissionsInfo({ type }: { type: InstructionAvailability }) {
|
||||
const styles = useStyles2(getStyles);
|
||||
const { tokenText, createTokenLink, createTokenButtonText } = connectStepInstruction()[type];
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
{/* GitHub UI is English only, so these strings are not translated */}
|
||||
{/* eslint-disable @grafana/i18n/no-untranslated-strings */}
|
||||
<Stack gap={0.5} wrap={'wrap'}>
|
||||
<Trans i18nKey="provisioning.token-permissions-info.go-to">Go to</Trans>
|
||||
<TextLink external href="https://github.com/settings/personal-access-tokens/new">
|
||||
GitHub Personal Access Tokens
|
||||
<TextLink external href={createTokenLink}>
|
||||
{tokenText}
|
||||
</TextLink>
|
||||
<Trans i18nKey="provisioning.token-permissions-info.and-click">and click</Trans>
|
||||
<strong>"Fine-grained token".</strong>
|
||||
<strong>"{createTokenButtonText}".</strong>
|
||||
<Trans i18nKey="provisioning.token-permissions-info.make-sure">Make sure to include these permissions</Trans>:
|
||||
</Stack>
|
||||
{/* eslint-enable @grafana/i18n/no-untranslated-strings */}
|
||||
|
||||
<ul className={styles.permissionsList}>
|
||||
{/* eslint-disable-next-line @grafana/i18n/no-untranslated-strings */}
|
||||
<li>
|
||||
Content: <span className={styles.accessLevel}>Read and write</span>
|
||||
</li>
|
||||
{/* eslint-disable-next-line @grafana/i18n/no-untranslated-strings */}
|
||||
<li>
|
||||
Metadata: <span className={styles.accessLevel}>Read only</span>
|
||||
</li>
|
||||
{/* eslint-disable-next-line @grafana/i18n/no-untranslated-strings */}
|
||||
<li>
|
||||
Pull requests: <span className={styles.accessLevel}>Read and write</span>
|
||||
</li>
|
||||
{/* eslint-disable-next-line @grafana/i18n/no-untranslated-strings */}
|
||||
<li>
|
||||
Webhooks: <span className={styles.accessLevel}>Read and write</span>
|
||||
</li>
|
||||
{getPermissionsForProvider(type).map((permission) => (
|
||||
<AccessLevelField key={permission.name} label={permission.name} access={permission.access} />
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
|
|
@ -72,3 +59,87 @@ function getStyles(theme: GrafanaTheme2) {
|
|||
}),
|
||||
};
|
||||
}
|
||||
|
||||
type Permission = {
|
||||
name: string;
|
||||
access: string;
|
||||
};
|
||||
|
||||
function getPermissionsForProvider(type: InstructionAvailability): Permission[] {
|
||||
switch (type) {
|
||||
case 'github':
|
||||
// GitHub UI is English only, so these strings are not translated
|
||||
return [
|
||||
{ name: 'Contents', access: 'Read and write' },
|
||||
{ name: 'Metadata', access: 'Read only' },
|
||||
{ name: 'Pull requests', access: 'Read and write' },
|
||||
{ name: 'Webhooks', access: 'Read and write' },
|
||||
];
|
||||
case 'gitlab':
|
||||
return [
|
||||
{
|
||||
name: t('provisioning.gitlab.permissions.repository-label', 'Repository'),
|
||||
access: t('provisioning.gitlab.permissions.repository-read-write', 'Read and write'),
|
||||
},
|
||||
{
|
||||
name: t('provisioning.gitlab.permissions.user-label', 'User'),
|
||||
access: t('provisioning.gitlab.permissions.user-read', 'Read only'),
|
||||
},
|
||||
{
|
||||
name: t('provisioning.gitlab.permissions.api', 'API'),
|
||||
access: t('provisioning.gitlab.permissions.api-read-write', 'Read and write'),
|
||||
},
|
||||
];
|
||||
case 'bitbucket':
|
||||
return [
|
||||
{
|
||||
name: t('provisioning.bitbucket.permissions.repository-label', 'Repositories'),
|
||||
access: t('provisioning.bitbucket.permissions.repository-read-write-admin', 'Read, and write'),
|
||||
},
|
||||
{
|
||||
name: t('provisioning.bitbucket.permissions.pull-requests-label', 'Pull requests'),
|
||||
access: t('provisioning.bitbucket.permissions.pull-requests-read-write', 'Read and write'),
|
||||
},
|
||||
{
|
||||
name: t('provisioning.bitbucket.permissions.webhooks-label', 'Webhooks'),
|
||||
access: t('provisioning.bitbucket.permissions.webhooks-read-write', 'Read and write'),
|
||||
},
|
||||
];
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
function AccessLevelField({ label, access }: { label: string; access: string }) {
|
||||
const styles = useStyles2(getStyles);
|
||||
return (
|
||||
<li>
|
||||
{label}: <span className={styles.accessLevel}>{access}</span>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
||||
function connectStepInstruction() {
|
||||
return {
|
||||
bitbucket: {
|
||||
// Bitbucket App password will be replaced by API tokens on Sep 9 2025
|
||||
createTokenLink: 'https://bitbucket.org/account/settings/app-passwords/',
|
||||
tokenText: t('provisioning.token-permissions-info.bitbucket.token-text', 'Bitbucket Personal Access Token'),
|
||||
createTokenButtonText: t(
|
||||
'provisioning.token-permissions-info.bitbucket.create-token-button',
|
||||
'Create App passwords'
|
||||
),
|
||||
},
|
||||
gitlab: {
|
||||
createTokenLink: 'https://gitlab.com/-/user_settings/personal_access_tokens',
|
||||
tokenText: t('provisioning.token-permissions-info.gitlab.token-text', 'GitLab Personal Access Token'),
|
||||
createTokenButtonText: t('provisioning.token-permissions-info.gitlab.create-token-button', 'Add new token'),
|
||||
},
|
||||
// GitHub UI is English only, so these strings are not translated
|
||||
github: {
|
||||
createTokenLink: 'https://github.com/settings/personal-access-tokens/new',
|
||||
tokenText: 'GitHub Personal Access Token',
|
||||
createTokenButtonText: 'Fine-grained token',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { Controller, useFormContext } from 'react-hook-form';
|
|||
import { Field, Input, SecretInput, Stack } from '@grafana/ui';
|
||||
|
||||
import { TokenPermissionsInfo } from '../Shared/TokenPermissionsInfo';
|
||||
import { getHasTokenInstructions } from '../utils/git';
|
||||
import { isGitProvider } from '../utils/repositoryTypes';
|
||||
|
||||
import { getGitProviderFields, getLocalProviderFields } from './fields';
|
||||
|
|
@ -26,11 +27,11 @@ export function ConnectStep() {
|
|||
// Get field configurations based on provider type
|
||||
const gitFields = isGitBased ? getGitProviderFields(type) : null;
|
||||
const localFields = !isGitBased ? getLocalProviderFields(type) : null;
|
||||
const hasTokenInstructions = getHasTokenInstructions(type);
|
||||
|
||||
return (
|
||||
<Stack direction="column" gap={2}>
|
||||
{/*TODO: Add same permission info for other providers*/}
|
||||
{type === 'github' && <TokenPermissionsInfo />}
|
||||
{hasTokenInstructions && <TokenPermissionsInfo type={type} />}
|
||||
|
||||
{gitFields && (
|
||||
<>
|
||||
|
|
|
|||
|
|
@ -41,3 +41,5 @@ export type StepStatusInfo =
|
|||
| { status: 'success'; success?: string | StatusInfo }
|
||||
| { status: 'error'; error: string | StatusInfo }
|
||||
| { status: 'warning'; warning: string | StatusInfo };
|
||||
|
||||
export type InstructionAvailability = Extract<RepoType, 'bitbucket' | 'gitlab' | 'github'>;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
import { RepositorySpec } from 'app/api/clients/provisioning/v0alpha1';
|
||||
|
||||
import { InstructionAvailability, RepoType } from '../Wizard/types';
|
||||
|
||||
/**
|
||||
* Validates a Git branch name according to the following rules:
|
||||
* 1. The branch name cannot start with `/`, end with `/`, `.`, or whitespace.
|
||||
|
|
@ -64,3 +66,7 @@ export const getRepoHrefForProvider = (spec?: RepositorySpec) => {
|
|||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
export function getHasTokenInstructions(type: RepoType): type is InstructionAvailability {
|
||||
return type === 'github' || type === 'gitlab' || type === 'bitbucket';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11098,6 +11098,14 @@
|
|||
"branch-required": "Branch is required",
|
||||
"path-description": "Optional subdirectory path within the repository",
|
||||
"path-label": "Path",
|
||||
"permissions": {
|
||||
"pull-requests-label": "Pull requests",
|
||||
"pull-requests-read-write": "Read and write",
|
||||
"repository-label": "Repositories",
|
||||
"repository-read-write-admin": "Read, and write",
|
||||
"webhooks-label": "Webhooks",
|
||||
"webhooks-read-write": "Read and write"
|
||||
},
|
||||
"pr-workflow-description": "Allows users to choose whether to open a pull request when saving changes. If the repository does not allow direct changes to the main branch, a pull request may still be required.",
|
||||
"pr-workflow-label": "Enable pull request option when saving",
|
||||
"token-description": "Bitbucket App Password with repository permissions",
|
||||
|
|
@ -11311,6 +11319,14 @@
|
|||
"branch-required": "Branch is required",
|
||||
"path-description": "Optional subdirectory path within the repository",
|
||||
"path-label": "Path",
|
||||
"permissions": {
|
||||
"api": "API",
|
||||
"api-read-write": "Read and write",
|
||||
"repository-label": "Repository",
|
||||
"repository-read-write": "Read and write",
|
||||
"user-label": "User",
|
||||
"user-read": "Read only"
|
||||
},
|
||||
"pr-workflow-description": "Allows users to choose whether to open a merge request when saving changes. If the repository does not allow direct changes to the main branch, a merge request may still be required.",
|
||||
"pr-workflow-label": "Enable merge request option when saving",
|
||||
"token-description": "GitLab Project Access Token with repository permissions",
|
||||
|
|
@ -11517,6 +11533,14 @@
|
|||
},
|
||||
"token-permissions-info": {
|
||||
"and-click": "and click",
|
||||
"bitbucket": {
|
||||
"create-token-button": "Create App passwords",
|
||||
"token-text": "Bitbucket Personal Access Token"
|
||||
},
|
||||
"gitlab": {
|
||||
"create-token-button": "Add new token",
|
||||
"token-text": "GitLab Personal Access Token"
|
||||
},
|
||||
"go-to": "Go to",
|
||||
"make-sure": "Make sure to include these permissions"
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in New Issue