mirror of
https://github.com/atom/atom.git
synced 2026-01-26 07:19:06 -05:00
Merge pull request #17893 from atom/dw-migrate-about
➡️ Migrate core package 'about' into ./packages
This commit is contained in:
9
package-lock.json
generated
9
package-lock.json
generated
@@ -491,8 +491,7 @@
|
||||
"integrity": "sha1-hn2g/zn3eGEyQsRM/qg/CqTr35s="
|
||||
},
|
||||
"about": {
|
||||
"version": "https://www.atom.io/api/packages/about/versions/1.10.0/tarball",
|
||||
"integrity": "sha512-fM7e2HvlwwQ38lD5F2FFH6LaT6z4rm6q8XTeIpZOkIymtMx8YdNyZDl2WS0bP0+uBLPxeZdw2E+DJZmKxw9oRA==",
|
||||
"version": "file:packages/about",
|
||||
"requires": {
|
||||
"etch": "0.9.0",
|
||||
"semver": "^5.5.0"
|
||||
@@ -500,13 +499,11 @@
|
||||
"dependencies": {
|
||||
"etch": {
|
||||
"version": "0.9.0",
|
||||
"resolved": "https://registry.npmjs.org/etch/-/etch-0.9.0.tgz",
|
||||
"integrity": "sha1-CSJpiPLO4GkL3yCMyyXkFNXfrV8="
|
||||
"bundled": true
|
||||
},
|
||||
"semver": {
|
||||
"version": "5.5.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.5.1.tgz",
|
||||
"integrity": "sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw=="
|
||||
"bundled": true
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"@atom/nsfw": "^1.0.18",
|
||||
"@atom/source-map-support": "^0.3.4",
|
||||
"@atom/watcher": "1.0.8",
|
||||
"about": "https://www.atom.io/api/packages/about/versions/1.10.0/tarball",
|
||||
"about": "file:packages/about",
|
||||
"archive-view": "https://www.atom.io/api/packages/archive-view/versions/0.65.1/tarball",
|
||||
"async": "0.2.6",
|
||||
"atom-dark-syntax": "https://www.atom.io/api/packages/atom-dark-syntax/versions/0.29.0/tarball",
|
||||
@@ -183,7 +183,7 @@
|
||||
"one-light-syntax": "1.8.4",
|
||||
"solarized-dark-syntax": "1.1.5",
|
||||
"solarized-light-syntax": "1.1.5",
|
||||
"about": "1.10.0",
|
||||
"about": "file:./packages/about",
|
||||
"archive-view": "0.65.1",
|
||||
"autocomplete-atom-api": "0.10.7",
|
||||
"autocomplete-css": "0.17.5",
|
||||
|
||||
194
packages/README.md
Normal file
194
packages/README.md
Normal file
@@ -0,0 +1,194 @@
|
||||
# Atom Core Packages
|
||||
|
||||
This folder contains core packages that are bundled with Atom releases. Not all Atom core packages are kept here; please
|
||||
see the table below for the location of every core Atom package.
|
||||
|
||||
> **NOTE:** There is an ongoing effort to migrate more Atom packages from their individual repositories to this folder.
|
||||
See [RFC 003](https://github.com/atom/atom/blob/master/docs/rfcs/003-consolidate-core-packages.md) for more details.
|
||||
|
||||
| Package | Where to find it | Migration issue |
|
||||
|---------|------------------|-----------------|
|
||||
| **about** | [`./packages/about`](./about) | [#17832](https://github.com/atom/atom/issues/17832) |
|
||||
| **atom-dark-syntax** | [`atom/atom-dark-syntax`][atom-dark-syntax] | [#17849](https://github.com/atom/atom/issues/17849) |
|
||||
| **atom-dark-ui** | [`atom/atom-dark-ui`][atom-dark-ui] | [#17850](https://github.com/atom/atom/issues/17850) |
|
||||
| **atom-light-syntax** | [`atom/atom-light-syntax`][atom-light-syntax] | [#17851](https://github.com/atom/atom/issues/17851) |
|
||||
| **atom-light-ui** | [`atom/atom-light-ui`][atom-light-ui] | [#17852](https://github.com/atom/atom/issues/17852) |
|
||||
| **autocomplete-atom-api** | [`atom/autocomplete-atom-api`][autocomplete-atom-api] | |
|
||||
| **autocomplete-css** | [`atom/autocomplete-css`][autocomplete-css] | |
|
||||
| **autocomplete-html** | [`atom/autocomplete-html`][autocomplete-html] | |
|
||||
| **autocomplete-plus** | [`atom/autocomplete-plus`][autocomplete-plus] | |
|
||||
| **autocomplete-snippets** | [`atom/autocomplete-snippets`][autocomplete-snippets] | |
|
||||
| **autoflow** | [`atom/autoflow`][autoflow] | [#17833](https://github.com/atom/atom/issues/17833) |
|
||||
| **autosave** | [`atom/autosave`][autosave] | [#17834](https://github.com/atom/atom/issues/17834) |
|
||||
| **background-tips** | [`atom/background-tips`][background-tips] | [#17835](https://github.com/atom/atom/issues/17835) |
|
||||
| **base16-tomorrow-dark-theme** | [`atom/base16-tomorrow-dark-theme`][base16-tomorrow-dark-theme] | [#17836](https://github.com/atom/atom/issues/17836) |
|
||||
| **base16-tomorrow-light-theme** | [`atom/base16-tomorrow-light-theme`][base16-tomorrow-light-theme] | [#17837](https://github.com/atom/atom/issues/17837) |
|
||||
| **bookmarks** | [`atom/bookmarks`][bookmarks] | |
|
||||
| **bracket-matcher** | [`atom/bracket-matcher`][bracket-matcher] | |
|
||||
| **command-palette** | [`atom/command-palette`][command-palette] | |
|
||||
| **dalek** | [`atom/dalek`][dalek] | [#17838](https://github.com/atom/atom/issues/17838) |
|
||||
| **deprecation-cop** | [`atom/deprecation-cop`][deprecation-cop] | [#17839](https://github.com/atom/atom/issues/17839) |
|
||||
| **dev-live-reload** | [`atom/dev-live-reload`][dev-live-reload] | [#17840](https://github.com/atom/atom/issues/17840) |
|
||||
| **encoding-selector** | [`atom/encoding-selector`][encoding-selector] | [#17841](https://github.com/atom/atom/issues/17841) |
|
||||
| **exception-reporting** | [`atom/exception-reporting`][exception-reporting] | [#17842](https://github.com/atom/atom/issues/17842) |
|
||||
| **find-and-replace** | [`atom/find-and-replace`][find-and-replace] | |
|
||||
| **fuzzy-finder** | [`atom/fuzzy-finder`][fuzzy-finder] | |
|
||||
| **github** | [`atom/github`][github] | |
|
||||
| **git-diff** | [`atom/git-diff`][git-diff] | [#17843](https://github.com/atom/atom/issues/17843) |
|
||||
| **go-to-line** | [`atom/go-to-line`][go-to-line] | [#17844](https://github.com/atom/atom/issues/17844) |
|
||||
| **grammar-selector** | [`atom/grammar-selector`][grammar-selector] | [#17845](https://github.com/atom/atom/issues/17845) |
|
||||
| **image-view** | [`atom/image-view`][image-view] | |
|
||||
| **incompatible-packages** | [`atom/incompatible-packages`][incompatible-packages] | [#17846](https://github.com/atom/atom/issues/17846) |
|
||||
| **keybinding-resolver** | [`atom/keybinding-resolver`][keybinding-resolver] | |
|
||||
| **language-c** | [`atom/language-c`][language-c] | |
|
||||
| **language-clojure** | [`atom/language-clojure`][language-clojure] | |
|
||||
| **language-coffee-script** | [`atom/language-coffee-script`][language-coffee-script] | |
|
||||
| **language-csharp** | [`atom/language-csharp`][language-csharp] | |
|
||||
| **language-css** | [`atom/language-css`][language-css] | |
|
||||
| **language-gfm** | [`atom/language-gfm`][language-gfm] | |
|
||||
| **language-git** | [`atom/language-git`][language-git] | |
|
||||
| **language-go** | [`atom/language-go`][language-go] | |
|
||||
| **language-html** | [`atom/language-html`][language-html] | |
|
||||
| **language-hyperlink** | [`atom/language-hyperlink`][language-hyperlink] | |
|
||||
| **language-java** | [`atom/language-java`][language-java] | |
|
||||
| **language-javascript** | [`atom/language-javascript`][language-javascript] | |
|
||||
| **language-json** | [`atom/language-json`][language-json] | |
|
||||
| **language-less** | [`atom/language-less`][language-less] | |
|
||||
| **language-make** | [`atom/language-make`][language-make] | |
|
||||
| **language-mustache** | [`atom/language-mustache`][language-mustache] | |
|
||||
| **language-objective-c** | [`atom/language-objective-c`][language-objective-c] | |
|
||||
| **language-perl** | [`atom/language-perl`][language-perl] | |
|
||||
| **language-php** | [`atom/language-php`][language-php] | |
|
||||
| **language-property-list** | [`atom/language-property-list`][language-property-list] | |
|
||||
| **language-python** | [`atom/language-python`][language-python] | |
|
||||
| **language-ruby** | [`atom/language-ruby`][language-ruby] | |
|
||||
| **language-ruby-on-rails** | [`atom/language-ruby-on-rails`][language-ruby-on-rails] | |
|
||||
| **language-sass** | [`atom/language-sass`][language-sass] | |
|
||||
| **language-shellscript** | [`atom/language-shellscript`][language-shellscript] | |
|
||||
| **language-source** | [`atom/language-source`][language-source] | |
|
||||
| **language-sql** | [`atom/language-sql`][language-sql] | |
|
||||
| **language-text** | [`atom/language-text`][language-text] | |
|
||||
| **language-todo** | [`atom/language-todo`][language-todo] | |
|
||||
| **language-toml** | [`atom/language-toml`][language-toml] | |
|
||||
| **language-typescript** | [`atom/language-typescript`][language-typescript] | |
|
||||
| **language-xml** | [`atom/language-xml`][language-xml] | |
|
||||
| **language-yaml** | [`atom/language-yaml`][language-yaml] | |
|
||||
| **line-ending-selector** | [`atom/line-ending-selector`][line-ending-selector] | [#17847](https://github.com/atom/atom/issues/17847) |
|
||||
| **link** | [`atom/link`][link] | [#17848](https://github.com/atom/atom/issues/17848) |
|
||||
| **markdown-preview** | [`atom/markdown-preview`][markdown-preview] | |
|
||||
| **metrics** | [`atom/metrics`][metrics] | |
|
||||
| **notifications** | [`atom/notifications`][notifications] | |
|
||||
| **one-dark-syntax** | [`atom/one-dark-syntax`][one-dark-syntax] | [#17853](https://github.com/atom/atom/issues/17853) |
|
||||
| **one-dark-ui** | [`atom/one-dark-ui`][one-dark-ui] | [#17854](https://github.com/atom/atom/issues/17854) |
|
||||
| **one-light-syntax** | [`atom/one-light-syntax`][one-light-syntax] | [#17855](https://github.com/atom/atom/issues/17855) |
|
||||
| **one-light-ui** | [`atom/one-light-ui`][one-light-ui] | |
|
||||
| **open-on-github** | [`atom/open-on-github`][open-on-github] | |
|
||||
| **package-generator** | [`atom/package-generator`][package-generator] | |
|
||||
| **settings-view** | [`atom/settings-view`][settings-view] | |
|
||||
| **snippets** | [`atom/snippets`][snippets] | |
|
||||
| **solarized-dark-syntax** | [`atom/solarized-dark-syntax`][solarized-dark-syntax] | |
|
||||
| **solarized-light-syntax** | [`atom/solarized-light-syntax`][solarized-light-syntax] | |
|
||||
| **spell-check** | [`atom/spell-check`][spell-check] | |
|
||||
| **status-bar** | [`atom/status-bar`][status-bar] | |
|
||||
| **styleguide** | [`atom/styleguide`][styleguide] | |
|
||||
| **symbols-view** | [`atom/symbols-view`][symbols-view] | |
|
||||
| **tabs** | [`atom/tabs`][tabs] | |
|
||||
| **timecop** | [`atom/timecop`][timecop] | |
|
||||
| **tree-view** | [`atom/tree-view`][tree-view] | |
|
||||
| **update-package-dependencies** | [`atom/update-package-dependencies`][update-package-dependencies] | |
|
||||
| **welcome** | [`atom/welcome`][welcome] | |
|
||||
| **whitespace** | [`atom/whitespace`][whitespace] | |
|
||||
| **wrap-guide** | [`atom/wrap-guide`][wrap-guide] | |
|
||||
|
||||
[about]: https://github.com/atom/about
|
||||
[archive-view]: https://github.com/atom/archive-view
|
||||
[atom-dark-syntax]: https://github.com/atom/atom-dark-syntax
|
||||
[atom-dark-ui]: https://github.com/atom/atom-dark-ui
|
||||
[atom-light-syntax]: https://github.com/atom/atom-light-syntax
|
||||
[atom-light-ui]: https://github.com/atom/atom-light-ui
|
||||
[autocomplete-atom-api]: https://github.com/atom/autocomplete-atom-api
|
||||
[autocomplete-css]: https://github.com/atom/autocomplete-css
|
||||
[autocomplete-html]: https://github.com/atom/autocomplete-html
|
||||
[autocomplete-plus]: https://github.com/atom/autocomplete-plus
|
||||
[autocomplete-snippets]: https://github.com/atom/autocomplete-snippets
|
||||
[autoflow]: https://github.com/atom/autoflow
|
||||
[autosave]: https://github.com/atom/autosave
|
||||
[background-tips]: https://github.com/atom/background-tips
|
||||
[base16-tomorrow-dark-theme]: https://github.com/atom/base16-tomorrow-dark-theme
|
||||
[base16-tomorrow-light-theme]: https://github.com/atom/base16-tomorrow-light-theme
|
||||
[bookmarks]: https://github.com/atom/bookmarks
|
||||
[bracket-matcher]: https://github.com/atom/bracket-matcher
|
||||
[command-palette]: https://github.com/atom/command-palette
|
||||
[dalek]: https://github.com/atom/dalek
|
||||
[deprecation-cop]: https://github.com/atom/deprecation-cop
|
||||
[dev-live-reload]: https://github.com/atom/dev-live-reload
|
||||
[encoding-selector]: https://github.com/atom/encoding-selector
|
||||
[exception-reporting]: https://github.com/atom/exception-reporting
|
||||
[find-and-replace]: https://github.com/atom/find-and-replace
|
||||
[fuzzy-finder]: https://github.com/atom/fuzzy-finder
|
||||
[git-diff]: https://github.com/atom/git-diff
|
||||
[github]: https://github.com/atom/github
|
||||
[go-to-line]: https://github.com/atom/go-to-line
|
||||
[grammar-selector]: https://github.com/atom/grammar-selector
|
||||
[image-view]: https://github.com/atom/image-view
|
||||
[incompatible-packages]: https://github.com/atom/incompatible-packages
|
||||
[keybinding-resolver]: https://github.com/atom/keybinding-resolver
|
||||
[language-c]: https://github.com/atom/language-c
|
||||
[language-clojure]: https://github.com/atom/language-clojure
|
||||
[language-coffee-script]: https://github.com/atom/language-coffee-script
|
||||
[language-csharp]: https://github.com/atom/language-csharp
|
||||
[language-css]: https://github.com/atom/language-css
|
||||
[language-gfm]: https://github.com/atom/language-gfm
|
||||
[language-git]: https://github.com/atom/language-git
|
||||
[language-go]: https://github.com/atom/language-go
|
||||
[language-html]: https://github.com/atom/language-html
|
||||
[language-hyperlink]: https://github.com/atom/language-hyperlink
|
||||
[language-java]: https://github.com/atom/language-java
|
||||
[language-javascript]: https://github.com/atom/language-javascript
|
||||
[language-json]: https://github.com/atom/language-json
|
||||
[language-less]: https://github.com/atom/language-less
|
||||
[language-make]: https://github.com/atom/language-make
|
||||
[language-mustache]: https://github.com/atom/language-mustache
|
||||
[language-objective-c]: https://github.com/atom/language-objective-c
|
||||
[language-perl]: https://github.com/atom/language-perl
|
||||
[language-php]: https://github.com/atom/language-php
|
||||
[language-property-list]: https://github.com/atom/language-property-list
|
||||
[language-python]: https://github.com/atom/language-python
|
||||
[language-ruby]: https://github.com/atom/language-ruby
|
||||
[language-ruby-on-rails]: https://github.com/atom/language-ruby-on-rails
|
||||
[language-sass]: https://github.com/atom/language-sass
|
||||
[language-shellscript]: https://github.com/atom/language-shellscript
|
||||
[language-source]: https://github.com/atom/language-source
|
||||
[language-sql]: https://github.com/atom/language-sql
|
||||
[language-text]: https://github.com/atom/language-text
|
||||
[language-todo]: https://github.com/atom/language-todo
|
||||
[language-toml]: https://github.com/atom/language-toml
|
||||
[language-typescript]: https://github.com/atom/language-typescript
|
||||
[language-xml]: https://github.com/atom/language-xml
|
||||
[language-yaml]: https://github.com/atom/language-yaml
|
||||
[line-ending-selector]: https://github.com/atom/line-ending-selector
|
||||
[link]: https://github.com/atom/link
|
||||
[markdown-preview]: https://github.com/atom/markdown-preview
|
||||
[metrics]: https://github.com/atom/metrics
|
||||
[notifications]: https://github.com/atom/notifications
|
||||
[one-dark-syntax]: https://github.com/atom/one-dark-syntax
|
||||
[one-dark-ui]: https://github.com/atom/one-dark-ui
|
||||
[one-light-syntax]: https://github.com/atom/one-light-syntax
|
||||
[one-light-ui]: https://github.com/atom/one-light-ui
|
||||
[open-on-github]: https://github.com/atom/open-on-github
|
||||
[package-generator]: https://github.com/atom/package-generator
|
||||
[settings-view]: https://github.com/atom/settings-view
|
||||
[snippets]: https://github.com/atom/snippets
|
||||
[solarized-dark-syntax]: https://github.com/atom/solarized-dark-syntax
|
||||
[solarized-light-syntax]: https://github.com/atom/solarized-light-syntax
|
||||
[spell-check]: https://github.com/atom/spell-check
|
||||
[status-bar]: https://github.com/atom/status-bar
|
||||
[styleguide]: https://github.com/atom/styleguide
|
||||
[symbols-view]: https://github.com/atom/symbols-view
|
||||
[tabs]: https://github.com/atom/tabs
|
||||
[timecop]: https://github.com/atom/timecop
|
||||
[tree-view]: https://github.com/atom/tree-view
|
||||
[update-package-dependencies]: https://github.com/atom/update-package-dependencies
|
||||
[welcome]: https://github.com/atom/welcome
|
||||
[whitespace]: https://github.com/atom/whitespace
|
||||
[wrap-guide]: https://github.com/atom/wrap-guide
|
||||
3
packages/about/.gitignore
vendored
Normal file
3
packages/about/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
.DS_Store
|
||||
npm-debug.log
|
||||
node_modules
|
||||
20
packages/about/LICENSE.md
Normal file
20
packages/about/LICENSE.md
Normal file
@@ -0,0 +1,20 @@
|
||||
Copyright (c) 2015 Machisté N. Quintana
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
21
packages/about/README.md
Normal file
21
packages/about/README.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# About package
|
||||
|
||||
View useful information about your Atom installation.
|
||||
|
||||

|
||||
|
||||
This is a package for [Atom](https://atom.io), a hackable text editor for the 21st Century.
|
||||
|
||||
## Usage
|
||||
|
||||
This package provides a cross-platform "About Atom" view that displays information about your Atom installation, which currently includes the current version, the license, and the Terms of Use.
|
||||
|
||||
## Contributing
|
||||
Always feel free to help out! Whether it's filing bugs and feature requests
|
||||
or working on some of the open issues, Atom's [contributing guide](https://github.com/atom/atom/blob/master/CONTRIBUTING.md)
|
||||
will help get you started while the [guide for contributing to packages](https://github.com/atom/atom/blob/master/docs/contributing-to-packages.md)
|
||||
has some extra information.
|
||||
|
||||
## License
|
||||
|
||||
[MIT License](https://opensource.org/licenses/MIT) - see the [LICENSE](https://github.com/atom/about/blob/master/LICENSE.md) for more details.
|
||||
93
packages/about/lib/about.js
Normal file
93
packages/about/lib/about.js
Normal file
@@ -0,0 +1,93 @@
|
||||
const {CompositeDisposable, Emitter} = require('atom')
|
||||
const AboutView = require('./components/about-view')
|
||||
|
||||
// Deferred requires
|
||||
let shell
|
||||
|
||||
module.exports = class About {
|
||||
constructor (initialState) {
|
||||
this.subscriptions = new CompositeDisposable()
|
||||
this.emitter = new Emitter()
|
||||
|
||||
this.state = initialState
|
||||
this.views = {
|
||||
aboutView: null
|
||||
}
|
||||
|
||||
this.subscriptions.add(atom.workspace.addOpener((uriToOpen) => {
|
||||
if (uriToOpen === this.state.uri) {
|
||||
return this.deserialize()
|
||||
}
|
||||
}))
|
||||
|
||||
this.subscriptions.add(atom.commands.add('atom-workspace', 'about:view-release-notes', () => {
|
||||
shell = shell || require('electron').shell
|
||||
shell.openExternal(this.state.updateManager.getReleaseNotesURLForCurrentVersion())
|
||||
}))
|
||||
}
|
||||
|
||||
destroy () {
|
||||
if (this.views.aboutView) this.views.aboutView.destroy()
|
||||
this.views.aboutView = null
|
||||
|
||||
if (this.state.updateManager) this.state.updateManager.dispose()
|
||||
this.setState({updateManager: null})
|
||||
|
||||
this.subscriptions.dispose()
|
||||
}
|
||||
|
||||
setState (newState) {
|
||||
if (newState && typeof newState === 'object') {
|
||||
let {state} = this
|
||||
this.state = Object.assign({}, state, newState)
|
||||
|
||||
this.didChange()
|
||||
}
|
||||
}
|
||||
|
||||
didChange () {
|
||||
this.emitter.emit('did-change')
|
||||
}
|
||||
|
||||
onDidChange (callback) {
|
||||
this.emitter.on('did-change', callback)
|
||||
}
|
||||
|
||||
deserialize (state) {
|
||||
if (!this.views.aboutView) {
|
||||
this.setState(state)
|
||||
|
||||
this.views.aboutView = new AboutView({
|
||||
uri: this.state.uri,
|
||||
updateManager: this.state.updateManager,
|
||||
currentAtomVersion: this.state.currentAtomVersion,
|
||||
currentElectronVersion: this.state.currentElectronVersion,
|
||||
currentChromeVersion: this.state.currentChromeVersion,
|
||||
currentNodeVersion: this.state.currentNodeVersion,
|
||||
availableVersion: this.state.updateManager.getAvailableVersion()
|
||||
})
|
||||
this.handleStateChanges()
|
||||
}
|
||||
|
||||
return this.views.aboutView
|
||||
}
|
||||
|
||||
handleStateChanges () {
|
||||
this.onDidChange(() => {
|
||||
if (this.views.aboutView) {
|
||||
this.views.aboutView.update({
|
||||
updateManager: this.state.updateManager,
|
||||
currentAtomVersion: this.state.currentAtomVersion,
|
||||
currentElectronVersion: this.state.currentElectronVersion,
|
||||
currentChromeVersion: this.state.currentChromeVersion,
|
||||
currentNodeVersion: this.state.currentNodeVersion,
|
||||
availableVersion: this.state.updateManager.getAvailableVersion()
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
this.state.updateManager.onDidChange(() => {
|
||||
this.didChange()
|
||||
})
|
||||
}
|
||||
}
|
||||
30
packages/about/lib/components/about-status-bar.js
Normal file
30
packages/about/lib/components/about-status-bar.js
Normal file
@@ -0,0 +1,30 @@
|
||||
const {CompositeDisposable} = require('atom')
|
||||
const etch = require('etch')
|
||||
const EtchComponent = require('../etch-component')
|
||||
|
||||
const $ = etch.dom
|
||||
|
||||
module.exports =
|
||||
class AboutStatusBar extends EtchComponent {
|
||||
constructor () {
|
||||
super()
|
||||
this.subscriptions = new CompositeDisposable()
|
||||
|
||||
this.subscriptions.add(atom.tooltips.add(this.element, {title: 'An update will be installed the next time Atom is relaunched.<br/><br/>Click the squirrel icon for more information.'}))
|
||||
}
|
||||
|
||||
handleClick () {
|
||||
atom.workspace.open('atom://about')
|
||||
}
|
||||
|
||||
render () {
|
||||
return $.div({className: 'about-release-notes inline-block', onclick: this.handleClick.bind(this)},
|
||||
$.span({type: 'button', className: 'icon icon-squirrel'})
|
||||
)
|
||||
}
|
||||
|
||||
destroy () {
|
||||
super.destroy()
|
||||
this.subscriptions.dispose()
|
||||
}
|
||||
}
|
||||
159
packages/about/lib/components/about-view.js
Normal file
159
packages/about/lib/components/about-view.js
Normal file
@@ -0,0 +1,159 @@
|
||||
const {Disposable} = require('atom')
|
||||
const etch = require('etch')
|
||||
const shell = require('shell')
|
||||
const AtomLogo = require('./atom-logo')
|
||||
const EtchComponent = require('../etch-component')
|
||||
const UpdateView = require('./update-view')
|
||||
|
||||
const $ = etch.dom
|
||||
|
||||
module.exports =
|
||||
class AboutView extends EtchComponent {
|
||||
handleAtomVersionClick (e) {
|
||||
e.preventDefault()
|
||||
atom.clipboard.write(this.props.currentAtomVersion)
|
||||
}
|
||||
|
||||
handleElectronVersionClick (e) {
|
||||
e.preventDefault()
|
||||
atom.clipboard.write(this.props.currentElectronVersion)
|
||||
}
|
||||
|
||||
handleChromeVersionClick (e) {
|
||||
e.preventDefault()
|
||||
atom.clipboard.write(this.props.currentChromeVersion)
|
||||
}
|
||||
|
||||
handleNodeVersionClick (e) {
|
||||
e.preventDefault()
|
||||
atom.clipboard.write(this.props.currentNodeVersion)
|
||||
}
|
||||
|
||||
handleReleaseNotesClick (e) {
|
||||
e.preventDefault()
|
||||
shell.openExternal(this.props.updateManager.getReleaseNotesURLForAvailableVersion())
|
||||
}
|
||||
|
||||
handleLicenseClick (e) {
|
||||
e.preventDefault()
|
||||
atom.commands.dispatch(atom.views.getView(atom.workspace), 'application:open-license')
|
||||
}
|
||||
|
||||
handleTermsOfUseClick (e) {
|
||||
e.preventDefault()
|
||||
shell.openExternal('https://atom.io/terms')
|
||||
}
|
||||
|
||||
handleHowToUpdateClick (e) {
|
||||
e.preventDefault()
|
||||
shell.openExternal('https://flight-manual.atom.io/getting-started/sections/installing-atom/')
|
||||
}
|
||||
|
||||
handleShowMoreClick (e) {
|
||||
e.preventDefault()
|
||||
var showMoreDiv = document.querySelector('.show-more')
|
||||
var showMoreText = document.querySelector('.about-more-expand')
|
||||
switch (showMoreText.textContent) {
|
||||
case 'Show more':
|
||||
showMoreDiv.classList.toggle('hidden')
|
||||
showMoreText.textContent = 'Hide'
|
||||
break
|
||||
case 'Hide':
|
||||
showMoreDiv.classList.toggle('hidden')
|
||||
showMoreText.textContent = 'Show more'
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
return $.div({className: 'pane-item native-key-bindings about'},
|
||||
$.div({className: 'about-container'},
|
||||
$.header({className: 'about-header'},
|
||||
$.a({className: 'about-atom-io', href: 'https://atom.io'},
|
||||
$(AtomLogo)
|
||||
),
|
||||
$.div({className: 'about-header-info'},
|
||||
$.span({className: 'about-version-container inline-block atom', onclick: this.handleAtomVersionClick.bind(this)},
|
||||
$.span({className: 'about-version'}, `${this.props.currentAtomVersion} ${process.arch}`),
|
||||
$.span({className: 'icon icon-clippy about-copy-version'})
|
||||
),
|
||||
$.a({className: 'about-header-release-notes', onclick: this.handleReleaseNotesClick.bind(this)}, 'Release Notes')
|
||||
),
|
||||
$.span({className: 'about-version-container inline-block show-more-expand', onclick: this.handleShowMoreClick.bind(this)},
|
||||
$.span({className: 'about-more-expand'}, 'Show more')
|
||||
),
|
||||
$.div({className: 'show-more hidden about-more-info'},
|
||||
$.div({className: 'about-more-info'},
|
||||
$.span({className: 'about-version-container inline-block electron', onclick: this.handleElectronVersionClick.bind(this)},
|
||||
$.span({className: 'about-more-version'}, `Electron: ${this.props.currentElectronVersion} `),
|
||||
$.span({className: 'icon icon-clippy about-copy-version'})
|
||||
)
|
||||
),
|
||||
$.div({className: 'about-more-info'},
|
||||
$.span({className: 'about-version-container inline-block chrome', onclick: this.handleChromeVersionClick.bind(this)},
|
||||
$.span({className: 'about-more-version'}, `Chrome: ${this.props.currentChromeVersion} `),
|
||||
$.span({className: 'icon icon-clippy about-copy-version'})
|
||||
)
|
||||
),
|
||||
$.div({className: 'about-more-info'},
|
||||
$.span({className: 'about-version-container inline-block node', onclick: this.handleNodeVersionClick.bind(this)},
|
||||
$.span({className: 'about-more-version'}, `Node: ${this.props.currentNodeVersion} `),
|
||||
$.span({className: 'icon icon-clippy about-copy-version'})
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
$(UpdateView, {
|
||||
updateManager: this.props.updateManager,
|
||||
availableVersion: this.props.availableVersion,
|
||||
viewUpdateReleaseNotes: this.handleReleaseNotesClick.bind(this),
|
||||
viewUpdateInstructions: this.handleHowToUpdateClick.bind(this)
|
||||
}),
|
||||
|
||||
$.div({className: 'about-actions group-item'},
|
||||
$.div({className: 'btn-group'},
|
||||
$.button({className: 'btn view-license', onclick: this.handleLicenseClick.bind(this)}, 'License'),
|
||||
$.button({className: 'btn terms-of-use', onclick: this.handleTermsOfUseClick.bind(this)}, 'Terms of Use')
|
||||
)
|
||||
),
|
||||
|
||||
$.div({className: 'about-love group-start'},
|
||||
$.span({className: 'icon icon-code'}),
|
||||
$.span({className: 'inline'}, ' with '),
|
||||
$.span({className: 'icon icon-heart'}),
|
||||
$.span({className: 'inline'}, ' by '),
|
||||
$.a({className: 'icon icon-logo-github', href: 'https://github.com'})
|
||||
),
|
||||
|
||||
$.div({className: 'about-credits group-item'},
|
||||
$.span({className: 'inline'}, 'And the awesome '),
|
||||
$.a({href: 'https://github.com/atom/atom/contributors'}, 'Atom Community')
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
serialize () {
|
||||
return {
|
||||
deserializer: this.constructor.name,
|
||||
uri: this.props.uri
|
||||
}
|
||||
}
|
||||
|
||||
onDidChangeTitle () {
|
||||
return new Disposable()
|
||||
}
|
||||
|
||||
onDidChangeModified () {
|
||||
return new Disposable()
|
||||
}
|
||||
|
||||
getTitle () {
|
||||
return 'About'
|
||||
}
|
||||
|
||||
getIconName () {
|
||||
return 'info'
|
||||
}
|
||||
}
|
||||
28
packages/about/lib/components/atom-logo.js
Normal file
28
packages/about/lib/components/atom-logo.js
Normal file
@@ -0,0 +1,28 @@
|
||||
const etch = require('etch')
|
||||
const EtchComponent = require('../etch-component')
|
||||
|
||||
const $ = etch.dom
|
||||
|
||||
module.exports =
|
||||
class AtomLogo extends EtchComponent {
|
||||
render () {
|
||||
return $.svg({className: 'about-logo', width: '330px', height: '68px', viewBox: '0 0 330 68'},
|
||||
$.g({stroke: 'none', 'stroke-width': '1', fill: 'none', 'fill-rule': 'evenodd'},
|
||||
$.g({transform: 'translate(2.000000, 1.000000)'},
|
||||
$.g({transform: 'translate(96.000000, 8.000000)', fill: 'currentColor'},
|
||||
$.path({d: 'M185.498,3.399 C185.498,2.417 186.34,1.573 187.324,1.573 L187.674,1.573 C188.447,1.573 189.01,1.995 189.5,2.628 L208.676,30.862 L227.852,2.628 C228.272,1.995 228.905,1.573 229.676,1.573 L230.028,1.573 C231.01,1.573 231.854,2.417 231.854,3.399 L231.854,49.403 C231.854,50.387 231.01,51.231 230.028,51.231 C229.044,51.231 228.202,50.387 228.202,49.403 L228.202,8.246 L210.151,34.515 C209.729,35.148 209.237,35.428 208.606,35.428 C207.973,35.428 207.481,35.148 207.061,34.515 L189.01,8.246 L189.01,49.475 C189.01,50.457 188.237,51.231 187.254,51.231 C186.27,51.231 185.498,50.458 185.498,49.475 L185.498,3.399 L185.498,3.399 Z'}),
|
||||
$.path({d: 'M113.086,26.507 L113.086,26.367 C113.086,12.952 122.99,0.941 137.881,0.941 C152.77,0.941 162.533,12.811 162.533,26.225 L162.533,26.367 C162.533,39.782 152.629,51.792 137.74,51.792 C122.85,51.792 113.086,39.923 113.086,26.507 M158.74,26.507 L158.74,26.367 C158.74,14.216 149.89,4.242 137.74,4.242 C125.588,4.242 116.879,14.075 116.879,26.225 L116.879,26.367 C116.879,38.518 125.729,48.491 137.881,48.491 C150.031,48.491 158.74,38.658 158.74,26.507'}),
|
||||
$.path({d: 'M76.705,5.155 L60.972,5.155 C60.06,5.155 59.287,4.384 59.287,3.469 C59.287,2.556 60.059,1.783 60.972,1.783 L96.092,1.783 C97.004,1.783 97.778,2.555 97.778,3.469 C97.778,4.383 97.005,5.155 96.092,5.155 L80.358,5.155 L80.358,49.405 C80.358,50.387 79.516,51.231 78.532,51.231 C77.55,51.231 76.706,50.387 76.706,49.405 L76.706,5.155 L76.705,5.155 Z'}),
|
||||
$.path({d: 'M0.291,48.562 L21.291,3.05 C21.783,1.995 22.485,1.292 23.75,1.292 L23.891,1.292 C25.155,1.292 25.858,1.995 26.348,3.05 L47.279,48.421 C47.49,48.843 47.56,49.194 47.56,49.546 C47.56,50.458 46.788,51.231 45.803,51.231 C44.961,51.231 44.329,50.599 43.978,49.826 L38.219,37.183 L9.21,37.183 L3.45,49.897 C3.099,50.739 2.538,51.231 1.694,51.231 C0.781,51.231 0.008,50.529 0.008,49.685 C0.009,49.404 0.08,48.983 0.291,48.562 L0.291,48.562 Z M36.673,33.882 L23.749,5.437 L10.755,33.882 L36.673,33.882 L36.673,33.882 Z'})
|
||||
),
|
||||
$.g({},
|
||||
$.path({d: 'M40.363,32.075 C40.874,34.44 39.371,36.77 37.006,37.282 C34.641,37.793 32.311,36.29 31.799,33.925 C31.289,31.56 32.791,29.23 35.156,28.718 C37.521,28.207 39.851,29.71 40.363,32.075', fill: 'currentColor'}),
|
||||
$.path({d: 'M48.578,28.615 C56.851,45.587 58.558,61.581 52.288,64.778 C45.822,68.076 33.326,56.521 24.375,38.969 C15.424,21.418 13.409,4.518 19.874,1.221 C22.689,-0.216 26.648,1.166 30.959,4.629', stroke: 'currentColor', 'stroke-width': '3.08', 'stroke-linecap': 'round'}),
|
||||
$.path({d: 'M7.64,39.45 C2.806,36.94 -0.009,33.915 0.154,30.79 C0.531,23.542 16.787,18.497 36.462,19.52 C56.137,20.544 71.781,27.249 71.404,34.497 C71.241,37.622 68.127,40.338 63.06,42.333', stroke: 'currentColor', 'stroke-width': '3.08', 'stroke-linecap': 'round'}),
|
||||
$.path({d: 'M28.828,59.354 C23.545,63.168 18.843,64.561 15.902,62.653 C9.814,58.702 13.572,42.102 24.296,25.575 C35.02,9.048 48.649,-1.149 54.736,2.803 C57.566,4.639 58.269,9.208 57.133,15.232', stroke: 'currentColor', 'stroke-width': '3.08', 'stroke-linecap': 'round'})
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
121
packages/about/lib/components/update-view.js
Normal file
121
packages/about/lib/components/update-view.js
Normal file
@@ -0,0 +1,121 @@
|
||||
const etch = require('etch')
|
||||
const EtchComponent = require('../etch-component')
|
||||
const UpdateManager = require('../update-manager')
|
||||
|
||||
const $ = etch.dom
|
||||
|
||||
module.exports =
|
||||
class UpdateView extends EtchComponent {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
|
||||
if (this.props.updateManager.getAutoUpdatesEnabled() && this.props.updateManager.getState() === UpdateManager.State.Idle) {
|
||||
this.props.updateManager.checkForUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
handleAutoUpdateCheckbox (e) {
|
||||
atom.config.set('core.automaticallyUpdate', e.target.checked)
|
||||
}
|
||||
|
||||
shouldUpdateActionButtonBeDisabled () {
|
||||
let {state} = this.props.updateManager
|
||||
return state === UpdateManager.State.CheckingForUpdate || state === UpdateManager.State.DownloadingUpdate
|
||||
}
|
||||
|
||||
executeUpdateAction () {
|
||||
if (this.props.updateManager.state === UpdateManager.State.UpdateAvailableToInstall) {
|
||||
this.props.updateManager.restartAndInstallUpdate()
|
||||
} else {
|
||||
this.props.updateManager.checkForUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
renderUpdateStatus () {
|
||||
let updateStatus = ''
|
||||
|
||||
switch (this.props.updateManager.state) {
|
||||
case UpdateManager.State.Idle:
|
||||
updateStatus = $.div({className: 'about-updates-item is-shown about-default-update-message'},
|
||||
this.props.updateManager.getAutoUpdatesEnabled() ? 'Atom will check for updates automatically' : 'Automatic updates are disabled please check manually'
|
||||
)
|
||||
break
|
||||
case UpdateManager.State.CheckingForUpdate:
|
||||
updateStatus = $.div({className: 'about-updates-item app-checking-for-updates'},
|
||||
$.span({className: 'about-updates-label icon icon-search'}, 'Checking for updates...')
|
||||
)
|
||||
break
|
||||
case UpdateManager.State.DownloadingUpdate:
|
||||
updateStatus = $.div({className: 'about-updates-item app-downloading-update'},
|
||||
$.span({className: 'loading loading-spinner-tiny inline-block'}),
|
||||
$.span({className: 'about-updates-label'}, 'Downloading update')
|
||||
)
|
||||
break
|
||||
case UpdateManager.State.UpdateAvailableToInstall:
|
||||
updateStatus = $.div({className: 'about-updates-item app-update-available-to-install'},
|
||||
$.span({className: 'about-updates-label icon icon-squirrel'}, 'New update'),
|
||||
$.span({className: 'about-updates-version'}, this.props.availableVersion),
|
||||
$.a({className: 'about-updates-release-notes', onclick: this.props.viewUpdateReleaseNotes}, 'Release Notes')
|
||||
)
|
||||
break
|
||||
case UpdateManager.State.UpToDate:
|
||||
updateStatus = $.div({className: 'about-updates-item app-up-to-date'},
|
||||
$.span({className: 'icon icon-check'}),
|
||||
$.span({className: 'about-updates-label is-strong'}, 'Atom is up to date!')
|
||||
)
|
||||
break
|
||||
case UpdateManager.State.Unsupported:
|
||||
updateStatus = $.div({className: 'about-updates-item app-unsupported'},
|
||||
$.span({className: 'about-updates-label is-strong'}, 'Your system does not support automatic updates'),
|
||||
$.a({className: 'about-updates-instructions', onclick: this.props.viewUpdateInstructions}, 'How to update')
|
||||
)
|
||||
break
|
||||
case UpdateManager.State.Error:
|
||||
updateStatus = $.div({className: 'about-updates-item app-update-error'},
|
||||
$.span({className: 'icon icon-x'}),
|
||||
$.span({className: 'about-updates-label app-error-message is-strong'}, this.props.updateManager.getErrorMessage())
|
||||
)
|
||||
break
|
||||
}
|
||||
|
||||
return updateStatus
|
||||
}
|
||||
|
||||
render () {
|
||||
return $.div({className: 'about-updates group-start'},
|
||||
$.div({className: 'about-updates-box'},
|
||||
$.div({className: 'about-updates-status'}, this.renderUpdateStatus()),
|
||||
$.button(
|
||||
{
|
||||
className: 'btn about-update-action-button',
|
||||
disabled: this.shouldUpdateActionButtonBeDisabled(),
|
||||
onclick: this.executeUpdateAction.bind(this),
|
||||
style: {
|
||||
display: this.props.updateManager.state === UpdateManager.State.Unsupported ? 'none' : 'block'
|
||||
}
|
||||
},
|
||||
this.props.updateManager.state === 'update-available' ? 'Restart and install' : 'Check now'
|
||||
)
|
||||
),
|
||||
$.div(
|
||||
{
|
||||
className: 'about-auto-updates',
|
||||
style: {
|
||||
display: this.props.updateManager.state === UpdateManager.State.Unsupported ? 'none' : 'block'
|
||||
}
|
||||
},
|
||||
$.label({},
|
||||
$.input(
|
||||
{
|
||||
className: 'input-checkbox',
|
||||
type: 'checkbox',
|
||||
checked: this.props.updateManager.getAutoUpdatesEnabled(),
|
||||
onchange: this.handleAutoUpdateCheckbox.bind(this)
|
||||
}
|
||||
),
|
||||
$.span({}, 'Automatically download updates')
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
57
packages/about/lib/etch-component.js
Normal file
57
packages/about/lib/etch-component.js
Normal file
@@ -0,0 +1,57 @@
|
||||
const etch = require('etch')
|
||||
|
||||
/*
|
||||
Public: Abstract class for handling the initialization
|
||||
boilerplate of an Etch component.
|
||||
*/
|
||||
module.exports =
|
||||
class EtchComponent {
|
||||
constructor (props) {
|
||||
this.props = props
|
||||
|
||||
etch.initialize(this)
|
||||
EtchComponent.setScheduler(atom.views)
|
||||
}
|
||||
|
||||
/*
|
||||
Public: Gets the scheduler Etch uses for coordinating DOM updates.
|
||||
|
||||
Returns a {Scheduler}
|
||||
*/
|
||||
static getScheduler () {
|
||||
return etch.getScheduler()
|
||||
}
|
||||
|
||||
/*
|
||||
Public: Sets the scheduler Etch uses for coordinating DOM updates.
|
||||
|
||||
* `scheduler` {Scheduler}
|
||||
*/
|
||||
static setScheduler (scheduler) {
|
||||
etch.setScheduler(scheduler)
|
||||
}
|
||||
|
||||
/*
|
||||
Public: Updates the component's properties and re-renders it. Only the
|
||||
properties you specify in this object will update – any other properties
|
||||
the component stores will be unaffected.
|
||||
|
||||
* `props` an {Object} representing the properties you want to update
|
||||
*/
|
||||
update (props) {
|
||||
let oldProps = this.props
|
||||
this.props = Object.assign({}, oldProps, props)
|
||||
return etch.update(this)
|
||||
}
|
||||
|
||||
/*
|
||||
Public: Destroys the component, removing it from the DOM.
|
||||
*/
|
||||
destroy () {
|
||||
etch.destroy(this)
|
||||
}
|
||||
|
||||
render () {
|
||||
throw new Error('Etch components must implement a `render` method')
|
||||
}
|
||||
}
|
||||
96
packages/about/lib/main.js
Normal file
96
packages/about/lib/main.js
Normal file
@@ -0,0 +1,96 @@
|
||||
const {CompositeDisposable} = require('atom')
|
||||
const semver = require('semver')
|
||||
const UpdateManager = require('./update-manager')
|
||||
const About = require('./about')
|
||||
const StatusBarView = require('./components/about-status-bar')
|
||||
let updateManager
|
||||
|
||||
// The local storage key for the available update version.
|
||||
const AvailableUpdateVersion = 'about:version-available'
|
||||
const AboutURI = 'atom://about'
|
||||
|
||||
module.exports = {
|
||||
activate () {
|
||||
this.subscriptions = new CompositeDisposable()
|
||||
|
||||
this.createModel()
|
||||
|
||||
let availableVersion = window.localStorage.getItem(AvailableUpdateVersion)
|
||||
if (atom.getReleaseChannel() === 'dev' || (availableVersion && semver.lte(availableVersion, atom.getVersion()))) {
|
||||
this.clearUpdateState()
|
||||
}
|
||||
|
||||
this.subscriptions.add(updateManager.onDidChange(() => {
|
||||
if (updateManager.getState() === UpdateManager.State.UpdateAvailableToInstall) {
|
||||
window.localStorage.setItem(AvailableUpdateVersion, updateManager.getAvailableVersion())
|
||||
this.showStatusBarIfNeeded()
|
||||
}
|
||||
}))
|
||||
|
||||
this.subscriptions.add(atom.commands.add('atom-workspace', 'about:clear-update-state', () => {
|
||||
this.clearUpdateState()
|
||||
}))
|
||||
},
|
||||
|
||||
deactivate () {
|
||||
this.model.destroy()
|
||||
if (this.statusBarTile) this.statusBarTile.destroy()
|
||||
|
||||
if (updateManager) {
|
||||
updateManager.dispose()
|
||||
updateManager = undefined
|
||||
}
|
||||
},
|
||||
|
||||
clearUpdateState () {
|
||||
window.localStorage.removeItem(AvailableUpdateVersion)
|
||||
},
|
||||
|
||||
consumeStatusBar (statusBar) {
|
||||
this.statusBar = statusBar
|
||||
this.showStatusBarIfNeeded()
|
||||
},
|
||||
|
||||
deserializeAboutView (state) {
|
||||
if (!this.model) {
|
||||
this.createModel()
|
||||
}
|
||||
|
||||
return this.model.deserialize(state)
|
||||
},
|
||||
|
||||
createModel () {
|
||||
updateManager = updateManager || new UpdateManager()
|
||||
|
||||
this.model = new About({
|
||||
uri: AboutURI,
|
||||
currentAtomVersion: atom.getVersion(),
|
||||
currentElectronVersion: process.versions.electron,
|
||||
currentChromeVersion: process.versions.chrome,
|
||||
currentNodeVersion: process.version,
|
||||
updateManager: updateManager
|
||||
})
|
||||
},
|
||||
|
||||
isUpdateAvailable () {
|
||||
let availableVersion = window.localStorage.getItem(AvailableUpdateVersion)
|
||||
return availableVersion && semver.gt(availableVersion, atom.getVersion())
|
||||
},
|
||||
|
||||
showStatusBarIfNeeded () {
|
||||
if (this.isUpdateAvailable() && this.statusBar) {
|
||||
let statusBarView = new StatusBarView()
|
||||
|
||||
if (this.statusBarTile) {
|
||||
this.statusBarTile.destroy()
|
||||
}
|
||||
|
||||
this.statusBarTile = this.statusBar.addRightTile({
|
||||
item: statusBarView,
|
||||
priority: -100
|
||||
})
|
||||
|
||||
return this.statusBarTile
|
||||
}
|
||||
}
|
||||
}
|
||||
146
packages/about/lib/update-manager.js
Normal file
146
packages/about/lib/update-manager.js
Normal file
@@ -0,0 +1,146 @@
|
||||
const {Emitter, CompositeDisposable} = require('atom')
|
||||
|
||||
const Unsupported = 'unsupported'
|
||||
const Idle = 'idle'
|
||||
const CheckingForUpdate = 'checking'
|
||||
const DownloadingUpdate = 'downloading'
|
||||
const UpdateAvailableToInstall = 'update-available'
|
||||
const UpToDate = 'no-update-available'
|
||||
const ErrorState = 'error'
|
||||
|
||||
let UpdateManager = class UpdateManager {
|
||||
constructor () {
|
||||
this.emitter = new Emitter()
|
||||
this.currentVersion = atom.getVersion()
|
||||
this.availableVersion = atom.getVersion()
|
||||
this.resetState()
|
||||
this.listenForAtomEvents()
|
||||
}
|
||||
|
||||
listenForAtomEvents () {
|
||||
this.subscriptions = new CompositeDisposable()
|
||||
|
||||
this.subscriptions.add(
|
||||
atom.autoUpdater.onDidBeginCheckingForUpdate(() => {
|
||||
this.setState(CheckingForUpdate)
|
||||
}),
|
||||
atom.autoUpdater.onDidBeginDownloadingUpdate(() => {
|
||||
this.setState(DownloadingUpdate)
|
||||
}),
|
||||
atom.autoUpdater.onDidCompleteDownloadingUpdate(({releaseVersion}) => {
|
||||
this.setAvailableVersion(releaseVersion)
|
||||
}),
|
||||
atom.autoUpdater.onUpdateNotAvailable(() => {
|
||||
this.setState(UpToDate)
|
||||
}),
|
||||
atom.autoUpdater.onUpdateError(() => {
|
||||
this.setState(ErrorState)
|
||||
}),
|
||||
atom.config.observe('core.automaticallyUpdate', (value) => {
|
||||
this.autoUpdatesEnabled = value
|
||||
this.emitDidChange()
|
||||
})
|
||||
)
|
||||
|
||||
// TODO: When https://github.com/atom/electron/issues/4587 is closed we can add this support.
|
||||
// atom.autoUpdater.onUpdateAvailable =>
|
||||
// @find('.about-updates-item').removeClass('is-shown')
|
||||
// @updateAvailable.addClass('is-shown')
|
||||
}
|
||||
|
||||
dispose () {
|
||||
this.subscriptions.dispose()
|
||||
}
|
||||
|
||||
onDidChange (callback) {
|
||||
return this.emitter.on('did-change', callback)
|
||||
}
|
||||
|
||||
emitDidChange () {
|
||||
this.emitter.emit('did-change')
|
||||
}
|
||||
|
||||
getAutoUpdatesEnabled () {
|
||||
return this.autoUpdatesEnabled && this.state !== UpdateManager.State.Unsupported
|
||||
}
|
||||
|
||||
setAutoUpdatesEnabled (enabled) {
|
||||
return atom.config.set('core.automaticallyUpdate', enabled)
|
||||
}
|
||||
|
||||
getErrorMessage () {
|
||||
return atom.autoUpdater.getErrorMessage()
|
||||
}
|
||||
|
||||
getState () {
|
||||
return this.state
|
||||
}
|
||||
|
||||
setState (state) {
|
||||
this.state = state
|
||||
this.emitDidChange()
|
||||
}
|
||||
|
||||
resetState () {
|
||||
this.state = atom.autoUpdater.platformSupportsUpdates() ? atom.autoUpdater.getState() : Unsupported
|
||||
this.emitDidChange()
|
||||
}
|
||||
|
||||
getAvailableVersion () {
|
||||
return this.availableVersion
|
||||
}
|
||||
|
||||
setAvailableVersion (version) {
|
||||
this.availableVersion = version
|
||||
|
||||
if (this.availableVersion !== this.currentVersion) {
|
||||
this.state = UpdateAvailableToInstall
|
||||
} else {
|
||||
this.state = UpToDate
|
||||
}
|
||||
|
||||
this.emitDidChange()
|
||||
}
|
||||
|
||||
checkForUpdate () {
|
||||
atom.autoUpdater.checkForUpdate()
|
||||
}
|
||||
|
||||
restartAndInstallUpdate () {
|
||||
atom.autoUpdater.restartAndInstallUpdate()
|
||||
}
|
||||
|
||||
getReleaseNotesURLForCurrentVersion () {
|
||||
return this.getReleaseNotesURLForVersion(this.currentVersion)
|
||||
}
|
||||
|
||||
getReleaseNotesURLForAvailableVersion () {
|
||||
return this.getReleaseNotesURLForVersion(this.availableVersion)
|
||||
}
|
||||
|
||||
getReleaseNotesURLForVersion (appVersion) {
|
||||
// Dev versions will not have a releases page
|
||||
if (appVersion.indexOf('dev') > -1) {
|
||||
return 'https://atom.io/releases'
|
||||
}
|
||||
|
||||
if (!appVersion.startsWith('v')) {
|
||||
appVersion = `v${appVersion}`
|
||||
}
|
||||
|
||||
const releaseRepo = appVersion.indexOf('nightly') > -1 ? 'atom-nightly-releases' : 'atom'
|
||||
return `https://github.com/atom/${releaseRepo}/releases/tag/${appVersion}`
|
||||
}
|
||||
}
|
||||
|
||||
UpdateManager.State = {
|
||||
Unsupported: Unsupported,
|
||||
Idle: Idle,
|
||||
CheckingForUpdate: CheckingForUpdate,
|
||||
DownloadingUpdate: DownloadingUpdate,
|
||||
UpdateAvailableToInstall: UpdateAvailableToInstall,
|
||||
UpToDate: UpToDate,
|
||||
Error: ErrorState
|
||||
}
|
||||
|
||||
module.exports = UpdateManager
|
||||
1806
packages/about/package-lock.json
generated
Normal file
1806
packages/about/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
44
packages/about/package.json
Normal file
44
packages/about/package.json
Normal file
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"name": "about",
|
||||
"author": "Machisté N. Quintana <mnquintana@users.noreply.github.com>",
|
||||
"main": "./lib/main",
|
||||
"version": "1.9.1",
|
||||
"description": "View useful information about your Atom installation.",
|
||||
"keywords": [],
|
||||
"repository": "https://github.com/atom/about",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"lint": "standard"
|
||||
},
|
||||
"engines": {
|
||||
"atom": ">=1.7 <2.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"etch": "0.9.0",
|
||||
"semver": "^5.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"standard": "^11.0.0"
|
||||
},
|
||||
"consumedServices": {
|
||||
"status-bar": {
|
||||
"versions": {
|
||||
"^1.0.0": "consumeStatusBar"
|
||||
}
|
||||
}
|
||||
},
|
||||
"deserializers": {
|
||||
"AboutView": "deserializeAboutView"
|
||||
},
|
||||
"standard": {
|
||||
"env": [
|
||||
"browser",
|
||||
"node",
|
||||
"atomtest",
|
||||
"jasmine"
|
||||
],
|
||||
"globals": [
|
||||
"atom"
|
||||
]
|
||||
}
|
||||
}
|
||||
101
packages/about/spec/about-spec.js
Normal file
101
packages/about/spec/about-spec.js
Normal file
@@ -0,0 +1,101 @@
|
||||
const {it, fit, ffit, fffit, beforeEach, afterEach} = require('./helpers/async-spec-helpers') // eslint-disable-line no-unused-vars
|
||||
|
||||
describe('About', () => {
|
||||
let workspaceElement
|
||||
|
||||
beforeEach(async () => {
|
||||
let storage = {}
|
||||
|
||||
spyOn(window.localStorage, 'setItem').andCallFake((key, value) => {
|
||||
storage[key] = value
|
||||
})
|
||||
spyOn(window.localStorage, 'getItem').andCallFake((key) => {
|
||||
return storage[key]
|
||||
})
|
||||
|
||||
workspaceElement = atom.views.getView(atom.workspace)
|
||||
await atom.packages.activatePackage('about')
|
||||
})
|
||||
|
||||
it('deserializes correctly', () => {
|
||||
let deserializedAboutView = atom.deserializers.deserialize({
|
||||
deserializer: 'AboutView',
|
||||
uri: 'atom://about'
|
||||
})
|
||||
|
||||
expect(deserializedAboutView).toBeTruthy()
|
||||
})
|
||||
|
||||
describe('when the about:about-atom command is triggered', () => {
|
||||
it('shows the About Atom view', async () => {
|
||||
// Attaching the workspaceElement to the DOM is required to allow the
|
||||
// `toBeVisible()` matchers to work. Anything testing visibility or focus
|
||||
// requires that the workspaceElement is on the DOM. Tests that attach the
|
||||
// workspaceElement to the DOM are generally slower than those off DOM.
|
||||
jasmine.attachToDOM(workspaceElement)
|
||||
|
||||
expect(workspaceElement.querySelector('.about')).not.toExist()
|
||||
await atom.workspace.open('atom://about')
|
||||
|
||||
let aboutElement = workspaceElement.querySelector('.about')
|
||||
expect(aboutElement).toBeVisible()
|
||||
})
|
||||
})
|
||||
|
||||
describe('when the Atom version number is clicked', () => {
|
||||
it('copies the version number to the clipboard', async () => {
|
||||
await atom.workspace.open('atom://about')
|
||||
|
||||
let aboutElement = workspaceElement.querySelector('.about')
|
||||
let versionContainer = aboutElement.querySelector('.atom')
|
||||
versionContainer.click()
|
||||
expect(atom.clipboard.read()).toBe(atom.getVersion())
|
||||
})
|
||||
})
|
||||
|
||||
describe('when the show more link is clicked', () => {
|
||||
it('expands to show additional version numbers', async () => {
|
||||
await atom.workspace.open('atom://about')
|
||||
jasmine.attachToDOM(workspaceElement)
|
||||
|
||||
let aboutElement = workspaceElement.querySelector('.about')
|
||||
let showMoreElement = aboutElement.querySelector('.show-more-expand')
|
||||
let moreInfoElement = workspaceElement.querySelector('.show-more')
|
||||
showMoreElement.click()
|
||||
expect(moreInfoElement).toBeVisible()
|
||||
})
|
||||
})
|
||||
|
||||
describe('when the Electron version number is clicked', () => {
|
||||
it('copies the version number to the clipboard', async () => {
|
||||
await atom.workspace.open('atom://about')
|
||||
|
||||
let aboutElement = workspaceElement.querySelector('.about')
|
||||
let versionContainer = aboutElement.querySelector('.electron')
|
||||
versionContainer.click()
|
||||
expect(atom.clipboard.read()).toBe(process.versions.electron)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when the Chrome version number is clicked', () => {
|
||||
it('copies the version number to the clipboard', async () => {
|
||||
await atom.workspace.open('atom://about')
|
||||
|
||||
let aboutElement = workspaceElement.querySelector('.about')
|
||||
let versionContainer = aboutElement.querySelector('.chrome')
|
||||
versionContainer.click()
|
||||
expect(atom.clipboard.read()).toBe(process.versions.chrome)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when the Node version number is clicked', () => {
|
||||
it('copies the version number to the clipboard', async () => {
|
||||
await atom.workspace.open('atom://about')
|
||||
|
||||
let aboutElement = workspaceElement.querySelector('.about')
|
||||
let versionContainer = aboutElement.querySelector('.node')
|
||||
versionContainer.click()
|
||||
expect(atom.clipboard.read()).toBe(process.version)
|
||||
})
|
||||
})
|
||||
})
|
||||
179
packages/about/spec/about-status-bar-spec.js
Normal file
179
packages/about/spec/about-status-bar-spec.js
Normal file
@@ -0,0 +1,179 @@
|
||||
const {it, fit, ffit, fffit, beforeEach, afterEach, conditionPromise} = require('./helpers/async-spec-helpers') // eslint-disable-line no-unused-vars
|
||||
const MockUpdater = require('./mocks/updater')
|
||||
|
||||
describe('the status bar', () => {
|
||||
let atomVersion
|
||||
let workspaceElement
|
||||
|
||||
beforeEach(async () => {
|
||||
let storage = {}
|
||||
|
||||
spyOn(window.localStorage, 'setItem').andCallFake((key, value) => {
|
||||
storage[key] = value
|
||||
})
|
||||
spyOn(window.localStorage, 'getItem').andCallFake((key) => {
|
||||
return storage[key]
|
||||
})
|
||||
spyOn(atom, 'getVersion').andCallFake(() => {
|
||||
return atomVersion
|
||||
})
|
||||
|
||||
workspaceElement = atom.views.getView(atom.workspace)
|
||||
|
||||
await atom.packages.activatePackage('status-bar')
|
||||
await atom.workspace.open('sample.js')
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await atom.packages.deactivatePackage('about')
|
||||
await atom.packages.deactivatePackage('status-bar')
|
||||
})
|
||||
|
||||
describe('on a stable version', function () {
|
||||
beforeEach(async () => {
|
||||
atomVersion = '1.2.3'
|
||||
|
||||
await atom.packages.activatePackage('about')
|
||||
})
|
||||
|
||||
describe('with no update', () => {
|
||||
it('does not show the view', () => {
|
||||
expect(workspaceElement).not.toContain('.about-release-notes')
|
||||
})
|
||||
})
|
||||
|
||||
describe('with an update', () => {
|
||||
it('shows the view when the update finishes downloading', () => {
|
||||
MockUpdater.finishDownloadingUpdate('42.0.0')
|
||||
expect(workspaceElement).toContain('.about-release-notes')
|
||||
})
|
||||
|
||||
describe('clicking on the status', () => {
|
||||
it('opens the about page', async () => {
|
||||
MockUpdater.finishDownloadingUpdate('42.0.0')
|
||||
workspaceElement.querySelector('.about-release-notes').click()
|
||||
await conditionPromise(() => workspaceElement.querySelector('.about'))
|
||||
expect(workspaceElement.querySelector('.about')).toExist()
|
||||
})
|
||||
})
|
||||
|
||||
it('continues to show the squirrel until Atom is updated to the new version', async () => {
|
||||
MockUpdater.finishDownloadingUpdate('42.0.0')
|
||||
expect(workspaceElement).toContain('.about-release-notes')
|
||||
|
||||
await atom.packages.deactivatePackage('about')
|
||||
expect(workspaceElement).not.toContain('.about-release-notes')
|
||||
|
||||
await atom.packages.activatePackage('about')
|
||||
await Promise.resolve() // Service consumption hooks are deferred until the next tick
|
||||
expect(workspaceElement).toContain('.about-release-notes')
|
||||
|
||||
await atom.packages.deactivatePackage('about')
|
||||
expect(workspaceElement).not.toContain('.about-release-notes')
|
||||
|
||||
atomVersion = '42.0.0'
|
||||
await atom.packages.activatePackage('about')
|
||||
|
||||
await Promise.resolve() // Service consumption hooks are deferred until the next tick
|
||||
expect(workspaceElement).not.toContain('.about-release-notes')
|
||||
})
|
||||
|
||||
it('does not show the view if Atom is updated to a newer version than notified', async () => {
|
||||
MockUpdater.finishDownloadingUpdate('42.0.0')
|
||||
|
||||
await atom.packages.deactivatePackage('about')
|
||||
|
||||
atomVersion = '43.0.0'
|
||||
await atom.packages.activatePackage('about')
|
||||
|
||||
await Promise.resolve() // Service consumption hooks are deferred until the next tick
|
||||
expect(workspaceElement).not.toContain('.about-release-notes')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('on a beta version', function () {
|
||||
beforeEach(async () => {
|
||||
atomVersion = '1.2.3-beta4'
|
||||
|
||||
await atom.packages.activatePackage('about')
|
||||
})
|
||||
|
||||
describe('with no update', () => {
|
||||
it('does not show the view', () => {
|
||||
expect(workspaceElement).not.toContain('.about-release-notes')
|
||||
})
|
||||
})
|
||||
|
||||
describe('with an update', () => {
|
||||
it('shows the view when the update finishes downloading', () => {
|
||||
MockUpdater.finishDownloadingUpdate('42.0.0')
|
||||
expect(workspaceElement).toContain('.about-release-notes')
|
||||
})
|
||||
|
||||
describe('clicking on the status', () => {
|
||||
it('opens the about page', async () => {
|
||||
MockUpdater.finishDownloadingUpdate('42.0.0')
|
||||
workspaceElement.querySelector('.about-release-notes').click()
|
||||
await conditionPromise(() => workspaceElement.querySelector('.about'))
|
||||
expect(workspaceElement.querySelector('.about')).toExist()
|
||||
})
|
||||
})
|
||||
|
||||
it('continues to show the squirrel until Atom is updated to the new version', async () => {
|
||||
MockUpdater.finishDownloadingUpdate('42.0.0')
|
||||
expect(workspaceElement).toContain('.about-release-notes')
|
||||
|
||||
await atom.packages.deactivatePackage('about')
|
||||
expect(workspaceElement).not.toContain('.about-release-notes')
|
||||
|
||||
await atom.packages.activatePackage('about')
|
||||
await Promise.resolve() // Service consumption hooks are deferred until the next tick
|
||||
expect(workspaceElement).toContain('.about-release-notes')
|
||||
|
||||
await atom.packages.deactivatePackage('about')
|
||||
expect(workspaceElement).not.toContain('.about-release-notes')
|
||||
|
||||
atomVersion = '42.0.0'
|
||||
await atom.packages.activatePackage('about')
|
||||
|
||||
await Promise.resolve() // Service consumption hooks are deferred until the next tick
|
||||
expect(workspaceElement).not.toContain('.about-release-notes')
|
||||
})
|
||||
|
||||
it('does not show the view if Atom is updated to a newer version than notified', async () => {
|
||||
MockUpdater.finishDownloadingUpdate('42.0.0')
|
||||
|
||||
await atom.packages.deactivatePackage('about')
|
||||
|
||||
atomVersion = '43.0.0'
|
||||
await atom.packages.activatePackage('about')
|
||||
|
||||
await Promise.resolve() // Service consumption hooks are deferred until the next tick
|
||||
expect(workspaceElement).not.toContain('.about-release-notes')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('on a development version', function () {
|
||||
beforeEach(async () => {
|
||||
atomVersion = '1.2.3-dev-0123abcd'
|
||||
|
||||
await atom.packages.activatePackage('about')
|
||||
})
|
||||
|
||||
describe('with no update', () => {
|
||||
it('does not show the view', () => {
|
||||
expect(workspaceElement).not.toContain('.about-release-notes')
|
||||
})
|
||||
})
|
||||
|
||||
describe('with a previously downloaded update', () => {
|
||||
it('does not show the view', () => {
|
||||
window.localStorage.setItem('about:version-available', '42.0.0')
|
||||
|
||||
expect(workspaceElement).not.toContain('.about-release-notes')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
65
packages/about/spec/helpers/async-spec-helpers.js
Normal file
65
packages/about/spec/helpers/async-spec-helpers.js
Normal file
@@ -0,0 +1,65 @@
|
||||
/** @babel */
|
||||
|
||||
const {now} = Date
|
||||
const {setTimeout} = global
|
||||
|
||||
export function beforeEach (fn) {
|
||||
global.beforeEach(function () {
|
||||
const result = fn()
|
||||
if (result instanceof Promise) {
|
||||
waitsForPromise(() => result)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function afterEach (fn) {
|
||||
global.afterEach(function () {
|
||||
const result = fn()
|
||||
if (result instanceof Promise) {
|
||||
waitsForPromise(() => result)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
['it', 'fit', 'ffit', 'fffit'].forEach(function (name) {
|
||||
module.exports[name] = function (description, fn) {
|
||||
global[name](description, function () {
|
||||
const result = fn()
|
||||
if (result instanceof Promise) {
|
||||
waitsForPromise(() => result)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
export async function conditionPromise (condition) {
|
||||
const startTime = now()
|
||||
|
||||
while (true) {
|
||||
await timeoutPromise(100)
|
||||
|
||||
if (await condition()) {
|
||||
return
|
||||
}
|
||||
|
||||
if (now() - startTime > 5000) {
|
||||
throw new Error('Timed out waiting on condition')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function timeoutPromise (timeout) {
|
||||
return new Promise(function (resolve) {
|
||||
setTimeout(resolve, timeout)
|
||||
})
|
||||
}
|
||||
|
||||
function waitsForPromise (fn) {
|
||||
const promise = fn()
|
||||
global.waitsFor('spec promise to resolve', function (done) {
|
||||
promise.then(done, function (error) {
|
||||
jasmine.getEnv().currentSpec.fail(error)
|
||||
done()
|
||||
})
|
||||
})
|
||||
}
|
||||
21
packages/about/spec/mocks/updater.js
Normal file
21
packages/about/spec/mocks/updater.js
Normal file
@@ -0,0 +1,21 @@
|
||||
module.exports = {
|
||||
updateError () {
|
||||
atom.autoUpdater.emitter.emit('update-error')
|
||||
},
|
||||
|
||||
checkForUpdate () {
|
||||
atom.autoUpdater.emitter.emit('did-begin-checking-for-update')
|
||||
},
|
||||
|
||||
updateNotAvailable () {
|
||||
atom.autoUpdater.emitter.emit('update-not-available')
|
||||
},
|
||||
|
||||
downloadUpdate () {
|
||||
atom.autoUpdater.emitter.emit('did-begin-downloading-update')
|
||||
},
|
||||
|
||||
finishDownloadingUpdate (releaseVersion) {
|
||||
atom.autoUpdater.emitter.emit('did-complete-downloading-update', {releaseVersion})
|
||||
}
|
||||
}
|
||||
22
packages/about/spec/update-manager-spec.js
Normal file
22
packages/about/spec/update-manager-spec.js
Normal file
@@ -0,0 +1,22 @@
|
||||
const UpdateManager = require('../lib/update-manager')
|
||||
|
||||
describe('UpdateManager', () => {
|
||||
let updateManager
|
||||
|
||||
beforeEach(() => {
|
||||
updateManager = new UpdateManager()
|
||||
})
|
||||
|
||||
describe('::getReleaseNotesURLForVersion', () => {
|
||||
it('returns atom.io releases when dev version', () => {
|
||||
expect(updateManager.getReleaseNotesURLForVersion('1.7.0-dev-e44b57d')).toContain('atom.io/releases')
|
||||
})
|
||||
|
||||
it('returns the page for the release when not a dev version', () => {
|
||||
expect(updateManager.getReleaseNotesURLForVersion('1.7.0')).toContain('atom/atom/releases/tag/v1.7.0')
|
||||
expect(updateManager.getReleaseNotesURLForVersion('v1.7.0')).toContain('atom/atom/releases/tag/v1.7.0')
|
||||
expect(updateManager.getReleaseNotesURLForVersion('1.7.0-beta10')).toContain('atom/atom/releases/tag/v1.7.0-beta10')
|
||||
expect(updateManager.getReleaseNotesURLForVersion('1.7.0-nightly10')).toContain('atom/atom-nightly-releases/releases/tag/v1.7.0-nightly10')
|
||||
})
|
||||
})
|
||||
})
|
||||
280
packages/about/spec/update-view-spec.js
Normal file
280
packages/about/spec/update-view-spec.js
Normal file
@@ -0,0 +1,280 @@
|
||||
const {shell} = require('electron')
|
||||
const {it, fit, ffit, fffit, beforeEach, afterEach} = require('./helpers/async-spec-helpers') // eslint-disable-line no-unused-vars
|
||||
const main = require('../lib/main')
|
||||
const AboutView = require('../lib/components/about-view')
|
||||
const UpdateView = require('../lib/components/update-view')
|
||||
const MockUpdater = require('./mocks/updater')
|
||||
|
||||
describe('UpdateView', () => {
|
||||
let aboutElement
|
||||
let updateManager
|
||||
let workspaceElement
|
||||
let scheduler
|
||||
|
||||
beforeEach(async () => {
|
||||
let storage = {}
|
||||
|
||||
spyOn(window.localStorage, 'setItem').andCallFake((key, value) => {
|
||||
storage[key] = value
|
||||
})
|
||||
spyOn(window.localStorage, 'getItem').andCallFake((key) => {
|
||||
return storage[key]
|
||||
})
|
||||
|
||||
workspaceElement = atom.views.getView(atom.workspace)
|
||||
await atom.packages.activatePackage('about')
|
||||
spyOn(atom.autoUpdater, 'getState').andReturn('idle')
|
||||
spyOn(atom.autoUpdater, 'checkForUpdate')
|
||||
spyOn(atom.autoUpdater, 'platformSupportsUpdates').andReturn(true)
|
||||
})
|
||||
|
||||
describe('when the About page is open', () => {
|
||||
beforeEach(async () => {
|
||||
jasmine.attachToDOM(workspaceElement)
|
||||
await atom.workspace.open('atom://about')
|
||||
aboutElement = workspaceElement.querySelector('.about')
|
||||
updateManager = main.model.state.updateManager
|
||||
scheduler = AboutView.getScheduler()
|
||||
})
|
||||
|
||||
describe('when the updates are not supported by the platform', () => {
|
||||
beforeEach(async () => {
|
||||
atom.autoUpdater.platformSupportsUpdates.andReturn(false)
|
||||
updateManager.resetState()
|
||||
await scheduler.getNextUpdatePromise()
|
||||
})
|
||||
|
||||
it('hides the auto update UI and shows the update instructions link', async () => {
|
||||
expect(aboutElement.querySelector('.about-update-action-button')).not.toBeVisible()
|
||||
expect(aboutElement.querySelector('.about-auto-updates')).not.toBeVisible()
|
||||
})
|
||||
|
||||
it('opens the update instructions page when the instructions link is clicked', async () => {
|
||||
spyOn(shell, 'openExternal')
|
||||
let link = aboutElement.querySelector('.app-unsupported .about-updates-instructions')
|
||||
link.click()
|
||||
|
||||
let args = shell.openExternal.mostRecentCall.args
|
||||
expect(shell.openExternal).toHaveBeenCalled()
|
||||
expect(args[0]).toContain('installing-atom')
|
||||
})
|
||||
})
|
||||
|
||||
describe('when updates are supported by the platform', () => {
|
||||
beforeEach(async () => {
|
||||
atom.autoUpdater.platformSupportsUpdates.andReturn(true)
|
||||
updateManager.resetState()
|
||||
await scheduler.getNextUpdatePromise()
|
||||
})
|
||||
|
||||
it('shows the auto update UI', () => {
|
||||
expect(aboutElement.querySelector('.about-updates')).toBeVisible()
|
||||
})
|
||||
|
||||
it('shows the correct panels when the app checks for updates and there is no update available', async () => {
|
||||
expect(aboutElement.querySelector('.about-default-update-message')).toBeVisible()
|
||||
|
||||
MockUpdater.checkForUpdate()
|
||||
await scheduler.getNextUpdatePromise()
|
||||
expect(aboutElement.querySelector('.app-up-to-date')).not.toBeVisible()
|
||||
expect(aboutElement.querySelector('.app-checking-for-updates')).toBeVisible()
|
||||
|
||||
MockUpdater.updateNotAvailable()
|
||||
await scheduler.getNextUpdatePromise()
|
||||
expect(aboutElement.querySelector('.app-up-to-date')).toBeVisible()
|
||||
expect(aboutElement.querySelector('.app-checking-for-updates')).not.toBeVisible()
|
||||
})
|
||||
|
||||
it('shows the correct panels when the app checks for updates and encounters an error', async () => {
|
||||
expect(aboutElement.querySelector('.about-default-update-message')).toBeVisible()
|
||||
|
||||
MockUpdater.checkForUpdate()
|
||||
await scheduler.getNextUpdatePromise()
|
||||
expect(aboutElement.querySelector('.app-up-to-date')).not.toBeVisible()
|
||||
expect(aboutElement.querySelector('.app-checking-for-updates')).toBeVisible()
|
||||
|
||||
spyOn(atom.autoUpdater, 'getErrorMessage').andReturn('an error message')
|
||||
MockUpdater.updateError()
|
||||
await scheduler.getNextUpdatePromise()
|
||||
expect(aboutElement.querySelector('.app-update-error')).toBeVisible()
|
||||
expect(aboutElement.querySelector('.app-error-message').textContent).toBe('an error message')
|
||||
expect(aboutElement.querySelector('.app-checking-for-updates')).not.toBeVisible()
|
||||
expect(aboutElement.querySelector('.about-update-action-button').disabled).toBe(false)
|
||||
expect(aboutElement.querySelector('.about-update-action-button').textContent).toBe('Check now')
|
||||
})
|
||||
|
||||
it('shows the correct panels and button states when the app checks for updates and an update is downloaded', async () => {
|
||||
expect(aboutElement.querySelector('.about-default-update-message')).toBeVisible()
|
||||
expect(aboutElement.querySelector('.about-update-action-button').disabled).toBe(false)
|
||||
expect(aboutElement.querySelector('.about-update-action-button').textContent).toBe('Check now')
|
||||
|
||||
MockUpdater.checkForUpdate()
|
||||
await scheduler.getNextUpdatePromise()
|
||||
|
||||
expect(aboutElement.querySelector('.app-up-to-date')).not.toBeVisible()
|
||||
expect(aboutElement.querySelector('.app-checking-for-updates')).toBeVisible()
|
||||
expect(aboutElement.querySelector('.about-update-action-button').disabled).toBe(true)
|
||||
expect(aboutElement.querySelector('.about-update-action-button').textContent).toBe('Check now')
|
||||
|
||||
MockUpdater.downloadUpdate()
|
||||
await scheduler.getNextUpdatePromise()
|
||||
expect(aboutElement.querySelector('.app-checking-for-updates')).not.toBeVisible()
|
||||
expect(aboutElement.querySelector('.app-downloading-update')).toBeVisible()
|
||||
// TODO: at some point it would be nice to be able to cancel an update download, and then this would be a cancel button
|
||||
expect(aboutElement.querySelector('.about-update-action-button').disabled).toBe(true)
|
||||
expect(aboutElement.querySelector('.about-update-action-button').textContent).toBe('Check now')
|
||||
|
||||
MockUpdater.finishDownloadingUpdate('42.0.0')
|
||||
await scheduler.getNextUpdatePromise()
|
||||
expect(aboutElement.querySelector('.app-downloading-update')).not.toBeVisible()
|
||||
expect(aboutElement.querySelector('.app-update-available-to-install')).toBeVisible()
|
||||
|
||||
expect(aboutElement.querySelector('.app-update-available-to-install .about-updates-version').textContent).toBe('42.0.0')
|
||||
expect(aboutElement.querySelector('.about-update-action-button').disabled).toBe(false)
|
||||
expect(aboutElement.querySelector('.about-update-action-button').textContent).toBe('Restart and install')
|
||||
})
|
||||
|
||||
it('opens the release notes for the downloaded release when the release notes link are clicked', async () => {
|
||||
MockUpdater.finishDownloadingUpdate('1.2.3')
|
||||
await scheduler.getNextUpdatePromise()
|
||||
|
||||
spyOn(shell, 'openExternal')
|
||||
let link = aboutElement.querySelector('.app-update-available-to-install .about-updates-release-notes')
|
||||
link.click()
|
||||
|
||||
let args = shell.openExternal.mostRecentCall.args
|
||||
expect(shell.openExternal).toHaveBeenCalled()
|
||||
expect(args[0]).toContain('/v1.2.3')
|
||||
})
|
||||
|
||||
it('executes checkForUpdate() when the check for update button is clicked', () => {
|
||||
let button = aboutElement.querySelector('.about-update-action-button')
|
||||
button.click()
|
||||
expect(atom.autoUpdater.checkForUpdate).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('executes restartAndInstallUpdate() when the restart and install button is clicked', async () => {
|
||||
spyOn(atom.autoUpdater, 'restartAndInstallUpdate')
|
||||
MockUpdater.finishDownloadingUpdate('42.0.0')
|
||||
await scheduler.getNextUpdatePromise()
|
||||
|
||||
let button = aboutElement.querySelector('.about-update-action-button')
|
||||
button.click()
|
||||
expect(atom.autoUpdater.restartAndInstallUpdate).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("starts in the same state as atom's AutoUpdateManager", async () => {
|
||||
atom.autoUpdater.getState.andReturn('downloading')
|
||||
updateManager.resetState()
|
||||
|
||||
await scheduler.getNextUpdatePromise()
|
||||
expect(aboutElement.querySelector('.app-checking-for-updates')).not.toBeVisible()
|
||||
expect(aboutElement.querySelector('.app-downloading-update')).toBeVisible()
|
||||
expect(aboutElement.querySelector('.about-update-action-button').disabled).toBe(true)
|
||||
expect(aboutElement.querySelector('.about-update-action-button').textContent).toBe('Check now')
|
||||
})
|
||||
|
||||
describe('when core.automaticallyUpdate is toggled', () => {
|
||||
beforeEach(async () => {
|
||||
expect(atom.config.get('core.automaticallyUpdate')).toBe(true)
|
||||
atom.autoUpdater.checkForUpdate.reset()
|
||||
})
|
||||
|
||||
it('shows the auto update UI', async () => {
|
||||
expect(aboutElement.querySelector('.about-auto-updates input').checked).toBe(true)
|
||||
expect(aboutElement.querySelector('.about-default-update-message')).toBeVisible()
|
||||
expect(aboutElement.querySelector('.about-default-update-message').textContent).toBe('Atom will check for updates automatically')
|
||||
|
||||
atom.config.set('core.automaticallyUpdate', false)
|
||||
await scheduler.getNextUpdatePromise()
|
||||
|
||||
expect(aboutElement.querySelector('.about-auto-updates input').checked).toBe(false)
|
||||
expect(aboutElement.querySelector('.about-default-update-message')).toBeVisible()
|
||||
expect(aboutElement.querySelector('.about-default-update-message').textContent).toBe('Automatic updates are disabled please check manually')
|
||||
})
|
||||
|
||||
it('updates config and the UI when the checkbox is used to toggle', async () => {
|
||||
expect(aboutElement.querySelector('.about-auto-updates input').checked).toBe(true)
|
||||
|
||||
aboutElement.querySelector('.about-auto-updates input').click()
|
||||
await scheduler.getNextUpdatePromise()
|
||||
|
||||
expect(atom.config.get('core.automaticallyUpdate')).toBe(false)
|
||||
expect(aboutElement.querySelector('.about-auto-updates input').checked).toBe(false)
|
||||
expect(aboutElement.querySelector('.about-default-update-message')).toBeVisible()
|
||||
expect(aboutElement.querySelector('.about-default-update-message').textContent).toBe('Automatic updates are disabled please check manually')
|
||||
|
||||
aboutElement.querySelector('.about-auto-updates input').click()
|
||||
await scheduler.getNextUpdatePromise()
|
||||
|
||||
expect(atom.config.get('core.automaticallyUpdate')).toBe(true)
|
||||
expect(aboutElement.querySelector('.about-auto-updates input').checked).toBe(true)
|
||||
expect(aboutElement.querySelector('.about-default-update-message')).toBeVisible()
|
||||
expect(aboutElement.querySelector('.about-default-update-message').textContent).toBe('Atom will check for updates automatically')
|
||||
})
|
||||
|
||||
describe('checking for updates', function () {
|
||||
afterEach(() => {
|
||||
this.updateView = null
|
||||
})
|
||||
|
||||
it('checks for update when the about page is shown', () => {
|
||||
expect(atom.autoUpdater.checkForUpdate).not.toHaveBeenCalled()
|
||||
|
||||
this.updateView = new UpdateView({
|
||||
updateManager: updateManager,
|
||||
availableVersion: '9999.0.0',
|
||||
viewUpdateReleaseNotes: () => {}
|
||||
})
|
||||
|
||||
expect(atom.autoUpdater.checkForUpdate).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('does not check for update when the about page is shown and the update manager is not in the idle state', () => {
|
||||
atom.autoUpdater.getState.andReturn('downloading')
|
||||
updateManager.resetState()
|
||||
expect(atom.autoUpdater.checkForUpdate).not.toHaveBeenCalled()
|
||||
|
||||
this.updateView = new UpdateView({
|
||||
updateManager: updateManager,
|
||||
availableVersion: '9999.0.0',
|
||||
viewUpdateReleaseNotes: () => {}
|
||||
})
|
||||
|
||||
expect(atom.autoUpdater.checkForUpdate).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('does not check for update when the about page is shown and auto updates are turned off', () => {
|
||||
atom.config.set('core.automaticallyUpdate', false)
|
||||
expect(atom.autoUpdater.checkForUpdate).not.toHaveBeenCalled()
|
||||
|
||||
this.updateView = new UpdateView({
|
||||
updateManager: updateManager,
|
||||
availableVersion: '9999.0.0',
|
||||
viewUpdateReleaseNotes: () => {}
|
||||
})
|
||||
|
||||
expect(atom.autoUpdater.checkForUpdate).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('when the About page is not open and an update is downloaded', () => {
|
||||
it('should display the new version when it is opened', async () => {
|
||||
MockUpdater.finishDownloadingUpdate('42.0.0')
|
||||
|
||||
jasmine.attachToDOM(workspaceElement)
|
||||
await atom.workspace.open('atom://about')
|
||||
aboutElement = workspaceElement.querySelector('.about')
|
||||
updateManager = main.model.state.updateManager
|
||||
scheduler = AboutView.getScheduler()
|
||||
|
||||
expect(aboutElement.querySelector('.app-update-available-to-install')).toBeVisible()
|
||||
expect(aboutElement.querySelector('.app-update-available-to-install .about-updates-version').textContent).toBe('42.0.0')
|
||||
expect(aboutElement.querySelector('.about-update-action-button').disabled).toBe(false)
|
||||
expect(aboutElement.querySelector('.about-update-action-button').textContent).toBe('Restart and install')
|
||||
})
|
||||
})
|
||||
})
|
||||
175
packages/about/styles/about.less
Normal file
175
packages/about/styles/about.less
Normal file
@@ -0,0 +1,175 @@
|
||||
@import "ui-variables";
|
||||
@import "variables";
|
||||
|
||||
.about {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
-webkit-user-select: none;
|
||||
cursor: default;
|
||||
overflow: auto;
|
||||
text-align: center;
|
||||
font-size: 1.25em;
|
||||
line-height: 1.4;
|
||||
padding: 4em;
|
||||
color: @text-color;
|
||||
background-color: @base-background-color;
|
||||
|
||||
button {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
a:focus {
|
||||
// Don't use Bootstrap default here
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
img, a {
|
||||
-webkit-user-drag: none;
|
||||
}
|
||||
|
||||
.input-checkbox {
|
||||
margin-top: -.2em;
|
||||
}
|
||||
|
||||
// used to group different elements
|
||||
.group-start {
|
||||
margin-top: 4em;
|
||||
}
|
||||
.group-item {
|
||||
margin-top: 1.5em;
|
||||
}
|
||||
}
|
||||
|
||||
.about-container {
|
||||
width: 100%;
|
||||
max-width: 500px;
|
||||
}
|
||||
|
||||
// Header --------------------------------
|
||||
|
||||
.about-atom-io:hover {
|
||||
.about-logo {
|
||||
color: @atom-green;
|
||||
}
|
||||
}
|
||||
|
||||
.about-logo {
|
||||
display: block;
|
||||
width: 100%;
|
||||
max-width: 280px;
|
||||
margin: 0 auto 1em auto;
|
||||
color: @text-color-highlight;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
|
||||
.about-version-container {
|
||||
&:hover {
|
||||
color: lighten(@text-color, 15%);
|
||||
}
|
||||
&:active {
|
||||
color: lighten(@text-color, 30%);
|
||||
}
|
||||
}
|
||||
|
||||
.about-version {
|
||||
margin-right: .5em;
|
||||
font-size: 1.25em;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.about-more-version {
|
||||
color: @text-color-subtle;
|
||||
font-size: .9em;
|
||||
}
|
||||
|
||||
.about-header-release-notes {
|
||||
vertical-align: middle;
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
|
||||
// Updates --------------------------------
|
||||
|
||||
.about-updates {
|
||||
width: 100%;
|
||||
max-width: 500px;
|
||||
}
|
||||
|
||||
.about-updates-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: @component-padding;
|
||||
border: 1px solid @base-border-color;
|
||||
border-radius: @component-border-radius * 2;
|
||||
background-color: @background-color-highlight;
|
||||
}
|
||||
|
||||
.about-updates-status {
|
||||
flex: 1;
|
||||
margin-left: .5em;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.about-updates-item,
|
||||
.about-default-update-message .about-updates-label {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.about-updates-label {
|
||||
color: @text-color-subtle;
|
||||
&.is-strong {
|
||||
color: @text-color;
|
||||
}
|
||||
}
|
||||
|
||||
.about-updates-version {
|
||||
margin: 0 .4em;
|
||||
}
|
||||
|
||||
.about-updates-release-notes,
|
||||
.about-updates-instructions {
|
||||
margin: 0 1em 0 1.5em;
|
||||
}
|
||||
|
||||
.about-auto-updates {
|
||||
margin-top: 1em;
|
||||
input {
|
||||
margin-right: .5em;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Love --------------------------------
|
||||
|
||||
.about-love {
|
||||
.icon::before {
|
||||
// Make these octicons look good inlined with text
|
||||
position: relative;
|
||||
width: auto;
|
||||
height: auto;
|
||||
margin-right: 0;
|
||||
font-size: 1.5em;
|
||||
vertical-align: text-top;
|
||||
}
|
||||
|
||||
.icon-logo-github::before {
|
||||
font-size: 3.6em;
|
||||
height: .36em;
|
||||
}
|
||||
}
|
||||
|
||||
.about-credits {
|
||||
color: @text-color-subtle;
|
||||
}
|
||||
|
||||
|
||||
// the blue squirrel --------------------------------
|
||||
|
||||
.about-release-notes {
|
||||
color: @background-color-info;
|
||||
&:hover {
|
||||
color: lighten(@background-color-info, 15%);
|
||||
}
|
||||
}
|
||||
1
packages/about/styles/variables.less
Normal file
1
packages/about/styles/variables.less
Normal file
@@ -0,0 +1 @@
|
||||
@atom-green: #40a977;
|
||||
Reference in New Issue
Block a user