Prettier the Markdown and SCSS 💄

This commit is contained in:
Jed Fox 2017-12-12 06:19:11 -05:00
parent adbffea777
commit 15e8fcf623
78 changed files with 1568 additions and 1088 deletions

View file

@ -5,9 +5,9 @@
In the interest of fostering an open and welcoming environment, we as In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of experience, size, disability, ethnicity, gender identity and expression, level of
nationality, personal appearance, race, religion, or sexual identity and experience, nationality, personal appearance, race, religion, or sexual identity
orientation. and orientation.
## Our Standards ## Our Standards
@ -23,7 +23,7 @@ include:
Examples of unacceptable behavior by participants include: Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or * The use of sexualized language or imagery and unwelcome sexual attention or
advances advances
* Trolling, insulting/derogatory comments, and personal or political attacks * Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment * Public or private harassment
* Publishing others' private information, such as a physical or electronic * Publishing others' private information, such as a physical or electronic
@ -37,11 +37,11 @@ Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior. response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or Project maintainers have the right and responsibility to remove, edit, or reject
reject comments, commits, code, wiki edits, issues, and other contributions comments, commits, code, wiki edits, issues, and other contributions that are
that are not aligned to this Code of Conduct, or to ban temporarily or not aligned to this Code of Conduct, or to ban temporarily or permanently any
permanently any contributor for other behaviors that they deem inappropriate, contributor for other behaviors that they deem inappropriate, threatening,
threatening, offensive, or harmful. offensive, or harmful.
## Scope ## Scope
@ -55,11 +55,11 @@ further defined and clarified by project maintainers.
## Enforcement ## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at opensource@github.com. All reported by contacting the project team at opensource@github.com. All complaints
complaints will be reviewed and investigated and will result in a response that will be reviewed and investigated and will result in a response that is deemed
is deemed necessary and appropriate to the circumstances. The project team is necessary and appropriate to the circumstances. The project team is obligated to
obligated to maintain confidentiality with regard to the reporter of an incident. maintain confidentiality with regard to the reporter of an incident. Further
Further details of specific enforcement policies may be posted separately. details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other faith may face temporary or permanent repercussions as determined by other
@ -67,8 +67,8 @@ members of the project's leadership.
## Attribution ## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, This Code of Conduct is adapted from the [Contributor Covenant][homepage],
available at [http://contributor-covenant.org/version/1/4][version] version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org [homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/ [version]: http://contributor-covenant.org/version/1/4/

View file

@ -1,11 +1,13 @@
# Contributing to GitHub Desktop # Contributing to GitHub Desktop
:+1: :tada: :sparkling_heart: Thanks for your interest! :sparkling_heart: :tada: :+1: :+1: :tada: :sparkling_heart: Thanks for your interest! :sparkling_heart: :tada:
:+1:
The following is a set of guidelines for contributing to GitHub Desktop and its The following is a set of guidelines for contributing to GitHub Desktop and its
related projects, which are hosted in the [Desktop organization](https://github.com/desktop) related projects, which are hosted in the
on GitHub. These are just guidelines, not rules. Use your best judgment, and [Desktop organization](https://github.com/desktop) on GitHub. These are just
feel free to propose changes to this document in a pull request. guidelines, not rules. Use your best judgment, and feel free to propose changes
to this document in a pull request.
Note that GitHub Desktop is an evolving project, so expect things to change over Note that GitHub Desktop is an evolving project, so expect things to change over
time as the team learns, listens and refines how we work with the community. time as the team learns, listens and refines how we work with the community.
@ -13,24 +15,28 @@ time as the team learns, listens and refines how we work with the community.
#### Table Of Contents #### Table Of Contents
[What should I know before I get started?](#what-should-i-know-before-i-get-started) [What should I know before I get started?](#what-should-i-know-before-i-get-started)
* [Code of Conduct](#code-of-conduct)
* [The Roadmap](#the-roadmap) * [Code of Conduct](#code-of-conduct)
* [The Roadmap](#the-roadmap)
[How Can I Contribute?](#how-can-i-contribute) [How Can I Contribute?](#how-can-i-contribute)
* [Reporting Bugs](#reporting-bugs)
* [Suggesting Enhancements](#suggesting-enhancements) * [Reporting Bugs](#reporting-bugs)
* [Help Wanted](#help-wanted) * [Suggesting Enhancements](#suggesting-enhancements)
* [Help Wanted](#help-wanted)
[Additional Notes](#additional-notes) [Additional Notes](#additional-notes)
* [Issue and Pull Request Labels](#issue-and-pull-request-labels)
* [Issue and Pull Request Labels](#issue-and-pull-request-labels)
## What should I know before I get started? ## What should I know before I get started?
### Code of Conduct ### Code of Conduct
This project adheres to the Contributor Covenant [code of conduct](CODE_OF_CONDUCT.md). This project adheres to the Contributor Covenant
By participating, you are expected to uphold this code. [code of conduct](CODE_OF_CONDUCT.md). By participating, you are expected to
Please report unacceptable behavior to [opensource+desktop@github.com](mailto:opensource+desktop@github.com). uphold this code. Please report unacceptable behavior to
[opensource+desktop@github.com](mailto:opensource+desktop@github.com).
### The Roadmap ### The Roadmap
@ -38,7 +44,8 @@ GitHub Desktop recently announced its
[1.0 release](https://github.com/blog/2437-announcing-github-desktop-1-0) and [1.0 release](https://github.com/blog/2437-announcing-github-desktop-1-0) and
are working towards deprecating the classic Mac and Windows applications. are working towards deprecating the classic Mac and Windows applications.
Beyond that, we are working on a roadmap you can read [here](https://github.com/desktop/desktop/blob/master/docs/process/roadmap.md). Beyond that, we are working on a roadmap you can read
[here](https://github.com/desktop/desktop/blob/master/docs/process/roadmap.md).
The immediate milestones are more detailed, and the latter milestones are more The immediate milestones are more detailed, and the latter milestones are more
fuzzy and subject to change. fuzzy and subject to change.
@ -55,65 +62,71 @@ Following these guidelines helps maintainers and the community understand your
report :pencil:, reproduce the behavior :computer: :computer:, and find related report :pencil:, reproduce the behavior :computer: :computer:, and find related
reports :mag_right:. reports :mag_right:.
Before creating bug reports, please check [this list](#before-submitting-a-bug-report) Before creating bug reports, please check
as you might find out that you don't need to create one. When you are creating [this list](#before-submitting-a-bug-report) as you might find out that you
a bug report, please [include as many details as possible](#how-do-i-submit-a-good-bug-report). don't need to create one. When you are creating a bug report, please
Fill out [the required template](./.github/ISSUE_TEMPLATE.md), the information [include as many details as possible](#how-do-i-submit-a-good-bug-report). Fill
it asks for helps us resolve issues faster. out [the required template](./.github/ISSUE_TEMPLATE.md), the information it
asks for helps us resolve issues faster.
#### Before Submitting A Bug Report #### Before Submitting A Bug Report
**Perform a [cursory search](https://github.com/desktop/desktop/labels/bug)** **Perform a [cursory search](https://github.com/desktop/desktop/labels/bug)** to
to see if the problem has already been reported. If it does exist, add a see if the problem has already been reported. If it does exist, add a :thumbsup:
:thumbsup: to the issue to indicate this is also an issue for you, and add a to the issue to indicate this is also an issue for you, and add a comment to the
comment to the existing issue if there is extra information you can contribute. existing issue if there is extra information you can contribute.
#### How Do I Submit A (Good) Bug Report? #### How Do I Submit A (Good) Bug Report?
Bugs are tracked as [GitHub issues](https://guides.github.com/features/issues/). Bugs are tracked as [GitHub issues](https://guides.github.com/features/issues/).
Simply create an issue on the [GitHub Desktop issue tracker](https://github.com/desktop/desktop/issues) Simply create an issue on the
and fill out the provided [issue template](./.github/ISSUE_TEMPLATE.md). [GitHub Desktop issue tracker](https://github.com/desktop/desktop/issues) and
fill out the provided [issue template](./.github/ISSUE_TEMPLATE.md).
The information we are interested in includes: The information we are interested in includes:
- details about your environment - which build, which operating system * details about your environment - which build, which operating system
- details about reproducing the issue - what steps to take, what happens, how * details about reproducing the issue - what steps to take, what happens, how
often it happens often it happens
- other relevant information - log files, screenshots, etc. * other relevant information - log files, screenshots, etc.
### Suggesting Enhancements ### Suggesting Enhancements
This section guides you through submitting an enhancement suggestion for This section guides you through submitting an enhancement suggestion for GitHub
GitHub Desktop, including completely new features and minor improvements to Desktop, including completely new features and minor improvements to existing
existing functionality. Following these guidelines helps maintainers and the functionality. Following these guidelines helps maintainers and the community
community understand your suggestion :pencil: and find related suggestions understand your suggestion :pencil: and find related suggestions :mag_right:.
:mag_right:.
Before creating enhancement suggestions, please check [this list](#before-submitting-an-enhancement-suggestion) Before creating enhancement suggestions, please check
as you might find out that you don't need to create one. When you are creating [this list](#before-submitting-an-enhancement-suggestion) as you might find out
an enhancement suggestion, please [include as many details as possible](#how-do-i-submit-a-good-enhancement-suggestion). that you don't need to create one. When you are creating an enhancement
Fill in [the template](./.github/ISSUE_TEMPLATE.md), including the steps suggestion, please
that you imagine you would take if the feature you're requesting existed. [include as many details as possible](#how-do-i-submit-a-good-enhancement-suggestion).
Fill in [the template](./.github/ISSUE_TEMPLATE.md), including the steps that
you imagine you would take if the feature you're requesting existed.
#### Before Submitting An Enhancement Suggestion #### Before Submitting An Enhancement Suggestion
**Perform a [cursory search](https://github.com/desktop/desktop/labels/enhancement)** **Perform a
to see if the enhancement has already been suggested. If it has, add a [cursory search](https://github.com/desktop/desktop/labels/enhancement)** to see
:thumbsup: to indicate your interest in it, or comment if there is additional if the enhancement has already been suggested. If it has, add a :thumbsup: to
information you would like to add. indicate your interest in it, or comment if there is additional information you
would like to add.
#### How Do I Submit A (Good) Enhancement Suggestion? #### How Do I Submit A (Good) Enhancement Suggestion?
Enhancement suggestions are tracked as [GitHub issues](https://guides.github.com/features/issues/). Enhancement suggestions are tracked as
[GitHub issues](https://guides.github.com/features/issues/).
Simply create an issue on the [GitHub Desktop issue tracker](https://github.com/desktop/desktop/issues) Simply create an issue on the
and provide the following information: [GitHub Desktop issue tracker](https://github.com/desktop/desktop/issues) and
provide the following information:
* **Use a clear and descriptive title** for the issue to identify the * **Use a clear and descriptive title** for the issue to identify the
suggestion. suggestion.
* **Provide a step-by-step description of the suggested enhancement** in as * **Provide a step-by-step description of the suggested enhancement** in as much
much detail as possible. This additional context helps the maintainers to detail as possible. This additional context helps the maintainers to
understand the enhancement from your perspective understand the enhancement from your perspective
* **Explain why this enhancement would be useful** to GitHub Desktop users. * **Explain why this enhancement would be useful** to GitHub Desktop users.
* **Include screenshots and animated GIFs** if relevant to help you demonstrate * **Include screenshots and animated GIFs** if relevant to help you demonstrate
@ -127,47 +140,48 @@ and provide the following information:
As part of building GitHub Desktop, we'll identify tasks that are good for As part of building GitHub Desktop, we'll identify tasks that are good for
external contributors to pick up. These tasks: external contributors to pick up. These tasks:
- have low impact, or have a known workaround * have low impact, or have a known workaround
- should be addressed * should be addressed
- have a narrow scope and/or easy reproduction steps * have a narrow scope and/or easy reproduction steps
- can be worked on independent of other tasks * can be worked on independent of other tasks
These issues will be labelled as [`help wanted`](https://github.com/desktop/desktop/labels/help%20wanted) These issues will be labelled as
in the repository. If you are interested in contributing to the project, please [`help wanted`](https://github.com/desktop/desktop/labels/help%20wanted) in the
comment on the issue to let the core team (and the community) know you are repository. If you are interested in contributing to the project, please comment
interested in the issue. on the issue to let the core team (and the community) know you are interested in
the issue.
## Additional Notes ## Additional Notes
### Issue and Pull Request Labels ### Issue and Pull Request Labels
This section lists the labels we use to help us track and manage issues and This section lists the labels we use to help us track and manage issues and pull
pull requests. requests.
#### Type of Issue and Issue State #### Type of Issue and Issue State
| Label name | :mag_right: | Description | | Label name | :mag_right: | Description |
| --- | --- | --- | | ------------------------- | --------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| `enhancement` | [search](https://github.com/desktop/desktop/labels/enhancement) | Feature requests. | | `enhancement` | [search](https://github.com/desktop/desktop/labels/enhancement) | Feature requests. |
| `bug` | [search](https://github.com/desktop/desktop/labels/bug) | Confirmed bugs or reports that are very likely to be bugs. | | `bug` | [search](https://github.com/desktop/desktop/labels/bug) | Confirmed bugs or reports that are very likely to be bugs. |
| `more-information-needed` | [search](https://github.com/desktop/desktop/labels/more-information-needed) | More information needs to be collected about these problems or feature requests (e.g. steps to reproduce). | | `more-information-needed` | [search](https://github.com/desktop/desktop/labels/more-information-needed) | More information needs to be collected about these problems or feature requests (e.g. steps to reproduce). |
| `needs-reproduction` | [search](https://github.com/desktop/desktop/labels/needs-reproduction) | Likely bugs, but haven't been reliably reproduced. | | `needs-reproduction` | [search](https://github.com/desktop/desktop/labels/needs-reproduction) | Likely bugs, but haven't been reliably reproduced. |
| `stale` | [search](https://github.com/desktop/desktop/labels/stale) | Issues that are inactive and marked to be closed. | | `stale` | [search](https://github.com/desktop/desktop/labels/stale) | Issues that are inactive and marked to be closed. |
| `macOS` | [search](https://github.com/desktop/desktop/labels/macOS) | Issues specific to macOS users. | | `macOS` | [search](https://github.com/desktop/desktop/labels/macOS) | Issues specific to macOS users. |
| `Windows` | [search](https://github.com/desktop/desktop/labels/Windows) | Issues specific to Windows users. | | `Windows` | [search](https://github.com/desktop/desktop/labels/Windows) | Issues specific to Windows users. |
| `codemirror` | [search](https://github.com/desktop/desktop/labels/codemirror) | Issues related to our use of [CodeMirror](https://codemirror.net/) that may require upstream fixes. | | `codemirror` | [search](https://github.com/desktop/desktop/labels/codemirror) | Issues related to our use of [CodeMirror](https://codemirror.net/) that may require upstream fixes. |
| `electron` | [search](https://github.com/desktop/desktop/labels/electron) | Issues related to our use of [Electron](https://electron.atom.io) that may require upstream fixes. | | `electron` | [search](https://github.com/desktop/desktop/labels/electron) | Issues related to our use of [Electron](https://electron.atom.io) that may require upstream fixes. |
#### Topics #### Topics
| Label name | :mag_right: | Description | | Label name | :mag_right: | Description |
| --- | --- | --- | | -------------------- | ---------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| `help wanted` | [search](https://github.com/desktop/desktop/labels/help%20wanted) | Issues marked as ideal for external contributors. | | `help wanted` | [search](https://github.com/desktop/desktop/labels/help%20wanted) | Issues marked as ideal for external contributors. |
| `tech-debt` | [search](https://github.com/desktop/desktop/labels/tech-debt) | Issues related to code or architecture decisions. | | `tech-debt` | [search](https://github.com/desktop/desktop/labels/tech-debt) | Issues related to code or architecture decisions. |
| `needs-design-input` | [search](https://github.com/desktop/desktop/labels/needs-design-input) | Issues that require design input from the core team before the work can be started. | | `needs-design-input` | [search](https://github.com/desktop/desktop/labels/needs-design-input) | Issues that require design input from the core team before the work can be started. |
#### Workflow #### Workflow
| Label name | :mag_right: | Description | | Label name | :mag_right: | Description |
| --- | --- | --- | | ------------------ | -------------------------------------------------------------------- | --------------------------------------------------------------- |
| `ready-for-review` | [search](https://github.com/desktop/desktop/labels/ready-for-review) | Pull Requests that are ready to be reviewed by the maintainers. | | `ready-for-review` | [search](https://github.com/desktop/desktop/labels/ready-for-review) | Pull Requests that are ready to be reviewed by the maintainers. |

View file

@ -16,16 +16,19 @@ uses [React](https://facebook.github.io/react/).
Download the official installer for your operating system: Download the official installer for your operating system:
- [macOS](https://central.github.com/deployments/desktop/desktop/latest/darwin) * [macOS](https://central.github.com/deployments/desktop/desktop/latest/darwin)
- [Windows](https://central.github.com/deployments/desktop/desktop/latest/win32) * [Windows](https://central.github.com/deployments/desktop/desktop/latest/win32)
- [Windows machine-wide install](https://central.github.com/deployments/desktop/desktop/latest/win32?format=msi) * [Windows machine-wide install](https://central.github.com/deployments/desktop/desktop/latest/win32?format=msi)
There are several community-supported package managers that can be used to install Github Desktop. There are several community-supported package managers that can be used to
- Windows users can install using [Chocolatey](https://chocolatey.org/) package manager: install Github Desktop.
`c:\> choco install github-desktop`
- macOS users can install using [Homebrew](https://brew.sh/) package manager: * Windows users can install using [Chocolatey](https://chocolatey.org/) package
`$ brew cask install github` manager: `c:\> choco install github-desktop`
- Arch Linux users can install the latest version from the [AUR](https://aur.archlinux.org/packages/github-desktop/). * macOS users can install using [Homebrew](https://brew.sh/) package manager:
`$ brew cask install github`
* Arch Linux users can install the latest version from the
[AUR](https://aur.archlinux.org/packages/github-desktop/).
You can install this alongside your existing GitHub Desktop for Mac or GitHub You can install this alongside your existing GitHub Desktop for Mac or GitHub
Desktop for Windows application. Desktop for Windows application.
@ -39,18 +42,19 @@ from disk onto the application to get started.
Want to test out new features and get fixes before everyone else? Install the Want to test out new features and get fixes before everyone else? Install the
beta channel to get access to early builds of Desktop: beta channel to get access to early builds of Desktop:
- [macOS](https://central.github.com/deployments/desktop/desktop/latest/darwin?env=beta) * [macOS](https://central.github.com/deployments/desktop/desktop/latest/darwin?env=beta)
- [Windows](https://central.github.com/deployments/desktop/desktop/latest/win32?env=beta) * [Windows](https://central.github.com/deployments/desktop/desktop/latest/win32?env=beta)
## I have a problem with GitHub Desktop ## I have a problem with GitHub Desktop
First, please search the [open issues](https://github.com/desktop/desktop/issues?q=is%3Aopen) First, please search the
and [closed issues](https://github.com/desktop/desktop/issues?q=is%3Aclosed) [open issues](https://github.com/desktop/desktop/issues?q=is%3Aopen) and
to see if your issue hasn't already been reported (it may also be fixed). [closed issues](https://github.com/desktop/desktop/issues?q=is%3Aclosed) to see
if your issue hasn't already been reported (it may also be fixed).
If you can't find an issue that matches what you're seeing, open a [new issue](https://github.com/desktop/desktop/issues/new) If you can't find an issue that matches what you're seeing, open a
and fill out the template to provide us with enough information to investigate [new issue](https://github.com/desktop/desktop/issues/new) and fill out the
further. template to provide us with enough information to investigate further.
## How can I contribute to GitHub Desktop? ## How can I contribute to GitHub Desktop?
@ -58,7 +62,9 @@ The [CONTRIBUTING.md](./CONTRIBUTING.md) document will help you get setup and
familiar with the source. The [documentation](docs/) folder also contains more familiar with the source. The [documentation](docs/) folder also contains more
resources relevant to the project. resources relevant to the project.
If you're looking for something to work on, check out the [help wanted](https://github.com/desktop/desktop/issues?q=is%3Aissue+is%3Aopen+label%3A%22help%20wanted%22) label. If you're looking for something to work on, check out the
[help wanted](https://github.com/desktop/desktop/issues?q=is%3Aissue+is%3Aopen+label%3A%22help%20wanted%22)
label.
## More Resources ## More Resources
@ -70,10 +76,10 @@ information about GitHub Desktop.
**[MIT](LICENSE)** **[MIT](LICENSE)**
The MIT license grant is not for GitHub's trademarks, which include the logo The MIT license grant is not for GitHub's trademarks, which include the logo
designs. GitHub reserves all trademark and copyright rights in and to all designs. GitHub reserves all trademark and copyright rights in and to all GitHub
GitHub trademarks. GitHub's logos include, for instance, the stylized trademarks. GitHub's logos include, for instance, the stylized Invertocat
Invertocat designs that include "logo" in the file title in the following designs that include "logo" in the file title in the following folder:
folder: [logos](app/static/logos). [logos](app/static/logos).
GitHub® and its stylized versions and the Invertocat mark are GitHub's GitHub® and its stylized versions and the Invertocat mark are GitHub's
Trademarks or registered Trademarks. When using GitHub's logos, be sure to Trademarks or registered Trademarks. When using GitHub's logos, be sure to

View file

@ -0,0 +1 @@
singleQuote: false

View file

@ -29,7 +29,8 @@ html {
// We never want the window to be scrollable, everything has to fit // We never want the window to be scrollable, everything has to fit
// or be placed into a scrollable container. // or be placed into a scrollable container.
html, body { html,
body {
height: 100%; height: 100%;
width: 100%; width: 100%;
margin: 0; margin: 0;
@ -58,7 +59,9 @@ body {
} }
:not(input):not(textarea) { :not(input):not(textarea) {
&, &::after, &::before { &,
&::after,
&::before {
-webkit-user-select: none; -webkit-user-select: none;
user-select: none; user-select: none;
cursor: default; cursor: default;
@ -81,9 +84,14 @@ img {
// margin for easier control within type scales as it avoids margin collapsing. // margin for easier control within type scales as it avoids margin collapsing.
// //
// From: https://github.com/twbs/bootstrap/blob/a0f10e6dcb9aef2d8e36e57f3c8b1b06034a8877/scss/_reboot.scss // From: https://github.com/twbs/bootstrap/blob/a0f10e6dcb9aef2d8e36e57f3c8b1b06034a8877/scss/_reboot.scss
h1, h2, h3, h4, h5, h6 { h1,
h2,
h3,
h4,
h5,
h6 {
margin-top: 0; margin-top: 0;
margin-bottom: .5rem; margin-bottom: 0.5rem;
} }
// Regardless of platform behavior we never want buttons to be // Regardless of platform behavior we never want buttons to be

View file

@ -56,7 +56,7 @@
@import "ui/terms-and-conditions"; @import "ui/terms-and-conditions";
@import "ui/ref"; @import "ui/ref";
@import "ui/monospaced"; @import "ui/monospaced";
@import 'ui/initialize-lfs'; @import "ui/initialize-lfs";
@import 'ui/ci-status'; @import "ui/ci-status";
@import 'ui/pull-request-badge'; @import "ui/pull-request-badge";
@import 'ui/no-branches'; @import "ui/no-branches";

View file

@ -3,7 +3,7 @@
// This files contains CSS variables accessible to all selectors // This files contains CSS variables accessible to all selectors
// Primer colors, see https://github.com/primer/primer-css/blob/master/modules/primer-support/lib/variables/color-system.scss // Primer colors, see https://github.com/primer/primer-css/blob/master/modules/primer-support/lib/variables/color-system.scss
@import '~primer-support/lib/variables/color-system.scss'; @import "~primer-support/lib/variables/color-system.scss";
:root { :root {
--color-new: $green; --color-new: $green;
@ -36,8 +36,11 @@
// Typography // Typography
// //
// Font, line-height, and color for body text, headings, and more. // Font, line-height, and color for body text, headings, and more.
--font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", Arial, sans-serif; --font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI",
--font-family-monospace: Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans",
"Helvetica Neue", Arial, sans-serif;
--font-family-monospace: Menlo, Monaco, Consolas, "Liberation Mono",
"Courier New", monospace;
/** /**
* Font weight to use for semibold text * Font weight to use for semibold text

View file

@ -1,4 +1,4 @@
@import "~react-virtualized/styles.css"; @import "~react-virtualized/styles.css";
@import "~codemirror/lib/codemirror.css"; @import "~codemirror/lib/codemirror.css";
@import "~codemirror/theme/solarized.css"; @import "~codemirror/theme/solarized.css";
@import "~codemirror/addon/scroll/simplescrollbars.css" @import "~codemirror/addon/scroll/simplescrollbars.css";

View file

@ -6,4 +6,4 @@
@import "globals"; @import "globals";
@import "type"; @import "type";
@import "ui" @import "ui";

View file

@ -1,12 +1,26 @@
@mixin octicon-status { @mixin octicon-status {
.status { .status {
&-new { fill: var(--color-new); } &-new {
&-copied { fill: var(--color-new); } fill: var(--color-new);
&-modified { fill: var(--color-modified); } }
&-renamed { fill: var(--color-renamed); } &-copied {
&-deleted { fill: var(--color-deleted); } fill: var(--color-new);
&-conflicted { fill: var(--color-conflicted); } }
&-modified {
fill: var(--color-modified);
}
&-renamed {
fill: var(--color-renamed);
}
&-deleted {
fill: var(--color-deleted);
}
&-conflicted {
fill: var(--color-conflicted);
}
} }
.line-endings { fill: var(--color-conflicted); } .line-endings {
fill: var(--color-conflicted);
}
} }

View file

@ -1,11 +1,11 @@
dialog#about { dialog#about {
.dialog-content { .dialog-content {
.row-component { .row-component {
justify-content: center; justify-content: center;
} }
p, h2 { p,
h2 {
text-align: center; text-align: center;
} }
@ -40,7 +40,6 @@ dialog#about {
} }
.update-status { .update-status {
.octicon.spin { .octicon.spin {
// Make sure the spinner is aligned with the text. // Make sure the spinner is aligned with the text.
align-self: center; align-self: center;

View file

@ -46,8 +46,8 @@
padding: 0; padding: 0;
.row-component:not(:last-child) { .row-component:not(:last-child) {
margin: 0; margin: 0;
} }
} }
&.clone-generic-repository-content { &.clone-generic-repository-content {

View file

@ -37,7 +37,6 @@
} }
&:not(:last-child) { &:not(:last-child) {
// We want list items in previous menus to behave as if they have focus // We want list items in previous menus to behave as if they have focus
// even though they don't, ie we want the selected+focus state // even though they don't, ie we want the selected+focus state
// to be in effect for all parent selected menu items as well as // to be in effect for all parent selected menu items as well as
@ -68,7 +67,9 @@
width: 100%; width: 100%;
min-width: 0; min-width: 0;
&.disabled { opacity: 0.3; } &.disabled {
opacity: 0.3;
}
.label { .label {
flex-grow: 1; flex-grow: 1;

View file

@ -1,7 +1,6 @@
@import "../mixins"; @import "../mixins";
#desktop-app { #desktop-app {
// This is just a dummy wrapper needed because react doesn't like // This is just a dummy wrapper needed because react doesn't like
// being installed into <body>, see https://github.com/facebook/react/issues/3207 // being installed into <body>, see https://github.com/facebook/react/issues/3207
&-container { &-container {
@ -23,6 +22,6 @@
&-contents { &-contents {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
flex-grow: 1 flex-grow: 1;
} }
} }

View file

@ -15,16 +15,21 @@
border-radius: var(--border-radius); border-radius: var(--border-radius);
overflow: hidden; // To get those sweet rounded corners overflow: hidden; // To get those sweet rounded corners
&.emoji { width: 200px; } &.emoji {
&.user { width: 220px; } width: 200px;
&.issue { width: 300px; } }
&.user {
width: 220px;
}
&.issue {
width: 300px;
}
background-color: var(--background-color); background-color: var(--background-color);
box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.3); box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.3);
.list-item .list-item {
{
border-bottom: none; border-bottom: none;
&:not(:first-child) { &:not(:first-child) {
@ -40,14 +45,13 @@
border-top-color: var(--box-selected-active-background-color); border-top-color: var(--box-selected-active-background-color);
& + .list-item { & + .list-item {
border-top-color: var(--box-selected-active-background-color); border-top-color: var(--box-selected-active-background-color);
} }
} }
} }
} }
.autocompletion-item { .autocompletion-item {
flex-grow: 1; flex-grow: 1;
height: 100%; height: 100%;
min-width: 0; min-width: 0;
@ -61,7 +65,6 @@
} }
.emoji { .emoji {
display: flex; display: flex;
flex-grow: 1; flex-grow: 1;

View file

@ -1,4 +1,4 @@
@import '../mixins'; @import "../mixins";
.branches-container { .branches-container {
height: 100%; height: 100%;
@ -168,7 +168,7 @@
rgba(255, 255, 255, 0.5) 50%, rgba(255, 255, 255, 0.5) 50%,
rgba(255, 255, 255, 0) 100% rgba(255, 255, 255, 0) 100%
); );
content: ''; content: "";
display: block; display: block;
height: 100%; height: 100%;
width: 100%; width: 100%;

View file

@ -26,14 +26,16 @@
box-shadow: 0 0 0 1px var(--secondary-button-focus-shadow-color); box-shadow: 0 0 0 1px var(--secondary-button-focus-shadow-color);
} }
&:disabled { opacity: 0.6; } &:disabled {
opacity: 0.6;
}
.octicon { .octicon {
vertical-align: middle; vertical-align: middle;
} }
} }
.button-component[type='submit'] { .button-component[type="submit"] {
background-color: var(--button-background); background-color: var(--button-background);
color: var(--button-text-color); color: var(--button-text-color);
border: 1px solid var(--button-background); border: 1px solid var(--button-background);

View file

@ -4,7 +4,6 @@
align-items: center; align-items: center;
input { input {
margin: 0; margin: 0;
// Only add a right margin if there's a label attached to it // Only add a right margin if there's a label attached to it

View file

@ -1,7 +1,6 @@
@import "../mixins"; @import "../mixins";
#cloning-repository-view { #cloning-repository-view {
/* The view's position in relation to its parent, ie full /* The view's position in relation to its parent, ie full
* width, vertically centered... */ * width, vertically centered... */
justify-content: center; justify-content: center;

View file

@ -8,7 +8,6 @@
// allow easy layout using generalized components and elements such as <Row> // allow easy layout using generalized components and elements such as <Row>
// and <p>. // and <p>.
dialog { dialog {
// These are custom version of the alert and stop octicons that have been // These are custom version of the alert and stop octicons that have been
// scaled and adjusted to render crisply at 24px. // scaled and adjusted to render crisply at 24px.
// //
@ -38,7 +37,6 @@ dialog {
// The modal class here is the transition name for the react css transition // The modal class here is the transition name for the react css transition
// group which allows us to apply an animation when the popup appears. // group which allows us to apply an animation when the popup appears.
&.modal { &.modal {
&-enter { &-enter {
opacity: 1; opacity: 1;
transform: scale(0.75); transform: scale(0.75);
@ -74,7 +72,7 @@ dialog {
opacity: 0.01; opacity: 0.01;
transform: scale(0.25); transform: scale(0.25);
transition: opacity 100ms ease-in, transition: opacity 100ms ease-in,
transform 100ms var(--easing-ease-in-back); transform 100ms var(--easing-ease-in-back);
&::backdrop { &::backdrop {
opacity: 0.01; opacity: 0.01;
@ -143,7 +141,9 @@ dialog {
// Let the button deal with all mouse events. // Let the button deal with all mouse events.
// Without this the octicon resets the cursor when // Without this the octicon resets the cursor when
// hovering over the <path>. // hovering over the <path>.
.octicon { pointer-events: none; } .octicon {
pointer-events: none;
}
&:hover { &:hover {
color: var(--text-color); color: var(--text-color);
@ -155,7 +155,8 @@ dialog {
} }
} }
&.warning, &.error { &.warning,
&.error {
.dialog-content { .dialog-content {
position: relative; position: relative;
margin-left: var(--spacing-double); margin-left: var(--spacing-double);
@ -167,7 +168,10 @@ dialog {
// Ensure that the dialog contents always have room for the icon, // Ensure that the dialog contents always have room for the icon,
// account for two double spacers at top and bottom plus the 5px // account for two double spacers at top and bottom plus the 5px
// icon offset (margin-top) and the size of the icon itself. // icon offset (margin-top) and the size of the icon itself.
min-height: calc(var(--spacing-double) * 2 + var(--spacing-half) + var(--dialog-icon-size)); min-height: calc(
var(--spacing-double) * 2 + var(--spacing-half) +
var(--dialog-icon-size)
);
// We're creating an opaque 24 by 24px div with the background color // We're creating an opaque 24 by 24px div with the background color
// that we want the icon to appear in and then apply the icon path // that we want the icon to appear in and then apply the icon path
@ -176,7 +180,7 @@ dialog {
// //
// https://codepen.io/noahblon/post/coloring-svgs-in-css-background-images // https://codepen.io/noahblon/post/coloring-svgs-in-css-background-images
&::before { &::before {
content: ''; content: "";
display: block; display: block;
position: absolute; position: absolute;
left: 0; left: 0;
@ -220,7 +224,8 @@ dialog {
} }
} }
h2, h3 { h2,
h3 {
font-weight: var(--font-weight-semibold); font-weight: var(--font-weight-semibold);
margin-top: 0; margin-top: 0;
margin-bottom: var(--spacing); margin-bottom: var(--spacing);
@ -230,15 +235,22 @@ dialog {
} }
} }
h2 { font-size: var(--font-size-md); } h2 {
h3 { font-size: var(--font-size); } font-size: var(--font-size-md);
}
h3 {
font-size: var(--font-size);
}
ul, ol { ul,
ol {
margin-top: 0; margin-top: 0;
padding-left: var(--spacing-double); padding-left: var(--spacing-double);
list-style-position: outside; list-style-position: outside;
&:last-child { margin-bottom: 0; } &:last-child {
margin-bottom: 0;
}
li { li {
margin-bottom: var(--spacing); margin-bottom: var(--spacing);
@ -248,7 +260,6 @@ dialog {
} }
.dialog-footer { .dialog-footer {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -316,12 +327,24 @@ dialog {
} }
} }
&#preferences { width: 450px; } &#preferences {
&#about { width: 450px; } width: 450px;
&#create-repository { width: 400px; } }
&#create-branch { width: 400px; } &#about {
&#push-branch-commits { width: 450px; } width: 450px;
&#publish-branch { width: 450px; } }
&#create-repository {
width: 400px;
}
&#create-branch {
width: 400px;
}
&#push-branch-commits {
width: 450px;
}
&#publish-branch {
width: 450px;
}
&#generic-git-auth { &#generic-git-auth {
width: 450px; width: 450px;
} }
@ -343,13 +366,16 @@ dialog {
text-align: center; text-align: center;
} }
.forgot-password-row, .what-is-this-row { .forgot-password-row,
.what-is-this-row {
font-size: var(--font-size-sm); font-size: var(--font-size-sm);
justify-content: flex-end; justify-content: flex-end;
} }
} }
&#add-existing-repository { width: 400px; } &#add-existing-repository {
width: 400px;
}
&#initialize-lfs { &#initialize-lfs {
width: 400px; width: 400px;

View file

@ -1,4 +1,4 @@
@import '../mixins'; @import "../mixins";
/** The container for the CodeMirror element. */ /** The container for the CodeMirror element. */
.diff-code-mirror { .diff-code-mirror {

View file

@ -1,7 +1,6 @@
@import "../mixins"; @import "../mixins";
.file-list { .file-list {
// this value affects virtualized lists, and without it // this value affects virtualized lists, and without it
// you'll see react-virtualized just skip rendering // you'll see react-virtualized just skip rendering
// as the available vertical space is computed as zero // as the available vertical space is computed as zero
@ -33,7 +32,10 @@
width: 20px; width: 20px;
} }
input, .status { flex-shrink: 0; } input,
.status {
flex-shrink: 0;
}
.path { .path {
display: flex; display: flex;
@ -48,6 +50,8 @@
flex-shrink: 0; flex-shrink: 0;
} }
.octicon { vertical-align: text-bottom; } .octicon {
vertical-align: text-bottom;
}
} }
} }

View file

@ -1,4 +1,4 @@
@import '../mixins'; @import "../mixins";
.filter-list { .filter-list {
display: flex; display: flex;

View file

@ -2,7 +2,6 @@
z-index: var(--foldout-z-index); z-index: var(--foldout-z-index);
.overlay { .overlay {
// No focus styles whatsovever for the overlay. // No focus styles whatsovever for the overlay.
// The overlay has a tab index of -1 so that clicking on it // The overlay has a tab index of -1 so that clicking on it
// won't immediately trigger the lost focus event on the app // won't immediately trigger the lost focus event on the app

View file

@ -6,7 +6,7 @@
&:after { &:after {
border-bottom: var(--base-border); border-bottom: var(--base-border);
content: ''; content: "";
position: absolute; position: absolute;
left: 0; left: 0;
right: 0; right: 0;

View file

@ -33,10 +33,14 @@
// with the height of the content in the main container. // with the height of the content in the main container.
// Hide the actual scroll bar // Hide the actual scroll bar
.ReactVirtualized__Grid::-webkit-scrollbar { display: none; } .ReactVirtualized__Grid::-webkit-scrollbar {
display: none;
}
// Hide the scroll bar by default // Hide the scroll bar by default
.fake-scroll { display: none; } .fake-scroll {
display: none;
}
&:hover { &:hover {
.fake-scroll { .fake-scroll {
@ -59,7 +63,6 @@
} }
.list-item { .list-item {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
@ -83,5 +86,7 @@
} }
} }
&:focus { outline: none; } &:focus {
outline: none;
}
} }

View file

@ -1,7 +1,6 @@
@import "../mixins"; @import "../mixins";
#missing-repository-view { #missing-repository-view {
/* The view's position in relation to its parent, ie full /* The view's position in relation to its parent, ie full
* width, vertically centered... */ * width, vertically centered... */
justify-content: center; justify-content: center;

View file

@ -1,7 +1,9 @@
@import '../mixins'; @import "../mixins";
.path-text-component { .path-text-component {
@include ellipsis; @include ellipsis;
.dirname { color: var(--text-secondary-color); } .dirname {
color: var(--text-secondary-color);
}
} }

View file

@ -1,6 +1,5 @@
#preferences { #preferences {
.accounts-tab { .accounts-tab {
.account-info { .account-info {
.avatar { .avatar {
// 32px for the image + 2 on each side for the base border. // 32px for the image + 2 on each side for the base border.

View file

@ -12,9 +12,13 @@ progress {
} }
&:indeterminate { &:indeterminate {
background-image: background-image: -webkit-linear-gradient(
-webkit-linear-gradient(-45deg, transparent 33%, var(--text-color) 33%, -45deg,
var(--text-color) 66%, transparent 66%); transparent 33%,
var(--text-color) 33%,
var(--text-color) 66%,
transparent 66%
);
background-size: 25px 10px, 100% 100%, 100% 100%; background-size: 25px 10px, 100% 100%, 100% 100%;
-webkit-animation: progress-indeterminate-animation 5s linear infinite; -webkit-animation: progress-indeterminate-animation 5s linear infinite;
@ -22,5 +26,7 @@ progress {
} }
@-webkit-keyframes progress-indeterminate-animation { @-webkit-keyframes progress-indeterminate-animation {
100% { background-position: 100px 0px; } 100% {
background-position: 100px 0px;
}
} }

View file

@ -2,7 +2,6 @@
/** A React component holding the currently selected repository */ /** A React component holding the currently selected repository */
#repository { #repository {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
flex: 1; flex: 1;

View file

@ -1,5 +1,4 @@
.resizable-component { .resizable-component {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
flex-shrink: 0; flex-shrink: 0;

View file

@ -50,7 +50,8 @@
} }
// When someone hovers over, or presses the bar we'll expand it to 8px // When someone hovers over, or presses the bar we'll expand it to 8px
&:hover, &:active { &:hover,
&:active {
border-width: 1px; border-width: 1px;
background-color: var(--scroll-bar-thumb-background-color-active); background-color: var(--scroll-bar-thumb-background-color-active);
cursor: pointer; cursor: pointer;

View file

@ -27,7 +27,7 @@
// adapted to be 8 by 5px. The gif is in 2x and the background-size // adapted to be 8 by 5px. The gif is in 2x and the background-size
// scales it back down so that we can have crisp arrows on high-dpi // scales it back down so that we can have crisp arrows on high-dpi
// displays. The path is M 0,0 4,5 8,0 Z and the color is #6a737d. // displays. The path is M 0,0 4,5 8,0 Z and the color is #6a737d.
background-image: url('data:image/gif;base64,R0lGODlhEAAKAMQAAGpzff///8PHy6arsXqCi46UnN7g4vHy8/v7+253gYuSmm12gO/w8dve4Pz8/KassniAicfLzwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAAAAAALAAAAAAQAAoAAAUw4ACMZFk+TmGugIIEB8GSEBPcRjIvze1HM4FvKDI9hsNUyYUcxka1JjLHkzYFwmYIADs='); background-image: url("data:image/gif;base64,R0lGODlhEAAKAMQAAGpzff///8PHy6arsXqCi46UnN7g4vHy8/v7+253gYuSmm12gO/w8dve4Pz8/KassniAicfLzwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAAAAAALAAAAAAQAAoAAAUw4ACMZFk+TmGugIIEB8GSEBPcRjIvze1HM4FvKDI9hsNUyYUcxka1JjLHkzYFwmYIADs=");
background-size: 8px 5px; background-size: 8px 5px;
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: right var(--spacing-half) center; background-position: right var(--spacing-half) center;

View file

@ -53,7 +53,7 @@
} }
} }
&.switch &-item { &.switch &-item {
// Reset styles from global buttons // Reset styles from global buttons
cursor: pointer; cursor: pointer;
border: none; border: none;

View file

@ -5,7 +5,12 @@
height: 250px; height: 250px;
overflow: scroll; overflow: scroll;
p, ol, ul, li, h2, h3 { p,
ol,
ul,
li,
h2,
h3 {
cursor: text; cursor: text;
user-select: text; user-select: text;
} }

View file

@ -23,23 +23,23 @@
} }
.close { .close {
position: absolute; position: absolute;
right: var(--spacing); right: var(--spacing);
border: 0; border: 0;
height: 16px; height: 16px;
width: 16px; width: 16px;
margin: 0; margin: 0;
padding: 0; padding: 0;
background: transparent; background: transparent;
color: var(--text-secondary-color); color: var(--text-secondary-color);
&:hover { &:hover {
color: var(--text-color); color: var(--text-color);
} }
&:focus { &:focus {
outline: 0; outline: 0;
} }
} }
} }

View file

@ -1,7 +1,6 @@
@import "../mixins"; @import "../mixins";
fieldset.vertical-segmented-control { fieldset.vertical-segmented-control {
// Reset styles for fieldset // Reset styles for fieldset
border: none; border: none;
margin: 0; margin: 0;

View file

@ -53,7 +53,8 @@
} }
} }
input, button { input,
button {
font-size: var(--font-size-md); font-size: var(--font-size-md);
height: auto; height: auto;
} }

View file

@ -35,10 +35,10 @@
@include ellipsis; @include ellipsis;
} }
input[type=checkbox] { input[type="checkbox"] {
flex-grow: 0; flex-grow: 0;
flex-shrink: 0; flex-shrink: 0;
} }
} }
} }
} }

View file

@ -2,7 +2,6 @@
/** A React component holding the commit message entry */ /** A React component holding the commit message entry */
#commit-message { #commit-message {
border-top: 1px solid var(--box-border-color); border-top: 1px solid var(--box-border-color);
flex-direction: column; flex-direction: column;
flex-shrink: 0; flex-shrink: 0;
@ -20,13 +19,15 @@
flex: 1; flex: 1;
margin-bottom: var(--spacing); margin-bottom: var(--spacing);
input { width: 100%; } input {
width: 100%;
}
} }
.avatar { .avatar {
flex-shrink: 0; flex-shrink: 0;
width: var(--text-field-height); width: var(--text-field-height);
height:var(--text-field-height); height: var(--text-field-height);
border: var(--base-border); border: var(--base-border);
margin-right: var(--spacing-half); margin-right: var(--spacing-half);
} }
@ -52,6 +53,8 @@
* the contents of the button in a block element and put * the contents of the button in a block element and put
* ellipsis on that instead. See commit 67fad24ed * ellipsis on that instead. See commit 67fad24ed
*/ */
> span { @include ellipsis } > span {
@include ellipsis;
}
} }
} }

View file

@ -1,4 +1,4 @@
@import '../../mixins'; @import "../../mixins";
dialog#merge { dialog#merge {
width: 450px; width: 450px;
@ -15,7 +15,6 @@ dialog#merge {
} }
.dialog-content { .dialog-content {
padding: 0; padding: 0;
.filter-field-row { .filter-field-row {
@ -31,14 +30,15 @@ dialog#merge {
.list-item { .list-item {
padding: 0 var(--spacing-double); padding: 0 var(--spacing-double);
.filter-list-group-header, .branches-list-item { .filter-list-group-header,
.branches-list-item {
padding: 0; padding: 0;
} }
} }
} }
.dialog-footer { .dialog-footer {
button[type=submit] { button[type="submit"] {
height: auto; height: auto;
width: 100%; width: 100%;
padding: var(--spacing-half); padding: var(--spacing-half);

View file

@ -2,7 +2,6 @@
/** A React component holding history's commit list */ /** A React component holding history's commit list */
#commit-list { #commit-list {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
flex: 1; flex: 1;
@ -30,7 +29,10 @@
overflow: hidden; overflow: hidden;
margin-left: var(--spacing-half); margin-left: var(--spacing-half);
.summary, .byline { @include ellipsis } .summary,
.byline {
@include ellipsis;
}
} }
} }
} }

View file

@ -2,7 +2,6 @@
/** A React component holding the selected commit's detailed information */ /** A React component holding the selected commit's detailed information */
#commit-summary { #commit-summary {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -24,7 +23,6 @@
} }
&.expanded { &.expanded {
.commit-summary-description-container { .commit-summary-description-container {
border-bottom: none; border-bottom: none;
} }
@ -81,7 +79,13 @@
&:before { &:before {
content: ""; content: "";
background: linear-gradient(180deg, rgba(255, 255, 255, 0) 0px, rgba(255, 255, 255, 0) 40px, rgba(255, 255, 255, 0.5) 40px, white 60px); background: linear-gradient(
180deg,
rgba(255, 255, 255, 0) 0px,
rgba(255, 255, 255, 0) 40px,
rgba(255, 255, 255, 0.5) 40px,
white 60px
);
position: absolute; position: absolute;
height: 100%; height: 100%;
width: 100%; width: 100%;
@ -91,11 +95,14 @@
// Enable text selection inside the title and description elements. // Enable text selection inside the title and description elements.
&-title, &-title,
&-description { &-description {
span, a { span,
a {
-webkit-user-select: text; -webkit-user-select: text;
user-select: text; user-select: text;
} }
span { cursor: text; } span {
cursor: text;
}
} }
&-description { &-description {

View file

@ -1,5 +1,4 @@
.toolbar-button { .toolbar-button {
// Make sure the contents shrink beyond their intrinsic width // Make sure the contents shrink beyond their intrinsic width
// See https://css-tricks.com/flexbox-truncated-text/ // See https://css-tricks.com/flexbox-truncated-text/
min-width: 0; min-width: 0;
@ -17,7 +16,7 @@
// explicitly use > here to only target the direct descendant button since // explicitly use > here to only target the direct descendant button since
// there might be buttons in foldouts which would otherwise be affected // there might be buttons in foldouts which would otherwise be affected
// as well. // as well.
&>button { & > button {
// Reset styles from global buttons // Reset styles from global buttons
-webkit-appearance: none; -webkit-appearance: none;
border: none; border: none;
@ -28,7 +27,9 @@
margin: 0; margin: 0;
padding: 0; padding: 0;
&:active { box-shadow: none; } &:active {
box-shadow: none;
}
&:focus { &:focus {
background-color: var(--toolbar-button-focus-background-color); background-color: var(--toolbar-button-focus-background-color);
@ -74,8 +75,7 @@
width: 100%; width: 100%;
} }
&>button { & > button {
position: relative; position: relative;
display: flex; display: flex;
@ -124,7 +124,10 @@
position: relative; position: relative;
} }
.title, .description { @include ellipsis } .title,
.description {
@include ellipsis;
}
.progress { .progress {
position: absolute; position: absolute;
@ -135,7 +138,7 @@
background: var(--toolbar-button-progress-color); background: var(--toolbar-button-progress-color);
transform-origin: left; transform-origin: left;
pointer-events: none; pointer-events: none;
transition: transform .3s var(--easing-ease-out-quint); transition: transform 0.3s var(--easing-ease-out-quint);
} }
} }
@ -144,6 +147,8 @@
// progress we want the text to be slightly legible so we'll make it // progress we want the text to be slightly legible so we'll make it
// opaque. Since a toolbar button with progress also shows a spinner // opaque. Since a toolbar button with progress also shows a spinner
// there's plenty of indication that it can't be used. // there's plenty of indication that it can't be used.
&:disabled { opacity: 1; } &:disabled {
opacity: 1;
}
} }
} }

View file

@ -1,16 +1,15 @@
.toolbar-dropdown { .toolbar-dropdown {
// Make sure the contents shrink beyond their intrinsic width // Make sure the contents shrink beyond their intrinsic width
// See https://css-tricks.com/flexbox-truncated-text/ // See https://css-tricks.com/flexbox-truncated-text/
min-width: 0; min-width: 0;
&>.toolbar-button { & > .toolbar-button {
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
&.open { &.open {
&>.toolbar-button > button { & > .toolbar-button > button {
color: var(--toolbar-button-active-color); color: var(--toolbar-button-active-color);
background-color: var(--toolbar-button-active-background-color); background-color: var(--toolbar-button-active-background-color);

View file

@ -25,17 +25,21 @@
flex-direction: row; flex-direction: row;
flex-shrink: 0; flex-shrink: 0;
&>:last-child { & > :last-child {
flex-grow: 1; flex-grow: 1;
} }
} }
.toolbar-button { .toolbar-button {
&.push-pull-button { width: 230px; } &.push-pull-button {
width: 230px;
}
} }
.toolbar-dropdown { .toolbar-dropdown {
&.branch-button { width: 230px; } &.branch-button {
width: 230px;
}
} }
.toolbar-button { .toolbar-button {
@ -45,10 +49,15 @@
} }
} }
@keyframes spin { 100% { -webkit-transform: rotate(360deg); transform:rotate(360deg); } } @keyframes spin {
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
.spin { .spin {
animation:spin 1s linear infinite; animation: spin 1s linear infinite;
} }
.ahead-behind { .ahead-behind {
@ -78,7 +87,9 @@
// Only add left margin if both ahead and behind are // Only add left margin if both ahead and behind are
// showing at the same time. // showing at the same time.
&:nth-child(2) { margin-left: var(--spacing-half); } &:nth-child(2) {
margin-left: var(--spacing-half);
}
// We're using arrowSmallUp and arrowSmallDown which are // We're using arrowSmallUp and arrowSmallDown which are
// both exactly 6px wide. Let's use that so that spacing // both exactly 6px wide. Let's use that so that spacing

View file

@ -2,7 +2,7 @@
display: flex; display: flex;
.toolbar-button > button { .toolbar-button > button {
padding: 0 var(--spacing); padding: 0 var(--spacing);
border: 0; border: 0;
.access-key.highlight { .access-key.highlight {
@ -13,7 +13,8 @@
.toolbar-dropdown:not(.open) > .toolbar-button > button { .toolbar-dropdown:not(.open) > .toolbar-button > button {
color: var(--toolbar-button-secondary-color); color: var(--toolbar-button-secondary-color);
&:hover,&:focus { &:hover,
&:focus {
color: var(--toolbar-button-color); color: var(--toolbar-button-color);
} }
} }

View file

@ -11,7 +11,7 @@
@include darwin { @include darwin {
height: var(--darwin-title-bar-height); height: var(--darwin-title-bar-height);
background: linear-gradient(to bottom, #3b3f46 0%,#2b2e33 100%); background: linear-gradient(to bottom, #3b3f46 0%, #2b2e33 100%);
border-bottom: 1px solid #000; border-bottom: 1px solid #000;
} }
@ -28,7 +28,6 @@
} }
.resize-handle { .resize-handle {
position: absolute; position: absolute;
top: 0px; top: 0px;
left: 0px; left: 0px;
@ -50,7 +49,6 @@
// automatically even for borderless window so we only render // automatically even for borderless window so we only render
// controls on Windows. // controls on Windows.
.window-controls { .window-controls {
flex-grow: 0; flex-grow: 0;
flex-shrink: 0; flex-shrink: 0;
margin-left: auto; margin-left: auto;
@ -77,7 +75,9 @@
background-color: transparent; background-color: transparent;
transition: background-color 0.25s ease; transition: background-color 0.25s ease;
&:focus { outline: none; } &:focus {
outline: none;
}
&:hover { &:hover {
background-color: #888; background-color: #888;
@ -110,7 +110,9 @@
} }
/* https://css-tricks.com/cascading-svg-fill-color/ */ /* https://css-tricks.com/cascading-svg-fill-color/ */
svg { fill: currentColor; } svg {
fill: currentColor;
}
} }
} }
} }

View file

@ -37,12 +37,18 @@
} }
.toast-animation { .toast-animation {
&-appear { transform: scale(0.25); opacity: 0.1; } &-appear {
transform: scale(0.25);
opacity: 0.1;
}
&-appear-active { &-appear-active {
transform: scale(1); transform: scale(1);
opacity: 1; opacity: 1;
transition: all 100ms ease-out; transition: all 100ms ease-out;
} }
&-leave-active { opacity: 0; transition: all 250ms ease-out; } &-leave-active {
opacity: 0;
transition: all 250ms ease-out;
}
} }

View file

@ -11,7 +11,7 @@
top: 0; top: 0;
left: 0; left: 0;
&>div { & > div {
padding: var(--spacing); padding: var(--spacing);
min-width: 100px; min-width: 100px;
background: rgba($gray-900, 0.6); background: rgba($gray-900, 0.6);
@ -27,15 +27,25 @@
} }
.zoom-in { .zoom-in {
&-appear { transform: scale(0.25); opacity: 0; } &-appear {
transform: scale(0.25);
opacity: 0;
}
} }
.zoom-out { .zoom-out {
&-appear { transform: scale(1.75); opacity: 0; } &-appear {
transform: scale(1.75);
opacity: 0;
}
} }
.zoom-in, .zoom-out { .zoom-in,
&-leave-active { opacity: 0; transition: opacity 100ms ease-out; } .zoom-out {
&-leave-active {
opacity: 0;
transition: opacity 100ms ease-out;
}
&-appear-active { &-appear-active {
transform: scale(1); transform: scale(1);
opacity: 1; opacity: 1;

View file

@ -8,38 +8,39 @@ documentation.
If you are interested in contributing to the project, you should read these If you are interested in contributing to the project, you should read these
resources to get familiar with how things work: resources to get familiar with how things work:
- **[How Can I Contribute?](../CONTRIBUTING.md#how-can-i-contribute)** - * **[How Can I Contribute?](../CONTRIBUTING.md#how-can-i-contribute)** - details
details about how you can participate about how you can participate
- **[Development Environment Setup](contributing/setup.md)** - everything * **[Development Environment Setup](contributing/setup.md)** - everything you
you need to know to get Desktop up and running need to know to get Desktop up and running
- **[Engineering Values](contributing/engineering-values.md)** - our high-level engineering values * **[Engineering Values](contributing/engineering-values.md)** - our high-level
- **[Style Guide](contributing/styleguide.md)** - notes on the coding style engineering values
- **[Tooling](contributing/tooling.md)** - if you have a preferred IDE, * **[Style Guide](contributing/styleguide.md)** - notes on the coding style
there's some enhancements to make your life easier * **[Tooling](contributing/tooling.md)** - if you have a preferred IDE, there's
- **[Troubleshooting](contributing/troubleshooting.md)** - some additional some enhancements to make your life easier
known issues if you're having environment issues * **[Troubleshooting](contributing/troubleshooting.md)** - some additional known
issues if you're having environment issues
## Process ## Process
Details about how the team is organizing and shipping GitHub Desktop: Details about how the team is organizing and shipping GitHub Desktop:
- **[Roadmap](process/roadmap.md)** - the future as planned so far * **[Roadmap](process/roadmap.md)** - the future as planned so far
- **[Release Planning](process/release-planning.md)** - how we plan and execute * **[Release Planning](process/release-planning.md)** - how we plan and execute
releases releases
- **[Issue Triage](process/issue-triage.md)** - how we address issues reported * **[Issue Triage](process/issue-triage.md)** - how we address issues reported
by users by users
- **[Review Process](process/reviews.md)** - how we review contributions * **[Review Process](process/reviews.md)** - how we review contributions
- **[Releasing Updates](process/releasing-updates.md)** - how we deploy things * **[Releasing Updates](process/releasing-updates.md)** - how we deploy things
## Technical ## Technical
These documents contain more details about the internals of GitHub Desktop These documents contain more details about the internals of GitHub Desktop and
and how things work: how things work:
- **[Dialogs](technical/dialogs.md)** - details about the dialog component API * **[Dialogs](technical/dialogs.md)** - details about the dialog component API
- **[Windows menu bar](technical/windows-menu-bar.md)** - Electron doesn't * **[Windows menu bar](technical/windows-menu-bar.md)** - Electron doesn't
provide inbuilt support for styling the menu for Windows, so we've created provide inbuilt support for styling the menu for Windows, so we've created our
our own custom components to achieve this. own custom components to achieve this.
- **[Developer OAuth App](technical/oauth.md)** - GitHub Desktop ships with * **[Developer OAuth App](technical/oauth.md)** - GitHub Desktop ships with the
the ability to OAuth on behalf of a user. A developer OAuth app is bundled ability to OAuth on behalf of a user. A developer OAuth app is bundled to
to reduce the friction of getting started. reduce the friction of getting started.

View file

@ -1,12 +1,19 @@
# GitHub Desktop Engineering Values # GitHub Desktop Engineering Values
There's value in defining what we as shepherds of this project believe are important traits and practices. As we grow and welcome new members into our team it's beneficial to have a sense of what guided us towards the product being implemented the way it has been. There's value in defining what we as shepherds of this project believe are
important traits and practices. As we grow and welcome new members into our team
it's beneficial to have a sense of what guided us towards the product being
implemented the way it has been.
## What this is and what this isn't ## What this is and what this isn't
These values are not unbendable rules. They're an attempt to share knowledge about how the application came to be and how we currently think it should be developed. It's a non-exhaustive, living document of intentions, and beliefs. These values are not unbendable rules. They're an attempt to share knowledge
about how the application came to be and how we currently think it should be
developed. It's a non-exhaustive, living document of intentions, and beliefs.
We've chosen to focus exclusively on the engineering (i.e. how we write code) part in this document. There are other values surrounding visual design, product and project management, community etc that we're not going to consider here. We've chosen to focus exclusively on the engineering (i.e. how we write code)
part in this document. There are other values surrounding visual design, product
and project management, community etc that we're not going to consider here.
## Our values ## Our values
@ -16,23 +23,47 @@ We've chosen to focus exclusively on the engineering (i.e. how we write code) pa
### Types are good ### Types are good
We believe in strongly typed programming languages that help us avoid mistakes that are all too easy to make. When the compiler can't help us we believe in augmenting with other kinds of static analysis. Type systems and static analysis helps us not only in the moment we're writing code but also extends further out. By codifying our intentions we help prevent the next person from making a mistake. We believe in strongly typed programming languages that help us avoid mistakes
that are all too easy to make. When the compiler can't help us we believe in
augmenting with other kinds of static analysis. Type systems and static analysis
helps us not only in the moment we're writing code but also extends further out.
By codifying our intentions we help prevent the next person from making a
mistake.
#### Examples #### Examples
Our [assertNever](https://github.com/desktop/desktop/blob/d26fd1ee670dfa7f16ded74b7a4108d2bfe68c79/app/src/lib/fatal-error.ts#L6-L21) helper lets us leverage the type system to verify exhaustiveness and get [compile-time errors](https://github.com/desktop/desktop/blob/8fc8e6f5d1a8153cc92bb0e324b9c26602211646/app/src/ui/branches/ci-status.tsx#L36-L47) when that assertion fails. Our
[assertNever](https://github.com/desktop/desktop/blob/d26fd1ee670dfa7f16ded74b7a4108d2bfe68c79/app/src/lib/fatal-error.ts#L6-L21)
helper lets us leverage the type system to verify exhaustiveness and get
[compile-time errors](https://github.com/desktop/desktop/blob/8fc8e6f5d1a8153cc92bb0e324b9c26602211646/app/src/ui/branches/ci-status.tsx#L36-L47)
when that assertion fails.
Our [react-readonly-props-and-state](https://github.com/desktop/desktop/blob/d26fd1ee670dfa7f16ded74b7a4108d2bfe68c79/tslint-rules/reactReadonlyPropsAndStateRule.ts) static analysis ensures that we don't accidentally mutate state which React prohibits being mutated but isn't able to enforce due to the dynamic runtime. Our
[react-readonly-props-and-state](https://github.com/desktop/desktop/blob/d26fd1ee670dfa7f16ded74b7a4108d2bfe68c79/tslint-rules/reactReadonlyPropsAndStateRule.ts)
static analysis ensures that we don't accidentally mutate state which React
prohibits being mutated but isn't able to enforce due to the dynamic runtime.
We [write our own type definitions](https://github.com/desktop/desktop/blob/eee92a96943afbc39057b1aae66c642e23dbf136/app/src/lib/globals.d.ts#L94-L112) when none exist. We
[write our own type definitions](https://github.com/desktop/desktop/blob/eee92a96943afbc39057b1aae66c642e23dbf136/app/src/lib/globals.d.ts#L94-L112)
when none exist.
### Immutability is good ### Immutability is good
By choosing to keep as much of our state as possible in immutable data structures we can be explicit about when and where we update it and have confidence that it's not going to change from underneath us. The last part is especially important in an application such as GitHub Desktop which has lots of state. The best way we've found so far to maintain our sanity is to be explicit about how that state flows through the app and when it's updated and immutability is one tool to help us stay on the right track. By choosing to keep as much of our state as possible in immutable data
structures we can be explicit about when and where we update it and have
confidence that it's not going to change from underneath us. The last part is
especially important in an application such as GitHub Desktop which has lots of
state. The best way we've found so far to maintain our sanity is to be explicit
about how that state flows through the app and when it's updated and
immutability is one tool to help us stay on the right track.
#### Examples #### Examples
We use [read-only versions of arrays](https://github.com/desktop/desktop/blob/a61a5bdc94ee8237dfff328957cdaee99a9b61e1/app/src/models/commit.ts#L21) in interfaces and object as well as [in function parameters](https://github.com/desktop/desktop/blob/355f9671860e4777827912ddc6aac44399f5732f/app/src/lib/email.ts#L17). ( We use
[read-only versions of arrays](https://github.com/desktop/desktop/blob/a61a5bdc94ee8237dfff328957cdaee99a9b61e1/app/src/models/commit.ts#L21)
in interfaces and object as well as
[in function parameters](https://github.com/desktop/desktop/blob/355f9671860e4777827912ddc6aac44399f5732f/app/src/lib/email.ts#L17).
(
We prefer We prefer
@ -45,29 +76,54 @@ over
```ts ```ts
let a = someDefaultValue let a = someDefaultValue
if (someCondition) { if (someCondition) {
a = someOtherValue a = someOtherValue
} }
``` ```
We prefer the first example to the second because it states to ourselves and future readers that you can trust `a` to not change. Not only does it make that intention clear, it enforces it. In the case of `let` we'd have to scan the method to verify that it doesn't get mutated and even then we can't be sure that some developer in the future adds logic which changes it. Again, we're stating our intentions and letting the type system help us keep our promises. We prefer the first example to the second because it states to ourselves and
future readers that you can trust `a` to not change. Not only does it make that
intention clear, it enforces it. In the case of `let` we'd have to scan the
method to verify that it doesn't get mutated and even then we can't be sure that
some developer in the future adds logic which changes it. Again, we're stating
our intentions and letting the type system help us keep our promises.
If the checks required to determine the result are too complicated it might be time to create another function which does the heavy lifting and returns a value that you can assign to a `const`. If the checks required to determine the result are too complicated it might be
time to create another function which does the heavy lifting and returns a value
that you can assign to a `const`.
### Passing values to functions is good ### Passing values to functions is good
We believe that small, consistent, and composable methods are easier to understand, and less prone to errors than larger methods operating on data from sources other than those passed to it via arguments. You might recognize this sentiment from the concept of pure functions in functional programming. While we aren't using a language which lets us express such conditions we believe in striving towards writing methods which act on values that is provided to it via arguments and returns a consistent result based solely on those values. We believe that small, consistent, and composable methods are easier to
understand, and less prone to errors than larger methods operating on data from
sources other than those passed to it via arguments. You might recognize this
sentiment from the concept of pure functions in functional programming. While we
aren't using a language which lets us express such conditions we believe in
striving towards writing methods which act on values that is provided to it via
arguments and returns a consistent result based solely on those values.
If a method has to acquire data from multiple sources to then do some processing on it we prefer that the gathering of data and the processing of it is separated into two methods such that the computational part doesn't get entangled with acquisition of state. If a method has to acquire data from multiple sources to then do some processing
on it we prefer that the gathering of data and the processing of it is separated
into two methods such that the computational part doesn't get entangled with
acquisition of state.
At times we move methods out of classes or even out into their own file to reinforce that it's a function only acting on its given parameters (as opposed to instance fields or shared variables the function has closed over). At times we move methods out of classes or even out into their own file to
reinforce that it's a function only acting on its given parameters (as opposed
to instance fields or shared variables the function has closed over).
#### Examples #### Examples
In app-menu-bar we've extracted a method called [createState](https://github.com/desktop/desktop/blob/d26fd1ee670dfa7f16ded74b7a4108d2bfe68c79/app/src/ui/app-menu/app-menu-bar.tsx#L50-L75) from the component to live outside of the class such that we can be sure that the only thing that matters to the outcome of that function is the props object that's passed to it. By doing this we can avoid a very common example of using `this.props` inside of the method when, in fact, we might want to create a state object from `nextProps` or even `prevProps` that was given to us from one of the [React lifecycle methods](https://reactjs.org/docs/react-component.html#the-component-lifecycle). In app-menu-bar we've extracted a method called
[createState](https://github.com/desktop/desktop/blob/d26fd1ee670dfa7f16ded74b7a4108d2bfe68c79/app/src/ui/app-menu/app-menu-bar.tsx#L50-L75)
from the component to live outside of the class such that we can be sure that
the only thing that matters to the outcome of that function is the props object
that's passed to it. By doing this we can avoid a very common example of using
`this.props` inside of the method when, in fact, we might want to create a state
object from `nextProps` or even `prevProps` that was given to us from one of the
[React lifecycle methods](https://reactjs.org/docs/react-component.html#the-component-lifecycle).
## Recommended resources ## Recommended resources
- [Lifting state up](https://reactjs.org/docs/lifting-state-up.html) * [Lifting state up](https://reactjs.org/docs/lifting-state-up.html)
- [The Value of Values](https://www.infoq.com/presentations/Value-Values) * [The Value of Values](https://www.infoq.com/presentations/Value-Values)
- [Simple Made Easy](https://www.infoq.com/presentations/Simple-Made-Easy) * [Simple Made Easy](https://www.infoq.com/presentations/Simple-Made-Easy)
- [Boundaries aka Functional Core, Imperative Shell](https://www.destroyallsoftware.com/talks/boundaries) * [Boundaries aka Functional Core, Imperative Shell](https://www.destroyallsoftware.com/talks/boundaries)

View file

@ -1,9 +1,9 @@
# Preview Features # Preview Features
If you're running GitHub Desktop you can enable **"preview features"**, which If you're running GitHub Desktop you can enable **"preview features"**, which we
we consider something we want to eventually ship to everyone, but needs some consider something we want to eventually ship to everyone, but needs some sort
sort of refinement before we can do that, and in the meantime we would like of refinement before we can do that, and in the meantime we would like feedback
feedback from users on these features. from users on these features.
To opt-in for testing preview features, set the To opt-in for testing preview features, set the
`GITHUB_DESKTOP_PREVIEW_FEATURES` environment variable to any value and launch `GITHUB_DESKTOP_PREVIEW_FEATURES` environment variable to any value and launch

View file

@ -1,4 +1,4 @@
# Development Environment Setup # Development Environment Setup
## Setup ## Setup
@ -6,29 +6,33 @@ You will need to install these tools on your machine:
### macOS ### macOS
- [Node.js v8.9.0](https://nodejs.org/dist/v8.9.0/) * [Node.js v8.9.0](https://nodejs.org/dist/v8.9.0/)
- [Python 2.7](https://www.python.org/downloads/mac-osx/) * [Python 2.7](https://www.python.org/downloads/mac-osx/)
- Xcode and Xcode Command Line Tools (Xcode -> Preferences -> Downloads) * Xcode and Xcode Command Line Tools (Xcode -> Preferences -> Downloads)
### Windows ### Windows
- [Node.js v8.9.0](https://nodejs.org/dist/v8.9.0/) * [Node.js v8.9.0](https://nodejs.org/dist/v8.9.0/)
- *Make sure you allow the Node.js installer to add node to the PATH.* * _Make sure you allow the Node.js installer to add node to the PATH._
- [Python 2.7](https://www.python.org/downloads/windows/) * [Python 2.7](https://www.python.org/downloads/windows/)
- *Let Python install into the default suggested path (`c:\Python27`), otherwise you'll have * _Let Python install into the default suggested path (`c:\Python27`),
to configure node-gyp manually with the path which is annoying.* otherwise you'll have to configure node-gyp manually with the path which is
- *Ensure the **Add python.exe to Path** option is selected.* annoying._
- One of Visual Studio 2015, Visual C++ Build Tools or Visual Studio 2017 * _Ensure the **Add python.exe to Path** option is selected._
- [Visual C++ Build Tools](http://go.microsoft.com/fwlink/?LinkId=691126) * One of Visual Studio 2015, Visual C++ Build Tools or Visual Studio 2017
- *Run `npm config set msvs_version 2015` to tell node to use this toolchain.* * [Visual C++ Build Tools](http://go.microsoft.com/fwlink/?LinkId=691126)
- Visual Studio 2015 * _Run `npm config set msvs_version 2015` to tell node to use this
- *Ensure you select the **Common Tools for Visual C++ 2015** feature as that is required by Node.js toolchain._
for installing native modules.* * Visual Studio 2015
- *Run `npm config set msvs_version 2015` to tell node to use this toolchain.* * _Ensure you select the **Common Tools for Visual C++ 2015** feature as
- [Visual Studio 2017](https://www.visualstudio.com/vs/community/) that is required by Node.js for installing native modules._
- *Ensure you select the **Desktop development with C++** feature as that is required by Node.js for * _Run `npm config set msvs_version 2015` to tell node to use this
installing native modules.* toolchain._
- *Run `npm config set msvs_version 2017` to tell node to use this toolchain.* * [Visual Studio 2017](https://www.visualstudio.com/vs/community/)
* _Ensure you select the **Desktop development with C++** feature as that is
required by Node.js for installing native modules._
* _Run `npm config set msvs_version 2017` to tell node to use this
toolchain._
### Fedora 26 ### Fedora 26
@ -44,15 +48,18 @@ After that, install the dependencies to build and test the app:
$ sudo dnf install -y nodejs gcc-c++ make libsecret-devel libXScrnSaver $ sudo dnf install -y nodejs gcc-c++ make libsecret-devel libXScrnSaver
``` ```
If you want to package Desktop for distribution, you will need these additional dependencies: If you want to package Desktop for distribution, you will need these additional
dependencies:
```shellsession ```shellsession
$ sudo dnf install fakeroot dpkg rpm rpm-build xz xorriso appstream bzip2-devel $ sudo dnf install fakeroot dpkg rpm rpm-build xz xorriso appstream bzip2-devel
``` ```
If you have problems packaging for AppImage, you may need to force the linker to use the right If you have problems packaging for AppImage, you may need to force the linker to
version of specific dependencies. More information [here](https://michaelheap.com/error-while-loading-shared-libraries-libbz2-so-1-0-cannot-open-shared-object-file-on-centos-7) use the right version of specific dependencies. More information
and [here](https://github.com/electron-userland/electron-builder/issues/993#issuecomment-291021974) [here](https://michaelheap.com/error-while-loading-shared-libraries-libbz2-so-1-0-cannot-open-shared-object-file-on-centos-7)
and
[here](https://github.com/electron-userland/electron-builder/issues/993#issuecomment-291021974)
```shellsession ```shellsession
$ sudo ln -s `find /usr/lib64/ -type f -name "libbz2.so.1*"` /usr/lib64/libbz2.so.1.0 $ sudo ln -s `find /usr/lib64/ -type f -name "libbz2.so.1*"` /usr/lib64/libbz2.so.1.0
@ -87,17 +94,19 @@ $ sudo apt install -y fakeroot dpkg rpm xz-utils xorriso zsync
## Verification ## Verification
With these things installed, open a shell and install `yarn` (you might need With these things installed, open a shell and install `yarn` (you might need to
to `sudo` here depending on how Node was installed): `sudo` here depending on how Node was installed):
```shellsession ```shellsession
$ npm install -g yarn@1.3.2 $ npm install -g yarn@1.3.2
``` ```
This is important because yarn uses lock files to pin dependencies. If you find This is important because yarn uses lock files to pin dependencies. If you find
yourself changing packages, this will prevent mismatches in versions between machines. yourself changing packages, this will prevent mismatches in versions between
machines.
Then validate you have these commands available and that the versions look similar: Then validate you have these commands available and that the versions look
similar:
```shellsession ```shellsession
$ node -v $ node -v
@ -110,21 +119,21 @@ $ python --version
Python 2.7.13 Python 2.7.13
``` ```
There are also [additional resources](tooling.md) to There are also [additional resources](tooling.md) to configure your favorite
configure your favorite editor to work nicely with the GitHub Desktop editor to work nicely with the GitHub Desktop repository.
repository.
## Building Desktop ## Building Desktop
After cloning the repository, the typical workflow to get up running After cloning the repository, the typical workflow to get up running is as
is as follows: follows:
* Run `yarn` to get all required dependencies on your machine. * Run `yarn` to get all required dependencies on your machine.
* Run `yarn build:dev` to create a development build of the app. * Run `yarn build:dev` to create a development build of the app.
* Run `yarn start` to launch the application. Changes will be compiled in the * Run `yarn start` to launch the application. Changes will be compiled in the
background. The app can then be reloaded to see the changes (Ctrl/Command+R). background. The app can then be reloaded to see the changes (Ctrl/Command+R).
**Optional Tip**: On macOS and Linux, you can use `screen` to avoid filling your terminal with logging output: **Optional Tip**: On macOS and Linux, you can use `screen` to avoid filling your
terminal with logging output:
```shellsession ```shellsession
$ screen -S "desktop" yarn start # -S sets the name of the session; you can pick anything $ screen -S "desktop" yarn start # -S sets the name of the session; you can pick anything
@ -134,19 +143,18 @@ $ screen -R "desktop" # to reopen the session, read the logs, and exit (Ctrl+C)
[screen is terminating] [screen is terminating]
``` ```
If you've made changes in the `main-process` folder you need to run `yarn If you've made changes in the `main-process` folder you need to run
build:dev` to rebuild the package, and then `yarn start` for these changes to be `yarn build:dev` to rebuild the package, and then `yarn start` for these changes
reflected in the running app. to be reflected in the running app.
If you're still encountering issues with building, refer to our If you're still encountering issues with building, refer to our
[troubleshooting](troubleshooting.md) guide for more common [troubleshooting](troubleshooting.md) guide for more common problems.
problems.
## Running tests ## Running tests
- `yarn test` - Runs all unit and integration tests * `yarn test` - Runs all unit and integration tests
- `yarn test:unit` - Runs all unit tests * `yarn test:unit` - Runs all unit tests
- `yarn test:integration` - Runs all integration tests * `yarn test:integration` - Runs all integration tests
**Pro Tip:** If you're only interested in the results of a single test and don't **Pro Tip:** If you're only interested in the results of a single test and don't
wish to run the entire test suite to see it you can pass along a search string wish to run the entire test suite to see it you can pass along a search string
@ -171,8 +179,8 @@ When running the app in development mode,
should automatically install itself on first start when in development mode. should automatically install itself on first start when in development mode.
An additional extension, [Devtron](http://electron.atom.io/devtron/), is also An additional extension, [Devtron](http://electron.atom.io/devtron/), is also
included but is disabled by default. To enable Devtron, select the Console included but is disabled by default. To enable Devtron, select the Console tab
tab in Chrome Developer Tools and run this command: in Chrome Developer Tools and run this command:
```js ```js
require('devtron').install() require('devtron').install()
@ -182,7 +190,7 @@ require('devtron').install()
You're almost there! Here's a couple of things we recommend you read next: You're almost there! Here's a couple of things we recommend you read next:
- [Help Wanted](../../CONTRIBUTING.md#help-wanted) - we've marked some tasks in * [Help Wanted](../../CONTRIBUTING.md#help-wanted) - we've marked some tasks in
the backlog that are ideal for external contributors the backlog that are ideal for external contributors
- [Code Reviews](../process/reviews.md) - some notes on how the team does * [Code Reviews](../process/reviews.md) - some notes on how the team does code
code reviews reviews

View file

@ -1,33 +1,42 @@
# TypeScript Style Guide # TypeScript Style Guide
Most of our preferred style when writing typescript is configured in our [`tslint.json`](../../tslint.json) and [`.eslintrc.yml`](../../.eslintrc.yml) files. Most of our preferred style when writing typescript is configured in our
[`tslint.json`](../../tslint.json) and [`.eslintrc.yml`](../../.eslintrc.yml)
files.
## Do ## Do
- Use camelCase for methods
- Use PascalCase for class names * Use camelCase for methods
- Enable [TSLint](https://palantir.github.io/tslint/usage/third-party-tools/) and [ESLint](https://eslint.org/docs/user-guide/integrations) in your editor * Use PascalCase for class names
* Enable [TSLint](https://palantir.github.io/tslint/usage/third-party-tools/)
and [ESLint](https://eslint.org/docs/user-guide/integrations) in your editor
# Documenting your code # Documenting your code
We currently use [JSDoc](http://usejsdoc.org/) even though we don't currently generate any documentation or We currently use [JSDoc](http://usejsdoc.org/) even though we don't currently
verify the format. We're using JSDoc over other formats because the typescript compiler has built-in support generate any documentation or verify the format. We're using JSDoc over other
for parsing jsdoc and presenting it in IDEs. formats because the typescript compiler has built-in support for parsing jsdoc
and presenting it in IDEs.
While there doesn't appear to be any well-used typescript documentation export utilities out there at the While there doesn't appear to be any well-used typescript documentation export
moment we hope that it's only a matter of time. JSDoc uses a lot of metadata that is already self-documented utilities out there at the moment we hope that it's only a matter of time. JSDoc
in the typescript type system such as visibility, inheritance, membership. uses a lot of metadata that is already self-documented in the typescript type
system such as visibility, inheritance, membership.
For now all you need to know is that you can document classes, methods, properties and fields by using the For now all you need to know is that you can document classes, methods,
following formatted comment on the line above whatever you're trying to document. properties and fields by using the following formatted comment on the line above
whatever you're trying to document.
```ts ```ts
/** This is a documentation string */ /** This is a documentation string */
``` ```
The double start `/**` opener is the key. It has to be exactly two stars for it to be a valid JSDoc open token. The double start `/**` opener is the key. It has to be exactly two stars for it
to be a valid JSDoc open token.
If you need multiple lines to describe the subject try to sum up the thing you're describing in a short title If you need multiple lines to describe the subject try to sum up the thing
and leave a blank line before you go into detail, similar to a git commit message. you're describing in a short title and leave a blank line before you go into
detail, similar to a git commit message.
```ts ```ts
/** /**
@ -39,16 +48,18 @@ and leave a blank line before you go into detail, similar to a git commit messag
## Visibility of AppStore Methods ## Visibility of AppStore Methods
The [`Dispatcher`](https://github.com/desktop/desktop/blob/master/app/src/lib/dispatcher/dispatcher.ts) The
is the entry point for most interactions with the application which update state, [`Dispatcher`](https://github.com/desktop/desktop/blob/master/app/src/lib/dispatcher/dispatcher.ts)
and for most usages this work is then delegated to the [`AppStore`](https://github.com/desktop/desktop/blob/master/app/src/lib/dispatcher/app-store.ts). is the entry point for most interactions with the application which update
state, and for most usages this work is then delegated to the
[`AppStore`](https://github.com/desktop/desktop/blob/master/app/src/lib/dispatcher/app-store.ts).
Due to this coupling, we need to discourage callers directly manipulating Due to this coupling, we need to discourage callers directly manipulating
specific methods in the `AppStore` unless there's a compelling reason. specific methods in the `AppStore` unless there's a compelling reason.
We do this by making the methods look unappealing: We do this by making the methods look unappealing:
- underscore prefix on method name * underscore prefix on method name
- comment indicating that you should be looking elsewhere * comment indicating that you should be looking elsewhere
```ts ```ts
/** This shouldn't be called directly. See `Dispatcher`. */ /** This shouldn't be called directly. See `Dispatcher`. */
@ -66,10 +77,10 @@ there's a compelling reason and no asynchronous alternative. In those cases the
method should be suffixed with `Sync` to make it clear to the caller what's method should be suffixed with `Sync` to make it clear to the caller what's
happening. We also fall back to `Sync` methods for readability in tests. happening. We also fall back to `Sync` methods for readability in tests.
We use [an ESLint rule](https://eslint.org/docs/rules/no-sync) to enforce We use [an ESLint rule](https://eslint.org/docs/rules/no-sync) to enforce this
this standard. standard.
### Scripts ### Scripts
For scripts we should favor synchronous APIs as the asynchronous benefits are For scripts we should favor synchronous APIs as the asynchronous benefits are
not so important there, and it makes the code easier to read. not so important there, and it makes the code easier to read.

View file

@ -1,43 +1,43 @@
# Profiling Desktop using the Chrome Developer Tools # Profiling Desktop using the Chrome Developer Tools
Sometimes performance issues are hard to identify and recreate. If you notice Sometimes performance issues are hard to identify and recreate. If you notice a
a regression and can reproduce it, you can use the Timeline tools in Chrome Dev regression and can reproduce it, you can use the Timeline tools in Chrome Dev
Tools to take a snapshot of the application performance and attach it to an Tools to take a snapshot of the application performance and attach it to an
issue. issue.
## Steps ## Steps
- Launch Desktop and select **View** | **Toggle Developer Tools**. * Launch Desktop and select **View** | **Toggle Developer Tools**.
<img width="558" src="https://user-images.githubusercontent.com/359239/26888284-f80ed244-4b80-11e7-86cf-933c59b8f370.png"> <img width="558" src="https://user-images.githubusercontent.com/359239/26888284-f80ed244-4b80-11e7-86cf-933c59b8f370.png">
- Get the Desktop application ready to perform the problem action. * Get the Desktop application ready to perform the problem action.
- Select the **Timeline** tab. * Select the **Timeline** tab.
<img width="1123" src="https://user-images.githubusercontent.com/359239/26887089-7c82f0cc-4b7d-11e7-9cf4-fcbd5a994e1f.png"> <img width="1123" src="https://user-images.githubusercontent.com/359239/26887089-7c82f0cc-4b7d-11e7-9cf4-fcbd5a994e1f.png">
- Ensure you have **JS Profile** checked - other items might be helpful, but * Ensure you have **JS Profile** checked - other items might be helpful, but
will add to the size of the generated timeline data. will add to the size of the generated timeline data.
<img width="1123" src="https://user-images.githubusercontent.com/359239/26888385-3fc9157c-4b81-11e7-9083-379a37d20641.png"> <img width="1123" src="https://user-images.githubusercontent.com/359239/26888385-3fc9157c-4b81-11e7-9083-379a37d20641.png">
- Press the **Record** button on the left to start recording. * Press the **Record** button on the left to start recording.
<img width="1123" src="https://user-images.githubusercontent.com/359239/26887091-7c8acc3e-4b7d-11e7-9d32-961ac353f1b9.png"> <img width="1123" src="https://user-images.githubusercontent.com/359239/26887091-7c8acc3e-4b7d-11e7-9d32-961ac353f1b9.png">
- Perform the problem action in Desktop. Try and keep the test focused on the * Perform the problem action in Desktop. Try and keep the test focused on the
issue you're seeing. issue you're seeing.
- Switch back to the Developer tools and press **Stop** to complete recording. * Switch back to the Developer tools and press **Stop** to complete recording.
<img width="1011" src="https://user-images.githubusercontent.com/359239/26887304-0700a514-4b7e-11e7-9a1d-74fac88cecee.png"> <img width="1011" src="https://user-images.githubusercontent.com/359239/26887304-0700a514-4b7e-11e7-9a1d-74fac88cecee.png">
- In the graph section, right-click and select **Save timeline data**. Save the * In the graph section, right-click and select **Save timeline data**. Save the
JSON file somewhere you can access later. JSON file somewhere you can access later.
<img width="1014" alt="screen shot 2017-06-07 at 12 38 18 pm" src="https://user-images.githubusercontent.com/359239/26887386-472e9c7c-4b7e-11e7-9d39-a9b71ea3d70a.png"> <img width="1014" alt="screen shot 2017-06-07 at 12 38 18 pm" src="https://user-images.githubusercontent.com/359239/26887386-472e9c7c-4b7e-11e7-9d39-a9b71ea3d70a.png">
- Compress the JSON file to reduce the file size (it could be 10MB or more * Compress the JSON file to reduce the file size (it could be 10MB or more
depending on how long you ran the test for). depending on how long you ran the test for).
- Attach the file to your GitHub issue so the contributors can load this into * Attach the file to your GitHub issue so the contributors can load this into
their environment and spelunk the diagnostic information. their environment and spelunk the diagnostic information.

View file

@ -6,17 +6,19 @@ Recommended packages:
* [atom-typescript](https://atom.io/packages/atom-typescript) - syntax * [atom-typescript](https://atom.io/packages/atom-typescript) - syntax
highlighting and intellisense for TypeScript highlighting and intellisense for TypeScript
* [atom-build-npm-apm](https://atom.io/packages/build-npm-apm) - invoke * [atom-build-npm-apm](https://atom.io/packages/build-npm-apm) - invoke all npm
all npm scripts straight from the editor by pressing F7 (requires scripts straight from the editor by pressing F7 (requires
[atom-build](https://atom.io/packages/build)) [atom-build](https://atom.io/packages/build))
* [linter](https://atom.io/packages/linter) and * [linter](https://atom.io/packages/linter) and
[linter-tslint](https://atom.io/packages/linter-tslint) - shows linter errors and warning in the editor [linter-tslint](https://atom.io/packages/linter-tslint) - shows linter errors
and warning in the editor
### [Visual Studio Code](https://code.visualstudio.com/) ### [Visual Studio Code](https://code.visualstudio.com/)
The Desktop repository includes a list of recommended extensions: The Desktop repository includes a list of recommended extensions:
1. Select the _Extension_ view, select *Show Workspace Recommended Extensions* from the dropdown menu 1. Select the _Extension_ view, select _Show Workspace Recommended Extensions_
from the dropdown menu
2. Install all the extensions 2. Install all the extensions
## Debugging ## Debugging
@ -26,5 +28,7 @@ The Desktop repository includes a list of recommended extensions:
1. Run the command `npm start` 1. Run the command `npm start`
2. Open _Chrome Dev Tools_ 2. Open _Chrome Dev Tools_
[React Dev Tools](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=en) should automatically install itself on first start. If you would also like to use [Devtron](http://electron.atom.io/devtron/), run the command `require('devtron').install()` inside of the console in _Chrome Dev Tools_. [React Dev Tools](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=en)
should automatically install itself on first start. If you would also like to
use [Devtron](http://electron.atom.io/devtron/), run the command
`require('devtron').install()` inside of the console in _Chrome Dev Tools_.

View file

@ -5,7 +5,8 @@ while working on GitHub Desktop:
### Issues compiling node-keytar on Windows ### Issues compiling node-keytar on Windows
If keytar fails to build on Windows with the following error during `npm install`: If keytar fails to build on Windows with the following error during
`npm install`:
``` ```
npm ERR! keytar@3.0.2 install: `node-gyp rebuild` npm ERR! keytar@3.0.2 install: `node-gyp rebuild`

View file

@ -50,4 +50,4 @@ To remove any packages that are no longer needed:
```sh ```sh
> yarn remove [package-name] > yarn remove [package-name]
``` ```

View file

@ -1,30 +1,48 @@
# Installing GitHub Desktop # Installing GitHub Desktop
GitHub Desktop currently supports Windows 7 (or higher) and macOS 10.9 (or higher). GitHub Desktop currently supports Windows 7 (or higher) and macOS 10.9 (or
higher).
### macOS ### macOS
Download the `GitHub Desktop.zip`, unpack the application and put it wherever you want. Download the `GitHub Desktop.zip`, unpack the application and put it wherever
you want.
### Windows ### Windows
On Windows you have two options: On Windows you have two options:
- Download the `GitHubDesktopSetup.exe` and run it to install it for the current user. * Download the `GitHubDesktopSetup.exe` and run it to install it for the current
- Download the `GitHubDesktopSetup.msi` and run it to install a machine-wide version of GitHub Desktop - each logged-in user will then be able to run GitHub Desktop from the program at `%PROGRAMFILES(x86)\GitHub Desktop Installer\desktop.exe` user.
* Download the `GitHubDesktopSetup.msi` and run it to install a machine-wide
version of GitHub Desktop - each logged-in user will then be able to run
GitHub Desktop from the program at
`%PROGRAMFILES(x86)\GitHub Desktop Installer\desktop.exe`
## Data Directories ## Data Directories
GitHub Desktop will create directories to manage the files and data it needs to function. If you manage a network of computers and want to install GitHub Desktop, here is more information about how things work. GitHub Desktop will create directories to manage the files and data it needs to
function. If you manage a network of computers and want to install GitHub
Desktop, here is more information about how things work.
### macOS ### macOS
- `~/Library/Application Support/GitHub Desktop/` - this directory contains user-specific data which the application requires to run, and is created on launch if it doesn't exist. Log files are also stored in this location.
* `~/Library/Application Support/GitHub Desktop/` - this directory contains
user-specific data which the application requires to run, and is created on
launch if it doesn't exist. Log files are also stored in this location.
### Windows ### Windows
- `%LOCALAPPDATA%\GitHubDesktop\` - contains the latest versions of the app, and some older versions if the user has updated from a previous version. * `%LOCALAPPDATA%\GitHubDesktop\` - contains the latest versions of the app, and
- `%APPDATA%\GitHub Desktop\` - this directory contains user-specific data which the application requires to run, and is created on launch if it doesn't exist. Log files are also stored in this location. some older versions if the user has updated from a previous version.
* `%APPDATA%\GitHub Desktop\` - this directory contains user-specific data which
the application requires to run, and is created on launch if it doesn't exist.
Log files are also stored in this location.
## Log Files ## Log Files
GitHub Desktop will generate log files if an unhandled exception is raised, to assist with troubleshooting. They are located in the data directory that GitHub Desktop uses (see above) under a `logs` subdirectory, organized by date using the format `YYYY-MM-DD.desktop.production.log`, where `YYYY-MM-DD` is the day the log was created. GitHub Desktop will generate log files if an unhandled exception is raised, to
assist with troubleshooting. They are located in the data directory that GitHub
Desktop uses (see above) under a `logs` subdirectory, organized by date using
the format `YYYY-MM-DD.desktop.production.log`, where `YYYY-MM-DD` is the day
the log was created.

View file

@ -2,20 +2,23 @@
## Authentication ## Authentication
To authenticate against Visual Studio Team Services repositories, you need to enable the alternate authentication credentials. To authenticate against Visual Studio Team Services repositories, you need to
enable the alternate authentication credentials.
- Select **Security** in the user profile's dropdown: * Select **Security** in the user profile's dropdown:
![](https://user-images.githubusercontent.com/4404199/29400833-79755fe0-8337-11e7-8cfb-1d346a6801b4.png) ![](https://user-images.githubusercontent.com/4404199/29400833-79755fe0-8337-11e7-8cfb-1d346a6801b4.png)
- Select **Alternate authentication credentials**: * Select **Alternate authentication credentials**:
![](https://user-images.githubusercontent.com/4404199/29400853-8cc5918c-8337-11e7-92ad-60563d4d49e2.png) ![](https://user-images.githubusercontent.com/4404199/29400853-8cc5918c-8337-11e7-92ad-60563d4d49e2.png)
- Check the **Enable alternate authentication credentials** checkbox, and then choose a suitable username/password: * Check the **Enable alternate authentication credentials** checkbox, and then
choose a suitable username/password:
![](https://user-images.githubusercontent.com/4404199/29400917-bed11cc8-8337-11e7-9d3e-1bda2e99d519.png) ![](https://user-images.githubusercontent.com/4404199/29400917-bed11cc8-8337-11e7-9d3e-1bda2e99d519.png)
- Enter your chosen credentials in Desktop when prompted. You can either use your email or the chosen username to authenticate: * Enter your chosen credentials in Desktop when prompted. You can either use
your email or the chosen username to authenticate:
![](https://user-images.githubusercontent.com/4404199/29401109-8bf03536-8338-11e7-8abb-b467378b6115.png) ![](https://user-images.githubusercontent.com/4404199/29401109-8bf03536-8338-11e7-8abb-b467378b6115.png)

View file

@ -10,15 +10,31 @@ We have a first responder rotation. The goals of the rotation are:
Each rotation is a week long. While first responder your primary duties are: Each rotation is a week long. While first responder your primary duties are:
1. Triage issues. 1. Triage issues.
* Troubleshoot or follow up on troubleshooting started by the previous first responder. The current first responder should always bear responsibility for pushing troubleshooting forward, unless another team member has explicitly taken ownership. * Troubleshoot or follow up on troubleshooting started by the previous first
* Ensure issues are labeled accurately. responder. The current first responder should always bear responsibility
* Review the [`more-information-needed`](https://github.com/desktop/desktop/issues?q=is%3Aopen+is%3Aissue+label%3Amore-information-needed+sort%3Aupdated-asc) and [`needs-reproduction`](https://github.com/desktop/desktop/issues?q=is%3Aopen+is%3Aissue+sort%3Aupdated-asc+label%3Aneeds-reproduction) issues and close any that have gone 2 weeks with no new activity. for pushing troubleshooting forward, unless another team member has
* See [issue-triage.md](issue-triage.md) for more information on our issue triage process. explicitly taken ownership.
* Ensure issues are labeled accurately.
* Review the
[`more-information-needed`](https://github.com/desktop/desktop/issues?q=is%3Aopen+is%3Aissue+label%3Amore-information-needed+sort%3Aupdated-asc)
and
[`needs-reproduction`](https://github.com/desktop/desktop/issues?q=is%3Aopen+is%3Aissue+sort%3Aupdated-asc+label%3Aneeds-reproduction)
issues and close any that have gone 2 weeks with no new activity.
* See [issue-triage.md](issue-triage.md) for more information on our issue
triage process.
1. Check community pull requests and label ones that are `ready-for-review`. 1. Check community pull requests and label ones that are `ready-for-review`.
1. Review community pull requests. 1. Review community pull requests.
Once those things are done, you should feel free to spend your time scratching your own itches on the project. Really wanna refactor that one monstrous component? Go for it! Wanna fix that one bug that drives you nuts? Do it! Wanna upgrade all of our dependencies? You're an awesome masochist! Once those things are done, you should feel free to spend your time scratching
your own itches on the project. Really wanna refactor that one monstrous
component? Go for it! Wanna fix that one bug that drives you nuts? Do it! Wanna
upgrade all of our dependencies? You're an awesome masochist!
That said, tasks which need design work generally *aren't* well-suited to this. It would pull our fantastic designers away from milestone work and it would be hard to get done in a week's time. That said, tasks which need design work generally _aren't_ well-suited to this.
It would pull our fantastic designers away from milestone work and it would be
hard to get done in a week's time.
If you're at a loss for ideas or wonder if something is an appropriate first responder task, ask the rest of the team! Or poke through the [`tech-debt`](https://github.com/desktop/desktop/labels/tech-debt) label for some inspiration. If you're at a loss for ideas or wonder if something is an appropriate first
responder task, ask the rest of the team! Or poke through the
[`tech-debt`](https://github.com/desktop/desktop/labels/tech-debt) label for
some inspiration.

View file

@ -1,11 +1,11 @@
# Issue Triage # Issue Triage
> Triage (/ˈtriːɑːʒ/ or /triːˈɑːʒ/) is the process of determining the priority > Triage (/ˈtriːɑːʒ/ or /triːˈɑːʒ/) is the process of determining the priority
> of patients' treatments based on the severity of their condition. This > of patients' treatments based on the severity of their condition. This rations
> rations patient treatment efficiently when resources are insufficient for all > patient treatment efficiently when resources are insufficient for all to be
> to be treated immediately. > treated immediately.
> >
> *From Wikipedia* > _From Wikipedia_
The above describes medical triage but it is clear that it also applies to our The above describes medical triage but it is clear that it also applies to our
situation. Triage is a process of sifting through all the things that we could situation. Triage is a process of sifting through all the things that we could
@ -19,18 +19,18 @@ participation. In order to do this, we will have to be clear about what we need
from people so that we can deliver what they need. This also means that we will from people so that we can deliver what they need. This also means that we will
have to be very clear and decisive when we are not getting the information or have to be very clear and decisive when we are not getting the information or
cooperation we need so that we can move on. Just like in an emergency room, if cooperation we need so that we can move on. Just like in an emergency room, if
it is a choice between spending several hours to have a 10% chance of saving it is a choice between spending several hours to have a 10% chance of saving one
one person or spending several hours definitely saving multiple people, the person or spending several hours definitely saving multiple people, the choice
choice is clear. is clear.
## Goals ## Goals
* Communicate clearly and effectively * Communicate clearly and effectively
* What the maintainers will work on * What the maintainers will work on
* What pull requests will be reviewed for acceptance * What pull requests will be reviewed for acceptance
* What pull requests *will not* be reviewed for acceptance * What pull requests _will not_ be reviewed for acceptance
* Outline exactly what is expected for an issue to meet the "triage bar" so * Outline exactly what is expected for an issue to meet the "triage bar" so that
that issues that don't meet the bar can be closed issues that don't meet the bar can be closed
* Reduce the amount of time and back-and-forth needed to take an issue from * Reduce the amount of time and back-and-forth needed to take an issue from
being first-opened to `triaged` or closed being first-opened to `triaged` or closed
* Accept input from the community that helps us deliver meaningful results back * Accept input from the community that helps us deliver meaningful results back
@ -39,9 +39,9 @@ choice is clear.
## The Issues List Is Our Backlog ## The Issues List Is Our Backlog
The GitHub Desktop issues list is what the maintainers team uses to guide our The GitHub Desktop issues list is what the maintainers team uses to guide our
work. In order for our work to be focused and efficient, our issues list must work. In order for our work to be focused and efficient, our issues list must be
be clean and well-organized. Accepting input from the community is a clean and well-organized. Accepting input from the community is a significant
significant benefit *when it does not distract us from making things better*. benefit _when it does not distract us from making things better_.
* Untriaged issues are tasks that are being evaluated to determine if they meet * Untriaged issues are tasks that are being evaluated to determine if they meet
the triage bar the triage bar
@ -57,19 +57,19 @@ contain in the body of the issue:
* The build number associated with the given issue * The build number associated with the given issue
* The operating system and OS version number that the problem was reproduced on * The operating system and OS version number that the problem was reproduced on
* Specific steps to reproduce the problem or desired behavior * Specific steps to reproduce the problem or desired behavior
* If the steps to reproduce the problem do not reproduce it 100% of the time, * If the steps to reproduce the problem do not reproduce it 100% of the time, an
an estimate of how often it reproduces with the given steps and configuration estimate of how often it reproduces with the given steps and configuration
* **One** and only one issue * **One** and only one issue
* Any other information that is required to reproduce the problem (sample Git * Any other information that is required to reproduce the problem (sample Git
repository, specific OS configuration, etc) repository, specific OS configuration, etc)
### The Body of the Issue ### The Body of the Issue
You'll notice above that the body of the issue gets special mention. The body You'll notice above that the body of the issue gets special mention. The body of
of the issue is the description of the task to be done. A maintainer should the issue is the description of the task to be done. A maintainer should only
only have to read the body of the issue to understand what needs to happen. have to read the body of the issue to understand what needs to happen. They
They should not have to read the pages of comments to understand what they need should not have to read the pages of comments to understand what they need to do
to do in order to address the issue at hand. in order to address the issue at hand.
## Process ## Process
@ -81,7 +81,8 @@ issues from time to time that isn't and won't be covered here.
1. Person files a new issue 1. Person files a new issue
1. Maintainer checks to ensure they adequately filled out the template. If not, 1. Maintainer checks to ensure they adequately filled out the template. If not,
close with the [request to fill out the template](canned-messages/needs-template.md). close with the
[request to fill out the template](canned-messages/needs-template.md).
1. Label the issue as a `bug` if the issue is a regression or behaviour that 1. Label the issue as a `bug` if the issue is a regression or behaviour that
needs to be fixed. needs to be fixed.
1. If the issue has already been fixed, add a comment linking to the original 1. If the issue has already been fixed, add a comment linking to the original
@ -89,25 +90,26 @@ issues from time to time that isn't and won't be covered here.
1. If anything is unclear but the template is adequately filled out, post what 1. If anything is unclear but the template is adequately filled out, post what
questions you have and label with `more-information-needed` questions you have and label with `more-information-needed`
1. Maintainer attempts to reproduce the problem 1. Maintainer attempts to reproduce the problem
1. If the problem is not reproducible, label with `needs-reproduction` and 1. If the problem is not reproducible, label with `needs-reproduction` and
ask the author of the issue for [clarification on the repro steps](canned-messages/repro-steps.md) ask the author of the issue for
1. Label the issue as an `enhancement` if the issue mentions new behaviour [clarification on the repro steps](canned-messages/repro-steps.md)
or functionality that the app should have. 1. Label the issue as an `enhancement` if the issue mentions new behaviour or
functionality that the app should have.
# Labels # Labels
## More Information Needed ## More Information Needed
Periodically we should be doing a sweep of issues that are open and labeled Periodically we should be doing a sweep of issues that are open and labeled
`more-information-needed`. If the original poster has not responded within `more-information-needed`. If the original poster has not responded within two
two weeks after the last question by an official maintainer, close the issue weeks after the last question by an official maintainer, close the issue with
with [the no response message](canned-messages/no-response.md). [the no response message](canned-messages/no-response.md).
## Needs Reproduction ## Needs Reproduction
If a problem is consistently not reproducible, we **need** more information If a problem is consistently not reproducible, we **need** more information from
from the person reporting the problem. If it isn't a simple misunderstanding the person reporting the problem. If it isn't a simple misunderstanding about
about the steps to reproduce the problem, then we should label it the steps to reproduce the problem, then we should label it
`more-information-needed` as well and follow that process. `more-information-needed` as well and follow that process.
## Bugs ## Bugs
@ -115,9 +117,9 @@ about the steps to reproduce the problem, then we should label it
These are problems with the current app that are identified by users. These These are problems with the current app that are identified by users. These
should be reviewed to ensure they: should be reviewed to ensure they:
- specify the build associated with the issue * specify the build associated with the issue
- have instructions sufficient to reproduce the issue * have instructions sufficient to reproduce the issue
- have details about the impact and severity of the issue * have details about the impact and severity of the issue
We will use the `more-information-needed` and `reproduction-required` labels to We will use the `more-information-needed` and `reproduction-required` labels to
indicate when issues are incomplete. indicate when issues are incomplete.
@ -139,9 +141,9 @@ To ensure the quality of the application remains high over time, the core team
may need to work with the user proposing the change to clarify details before may need to work with the user proposing the change to clarify details before
work should proceed: work should proceed:
- user interface - appropriate use of styles, layout * user interface - appropriate use of styles, layout
- user experience - ensure things are consistent, discoverable * user experience - ensure things are consistent, discoverable
- quality - ensure the change does not adversely affect other features * quality - ensure the change does not adversely affect other features
e.g. GitHub Desktop should support worktrees as a first class feature. e.g. GitHub Desktop should support worktrees as a first class feature.
@ -153,11 +155,12 @@ by the community will be for things that are interesting but are also well
beyond the current plans of the team. beyond the current plans of the team.
We will apply the `future-proposal` label to these issues, so that they can be We will apply the `future-proposal` label to these issues, so that they can be
searched for when it comes time to plan for the future. However, to keep searched for when it comes time to plan for the future. However, to keep our
our issue tracker focused on tasks currently on the roadmap we will close these issue tracker focused on tasks currently on the roadmap we will close these
future proposals to avoid information overload. future proposals to avoid information overload.
You can view [the list](https://github.com/desktop/desktop/issues?q=is%3Aissue+label%3Afuture-proposal) You can view
[the list](https://github.com/desktop/desktop/issues?q=is%3Aissue+label%3Afuture-proposal)
of these `future-proposal` tasks, and continue to add your thoughts and feedback of these `future-proposal` tasks, and continue to add your thoughts and feedback
there. there.

View file

@ -1,7 +1,12 @@
# Release Planning # Release Planning
We plan work at two levels of granularity: first at the marketing release level (1.1, 1.2, etc.) and then at the milestone level. Marketing releases are made up of multiple milestones. Milestones should contain roughly a months worth of work. We plan work at two levels of granularity: first at the marketing release level
(1.1, 1.2, etc.) and then at the milestone level. Marketing releases are made up
of multiple milestones. Milestones should contain roughly a months worth of
work.
Well release updates as needed or when a milestone is completed. Well release updates as needed or when a milestone is completed.
Large features and user-visible changes are feature-flagged, to be unflagged in the next marketing release. Beta and dev builds will have all feature flags enabled. Large features and user-visible changes are feature-flagged, to be unflagged in
the next marketing release. Beta and dev builds will have all feature flags
enabled.

View file

@ -2,23 +2,34 @@
## Channels ## Channels
We have three channels to which we can release: `production`, `beta`, and `test`. We have three channels to which we can release: `production`, `beta`, and
`test`.
- `production` is the channel from which the general public downloads and receives updates. It should be stable and polished. * `production` is the channel from which the general public downloads and
receives updates. It should be stable and polished.
- `beta` is released more often than `production`. It may be buggy and unpolished. * `beta` is released more often than `production`. It may be buggy and
unpolished.
- `test` is unlike the other two. It does not receive updates. Each test release is locked in time. It's used entirely for providing test releases. * `test` is unlike the other two. It does not receive updates. Each test release
is locked in time. It's used entirely for providing test releases.
## The Process ## The Process
1. Ensure the release notes for `$version` in [`changelog.json`](../../changelog.json) are up-to-date. 1. Ensure the release notes for `$version` in
[`changelog.json`](../../changelog.json) are up-to-date.
1. Bump `version` in [`app/package.json`](../../app/package.json) to `$version`. 1. Bump `version` in [`app/package.json`](../../app/package.json) to `$version`.
1. Commit & push the changes. 1. Commit & push the changes.
1. Run `.release! desktop/YOUR_BRANCH to {production|beta|test}`. 1. Run `.release! desktop/YOUR_BRANCH to {production|beta|test}`.
* We're using `.release` with a bang so that we don't have to wait for any current CI on the branch to finish. This might feel a little wrong, but it's OK since making the release itself will also run CI.
1. If you're releasing a production update, release a beta update for the next version too, so that beta users are on the latest release. * We're using `.release` with a bang so that we don't have to wait for any
current CI on the branch to finish. This might feel a little wrong, but it's
OK since making the release itself will also run CI.
1. If you're releasing a production update, release a beta update for the next
version too, so that beta users are on the latest release.
## Error Reporting ## Error Reporting
If an error occurs during the release process, a needle will be reported to Central's [haystack](https://haystack.githubapp.com/central). If an error occurs during the release process, a needle will be reported to
Central's [haystack](https://haystack.githubapp.com/central).

View file

@ -4,8 +4,8 @@ This is the typical flow:
1. **Contributor** opens pull request. 1. **Contributor** opens pull request.
1. When it's ready for review, they comment on it saying so. 1. When it's ready for review, they comment on it saying so.
1. A member of the maintainer team will give it a quick look over and 1. A member of the maintainer team will give it a quick look over and add the
add the `ready-for-review` label. `ready-for-review` label.
1. Suddenly a wild **reviewer** appears! 1. Suddenly a wild **reviewer** appears!
1. **Reviewer** assigns the PR to themselves. 1. **Reviewer** assigns the PR to themselves.
1. **Reviewer** leaves line comments with suggestions or questions. 1. **Reviewer** leaves line comments with suggestions or questions.
@ -16,7 +16,7 @@ This is the typical flow:
comment on the PR with an emoji, meme, pokémon or words to that effect. comment on the PR with an emoji, meme, pokémon or words to that effect.
1. Goto 6 until both parties are happy with the PR. 1. Goto 6 until both parties are happy with the PR.
1. The **reviewer** hits the big green merge button and deletes the branch (if 1. The **reviewer** hits the big green merge button and deletes the branch (if
applicable). applicable).
The rest of this document goes into more details around this flow. The rest of this document goes into more details around this flow.
@ -40,17 +40,18 @@ understand quickly what's changed.
### Keep The Commit History Tidy ### Keep The Commit History Tidy
We're not that fussy about the history, but to make reviewing easier here's We're not that fussy about the history, but to make reviewing easier here's some
some general tips: general tips:
- make small, meaningful and logical commits - these make the review process easier * make small, meaningful and logical commits - these make the review process
- [write good commit messages](https://chris.beams.io/posts/git-commit/) - easier
these help the reviewer to understand the changes * [write good commit messages](https://chris.beams.io/posts/git-commit/) - these
- keep up to date with `master` - not only does this address potential merge help the reviewer to understand the changes
conflicts, it ensures you're integrating with the latest code * keep up to date with `master` - not only does this address potential merge
conflicts, it ensures you're integrating with the latest code
When merging, we prefer you merge `master` into your branch, but for small When merging, we prefer you merge `master` into your branch, but for small PRs a
PRs a rebase is fine. rebase is fine.
### At Least One Assignee ### At Least One Assignee
@ -64,11 +65,11 @@ reviewer.
We're using GitHub's review tools to co-ordinate feedback, and we like to be We're using GitHub's review tools to co-ordinate feedback, and we like to be
methodical with our reviews, so you'll probably end up with one of two results: methodical with our reviews, so you'll probably end up with one of two results:
- **Approved**: nothing else to do; the reviewer merges * **Approved**: nothing else to do; the reviewer merges
- **Request Changes**: there are things to address; reviewer provides details * **Request Changes**: there are things to address; reviewer provides details
Reviews can take a few iterations, especially for large contributions. Don't Reviews can take a few iterations, especially for large contributions. Don't be
be disheartened if you feel it takes time - we just want to ensure each disheartened if you feel it takes time - we just want to ensure each
contribution is high-quality and that any outstanding questions are resolved, contribution is high-quality and that any outstanding questions are resolved,
captured or documented for posterity. captured or documented for posterity.
@ -90,4 +91,3 @@ requests.
While everyone has their own domain expertise around the codebase, we encourage While everyone has their own domain expertise around the codebase, we encourage
people to share the load of reviews and reviewing areas of the codebase that people to share the load of reviews and reviewing areas of the codebase that
aren't as familiar. This spreads knowledge across the team aren't as familiar. This spreads knowledge across the team

View file

@ -1,63 +1,75 @@
# Roadmap # Roadmap
The following are our marketing releases as planned to date. They contain the broad features we're considering. The further away a release is, the less defined it is. Releases are subject to change at any time. The following are our marketing releases as planned to date. They contain the
broad features we're considering. The further away a release is, the less
defined it is. Releases are subject to change at any time.
## 1.1 ## 1.1
- Relationship to _X_ * Relationship to _X_
- Show how the current branch relates to the target branch
- The target is the default branch or the upstream's default branch
- _Probably_ let the user switch the target branch
- Conflict resolution lite * Show how the current branch relates to the target branch
- Differentiate conflicted files from other changed files * The target is the default branch or the upstream's default branch
- Let me choose my mergetool * _Probably_ let the user switch the target branch
- Let me open my mergetool
- Pull request list * Conflict resolution lite
- _Probably_ a tab in the Branches foldout
- Group my pull requests vs. others
- Pull request CI status * Differentiate conflicted files from other changed files
- Show PRs CI status in the above pull request list * Let me choose my mergetool
* Let me open my mergetool
- Auto-config upstreams on fork * Pull request list
- Create an `upstream` remote for forks
- Fetch periodically * _Probably_ a tab in the Branches foldout
* Group my pull requests vs. others
* Pull request CI status
* Show PRs CI status in the above pull request list
* Auto-config upstreams on fork
* Create an `upstream` remote for forks
* Fetch periodically
## 1.2 ## 1.2
- Full conflict resolution * Full conflict resolution
- Lots TBD
- Pick ours/theirs/both
- Edit inline
- Abort merge
- How did I get here?
- Fork if needed * Lots TBD
- Offer to fork on clone, or push, or ? * Pick ours/theirs/both
* Edit inline
* Abort merge
* How did I get here?
- Protected branches and default branch protection * Fork if needed
- Don't let me commit to branches I shouldn't commit to
- Guide me to creating my own branches
- CI status notifications lite * Offer to fork on clone, or push, or ?
- Only on my PRs
- Use OS notifications * Protected branches and default branch protection
- Notifications link to the PR on dotcom
* Don't let me commit to branches I shouldn't commit to
* Guide me to creating my own branches
* CI status notifications lite
* Only on my PRs
* Use OS notifications
* Notifications link to the PR on dotcom
## 1.3 ## 1.3
- Keep environment up-to-date * Keep environment up-to-date
- Do I need to run `npm install`? `bundle install`?
- Is it pluggable?
- Linting * Do I need to run `npm install`? `bundle install`?
- TBD * Is it pluggable?
- Save face * Linting
- Keep me from making embarrassing mistakes
- Don't let me commit a file with conflict markers
- Repository list info * TBD
- Does a repository need my attention?
* Save face
* Keep me from making embarrassing mistakes
* Don't let me commit a file with conflict markers
* Repository list info
* Does a repository need my attention?

View file

@ -1,366 +1,491 @@
### Download Desktop ### Download Desktop
- [ ] User can download latest (Mac & Windows) Desktop from https://desktop.github.com/
- [ ] Mac: https://central.github.com/deployments/desktop/desktop/latest/darwin * [ ] User can download latest (Mac & Windows) Desktop from
- [ ] Homebrew package manager: $ brew cask install github-desktop https://desktop.github.com/
- [ ] Windows: https://central.github.com/deployments/desktop/desktop/latest/win32 * [ ] Mac:
- [ ] Chocolatey package manager: c:\> choco install github-desktop https://central.github.com/deployments/desktop/desktop/latest/darwin
- [ ] 64-bit and up * [ ] Homebrew package manager: $ brew cask install github-desktop
- [ ] Data is retained if you download and open a fresh copy * [ ] Windows:
- [ ] Release notes page is up-to-date https://central.github.com/deployments/desktop/desktop/latest/win32
- [ ] Help page is accessible * [ ] Chocolatey package manager: c:\> choco install github-desktop
- [ ] 'Please update' notifcation shown in Classic apps * [ ] 64-bit and up
* [ ] Data is retained if you download and open a fresh copy
* [ ] Release notes page is up-to-date
* [ ] Help page is accessible
* [ ] 'Please update' notifcation shown in Classic apps
### Welcome Flow ### Welcome Flow
- [ ] Create your account (/join?source=github-desktop)
- [ ] User is not automatically logged into Desktop post account creation
- [ ] `Sign in to Github.com` link
- [ ] `Sign in` successful if valid username/email and password
- [ ] If 2FA activated, user sent auth code to enter (test SMS and authenticator app)
- [ ] User can reissue auth code with `Resend SMS` link
- [ ] Sign in successful with active 2FA code, user goes to Configure Git
- [ ] User sees Repository landing page if sign in successful
- [ ] Error message if code is wrong or inactive
- [ ] Error message if incorrect username/email or password
- [ ] Forgot link (/password_reset)
- [ ] `Cancel` returns to initial Welcome Flow
- [ ] `Sign in using your browser` opens default browser
- [ ] Browser login, "authorize" GitHub Desktop, “accept” link
- [ ] If successful, Desktop shown in `/settings/applications` in user profile
- [ ] `Sign in to Enterprise` link (works with v2.8 and up)
- [ ] `Continue` successful if server address is valid, else error message
- [ ] `Sign in using your browser` opens default browser
- [ ] Browser login, [insert custom security measure], Authorize GitHub Desktop, “accept” link
- [ ] User goes to Configure Git if successful
- [ ] `Cancel` returns to initial Welcome Flow
- [ ] User served generic message if not authorized to access Enterprise server
- [ ] Skip "username+password" step
- [ ] Configure Git
- [ ] Name and email pulled from global `.gitconfig` file, if configured
- [ ] If recognized, your avatar is present in example commit; gravatars not recognized
- [ ] `Continue` okay if fields populated or blank
- [ ] Valid login credentials from dotcom or Enterprise carried through
- [ ] User sees Repository landing page if sign in successful
- [ ] Usage Data
- [ ] Checked by default; user can uncheck. (Should not be checked if user on free plan only.)
- [ ] Clicking `Finish`, and user is signed in successfully to Desktop
- [ ] `Cancel` returns to initial Configure Git page
### Repositories landing page; default no repositories * [ ] Create your account (/join?source=github-desktop)
- [ ] Create New Repository (Mac: ⌘N; Windows: Ctrl+N) * [ ] User is not automatically logged into Desktop post account creation
- [ ] Modal opens with name, path (choose option), readme (unchecked), git ignore, license. Name and path mandatory. * [ ] `Sign in to Github.com` link
- [ ] If `Add this repository` warning message appears, clicking it adds to Repo list * [ ] `Sign in` successful if valid username/email and password
- [ ] If repository name is over 100 characterers, warning message is surfaced in modal * [ ] If 2FA activated, user sent auth code to enter (test SMS and
- [ ] If repository contains URL-hostile characters, show error message authenticator app)
- [ ] `Create Repository` button adds new repo, which is added to Repo list * [ ] User can reissue auth code with `Resend SMS` link
- [ ] `Cancel` button does not save any changes made; modal closed * [ ] Sign in successful with active 2FA code, user goes to Configure Git
- [ ] User cannot create a new repo inside a locked local directory * [ ] User sees Repository landing page if sign in successful
- [ ] Clone a Repository (Mac: ⇧⌘O; Windows: Ctrl+Shift+O) * [ ] Error message if code is wrong or inactive
- [ ] Enter valid URL or username/repo/gist, else error message * [ ] Error message if incorrect username/email or password
- [ ] If authentication error for Github.com, modal with username/password surfaced; `Cancel` or `Save and Retry` buttons * [ ] Forgot link (/password_reset)
- [ ] If successful, repo is cloned * [ ] `Cancel` returns to initial Welcome Flow
- [ ] Modal surfaces again if unsuccessful * [ ] `Sign in using your browser` opens default browser
- [ ] If authentication error for Enterprise, user redirected to Preferences * [ ] Browser login, "authorize" GitHub Desktop, “accept” link
- [ ] Valid path can be entered or selected * [ ] If successful, Desktop shown in `/settings/applications` in user
- [ ] Local path is prepopulated; if not unique then error surfaced profile
- [ ] All repos from both GitHub.com and Enterprise are populated -- your repos are listed first, followed by org(s) * [ ] `Sign in to Enterprise` link (works with v2.8 and up)
- [ ] User must be logged in to view list; else `Sign In` button present * [ ] `Continue` successful if server address is valid, else error message
- [ ] Results are filterable, and can be selected for cloning * [ ] `Sign in using your browser` opens default browser
- [ ] `Clone` creates repo at selected path * [ ] Browser login, [insert custom security measure], Authorize GitHub
- [ ] Repo added to Repo list Desktop, “accept” link
- [ ] `Cancel` closes modal, no repo cloned * [ ] User goes to Configure Git if successful
- [ ] Add a Local Repository (Mac: ⌘O; Windows: Ctrl+O) * [ ] `Cancel` returns to initial Welcome Flow
- [ ] Valid path can be entered or selected * [ ] User served generic message if not authorized to access Enterprise
- [ ] `Add repository` activated if repo path exists server
- [ ] Repo added to Repo list * [ ] Skip "username+password" step
- [ ] If directory path not valid, 'Create a new repo' error message is present * [ ] Configure Git
- [ ] `Cancel` closes modal, no repo added * [ ] Name and email pulled from global `.gitconfig` file, if configured
- [ ] Large repos (> 100MB) trigger Initialize Git LFS modal * [ ] If recognized, your avatar is present in example commit; gravatars not
- [ ] Link takes user to (https://git-lfs.github.com/) recognized
- [ ] Local path to repo is displayed * [ ] `Continue` okay if fields populated or blank
- [ ] User can click `Cancel` or `Initialize Git LFS` * [ ] Valid login credentials from dotcom or Enterprise carried through
- [ ] Drag and drop repository * [ ] User sees Repository landing page if sign in successful
- [ ] User can drag existing local repository into Desktop * [ ] Usage Data
- [ ] Successful attempt adds repo to Repo list; else error message * [ ] Checked by default; user can uncheck. (Should not be checked if user on
free plan only.)
* [ ] Clicking `Finish`, and user is signed in successfully to Desktop
* [ ] `Cancel` returns to initial Configure Git page
### Repositories landing page; default no repositories
* [ ] Create New Repository (Mac: ⌘N; Windows: Ctrl+N)
* [ ] Modal opens with name, path (choose option), readme (unchecked), git
ignore, license. Name and path mandatory.
* [ ] If `Add this repository` warning message appears, clicking it adds to
Repo list
* [ ] If repository name is over 100 characterers, warning message is
surfaced in modal
* [ ] If repository contains URL-hostile characters, show error message
* [ ] `Create Repository` button adds new repo, which is added to Repo list
* [ ] `Cancel` button does not save any changes made; modal closed
* [ ] User cannot create a new repo inside a locked local directory
* [ ] Clone a Repository (Mac: ⇧⌘O; Windows: Ctrl+Shift+O)
* [ ] Enter valid URL or username/repo/gist, else error message
* [ ] If authentication error for Github.com, modal with username/password
surfaced; `Cancel` or `Save and Retry` buttons
* [ ] If successful, repo is cloned
* [ ] Modal surfaces again if unsuccessful
* [ ] If authentication error for Enterprise, user redirected to Preferences
* [ ] Valid path can be entered or selected
* [ ] Local path is prepopulated; if not unique then error surfaced
* [ ] All repos from both GitHub.com and Enterprise are populated -- your
repos are listed first, followed by org(s)
* [ ] User must be logged in to view list; else `Sign In` button present
* [ ] Results are filterable, and can be selected for cloning
* [ ] `Clone` creates repo at selected path
* [ ] Repo added to Repo list
* [ ] `Cancel` closes modal, no repo cloned
* [ ] Add a Local Repository (Mac: ⌘O; Windows: Ctrl+O)
* [ ] Valid path can be entered or selected
* [ ] `Add repository` activated if repo path exists
* [ ] Repo added to Repo list
* [ ] If directory path not valid, 'Create a new repo' error message is
present
* [ ] `Cancel` closes modal, no repo added
* [ ] Large repos (> 100MB) trigger Initialize Git LFS modal
* [ ] Link takes user to (https://git-lfs.github.com/)
* [ ] Local path to repo is displayed
* [ ] User can click `Cancel` or `Initialize Git LFS`
* [ ] Drag and drop repository
* [ ] User can drag existing local repository into Desktop
* [ ] Successful attempt adds repo to Repo list; else error message
### Publishing a repository ### Publishing a repository
- [ ] Publish Repository modal present if repo is unpublished and user clicks `Publish repository` button
- [ ] GitHub tab is default; Enterprise tab is also present * [ ] Publish Repository modal present if repo is unpublished and user clicks
- [ ] User must be signed in to publish, else `Sign In` button present on tab `Publish repository` button
- [ ] Modal fields are Name, Description (optional), `Keep this code private` checkbox, Organization list (alpha order, tab-specific), `Cancel` button, `Publish Repository` button * [ ] GitHub tab is default; Enterprise tab is also present
- [ ] Clicking `Publish Repository` button pushes repo to GitHub.com or Enterprise; `Cancel` button closes modal * [ ] User must be signed in to publish, else `Sign In` button present on
- [ ] Repository is present on GitHub.com or Enterprise if published tab
- [ ] 'Visibility can't be private error' shown, if user's plan is not sufficient * [ ] Modal fields are Name, Description (optional), `Keep this code private`
- [ ] A `.gitattributes` file is added to the repository as part of the initial commit checkbox, Organization list (alpha order, tab-specific), `Cancel`
button, `Publish Repository` button
* [ ] Clicking `Publish Repository` button pushes repo to GitHub.com or
Enterprise; `Cancel` button closes modal
* [ ] Repository is present on GitHub.com or Enterprise if published
* [ ] 'Visibility can't be private error' shown, if user's plan is not
sufficient
* [ ] A `.gitattributes` file is added to the repository as part of the
initial commit
### Application ### Application
- [ ] Minimize, Maximize, Close buttons work in top nav
- [ ] If user zooms in and quits app, settings should be retained when reopened * [ ] Minimize, Maximize, Close buttons work in top nav
- [ ] Double-clicking local desktop icon opens the application (Mac only) * [ ] If user zooms in and quits app, settings should be retained when
- [ ] Double clicking top nav bar toggles full-screen / last used screen-size (Mac only); Exit by (Mac: ^⌘f11; Windows: Alt) reopened
- [ ] Clicking Desktop icon in dock/taskbar opens the application * [ ] Double-clicking local desktop icon opens the application (Mac only)
- [ ] Changing desktop icon name while app is open results in package error; closed app name change is successful * [ ] Double clicking top nav bar toggles full-screen / last used screen-size
(Mac only); Exit by (Mac: ^⌘f11; Windows: Alt)
* [ ] Clicking Desktop icon in dock/taskbar opens the application
* [ ] Changing desktop icon name while app is open results in package error;
closed app name change is successful
### GitHub Desktop menu top-level ### GitHub Desktop menu top-level
- [ ] About GitHub Desktop
- [ ] Current version shown * [ ] About GitHub Desktop
- [ ] Links to release notes (dotcom), terms (modal), licenses (modal) * [ ] Current version shown
- [ ] Update banner shows `whats new` link and `retart now` link * [ ] Links to release notes (dotcom), terms (modal), licenses (modal)
- [ ] Update modal shows enhancements / bug fixes in latest build with `Install button`; user can X the banner * [ ] Update banner shows `whats new` link and `retart now` link
- [ ] Clicking the version number copies to clipboard * [ ] Update modal shows enhancements / bug fixes in latest build with
- [ ] Edge case: If build is "old", error message displays warning user to "... manually check for updates". `Install button`; user can X the banner
- [ ] Clicking `Check for updates` button produces "read-only volume" error message, with link for help * [ ] Clicking the version number copies to clipboard
- [ ] Clicking `Check for updates` button timestamps last attempt * [ ] Edge case: If build is "old", error message displays warning user to
- [ ] If update available, `Install Update` button will quit app and install update "... manually check for updates".
- [ ] If update available, download banner is present in main window with `restart` and `whats new` links * [ ] Clicking `Check for updates` button produces "read-only volume" error
- [ ] If checking for update or download latest update, the `Check for updates` button is disabled message, with link for help
- [ ] Restarting the app automatically checks for updates * [ ] Clicking `Check for updates` button timestamps last attempt
- [ ] `Close` button closes modal * [ ] If update available, `Install Update` button will quit app and install
- [ ] Preferences/Options (Mac/Windows: ⌘,) update
- [ ] Accounts * [ ] If update available, download banner is present in main window with
- [ ] GitHub.com name, handle, avatar, `sign out` button, if user signed in `restart` and `whats new` links
- [ ] Enterprise handle, avatar, `sign out` button, if user signed in * [ ] If checking for update or download latest update, the
- [ ] User can sign out of either account `Check for updates` button is disabled
- [ ] User can sign-in to both Enterprise and GitHub.com at same time * [ ] Restarting the app automatically checks for updates
- [ ] Git * [ ] `Close` button closes modal
- [ ] Username and email are displayed if `.gitconfig` configured for Welcome flow * [ ] Preferences/Options (Mac/Windows: ⌘,)
- [ ] `Save` button saves any changes made * [ ] Accounts
- [ ] `Cancel` button does not save any changes made; modal closed * [ ] GitHub.com name, handle, avatar, `sign out` button, if user signed in
- [ ] Advanced * [ ] Enterprise handle, avatar, `sign out` button, if user signed in
- [ ] External Editor options shown in dropdown; else show "Install Atom?" link * [ ] User can sign out of either account
- [ ] Shell options shown in dropdown * [ ] User can sign-in to both Enterprise and GitHub.com at same time
- [ ] Shared usage data option; selection carried through from Welcome flow * [ ] Git
- [ ] `anonymous usage data` link opens https://desktop.github.com/usage-data/ * [ ] Username and email are displayed if `.gitconfig` configured for
- [ ] Check `stats-opt-out` value in Dev Tools > Application > Local storage > file:// Welcome flow
- [ ] Confirmation dialogue for removing repositories is checked by default; user can toggle * [ ] `Save` button saves any changes made
- [ ] Check `ConfirmDiscardChanges` value in Dev Tools > Application > Local storage > file:// * [ ] `Cancel` button does not save any changes made; modal closed
- [ ] Confirmation dialogue for disgarding files is checked by default; user can toggle * [ ] Advanced
- [ ] Check `ConfirmRepoRemoval` value in Dev Tools > Application > Local storage > file:// * [ ] External Editor options shown in dropdown; else show "Install Atom?"
- [ ] `Save` button saves any changes made link
- [ ] `Cancel` button does not save any changes made; modal closed * [ ] Shell options shown in dropdown
- [ ] Install command line tool installs tool at `/usr/local/bin/github` (Mac only as Windows done automagically, Helper may require password, else error message) * [ ] Shared usage data option; selection carried through from Welcome flow
- [ ] If already installed, user sees: "The command line tool has been installed at /usr/local/bin/github" * [ ] `anonymous usage data` link opens
- [ ] Clicking `OK` closes modal https://desktop.github.com/usage-data/
- [ ] Quit/Exit Desktop (Mac: ⌘Q) * [ ] Check `stats-opt-out` value in Dev Tools > Application > Local
- [ ] Quitting/Exiting and reopening Desktop returns you to last visited repo storage > file://
* [ ] Confirmation dialogue for removing repositories is checked by default;
user can toggle
* [ ] Check `ConfirmDiscardChanges` value in Dev Tools > Application >
Local storage > file://
* [ ] Confirmation dialogue for disgarding files is checked by default; user
can toggle
* [ ] Check `ConfirmRepoRemoval` value in Dev Tools > Application > Local
storage > file://
* [ ] `Save` button saves any changes made
* [ ] `Cancel` button does not save any changes made; modal closed
* [ ] Install command line tool installs tool at `/usr/local/bin/github` (Mac
only as Windows done automagically, Helper may require password, else
error message)
* [ ] If already installed, user sees: "The command line tool has been
installed at /usr/local/bin/github"
* [ ] Clicking `OK` closes modal
* [ ] Quit/Exit Desktop (Mac: ⌘Q)
* [ ] Quitting/Exiting and reopening Desktop returns you to last visited repo
### File top-level menu ### File top-level menu
- [ ] Create New Repository (Mac: ⌘N; Windows: Ctrl+N)
- [ ] Clone a Repository (Mac: ⇧⌘O; Windows: Ctrl+Shift+O) * [ ] Create New Repository (Mac: ⌘N; Windows: Ctrl+N)
- [ ] Add a Local Repository (Mac: ⌘O; Windows: Ctrl+O) * [ ] Clone a Repository (Mac: ⇧⌘O; Windows: Ctrl+Shift+O)
- [ ] Options... (Windows only: Ctrl+,) * [ ] Add a Local Repository (Mac: ⌘O; Windows: Ctrl+O)
- [ ] Exit (Windows only; quits the app) * [ ] Options... (Windows only: Ctrl+,)
* [ ] Exit (Windows only; quits the app)
### Edit top-level menu ### Edit top-level menu
- [ ] Undo (Mac: ⌘Z; Windows: Ctrl+Z)
- [ ] Redo (Mac: ⇧⌘Z; Windows: Ctrl+Y) * [ ] Undo (Mac: ⌘Z; Windows: Ctrl+Z)
- [ ] Cut (Mac: ⌘X; Windows: Ctrl+X) * [ ] Redo (Mac: ⇧⌘Z; Windows: Ctrl+Y)
- [ ] Copy (Mac: ⌘C; Windows: Ctrl+C) * [ ] Cut (Mac: ⌘X; Windows: Ctrl+X)
- [ ] Paste (Mac: ⌘V; Windows: Ctrl+V) * [ ] Copy (Mac: ⌘C; Windows: Ctrl+C)
- [ ] Select all (Mac: ⌘A; Windows: Ctrl+A) * [ ] Paste (Mac: ⌘V; Windows: Ctrl+V)
* [ ] Select all (Mac: ⌘A; Windows: Ctrl+A)
### View top-level menu ### View top-level menu
- [ ] Show Changes (Mac: ⌘1; Windows: Ctrl+1)
- [ ] Show History (Mac: ⌘2; Windows: Ctrl+2) * [ ] Show Changes (Mac: ⌘1; Windows: Ctrl+1)
- [ ] Show Repositories List (Mac: ⌘T; Windows: Ctrl+T) * [ ] Show History (Mac: ⌘2; Windows: Ctrl+2)
- [ ] Show Branches List (Mac: ⌘B; Windows: Ctrl+B) * [ ] Show Repositories List (Mac: ⌘T; Windows: Ctrl+T)
- [ ] Enter Full Zoom (Mac: ^⌘F; Windows: F11) * [ ] Show Branches List (Mac: ⌘B; Windows: Ctrl+B)
- [ ] Reset Zoom (Mac: ⌘0; Windows: Ctrl+0) * [ ] Enter Full Zoom (Mac: ^⌘F; Windows: F11)
- [ ] Zoom In (Mac: ⌘=; Windows: Ctrl+=) * [ ] Reset Zoom (Mac: ⌘0; Windows: Ctrl+0)
- [ ] Zoom Out (Mac: ⌘-; Windows: Ctrl+-) * [ ] Zoom In (Mac: ⌘=; Windows: Ctrl+=)
- [ ] Toggle Developer Tools (Mac: ⌥⌘I; Windows: Ctrl+Shift+I) * [ ] Zoom Out (Mac: ⌘-; Windows: Ctrl+-)
* [ ] Toggle Developer Tools (Mac: ⌥⌘I; Windows: Ctrl+Shift+I)
### Repository top-level menu. (Only enabled if one repo present) ### Repository top-level menu. (Only enabled if one repo present)
- [ ] Push (Mac: ⌘P; Windows: Ctrl+P)
- [ ] Commits from repo pushed to .com; error message shown if conflicts * [ ] Push (Mac: ⌘P; Windows: Ctrl+P)
- [ ] Pull (Mac: ⇧⌘P; Windows: Ctrl+Shirt+P) * [ ] Commits from repo pushed to .com; error message shown if conflicts
- [ ] Commits from repo pulled from .com; error message shown if conflicts * [ ] Pull (Mac: ⇧⌘P; Windows: Ctrl+Shirt+P)
- [ ] Remove * [ ] Commits from repo pulled from .com; error message shown if conflicts
- [ ] Repo is removed from Repo List; confirmation dialgue shown if Preferences option enabled * [ ] Remove
- [ ] View on GitHub (Mac: ⌥⌘G; Windows: Ctrl+Alt+G) * [ ] Repo is removed from Repo List; confirmation dialgue shown if
- [ ] Repo on .com is opened; must be logged in if private repo or Enterprise Preferences option enabled
- [ ] Open in Terminal/Command prompt * [ ] View on GitHub (Mac: ⌥⌘G; Windows: Ctrl+Alt+G)
- [ ] Local repo is opened * [ ] Repo on .com is opened; must be logged in if private repo or Enterprise
- [ ] If git not installed, modal asks to Open with Git or Install Git * [ ] Open in Terminal/Command prompt
- [ ] Show in Finder/Explorer (Mac: ⇧⌘F; Windows: Ctrl+Shift+F) * [ ] Local repo is opened
- [ ] Local repo is opened * [ ] If git not installed, modal asks to Open with Git or Install Git
- [ ] Open in External Editor (Mac: ⇧⌘A; Windows: Ctrl+Shift+A); see External Editor option in prefs * [ ] Show in Finder/Explorer (Mac: ⇧⌘F; Windows: Ctrl+Shift+F)
- [ ] Secondary modal appears if no Editors set; option to Download Atom * [ ] Local repo is opened
- [ ] Repository settings * [ ] Open in External Editor (Mac: ⇧⌘A; Windows: Ctrl+Shift+A); see External
- [ ] Remote path can be edited; origin already set. Cannot be empty string, else error message. Editor option in prefs
- [ ] `Saved` button saves last entry * [ ] Secondary modal appears if no Editors set; option to Download Atom
- [ ] `Cancel` button closes modal * [ ] Repository settings
- [ ] Ignored Files * [ ] Remote path can be edited; origin already set. Cannot be empty string,
- [ ] `.gitignore` file contents are shown and can be edited else error message.
- [ ] `Saved` button saves last entry; changes create a new commit * [ ] `Saved` button saves last entry
- [ ] `Cancel` button closes modal * [ ] `Cancel` button closes modal
* [ ] Ignored Files
* [ ] `.gitignore` file contents are shown and can be edited
* [ ] `Saved` button saves last entry; changes create a new commit
* [ ] `Cancel` button closes modal
### Branch top-level menu ### Branch top-level menu
- [ ] New Branch (Mac: ⇧⌘N; Windows: Ctrl+Shift+N)
- [ ] Clicking `Create Branch` makes new branch based on the entered name, if not a duplicate * [ ] New Branch (Mac: ⇧⌘N; Windows: Ctrl+Shift+N)
- [ ] Master branch is mentioned in the list; current branch shown first * [ ] Clicking `Create Branch` makes new branch based on the entered name, if
- [ ] `Cancel` button closes modal not a duplicate
- [ ] Rename (cannot be master) * [ ] Master branch is mentioned in the list; current branch shown first
- [ ] `Rename` button changes branch name if field updated * [ ] `Cancel` button closes modal
- [ ] Same branch on GitHub.com is not renamed * [ ] Rename (cannot be master)
- [ ] `Cancel` button closes modal * [ ] `Rename` button changes branch name if field updated
- [ ] Protected branches cannot be renamed * [ ] Same branch on GitHub.com is not renamed
- [ ] Delete (cannot be master) * [ ] `Cancel` button closes modal
- [ ] Option to delete branch on the remote; default is unchecked * [ ] Protected branches cannot be renamed
- [ ] `Delete` button deletes branch name (and remote too if option checked) * [ ] Delete (cannot be master)
- [ ] `Cancel` button closes modal * [ ] Option to delete branch on the remote; default is unchecked
- [ ] Protected branches cannot be deleted * [ ] `Delete` button deletes branch name (and remote too if option checked)
- [ ] Update from Default Branch (cannot be master) * [ ] `Cancel` button closes modal
- [ ] Merge into Current Branch * [ ] Protected branches cannot be deleted
- [ ] Use can filter existing branches * [ ] Update from Default Branch (cannot be master)
- [ ] User can select branch, other than current * [ ] Merge into Current Branch
- [ ] `Merge` button only activated if something to merge * [ ] Use can filter existing branches
- [ ] `Cancel` button closes modal * [ ] User can select branch, other than current
- [ ] Compare on GitHub (Mac: ⇧⌘C; Windows: Ctrl+Shift+C) (if repo already published on `github.com`) * [ ] `Merge` button only activated if something to merge
- [ ] Create Pull request (Mac: ⌘R; Windows: Ctrl+R) opens Pull Request on `github.com` * [ ] `Cancel` button closes modal
- [ ] If branch unpublished, dialogue asks to publish the branch * [ ] Compare on GitHub (Mac: ⇧⌘C; Windows: Ctrl+Shift+C) (if repo already
- [ ] `Push Local Changes` modal surfaces with option to `Create Without Pushing` and `Push Commits`;(trigger: `Create Pull Request` after commit on branch before pushing) published on `github.com`)
* [ ] Create Pull request (Mac: ⌘R; Windows: Ctrl+R) opens Pull Request on
`github.com`
* [ ] If branch unpublished, dialogue asks to publish the branch
* [ ] `Push Local Changes` modal surfaces with option to
`Create Without Pushing` and `Push Commits`;(trigger:
`Create Pull Request` after commit on branch before pushing)
### Window top-level menu (Mac only) ### Window top-level menu (Mac only)
- [ ] Minimize, Zoom (maximize app size), Close, Bring All to Front, GitHub Desktop
* [ ] Minimize, Zoom (maximize app size), Close, Bring All to Front, GitHub
Desktop
### Help top-level menu ### Help top-level menu
- [ ] `Report Issue` opens issue template in Desktop repo on `github.com`
- [ ] `Contact GitHub Support` opens `https://github.com/contact` page with user and build prepopulated * [ ] `Report Issue` opens issue template in Desktop repo on `github.com`
- [ ] `Show User Guides` opens Desktop help page on `github.com` * [ ] `Contact GitHub Support` opens `https://github.com/contact` page with user
- [ ] `Show Logs in Finder/Explorer` opens Finder/Explorer logs in local directory and build prepopulated
- [ ] Mac: `ls ~/Library/Application\ Support/GitHub\ Desktop/Logs/*.log` * [ ] `Show User Guides` opens Desktop help page on `github.com`
- [ ] Windows: `%LOCALAPPDATA%\\Desktop\\*.desktop.production.log` * [ ] `Show Logs in Finder/Explorer` opens Finder/Explorer logs in local
- [ ] About GitHub Desktop (Windows only) directory
* [ ] Mac: `ls ~/Library/Application\ Support/GitHub\ Desktop/Logs/*.log`
* [ ] Windows: `%LOCALAPPDATA%\\Desktop\\*.desktop.production.log`
* [ ] About GitHub Desktop (Windows only)
### Repositories list ### Repositories list
- [ ] Current repo is always shown in top slot with respective icon; if repo exists
- [ ] Opening list shows all repos in categorized format with a working filter * [ ] Current repo is always shown in top slot with respective icon; if repo
- [ ] `ESC` clears the filter exists
- [ ] All repos (private, enterprise, local, public, forked, other) have proper icon and found in the proper category (GitHub.com/Enterprise/Other) * [ ] Opening list shows all repos in categorized format with a working filter
- [ ] Hover shows username/repo, url, and/or local path in tooltip * [ ] `ESC` clears the filter
- [ ] User must have paid account for private repos * [ ] All repos (private, enterprise, local, public, forked, other) have
- [ ] Repo icon is updated if admin changes status (public vs private) proper icon and found in the proper category
- [ ] Repositories cloned from non-github servers should always be in the Other group, and have the 'computer' icon. (GitHub.com/Enterprise/Other)
- [ ] Selecting a repo updates Changes/History/Diff areas * [ ] Hover shows username/repo, url, and/or local path in tooltip
- [ ] If no Changes, Diff area shows `Open this repository` link to Finder/Explorer on local * [ ] User must have paid account for private repos
- [ ] `Right-click` on any repo shows `Open in Terminal`, `Open in Finder/Explorer`, `Open in External Editor`, and `Remove` options * [ ] Repo icon is updated if admin changes status (public vs private)
- [ ] Repos which have been removed locally (and trash emptied) have 'cannot find repository' warning * [ ] Repositories cloned from non-github servers should always be in the Other
- [ ] Relaunching the app when it displays a missing repository preserves the repo's name and last seen path group, and have the 'computer' icon.
- [ ] Remove a repo which can not be found (deleted locally & trash emptied) * [ ] Selecting a repo updates Changes/History/Diff areas
- [ ] Repos which are cloning display a progress bar * [ ] If no Changes, Diff area shows `Open this repository` link to
Finder/Explorer on local
* [ ] `Right-click` on any repo shows `Open in Terminal`,
`Open in Finder/Explorer`, `Open in External Editor`, and `Remove` options
* [ ] Repos which have been removed locally (and trash emptied) have 'cannot
find repository' warning
* [ ] Relaunching the app when it displays a missing repository preserves the
repo's name and last seen path
* [ ] Remove a repo which can not be found (deleted locally & trash emptied)
* [ ] Repos which are cloning display a progress bar
### Changes tab ### Changes tab
- [ ] Changes tab shows `•` icon if files are waiting to be committed
- [ ] Number of changed files is always present; it can be 0 * [ ] Changes tab shows `•` icon if files are waiting to be committed
- [ ] Any changed files appear in the list, with respective +/•/- sign; with arrow keys enabled * [ ] Number of changed files is always present; it can be 0
- [ ] Merge-conflicted files showin with hazard icon; cannot be committed until fixed * [ ] Any changed files appear in the list, with respective +/•/- sign; with
- [ ] User can check none, or check one or more files to commit; list is scrollable arrow keys enabled
- [ ] User can select one or more lines to commit; diff is scrollable * [ ] Merge-conflicted files showin with hazard icon; cannot be committed
- [ ] Right-clicking any file shows menu with options until fixed
- [ ] User can discard the file; pending confirmation dialogue * [ ] User can check none, or check one or more files to commit; list is
- [ ] `Do not show this message again`overrides the preference setting if true scrollable
- [ ] User can ignore single/all files, show in Finder/Explorer, reveal in external editor, or open in default program * [ ] User can select one or more lines to commit; diff is scrollable
- [ ] A specific files can only be ignored once * [ ] Right-clicking any file shows menu with options
- [ ] All ignored files found in Repository Settings > Ignored Files tab * [ ] User can discard the file; pending confirmation dialogue
- [ ] Panes can be resized horizontally, and contents resize to take the full width * [ ] `Do not show this message again`overrides the preference setting if
- [ ] Quitting Desktop and relaunching remembers sizes true
* [ ] User can ignore single/all files, show in Finder/Explorer, reveal in
external editor, or open in default program
* [ ] A specific files can only be ignored once
* [ ] All ignored files found in Repository Settings > Ignored Files tab
* [ ] Panes can be resized horizontally, and contents resize to take the full
width
* [ ] Quitting Desktop and relaunching remembers sizes
### History tab ### History tab
- [ ] All commits listed in chronological order, with avatar, date and name; list is scrollable with arrow keys enabled
- [ ] Right clicking any commit shows options: Revert, Copy SHA, View on GitHub
- [ ] Hover shows file name in tooltip
### Diffs tab * [ ] All commits listed in chronological order, with avatar, date and name;
- [ ] All commits have avatar, selectable SHA, # of files changed, commit message, commit description (optional) list is scrollable with arrow keys enabled
- [ ] Long commit descriptions can be toggled with expand/collapse icon * [ ] Right clicking any commit shows options: Revert, Copy SHA, View on
- [ ] Reverting commit repopulates commit area GitHub
- [ ] Error message if no changes to commit * [ ] Hover shows file name in tooltip
- [ ] All files within a commit listed, with respective +/•/-/-> sign; list is scrollable
- [ ] Diffs are viewable; list is scrollable with arrow keys enabled ### Diffs tab
- [ ] Green is for additions, red for deletions
- [ ] Different file types are rendered properly * [ ] All commits have avatar, selectable SHA, # of files changed, commit
- [ ] Single pic file with the `->` sign has multiple view options: 2-up (default); Swipe; Onion Skin; and Difference message, commit description (optional)
- [ ] Panes can be resized horizontally, and contents resize to take the full width * [ ] Long commit descriptions can be toggled with expand/collapse icon
- [ ] Diffs cannot be over 3MB * [ ] Reverting commit repopulates commit area
- [ ] Diffs cannot be longer than 500,000 characters * [ ] Error message if no changes to commit
* [ ] All files within a commit listed, with respective +/•/-/-> sign; list is
scrollable
* [ ] Diffs are viewable; list is scrollable with arrow keys enabled
* [ ] Green is for additions, red for deletions
* [ ] Different file types are rendered properly
* [ ] Single pic file with the `->` sign has multiple view options: 2-up
(default); Swipe; Onion Skin; and Difference
* [ ] Panes can be resized horizontally, and contents resize to take the full
width
* [ ] Diffs cannot be over 3MB
* [ ] Diffs cannot be longer than 500,000 characters
### Commit section ### Commit section
- [ ] Commit created if user clicks `Commit to [branch]` button with commit message and at least one checked file
- [ ] `Fetch origin` changes to `Push` with number of commits badge * [ ] Commit created if user clicks `Commit to [branch]` button with commit
- [ ] Avatar of user is shown message and at least one checked file
- [ ] User can 'at-mention' those associated with the respective repo; either subject or description field is ok (published repositories only) * [ ] `Fetch origin` changes to `Push` with number of commits badge
- [ ] User can 'pound-mention' an issue in the either subject or description field; issue number should populate (published repositories only) * [ ] Avatar of user is shown
- [ ] Description field is optional * [ ] User can 'at-mention' those associated with the respective repo; either
- [ ] User can undo last commit subject or description field is ok (published repositories only)
- [ ] `Push` with number of commits badge is decremented or reverts to `Fetch origin` * [ ] User can 'pound-mention' an issue in the either subject or description
- [ ] `Undo` button disabled if user is pushing commit field; issue number should populate (published repositories only)
- [ ] User can publish a new repo with no commits (aka unborn repo/branch) * [ ] Description field is optional
* [ ] User can undo last commit
* [ ] `Push` with number of commits badge is decremented or reverts to
`Fetch origin`
* [ ] `Undo` button disabled if user is pushing commit
* [ ] User can publish a new repo with no commits (aka unborn repo/branch)
### Branches list ### Branches list
- [ ] Current branch always shows if repository present
- [ ] Hover shows full branch name in tooltip * [ ] Current branch always shows if repository present
- [ ] Opening list shows all branches in categorized format with a working filter * [ ] Hover shows full branch name in tooltip
- [ ] `New` button opens 'New Branch' modal * [ ] Opening list shows all branches in categorized format with a working
- [ ] If filters results are nil, then prefill branch name in modal if user clicks `Create New Branch` filter
- [ ] Active branch is highlighted and marked with a check * [ ] `New` button opens 'New Branch' modal
- [ ] `ESC` clears the filter * [ ] If filters results are nil, then prefill branch name in modal if user
- [ ] Hover shows full branch name in tooltip clicks `Create New Branch`
- [ ] Default branch labeled and listed first, with timestamp * [ ] Active branch is highlighted and marked with a check
- [ ] Selecting a branch switches branches * [ ] `ESC` clears the filter
- [ ] Creating a new branch shows `Publish branch` button * [ ] Hover shows full branch name in tooltip
- [ ] Publishing successful if logged in only; else error message * [ ] Default branch labeled and listed first, with timestamp
- [ ] `Create Pull Request` menu option shows warning if branch not published yet * [ ] Selecting a branch switches branches
- [ ] Renamed branches updated on .com and vice-versa if logged in; else error message * [ ] Creating a new branch shows `Publish branch` button
- [ ] Opens modal with ability to enter new name * [ ] Publishing successful if logged in only; else error message
- [ ] Deleted branches updated on .com and vice-versa if logged in; else error message * [ ] `Create Pull Request` menu option shows warning if branch not
- [ ] Deleting branch show warning message published yet
* [ ] Renamed branches updated on .com and vice-versa if logged in; else error
message
* [ ] Opens modal with ability to enter new name
* [ ] Deleted branches updated on .com and vice-versa if logged in; else error
message
* [ ] Deleting branch show warning message
### Fetching origin/Pull ### Fetching origin/Pull
- [ ] Code is constantly being fetched from .com with timestamp
- [ ] Hover shows timestamp in tooltip * [ ] Code is constantly being fetched from .com with timestamp
- [ ] If Pull Requests on .com, they are reflected with down arrow and quantity * [ ] Hover shows timestamp in tooltip
- [ ] Pull Requests and Commits can co-exist; error surfaces if merge commit * [ ] If Pull Requests on .com, they are reflected with down arrow and
- [ ] User cannot Push/Pull without being signed in; error message surfaced quantity
- [ ] Push/Pull works with public/private/Enterprise repos * [ ] Pull Requests and Commits can co-exist; error surfaces if merge commit
- [ ] Tooltip shows status upon hover, if progress to display * [ ] User cannot Push/Pull without being signed in; error message surfaced
- [ ] When a branch is local-only make sure that the `Fetch` button changes to `Publish` and it publishes * [ ] Push/Pull works with public/private/Enterprise repos
* [ ] Tooltip shows status upon hover, if progress to display
* [ ] When a branch is local-only make sure that the `Fetch` button changes to
`Publish` and it publishes
### Publishing only ### Publishing only
- [ ] Unpublished repository, unborn HEAD - `Publish button` enabled (user can publish repository)
- [ ] Unpublished repository, valid branch - `Publish button` enabled (user can publish repository and branch) * [ ] Unpublished repository, unborn HEAD - `Publish button` enabled (user can
- [ ] Published repository, unborn HEAD - `Publish button` disabled (no branch to push) publish repository)
- [ ] Published repository, branch without tracking - `Publish button` enabled (user can publish branch) * [ ] Unpublished repository, valid branch - `Publish button` enabled (user can
- [ ] Published repository, network action - `Publish button` disabled (don't interfere with existing action) publish repository and branch)
* [ ] Published repository, unborn HEAD - `Publish button` disabled (no branch
to push)
* [ ] Published repository, branch without tracking - `Publish button` enabled
(user can publish branch)
* [ ] Published repository, network action - `Publish button` disabled (don't
interfere with existing action)
### Dotcom ### Dotcom
- [ ] If Desktop linked to .com (/settings/applications), the Desktop icon should show on File Revisions tab for all Pull Requests.
- [ ] Clicking the "computer icon" opens from a Pull Request page opens the branch on Desktop * [ ] If Desktop linked to .com (/settings/applications), the Desktop icon
- [ ] If private email is enabled (http://github.com/settings/emails), user is blocked from pushing to all associated repositories on Desktop? should show on File Revisions tab for all Pull Requests.
- [ ] If user updates name in Settings, change should reflect in Preferences * [ ] Clicking the "computer icon" opens from a Pull Request page opens the
branch on Desktop
* [ ] If private email is enabled (http://github.com/settings/emails), user is
blocked from pushing to all associated repositories on Desktop?
* [ ] If user updates name in Settings, change should reflect in Preferences
### Pull Request list + CI status (v1.1) ### Pull Request list + CI status (v1.1)
- [ ] Pull request list shown as subsection of Branch list
- [ ] Only open Pull Requests are reflected; closed Pull Requests not shown in the list * [ ] Pull request list shown as subsection of Branch list
- [ ] Pull Request toolbar status is surfaced with yellow, green or red icon, or no icon if no status * [ ] Only open Pull Requests are reflected; closed Pull Requests not shown in
- [ ] If no pull requests, then no badge shown, and Pull Request tab shows `0` the list
- [ ] User shown current branch in text area, and given option to create a new branch or create new pull request * [ ] Pull Request toolbar status is surfaced with yellow, green or red icon, or
- [ ] Pull request for the current branch selected by default, with pull-request-number badge in header no icon if no status
- [ ] Pull request list can be filtered; `esc` key clears filter; arrow keys can scroll list * [ ] If no pull requests, then no badge shown, and Pull Request tab shows `0`
- [ ] Results in chronological order, with name, id number, date, username, and CI status * [ ] User shown current branch in text area, and given option to create a new
- [ ] Status checks run frequently in background, especially if yellow branch or create new pull request
- [ ] PR status can be updated independently of respective PR * [ ] Pull request for the current branch selected by default, with
pull-request-number badge in header
* [ ] Pull request list can be filtered; `esc` key clears filter; arrow keys
can scroll list
* [ ] Results in chronological order, with name, id number, date, username,
and CI status
* [ ] Status checks run frequently in background, especially if yellow
* [ ] PR status can be updated independently of respective PR
### TBD placeholder (WIP) ### TBD placeholder (WIP)
- Merge tool for conflicted files
- Conflicted files vs changed files * Merge tool for conflicted files
- Relationship between branches * Conflicted files vs changed files
- Commit/Compare tabs now occupy left pane * Relationship between branches
- Compare tab shows branch dropdown * Commit/Compare tabs now occupy left pane
- Choose a branch from the list (same order as branch list? current branch present?) or user filter; `esc` clears filter * Compare tab shows branch dropdown
- Once branch selected, quantity of commits behind surfaced; matches commits shown * Choose a branch from the list (same order as branch list? current branch
- `Merge X commits` button is activated present?) or user filter; `esc` clears filter
- Merge conflict count surfaced below button if relevant * Once branch selected, quantity of commits behind surfaced; matches
- Clicking `Merge` button merges all shown commits commits shown
- Commit history present, chronological order, descending * `Merge X commits` button is activated
- Show Git LFS (Cloning, Committing, Checking out, Reverting, Switching branches) * Merge conflict count surfaced below button if relevant
- Report Git LFS (Cloning, Pushing, Pulling, Switching branches, Reverting) * Clicking `Merge` button merges all shown commits
* Commit history present, chronological order, descending
* Show Git LFS (Cloning, Committing, Checking out, Reverting, Switching
branches)
* Report Git LFS (Cloning, Pushing, Pulling, Switching branches, Reverting)

View file

@ -25,10 +25,10 @@ are constrained to within the dialog itself.
## Errors ## Errors
Dialogs should, when practical, render errors caused by its actions inline as Dialogs should, when practical, render errors caused by its actions inline as
opposed to opening an error dialog. An example of this is the Preferences dialog. opposed to opening an error dialog. An example of this is the Preferences
If the dialog fails to write to the .gitignore or git config files as part of dialog. If the dialog fails to write to the .gitignore or git config files as
persisting changes it renders a short error message inline in the dialog using part of persisting changes it renders a short error message inline in the dialog
the `DialogError` component. using the `DialogError` component.
The `DialogError` component, if used, must be the first child element of the The `DialogError` component, if used, must be the first child element of the
Dialog itself. Dialog itself.
@ -49,22 +49,21 @@ Dialog itself.
</Dialog> </Dialog>
``` ```
The content inside of the DialogError should be primarily text based. Avoid using The content inside of the DialogError should be primarily text based. Avoid
the term 'Error' inside the text as that should be evident already based on the using the term 'Error' inside the text as that should be evident already based
styling of the `DialogError` component. on the styling of the `DialogError` component.
## Best practices ## Best practices
### DO: Let children render the DialogContent component ### DO: Let children render the DialogContent component
If you're using a one-child-per-tab approach you should render the DialogContent If you're using a one-child-per-tab approach you should render the DialogContent
as the top-level element in those children instead of wrapping children inside the as the top-level element in those children instead of wrapping children inside
DialogContent element. This avoid needless nesting and lets us leverage generic the DialogContent element. This avoid needless nesting and lets us leverage
dialog/form/row styles in a more straightforward way. generic dialog/form/row styles in a more straightforward way.
#### Example (good) #### Example (good)
```html ```html
<!-- SomeComponent.tsx --> <!-- SomeComponent.tsx -->
<Dialog title='Title'> <Dialog title='Title'>
@ -85,7 +84,6 @@ dialog/form/row styles in a more straightforward way.
#### Example (bad) #### Example (bad)
```html ```html
<!-- SomeComponent.tsx --> <!-- SomeComponent.tsx -->
<Dialog title='Title'> <Dialog title='Title'>
@ -108,8 +106,8 @@ dialog/form/row styles in a more straightforward way.
### DO: Use Row components to lay out content ### DO: Use Row components to lay out content
The `Row` component receives a bottom margin, when used as an immediate The `Row` component receives a bottom margin, when used as an immediate child of
child of `DialogContent`, making it an excellent tool for structuring content. `DialogContent`, making it an excellent tool for structuring content.
If the content is primary text, as opposed to form component the `<p>` element If the content is primary text, as opposed to form component the `<p>` element
should be used instead of the `Row` component. should be used instead of the `Row` component.

View file

@ -8,10 +8,10 @@ on a repository in the sidebar.
This is the checklist of things that it needs to support: This is the checklist of things that it needs to support:
- the editor supports opening a directory, not just a file * the editor supports opening a directory, not just a file
- the editor is installed by the user, so there is a reliable way to find it * the editor is installed by the user, so there is a reliable way to find it on
on the user's machine the user's machine
- it comes with a command-line interface that can be launched by Desktop * it comes with a command-line interface that can be launched by Desktop
If you think your editor satisfies all these please read on to understand how If you think your editor satisfies all these please read on to understand how
Desktop integrates with each OS, and if you're still keen to integrate this Desktop integrates with each OS, and if you're still keen to integrate this
@ -24,9 +24,9 @@ The source for the editor integration on Windows is found in
These editors are currently supported: These editors are currently supported:
- [Atom](https://atom.io/) * [Atom](https://atom.io/)
- [Visual Studio Code](https://code.visualstudio.com/) * [Visual Studio Code](https://code.visualstudio.com/)
- [Sublime Text](https://www.sublimetext.com/) * [Sublime Text](https://www.sublimetext.com/)
These are defined in an enum at the top of the file: These are defined in an enum at the top of the file:
@ -38,8 +38,8 @@ export enum ExternalEditor {
} }
``` ```
If you want to add another editor, add a new key to the `ExternalEditor` If you want to add another editor, add a new key to the `ExternalEditor` enum
enum with a friendly name for the value. This will trigger a number of compiler with a friendly name for the value. This will trigger a number of compiler
errors, which are places in the module you need to add code. errors, which are places in the module you need to add code.
The steps for resolving each editor can be found in `findApplication()` and in The steps for resolving each editor can be found in `findApplication()` and in
@ -60,10 +60,9 @@ entries to the registry to help the OS with cleaning up later, if the user
wishes to uninstall. These entries are used by GitHub Desktop to identify wishes to uninstall. These entries are used by GitHub Desktop to identify
relevant programs and where they can be located. relevant programs and where they can be located.
The registry locations for each editor are listed in `getRegistryKeys()`. The registry locations for each editor are listed in `getRegistryKeys()`. Some
Some editors support multiple install locations, but are structurally the editors support multiple install locations, but are structurally the same (for
same (for example 64-bit or 32-bit application, or stable and developer example 64-bit or 32-bit application, or stable and developer channels).
channels).
```ts ```ts
function getRegistryKeys(editor: ExternalEditor): ReadonlyArray<string> { function getRegistryKeys(editor: ExternalEditor): ReadonlyArray<string> {
@ -83,26 +82,25 @@ function getRegistryKeys(editor: ExternalEditor): ReadonlyArray<string> {
If you're not sure how your editor is installed, check one of these locations: If you're not sure how your editor is installed, check one of these locations:
- `HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall` - * `HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall` -
uninstall information about 64-bit Windows software is found here uninstall information about 64-bit Windows software is found here
- `HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall` - * `HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall` -
uninstall information about 32-bit Windows software is found here uninstall information about 32-bit Windows software is found here
- `HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall` - * `HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall` -
uninstall information for software that doesn't require administrator uninstall information for software that doesn't require administrator
permissions is found here permissions is found here
Your editor is probably hiding behind a GUID in one of these locations - this is
Your editor is probably hiding behind a GUID in one of these locations - this the the key that Desktop needs to read the registry and find the installation
is the the key that Desktop needs to read the registry and find the installation for your editor. for your editor.
### Step 2: Validate The Installation ### Step 2: Validate The Installation
As part of installing to the registry, a program will insert a As part of installing to the registry, a program will insert a number of
number of key-value pairs - Desktop will enumerate these to ensure it's the key-value pairs - Desktop will enumerate these to ensure it's the application it
application it expects, and identify where the install location of the expects, and identify where the install location of the application.
application.
There's two steps to this process. The first step is reading the registry, and There's two steps to this process. The first step is reading the registry, and
you can see this code in `extractApplicationInformation()`: you can see this code in `extractApplicationInformation()`:
@ -171,11 +169,11 @@ function isExpectedInstallation(
### Step 3: Launch the program ### Step 3: Launch the program
Now that Desktop knows the program is the one it expects, it can use the Now that Desktop knows the program is the one it expects, it can use the install
install location to then find the executable to launch. Many editors provide a location to then find the executable to launch. Many editors provide a shim or
shim or standalone tool to manage this, rather than launching the standalone tool to manage this, rather than launching the executable directly.
executable directly. Whatever options there are, this should be a known Whatever options there are, this should be a known location with an interface
location with an interface that doesn't change between updates. that doesn't change between updates.
```ts ```ts
function getExecutableShim( function getExecutableShim(
@ -191,8 +189,8 @@ function getExecutableShim(
} }
``` ```
Desktop will confirm this file exists on disk before launching - if it's Desktop will confirm this file exists on disk before launching - if it's missing
missing or lost it won't let you launch the external editor. or lost it won't let you launch the external editor.
## macOS ## macOS
@ -201,10 +199,10 @@ The source for the editor integration on macOS is found in
These editors are currently supported: These editors are currently supported:
- [Atom](https://atom.io/) * [Atom](https://atom.io/)
- [Visual Studio Code](https://code.visualstudio.com/) * [Visual Studio Code](https://code.visualstudio.com/)
- [Sublime Text](https://www.sublimetext.com/) * [Sublime Text](https://www.sublimetext.com/)
- [BBEdit](http://www.barebones.com/products/bbedit/) * [BBEdit](http://www.barebones.com/products/bbedit/)
These are defined in an enum at the top of the file: These are defined in an enum at the top of the file:
@ -216,8 +214,8 @@ export enum ExternalEditor {
} }
``` ```
If you want to add another editor, add a new key to the `ExternalEditor` If you want to add another editor, add a new key to the `ExternalEditor` enum
enum with a friendly name for the value. This will trigger a number of compiler with a friendly name for the value. This will trigger a number of compiler
errors, which are places in the module you need to add code. errors, which are places in the module you need to add code.
The steps for resolving each editor can be found in `findApplication()` and in The steps for resolving each editor can be found in `findApplication()` and in
@ -232,12 +230,12 @@ async function findApplication(editor: ExternalEditor): Promise<string | null> {
### Step 1: Find installation path ### Step 1: Find installation path
macOS programs are packaged as application bundles, and applications can macOS programs are packaged as application bundles, and applications can read
read information from the OS to see if they are present. information from the OS to see if they are present.
The `CFBundleIdentifier` value in the plist is what applications use to The `CFBundleIdentifier` value in the plist is what applications use to uniquely
uniquely identify themselves, for example `com.github.GitHubClient` is the identify themselves, for example `com.github.GitHubClient` is the identifier for
identifier for GitHub Desktop. GitHub Desktop.
The `getBundleIdentifier()` method is the lookup method for this value: The `getBundleIdentifier()` method is the lookup method for this value:
@ -252,9 +250,10 @@ function getBundleIdentifier(editor: ExternalEditor): string {
} }
``` ```
AppKit provides an [`API`](https://developer.apple.com/documentation/appkit/nsworkspace/1533086-absolutepathforappbundlewithiden?language=objc) AppKit provides an
for searching for an application bundle. If it finds an application bundle, [`API`](https://developer.apple.com/documentation/appkit/nsworkspace/1533086-absolutepathforappbundlewithiden?language=objc)
it will return the path to the application on disk. Otherwise it will raise an for searching for an application bundle. If it finds an application bundle, it
will return the path to the application on disk. Otherwise it will raise an
exception. exception.
### Step 2: Find executable to launch ### Step 2: Find executable to launch
@ -287,15 +286,14 @@ function getExecutableShim(
## Linux ## Linux
The source for the editor integration on Linux is found in The source for the editor integration on Linux is found in
[`app/src/lib/editors/linux.ts`](https://github.com/desktop/desktop/blob/master/app/src/lib/editors/linux.ts). [`app/src/lib/editors/linux.ts`](https://github.com/desktop/desktop/blob/master/app/src/lib/editors/linux.ts).
These editors are currently supported: These editors are currently supported:
- [Atom](https://atom.io/) * [Atom](https://atom.io/)
- [Visual Studio Code](https://code.visualstudio.com/) * [Visual Studio Code](https://code.visualstudio.com/)
- [Sublime Text](https://www.sublimetext.com/) * [Sublime Text](https://www.sublimetext.com/)
These are defined in an enum at the top of the file: These are defined in an enum at the top of the file:
@ -307,24 +305,24 @@ export enum ExternalEditor {
} }
``` ```
If you want to add another editor, add a new key to the `ExternalEditor` If you want to add another editor, add a new key to the `ExternalEditor` enum
enum with a friendly name for the value. This will trigger a compiler with a friendly name for the value. This will trigger a compiler error, and you
error, and you need to add code to `getEditorPath()` to get the source need to add code to `getEditorPath()` to get the source building again.
building again.
### Step 1: Find executable path ### Step 1: Find executable path
The `getEditorPath()` maps the editor enum to an expected path to the The `getEditorPath()` maps the editor enum to an expected path to the editor
editor executable. Add a new `case` statement for your editor. executable. Add a new `case` statement for your editor.
```ts ```ts
case ExternalEditor.VisualStudioCode: case ExternalEditor.VisualStudioCode:
return getPathIfAvailable('/usr/bin/code') return getPathIfAvailable('/usr/bin/code')
``` ```
### Step 2: Lookup executable ### Step 2: Lookup executable
Once you've done that, add code to `getAvailableEditors()` so that it checks Once you've done that, add code to `getAvailableEditors()` so that it checks for
for your new editor, following the existing patterns. your new editor, following the existing patterns.
```ts ```ts
export async function getAvailableEditors(): Promise< export async function getAvailableEditors(): Promise<

View file

@ -13,7 +13,8 @@ old friend `undefined is not a function`. This is a problem with the code itself
which cannot be resolved at runtime. Our only option is to quit the app and which cannot be resolved at runtime. Our only option is to quit the app and
relaunch. relaunch.
We handle uncaught exceptions by registering a [global listener](https://github.com/desktop/desktop/blob/fb4e73560127f491ccf5f59984a310481911f2b6/app/src/ui/index.tsx#L75). We handle uncaught exceptions by registering a
[global listener](https://github.com/desktop/desktop/blob/fb4e73560127f491ccf5f59984a310481911f2b6/app/src/ui/index.tsx#L75).
We report the exception to Central, tell the user that an unrecoverable error We report the exception to Central, tell the user that an unrecoverable error
happened, and then quit and relaunch. End of story. happened, and then quit and relaunch. End of story.
@ -24,8 +25,10 @@ standard usage of the app. For example, if the internet's down or a git
repository is in a funny state, we're gonna get some errors. repository is in a funny state, we're gonna get some errors.
Our error reporting flows through the `Dispatcher` like most everything in the Our error reporting flows through the `Dispatcher` like most everything in the
app. [`postError`](https://github.com/desktop/desktop/blob/fb4e73560127f491ccf5f59984a310481911f2b6/app/src/lib/dispatcher/dispatcher.ts#L308) app.
calls the [registered](https://github.com/desktop/desktop/blob/fb4e73560127f491ccf5f59984a310481911f2b6/app/src/lib/dispatcher/dispatcher.ts#L711) [`postError`](https://github.com/desktop/desktop/blob/fb4e73560127f491ccf5f59984a310481911f2b6/app/src/lib/dispatcher/dispatcher.ts#L308)
calls the
[registered](https://github.com/desktop/desktop/blob/fb4e73560127f491ccf5f59984a310481911f2b6/app/src/lib/dispatcher/dispatcher.ts#L711)
[error handlers](https://github.com/desktop/desktop/blob/fb4e73560127f491ccf5f59984a310481911f2b6/app/src/lib/dispatcher/error-handlers.ts), [error handlers](https://github.com/desktop/desktop/blob/fb4e73560127f491ccf5f59984a310481911f2b6/app/src/lib/dispatcher/error-handlers.ts),
starting with the most recently registered. The error handlers have the chance starting with the most recently registered. The error handlers have the chance
to pass the error through untouched, return a different or more specific error, to pass the error through untouched, return a different or more specific error,
@ -43,7 +46,8 @@ export async function myCoolErrorHandler(
``` ```
If an error passes through all the registered error handlers, the final error If an error passes through all the registered error handlers, the final error
handler will call [`Dispatcher#presentError`](https://github.com/desktop/desktop/blob/75445ea61177347b2df08e846aae30e637d5f1de/app/src/lib/dispatcher/dispatcher.ts#L334). handler will call
[`Dispatcher#presentError`](https://github.com/desktop/desktop/blob/75445ea61177347b2df08e846aae30e637d5f1de/app/src/lib/dispatcher/dispatcher.ts#L334).
That will present the generic error dialog to the user. That will present the generic error dialog to the user.
``` ```
@ -74,9 +78,11 @@ We have a couple `Error` subclasses which we use to provide more context to
error handlers: error handlers:
* [`GitError`](https://github.com/desktop/desktop/blob/75445ea61177347b2df08e846aae30e637d5f1de/app/src/lib/git/core.ts#L62) - * [`GitError`](https://github.com/desktop/desktop/blob/75445ea61177347b2df08e846aae30e637d5f1de/app/src/lib/git/core.ts#L62) -
All errors coming from git should be `GitError`s. All errors coming from git should be `GitError`s.
* [`ErrorWithMetadata`](https://github.com/desktop/desktop/blob/75445ea61177347b2df08e846aae30e637d5f1de/app/src/lib/error-with-metadata.ts) - * [`ErrorWithMetadata`](https://github.com/desktop/desktop/blob/75445ea61177347b2df08e846aae30e637d5f1de/app/src/lib/error-with-metadata.ts) -
Wraps an existing `Error` with additional metadata. Wraps an existing `Error` with additional metadata.
`ErrorWithMetadata` instances can provide a [`RetryAction`](https://github.com/desktop/desktop/blob/75445ea61177347b2df08e846aae30e637d5f1de/app/src/lib/retry-actions.ts) `ErrorWithMetadata` instances can provide a
which gives error handlers the ability to retry whatever action caused the error. [`RetryAction`](https://github.com/desktop/desktop/blob/75445ea61177347b2df08e846aae30e637d5f1de/app/src/lib/retry-actions.ts)
which gives error handlers the ability to retry whatever action caused the
error.

View file

@ -2,27 +2,27 @@
To ensure Desktop along without being blocked on design feedback, we need a way To ensure Desktop along without being blocked on design feedback, we need a way
to be able to ship features that are stable but not necessarily ready for to be able to ship features that are stable but not necessarily ready for
general usage. This document outlines what we should flag and how to flag general usage. This document outlines what we should flag and how to flag these
these features. features.
## What Should Be Feature Flagged? ## What Should Be Feature Flagged?
A **preview feature** can be considered as: A **preview feature** can be considered as:
- something that has a well-defined scope * something that has a well-defined scope
- a consensus exists that the team is happy to proceed, but * a consensus exists that the team is happy to proceed, but
- some details need to be thought through or clarified * some details need to be thought through or clarified
We're currently focused on user interface changes - new views, significant We're currently focused on user interface changes - new views, significant
changes to existing views, and so on. We can revisit this list when we changes to existing views, and so on. We can revisit this list when we identify
identify other cases where this sort of feature flagging needs to occur. other cases where this sort of feature flagging needs to occur.
A **beta feature** should be: A **beta feature** should be:
- a feature that is slated for an upcoming release, and * a feature that is slated for an upcoming release, and
- is usably complete, but * is usably complete, but
- needs more testing, or * needs more testing, or
- needs to be used to see how it feels * needs to be used to see how it feels
Beta features are a superset of preview features. Beta features are a superset of preview features.
@ -30,19 +30,24 @@ Beta features are a superset of preview features.
A few reasons: A few reasons:
- some solutions just need time to appear, and this lets us get working code * some solutions just need time to appear, and this lets us get working code out
out quicker. quicker.
- we want to get feedback easily - users can opt-in to these preview features. * we want to get feedback easily - users can opt-in to these preview features.
- we want to be conservative with evolving the UI - most users aren't fans of * we want to be conservative with evolving the UI - most users aren't fans of
frequent, unnecessary churn. frequent, unnecessary churn.
- if we don't like something we can pull it before people get too attached to * if we don't like something we can pull it before people get too attached to
it. it.
## How to Feature Flag? ## How to Feature Flag?
First add a new function to [feature-flag.ts](https://github.com/desktop/desktop/blob/3ee29eb1bd083a53f69fdbec2e2b10ec93404e44/app/src/lib/feature-flag.ts#L30). The function should usually check `enableDevelopmentFeatures()` or `enableBetaFeatures()`. Then, at runtime, your code should check either your feature flag function and either display the new feature or the existing one. First add a new function to
[feature-flag.ts](https://github.com/desktop/desktop/blob/3ee29eb1bd083a53f69fdbec2e2b10ec93404e44/app/src/lib/feature-flag.ts#L30).
The function should usually check `enableDevelopmentFeatures()` or
`enableBetaFeatures()`. Then, at runtime, your code should check either your
feature flag function and either display the new feature or the existing one.
See pull request integration in [#3339](https://github.com/desktop/desktop/pull/3339) for an example. See pull request integration in
[#3339](https://github.com/desktop/desktop/pull/3339) for an example.
This separation and naming scheme makes it easier to clean up the new or old This separation and naming scheme makes it easier to clean up the new or old
feature once things are stabilized. feature once things are stabilized.

View file

@ -1,20 +1,22 @@
# Developer OAuth App # Developer OAuth App
Because GitHub Desktop uses [OAuth web application flow](https://developer.github.com/v3/oauth/#web-application-flow) Because GitHub Desktop uses
[OAuth web application flow](https://developer.github.com/v3/oauth/#web-application-flow)
to interact with the GitHub API and perform actions on behalf of a user, it to interact with the GitHub API and perform actions on behalf of a user, it
needs to be bundled with a Client ID and Secret. needs to be bundled with a Client ID and Secret.
For external contributors, we have bundled a developer OAuth application For external contributors, we have bundled a developer OAuth application with
with the Desktop application so that you can complete the sign in flow locally the Desktop application so that you can complete the sign in flow locally
without needing to configure your own application. without needing to configure your own application.
These are listed in [app/webpack.common.js](https://github.com/desktop/desktop/blob/c286d0d513d82b97e1a9c60d44c23020f2ba34d7/app/webpack.common.js#L9-L10). These are listed in
[app/webpack.common.js](https://github.com/desktop/desktop/blob/c286d0d513d82b97e1a9c60d44c23020f2ba34d7/app/webpack.common.js#L9-L10).
**DO NOT TRUST THIS CLIENT ID AND SECRET! THIS IS ONLY FOR TESTING PURPOSES!!** **DO NOT TRUST THIS CLIENT ID AND SECRET! THIS IS ONLY FOR TESTING PURPOSES!!**
The limitation with this developer application is that **this will not work The limitation with this developer application is that **this will not work with
with GitHub Enterprise**. You will see sign-in will fail on the OAuth callback GitHub Enterprise**. You will see sign-in will fail on the OAuth callback due to
due to the credentials not being present there. the credentials not being present there.
## Provide your own Client ID and Secret ## Provide your own Client ID and Secret
@ -22,5 +24,5 @@ The OAuth client ID and Client Secret are bundled into the application with
webpack. If you want to provide your own Client ID and Client Secret, set these webpack. If you want to provide your own Client ID and Client Secret, set these
environment variables: environment variables:
- `DESKTOP_OAUTH_CLIENT_ID` * `DESKTOP_OAUTH_CLIENT_ID`
- `DESKTOP_OAUTH_CLIENT_SECRET` * `DESKTOP_OAUTH_CLIENT_SECRET`

View file

@ -1,10 +1,11 @@
## Placeholders and Replacements in Source Code ## Placeholders and Replacements in Source Code
As GitHub Desktop uses Webpack to transpile, minify and merge our code As GitHub Desktop uses Webpack to transpile, minify and merge our code into
into unified scripts for each configuration we define, we use some tricks unified scripts for each configuration we define, we use some tricks to manage
to manage complexity and enable some optimizations. complexity and enable some optimizations.
For example, you might come across this code in [`app-window.ts`](https://github.com/desktop/desktop/blob/master/app/src/main-process/app-window.ts): For example, you might come across this code in
[`app-window.ts`](https://github.com/desktop/desktop/blob/master/app/src/main-process/app-window.ts):
```ts ```ts
if (__DARWIN__) { if (__DARWIN__) {
@ -29,7 +30,8 @@ we get significant benefits from doing it the first way.
### Replacements ### Replacements
The replacements defined for Desktop are found in [`app/app-info.js`](https://github.com/desktop/desktop/blob/master/app/app-info.js) The replacements defined for Desktop are found in
[`app/app-info.js`](https://github.com/desktop/desktop/blob/master/app/app-info.js)
as a hash of key-value pairs. as a hash of key-value pairs.
```ts ```ts
@ -54,8 +56,8 @@ function getReplacements() {
} }
``` ```
This means we can embed values at build time based on the current platform. This means we can embed values at build time based on the current platform. Note
Note the values we are embeddeding for `__DARWIN__` and `__WIN32__`: the values we are embeddeding for `__DARWIN__` and `__WIN32__`:
```ts ```ts
__DARWIN__: process.platform === 'darwin', __DARWIN__: process.platform === 'darwin',
@ -96,13 +98,14 @@ And this code for Windows:
windowOptions.frame = false windowOptions.frame = false
``` ```
This means less code is emitted as part of the packaged app, and less This means less code is emitted as part of the packaged app, and less JavaScript
JavaScript is interpreted and executed at runtime. is interpreted and executed at runtime.
### Placeholders ### Placeholders
As we are working in TypeScript, we need to define these placeholders as As we are working in TypeScript, we need to define these placeholders as globals
globals under [`app/src/lib/globals.ts`](https://github.com/desktop/desktop/blob/master/app/src/lib/globals.d.ts) under
[`app/src/lib/globals.ts`](https://github.com/desktop/desktop/blob/master/app/src/lib/globals.d.ts)
to provide the appropriate type information to the source code. to provide the appropriate type information to the source code.
For example, the values for `__DARWIN__` and `__WIN32__` are declared as For example, the values for `__DARWIN__` and `__WIN32__` are declared as

View file

@ -7,26 +7,26 @@ machine, to work with Git repositories outside of Desktop.
This is the checklist of things that it needs to support: This is the checklist of things that it needs to support:
- Desktop can check it exists on the user's machine * Desktop can check it exists on the user's machine
- Desktop is able to launch it using the operating system's APIs * Desktop is able to launch it using the operating system's APIs
- It has a stable interface (command line arguments) that doesn't change * It has a stable interface (command line arguments) that doesn't change between
between updates updates
If you think your shell satifies all these requirements please read on to If you think your shell satifies all these requirements please read on to
understand how Desktop integrates with each OS, and if you're still keen to understand how Desktop integrates with each OS, and if you're still keen to
integrate this please fork and contribute a pull request for the team to integrate this please fork and contribute a pull request for the team to review.
review.
## Windows ## Windows
The source for the Windows shell integration is found in [`app/src/lib/shells/win32.ts`](https://github.com/desktop/desktop/blob/master/app/src/lib/shell/win32.ts). The source for the Windows shell integration is found in
[`app/src/lib/shells/win32.ts`](https://github.com/desktop/desktop/blob/master/app/src/lib/shell/win32.ts).
These shells are currently supported: These shells are currently supported:
- Command Prompt (cmd) * Command Prompt (cmd)
- PowerShell * PowerShell
- [Hyper](https://hyper.sh/) * [Hyper](https://hyper.sh/)
- Git Bash (from [Git for Windows](https://git-for-windows.github.io/)) * Git Bash (from [Git for Windows](https://git-for-windows.github.io/))
These are defined in an enum at the top of the file: These are defined in an enum at the top of the file:
@ -39,14 +39,14 @@ export enum Shell {
} }
``` ```
To add another shell, add a new key to the `Shell` enum with a friendly name To add another shell, add a new key to the `Shell` enum with a friendly name for
for the value. You will need to add code in this module to find your shell, and I'll the value. You will need to add code in this module to find your shell, and I'll
use **Git Bash** as a reference for the rest of the process. use **Git Bash** as a reference for the rest of the process.
### Step 1: Find the shell executable ### Step 1: Find the shell executable
The `getAvailableShells()` method is used to find each shell, as some may not The `getAvailableShells()` method is used to find each shell, as some may not be
be present on the user's machine. You will need to add some code in here. present on the user's machine. You will need to add some code in here.
For Git Bash we perform a couple of checks: For Git Bash we perform a couple of checks:
@ -67,9 +67,9 @@ if (gitBash.length > 0) {
This approximately reads as: This approximately reads as:
- check if Git for Windows has been installed, using the registry * check if Git for Windows has been installed, using the registry
- if it is, check the installation path exists * if it is, check the installation path exists
- return the path to `git-bash.exe` within that directory * return the path to `git-bash.exe` within that directory
### Step 2: Launch the shell ### Step 2: Launch the shell
@ -87,13 +87,14 @@ changes here.
## macOS ## macOS
The source for the macOS shell integration is found in [`app/src/lib/shells/darwin.ts`](https://github.com/desktop/desktop/blob/master/app/src/lib/shell/darwin.ts). The source for the macOS shell integration is found in
[`app/src/lib/shells/darwin.ts`](https://github.com/desktop/desktop/blob/master/app/src/lib/shell/darwin.ts).
These shells are currently supported: These shells are currently supported:
- Terminal * Terminal
- [Hyper](https://hyper.sh/) * [Hyper](https://hyper.sh/)
- [iTerm2](https://www.iterm2.com/) * [iTerm2](https://www.iterm2.com/)
These are defined in an enum at the top of the file: These are defined in an enum at the top of the file:
@ -108,22 +109,21 @@ export enum Shell {
If you want to add another shell, add a new key to the `Shell` enum with a If you want to add another shell, add a new key to the `Shell` enum with a
friendly name for the value. friendly name for the value.
There's a couple of places you need to add code to find your shell, and I'll There's a couple of places you need to add code to find your shell, and I'll use
use Hyper as a reference to explain the rest of the process. Hyper as a reference to explain the rest of the process.
### Step 1: Find the shell application ### Step 1: Find the shell application
The `getBundleID()` function is used to map a shell enum to it's bundle ID The `getBundleID()` function is used to map a shell enum to it's bundle ID that
that is defined in it's manifest. You should add a new entry here for your is defined in it's manifest. You should add a new entry here for your shell.
shell.
```ts ```ts
case Shell.Hyper: case Shell.Hyper:
return 'co.zeit.hyper' return 'co.zeit.hyper'
``` ```
After that, follow the existing patterns in `getAvailableShells()` and add a After that, follow the existing patterns in `getAvailableShells()` and add a new
new entry to lookup the install path for your shell. entry to lookup the install path for your shell.
```ts ```ts
export async function getAvailableShells(): Promise< export async function getAvailableShells(): Promise<
@ -147,9 +147,9 @@ export async function getAvailableShells(): Promise<
### Step 2: Launch the shell ### Step 2: Launch the shell
The launch step will use the `open` command in macOS to launch a given bundle The launch step will use the `open` command in macOS to launch a given bundle at
at the path requested by the user. You may not need to make changes here, the path requested by the user. You may not need to make changes here, unless
unless your shell behaviour differs significanlty from this. your shell behaviour differs significanlty from this.
```ts ```ts
export async function launch(shell: Shell, path: string): Promise<void> { export async function launch(shell: Shell, path: string): Promise<void> {
@ -161,15 +161,16 @@ export async function launch(shell: Shell, path: string): Promise<void> {
## Linux ## Linux
The source for the Linux shell integration is found in [`app/src/lib/shells/linux.ts`](https://github.com/desktop/desktop/blob/master/app/src/lib/shell/linux.ts). The source for the Linux shell integration is found in
[`app/src/lib/shells/linux.ts`](https://github.com/desktop/desktop/blob/master/app/src/lib/shell/linux.ts).
These shells are currently supported: These shells are currently supported:
- [GNOME Terminal](https://help.gnome.org/users/gnome-terminal/stable/) * [GNOME Terminal](https://help.gnome.org/users/gnome-terminal/stable/)
- [Tilix](https://github.com/gnunn1/tilix) * [Tilix](https://github.com/gnunn1/tilix)
- [Rxvt Unicode](http://software.schmorp.de/pkg/rxvt-unicode.html) * [Rxvt Unicode](http://software.schmorp.de/pkg/rxvt-unicode.html)
- [Konsole](https://konsole.kde.org/) * [Konsole](https://konsole.kde.org/)
- [XTerm](http://invisible-island.net/xterm/) * [XTerm](http://invisible-island.net/xterm/)
These are defined in an enum at the top of the file: These are defined in an enum at the top of the file:
@ -183,9 +184,9 @@ export enum Shell {
} }
``` ```
To add another shell, add a new key to the `Shell` enum with a friendly name To add another shell, add a new key to the `Shell` enum with a friendly name for
for the value. You will need to add code in this module to find your shell, and the value. You will need to add code in this module to find your shell, and I'll
I'll use Tilix as a reference for the rest of the process. use Tilix as a reference for the rest of the process.
### Step 1: Find the shell application ### Step 1: Find the shell application
@ -198,8 +199,8 @@ case Shell.Tilix:
return getPathIfAvailable('/usr/bin/tilix') return getPathIfAvailable('/usr/bin/tilix')
``` ```
After that, follow the existing patterns in `getAvailableShells()` and add a After that, follow the existing patterns in `getAvailableShells()` and add a new
new entry to lookup the install path for your shell. entry to lookup the install path for your shell.
```ts ```ts
export async function getAvailableShells(): Promise< export async function getAvailableShells(): Promise<
@ -224,8 +225,8 @@ export async function getAvailableShells(): Promise<
### Step 2: Launch the shell ### Step 2: Launch the shell
The `launch()` method will use the received `shell.shell` executable path and The `launch()` method will use the received `shell.shell` executable path and
the path requested by the user. You may need to make changes here, if your the path requested by the user. You may need to make changes here, if your shell
shell has a different command line interface. has a different command line interface.
```ts ```ts
export async function launch( export async function launch(
@ -251,5 +252,4 @@ export async function launch(
const commandArgs = ['--working-directory', path] const commandArgs = ['--working-directory', path]
await spawn(shell.path, commandArgs) await spawn(shell.path, commandArgs)
} }
``` ```

View file

@ -1,6 +1,7 @@
# Syntax Highlighted Diffs # Syntax Highlighted Diffs
We introduced syntax highlighted diffs in [#3101](https://github.com/desktop/desktop/pull/3101). We introduced syntax highlighted diffs in
[#3101](https://github.com/desktop/desktop/pull/3101).
<img width="578" alt="A screenshot of GitHub Desktop showing a diff with syntax highlighting" src="https://user-images.githubusercontent.com/634063/31934229-d2ffdac8-b8ab-11e7-84e7-1bb2c0e1a0ec.png"> <img width="578" alt="A screenshot of GitHub Desktop showing a diff with syntax highlighting" src="https://user-images.githubusercontent.com/634063/31934229-d2ffdac8-b8ab-11e7-84e7-1bb2c0e1a0ec.png">
@ -8,41 +9,86 @@ We introduced syntax highlighted diffs in [#3101](https://github.com/desktop/des
We currently support syntax highlighting for the following languages. We currently support syntax highlighting for the following languages.
JavaScript, JSON, TypeScript, Coffeescript, HTML, CSS, SCSS, LESS, VUE, Markdown, Yaml, XML, Objective-C, Scala, C#, Java, C, C++, Kotlin, Ocaml, F#, sh/bash, Swift, SQL, CYPHER, Go, Perl, PHP, Python, Ruby, Clojure JavaScript, JSON, TypeScript, Coffeescript, HTML, CSS, SCSS, LESS, VUE,
Markdown, Yaml, XML, Objective-C, Scala, C#, Java, C, C++, Kotlin, Ocaml, F#,
sh/bash, Swift, SQL, CYPHER, Go, Perl, PHP, Python, Ruby, Clojure
This list was never meant to be exhaustive, we expect to add more languages going forward but this seemed like a good first step. This list was never meant to be exhaustive, we expect to add more languages
going forward but this seemed like a good first step.
Note, however that this list is likely to grow stale so I'd recommend checking [the code](https://github.com/desktop/desktop/blob/master/app/src/highlighter/index.ts) directly. Note, however that this list is likely to grow stale so I'd recommend checking
[the code](https://github.com/desktop/desktop/blob/master/app/src/highlighter/index.ts)
directly.
### I want to add my favorite language ### I want to add my favorite language
Cool! As long as it's a language that [CodeMirror supports out of the box](https://codemirror.net/mode/index.html) we should be able to make it work. Open an issue and we'll take it from there. Cool! As long as it's a language that
[CodeMirror supports out of the box](https://codemirror.net/mode/index.html) we
should be able to make it work. Open an issue and we'll take it from there.
If you want to create a PR and add highlighter support for your favourite programming langauge don't forget to: If you want to create a PR and add highlighter support for your favourite
1. Submit a PR with a sample file for the language to [desktop/highlighter-tests](https://github.com/desktop/highlighter-tests). programming langauge don't forget to:
2. Add the language that the highlighter going to support to the `Supported Languages` list above.
1. Submit a PR with a sample file for the language to
[desktop/highlighter-tests](https://github.com/desktop/highlighter-tests).
2. Add the language that the highlighter going to support to the
`Supported Languages` list above.
## Why do the diffs on GitHub.com and Desktop look different ## Why do the diffs on GitHub.com and Desktop look different
GitHub.com uses TextMate/Atom grammars whereas GitHub Desktop currently uses the [built-in](https://codemirror.net/mode/index.html) modes in CodeMirror. There's some significant differences both in granularity and in tokenization between these two. CodeMirror was a good way for us to get started but depending on how it plays out we might consider looking into other grammars. GitHub.com uses TextMate/Atom grammars whereas GitHub Desktop currently uses the
[built-in](https://codemirror.net/mode/index.html) modes in CodeMirror. There's
some significant differences both in granularity and in tokenization between
these two. CodeMirror was a good way for us to get started but depending on how
it plays out we might consider looking into other grammars.
## The Problem ## The Problem
Syntax highlighting is a well-understood problem with tons of options. Atom uses TextMate grammars to do theirs but since we're already using CodeMirror I took a stab at implementing ours using that. Syntax highlighting is a well-understood problem with tons of options. Atom uses
TextMate grammars to do theirs but since we're already using CodeMirror I took a
stab at implementing ours using that.
Syntax highlighted diffs have been a much appreciated feature of GitHub.com for a long time now and one that I have missed in GitHub Desktop for a long time. Highlighting in diffs presents some added complexity over that of highlighting in a normal source file though. Pretty much all languages are contextual, in that what happened on some line "higher up" affects what's going on further down. As such you can't just pull out a line from a diff and expect it to be highlighted properly. Here's a good example Syntax highlighted diffs have been a much appreciated feature of GitHub.com for
a long time now and one that I have missed in GitHub Desktop for a long time.
Highlighting in diffs presents some added complexity over that of highlighting
in a normal source file though. Pretty much all languages are contextual, in
that what happened on some line "higher up" affects what's going on further
down. As such you can't just pull out a line from a diff and expect it to be
highlighted properly. Here's a good example
<img width="658" alt="A screenshot of GitHub Desktop showing a diff with a multi-line comment which is missing the opening statement" src="https://user-images.githubusercontent.com/634063/31782735-34dfe412-b4fc-11e7-8d79-46a949417ed2.png"> <img width="658" alt="A screenshot of GitHub Desktop showing a diff with a multi-line comment which is missing the opening statement" src="https://user-images.githubusercontent.com/634063/31782735-34dfe412-b4fc-11e7-8d79-46a949417ed2.png">
Had we just tried to highlight individual lines here we wouldn't have been able to infer that the first line was part of a multi-line comment. Had we just tried to highlight individual lines here we wouldn't have been able
to infer that the first line was part of a multi-line comment.
Instead, we have to take the contents of the file before the change, and the contents of it after and run highlighting on both versions. Once that's done we can stitch these together to form one syntax highlighted diff.
Instead, we have to take the contents of the file before the change, and the
contents of it after and run highlighting on both versions. Once that's done we
can stitch these together to form one syntax highlighted diff.
## The Approach ## The Approach
When we are about to perform highlighting on a diff we start out by scanning through the diff to figure out which lines we need from which file. Context lines can be pulled from either version while added/removed lines obviously need to come from a particular version. If we find that a file consists entirely of additions or entirely of deletions we can optimize further by adding a preference for one of the versions and thus getting away with loading just one file. When we are about to perform highlighting on a diff we start out by scanning
through the diff to figure out which lines we need from which file. Context
lines can be pulled from either version while added/removed lines obviously need
to come from a particular version. If we find that a file consists entirely of
additions or entirely of deletions we can optimize further by adding a
preference for one of the versions and thus getting away with loading just one
file.
Once we've got that settled we load the first 256kb from both versions (256kb picked arbitrarily because I figured it should cover the majority of source files while adding a very manageable memory overhead for the feature). We then pass this content, along with which lines we want to get tokens for to one or two web workers which then run the modes. CodeMirror modes are synchronous but running them in a web worker means we can get on with other things while we're tokenizing up to half a megabyte of content in up to two different threads (threads in javascript, what have we come to). It also means that we have a real nice containment of the highlighting process and that we can terminate it should it for some reason end up taking a very long time to complete. Once we've got that settled we load the first 256kb from both versions (256kb
picked arbitrarily because I figured it should cover the majority of source
files while adding a very manageable memory overhead for the feature). We then
pass this content, along with which lines we want to get tokens for to one or
two web workers which then run the modes. CodeMirror modes are synchronous but
running them in a web worker means we can get on with other things while we're
tokenizing up to half a megabyte of content in up to two different threads
(threads in javascript, what have we come to). It also means that we have a real
nice containment of the highlighting process and that we can terminate it should
it for some reason end up taking a very long time to complete.
When we get the results from the workers we apply our own custom CodeMirror mode which takes the tokens from the language modes and applies them inside of our diff. That means that there's a small window in between when users see the diff and when highlighting gets applied. In my testing it's barely noticeable and it means we can deliver what really matters (the diff) as quickly as we've done before. When we get the results from the workers we apply our own custom CodeMirror mode
which takes the tokens from the language modes and applies them inside of our
diff. That means that there's a small window in between when users see the diff
and when highlighting gets applied. In my testing it's barely noticeable and it
means we can deliver what really matters (the diff) as quickly as we've done
before.

View file

@ -6,54 +6,62 @@ the application (visually) and anchored at the top of the screen. On Windows
things aren't quite as simple. things aren't quite as simple.
Since we wanted a "frameless" design on Windows we explored putting the Since we wanted a "frameless" design on Windows we explored putting the
application menu behind a hamburger icon in [#689](https://github.com/desktop/desktop/pull/689) application menu behind a hamburger icon in
which worked decently until the advent of the separate title bar in [#775](https://github.com/desktop/desktop/pull/775) which was introduced so that [#689](https://github.com/desktop/desktop/pull/689) which worked decently until
there would be draggable areas of the window even when running on small resolutions. the advent of the separate title bar in
[#775](https://github.com/desktop/desktop/pull/775) which was introduced so that
there would be draggable areas of the window even when running on small
resolutions.
Ultimately we decided that the familiar UX of a menu bar was superior to anything Ultimately we decided that the familiar UX of a menu bar was superior to
we had tried up until that point. anything we had tried up until that point.
The first iteration of this menu bar was implemented in [#991](https://github.com/desktop/desktop/pull/991) and this document serves to The first iteration of this menu bar was implemented in
[#991](https://github.com/desktop/desktop/pull/991) and this document serves to
document what a Windows menu bar is supposed to do such that we can detect document what a Windows menu bar is supposed to do such that we can detect
regressions going forward. regressions going forward.
## The basics ## The basics
The menu bar should display the top-level menu items and each menu item The menu bar should display the top-level menu items and each menu item should
should be clickable. When clicking on a menu item the associated sub menu be clickable. When clicking on a menu item the associated sub menu should expand
should expand (or collapse if already open). (or collapse if already open).
## Keyboard navigation ## Keyboard navigation
When a user is holding down the <kbd>Alt</kbd> key the access-keys (which is separate from When a user is holding down the <kbd>Alt</kbd> key the access-keys (which is
accelerator or "shortcut" keys) in the top-level menu items should be underlined. separate from accelerator or "shortcut" keys) in the top-level menu items should
be underlined.
![underlined access keys](https://cloud.githubusercontent.com/assets/634063/24377826/02f7cb34-1341-11e7-9514-4b229372f985.png) ![underlined access keys](https://cloud.githubusercontent.com/assets/634063/24377826/02f7cb34-1341-11e7-9514-4b229372f985.png)
Pressing, and holding down, <kbd>Alt</kbd> followed by one of the access keys in the top Pressing, and holding down, <kbd>Alt</kbd> followed by one of the access keys in
level menu should expand that menu. The menu should now be put in such as state the top level menu should expand that menu. The menu should now be put in such
that menu items in sub menus have their access keys highlighted as well. as state that menu items in sub menus have their access keys highlighted as
well.
If a menu is opened using <kbd>ALT</kbd>+<kbd>X</kbd> (where x is an access key for a top level menu If a menu is opened using <kbd>ALT</kbd>+<kbd>X</kbd> (where x is an access key
item) a user should be able to activate (execute) its sub menu items should by for a top level menu item) a user should be able to activate (execute) its sub
pressing the corresponding access key. Note, however, that this key should *not* menu items should by pressing the corresponding access key. Note, however, that
be used in conjunction with the <kbd>Alt</kbd> key. In other words, to execute the this key should _not_ be used in conjunction with the <kbd>Alt</kbd> key. In
File -> New Branch item a user should be able to press <kbd>ALT</kbd>+<kbd>F</kbd> other words, to execute the File -> New Branch item a user should be able to
followed by <kbd>B</kbd>. press <kbd>ALT</kbd>+<kbd>F</kbd> followed by <kbd>B</kbd>.
Pressing the <kbd>Alt</kbd> key and releasing it without pressing an access key should Pressing the <kbd>Alt</kbd> key and releasing it without pressing an access key
put focus on the first top level menu item if no menu is currently expanded. If should put focus on the first top level menu item if no menu is currently
any menus are expanded pressing <kbd>Alt</kbd> should immediately close any open menus. expanded. If any menus are expanded pressing <kbd>Alt</kbd> should immediately
close any open menus.
![focused menu item](https://cloud.githubusercontent.com/assets/634063/24378079/f6bff85e-1341-11e7-8d79-dbc8681fa9f0.png) ![focused menu item](https://cloud.githubusercontent.com/assets/634063/24378079/f6bff85e-1341-11e7-8d79-dbc8681fa9f0.png)
Pressing and releasing the <kbd>Alt</kbd> key while a top level menu item is focused should Pressing and releasing the <kbd>Alt</kbd> key while a top level menu item is
remove keyboard focus from the item. focused should remove keyboard focus from the item.
### Focused top-level menu items ### Focused top-level menu items
When a top-level menu item has keyboard focused (and its menu is collapsed) a When a top-level menu item has keyboard focused (and its menu is collapsed) a
user should be able to expand the menu by pressing <kbd>Enter</kbd> or <kbd></kbd>. user should be able to expand the menu by pressing <kbd>Enter</kbd> or
<kbd></kbd>.
Using the <kbd></kbd> and <kbd></kbd> keys should move focus to the next Using the <kbd></kbd> and <kbd></kbd> keys should move focus to the next
adjacent menu item in that direction, looping around if necessary. adjacent menu item in that direction, looping around if necessary.
@ -63,18 +71,20 @@ adjacent menu item in that direction, looping around if necessary.
An expanded menu respond to <kbd></kbd> and <kbd></kbd>, moving the selection An expanded menu respond to <kbd></kbd> and <kbd></kbd>, moving the selection
to the next adjacent menu item in that direction, looping around if necessary. to the next adjacent menu item in that direction, looping around if necessary.
Hitting <kbd>Enter</kbd> or <kbd>Space</kbd> should execute the currently selected menu item. Hitting <kbd>Enter</kbd> or <kbd>Space</kbd> should execute the currently
selected menu item.
<kbd></kbd> should open a submenu if the currently selected item has one and <kbd></kbd> should open a submenu if the currently selected item has one and
move selection (and focus) to the first item in that submenu. If the current move selection (and focus) to the first item in that submenu. If the current
item does not have a submenu <kbd></kbd> should have no effect. item does not have a submenu <kbd></kbd> should have no effect. Similarly
Similarly <kbd></kbd> should close the currently open submenu and move focus <kbd></kbd> should close the currently open submenu and move focus back to the
back to the sub-menu's parent item. sub-menu's parent item.
#### Pointer device interactions #### Pointer device interactions
Menu item selection should follow the pointer device so that pointing on a menu Menu item selection should follow the pointer device so that pointing on a menu
item automatically selects it. Moving outside of a menu should not close the menu. item automatically selects it. Moving outside of a menu should not close the
menu.
If a user points at a menu item which has a submenu of its own the selection If a user points at a menu item which has a submenu of its own the selection
should immediately switch to that menu item but the sub menu should not expand should immediately switch to that menu item but the sub menu should not expand