Skip to content

Commit

Permalink
Merge pull request #115 from devhubapp/github-app
Browse files Browse the repository at this point in the history
Private repositories support
  • Loading branch information
brunolemos authored Feb 26, 2019
2 parents d85d784 + ae356f4 commit 304eb5c
Show file tree
Hide file tree
Showing 96 changed files with 2,823 additions and 660 deletions.
23 changes: 13 additions & 10 deletions PRIVACY.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
# Privacy Policy

## DevHub

### Personal user information
This app requires GitHub authentication.<br/>
These are all permissions that may be requested to you and their reasons:
DevHub requests access to the user's profile data, e-mail and notifications.


### Repository and org access
You have the option to install DevHub's GitHub App in some specific orgs and repositories.
This is required to enable access to activities from private repositories.

DevHub will have access to issues, pull requests, comments, labels, assignees, milestones, merges, collaborators and some other metadata (e.g. repository name).

- [required] `read:user`: Read-only access to the user's profile data, like username, email and avatar;
- [required] `user:email`: Read-only access to the user's e-mail, so DevHub has a way to contact its users if necessary, e.g. security disclosures;
- [required] `notifications`: Read user's public and private notifications; mark as read;
- [required] `read:org`: Read-only access to the user's organizations;
- [deprecated] `public_repo`: Allow starring repositories (removed while DevHub doesn't have this feature activated);
- [deprecated] `repo`: Read user's private content, like events from private repositories ([not recommended](https://github.com/devhubapp/devhub/issues/32)).
DevHub does not have access to any code from any repository.


### Diagnostics information
This app uses [Bugsnag](https://bugsnag.com), [Google Analytics](https://analytics.google.com/) and [Firebase](https://firebase.google.com/) to collect information about crashes and app usage.
No personal information is ever sent to third parties, only an anonymous id. Services may collect user's IP. Some device information may be included for debugging purposes, like `brand`, `model` and `operation system`.
No personal information is ever sent to third parties, only an anonymous id. Services may collect the user's IP. Some device information may be included for debugging purposes, like `brand`, `model` and `operation system`.


### Security & Limited Liability
Expand All @@ -24,7 +27,7 @@ DevHub follows good practices of security, but 100% security can't be granted in

Client-side communication is encrypted using HTTPS. Server-side tokens are encrypted or behind environment variables.

Disclaimer: DevHub does not access any code from any repository, but GitHub's oauth permissions `public_repo` and `repo` provide write access. These permissions are not asked by DevHub anymore, but you may have already granted them on early versions. You can revoke the tokens in your GitHub settings. Make sure to keep your tokens safe. For example, be extra careful with which browser extensions you have installed. Token safety is user's responsibility.
We recommend being extra careful with which browser extensions you have installed to avoid token exposure to third parties.


### Support
Expand All @@ -33,4 +36,4 @@ If you find any bug, please contribute by opening an issue or sending a pull req

---

Updated January 13rd, 2019.
Updated: Feb 11th, 2019.
2 changes: 1 addition & 1 deletion packages/components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
},
"dependencies": {
"@devhub/core": "0.46.0",
"@octokit/rest": "^16.1.0",
"@octokit/rest": "16.15.0",
"axios": "^0.18.0",
"bugsnag-js": "^4.7.3",
"bugsnag-react": "^1.1.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,8 @@ import { createSpringAnimatedComponent } from './helpers'
export interface SpringAnimatedIconProps
extends Omit<OcticonIconProps, 'color'> {}

export const SpringAnimatedIcon = createSpringAnimatedComponent(Icon)
export const SpringAnimatedIcon = (createSpringAnimatedComponent(
Icon,
) as unknown) as React.ForwardRefExoticComponent<
SpringAnimatedIconProps & React.RefAttributes<Icon>
>
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import React, { useRef } from 'react'
import { StyleSheet, TextProps, View } from 'react-native'
import { useSpring } from 'react-spring/native'

import { GitHubIcon } from '@devhub/core'
import { GitHubIcon, Omit } from '@devhub/core'
import { useCSSVariablesOrSpringAnimatedTheme } from '../../hooks/use-css-variables-or-spring--animated-theme'
import { useHover } from '../../hooks/use-hover'
import { Platform } from '../../libs/platform'
Expand All @@ -19,7 +19,7 @@ import { SpringAnimatedView } from '../animated/spring/SpringAnimatedView'
import { useTheme } from '../context/ThemeContext'

export interface GitHubLoginButtonProps
extends SpringAnimatedTouchableOpacityProps {
extends Omit<SpringAnimatedTouchableOpacityProps, 'children'> {
horizontal?: boolean
leftIcon?: GitHubIcon
loading?: boolean
Expand Down
42 changes: 22 additions & 20 deletions packages/components/src/components/cards/EmptyCards.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react'
import { Image, Text, TextStyle, View, ViewStyle } from 'react-native'

import { LoadState } from '@devhub/core'
import { EnhancedLoadState } from '@devhub/core'
import { useCSSVariablesOrSpringAnimatedTheme } from '../../hooks/use-css-variables-or-spring--animated-theme'
import { useReduxAction } from '../../hooks/use-redux-action'
import * as actions from '../../redux/actions'
Expand All @@ -13,6 +13,7 @@ import {
import { SpringAnimatedActivityIndicator } from '../animated/spring/SpringAnimatedActivityIndicator'
import { SpringAnimatedText } from '../animated/spring/SpringAnimatedText'
import { Button } from '../common/Button'
import { GenericMessageWithButtonView } from './GenericMessageWithButtonView'

const clearMessages = [
'All clear!',
Expand All @@ -37,23 +38,25 @@ const getRandomEmoji = () => {
// only one message per app running instance
// because a chaning message is a bit distractive
const clearMessage = getRandomClearMessage()
const emoji = getRandomEmoji()
const emojiImageURL = getEmojiImageURL(emoji)
const randomEmoji = getRandomEmoji()
const randomEmojiImageURL = getEmojiImageURL(randomEmoji)

export interface EmptyCardsProps {
clearedAt: string | undefined
columnId: string
emoji?: GitHubEmoji
errorMessage?: string
errorTitle?: string
fetchNextPage: (() => void) | undefined
loadState: LoadState
loadState: EnhancedLoadState
refresh: (() => void | Promise<void>) | undefined
}

export const EmptyCards = React.memo((props: EmptyCardsProps) => {
const {
clearedAt,
columnId,
emoji = 'warning',
errorMessage,
errorTitle = 'Something went wrong',
fetchNextPage,
Expand All @@ -69,7 +72,10 @@ export const EmptyCards = React.memo((props: EmptyCardsProps) => {
const hasError = errorMessage || loadState === 'error'

const renderContent = () => {
if (loadState === 'loading_first') {
if (
loadState === 'loading_first' ||
(loadState === 'loading' && !refresh && !fetchNextPage)
) {
return (
<SpringAnimatedActivityIndicator
color={springAnimatedTheme.foregroundColor}
Expand All @@ -91,39 +97,35 @@ export const EmptyCards = React.memo((props: EmptyCardsProps) => {

if (hasError) {
return (
<View style={containerStyle}>
<SpringAnimatedText style={springAnimatedTextStyle}>
{`⚠️\n${errorTitle}`}
{!!errorMessage && (
<Text style={{ fontSize: 13 }}>{`\n${errorMessage}`}</Text>
)}
</SpringAnimatedText>

{!!refresh && (
<View style={{ padding: contentPadding }}>
<GenericMessageWithButtonView
buttonView={
!!refresh && (
<Button
analyticsLabel="try_again"
children="Try again"
disabled={loadState !== 'error'}
loading={loadState === 'loading'}
onPress={() => refresh()}
/>
</View>
)}
</View>
)
}
emoji={emoji}
title={errorTitle}
subtitle={errorMessage}
/>
)
}

return (
<View style={containerStyle}>
<SpringAnimatedText style={springAnimatedTextStyle}>
{clearMessage}
{!!emojiImageURL && (
{!!randomEmojiImageURL && (
<>
<Text children=" " />

<Image
source={{ uri: emojiImageURL }}
source={{ uri: randomEmojiImageURL }}
style={{ width: 16, height: 16 }}
/>
</>
Expand Down
16 changes: 8 additions & 8 deletions packages/components/src/components/cards/EventCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ export const EventCard = React.memo((props: EventCardProps) => {
? getGitHubAvatarURLFromPayload(payload, actor.id)
: undefined

const avatarURL = (isBot && botAvatarURL) || actor.avatar_url
const avatarUrl = (isBot && botAvatarURL) || actor.avatar_url

const { icon: pullRequestIconName, color: pullRequestIconColor } = pullRequest
? getPullRequestIconAndColor(pullRequest)
Expand Down Expand Up @@ -201,7 +201,7 @@ export const EventCard = React.memo((props: EventCardProps) => {
<EventCardHeader
key={`event-card-header-${id}`}
actionText={actionText}
avatarURL={avatarURL}
avatarUrl={avatarUrl}
cardIconColor={cardIconColor}
cardIconName={cardIconName}
date={event.created_at}
Expand Down Expand Up @@ -274,7 +274,7 @@ export const EventCard = React.memo((props: EventCardProps) => {
{Boolean(pullRequest) && (
<IssueOrPullRequestRow
key={`event-pr-row-${pullRequest.id}`}
avatarURL={pullRequest.user.avatar_url}
avatarUrl={pullRequest.user.avatar_url}
commentsCount={pullRequest.comments}
createdAt={pullRequest.created_at}
iconColor={pullRequestIconColor!}
Expand Down Expand Up @@ -305,7 +305,7 @@ export const EventCard = React.memo((props: EventCardProps) => {
{Boolean(issue) && (
<IssueOrPullRequestRow
key={`event-issue-row-${issue.id}`}
avatarURL={issue.user.avatar_url}
avatarUrl={issue.user.avatar_url}
commentsCount={issue.comments}
createdAt={issue.created_at}
iconColor={issueIconColor!}
Expand All @@ -329,7 +329,7 @@ export const EventCard = React.memo((props: EventCardProps) => {
Boolean(issue.body) && (
<CommentRow
key={`event-issue-body-row-${issue.id}`}
avatarURL={issue.user.avatar_url}
avatarUrl={issue.user.avatar_url}
body={issue.body}
isRead={isRead}
smallLeftColumn={smallLeftColumn}
Expand All @@ -343,7 +343,7 @@ export const EventCard = React.memo((props: EventCardProps) => {
Boolean(pullRequest.body) && (
<CommentRow
key={`event-pr-body-row-${pullRequest.id}`}
avatarURL={pullRequest.user.avatar_url}
avatarUrl={pullRequest.user.avatar_url}
body={pullRequest.body}
isRead={isRead}
smallLeftColumn={smallLeftColumn}
Expand All @@ -357,7 +357,7 @@ export const EventCard = React.memo((props: EventCardProps) => {
(Boolean(comment && comment.body) && (
<CommentRow
key={`event-comment-row-${comment.id}`}
avatarURL={comment.user.avatar_url}
avatarUrl={comment.user.avatar_url}
body={comment.body}
isRead={isRead}
smallLeftColumn={smallLeftColumn}
Expand All @@ -370,7 +370,7 @@ export const EventCard = React.memo((props: EventCardProps) => {
{Boolean(release) && (
<ReleaseRow
key={`event-release-row-${release.id}`}
avatarURL={release.author.avatar_url}
avatarUrl={release.author.avatar_url}
body={release.body}
branch={release.target_commitish}
isRead={isRead}
Expand Down
6 changes: 2 additions & 4 deletions packages/components/src/components/cards/EventCards.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,14 @@ import {
Column,
constants,
EnhancedGitHubEvent,
EnhancedLoadState,
isItemRead,
LoadState,
} from '@devhub/core'
import useKeyPressCallback from '../../hooks/use-key-press-callback'
import { useKeyboardScrolling } from '../../hooks/use-keyboard-scrolling'
import { useReduxAction } from '../../hooks/use-redux-action'
import { useReduxState } from '../../hooks/use-redux-state'
import { bugsnag, ErrorBoundary } from '../../libs/bugsnag'
import * as actions from '../../redux/actions'
import * as selectors from '../../redux/selectors'
import { contentPadding } from '../../styles/variables'
import { Button } from '../common/Button'
import { FlatListWithOverlay } from '../common/FlatListWithOverlay'
Expand All @@ -30,7 +28,7 @@ export interface EventCardsProps {
errorMessage: EmptyCardsProps['errorMessage']
events: EnhancedGitHubEvent[]
fetchNextPage: (() => void) | undefined
loadState: LoadState
loadState: EnhancedLoadState
refresh: EmptyCardsProps['refresh']
repoIsKnown?: boolean
swipeable?: boolean
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import React from 'react'
import { Image, Text, View } from 'react-native'

import { useCSSVariablesOrSpringAnimatedTheme } from '../../hooks/use-css-variables-or-spring--animated-theme'
import { contentPadding } from '../../styles/variables'
import {
getEmojiImageURL,
GitHubEmoji,
} from '../../utils/helpers/github/emojis'
import { SpringAnimatedText } from '../animated/spring/SpringAnimatedText'

export interface GenericMessageWithButtonViewProps {
buttonView: React.ReactNode
emoji: GitHubEmoji
subtitle: string | undefined
title: string
}

export const GenericMessageWithButtonView = React.memo(
(props: GenericMessageWithButtonViewProps) => {
const { buttonView, emoji, subtitle, title } = props

const springAnimatedTheme = useCSSVariablesOrSpringAnimatedTheme()

const emojiImageURL = getEmojiImageURL(emoji)

return (
<View
style={{
width: '100%',
padding: contentPadding,
}}
>
{!!emojiImageURL && (
<Image
source={{ uri: emojiImageURL }}
style={{
alignSelf: 'center',
width: 16,
height: 16,
marginBottom: 4,
}}
/>
)}

<SpringAnimatedText
style={{
lineHeight: 20,
fontSize: 14,
color: springAnimatedTheme.foregroundColorMuted50,
textAlign: 'center',
}}
>
{title}

{!!subtitle && (
<>
{!!title && <Text>{'\n'}</Text>}
<Text style={{ fontSize: 13 }}>{subtitle}</Text>
</>
)}
</SpringAnimatedText>

{!!buttonView && (
<View style={{ padding: contentPadding }}>{buttonView}</View>
)}
</View>
)
},
)
Loading

0 comments on commit 304eb5c

Please sign in to comment.