mirror of
https://github.com/Foundry376/Mailspring.git
synced 2025-01-11 10:38:11 +08:00
a25ec2551f
Summary: Package names must match directory names Not going to use new Swithc component, but might as well be part of component kit Move APMWrapper into core so it can be used from anywhere Move manual package install coe to package-manager Gray out window titles when in the background Do not allow multiple onboarding windows at the same time Finalize styling f initial-prefs and initial-packages, make it work (only github package atm) Other nits Change the welcome copy: - Call it easy to extend vs easy to use - Remove the subtitle from the first screen which doesn't really fit - Make the second page emphasize that its created /for/ developers and easy to extend with Javascript. - Explain what the sync engine is rather than saying it's "faster and more extensible" (??) Test Plan: Run tests Reviewers: evan, dillon Reviewed By: evan Maniphest Tasks: T3346 Differential Revision: https://phab.nylas.com/D2079
255 lines
8.1 KiB
CoffeeScript
255 lines
8.1 KiB
CoffeeScript
_ = require 'underscore'
|
|
ipc = require 'ipc'
|
|
Reflux = require 'reflux'
|
|
path = require 'path'
|
|
fs = require 'fs-plus'
|
|
shell = require 'shell'
|
|
SettingsActions = require './settings-actions'
|
|
{APMWrapper} = require 'nylas-exports'
|
|
dialog = require('remote').require('dialog')
|
|
|
|
module.exports =
|
|
SettingsPackagesStore = Reflux.createStore
|
|
|
|
init: ->
|
|
@_apm = new APMWrapper()
|
|
|
|
@_globalSearch = ""
|
|
@_installedSearch = ""
|
|
@_installing = {}
|
|
@_featured = {themes: [], packages: []}
|
|
@_newerVersions = []
|
|
@_searchResults = null
|
|
@_refreshFeatured()
|
|
|
|
@listenTo SettingsActions.refreshFeaturedPackages, @_refreshFeatured
|
|
@listenTo SettingsActions.refreshInstalledPackages, @_refreshInstalled
|
|
|
|
atom.commands.add 'body',
|
|
'application:create-package': => @_onCreatePackage()
|
|
|
|
atom.commands.add 'body',
|
|
'application:install-package': => @_onInstallPackage()
|
|
|
|
@listenTo SettingsActions.createPackage, @_onCreatePackage
|
|
@listenTo SettingsActions.updatePackage, @_onUpdatePackage
|
|
@listenTo SettingsActions.setGlobalSearchValue, @_onGlobalSearchChange
|
|
@listenTo SettingsActions.setInstalledSearchValue, @_onInstalledSearchChange
|
|
|
|
@listenTo SettingsActions.showPackage, (pkg) =>
|
|
dir = atom.packages.resolvePackagePath(pkg.name)
|
|
shell.showItemInFolder(dir) if dir
|
|
|
|
@listenTo SettingsActions.installPackage, (pkg) =>
|
|
@_installing[pkg.name] = true
|
|
@trigger(@)
|
|
@_apm.install pkg, (err) =>
|
|
if err
|
|
delete @_installing[pkg.name]
|
|
@_displayMessage("Sorry, an error occurred", err.toString())
|
|
else
|
|
if atom.packages.isPackageDisabled(pkg.name)
|
|
atom.packages.enablePackage(pkg.name)
|
|
@_onPackagesChanged()
|
|
|
|
@listenTo SettingsActions.uninstallPackage, (pkg) =>
|
|
if atom.packages.isPackageLoaded(pkg.name)
|
|
atom.packages.disablePackage(pkg.name)
|
|
atom.packages.unloadPackage(pkg.name)
|
|
@_apm.uninstall pkg, (err) =>
|
|
@_displayMessage("Sorry, an error occurred", err.toString()) if err
|
|
@_onPackagesChanged()
|
|
|
|
@listenTo SettingsActions.enablePackage, (pkg) ->
|
|
if atom.packages.isPackageDisabled(pkg.name)
|
|
atom.packages.enablePackage(pkg.name)
|
|
|
|
@listenTo SettingsActions.disablePackage, (pkg) ->
|
|
unless atom.packages.isPackageDisabled(pkg.name)
|
|
atom.packages.disablePackage(pkg.name)
|
|
|
|
@_hasPrepared = false
|
|
|
|
# Getters
|
|
|
|
installed: ->
|
|
@_prepareIfFresh()
|
|
@_addPackageStates(@_filter(@_installed, @_installedSearch))
|
|
|
|
installedSearchValue: ->
|
|
@_installedSearch
|
|
|
|
featured: ->
|
|
@_prepareIfFresh()
|
|
@_addPackageStates(@_featured)
|
|
|
|
searchResults: ->
|
|
@_addPackageStates(@_searchResults)
|
|
|
|
globalSearchValue: ->
|
|
@_globalSearch
|
|
|
|
# Action Handlers
|
|
|
|
_prepareIfFresh: ->
|
|
return if @_hasPrepared
|
|
atom.packages.onDidActivatePackage(=> @_onPackagesChangedDebounced())
|
|
atom.packages.onDidDeactivatePackage(=> @_onPackagesChangedDebounced())
|
|
atom.packages.onDidLoadPackage(=> @_onPackagesChangedDebounced())
|
|
atom.packages.onDidUnloadPackage(=> @_onPackagesChangedDebounced())
|
|
@_onPackagesChanged()
|
|
@_hasPrepared = true
|
|
|
|
_filter: (hash, search) ->
|
|
result = {}
|
|
search = search.toLowerCase()
|
|
for key, pkgs of hash
|
|
result[key] = _.filter pkgs, (p) =>
|
|
search.length is 0 or p.name.toLowerCase().indexOf(search) isnt -1
|
|
result
|
|
|
|
_refreshFeatured: ->
|
|
@_apm.getFeatured({themes: false}).then (results) =>
|
|
@_featured.packages = results
|
|
@trigger()
|
|
.catch (err) =>
|
|
# We may be offline
|
|
@_apm.getFeatured({themes: true}).then (results) =>
|
|
@_featured.themes = results
|
|
@trigger()
|
|
.catch (err) =>
|
|
# We may be offline
|
|
|
|
_refreshInstalled: ->
|
|
@_onPackagesChanged()
|
|
|
|
_refreshSearch: ->
|
|
return unless @_globalSearch?.length > 0
|
|
|
|
@_apm.search(@_globalSearch).then (results) =>
|
|
@_searchResults =
|
|
packages: results.filter ({theme}) -> not theme
|
|
themes: results.filter ({theme}) -> theme
|
|
@trigger()
|
|
.catch (err) =>
|
|
# We may be offline
|
|
|
|
_refreshSearchThrottled: _.debounce((-> @_refreshSearch()), 400)
|
|
|
|
_onPackagesChanged: ->
|
|
@_apm.getInstalled().then (packages) =>
|
|
for category in ['dev', 'user', 'core']
|
|
packages[category] = packages[category].filter ({theme}) -> not theme
|
|
packages[category].forEach (pkg) =>
|
|
pkg.category = category
|
|
delete @_installing[pkg.name]
|
|
@_installed = packages
|
|
@trigger()
|
|
|
|
@_apm.getOutdated().then (packages) =>
|
|
@_newerVersions = {}
|
|
for pkg in packages
|
|
@_newerVersions[pkg.name] = pkg.latestVersion
|
|
@trigger()
|
|
|
|
_onPackagesChangedDebounced: _.debounce((-> @_onPackagesChanged()), 200)
|
|
|
|
_onInstalledSearchChange: (val) ->
|
|
@_installedSearch = val
|
|
@trigger()
|
|
|
|
_onUpdatePackage: (pkg) ->
|
|
@_apm.update(pkg, pkg.newerVersion)
|
|
|
|
_onInstallPackage: ->
|
|
dialog.showOpenDialog
|
|
title: "Choose a Package Directory"
|
|
properties: ['openDirectory']
|
|
, (filenames) =>
|
|
return if not filenames or filenames.length is 0
|
|
atom.packages.installPackageFromPath filenames[0], (err) =>
|
|
return if err
|
|
packageName = path.basename(filenames[0])
|
|
msg = "#{packageName} has been installed and enabled. No need to \
|
|
restart! If you don't see the package loaded, check the \
|
|
console for errors."
|
|
@_displayMessage("Package installed", msg)
|
|
|
|
_onCreatePackage: ->
|
|
packagesDir = path.join(atom.getConfigDirPath(), 'packages')
|
|
fs.makeTreeSync(packagesDir)
|
|
|
|
dialog.showSaveDialog
|
|
title: "Save New Package"
|
|
defaultPath: packagesDir
|
|
properties: ['createDirectory']
|
|
, (packageDir) =>
|
|
return unless packageDir
|
|
|
|
packageName = path.basename(packageDir)
|
|
|
|
if not packageDir.startsWith(packagesDir)
|
|
return @_displayMessage('Invalid package location', 'Sorry, you must
|
|
create packages in the packages folder.')
|
|
|
|
if atom.packages.resolvePackagePath(packageName)
|
|
return @_displayMessage('Invalid package name', 'Sorry, you must
|
|
give your package a unqiue name.')
|
|
|
|
if packageName.indexOf(' ') isnt -1
|
|
return @_displayMessage('Invalid package name', 'Sorry, package names
|
|
cannot contain spaces.')
|
|
|
|
fs.mkdir packageDir, (err) =>
|
|
return @_displayMessage('Could not create package', err.toString()) if err
|
|
|
|
{resourcePath} = atom.getLoadSettings()
|
|
packageTemplatePath = path.join(resourcePath, 'static', 'package-template')
|
|
packageJSON =
|
|
name: packageName
|
|
main: "./lib/main"
|
|
version: '0.1.0'
|
|
repository:
|
|
type: 'git'
|
|
url: ''
|
|
engines:
|
|
atom: ">=#{atom.getVersion()}"
|
|
description: "Enter a description of your package!"
|
|
dependencies: {}
|
|
license: "MIT"
|
|
|
|
fs.copySync(packageTemplatePath, packageDir)
|
|
fs.writeFileSync(path.join(packageDir, 'package.json'), JSON.stringify(packageJSON, null, 2))
|
|
shell.showItemInFolder(packageDir)
|
|
_.defer ->
|
|
atom.packages.enablePackage(packageDir)
|
|
atom.packages.activatePackage(packageName)
|
|
|
|
_onGlobalSearchChange: (val) ->
|
|
# Clear previous search results data if this is a new
|
|
# search beginning from "".
|
|
if @_globalSearch.length is 0 and val.length > 0
|
|
@_searchResults = null
|
|
|
|
@_globalSearch = val
|
|
@_refreshSearchThrottled()
|
|
@trigger()
|
|
|
|
_addPackageStates: (pkgs) ->
|
|
installedNames = _.flatten(_.values(@_installed)).map (pkg) -> pkg.name
|
|
|
|
_.flatten(_.values(pkgs)).forEach (pkg) =>
|
|
pkg.enabled = !atom.packages.isPackageDisabled(pkg.name)
|
|
pkg.installed = pkg.name in installedNames
|
|
pkg.installing = @_installing[pkg.name]?
|
|
pkg.newerVersionAvailable = @_newerVersions[pkg.name]?
|
|
pkg.newerVersion = @_newerVersions[pkg.name]
|
|
|
|
pkgs
|
|
|
|
_displayMessage: (title, message) ->
|
|
chosen = dialog.showMessageBox
|
|
type: 'warning'
|
|
message: title
|
|
detail: message
|
|
buttons: ["OK"]
|