Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add sign in button in entity GitHub related cards #1665

7 changes: 7 additions & 0 deletions .changeset/wise-seahorses-swim.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@roadiehq/backstage-plugin-github-pull-requests': minor
'@roadiehq/backstage-plugin-security-insights': minor
'@roadiehq/backstage-plugin-github-insights': minor
---

Add SignIn button to all Github related cards from entity overwiew page.
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ import { defaultIntegrationsConfig } from '../../../mocks/scmIntegrationsApiMock

const mockGithubAuth = {
getAccessToken: async (_: string[]) => 'test-token',
sessionState$: jest.fn(() => ({
subscribe: (fn: (a: string) => void) => {
fn('SignedIn');
return { unsubscribe: jest.fn() };
},
})),
};

const apis: [AnyApiRef, Partial<unknown>][] = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ import {
GITHUB_INSIGHTS_ANNOTATION,
} from '../../utils/isGithubInsightsAvailable';
import { useEntity } from '@backstage/plugin-catalog-react';
import {
GithubNotAuthorized,
useGithubLoggedIn,
} from '../../../hooks/useGithubLoggedIn';

const useStyles = makeStyles(theme => ({
infoCard: {
Expand All @@ -48,12 +52,21 @@ const ContributorsCard = () => {
const { hostname } = useEntityGithubScmIntegration(entity);
const projectAlert = isGithubInsightsAvailable(entity);
const { owner, repo } = useProjectEntity(entity);
const isLoggedIn = useGithubLoggedIn();
if (!projectAlert) {
return (
<MissingAnnotationEmptyState annotation={GITHUB_INSIGHTS_ANNOTATION} />
);
}

if (!isLoggedIn) {
return (
<InfoCard title="Contributors" className={classes.infoCard}>
<GithubNotAuthorized />
</InfoCard>
);
}

if (loading) {
return <Progress />;
} else if (error) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ import { defaultIntegrationsConfig } from '../../../mocks/scmIntegrationsApiMock

const mockGithubAuth = {
getAccessToken: async (_: string[]) => 'test-token',
sessionState$: jest.fn(() => ({
subscribe: (fn: (a: string) => void) => {
fn('SignedIn');
return { unsubscribe: jest.fn() };
},
})),
};

const apis: [AnyApiRef, Partial<unknown>][] = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ import {
import { useRequest } from '../../../hooks/useRequest';
import { colors } from './colors';
import { useProjectEntity } from '../../../hooks/useProjectEntity';
import {
GithubNotAuthorized,
useGithubLoggedIn,
} from '../../../hooks/useGithubLoggedIn';
import {
isGithubInsightsAvailable,
GITHUB_INSIGHTS_ANNOTATION,
Expand Down Expand Up @@ -66,7 +70,7 @@ type Language = {
[key: string]: number;
};

const LanguagesCard = () => {
const LanguagesCardContent = () => {
const { entity } = useEntity();
let barWidth = 0;
const classes = useStyles();
Expand Down Expand Up @@ -154,4 +158,17 @@ const LanguagesCard = () => {
);
};

const LanguagesCard = () => {
const classes = useStyles();
const isLoggedIn = useGithubLoggedIn();

return isLoggedIn ? (
<LanguagesCardContent />
) : (
<InfoCard title="Languages" className={classes.infoCard}>
<GithubNotAuthorized />
</InfoCard>
);
};

export default LanguagesCard;
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ import { defaultIntegrationsConfig } from '../../../mocks/scmIntegrationsApiMock

const mockGithubAuth = {
getAccessToken: async (_: string[]) => 'test-token',
sessionState$: jest.fn(() => ({
subscribe: (fn: (a: string) => void) => {
fn('SignedIn');
return { unsubscribe: jest.fn() };
},
})),
};

const apis: [AnyApiRef, Partial<unknown>][] = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ import {
} from '../../utils/isGithubInsightsAvailable';
import { useEntity } from '@backstage/plugin-catalog-react';
import { styles as useStyles } from '../../utils/styles';
import {
GithubNotAuthorized,
useGithubLoggedIn,
} from '../../../hooks/useGithubLoggedIn';

type Release = {
id: number;
Expand All @@ -41,7 +45,7 @@ type Release = {
name: string;
};

const ReleasesCard = () => {
const ReleasesCardContent = () => {
const classes = useStyles();
const { entity } = useEntity();

Expand Down Expand Up @@ -108,4 +112,17 @@ const ReleasesCard = () => {
);
};

const ReleasesCard = () => {
const classes = useStyles();
const isLoggedIn = useGithubLoggedIn();

return isLoggedIn ? (
<ReleasesCardContent />
) : (
<InfoCard title="Releases" className={classes.infoCard}>
<GithubNotAuthorized />
</InfoCard>
);
};

export default ReleasesCard;
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright 2024 Larder Software Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React, { useEffect, useState } from 'react';
import {
useApi,
githubAuthApiRef,
SessionState,
} from '@backstage/core-plugin-api';
import { Grid, Tooltip, Button, Typography } from '@material-ui/core';

export const GithubNotAuthorized = () => {
const githubApi = useApi(githubAuthApiRef);
return (
<Grid container>
<Grid item xs={8}>
<Typography>
You are not logged into github. You need to be signed in to see the
content of this card.
</Typography>
</Grid>
<Grid item xs={4} container justifyContent="flex-end">
<Tooltip placement="top" arrow title="Sign in to Github">
<Button
variant="outlined"
color="primary"
// Calling getAccessToken instead of a plain signIn because we are going to get the correct scopes right away. No need to second request
onClick={() => githubApi.getAccessToken('repo')}
>
Sign in
</Button>
</Tooltip>
</Grid>
</Grid>
);
};

export const useGithubLoggedIn = () => {
const githubApi = useApi(githubAuthApiRef);
const [isLoggedIn, setIsLoggedIn] = useState(false);

useEffect(() => {
githubApi.getAccessToken('repo', { optional: true });
const authSubscription = githubApi.sessionState$().subscribe(state => {
if (state === SessionState.SignedIn) {
setIsLoggedIn(true);
}
});
return () => {
authSubscription.unsubscribe();
};
}, [githubApi]);

return isLoggedIn;
};
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ import { handlers } from '../../mocks/handlers';

const mockGithubAuth = {
getAccessToken: async (_: string[]) => 'test-token',
sessionState$: jest.fn(() => ({
subscribe: (fn: (a: string) => void) => {
fn('SignedIn');
return { unsubscribe: jest.fn() };
},
})),
};

const config = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import { Entity } from '@backstage/catalog-model';
import { useEntity } from '@backstage/plugin-catalog-react';
import { Tooltip } from '@material-ui/core';
import { TooltipContent } from './components/TooltipContent';
import { GithubNotAuthorized, useGithubLoggedIn } from '../useGithubLoggedIn';

const useStyles = makeStyles(theme => ({
infoCard: {
Expand Down Expand Up @@ -129,14 +130,23 @@ const StatsCard = (props: Props) => {
const PullRequestsStatsCard = (props: Props) => {
const { entity } = useEntity();
const projectName = isGithubSlugSet(entity);
const isLoggedIn = useGithubLoggedIn();

if (!projectName || projectName === '') {
return (
<MissingAnnotationEmptyState
annotation={GITHUB_PULL_REQUESTS_ANNOTATION}
/>
);
}
return <StatsCard {...props} />;

return isLoggedIn ? (
<StatsCard {...props} />
) : (
<InfoCard title="GitHub Pull Requests Statistics">
<GithubNotAuthorized />
</InfoCard>
);
};

export default PullRequestsStatsCard;
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ const GRAPHQL_GITHUB_API = graphql.link('https://api.github.com/graphql');

const mockGithubAuth = {
getAccessToken: async (_: string[]) => 'test-token',
sessionState$: jest.fn(() => ({
subscribe: (fn: (a: string) => void) => {
fn('SignedIn');
return { unsubscribe: jest.fn() };
},
})),
};

const config = {
Expand Down Expand Up @@ -87,10 +93,6 @@ describe('Dependabot alerts overview', () => {
const worker = setupServer();
setupRequestMockHandlers(worker);

beforeEach(() => {
jest.resetAllMocks();
});

describe('GithubDependabotAlertsTable', () => {
beforeEach(() => {
entity = entityStub;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { useProjectEntity } from '../useProjectEntity';
import { useUrl } from '../useUrl';
import { useEntity } from '@backstage/plugin-catalog-react';
import { InfoCard, Progress } from '@backstage/core-components';
import { GithubNotAuthorized, useGithubLoggedIn } from '../useGithubLoggedIn';

const useStyles = makeStyles((theme: Theme) => ({
infoCard: {
Expand Down Expand Up @@ -207,7 +208,7 @@ export const DependabotAlertInformations: FC<DependabotAlertsProps> = ({
);
};

export const DependabotAlertsWidget = () => {
const DependabotAlertsWidgetContent = () => {
const { entity } = useEntity();
const { owner, repo } = useProjectEntity(entity);
const auth = useApi(githubAuthApiRef);
Expand Down Expand Up @@ -283,3 +284,16 @@ export const DependabotAlertsWidget = () => {
<DependabotAlertInformations repository={value} detailsUrl={detailsUrl} />
) : null;
};

export const DependabotAlertsWidget = () => {
const classes = useStyles();
const isLoggedIn = useGithubLoggedIn();

return isLoggedIn ? (
<DependabotAlertsWidgetContent />
) : (
<InfoCard title="Dependabot Alerts" className={classes.infoCard}>
<GithubNotAuthorized />
</InfoCard>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ import { EntityProvider } from '@backstage/plugin-catalog-react';

const mockGithubAuth = {
getAccessToken: async (_: string[]) => 'test-token',
sessionState$: jest.fn(() => ({
subscribe: (fn: (a: string) => void) => {
fn('SignedIn');
return { unsubscribe: jest.fn() };
},
})),
};

const config = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import {
SecurityInsightFilterState,
} from '../../types';
import { useEntity } from '@backstage/plugin-catalog-react';
import { GithubNotAuthorized, useGithubLoggedIn } from '../useGithubLoggedIn';

const useStyles = makeStyles(theme => ({
infoCard: {
Expand Down Expand Up @@ -71,7 +72,7 @@ const IssuesCounter: FC<IssuesCounterProps> = ({
);
};

export const SecurityInsightsWidget = () => {
const SecurityInsightsWidgetContent = () => {
const { entity } = useEntity();
const { owner, repo } = useProjectEntity(entity);
const classes = useStyles();
Expand Down Expand Up @@ -138,3 +139,16 @@ export const SecurityInsightsWidget = () => {
</InfoCard>
);
};

export const SecurityInsightsWidget = () => {
const classes = useStyles();
const isLoggedIn = useGithubLoggedIn();

return isLoggedIn ? (
<SecurityInsightsWidgetContent />
) : (
<InfoCard title="Security Insights" className={classes.infoCard}>
<GithubNotAuthorized />
</InfoCard>
);
};
Loading
Loading