From 1e6431025f3d2b3275b53dae41219c45544be4a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=90=B4=E5=AD=A6=E8=B0=A6?= Date: Thu, 28 Dec 2017 19:31:39 +0800 Subject: [PATCH 01/25] use ts --- .babelrc | 21 +- .eslintrc.js | 36 - .gitignore | 2 +- .prettierrc | 4 + .stylelintrc | 29 + .tslintrc.json | 111 + build/dev-server.js | 53 - build/webpack.base.conf.babel.js | 126 - build/webpack.dev.conf.babel.js | 60 - build/webpack.prod.conf.babel.js | 118 - jsconfig.json => index.d.ts | 0 package.json | 172 +- .../styles/global/antd-theme.less | 0 .../{ => assets}/styles/global/global.less | 0 .../{ => assets}/styles/global/iconfont.css | 0 .../{ => assets}/styles/global/normalize.css | 0 .../{ => assets}/styles/global/system.less | 0 src/renderer/{ => assets}/styles/login.less | 0 src/renderer/{ => assets}/styles/main.less | 0 src/renderer/{ => assets}/styles/setting.less | 0 src/renderer/components/{app.jsx => app.tsx} | 10 +- .../{filterBar.jsx => filterBar.tsx} | 43 +- .../{loginPage.jsx => loginPage.tsx} | 78 +- src/renderer/constants/{index.js => index.ts} | 9 +- src/renderer/containers/{app.jsx => app.tsx} | 0 .../{filterBar.jsx => filterBar.tsx} | 0 .../{loginPage.jsx => loginPage.tsx} | 0 ...{mainDetailPane.jsx => mainDetailPane.tsx} | 0 ...ainGroupAvatar.jsx => mainGroupAvatar.tsx} | 3 +- ...ainGroupFooter.jsx => mainGroupFooter.tsx} | 0 .../{mainGroupNavs.jsx => mainGroupNavs.tsx} | 0 .../{mainGroupPane.jsx => mainGroupPane.tsx} | 5 +- .../{mainListPane.jsx => mainListPane.tsx} | 0 .../containers/{mainPage.jsx => mainPage.tsx} | 0 .../{mainSearchBox.jsx => mainSearchBox.tsx} | 0 ...reshIndicator.jsx => refreshIndicator.tsx} | 0 ...oClassifyTool.jsx => repoClassifyTool.tsx} | 0 ...ibutorsBar.jsx => repoContributorsBar.tsx} | 4 +- .../{repoDetail.jsx => repoDetail.tsx} | 3 +- ...etailToolbar.jsx => repoDetailToolbar.tsx} | 0 .../{repoReadme.jsx => repoReadme.tsx} | 0 .../{repoTagsBar.jsx => repoTagsBar.tsx} | 0 .../{reposList.jsx => reposList.tsx} | 0 .../{settingPage.jsx => settingPage.tsx} | 0 .../containers/{sortBar.jsx => sortBar.tsx} | 0 src/renderer/{index.jsx => index.tsx} | 17 +- .../reducers/{accounts.js => accounts.ts} | 10 +- .../reducers/{categories.js => categories.ts} | 0 .../{conditional.js => conditional.ts} | 20 +- src/renderer/reducers/{db.js => db.ts} | 0 src/renderer/reducers/{index.js => index.ts} | 14 +- .../reducers/{languages.js => languages.ts} | 0 .../reducers/{network.js => network.ts} | 4 +- .../reducers/{profile.js => profile.ts} | 0 src/renderer/reducers/{repo.js => repo.ts} | 0 src/renderer/reducers/{repos.js => repos.ts} | 0 src/renderer/{routes.jsx => routes.tsx} | 2 +- .../rxdb/{database.js => database.ts} | 51 +- .../rxdb/{dbExtension.js => dbExtension.ts} | 14 +- .../rxdb/{dbHandler.js => dbHandler.ts} | 122 +- .../{authorSchema.js => authorSchema.ts} | 0 ...{SCCategorySchema.js => categorySchema.ts} | 0 .../{languageSchema.js => languageSchema.ts} | 0 .../rxdb/schemas/{meSchema.js => meSchema.ts} | 0 .../schemas/{repoSchema.js => repoSchema.ts} | 0 .../{settingSchema.js => settingSchema.ts} | 0 .../schemas/{SCTagSchema.js => tagSchema.ts} | 0 ...figureDevStore.js => configureDevStore.ts} | 8 +- ...gureProdStore.js => configureProdStore.ts} | 2 +- .../{configureStore.js => configureStore.ts} | 0 src/renderer/utils/authentication.js | 155 - src/renderer/utils/authentication.ts | 113 + src/renderer/utils/data.js | 78 - src/renderer/utils/data.ts | 69 + src/renderer/utils/{dbName.js => dbName.ts} | 0 .../utils/{electronApp.js => electronApp.ts} | 0 .../{githubClient.js => githubClient.ts} | 11 +- .../utils/{logHelper.js => logHelper.ts} | 4 +- .../{offlineTitle.js => offlineTitle.ts} | 0 tsconfig.json | 28 + typings.json | 13 - typings/globals/antd/index.d.ts | 2077 ------ typings/globals/antd/typings.json | 8 - typings/globals/electron/index.d.ts | 6115 ----------------- typings/globals/electron/typings.json | 8 - typings/globals/mocha/index.d.ts | 230 - typings/globals/mocha/typings.json | 8 - typings/globals/node/index.d.ts | 3630 ---------- typings/globals/node/typings.json | 12 - typings/globals/redux/index.d.ts | 401 -- typings/globals/redux/typings.json | 8 - typings/index.d.ts | 9 - .../extract-text-webpack-plugin/index.d.ts | 53 - .../extract-text-webpack-plugin/typings.json | 8 - typings/modules/react-dom/index.d.ts | 67 - typings/modules/react-dom/typings.json | 8 - typings/modules/react-redux/index.d.ts | 107 - typings/modules/react-redux/typings.json | 17 - typings/modules/react/index.d.ts | 2858 -------- typings/modules/react/typings.json | 8 - webpack/base.conf.babel.js | 130 + webpack/dev.conf.babel.js | 68 + webpack/dll.conf.babel.js | 63 + webpack/prod.conf.babel.js | 83 + yarn.lock | 4045 ++++++----- 105 files changed, 2922 insertions(+), 18721 deletions(-) delete mode 100644 .eslintrc.js create mode 100644 .prettierrc create mode 100644 .stylelintrc create mode 100644 .tslintrc.json delete mode 100644 build/dev-server.js delete mode 100644 build/webpack.base.conf.babel.js delete mode 100644 build/webpack.dev.conf.babel.js delete mode 100644 build/webpack.prod.conf.babel.js rename jsconfig.json => index.d.ts (100%) rename src/renderer/{ => assets}/styles/global/antd-theme.less (100%) rename src/renderer/{ => assets}/styles/global/global.less (100%) rename src/renderer/{ => assets}/styles/global/iconfont.css (100%) rename src/renderer/{ => assets}/styles/global/normalize.css (100%) rename src/renderer/{ => assets}/styles/global/system.less (100%) rename src/renderer/{ => assets}/styles/login.less (100%) rename src/renderer/{ => assets}/styles/main.less (100%) rename src/renderer/{ => assets}/styles/setting.less (100%) rename src/renderer/components/{app.jsx => app.tsx} (77%) rename src/renderer/components/{filterBar.jsx => filterBar.tsx} (76%) rename src/renderer/components/{loginPage.jsx => loginPage.tsx} (79%) rename src/renderer/constants/{index.js => index.ts} (97%) rename src/renderer/containers/{app.jsx => app.tsx} (100%) rename src/renderer/containers/{filterBar.jsx => filterBar.tsx} (100%) rename src/renderer/containers/{loginPage.jsx => loginPage.tsx} (100%) rename src/renderer/containers/{mainDetailPane.jsx => mainDetailPane.tsx} (100%) rename src/renderer/containers/{mainGroupAvatar.jsx => mainGroupAvatar.tsx} (82%) rename src/renderer/containers/{mainGroupFooter.jsx => mainGroupFooter.tsx} (100%) rename src/renderer/containers/{mainGroupNavs.jsx => mainGroupNavs.tsx} (100%) rename src/renderer/containers/{mainGroupPane.jsx => mainGroupPane.tsx} (72%) rename src/renderer/containers/{mainListPane.jsx => mainListPane.tsx} (100%) rename src/renderer/containers/{mainPage.jsx => mainPage.tsx} (100%) rename src/renderer/containers/{mainSearchBox.jsx => mainSearchBox.tsx} (100%) rename src/renderer/containers/{refreshIndicator.jsx => refreshIndicator.tsx} (100%) rename src/renderer/containers/{repoClassifyTool.jsx => repoClassifyTool.tsx} (100%) rename src/renderer/containers/{repoContributorsBar.jsx => repoContributorsBar.tsx} (87%) rename src/renderer/containers/{repoDetail.jsx => repoDetail.tsx} (82%) rename src/renderer/containers/{repoDetailToolbar.jsx => repoDetailToolbar.tsx} (100%) rename src/renderer/containers/{repoReadme.jsx => repoReadme.tsx} (100%) rename src/renderer/containers/{repoTagsBar.jsx => repoTagsBar.tsx} (100%) rename src/renderer/containers/{reposList.jsx => reposList.tsx} (100%) rename src/renderer/containers/{settingPage.jsx => settingPage.tsx} (100%) rename src/renderer/containers/{sortBar.jsx => sortBar.tsx} (100%) rename src/renderer/{index.jsx => index.tsx} (54%) rename src/renderer/reducers/{accounts.js => accounts.ts} (79%) rename src/renderer/reducers/{categories.js => categories.ts} (100%) rename src/renderer/reducers/{conditional.js => conditional.ts} (77%) rename src/renderer/reducers/{db.js => db.ts} (100%) rename src/renderer/reducers/{index.js => index.ts} (77%) rename src/renderer/reducers/{languages.js => languages.ts} (100%) rename src/renderer/reducers/{network.js => network.ts} (77%) rename src/renderer/reducers/{profile.js => profile.ts} (100%) rename src/renderer/reducers/{repo.js => repo.ts} (100%) rename src/renderer/reducers/{repos.js => repos.ts} (100%) rename src/renderer/{routes.jsx => routes.tsx} (87%) rename src/renderer/rxdb/{database.js => database.ts} (66%) rename src/renderer/rxdb/{dbExtension.js => dbExtension.ts} (79%) rename src/renderer/rxdb/{dbHandler.js => dbHandler.ts} (89%) rename src/renderer/rxdb/schemas/{authorSchema.js => authorSchema.ts} (100%) rename src/renderer/rxdb/schemas/{SCCategorySchema.js => categorySchema.ts} (100%) rename src/renderer/rxdb/schemas/{languageSchema.js => languageSchema.ts} (100%) rename src/renderer/rxdb/schemas/{meSchema.js => meSchema.ts} (100%) rename src/renderer/rxdb/schemas/{repoSchema.js => repoSchema.ts} (100%) rename src/renderer/rxdb/schemas/{settingSchema.js => settingSchema.ts} (100%) rename src/renderer/rxdb/schemas/{SCTagSchema.js => tagSchema.ts} (100%) rename src/renderer/store/{configureDevStore.js => configureDevStore.ts} (76%) rename src/renderer/store/{configureProdStore.js => configureProdStore.ts} (100%) rename src/renderer/store/{configureStore.js => configureStore.ts} (100%) delete mode 100644 src/renderer/utils/authentication.js create mode 100644 src/renderer/utils/authentication.ts delete mode 100644 src/renderer/utils/data.js create mode 100644 src/renderer/utils/data.ts rename src/renderer/utils/{dbName.js => dbName.ts} (100%) rename src/renderer/utils/{electronApp.js => electronApp.ts} (100%) rename src/renderer/utils/{githubClient.js => githubClient.ts} (86%) rename src/renderer/utils/{logHelper.js => logHelper.ts} (71%) rename src/renderer/utils/{offlineTitle.js => offlineTitle.ts} (100%) create mode 100644 tsconfig.json delete mode 100644 typings.json delete mode 100644 typings/globals/antd/index.d.ts delete mode 100644 typings/globals/antd/typings.json delete mode 100644 typings/globals/electron/index.d.ts delete mode 100644 typings/globals/electron/typings.json delete mode 100644 typings/globals/mocha/index.d.ts delete mode 100644 typings/globals/mocha/typings.json delete mode 100644 typings/globals/node/index.d.ts delete mode 100644 typings/globals/node/typings.json delete mode 100644 typings/globals/redux/index.d.ts delete mode 100644 typings/globals/redux/typings.json delete mode 100644 typings/index.d.ts delete mode 100644 typings/modules/extract-text-webpack-plugin/index.d.ts delete mode 100644 typings/modules/extract-text-webpack-plugin/typings.json delete mode 100644 typings/modules/react-dom/index.d.ts delete mode 100644 typings/modules/react-dom/typings.json delete mode 100644 typings/modules/react-redux/index.d.ts delete mode 100644 typings/modules/react-redux/typings.json delete mode 100644 typings/modules/react/index.d.ts delete mode 100644 typings/modules/react/typings.json create mode 100644 webpack/base.conf.babel.js create mode 100644 webpack/dev.conf.babel.js create mode 100644 webpack/dll.conf.babel.js create mode 100644 webpack/prod.conf.babel.js diff --git a/.babelrc b/.babelrc index eae2e91..b79d0e9 100644 --- a/.babelrc +++ b/.babelrc @@ -1,8 +1,17 @@ { - "presets": ["es2015", "es2017", "stage-2"], - "plugins": ["transform-runtime", "transform-decorators-legacy", "transform-object-rest-spread", ["transform-async-to-module-method", { - "module": "bluebird", - "method": "coroutine" - }], ["import", {"libraryName": "antd", "style": true}]], - "comments": false + "presets": ["react", "es2015", "es2017", "stage-2"], + "plugins": [ + "transform-runtime", + "transform-decorators-legacy", + "transform-object-rest-spread", + [ + "transform-async-to-module-method", + { + "module": "bluebird", + "method": "coroutine" + } + ], + ["import", { "libraryName": "antd", "style": true }] + ], + "comments": false } diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 3501fb5..0000000 --- a/.eslintrc.js +++ /dev/null @@ -1,36 +0,0 @@ -// http://eslint.org/docs/user-guide/getting-started#configuration -// "off" or 0 - turn the rule off -// "warn" or 1 - turn the rule on as a warning (doesn’t affect exit code) -// "error" or 2 - turn the rule on as an error (exit code will be 1) - -module.exports = { - parser: "babel-eslint", - root: true, - // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style - extends: "standard", - env: { - es6: true, - node: true, - browser: true - }, - // required to lint *.vue files - plugins: ["html"], - // add your custom rules here - rules: { - // allow paren-less arrow functions - "arrow-parens": 0, - // allow debugger during development - "no-debugger": process.env.NODE_ENV === "production" ? 2 : 0, - // indent - indent: [0, 2, { SwitchCase: 2 }], - // unused vars - "no-unused-vars": 0, - "no-multi-spaces": [ - "error", - { exceptions: { ImportDeclaration: true } } - ], - quotes: ["error", "double"], - semi: ["error", "always", { omitLastInOneLineBlock: true }], - "space-before-function-paren": ["error", "never"] - } -}; diff --git a/.gitignore b/.gitignore index 7174b40..8c2e3f2 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,4 @@ dist/ release/ .idea/ .vscode/ -debug.log +*.log diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..a27a5d7 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,4 @@ +{ + "tabWidth": 4, + "printWidth": 100 +} diff --git a/.stylelintrc b/.stylelintrc new file mode 100644 index 0000000..24d296e --- /dev/null +++ b/.stylelintrc @@ -0,0 +1,29 @@ +{ + "extends": "stylelint-config-standard", + "rules": { + "at-rule-empty-line-before": null, + "at-rule-name-space-after": null, + "comment-empty-line-before": null, + "declaration-bang-space-before": null, + "declaration-empty-line-before": null, + "declaration-colon-newline-after": null, + "function-comma-newline-after": null, + "function-name-case": null, + "function-parentheses-newline-inside": null, + "function-max-empty-lines": null, + "function-whitespace-after": null, + "value-list-comma-newline-after": null, + "indentation": null, + "number-leading-zero": null, + "number-no-trailing-zeros": null, + "rule-empty-line-before": null, + "selector-combinator-space-after": null, + "selector-list-comma-newline-after": null, + "selector-pseudo-element-colon-notation": null, + "unit-no-unknown": null, + "value-list-max-empty-lines": null, + "no-empty-source": null, + "selector-combinator-space-before": null, + "selector-pseudo-class-no-unknown": null + } +} \ No newline at end of file diff --git a/.tslintrc.json b/.tslintrc.json new file mode 100644 index 0000000..e619c3e --- /dev/null +++ b/.tslintrc.json @@ -0,0 +1,111 @@ +{ + "extends": ["tslint-react", "tslint-eslint-rules", "custom-tslint-rules-collection"], + "rules": { + "align": [true, "parameters", "statements"], + "class-name": true, + "comment-format": [true, "check-space"], + "curly": true, + "object-curly-spacing": true, + "eofline": true, + "forin": true, + "indent": [true, "spaces"], + "jsdoc-format": false, + "label-position": true, + "max-line-length": [false, 120], + "member-ordering": [ + false, + { + "order": "statics-first" + } + ], + "new-parens": true, + "no-any": false, + "no-arg": true, + "no-bitwise": true, + "no-conditional-assignment": true, + "no-consecutive-blank-lines": true, + "no-console": [true, "debug", "info", "time", "timeEnd", "trace"], + "no-construct": true, + "no-constructor-vars": false, + "no-debugger": true, + "no-duplicate-variable": true, + "no-empty": false, + "no-eval": true, + "no-internal-module": true, + "no-namespace": true, + "no-reference": true, + "no-shadowed-variable": true, + "no-string-literal": true, + "no-switch-case-fall-through": false, + "no-trailing-whitespace": true, + "no-unused-expression": true, + "no-use-before-declare": false, + "no-var-keyword": true, + "no-var-requires": false, + "object-literal-sort-keys": false, + "one-line": [ + true, + "check-catch", + "check-else", + "check-finally", + "check-open-brace", + "check-whitespace" + ], + "one-variable-per-declaration": [true, "ignore-for-loop"], + "quotemark": [true, "double", "jsx-double"], + "radix": true, + "semicolon": [true, "always", "ignore-bound-class-methods"], + "switch-default": true, + "trailing-comma": [ + true, + { + "singleline": "never", + "multiline": "never" + } + ], + "triple-equals": [true, "allow-null-check"], + "typedef": false, + "typedef-whitespace": [ + true, + { + "call-signature": "nospace", + "index-signature": "nospace", + "parameter": "nospace", + "property-declaration": "nospace", + "variable-declaration": "nospace" + }, + { + "call-signature": "onespace", + "index-signature": "onespace", + "parameter": "onespace", + "property-declaration": "onespace", + "variable-declaration": "onespace" + } + ], + "use-isnan": true, + "variable-name": [ + true, + "allow-leading-underscore", + "ban-keywords", + "check-format", + "allow-pascal-case" + ], + "whitespace": [ + true, + "check-branch", + "check-decl", + "check-operator", + "check-separator", + "check-type", + "check-typecast" + ], + "tsx-no-any-props": true, + "tsx-no-any-state": true, + "jsx-no-lambda": false, + "jsx-no-string-ref": false, + "jsx-boolean-value": [true, "never"], + "jsx-wrap-multiline": false, + "jsx-alignment": false, + "jsx-no-multiline-js": false + } +} diff --git a/build/dev-server.js b/build/dev-server.js deleted file mode 100644 index b1739e2..0000000 --- a/build/dev-server.js +++ /dev/null @@ -1,53 +0,0 @@ -import express from 'express' -import webpack from 'webpack' -import devConfig from './webpack.dev.conf.babel' -import webpackDevMiddleware from 'webpack-dev-middleware'; -import webpackHotMiddleware from 'webpack-hot-middleware'; -import { spawn } from 'child_process'; - -let app = express() -let compiler = webpack(devConfig) -const PORT = process.env.PORT || 3000 - -const devMiddleware = webpackDevMiddleware(compiler, { - publicPath: devConfig.output.publicPath, - stats: { - colors: true - // chunks: false - } -}) - -let hotMiddleware = webpackHotMiddleware(compiler) - -// force page reload when html-webpack-plugin template changes -compiler.plugin('compilation', function (compilation) { - compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) { - hotMiddleware.publish({ action: 'reload' }) - cb() - }) -}) - -// handle fallback for HTML5 history API -app.use(require('connect-history-api-fallback')()) -// serve webpack bundle output -app.use(devMiddleware) -// enable hot-reload and state-preserving -// compilation error display -app.use(hotMiddleware) -// serve pure static assets -app.use('/static', express.static('./static')) - -const server = app.listen(PORT, 'localhost', err => { - if (err) { - return console.error(err) - } - console.log('Listening at http://localhost:' + PORT) -}) - -process.on('SIGTERM', () => { - console.log('Stopping dev server') - devMiddleware.close() - server.close(() => { - process.exit(0) - }) -}) diff --git a/build/webpack.base.conf.babel.js b/build/webpack.base.conf.babel.js deleted file mode 100644 index cdfe588..0000000 --- a/build/webpack.base.conf.babel.js +++ /dev/null @@ -1,126 +0,0 @@ -import path from "path"; -import webpack from "webpack"; -import ExtractTextPlugin from "extract-text-webpack-plugin"; - -export default { - // http://webpack.github.io/docs/configuration.html#node - node: { - __filename: false, - __dirname: false - }, - output: { - path: path.resolve(__dirname, "../dist"), - publicPath: "../dist/", - filename: "[name].js" - }, - resolve: { - extensions: [".js", ".jsx", ".css", ".less", ".scss"], - modules: [path.join(__dirname, "../node_modules")], - alias: { - app: path.resolve(__dirname, "../app"), - dist: path.resolve(__dirname, "../dist"), - src: path.resolve(__dirname, "../src") - } - }, - target: "electron-renderer", // important - module: { - rules: [ - { - test: /\.jsx$/, - loader: "eslint-loader", - exclude: /node_modules/, - enforce: "pre", - options: { - formatter: require("eslint-friendly-formatter") - } - }, - { - test: /\.js$/, - loader: "eslint-loader", - exclude: /node_modules/, - enforce: "pre", - options: { - formatter: require("eslint-friendly-formatter") - } - }, - { - test: /\.js$/, - loader: "babel-loader?presets[]=es2015&presets[]=stage-2", - exclude: /node_modules/ - }, - { - test: /\.json$/, - loader: "json-loader" - }, - { - test: /\.css$/, - include: [/global/, /node_modules/], - loader: ExtractTextPlugin.extract({ - fallback: "style-loader", - use: "css-loader?sourceMap" - }) - }, - { - test: /\.css$/, - exclude: [/global/, /node_modules/], - loader: ExtractTextPlugin.extract({ - fallback: "style-loader", - use: - "css-loader?modules&sourceMap&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]" - }) - }, - { - test: /\.less$/, - include: [/global/, /node_modules/], - loader: ExtractTextPlugin.extract({ - fallback: "style-loader", - use: - 'css-loader?sourceMap!less-loader?{"modifyVars": {"primary-color": "#3498db"}}' - }) - }, - { - test: /\.less$/, - exclude: [/global/, /node_modules/], - loader: ExtractTextPlugin.extract({ - fallback: "style-loader", - use: - "css-loader?modules&sourceMap&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!less-loader" - }) - }, - { - test: /\.(png|jpg|gif)$/, - exclude: /node_modules/, - loader: "url-loader", - query: { - limit: 2000, - name: "assets/images/[name].[ext]" // 'assets/images/[name].[ext]?[hash:7]' - } - }, - { - test: /\.(woff|woff2|eot|ttf|svg)/, // if /\.(woff|woff2|eot|ttf|svg)$/ the font-awesome with url like xx.woff?v=4.7.0 can not be loaded - exclude: /node_modules/, - loader: "url-loader", - query: { - limit: 10000, - name: "assets/fonts/[name].[ext]" - } - }, - { - test: /\.node$/, - loader: "node-loader" - } - ] - }, - plugins: [ - new webpack.optimize.OccurrenceOrderPlugin(), - // extract css to one file - new ExtractTextPlugin({ - filename: - process.env.NODE_ENV === "production" - ? "style.min.css" - : "style.css", - disable: false, - allChunks: true - }) - ] -}; diff --git a/build/webpack.dev.conf.babel.js b/build/webpack.dev.conf.babel.js deleted file mode 100644 index 8e127b3..0000000 --- a/build/webpack.dev.conf.babel.js +++ /dev/null @@ -1,60 +0,0 @@ -import path from 'path' -import webpack from 'webpack' -import baseConfig from './webpack.base.conf.babel' -import merge from 'webpack-merge' -import HtmlWebpackPlugin from 'html-webpack-plugin' - -const port = process.env.PORT || 3000 - -let devConfig = { - // eval-source-map is faster for development - devtool: '#source-map', // '#eval-source-map', - - entry: { - app: [ - `webpack-hot-middleware/client?path=http://localhost:${port}/__webpack_hmr`, - 'babel-polyfill', - './src/renderer/index.jsx' - ], - electron: [ - `webpack-hot-middleware/client?path=http://localhost:${port}/__webpack_hmr`, - 'babel-polyfill', - './src/main/index.js' - ] - }, - - output: { - path: path.resolve(__dirname, '../dist'), - publicPath: `http://localhost:${port}/static/` - }, - - module: { - rules: [ - { - test: /\.jsx$/, - exclude: /node_modules/, - loaders: ['react-hot-loader', 'babel-loader?presets[]=react&presets[]=es2015&presets[]=es2017&presets[]=stage-2'] - } - ] - }, - - plugins: [ - new webpack.DefinePlugin({ - 'process.env': { - NODE_ENV: JSON.stringify('development') - } - }), - new webpack.HotModuleReplacementPlugin(), - new webpack.NoEmitOnErrorsPlugin(), - // https://github.com/ampedandwired/html-webpack-plugin - new HtmlWebpackPlugin({ - template: 'src/renderer/index.html', - filename: '../dist/index.html', - inject: true, - excludeChunks: ['electron'], - bodyClass: `platform_${process.platform}` - }) - ] -} - -export default merge(baseConfig, devConfig) diff --git a/build/webpack.prod.conf.babel.js b/build/webpack.prod.conf.babel.js deleted file mode 100644 index dd00f39..0000000 --- a/build/webpack.prod.conf.babel.js +++ /dev/null @@ -1,118 +0,0 @@ -import path from 'path' -import webpack from 'webpack' -import baseConfig from './webpack.base.conf.babel' -import HtmlWebpackPlugin from 'html-webpack-plugin' -import merge from 'webpack-merge' -import OptimizeCssAssetsPlugin from 'optimize-css-assets-webpack-plugin' - -baseConfig.entry = {} - -let appProdConfig = { - // whether to generate source map for production files. - // disabling this can speed up the build. - devtool: false, // '#source-map', - - entry: { - app: [ - 'babel-polyfill', - './src/renderer/index.jsx' - ] - }, - - output: { - filename: '[name].[chunkhash:8].js', - chunkFilename: '[id].js', - path: path.resolve(__dirname, '../app/dist'), - publicPath: './' - }, - - module: { - rules: [ - { - test: /\.jsx$/, - loader: 'babel-loader?presets[]=react&presets[]=es2015&presets[]=es2017&presets[]=stage-2', - exclude: /node_modules/ - } - ] - }, - - plugins: [ - new webpack.DefinePlugin({ - 'process.env': { - NODE_ENV: JSON.stringify('production') - } - }), - new webpack.optimize.UglifyJsPlugin({ - compress: { - warnings: false - }, - mangle: { - except: ['exports', 'require', 'RxSchema', 'RxDatabase'] - }, - sourceMap: false - }), - new OptimizeCssAssetsPlugin({ - assetNameRegExp: /\.min\.css$/g, - cssProcessor: require('cssnano'), - cssProcessorOptions: { discardComments: {removeAll: true } }, - canPrint: true - }), - // see https://github.com/ampedandwired/html-webpack-plugin - new HtmlWebpackPlugin({ - filename: '../../app/dist/index.html', - template: 'src/renderer/index.html', - inject: true, - minify: { - removeComments: true, - collapseWhitespace: true, - removeAttributeQuotes: true - // more options: - // https://github.com/kangax/html-minifier#options-quick-reference - }, - bodyClass: `platform_${process.platform}` - }) - ] -} - -let electronProdConfig = { - // whether to generate source map for production files. - // disabling this can speed up the build. - devtool: false, // '#source-map', - - entry: { - electron: [ - 'babel-polyfill', - './src/main/index.js' - ] - }, - - output: { - filename: '[name].js', // for Electron, the main entry name is fixed in package.json, hash should removed - chunkFilename: '[id].js', - path: path.resolve(__dirname, '../app/dist'), - publicPath: './', - libraryTarget: "commonjs" // important for set externals // http://webpack.github.io/docs/configuration.html#externals - }, - - externals: [ - "keytar" - ], - - plugins: [ - new webpack.DefinePlugin({ - 'process.env': { - NODE_ENV: JSON.stringify('production') - } - }), - new webpack.optimize.UglifyJsPlugin({ - compress: { - warnings: false - } - }), - ] -} - -export default [ - merge(baseConfig, appProdConfig), - merge(baseConfig, electronProdConfig) -] diff --git a/jsconfig.json b/index.d.ts similarity index 100% rename from jsconfig.json rename to index.d.ts diff --git a/package.json b/package.json index 2b81468..91aa5f4 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,10 @@ "target": "nsis" }, "linux": { - "target": ["AppImage", "deb"] + "target": [ + "AppImage", + "deb" + ] }, "directories": { "app": "app", @@ -23,20 +26,6 @@ } }, "postinstall": "install-app-deps", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", - "dev-server": - "cross-env NODE_ENV=development PORT=3000 node -r babel-register build/dev-server.js", - "build": - "rimraf app/dist && mkdirp app/dist && cross-env NODE_ENV=production webpack --progress --hide-modules --config build/webpack.prod.conf.babel.js", - "build-dev": - "rimraf dist && mkdirp dist && cross-env NODE_ENV=development PORT=3000 webpack --progress --hide-modules --config build/webpack.dev.conf.babel.js", - "dev": "npm run build-dev && npm run dev-server", - "start": "electron .", - "pack": "npm run build && build --dir", - "dist": "npm run build && build", - "rebuild": "electron-rebuild" - }, "repository": { "type": "git", "url": "git+https://github.com/thundernet8/StarCabinet.git" @@ -60,100 +49,95 @@ "url": "https://github.com/thundernet8/StarCabinet/issues" }, "homepage": "https://github.com/thundernet8/StarCabinet#readme", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "dll": "cross-env NODE_ENV=production webpack -p --hide-modules --config webpack/dll.conf.babel.js", + "dll:dev": "cross-env NODE_ENV=development webpack --hide-modules --config webpack/dll.conf.babel.js", + "build": "rimraf app/dist && mkdirp app/dist && cross-env NODE_ENV=production npm run dll && cross-env NODE_ENV=production webpack -p --progress --hide-modules --config webpack/prod.conf.babel.js", + "build:dev": "rimraf dist && mkdirp dist && cross-env NODE_ENV=development npm run dll:dev && webpack --progress --hide-modules --config webpack/dev.conf.babel.js", + "dev": "npm run build:dev && webpack-dev-server --config webpack/dev.conf.babel.js", + "analyze": "cross-env ANALYZE_ENV=true npm run build", + "start": "electron .", + "pack": "npm run build && build --dir", + "dist": "npm run build && build", + "rebuild": "electron-rebuild", + "lint": "npm run lint:ts && npm run lint:style", + "lint:ts": "tslint -e node_modules typings -c .tslintrc.json src/**/*.tsx", + "lint:style": "stylelint \"src/**/*.less\" --syntax less", + "lint-staged": "lint-staged", + "lint-staged:ts": "tslint --fix -c .tslintrc.json", + "lint-staged:style": "stylelint --syntax less" + }, + "lint-staged": { + "src/**/*.{ts,tsx}": [ + "lint-staged:ts" + ], + "src/**/*.less": [ + "lint-staged:style" + ] + }, + "pre-commit": "lint-staged", "devDependencies": { - "@types/keytar": "^3.0.29", - "@types/react": "^15.0.12", - "@types/react-dom": "^0.14.23", - "babel-core": "^6.20.0", - "babel-eslint": "^6.1.2", - "babel-loader": "^6.2.10", - "babel-plugin-import": "^1.1.1", - "babel-plugin-transform-async-to-module-method": "^6.22.0", - "babel-plugin-transform-decorators-legacy": "^1.3.4", - "babel-plugin-transform-object-rest-spread": "^6.23.0", - "babel-plugin-transform-runtime": "^6.15.0", - "babel-polyfill": "^6.23.0", - "babel-preset-es2015": "^6.18.0", - "babel-preset-es2017": "^6.22.0", - "babel-preset-react": "^6.16.0", - "babel-preset-stage-2": "^6.18.0", - "babel-register": "^6.18.0", - "babel-runtime": "^6.20.0", - "clone": "^2.1.0", - "connect-history-api-fallback": "^1.3.0", - "cross-env": "^3.1.3", - "css-loader": "^0.26.2", + "@types/keytar": "^4.0.1", + "@types/node": "^8.5.2", + "@types/react": "^16.0.31", + "@types/webpack-env": "^1.13.3", + "babel-loader": "^7.1.2", + "babel-preset-es2015": "^6.24.1", + "babel-preset-react": "^6.24.1", + "babel-register": "^6.26.0", + "cross-env": "^5.1.3", + "css-loader": "^0.28.7", "cssnano": "^3.10.0", - "deep-equal": "^1.0.1", - "devtron": "^1.4.0", - "electron": "^1.4.15", - "electron-builder": "^10.17.3", - "electron-debug": "^1.1.0", - "electron-devtools-installer": "^2.0.1", - "electron-rebuild": "^1.5.6", - "eslint": "^3.15.0", - "eslint-config-standard": "^6.2.1", - "eslint-friendly-formatter": "^2.0.6", - "eslint-loader": "^1.6.1", - "eslint-plugin-html": "^1.7.0", - "eslint-plugin-promise": "^3.4.0", - "eslint-plugin-standard": "^2.0.1", - "express": "^4.14.0", - "extract-text-webpack-plugin": "^2.0.0", - "file-loader": "^0.10.0", - "html-webpack-plugin": "^2.24.1", - "json": "^9.0.4", - "json-loader": "^0.5.4", - "less": "^2.7.2", - "less-loader": "^2.2.3", + "custom-tslint-rules-collection": "^1.1.0", + "customized-progress-webpack-plugin": "^0.0.3", + "extract-text-webpack-plugin": "^3.0.2", + "file-loader": "^1.1.6", + "html-webpack-plugin": "^2.30.1", + "less": "^2.7.3", + "less-loader": "^4.0.5", + "lint-staged": "^6.0.0", "mkdirp": "^0.5.1", - "node-loader": "^0.6.0", - "optimize-css-assets-webpack-plugin": "^1.3.0", - "postcss": "^5.2.10", - "postcss-cssnext": "^2.9.0", - "postcss-import": "^9.1.0", - "postcss-loader": "^1.2.2", - "postcss-nested": "^1.0.0", - "postcss-smart-import": "^0.6.9", - "rebuild": "^0.1.2", - "rimraf": "^2.5.4", - "rxjs": "^5.2.0", - "scroll-behavior": "^0.9.2", - "style-loader": "^0.13.2", - "url-loader": "^0.5.7", - "webpack": "^2.2.1", - "webpack-dev-middleware": "^1.10.1", - "webpack-dev-server": "^2.4.1", - "webpack-hot-middleware": "^2.17.1", - "webpack-merge": "^3.0.0" + "optimize-css-assets-webpack-plugin": "^3.2.0", + "postcss-cssnext": "^3.0.2", + "postcss-loader": "^2.0.9", + "postcss-smart-import": "^0.7.6", + "pre-commit": "^1.2.2", + "precss": "^2.0.0", + "prettier": "^1.9.2", + "redux-logger": "^3.0.6", + "style-loader": "^0.19.1", + "stylelint": "^8.4.0", + "stylelint-config-standard": "^18.0.0", + "ts-loader": "^3.2.0", + "tslint-eslint-rules": "^4.1.1", + "tslint-react": "^3.3.3", + "typescript": "^2.6.2", + "url-loader": "^0.6.2", + "webpack": "^3.10.0", + "webpack-bundle-analyzer": "^2.9.1", + "webpack-dev-server": "^2.9.7" }, "devEngines": { "node": ">=6.x", "npm": ">=3.x" }, "dependencies": { - "antd": "^2.8.0", - "bluebird": "^3.4.7", - "blueimp-md5": "^2.7.0", + "antd": "^3.0.0-rc.4", + "bluebird": "^3.5.1", + "blueimp-md5": "^2.10.0", "classnames": "^2.2.5", + "electron": "^1.7.10", "github-api": "^3.0.0", - "github-markdown-css": "^2.4.1", + "github-markdown-css": "^2.9.0", "keytar": "^3.0.2", "pouchdb-adapter-idb": "6.1.2", - "react": "^15.4.2", - "react-addons-css-transition-group": "^15.4.2", - "react-copy-to-clipboard": "^4.2.3", - "react-css-modules": "^4.1.0", - "react-dom": "^15.4.2", - "react-fontawesome": "^1.5.0", - "react-hot-loader": "^1.3.1", - "react-markdown": "^2.4.5", - "react-redux": "^5.0.2", + "react-dom": "^16.2.0", + "react-redux": "^5.0.6", "react-router": "^3.0.0", - "react-router-redux": "^4.0.7", - "react-router-scroll": "^0.4.1", + "react-router-redux": "^4.0.8", + "react-router-scroll": "^0.4.4", "redux": "^3.6.0", - "redux-logger": "^2.7.4", "redux-thunk": "^2.2.0", "rxdb": "^6.0.1" } diff --git a/src/renderer/styles/global/antd-theme.less b/src/renderer/assets/styles/global/antd-theme.less similarity index 100% rename from src/renderer/styles/global/antd-theme.less rename to src/renderer/assets/styles/global/antd-theme.less diff --git a/src/renderer/styles/global/global.less b/src/renderer/assets/styles/global/global.less similarity index 100% rename from src/renderer/styles/global/global.less rename to src/renderer/assets/styles/global/global.less diff --git a/src/renderer/styles/global/iconfont.css b/src/renderer/assets/styles/global/iconfont.css similarity index 100% rename from src/renderer/styles/global/iconfont.css rename to src/renderer/assets/styles/global/iconfont.css diff --git a/src/renderer/styles/global/normalize.css b/src/renderer/assets/styles/global/normalize.css similarity index 100% rename from src/renderer/styles/global/normalize.css rename to src/renderer/assets/styles/global/normalize.css diff --git a/src/renderer/styles/global/system.less b/src/renderer/assets/styles/global/system.less similarity index 100% rename from src/renderer/styles/global/system.less rename to src/renderer/assets/styles/global/system.less diff --git a/src/renderer/styles/login.less b/src/renderer/assets/styles/login.less similarity index 100% rename from src/renderer/styles/login.less rename to src/renderer/assets/styles/login.less diff --git a/src/renderer/styles/main.less b/src/renderer/assets/styles/main.less similarity index 100% rename from src/renderer/styles/main.less rename to src/renderer/assets/styles/main.less diff --git a/src/renderer/styles/setting.less b/src/renderer/assets/styles/setting.less similarity index 100% rename from src/renderer/styles/setting.less rename to src/renderer/assets/styles/setting.less diff --git a/src/renderer/components/app.jsx b/src/renderer/components/app.tsx similarity index 77% rename from src/renderer/components/app.jsx rename to src/renderer/components/app.tsx index 0a910aa..2694b19 100644 --- a/src/renderer/components/app.jsx +++ b/src/renderer/components/app.tsx @@ -1,10 +1,16 @@ import React from "react"; -import { Link } from "react-router"; import offlineTitle from "../utils/offlineTitle"; import { message } from "antd"; import "../styles/global/global.less"; -export default class App extends React.Component { +interface AppProps { + listenNetworkChange: () => void; + diListenNetworkChange: () => void; +} + +interface AppState {} + +export default class App extends React.Component { componentDidMount() { this.props.listenNetworkChange(); } diff --git a/src/renderer/components/filterBar.jsx b/src/renderer/components/filterBar.tsx similarity index 76% rename from src/renderer/components/filterBar.jsx rename to src/renderer/components/filterBar.tsx index 9bd1008..ebdd8b2 100644 --- a/src/renderer/components/filterBar.jsx +++ b/src/renderer/components/filterBar.tsx @@ -1,13 +1,34 @@ import React from "react"; import classNames from "classnames"; -import styles from "../styles/main"; import { Icon, Menu, Dropdown, Checkbox } from "antd"; import * as CONSTANTS from "../constants"; -export default class FilterBar extends React.Component { - state = { - filters: [] +const styles = require("../assets/styles/main.less"); + +interface FilterCondition { + hasFlag: boolean; + hasNote: boolean; + unread: boolean; +} + +interface FilterBarProps { + fetchStatus: { + fetching: boolean; }; + onUpdateFilterCondition: (condition: FilterCondition) => void; +} + +interface FilterBarState { + filters: string[]; +} + +export default class FilterBar extends React.Component { + constructor(props) { + super(props); + this.state = { + filters: [] + }; + } onMenuSelect = ({ key }) => { if (this.props.fetchStatus && this.props.fetchStatus.fetching) { @@ -30,7 +51,7 @@ export default class FilterBar extends React.Component { filters }); - const filterCondition = { + const filterCondition: FilterCondition = { hasFlag: filters.indexOf(CONSTANTS.FILTER_OPTION_HAS_FLAG) > -1, hasNote: filters.indexOf(CONSTANTS.FILTER_OPTION_HAS_NOTE) > -1, unread: filters.indexOf(CONSTANTS.FILTER_OPTION_UNREAD) > -1 @@ -74,20 +95,12 @@ export default class FilterBar extends React.Component { return (
- + FILTERS -

- {this.state.filters - .map(filter => filterDict[filter]) - .join(",")} -

+

{this.state.filters.map(filter => filterDict[filter]).join(",")}

); } diff --git a/src/renderer/components/loginPage.jsx b/src/renderer/components/loginPage.tsx similarity index 79% rename from src/renderer/components/loginPage.jsx rename to src/renderer/components/loginPage.tsx index 9dc1e61..2f68292 100644 --- a/src/renderer/components/loginPage.jsx +++ b/src/renderer/components/loginPage.tsx @@ -1,18 +1,45 @@ import React from "react"; -import { Link } from "react-router"; -import styles from "../styles/login.less"; import * as EVENTS from "../../shared/events"; import * as SHAREDCONSTANTS from "../../shared/constants"; import { ipcRenderer } from "electron"; import { Input, Icon, Button, message } from "antd"; import classNames from "classnames"; +const styles = require("./assets/styles/login.less"); + message.config({ top: 60, duration: 5 }); -export default class LoginPage extends React.Component { +interface Credentials { + username: string; + password: string; +} + +interface LoginPageProps { + credentials: Credentials; + loginResult: { + success: boolean; + profile: { + name: string; + avatar_url: string; + }; + }; + onRequestLogin: (credentials: Credentials, cb: (success: boolean, msg: string) => void) => void; + onGetLocalCredentials: (local: boolean) => Promise; +} + +interface LoginPageState { + submitting: boolean; + username: string; + password: string; +} + +export default class LoginPage extends React.Component { + private userNameInput: HTMLInputElement; + private passwordInput: HTMLInputElement; + constructor(props) { super(props); this.state = { @@ -22,7 +49,15 @@ export default class LoginPage extends React.Component { }; } - emitUsernameEmpty = e => { + refUsernameInput = input => { + this.userNameInput = input; + }; + + refPasswordInput = input => { + this.passwordInput = input; + }; + + emitUsernameEmpty = () => { if (this.state.submitting) { return; } @@ -54,7 +89,7 @@ export default class LoginPage extends React.Component { }); }; - enterSubmit = e => { + enterSubmit = () => { if (this.state.submitting) { return; } @@ -113,11 +148,7 @@ export default class LoginPage extends React.Component { const passwordSuffix = password ? ( ) : null; - const btnDisabled = - !username || - !password || - username.length < 2 || - password.length < 5; + const btnDisabled = !username || !password || username.length < 2 || password.length < 5; const avatar = this.props.loginResult.profile ? this.props.loginResult.profile.avatar_url : require("../assets/images/icon.png"); @@ -125,11 +156,7 @@ export default class LoginPage extends React.Component {
{SHAREDCONSTANTS.APP}
- + @@ -138,18 +165,12 @@ export default class LoginPage extends React.Component { {this.props.loginResult.success === true && ( -
+
{this.props.loginResult.profile.name}
)} @@ -165,9 +186,7 @@ export default class LoginPage extends React.Component { value={username} onChange={this.onChangeUserName} disabled={submitting} - ref={node => { - this.userNameInput = node; - }} + ref={this.refUsernameInput} />
@@ -180,9 +199,7 @@ export default class LoginPage extends React.Component { value={password} onChange={this.onChangePassword} disabled={submitting} - ref={node => { - this.passwordInput = node; - }} + ref={this.refPasswordInput} />
@@ -193,9 +210,6 @@ export default class LoginPage extends React.Component { loading={submitting} onClick={this.enterSubmit} disabled={btnDisabled} - ref={node => { - this.submitBtn = node; - }} > {submitting ? "" : "Login"} diff --git a/src/renderer/constants/index.js b/src/renderer/constants/index.ts similarity index 97% rename from src/renderer/constants/index.js rename to src/renderer/constants/index.ts index 4967239..362689d 100644 --- a/src/renderer/constants/index.js +++ b/src/renderer/constants/index.ts @@ -175,8 +175,7 @@ export const QUERY_REPO_OWNER_SUCCESS = "QUERY_REPO_OWNER_SUCCESS"; export const QUERY_REPO_OWNER_FAIL = "QUERY_REPO_OWNER_FAIL"; export const QUERY_REPO_CONTRIBUTORS = "QUERY_REPO_CONTRIBUTORS"; -export const QUERY_REPO_CONTRIBUTORS_SUCCESS = - "QUERY_REPO_CONTRIBUTORS_SUCCESS"; +export const QUERY_REPO_CONTRIBUTORS_SUCCESS = "QUERY_REPO_CONTRIBUTORS_SUCCESS"; export const QUERY_REPO_CONTRIBUTORS_FAIL = "QUERY_REPO_CONTRIBUTORS_FAIL"; export const FETCH_REPO_README = "FETCH_REPO_README"; @@ -184,8 +183,7 @@ export const FETCH_REPO_README_SUCCESS = "FETCH_REPO_README_SUCCESS"; export const FETCH_REPO_README_FAIL = "FETCH_REPO_README_FAIL"; export const FETCH_REPO_CONTRIBUTORS = "FETCH_REPO_CONTRIBUTORS"; -export const FETCH_REPO_CONTRIBUTORS_SUCCESS = - "FETCH_REPO_CONTRIBUTORS_SUCCESS"; +export const FETCH_REPO_CONTRIBUTORS_SUCCESS = "FETCH_REPO_CONTRIBUTORS_SUCCESS"; export const FETCH_REPO_CONTRIBUTORS_FAIL = "FETCH_REPO_CONTRIBUTORS_FAIL"; export const UPDATE_SELECTED_REPO = "UPDATE_SELECTED_REPO"; @@ -201,6 +199,5 @@ export const UPDATE_REPO_CATEGORIES_SUCCESS = "UPDATE_REPO_CATEGORIES_SUCCESS"; export const UPDATE_REPO_CATEGORIES_FAIL = "UPDATE_REPO_CATEGORIES_FAIL"; export const UPDATE_REPO_CONTRIBUTORS = "UPDATE_REPO_CONTRIBUTORS"; -export const UPDATE_REPO_CONTRIBUTORS_SUCCESS = - "UPDATE_REPO_CONTRIBUTORS_SUCCESS"; +export const UPDATE_REPO_CONTRIBUTORS_SUCCESS = "UPDATE_REPO_CONTRIBUTORS_SUCCESS"; export const UPDATE_REPO_CONTRIBUTORS_FAIL = "UPDATE_REPO_CONTRIBUTORS_FAIL"; diff --git a/src/renderer/containers/app.jsx b/src/renderer/containers/app.tsx similarity index 100% rename from src/renderer/containers/app.jsx rename to src/renderer/containers/app.tsx diff --git a/src/renderer/containers/filterBar.jsx b/src/renderer/containers/filterBar.tsx similarity index 100% rename from src/renderer/containers/filterBar.jsx rename to src/renderer/containers/filterBar.tsx diff --git a/src/renderer/containers/loginPage.jsx b/src/renderer/containers/loginPage.tsx similarity index 100% rename from src/renderer/containers/loginPage.jsx rename to src/renderer/containers/loginPage.tsx diff --git a/src/renderer/containers/mainDetailPane.jsx b/src/renderer/containers/mainDetailPane.tsx similarity index 100% rename from src/renderer/containers/mainDetailPane.jsx rename to src/renderer/containers/mainDetailPane.tsx diff --git a/src/renderer/containers/mainGroupAvatar.jsx b/src/renderer/containers/mainGroupAvatar.tsx similarity index 82% rename from src/renderer/containers/mainGroupAvatar.jsx rename to src/renderer/containers/mainGroupAvatar.tsx index 838589b..bb14fc8 100644 --- a/src/renderer/containers/mainGroupAvatar.jsx +++ b/src/renderer/containers/mainGroupAvatar.tsx @@ -1,6 +1,5 @@ import { connect } from "react-redux"; import MainGroupAvatar from "../components/mainGroupAvatar"; -import Actions from "../actions"; // Redux connection const mapStateToProps = state => { @@ -9,7 +8,7 @@ const mapStateToProps = state => { }; }; -const mapDispatchToProps = dispatch => { +const mapDispatchToProps = _dispatch => { return {}; }; diff --git a/src/renderer/containers/mainGroupFooter.jsx b/src/renderer/containers/mainGroupFooter.tsx similarity index 100% rename from src/renderer/containers/mainGroupFooter.jsx rename to src/renderer/containers/mainGroupFooter.tsx diff --git a/src/renderer/containers/mainGroupNavs.jsx b/src/renderer/containers/mainGroupNavs.tsx similarity index 100% rename from src/renderer/containers/mainGroupNavs.jsx rename to src/renderer/containers/mainGroupNavs.tsx diff --git a/src/renderer/containers/mainGroupPane.jsx b/src/renderer/containers/mainGroupPane.tsx similarity index 72% rename from src/renderer/containers/mainGroupPane.jsx rename to src/renderer/containers/mainGroupPane.tsx index 6b72e2c..aa12051 100644 --- a/src/renderer/containers/mainGroupPane.jsx +++ b/src/renderer/containers/mainGroupPane.tsx @@ -1,13 +1,12 @@ import { connect } from "react-redux"; import MainGroupPane from "../components/mainGroupPane"; -import Actions from "../actions"; // Redux connection -const mapStateToProps = state => { +const mapStateToProps = _state => { return {}; }; -const mapDispatchToProps = dispatch => { +const mapDispatchToProps = _dispatch => { return {}; }; diff --git a/src/renderer/containers/mainListPane.jsx b/src/renderer/containers/mainListPane.tsx similarity index 100% rename from src/renderer/containers/mainListPane.jsx rename to src/renderer/containers/mainListPane.tsx diff --git a/src/renderer/containers/mainPage.jsx b/src/renderer/containers/mainPage.tsx similarity index 100% rename from src/renderer/containers/mainPage.jsx rename to src/renderer/containers/mainPage.tsx diff --git a/src/renderer/containers/mainSearchBox.jsx b/src/renderer/containers/mainSearchBox.tsx similarity index 100% rename from src/renderer/containers/mainSearchBox.jsx rename to src/renderer/containers/mainSearchBox.tsx diff --git a/src/renderer/containers/refreshIndicator.jsx b/src/renderer/containers/refreshIndicator.tsx similarity index 100% rename from src/renderer/containers/refreshIndicator.jsx rename to src/renderer/containers/refreshIndicator.tsx diff --git a/src/renderer/containers/repoClassifyTool.jsx b/src/renderer/containers/repoClassifyTool.tsx similarity index 100% rename from src/renderer/containers/repoClassifyTool.jsx rename to src/renderer/containers/repoClassifyTool.tsx diff --git a/src/renderer/containers/repoContributorsBar.jsx b/src/renderer/containers/repoContributorsBar.tsx similarity index 87% rename from src/renderer/containers/repoContributorsBar.jsx rename to src/renderer/containers/repoContributorsBar.tsx index d742b05..2ad0a21 100644 --- a/src/renderer/containers/repoContributorsBar.jsx +++ b/src/renderer/containers/repoContributorsBar.tsx @@ -21,6 +21,4 @@ const mapDispatchToProps = dispatch => { }; // Which props to inject from the global atomic state -export default connect(mapStateToProps, mapDispatchToProps)( - RepoContributorsBar -); +export default connect(mapStateToProps, mapDispatchToProps)(RepoContributorsBar); diff --git a/src/renderer/containers/repoDetail.jsx b/src/renderer/containers/repoDetail.tsx similarity index 82% rename from src/renderer/containers/repoDetail.jsx rename to src/renderer/containers/repoDetail.tsx index 5af751c..a59c5f5 100644 --- a/src/renderer/containers/repoDetail.jsx +++ b/src/renderer/containers/repoDetail.tsx @@ -1,6 +1,5 @@ import { connect } from "react-redux"; import RepoDetail from "../components/repoDetail"; -import Actions from "../actions"; // Redux connection const mapStateToProps = state => { @@ -9,7 +8,7 @@ const mapStateToProps = state => { }; }; -const mapDispatchToProps = dispatch => { +const mapDispatchToProps = _dispatch => { return {}; }; diff --git a/src/renderer/containers/repoDetailToolbar.jsx b/src/renderer/containers/repoDetailToolbar.tsx similarity index 100% rename from src/renderer/containers/repoDetailToolbar.jsx rename to src/renderer/containers/repoDetailToolbar.tsx diff --git a/src/renderer/containers/repoReadme.jsx b/src/renderer/containers/repoReadme.tsx similarity index 100% rename from src/renderer/containers/repoReadme.jsx rename to src/renderer/containers/repoReadme.tsx diff --git a/src/renderer/containers/repoTagsBar.jsx b/src/renderer/containers/repoTagsBar.tsx similarity index 100% rename from src/renderer/containers/repoTagsBar.jsx rename to src/renderer/containers/repoTagsBar.tsx diff --git a/src/renderer/containers/reposList.jsx b/src/renderer/containers/reposList.tsx similarity index 100% rename from src/renderer/containers/reposList.jsx rename to src/renderer/containers/reposList.tsx diff --git a/src/renderer/containers/settingPage.jsx b/src/renderer/containers/settingPage.tsx similarity index 100% rename from src/renderer/containers/settingPage.jsx rename to src/renderer/containers/settingPage.tsx diff --git a/src/renderer/containers/sortBar.jsx b/src/renderer/containers/sortBar.tsx similarity index 100% rename from src/renderer/containers/sortBar.jsx rename to src/renderer/containers/sortBar.tsx diff --git a/src/renderer/index.jsx b/src/renderer/index.tsx similarity index 54% rename from src/renderer/index.jsx rename to src/renderer/index.tsx index 481d54e..1c3cb39 100644 --- a/src/renderer/index.jsx +++ b/src/renderer/index.tsx @@ -2,21 +2,16 @@ import React from "react"; import ReactDOM from "react-dom"; import { Router, hashHistory, applyRouterMiddleware } from "react-router"; import { Provider } from "react-redux"; -import { combineReducers } from "redux"; import { syncHistoryWithStore } from "react-router-redux"; -// import useScroll from 'scroll-behavior' import { useScroll } from "react-router-scroll"; import configureStore from "./store/configureStore"; import routes from "./routes"; -// import 'antd/dist/antd.css' // we use 'babel-plugin-import' import antd components css -let store = configureStore(); +declare var window; -// const scrollHistory = useScroll(() => browserHistory)() -// Create an enhanced history that syncs navigation events with the store -// const history = syncHistoryWithStore(scrollHistory, store) +const store = configureStore(); -const history = syncHistoryWithStore(hashHistory, store); // use hashHistory instead browserHistory in case of react-router cannot match routes +const history = syncHistoryWithStore(hashHistory, store); // Make reducers hot reloadable, see http://stackoverflow.com/questions/34243684/make-redux-reducers-and-other-non-components-hot-loadable if (module.hot) { @@ -28,11 +23,7 @@ if (module.hot) { ReactDOM.render( - + , document.getElementById("app") ); diff --git a/src/renderer/reducers/accounts.js b/src/renderer/reducers/accounts.ts similarity index 79% rename from src/renderer/reducers/accounts.js rename to src/renderer/reducers/accounts.ts index c3764d8..6b4cae2 100644 --- a/src/renderer/reducers/accounts.js +++ b/src/renderer/reducers/accounts.ts @@ -1,9 +1,6 @@ import * as CONSTANTS from "../constants"; -export const credentialsReducer = ( - state = { username: "", password: "" }, - action -) => { +export const credentialsReducer = (state = { username: "", password: "" }, action) => { switch (action.type) { case CONSTANTS.GET_LOCAL_CREDENTIALS_SUCCESS: return { @@ -16,10 +13,7 @@ export const credentialsReducer = ( } }; -export const loginResultReducer = ( - state = { success: null, profile: null }, - action -) => { +export const loginResultReducer = (state = { success: null, profile: null }, action) => { switch (action.type) { case CONSTANTS.REQUEST_LOGIN_SUCCESS: return { diff --git a/src/renderer/reducers/categories.js b/src/renderer/reducers/categories.ts similarity index 100% rename from src/renderer/reducers/categories.js rename to src/renderer/reducers/categories.ts diff --git a/src/renderer/reducers/conditional.js b/src/renderer/reducers/conditional.ts similarity index 77% rename from src/renderer/reducers/conditional.js rename to src/renderer/reducers/conditional.ts index 0304eb2..7d3d534 100644 --- a/src/renderer/reducers/conditional.js +++ b/src/renderer/reducers/conditional.ts @@ -5,10 +5,7 @@ const initialSearchCondition = { field: CONSTANTS.SEARCH_FIELD_ALL }; -export const searchConditionReducer = ( - state = initialSearchCondition, - action -) => { +export const searchConditionReducer = (state = initialSearchCondition, action) => { switch (action.type) { case CONSTANTS.UPDATE_SEARCH_CONDITION: return { @@ -26,10 +23,7 @@ const initialFilterCondition = { unread: false }; -export const filterConditionReducer = ( - state = initialFilterCondition, - action -) => { +export const filterConditionReducer = (state = initialFilterCondition, action) => { switch (action.type) { case CONSTANTS.UPDATE_FILTER_CONDITION: return action.filter ? action.filter : initialFilterCondition; // TODO validation @@ -43,10 +37,7 @@ const initialOrderCondition = { desc: true }; -export const orderConditionReducer = ( - state = initialOrderCondition, - action -) => { +export const orderConditionReducer = (state = initialOrderCondition, action) => { switch (action.type) { case CONSTANTS.UPDATE_ORDER_CONDITION: return Object.assign({}, action.order); @@ -60,10 +51,7 @@ const initialGroupCondition = { id: CONSTANTS.GROUP_TYPE_ALL // 0 }; -export const groupConditionReducer = ( - state = initialGroupCondition, - action -) => { +export const groupConditionReducer = (state = initialGroupCondition, action) => { switch (action.type) { case CONSTANTS.UPDATE_GROUP_CONDITION: return Object.assign({}, action.group); diff --git a/src/renderer/reducers/db.js b/src/renderer/reducers/db.ts similarity index 100% rename from src/renderer/reducers/db.js rename to src/renderer/reducers/db.ts diff --git a/src/renderer/reducers/index.js b/src/renderer/reducers/index.ts similarity index 77% rename from src/renderer/reducers/index.js rename to src/renderer/reducers/index.ts index 90db844..b1ec5d2 100644 --- a/src/renderer/reducers/index.js +++ b/src/renderer/reducers/index.ts @@ -3,11 +3,7 @@ import { routerReducer } from "react-router-redux"; import { credentialsReducer, loginResultReducer } from "./accounts"; import { offlineReducer } from "./network"; import { dbConnectReducer } from "./db"; -import { - reposListReducer, - fetchingReposStatusReducer, - reposIncreaseReducer -} from "./repos"; +import { reposListReducer, fetchingReposStatusReducer, reposIncreaseReducer } from "./repos"; import { searchConditionReducer, orderConditionReducer, @@ -17,11 +13,7 @@ import { import { profileReducer } from "./profile"; import { languagesReducer } from "./languages"; import { categoriesReducer, categoryAddingResultReducer } from "./categories"; -import { - selectedRepoReducer, - selectedRepoTagsReducer, - selectedRepoCatsReducer -} from "./repo"; +import { selectedRepoReducer } from "./repo"; export default combineReducers({ routing: routerReducer, @@ -41,6 +33,4 @@ export default combineReducers({ fetchStatus: fetchingReposStatusReducer, catAdd: categoryAddingResultReducer, selectedRepo: selectedRepoReducer - // selectedRepoTags: selectedRepoTagsReducer // use promise instead - // selectedRepoCats: selectedRepoCatsReducer }); diff --git a/src/renderer/reducers/languages.js b/src/renderer/reducers/languages.ts similarity index 100% rename from src/renderer/reducers/languages.js rename to src/renderer/reducers/languages.ts diff --git a/src/renderer/reducers/network.js b/src/renderer/reducers/network.ts similarity index 77% rename from src/renderer/reducers/network.js rename to src/renderer/reducers/network.ts index 4ccfd46..3fe7723 100644 --- a/src/renderer/reducers/network.js +++ b/src/renderer/reducers/network.ts @@ -10,12 +10,12 @@ export const offlineReducer = (state = initialState, action) => { case CONSTANTS.APP_OFFLINE: return { value: true, - time: parseInt(new Date().getTime() / 1000) + time: Math.floor(new Date().getTime() / 1000) }; case CONSTANTS.APP_ONLINE: return { value: false, - time: parseInt(new Date().getTime() / 1000) // time of re-online + time: Math.floor(new Date().getTime() / 1000) // time of re-online }; default: return state; diff --git a/src/renderer/reducers/profile.js b/src/renderer/reducers/profile.ts similarity index 100% rename from src/renderer/reducers/profile.js rename to src/renderer/reducers/profile.ts diff --git a/src/renderer/reducers/repo.js b/src/renderer/reducers/repo.ts similarity index 100% rename from src/renderer/reducers/repo.js rename to src/renderer/reducers/repo.ts diff --git a/src/renderer/reducers/repos.js b/src/renderer/reducers/repos.ts similarity index 100% rename from src/renderer/reducers/repos.js rename to src/renderer/reducers/repos.ts diff --git a/src/renderer/routes.jsx b/src/renderer/routes.tsx similarity index 87% rename from src/renderer/routes.jsx rename to src/renderer/routes.tsx index afb48f3..c2b590e 100644 --- a/src/renderer/routes.jsx +++ b/src/renderer/routes.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { IndexRoute, Route, Link, IndexRedirect, Redirect } from "react-router"; +import { IndexRoute, Route } from "react-router"; /* containers */ import App from "./containers/app"; diff --git a/src/renderer/rxdb/database.js b/src/renderer/rxdb/database.ts similarity index 66% rename from src/renderer/rxdb/database.js rename to src/renderer/rxdb/database.ts index f111103..587f59a 100644 --- a/src/renderer/rxdb/database.js +++ b/src/renderer/rxdb/database.ts @@ -1,48 +1,57 @@ import * as RxDB from "rxdb"; +import { RxDatabase, RxCollectionCreator } from "rxdb"; import Logger from "../utils/logHelper"; import { extendRxDB } from "./dbExtension"; +import repoSchema from "./schemas/repoSchema"; +import authorSchema from "./schemas/authorSchema"; +import meSchema from "./schemas/meSchema"; +import tagSchema from "./schemas/tagSchema"; +import categorySchema from "./schemas/categorySchema"; +import languageSchema from "./schemas/languageSchema"; +import settingSchema from "./schemas/settingSchema"; + +declare var window; RxDB.plugin(require("pouchdb-adapter-idb")); -const collections = [ +const collections: RxCollectionCreator[] = [ { name: "repos", - schema: require("./schemas/repoSchema.js").default, - sync: false + schema: repoSchema as any }, { name: "authors", - schema: require("./schemas/authorSchema.js").default, - sync: false + schema: authorSchema + // sync: false }, { name: "me", - schema: require("./schemas/meSchema.js").default, - sync: false + schema: meSchema + // sync: false }, { name: "tags", - schema: require("./schemas/SCTagSchema.js").default, + schema: tagSchema as any, methods: { countRepos() { return this.repos.length; } - }, - sync: false + } + // sync: false }, { name: "categories", - schema: require("./schemas/SCCategorySchema.js").default, + schema: categorySchema, methods: { countRepos() { return this.repos.length; } - }, - sync: false + } + // sync: false }, { name: "languages", - schema: require("./schemas/languageSchema.js").default, + schema: languageSchema, methods: { countRepos() { return this.repos.length; @@ -51,14 +60,14 @@ const collections = [ }, { name: "settings", - schema: require("./schemas/settingSchema.js").default, - sync: false + schema: settingSchema + // sync: false } ]; -let dbPromise = null; +let dbPromise: Promise; -const _create = async function(dbName, dispatch) { +const _create = async function(dbName, _dispatch) { Logger(`DatabaseService: creating database ${dbName}..`); const db = await RxDB.create({ @@ -70,16 +79,14 @@ const _create = async function(dbName, dispatch) { Logger("DatabaseService: created database"); // debug if (window._DEBUG_) { - window["sc_db"] = db; + window.sc_db = db; // db.$.subscribe(changeEvent => Logger(changeEvent)) } // create collections Logger("DatabaseService: create collections"); - const cols = await Promise.all( - collections.map(colData => db.collection(colData)) - ); + const cols = await Promise.all(collections.map(colData => db.collection(colData))); cols.forEach(col => { extendRxDB(col); diff --git a/src/renderer/rxdb/dbExtension.js b/src/renderer/rxdb/dbExtension.ts similarity index 79% rename from src/renderer/rxdb/dbExtension.js rename to src/renderer/rxdb/dbExtension.ts index 5c9bc3f..a92504d 100644 --- a/src/renderer/rxdb/dbExtension.js +++ b/src/renderer/rxdb/dbExtension.ts @@ -2,21 +2,19 @@ import { default as clone } from "clone"; export const extendRxDB = $this => { // only update specified fields, other fields use old data if existed - const upsertWithFields = async (json, fields = []) => { + const upsertWithFields = async (json, fields: string[] = []) => { json = clone(json); const primary = json[$this.schema.primaryPath]; if (!primary) { - throw new Error( - "RxCollection.upsertWithFields() does not work without primary" - ); + throw new Error("RxCollection.upsertWithFields() does not work without primary"); } const existing = await $this.findOne(primary).exec(); if (existing) { for (let prop in json) { - json.hasOwnProperty(prop) && - fields.indexOf(prop) < 0 && + if (json.hasOwnProperty(prop) && fields.indexOf(prop) < 0) { delete json[prop]; + } } const data = existing._data; @@ -36,9 +34,7 @@ export const extendRxDB = $this => { json = clone(json); const primary = json[$this.schema.primaryPath]; if (!primary) { - throw new Error( - "RxCollection.upsertExcludeFields() does not work without primary" - ); + throw new Error("RxCollection.upsertExcludeFields() does not work without primary"); } const existing = await $this.findOne(primary).exec(); diff --git a/src/renderer/rxdb/dbHandler.js b/src/renderer/rxdb/dbHandler.ts similarity index 89% rename from src/renderer/rxdb/dbHandler.js rename to src/renderer/rxdb/dbHandler.ts index fc7e9f7..5b7691a 100644 --- a/src/renderer/rxdb/dbHandler.js +++ b/src/renderer/rxdb/dbHandler.ts @@ -1,8 +1,10 @@ import * as Database from "./database"; import * as CONSTANTS from "../constants"; -import Promise from "bluebird"; export default class DBHandler { + private dbName: string; + private RxDB; + constructor(dbOrName) { if (typeof dbOrName === "string") { this.dbName = dbOrName; @@ -58,9 +60,9 @@ export default class DBHandler { followers: profile.followers, following: profile.following, createdAt: profile.created_at, - createdTime: parseInt(new Date(profile.created_at) / 1000), + createdTime: Math.floor(new Date(profile.created_at).getTime() / 1000), updatedAt: profile.updated_at, - updatedTime: parseInt(new Date(profile.updated_at) / 1000), + updatedTime: Math.floor(new Date(profile.updated_at).getTime() / 1000), privateGists: profile.private_gists, totalPrivateRepos: profile.total_private_repos, ownedPrivateRepos: profile.owned_private_repos, @@ -95,9 +97,9 @@ export default class DBHandler { this.checkInstance(); let reposCollection = this.RxDB.repos; - let inserts = []; + let inserts: any[] = []; let index = 0; - let repoIds = []; + let repoIds: string[] = []; repos.reverse(); repos.forEach(repo => { @@ -153,11 +155,11 @@ export default class DBHandler { releasesUrl: repo.releases_url, deploymentsUrl: repo.deployments_url, createdAt: repo.created_at, - createdTime: parseInt(new Date(repo.created_at) / 1000), + createdTime: Math.floor(new Date(repo.created_at).getTime() / 1000), updatedAt: repo.updated_at, - updatedTime: parseInt(new Date(repo.updated_at) / 1000), + updatedTime: Math.floor(new Date(repo.updated_at).getTime() / 1000), pushedAt: repo.pushed_at, - pushedTime: parseInt(new Date(repo.pushed_at) / 1000), + pushedTime: Math.floor(new Date(repo.pushed_at).getTime() / 1000), gitUrl: repo.git_url, sshUrl: repo.ssh_url, cloneUrl: repo.clone_url, @@ -195,7 +197,7 @@ export default class DBHandler { // now remove some repos in db but not in fetched data(they were unstarred) await reposCollection.find({ id: { $nin: repoIds } }).remove(); - const results = await Promise.all(inserts); + const results: any[] = await Promise.all(inserts); return results.map(result => result.toJSON()); }; @@ -205,7 +207,7 @@ export default class DBHandler { const reposCollection = this.RxDB.repos; - let args = {}; + let args: { [key: string]: any } = {}; if (conditions.group) { const id = conditions.group.id; // string switch (conditions.group.type) { @@ -216,9 +218,7 @@ export default class DBHandler { case CONSTANTS.GROUP_TYPE_CATEGORY: // we should go to category table to find the repos list const catsCollection = this.RxDB.categories; - const category = await catsCollection - .findOne({ key: { $eq: id } }) - .exec(); + const category = await catsCollection.findOne({ key: { $eq: id } }).exec(); const repoIds = category.repos; args = { id: { $in: repoIds } }; // query = reposCollection.find(args) @@ -227,8 +227,8 @@ export default class DBHandler { const catsCollection2 = this.RxDB.categories; const categories = await catsCollection2.find().exec(); let nrepoIds = []; - categories.forEach(category => { - nrepoIds.concat(category.repos); + categories.forEach(cat => { + nrepoIds.concat(cat.repos); }); nrepoIds = Array.from(new Set(nrepoIds)); args = { id: { $nin: nrepoIds } }; @@ -240,9 +240,15 @@ export default class DBHandler { } if (conditions.filter) { - conditions.filter.hasFlag && (args.flag = { $eq: true }); - conditions.filter.hasNote && (args.note = { $ne: "" }); - conditions.filter.unread && (args.read = { $eq: false }); + if (conditions.filter.hasFlag) { + args.flag = { $eq: true }; + } + if (conditions.filter.hasNote) { + args.note = { $ne: "" }; + } + if (conditions.filter.unread) { + args.read = { $eq: false }; + } } if (conditions.search && conditions.search.key) { @@ -272,8 +278,7 @@ export default class DBHandler { name: { $regex: new RegExp("^" + key + "$", "i") } }) .exec(); - const tagRepoIds = - tag && tag.repos instanceof Array ? tag.repos : []; + const tagRepoIds = tag && tag.repos instanceof Array ? tag.repos : []; if (args.id) { const prevRepoIds = args.id.$in; const postRepoIds = tagRepoIds.filter( @@ -289,7 +294,7 @@ export default class DBHandler { // query = query.find({$or: [{name: {$regex: new RegExp(key, 'i')}}, {description: {$regex: new RegExp(key, 'i')}}, {note: {$regex: new RegExp(key, 'i')}}]}) // TODO this does not work but no error // so use the bad way - let tempRepoIds = []; + let tempRepoIds: string[] = []; const nameSearchDocs = await reposCollection .find( Object.assign({}, args, { @@ -326,7 +331,7 @@ export default class DBHandler { tempRepoIds = Array.from(new Set(tempRepoIds)); if (args.id) { args.id.$in = Array.from( - new Set([].concat(args.id.$in, tempRepoIds)) + new Set(new Array().concat(args.id.$in, tempRepoIds)) ); } else { args.id = { $in: tempRepoIds }; @@ -344,7 +349,7 @@ export default class DBHandler { let docs = await query.exec(); - let repos = []; + let repos: string[] = []; docs.forEach(doc => { let repo = doc.toJSON(); @@ -367,8 +372,8 @@ export default class DBHandler { owners["_" + repo.owner.id] = repo.owner; }); - let ownerIds = []; - let inserts = []; + let ownerIds: string[] = []; + let inserts: any[] = []; for (let key in owners) { if (!owners.hasOwnProperty(key)) { continue; @@ -402,9 +407,7 @@ export default class DBHandler { } // now remove some owners in db but not in fetched data - await authorsCollection - .find({ isOwner: { $eq: true }, id: { $nin: ownerIds } }) - .remove(); + await authorsCollection.find({ isOwner: { $eq: true }, id: { $nin: ownerIds } }).remove(); const results = await Promise.all(inserts); @@ -414,17 +417,15 @@ export default class DBHandler { upsertContributors = async (repoId, contributors) => { this.checkInstance(); - const repo = await this.RxDB.repos - .findOne({ id: { $eq: repoId } }) - .exec(); + const repo = await this.RxDB.repos.findOne({ id: { $eq: repoId } }).exec(); if (!repo) { return false; } const authorsCollection = this.RxDB.authors; - let contributorIds = []; - let inserts = []; + let contributorIds: string[] = []; + let inserts: any[] = []; contributors.forEach(contributor => { if (contributor.id !== repo.owner) { contributorIds.push(contributor.id); @@ -474,9 +475,7 @@ export default class DBHandler { this.checkInstance(); const authorsCollection = this.RxDB.authors; - const docs = await authorsCollection - .find({ repoId: { $eq: repoId } }) - .exec(); + const docs = await authorsCollection.find({ repoId: { $eq: repoId } }).exec(); return docs.map(doc => doc.toJSON()); }; @@ -485,10 +484,8 @@ export default class DBHandler { this.checkInstance(); const settingsCollection = this.RxDB.settings; - const doc = await settingsCollection - .findOne({ id: { $eq: "reposCount" } }) - .exec(); - const oldCount = doc ? parseInt(doc.value) : 0; + const doc = await settingsCollection.findOne({ id: { $eq: "reposCount" } }).exec(); + const oldCount = doc ? parseInt(doc.value, 10) : 0; if (doc) { doc.value = count.toString(); @@ -510,20 +507,22 @@ export default class DBHandler { // await langsCollection.find().remove() // clean the collection - let langs = { + let langs: { [key: string]: string[] } = { _Unknown: [] }; repos.forEach(repo => { if (!repo.language) { - langs["_Unknown"].push(repo.id); + langs._Unknown.push(repo.id); } else { - langs["_" + repo.language] - ? langs["_" + repo.language].push(repo.id) - : (langs["_" + repo.language] = [repo.id]); + if (langs["_" + repo.language]) { + langs["_" + repo.language].push(repo.id); + } else { + langs["_" + repo.language] = [repo.id]; + } } }); - let inserts = []; + let inserts: any[] = []; let index = 1; for (let key in langs) { inserts.push( @@ -549,7 +548,7 @@ export default class DBHandler { let docs = await query.exec(); - let languages = []; + let languages: any[] = []; docs.forEach(doc => { let language = doc.toJSON(); @@ -569,7 +568,7 @@ export default class DBHandler { let docs = await query.exec(); - let categories = []; + let categories: any[] = []; docs.forEach(doc => { let category = doc.toJSON(); @@ -601,8 +600,7 @@ export default class DBHandler { .sort({ id: -1 }) .limit(1) .exec(); - const start = - docs instanceof Array && docs.length > 0 ? docs[0].id + 1 : 1; + const start = docs instanceof Array && docs.length > 0 ? docs[0].id + 1 : 1; const date = new Date(); const category = { @@ -611,7 +609,7 @@ export default class DBHandler { name: name, repos: [], createdAt: date.toISOString(), - createdTime: parseInt(date.getTime() / 1000) + createdTime: Math.floor(date.getTime() / 1000) }; let upsert = await catsCollection.upsert(category); @@ -652,8 +650,7 @@ export default class DBHandler { .sort({ id: -1 }) .limit(1) .exec(); - const start = - docs instanceof Array && docs.length > 0 ? docs[0].id + 1 : 1; + const start = docs instanceof Array && docs.length > 0 ? docs[0].id + 1 : 1; const date = new Date(); const tag = { @@ -662,7 +659,7 @@ export default class DBHandler { name: name, repos: [], createdAt: date.toISOString(), - createdTime: parseInt(date.getTime() / 1000) + createdTime: Math.floor(date.getTime() / 1000) }; let upsert = await tagsCollection.upsert(tag); @@ -725,7 +722,7 @@ export default class DBHandler { } } - repo.rxChange = parseInt(new Date().getTime() / 1000); + repo.rxChange = Math.floor(new Date().getTime() / 1000); await repo.save(); return repo.toJSON(); @@ -740,14 +737,14 @@ export default class DBHandler { .sort({ id: 1 }) .exec(); - let updates = []; - let categories = []; + let updates: any[] = []; + let categories: any[] = []; categoryDocs.forEach(categoryDoc => { if (categoryDoc.repos.indexOf(id) < 0) { let repoIds = categoryDoc.repos; repoIds.push(id); categoryDoc.repos = repoIds; - categoryDoc.updatedTime = parseInt(new Date().getTime() / 1000); + categoryDoc.updatedTime = Math.floor(new Date().getTime() / 1000); updates.push(categoryDoc.save()); } categories.push(categoryDoc.toJSON()); @@ -775,9 +772,12 @@ export default class DBHandler { let tag = await this._upsertTag(tagName); let repoIds = tag.repos; - repoIds.indexOf(id) < 0 && repoIds.push(id); + if (repoIds.indexOf(id) < 0) { + repoIds.push(id); + } + tag.repos = repoIds; - tag.updatedTime = parseInt(new Date().getTime() / 1000); + tag.updatedTime = Math.floor(new Date().getTime() / 1000); await tag.save(); const repoTags = await this.getRepoTags(id); @@ -804,7 +804,7 @@ export default class DBHandler { repoIdIndex > -1 && repoIds.splice(repoIdIndex, 1); } tag.repos = repoIds; - tag.updatedTime = parseInt(new Date().getTime() / 1000); + tag.updatedTime = Math.floor(new Date().getTime() / 1000); await tag.save(); const repoTags = await this.getRepoTags(id); diff --git a/src/renderer/rxdb/schemas/authorSchema.js b/src/renderer/rxdb/schemas/authorSchema.ts similarity index 100% rename from src/renderer/rxdb/schemas/authorSchema.js rename to src/renderer/rxdb/schemas/authorSchema.ts diff --git a/src/renderer/rxdb/schemas/SCCategorySchema.js b/src/renderer/rxdb/schemas/categorySchema.ts similarity index 100% rename from src/renderer/rxdb/schemas/SCCategorySchema.js rename to src/renderer/rxdb/schemas/categorySchema.ts diff --git a/src/renderer/rxdb/schemas/languageSchema.js b/src/renderer/rxdb/schemas/languageSchema.ts similarity index 100% rename from src/renderer/rxdb/schemas/languageSchema.js rename to src/renderer/rxdb/schemas/languageSchema.ts diff --git a/src/renderer/rxdb/schemas/meSchema.js b/src/renderer/rxdb/schemas/meSchema.ts similarity index 100% rename from src/renderer/rxdb/schemas/meSchema.js rename to src/renderer/rxdb/schemas/meSchema.ts diff --git a/src/renderer/rxdb/schemas/repoSchema.js b/src/renderer/rxdb/schemas/repoSchema.ts similarity index 100% rename from src/renderer/rxdb/schemas/repoSchema.js rename to src/renderer/rxdb/schemas/repoSchema.ts diff --git a/src/renderer/rxdb/schemas/settingSchema.js b/src/renderer/rxdb/schemas/settingSchema.ts similarity index 100% rename from src/renderer/rxdb/schemas/settingSchema.js rename to src/renderer/rxdb/schemas/settingSchema.ts diff --git a/src/renderer/rxdb/schemas/SCTagSchema.js b/src/renderer/rxdb/schemas/tagSchema.ts similarity index 100% rename from src/renderer/rxdb/schemas/SCTagSchema.js rename to src/renderer/rxdb/schemas/tagSchema.ts diff --git a/src/renderer/store/configureDevStore.js b/src/renderer/store/configureDevStore.ts similarity index 76% rename from src/renderer/store/configureDevStore.js rename to src/renderer/store/configureDevStore.ts index e64830f..28ae4ba 100644 --- a/src/renderer/store/configureDevStore.js +++ b/src/renderer/store/configureDevStore.ts @@ -1,7 +1,7 @@ -import rootReducer from "../reducers"; import { applyMiddleware, createStore } from "redux"; import ReduxThunk from "redux-thunk"; import createLogger from "redux-logger"; +import rootReducer from "../reducers"; // const logger = createLogger({ // predicate: (getState, action) => action.type !== 'FETCHING' @@ -9,9 +9,5 @@ import createLogger from "redux-logger"; const logger = createLogger({ collapsed: true }); export default function configureStore(initialState) { - return createStore( - rootReducer, - initialState, - applyMiddleware(ReduxThunk, logger) - ); + return createStore(rootReducer, initialState, applyMiddleware(ReduxThunk, logger)); } diff --git a/src/renderer/store/configureProdStore.js b/src/renderer/store/configureProdStore.ts similarity index 100% rename from src/renderer/store/configureProdStore.js rename to src/renderer/store/configureProdStore.ts index 3751334..58f93c0 100644 --- a/src/renderer/store/configureProdStore.js +++ b/src/renderer/store/configureProdStore.ts @@ -1,6 +1,6 @@ -import rootReducer from "../reducers"; import { applyMiddleware, createStore } from "redux"; import ReduxThunk from "redux-thunk"; +import rootReducer from "../reducers"; export default function configureStore(initialState) { return createStore(rootReducer, initialState, applyMiddleware(ReduxThunk)); diff --git a/src/renderer/store/configureStore.js b/src/renderer/store/configureStore.ts similarity index 100% rename from src/renderer/store/configureStore.js rename to src/renderer/store/configureStore.ts diff --git a/src/renderer/utils/authentication.js b/src/renderer/utils/authentication.js deleted file mode 100644 index 81f15c1..0000000 --- a/src/renderer/utils/authentication.js +++ /dev/null @@ -1,155 +0,0 @@ -import GithubClient from "./githubClient"; -import * as EVENTS from "../../shared/events"; -import * as SHAREDCONSTANTS from "../../shared/constants"; -import * as CONSTANTS from "../constants"; -import { ipcRenderer } from "electron"; -import Promise from "bluebird"; -import DBHandler from "../rxdb/dbHandler"; -import dbName from "./dbName"; - -export default class Authentication { - static getLocalCredentials() { - let promise = new Promise((resolve, reject) => { - let username = localStorage.getItem( - CONSTANTS.LOCAL_STORAGE_USERNAME_KEY - ); - if (!username) { - reject(new Error("no local login record")); - } else { - ipcRenderer.send(EVENTS.GET_LOCAL_CREDENTIALS, username); - ipcRenderer.once( - EVENTS.GET_LOCAL_CREDENTIALS_REPLY, - (event, arg) => { - !arg && - reject( - new Error( - "retrieve password from keychain failed" - ) - ); - let credentials = JSON.parse(arg); - if (credentials.username && credentials.password) { - resolve(credentials); - } else { - reject( - new Error( - "retrieve password from keychain failed" - ) - ); - } - } - ); - } - }); - - return promise; - } - - static saveCredentialsToSystem(credentials) { - let promise = new Promise((resolve, reject) => { - localStorage.setItem( - CONSTANTS.LOCAL_STORAGE_USERNAME_KEY, - credentials.username - ); - ipcRenderer.send( - EVENTS.SAVE_CREDENTIALS_TO_SYSTEM, - JSON.stringify(credentials) - ); - ipcRenderer.once( - EVENTS.SAVE_CREDENTIALS_TO_SYSTEM_REPLY, - (event, result) => { - if (result) { - resolve(credentials); - } else { - reject( - new Error("save credentials to keychain failed") - ); - } - } - ); - }); - - return promise; - } - - static saveProfileToLocal(profile) { - let promise = new Promise((resolve, reject) => { - // localStorage.setItem(CONSTANTS.LOCAL_STORAGE_USER_PROFILE, JSON.stringify(profile)) - resolve(profile); - }); - - return promise; - } - - static deleteLocalCredentials() { - let promise = new Promise((resolve, reject) => { - let username = localStorage.getItem( - CONSTANTS.LOCAL_STORAGE_USERNAME_KEY - ); - if (!username) { - resolve(""); - } else { - ipcRenderer.send(EVENTS.DELETE_LOCAL_CREDENTIALS, username); - ipcRenderer.once( - EVENTS.DELETE_LOCAL_CREDENTIALS_REPLY, - (event, result) => { - result - ? resolve(username) - : reject( - new Error( - "delete credentials from keychain failed" - ) - ); - } - ); - } - }); - - return promise; - } - - static signInApp(credentials) { - let githubClient = new GithubClient(credentials); - return githubClient - .getMyProfile() - .then(profile => { - // success stuff - if (profile.login === credentials.username) { - // save credentials to windows credentials - let p1 = Authentication.saveCredentialsToSystem( - credentials, - null - ); - let p2 = Authentication.saveProfileToLocal(profile, null); - // init rxdb and save profile to db - const dbHandler = new DBHandler( - dbName(credentials.username) - ); - let p3 = dbHandler - .initDB() - .then(() => dbHandler.upsertProfile(profile)); - - // show main window now and close login window - setTimeout(() => { - ipcRenderer.send( - EVENTS.SHOW_MAIN_WIN_AND_CLOSE_LOGIN_WIN, - JSON.stringify(credentials) - ); - }, 3000); - - return Promise.all([p1, p2, p3]).then(() => profile); - } else { - return new Error( - "The token you provided does not match this account" - ); - } - }) - .catch(err => { - return err; - }); - } - - static signOutApp() { - localStorage.removeItem(CONSTANTS.LOCAL_STORAGE_USERNAME_KEY); - return Authentication.deleteLocalCredentials(); - } -} diff --git a/src/renderer/utils/authentication.ts b/src/renderer/utils/authentication.ts new file mode 100644 index 0000000..c25d313 --- /dev/null +++ b/src/renderer/utils/authentication.ts @@ -0,0 +1,113 @@ +import GithubClient from "./githubClient"; +import * as EVENTS from "../../shared/events"; +import * as CONSTANTS from "../constants"; +import { ipcRenderer } from "electron"; +import Promise from "bluebird"; +import DBHandler from "../rxdb/dbHandler"; +import dbName from "./dbName"; + +export default class Authentication { + static getLocalCredentials() { + let promise = new Promise((resolve, reject) => { + let username = localStorage.getItem(CONSTANTS.LOCAL_STORAGE_USERNAME_KEY); + if (!username) { + reject(new Error("no local login record")); + } else { + ipcRenderer.send(EVENTS.GET_LOCAL_CREDENTIALS, username); + ipcRenderer.once(EVENTS.GET_LOCAL_CREDENTIALS_REPLY, (_event, arg) => { + if (!arg) { + reject(new Error("retrieve password from keychain failed")); + } + let credentials = JSON.parse(arg); + if (credentials.username && credentials.password) { + resolve(credentials); + } else { + reject(new Error("retrieve password from keychain failed")); + } + }); + } + }); + + return promise; + } + + static saveCredentialsToSystem(credentials) { + let promise = new Promise((resolve, reject) => { + localStorage.setItem(CONSTANTS.LOCAL_STORAGE_USERNAME_KEY, credentials.username); + ipcRenderer.send(EVENTS.SAVE_CREDENTIALS_TO_SYSTEM, JSON.stringify(credentials)); + ipcRenderer.once(EVENTS.SAVE_CREDENTIALS_TO_SYSTEM_REPLY, (_event, result) => { + if (result) { + resolve(credentials); + } else { + reject(new Error("save credentials to keychain failed")); + } + }); + }); + + return promise; + } + + static saveProfileToLocal(profile) { + let promise = new Promise(resolve => { + // localStorage.setItem(CONSTANTS.LOCAL_STORAGE_USER_PROFILE, JSON.stringify(profile)) + resolve(profile); + }); + + return promise; + } + + static deleteLocalCredentials() { + let promise = new Promise((resolve, reject) => { + let username = localStorage.getItem(CONSTANTS.LOCAL_STORAGE_USERNAME_KEY); + if (!username) { + resolve(""); + } else { + ipcRenderer.send(EVENTS.DELETE_LOCAL_CREDENTIALS, username); + ipcRenderer.once(EVENTS.DELETE_LOCAL_CREDENTIALS_REPLY, (_event, result) => { + result + ? resolve(username) + : reject(new Error("delete credentials from keychain failed")); + }); + } + }); + + return promise; + } + + static signInApp(credentials) { + let githubClient = new GithubClient(credentials); + return githubClient + .getMyProfile() + .then(profile => { + // success stuff + if (profile.login === credentials.username) { + // save credentials to windows credentials + let p1 = Authentication.saveCredentialsToSystem(credentials); + let p2 = Authentication.saveProfileToLocal(profile); + // init rxdb and save profile to db + const dbHandler = new DBHandler(dbName(credentials.username)); + let p3 = dbHandler.initDB().then(() => dbHandler.upsertProfile(profile)); + + // show main window now and close login window + setTimeout(() => { + ipcRenderer.send( + EVENTS.SHOW_MAIN_WIN_AND_CLOSE_LOGIN_WIN, + JSON.stringify(credentials) + ); + }, 3000); + + return Promise.all([p1, p2, p3]).then(() => profile); + } else { + return new Error("The token you provided does not match this account"); + } + }) + .catch(err => { + return err; + }); + } + + static signOutApp() { + localStorage.removeItem(CONSTANTS.LOCAL_STORAGE_USERNAME_KEY); + return Authentication.deleteLocalCredentials(); + } +} diff --git a/src/renderer/utils/data.js b/src/renderer/utils/data.js deleted file mode 100644 index d925d4f..0000000 --- a/src/renderer/utils/data.js +++ /dev/null @@ -1,78 +0,0 @@ -import * as EVENTS from "../../shared/events"; -import { ipcRenderer } from "electron"; -import Promise from "bluebird"; - -export const starsDataExportHandler = db => { - return new Promise((resolve, reject) => { - ipcRenderer.send(EVENTS.SHOW_CHOOSE_DIRECTORY_DIALOG); - ipcRenderer.once( - EVENTS.SHOW_CHOOSE_DIRECTORY_DIALOG_REPLG, - (event, path) => { - if (!path) { - reject(new Error("save path is empty")); - } - db - .dump() - .then(data => { - const filePath = path + "/" + db.name + ".json"; - ipcRenderer.send( - EVENTS.EXPORT_STARS_DATA, - JSON.stringify({ - path: filePath, - data: JSON.stringify(data) - }) - ); - ipcRenderer.once( - EVENTS.EXPORT_STARS_DATA_SUCCESS_REPLY, - () => { - resolve("data export successfully"); - } - ); - ipcRenderer.once( - EVENTS.EXPORT_STARS_DATA_FAIL_REPLY, - () => { - reject(new Error("data export failed")); - } - ); - }) - .catch(err => { - reject(new Error(err)); - }); - } - ); - }); -}; - -export const starsDataImportHandler = db => { - return new Promise((resolve, reject) => { - ipcRenderer.send(EVENTS.SHOW_CHOOSE_FILE_DIALOG); - ipcRenderer.once(EVENTS.SENT_IMPORT_STARS_DATA, (event, data) => { - if (!data) { - reject(new Error("file is empty")); - } - - // clear current db first - Promise.all([ - db.repos.find().remove(), - db.authors.find().remove(), - db.me.find().remove(), - db.tags.find().remove(), - db.categories.find().remove(), - db.languages.find().remove(), - db.settings.find().remove() - ]) - .then(() => { - return db.importDump(JSON.parse(data)); - }) - .then(data => { - resolve("data import successfully"); - }) - .catch(err => { - reject(new Error(err)); - }); - }); - ipcRenderer.once(EVENTS.READ_FILE_FAILED, () => { - reject(new Error("read file failed")); - }); - }); -}; diff --git a/src/renderer/utils/data.ts b/src/renderer/utils/data.ts new file mode 100644 index 0000000..5c7775c --- /dev/null +++ b/src/renderer/utils/data.ts @@ -0,0 +1,69 @@ +import * as EVENTS from "../../shared/events"; +import { ipcRenderer } from "electron"; +import Promise from "bluebird"; + +export const starsDataExportHandler = db => { + return new Promise((resolve, reject) => { + ipcRenderer.send(EVENTS.SHOW_CHOOSE_DIRECTORY_DIALOG); + ipcRenderer.once(EVENTS.SHOW_CHOOSE_DIRECTORY_DIALOG_REPLG, (_event, path) => { + if (!path) { + reject(new Error("save path is empty")); + } + db + .dump() + .then(data => { + const filePath = path + "/" + db.name + ".json"; + ipcRenderer.send( + EVENTS.EXPORT_STARS_DATA, + JSON.stringify({ + path: filePath, + data: JSON.stringify(data) + }) + ); + ipcRenderer.once(EVENTS.EXPORT_STARS_DATA_SUCCESS_REPLY, () => { + resolve("data export successfully"); + }); + ipcRenderer.once(EVENTS.EXPORT_STARS_DATA_FAIL_REPLY, () => { + reject(new Error("data export failed")); + }); + }) + .catch(err => { + reject(new Error(err)); + }); + }); + }); +}; + +export const starsDataImportHandler = db => { + return new Promise((resolve, reject) => { + ipcRenderer.send(EVENTS.SHOW_CHOOSE_FILE_DIALOG); + ipcRenderer.once(EVENTS.SENT_IMPORT_STARS_DATA, (_event, data) => { + if (!data) { + reject(new Error("file is empty")); + } + + // clear current db first + Promise.all([ + db.repos.find().remove(), + db.authors.find().remove(), + db.me.find().remove(), + db.tags.find().remove(), + db.categories.find().remove(), + db.languages.find().remove(), + db.settings.find().remove() + ]) + .then(() => { + return db.importDump(JSON.parse(data)); + }) + .then(_data => { + resolve("data import successfully"); + }) + .catch(err => { + reject(new Error(err)); + }); + }); + ipcRenderer.once(EVENTS.READ_FILE_FAILED, () => { + reject(new Error("read file failed")); + }); + }); +}; diff --git a/src/renderer/utils/dbName.js b/src/renderer/utils/dbName.ts similarity index 100% rename from src/renderer/utils/dbName.js rename to src/renderer/utils/dbName.ts diff --git a/src/renderer/utils/electronApp.js b/src/renderer/utils/electronApp.ts similarity index 100% rename from src/renderer/utils/electronApp.js rename to src/renderer/utils/electronApp.ts diff --git a/src/renderer/utils/githubClient.js b/src/renderer/utils/githubClient.ts similarity index 86% rename from src/renderer/utils/githubClient.js rename to src/renderer/utils/githubClient.ts index a51633b..cad9221 100644 --- a/src/renderer/utils/githubClient.js +++ b/src/renderer/utils/githubClient.ts @@ -1,8 +1,9 @@ import GitHubApi from "github-api"; -import Constant from "../constants"; -import Promise from "bluebird"; export default class GithubClient { + private client: GitHubApi; + private me; + constructor(credentials) { this.client = new GitHubApi({ username: credentials.username, @@ -26,11 +27,7 @@ export default class GithubClient { // ugly hack const user = this.me; let requestOptions = user._getOptionsWithDefaults({ sort: "created" }); - return user._requestAllPages( - user.__getScopedUrl("starred"), - requestOptions, - null - ); + return user._requestAllPages(user.__getScopedUrl("starred"), requestOptions, null); }; starStarCabinet = () => { diff --git a/src/renderer/utils/logHelper.js b/src/renderer/utils/logHelper.ts similarity index 71% rename from src/renderer/utils/logHelper.js rename to src/renderer/utils/logHelper.ts index b0a8c55..994923e 100644 --- a/src/renderer/utils/logHelper.js +++ b/src/renderer/utils/logHelper.ts @@ -1,6 +1,8 @@ +declare var window; + const SCLogger = log => { // only on debug mode - if (!window._DEBUG_) return; + if (!window._DEBUG_) { return; } typeof log === "object" ? console.dir(log) : console.log(log); }; diff --git a/src/renderer/utils/offlineTitle.js b/src/renderer/utils/offlineTitle.ts similarity index 100% rename from src/renderer/utils/offlineTitle.js rename to src/renderer/utils/offlineTitle.ts diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..1014b72 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "strictNullChecks": true, + "moduleResolution": "node", + "allowSyntheticDefaultImports": true, + "experimentalDecorators": true, + "jsx": "react", + "noUnusedParameters": true, + "noUnusedLocals": true, + "target": "es2015", + "lib": [ + "dom", + "es7", + "es2015" + ], + "typeRoots": [ + "node_modules/@types", + "typings" + ], + "baseUrl": "./src", + "allowJs": false + }, + "exclude": [ + "node_modules", + "dist", + "**/*.spec.ts?" + ] +} diff --git a/typings.json b/typings.json deleted file mode 100644 index 48271ea..0000000 --- a/typings.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "globalDependencies": { - "antd": "registry:dt/antd#0.12.10+20170123203653", - "electron": "registry:dt/electron#1.4.8+20170202141310", - "mocha": "registry:dt/mocha#2.2.5+20170204022515", - "node": "registry:env/node#6.0.0+20170213133316", - "redux": "registry:dt/redux#3.5.2+20160703092728" - }, - "dependencies": { - "react": "registry:dt/react#15.0.0+20170217213317", - "react-redux": "registry:npm/react-redux#4.4.0+20160614222153" - } -} diff --git a/typings/globals/antd/index.d.ts b/typings/globals/antd/index.d.ts deleted file mode 100644 index 6e2bb75..0000000 --- a/typings/globals/antd/index.d.ts +++ /dev/null @@ -1,2077 +0,0 @@ -// Generated by typings -// Source: https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/9b5329839558a78550bf078c3e5f323c2f0f3b86/antd/index.d.ts -declare namespace Antd { - // Affix - interface AffixProps { - /** - * 达到指定偏移量后触发 - */ - offset?: number - } - /** - * # Affix - * 将页面元素钉在可视范围。 - * ## 何时使用 - * 当内容区域比较长,需要滚动页面时,这部分内容对应的操作或者导航需要在滚动范围内始终展现。常用于侧边菜单和按钮组合。 - * 页面可视范围过小时,慎用此功能以免遮挡页面内容。 - */ - export class Affix extends React.Component { - render(): JSX.Element - } - - - // Alert - interface AlertProps { - /** - * 必选参数,指定警告提示的样式,有四种选择`success`、`info`、`warn`、`error` - */ - type: string, - /**可选参数,默认不显示关闭按钮 */ - closable?: boolean, - /**可选参数,自定义关闭按钮 */ - closeText?: React.ReactNode, - /**必选参数,警告提示内容 */ - message: React.ReactNode, - /**可选参数,警告提示的辅助性文字介绍 */ - description?: React.ReactNode, - /**可选参数,关闭时触发的回调函数 */ - onClose?: Function, - /**可选参数,是否显示辅助图标 */ - showIcon?: boolean - } - - - /** - * # Alert - * 警告提示,展现需要关注的信息。 - - * ## 何时使用 - - * - 当某个页面需要向用户显示警告的信息时。 - * - 非浮层的静态展现形式,始终展现,不会自动消失,用户可以点击关闭。 - * */ - export class Alert extends React.Component { - render(): JSX.Element - } - - - // Badge - /** - * #Badge - * - * 图标右上角的圆形徽标数字。 - - * ## 何时使用 - - * 一般出现在通知图标或头像的右上角,用于显示需要处理的消息条数,通过醒目视觉形式吸引用户处理。 - * - */ - export class Badge extends React.Component { - render(): JSX.Element - } - interface BadgeProps { - /** 展示的数字,大于 overflowCount 时显示为 `${overflowCount}+`,为 0 时隐藏*/ - count: number, - /** 展示封顶的数字值*/ - overflowCount?: number, - /** 不展示数字,只有一个小红点*/ - dot?: boolean - } - - - // Button - interface ButtonProps { - /** 设置按钮类型,可选值为 `primary` `ghost` 或者不设 */ - type?: ButtonType | string, - /** 设置按钮形状,可选值为 `circle` `circle-outline` 或者不设*/ - shape?: string, - /** 设置按钮大小,可选值为 `small` `large` 或者不设*/ - size?: string, - /** 设置 `button` 原生的 `type` 值,可选值请参考 HTML标准*/ - htmlType?: string, - /** `click` 事件的 handler*/ - onClick?: Function, - /** 设置按钮载入状态*/ - loading?: boolean, - /** 样式名*/ - className?: string, - } - - - enum ButtonType { - primary, - ghost, - dashed - } - - interface ButtonGroupProps { - /** 设置按钮大小,可选值为 `small` `large` 或者不设*/ - size?: string - - } - - /** - 可以将多个 `Button` 放入 `Button.Group` 的容器中。 - - 通过设置 `size` 为 `large` `small` 分别把按钮组合设为大、小尺寸。若不设置 `size`,则尺寸为中。*/ - class ButtonGroup extends React.Component { - render(): JSX.Element - } - - /** - * #Button - 按钮用于开始一个即时操作。 - - ## 何时使用 - - 标记了一个(或封装一组)操作命令,响应用户点击行为,触发相应的业务逻辑。*/ - export class Button extends React.Component { - static Group: typeof ButtonGroup - render(): JSX.Element - } - - - - // Breadcrumb - - interface BreadcrumbItemProps { - /** 链接,如不传则不可点击 */ - href?: string - } - export class BreadcrumbItem extends React.Component { - render(): JSX.Element - } - - interface BreadcrumbProps { - /** router 的路由栈信息 */ - routes?: Array, - /** 路由的参数*/ - params?: Object, - /** 分隔符自定义*/ - separator?: string | React.ReactNode - } - /** - * #Breadcrumb - 显示当前页面在系统层级结构中的位置,并能向上返回。 - - ## 何时使用 - - - 当系统拥有超过两级以上的层级结构时; - - 当需要告知用户“你在哪里”时; - - 当需要向上导航的功能时。*/ - export class Breadcrumb extends React.Component { - static Item: typeof BreadcrumbItem - render(): JSX.Element - } - - - // Calendar - interface CalendarProps { - /** 自定义渲染月单元格*/ - monthCellRender?: Function, - /** 自定义渲染日期单元格*/ - dateCellRender?: Function, - /** 是否全屏显示*/ - fullscreen?: boolean, - /** 国际化配置*/ - locale?: Object, - prefixCls?: string, - className?: string, - style?: Object, - /** 日期面板变化回调*/ - onPanelChange?: Function, - /** 展示日期*/ - value?: Date, - /** 默认展示日期*/ - defaultValue?: Date, - /** 初始模式,`month/year`*/ - mode?: string - } - /** - * #Calendar - 按照日历形式展示数据的容器。 - - ## 何时使用 - - 当数据是日期或按照日期划分时,例如日程、课表、价格日历等,农历等。目前支持年/月切换。 - */ - export class Calendar extends React.Component { - render(): JSX.Element - } - - - // Carousel - interface CarouselProps { - /** 动画效果函数,可取 scrollx, fade*/ - effect?: string, - /** 是否显示面板指示点*/ - dots?: boolean, - /** 垂直显示*/ - vertical?: boolean, - /** 是否自动切换*/ - autoplay?: boolean, - /** 动画效果*/ - easing?: string, - /** 切换面板的回调*/ - beforeChange?: Function, - /** 切换面板的回调*/ - afterChange?: Function - } - /** - * #Carousel - 旋转木马,一组轮播的区域。 - - ## 何时使用 - - - 当有一组平级的内容。 - - 当内容空间不足时,可以用走马灯的形式进行收纳,进行轮播展现。 - - 常用于一组图片或卡片轮播。 - */ - export class Carousel extends React.Component { - render(): JSX.Element - } - - - - // Cascader - interface CascaderProps { - /** 可选项数据源*/ - options: Object, - /** 默认的选中项*/ - defaultValue?: Array, - /** 指定选中项*/ - value?: Array, - /** 选择完成后的回调*/ - onChange?: Function, - /** 选择后展示的渲染函数*/ - displayRender?: Function, - /** 自定义样式*/ - style?: Object, - /** 自定义类名*/ - className?: string, - /** 自定义浮层类名*/ - popupClassName?: string, - /** 浮层预设位置:`bottomLeft` `bottomRight` `topLeft` `topRight` */ - popupPlacement?: string, - /** 输入框占位文本*/ - placeholder?: string, - /** 输入框大小,可选 `large` `default` `small` */ - size?: string, - /** 禁用*/ - disabled?: boolean, - /** 是否支持清除*/ - allowClear?: boolean - - } - /** - * #Cascader - 级联选择框。 - - - ## 何时使用 - - - 需要从一组相关联的数据集合进行选择,例如省市区,公司层级,事物分类等。 - - 从一个较大的数据集合中进行选择时,用多级分类进行分隔,方便选择。 - - 比起 Select 组件,可以在同一个浮层中完成选择,有较好的体验。*/ - export class Cascader extends React.Component { - render(): JSX.Element - } - - - - - // Checkbox - interface CheckboxProps { - /** 指定当前是否选中*/ - checked?: boolean, - /** 初始是否选中*/ - defaultChecked?: boolean, - /** 变化时回调函数*/ - onChange?: Function - } - - interface CheckboxGroupProps { - /** 默认选中的选项*/ - defaultValue?: Array, - /** 指定选中的选项*/ - value?: Array, - /** 指定可选项*/ - options?: Array, - /** 变化时回调函数*/ - onChange?: Function - } - /** Checkbox 组*/ - class CheckboxGroup extends React.Component { - render(): JSX.Element - } - /** - * #Checkbox - 多选框。 - - ## 何时使用 - - - 在一组可选项中进行多项选择时; - - 单独使用可以表示两种状态之间的切换,和 `switch` 类似。区别在于切换 `switch` 会直接触发状态改变,而 `checkbox` 一般用于状态标记,需要和提交操作配合。 - */ - export class Checkbox extends React.Component { - static Group: typeof CheckboxGroup - render(): JSX.Element - } - - - - // Collapse - - interface CollapseProps { - /** 当前激活 tab 面板的 key*/ - activeKey?: Array | string, - /** 初始化选中面板的key */ - defaultActiveKey?: Array, - /** 切换面板的回调*/ - onChange?: Function - - } - class CollapsePanel extends React.Component<{ - /** 对应 activeKey */ - key: string, - /** 面板头内容*/ - header: React.ReactNode | string - }, {}> { - render(): JSX.Element - } - /** - * #Collapse - 可以折叠/展开的内容区域。 - - ## 何时使用 - - - 对复杂区域进行分组和隐藏,保持页面的整洁。 - - `手风琴` 是一种特殊的折叠面板,只允许单个内容区域展开。*/ - export class Collapse extends React.Component { - static Panel: typeof CollapsePanel - render(): JSX.Element - } - - - - // DatePicker - interface DatePickerProps { - - value?: string | Date, - defaultValue?: string | Date, - /** 展示的日期格式,配置参考 [GregorianCalendarFormat](https://github.com/yiminghe/gregorian-calendar-format)*/ - format?: string, - /** 不可选择的日期*/ - disabledDate?: Function, - /** 时间发生变化的回调,发生在用户选择时间时*/ - onChange?: Function, - /** 禁用*/ - disabled?: boolean, - style?: Object, - /** 格外的弹出日历样式*/ - popupStyle?: Object, - /** 输入框大小,`large` 高度为 32px,`small` 为 22px,默认是 28px*/ - size?: string, - /** 国际化配置*/ - locale?: Object, - /** 增加时间选择功能*/ - showTime?: boolean, - /** 点击确定按钮的回调*/ - onOk?: Function, - /** 定义浮层的容器,默认为 body 上新建 div*/ - getCalendarContainer?: Function - - } - interface RangePickProps extends DatePickerProps { - - } - class RangePicker extends React.Component { - render(): JSX.Element - } - class MonthPicker extends React.Component { - render(): JSX.Element - } - /** - * #DatePicker - 输入或选择日期的控件。 - - ## 何时使用 - - 当用户需要输入一个日期,可以点击标准输入框,弹出日期面板进行选择。*/ - export class DatePicker extends React.Component, {}> { - static RangePicker: typeof RangePicker - static MonthPicker: typeof MonthPicker - render(): JSX.Element - } - - - - - // Dropdown - - interface DropdownProps { - /** 触发下拉的行为 ['click'] or ['hover']*/ - trigger?: Array, - /** 菜单节点*/ - overlay: React.ReactNode - - } - - class DropdownButton extends React.Component<{ - /** 按钮类型*/ - type?: string, - /** 点击左侧按钮的回调*/ - onClick?: Function, - /** 触发下拉的行为*/ - trigger?: string, - /** 菜单节点*/ - overlay: React.ReactNode - }, {}> { - render(): JSX.Element - } - /** - * #Dropdown - 向下弹出的列表。 - - ## 何时使用 - - 当页面上的操作命令过多时,用此组件可以收纳操作元素。点击或移入触点,会出现一个下拉菜单。可在列表中进行选择,并执行相应的命令。 - */ - export class Dropdown extends React.Component { - static Button: typeof DropdownButton - render(): JSX.Element - } - - - - // Form - - interface FormItemProps { - prefixCls?: string, - /** label 标签的文本*/ - label?: React.ReactNode, - /** label 标签布局,通 `` 组件,设置 `span` `offset` 值,如 `{span: 3, offset: 12}`*/ - labelCol?: Object, - /** 提示信息,如不设置,则会根据校验规则自动生成 */ - help?: React.ReactNode | boolean, - /** 额外的提示信息,和 help 类似,当需要错误信息和提示文案同时出现时,可以使用这个。*/ - extra?: string, - /** 是否必填,如不设置,则会根据校验规则自动生成 */ - validateStatus?: string, - /** 配合 validateStatus 属性使用,是否展示校验状态图标 */ - hasFeedback?: boolean, - /** 需要为输入控件设置布局样式时,使用该属性,用法同 labelCol*/ - wrapperCol?: Object, - className?: string, - required?: boolean, - id?: string - } - /** - 表单一定会包含表单域,表单域可以是输入控件,标准表单域,标签,下拉菜单,文本域等。 - - 这里我们分别封装了表单域 `` 和输入控件 ``。*/ - export class FormItem extends React.Component { - render(): JSX.Element - } - interface FormComponentProps { - form: CreateFormOptions - } - export class FormComponent extends React.Component { - render(): JSX.Element - } - - // function create - type CreateFormOptions = { - /** 获取一组输入控件的值,如不传入参数,则获取全部组件的值*/ - getFieldsValue(): (fieldNames?: Array) => any - /** 获取一个输入控件的值*/ - getFieldValue(): (fieldName: string) => any - /** 设置一组输入控件的值*/ - setFieldsValue(): (obj: Object) => void - /** 设置一组输入控件的值*/ - setFields(): (obj: Object) => void - /** 校验并获取一组输入域的值与 Error*/ - validateFields(): (fieldNames?: Array, options?: Object, callback?: (erros: any, values: any) => void) => any - /** 与 `validateFields` 相似,但校验完后,如果校验不通过的菜单域不在可见范围内,则自动滚动进可见范围 */ - validateFieldsAndScroll(): (fieldNames?: Array, options?: Object, callback?: (erros: any, values: any) => void) => any - /** 获取某个输入控件的 Error */ - getFieldError(): (name: string) => Object - /** 判断一个输入控件是否在校验状态*/ - isFieldValidating(): (name: string) => Object - /**重置一组输入控件的值与状态,如不传入参数,则重置所有组件*/ - resetFields(): (names?: Array) => void - - getFieldsValue(): (id: string, options: { - /** 子节点的值的属性,如 Checkbox 的是 'checked'*/ - valuePropName?: string, - /** 子节点的初始值,类型、可选值均由子节点决定*/ - initialValue?: any, - /** 收集子节点的值的时机*/ - trigger?: string, - /** 校验子节点值的时机*/ - validateTrigger?: string, - /** 校验规则,参见 [async-validator](https://github.com/yiminghe/async-validator) */ - rules?: Array, - /** 必填输入控件唯一标志*/ - id?: string - }) => Array - - - } - - interface ComponentDecorator { - (component: T): T; - } - interface FormProps { - prefixCls?: string, - /** 水平排列布局*/ - horizontal?: boolean, - /** 行内排列布局*/ - inline?: boolean, - /** 经 `Form.create()` 包装过的组件会自带 `this.props.form` 属性,直接传给 Form 即可*/ - form?: Object, - /** 数据验证成功后回调事件*/ - onSubmit?: (e: React.FormEvent
) => void, - } - /** - * #Form - 具有数据收集、校验和提交功能的表单,包含复选框、单选框、输入框、下拉选择框等元素。 - - ## 表单 - - 我们为 `form` 提供了以下两种排列方式: - - - 水平排列:可以实现 `label` 标签和表单控件的水平排列; - - 行内排列:使其表现为 `inline-block` 级别的控件。 - */ - export class Form extends React.Component { - static Item: typeof FormItem - static create(options?: { - /** - * 当 `Form.Item` 子节点的值发生改变时触发,可以把对应的值转存到 Redux store - */ - onFieldsChange?: (props: Object, fields: Array) => void, - /** 把 props 转为对应的值,可用于把 Redux store 中的值读出 */ - mapPropsToFields?: (props: Object) => void - }): ComponentDecorator - render(): JSX.Element - } - - - - - - // Icon - interface IconProps { - /** 图标类型*/ - type: string - } - /** - * #Icon - 有含义的矢量图形,每一个图标打倒一个敌人。 - - ## 图标的命名规范 - - 我们为每个图标赋予了语义化的命名,命名规则如下: - - - 实心和描线图标保持同名,用 `-o` 来区分,比如 `question-circle`(实心) 和 `question-circle-o`(描线); - - - 命名顺序:`[icon名]-[形状可选]-[描线与否]-[方向可选]`。 - - ## 如何使用 - - 使用 `` 标签声明组件,指定图标对应的 type 属性,示例代码如下: - - ```html - - ``` - - 最终会渲染为: - - ```html - - ```*/ - export class Icon extends React.Component { - render(): JSX.Element - } - - - - - // Input - interface InputProps { - /** 【必须】声明 input 类型,同原生 input 标签的 type 属性*/ - type?: string, - id: string | number, - /** 控件大小,默认值为 default 。注:标准表单内的输入框大小限制为 large。 {'large','default','small'}*/ - size?: string, - /** 是否禁用状态,默认为 false*/ - disabled?: boolean, - value?: any, - /** 设置初始默认值*/ - defaultValue?: any, - className?: string, - /** 带标签的 input,设置前置标签*/ - addonBefore?: React.ReactNode, - /** 带标签的 input,设置后置标签*/ - addonAfter?: React.ReactNode, - prefixCls?: string, - placeholder?: string - } - export class Input extends React.Component { - render(): JSX.Element - } - - - - - // InputNumber - interface InputNumberProps { - /** 最小值*/ - min: number, - /** 最大值*/ - max: number, - /** 当前值*/ - value?: number, - /** 每次改变步数*/ - step?: number, - /** 初始值*/ - defaultValue?: number, - /** 变化回调*/ - onChange?: Function, - /** 禁用*/ - disabled?: boolean, - /** 输入框大小*/ - size?: string - - } - /** - * #InputNumber - 通过鼠标或键盘,输入范围内的数值。 - - ## 何时使用 - - 当需要获取标准数值时。*/ - export class InputNumber extends React.Component { - render(): JSX.Element - } - - - // Layout - // Row - interface RowProps { - type?: string, - align?: string, - justify?: string, - className?: string - } - export class Row extends React.Component { - render(): JSX.Element - } - - // Col - interface ColProps { - span?: string, - order?: string, - offset?: string, - push?: string, - pull?: string, - className?: string - } - /** - 在多数业务情况下,Ant Design需要在设计区域内解决大量信息收纳的问题,因此在12栅格系统的基础上,我们将整个设计建议区域按照24等分的原则进行划分。 - - 划分之后的信息区块我们称之为“盒子”。建议横向排列的盒子数量最多四个,最少一个。“盒子”在整个屏幕上占比见上图。设计部分基于盒子的单位定制盒子内部的排版规则,以保证视觉层面的舒适感。 - - ## 概述 - - 布局的栅格化系统,我们是基于行(row)和列(col)来定义信息区块的外部框架,以保证页面的每个区域能够稳健地排布起来。下面简单介绍一下它的工作原理: - - * 通过`row`在水平方向建立一组`column`(简写col) - * 你的内容应当放置于`col`内,并且,只有`col`可以作为`row`的直接元素 - * 栅格系统中的列是指1到24的值来表示其跨越的范围。例如,三个等宽的列可以使用`.col-8`来创建 - * 如果一个`row`中的`col`总和超过24,那么多余的`col`会作为一个整体另起一行排列 - - ## Flex 布局 - - 我们的栅格化系统支持 Flex 布局,允许子元素在父节点内的水平对齐方式 - 居左、居中、居右、等宽排列、分散排列。子元素与子元素之间,支持顶部对齐、垂直居中对齐、底部对齐的方式。同时,支持使用 order 来定义元素的排列顺序。 - - Flex 布局是基于 24 栅格来定义每一个“盒子”的宽度,但排版则不拘泥于栅格。*/ - export class Col extends React.Component { - render(): JSX.Element - } - - - - - // Menu - interface MenuItemProps { - /** - * (是否禁用) - * - * @type {boolean} - */ - disabled?: boolean, - key: string - } - export class MenuItem extends React.Component { - render(): JSX.Element - } - - interface MenuSubMenuProps { - /** - * (子菜单项值) - * - * @type {(string | React.ReactNode)} - */ - title: string | React.ReactNode, - /** - * (子菜单的菜单项) - * - * @type {(MenuItem | MenuSubMenu)} - */ - children?: JSX.Element[] - } - export class MenuSubMenu extends React.Component { - render(): JSX.Element - } - - interface MenuItemGroupProps { - /** - * (分组标题) - * - * @type {(string | React.ReactNode)} - */ - title: string | React.ReactNode, - /** - * (分组的菜单项) - * - * @type {MenuItem} - */ - children?: JSX.Element[] - } - export class MenuItemGroup extends React.Component { - render(): JSX.Element - } - - - // enum - enum MenuTheme { - light, - dark - } - enum MenuMode { - vertical, - horizontal, - inline - } - interface MenuProps { - /** 主题颜色*/ - theme?: MenuTheme | string, - /** 菜单类型 enum: `vertical` `horizontal` `inline`*/ - mode?: MenuMode | string, - /** 当前选中的菜单项 key 数组*/ - selectedKeys?: Array, - /** 初始选中的菜单项 key 数组*/ - defaultSelectedKeys?: Array, - /** 当前展开的菜单项 key 数组*/ - openKeys?: Array, - /** 初始展开的菜单项 key 数组*/ - defaultOpenKeys?: Array, - /** - * 被选中时调用 - * - * @type {(item: any, key: string, selectedKeys: Array) => void} - */ - onSelect?: (item: any, key: string, selectedKeys: Array) => void, - /** 取消选中时调用*/ - onDeselect?: (item: any, key: string, selectedKeys: Array) => void, - /** 点击 menuitem 调用此函数*/ - onClick?: (item: any, key: string) => void, - /** 根节点样式*/ - style?: Object - } - /** - # Menu - 为页面和功能提供导航的菜单列表。 - - ## 何时使用 - - 导航菜单是一个网站的灵魂,用户依赖导航在各个页面中进行跳转。一般分为顶部导航和侧边导航,顶部导航提供全局性的类目和功能,侧边导航提供多级结构来收纳和排列网站架构。 - - 更多布局和导航的范例可以参考:[常用布局](/spec/layout)。*/ - export class Menu extends React.Component { - static Item: typeof MenuItem - static SubMenu: typeof MenuSubMenu - static ItemGroup: typeof MenuItemGroup - static Divider: typeof React.Component - render(): JSX.Element - } - - - - // Message - type MessageFunc = ( - /** 提示内容*/ - content: string, - /** 自动关闭的延时*/ - duration?: number - ) => void - /** - * #Message - 全局展示操作反馈信息。 - - ## 何时使用 - - - 可提供成功、警告和错误等反馈信息。 - - 顶部居中显示并自动消失,是一种不打断用户操作的轻量级提示方式。*/ - export const message: { - - success: MessageFunc - error: MessageFunc - info: MessageFunc - loading: MessageFunc - config: (options: { - /** - * 消息距离顶部的位置 - * - * @type {number} - */ - top: number - }) => void - destroy: () => void - } - - // Modal - type ModalFunc = (options: { - visible?: boolean, - title?: React.ReactNode | string, - onOk?: Function, - onCancel?: Function, - width?: string | number, - iconClassName?: string, - okText?: string, - cancelText?: string - }) => void - - interface ModalProps { - /** 对话框是否可见*/ - visible?: boolean, - /** 确定按钮 loading*/ - confirmLoading?: boolean, - /** 标题*/ - title?: React.ReactNode | string, - /** 是否显示右上角的关闭按钮*/ - closable?: boolean, - /** 点击确定回调*/ - onOk?: Function, - /** 点击遮罩层或右上角叉或取消按钮的回调*/ - onCancel?: Function, - /** 宽度*/ - width?: string | number, - /** 底部内容*/ - footer?: React.ReactNode | string, - /** 确认按钮文字*/ - okText?: string, - /** 取消按钮文字*/ - cancelText?: string, - /** 点击蒙层是否允许关闭*/ - maskClosable?: boolean - } - - /** - # Modal - 模态对话框。 - - ## 何时使用 - - 需要用户处理事务,又不希望跳转页面以致打断工作流程时,可以使用 `Modal` 在当前页面正中打开一个浮层,承载相应的操作。 - - 另外当需要一个简洁的确认框询问用户时,可以使用精心封装好的 `ant.Modal.confirm()` 等方法。*/ - export class Modal extends React.Component { - static info: ModalFunc - static success: ModalFunc - static error: ModalFunc - static confirm: ModalFunc - render(): JSX.Element - } - - - - - // Notification - type NotificationFunc = ( - config: { - /** 通知提醒标题,必选 */ - message: React.ReactNode | string, - /** 通知提醒内容,必选*/ - description: React.ReactNode | string, - /** 自定义关闭按钮*/ - btn?: React.ReactNode | string, - /** 当前通知唯一标志*/ - key?: string, - /** 点击默认关闭按钮时触发的回调函数*/ - onClose?: Function, - /** 默认 4.5 秒后自动关闭,配置为 null 则不自动关闭*/ - duration?: number - }) => void - /** - * #notification - 全局展示通知提醒信息。 - - ## 何时使用 - - 在系统右上角显示通知提醒信息。经常用于以下情况: - - - 较为复杂的通知内容。 - - 带有交互的通知,给出用户下一步的行动点。 - - 系统主动推送。*/ - export const notification: { - success: NotificationFunc - error: NotificationFunc - info: NotificationFunc - warn: NotificationFunc - close: (key: string) => void - destroy: () => void - config: (options: { - /** 消息距离顶部的位置*/ - top: number - }) => void - - } - - - - - // Pagination - interface PaginationProps { - /** 当前页数*/ - current?: number, - /** 默认的当前页数*/ - defaultCurrent?: number, - /** 数据总数*/ - total: number, - /** 初始的每页条数*/ - defaultPageSize?: number, - /** 每页条数*/ - pageSize?: number, - /** 页码改变的回调,参数是改变后的页码*/ - onChange?: Function, - /** 是否可以改变 pageSize */ - showSizeChanger?: boolean, - /** 指定每页可以显示多少条*/ - pageSizeOptions?: Array - /** pageSize 变化的回调 */ - onShowSizeChange?: Function, - /** 是否可以快速跳转至某页*/ - showQuickJumper?: boolean, - /** 当为「small」时,是小尺寸分页 */ - size?: string, - /** 当添加该属性时,显示为简单分页*/ - simple?: Object, - /** 用于显示总共有多少条数据*/ - showTotal?: Function - } - /** - * #Pagination - 采用分页的形式分隔长列表,每次只加载一个页面。 - - ## 何时使用 - - - 当加载/渲染所有数据将花费很多时间时; - - 可切换页码浏览数据。*/ - export class Pagination extends React.Component { - render(): JSX.Element - } - - - - - // Popconfirm - enum Placement { - top, left, right, bottom - } - interface PopconfirmProps { - /** - * 气泡框位置,可选 `top/left/right/bottom` - * - * @type {(Placement | string)} - */ - placement?: Placement | string, - /** 确认框的描述*/ - title?: string, - /** 点击确认的回调*/ - onConfirm?: Function, - onCancel?: Function, - /** 显示隐藏的回调*/ - onVisibleChange?: (visible: boolean) => void, - /** 确认按钮文字*/ - okText?: string, - /** 取消按钮文字*/ - cancelText?: string - } - /** - * #Popconfirm - 点击元素,弹出气泡式的确认框。 - - ## 何时使用 - - 目标元素的操作需要用户进一步的确认时,在目标元素附近弹出浮层提示,询问用户。 - - 和 `confirm` 弹出的全屏居中模态对话框相比,交互形式更轻量。 - */ - export class Popconfirm extends React.Component { - render(): JSX.Element - } - - - - - // Popover - enum Trigger { - hover, focus, click - } - enum PopoverPlacement { - top, - left, right, bottom, - topLeft, topRight, bottomLeft, bottomRight, - leftTop, leftBottom, rightTop, rightBottom - } - interface PopoverProps { - /** 触发行为,可选 `hover/focus/click` */ - trigger?: Trigger | string, - /** 气泡框位置,可选 `top/left/right/bottom` `topLeft/topRight/bottomLeft/bottomRight` `leftTop/leftBottom/rightTop/rightBottom`*/ - placement?: PopoverPlacement | string, - /** 卡片标题*/ - title?: React.ReactNode | string, - /** 卡片内容*/ - overlay?: React.ReactNode | string, - prefixCls?: string, - /** 用于手动控制浮层显隐*/ - visible?: boolean, - /** 显示隐藏改变的回调*/ - onVisibleChange?: Function - } - /** - * #Popover - 点击/鼠标移入元素,弹出气泡式的卡片浮层。 - - ## 何时使用 - - 当目标元素有进一步的描述和相关操作时,可以收纳到卡片中,根据用户的操作行为进行展现。 - - 和 `Tooltip` 的区别是,用户可以对浮层上的元素进行操作,因此它可以承载更复杂的内容,比如链接或按钮等。 - */ - export class Popover extends React.Component { - render(): JSX.Element - } - - - - - // Progress - enum ProgressStatus { - normal, - exception, - active - } - - interface LineProps { - /** 百分比*/ - percent: number, - /** 内容的模板函数*/ - format?: (percent: any) => void, - /** 状态,可选:normal、exception、active*/ - status?: ProgressStatus | string, - /** 进度条线的宽度,单位是px*/ - strokeWidth?: number, - /** 是否显示进度数值和状态图标*/ - showInfo?: boolean - } - export class Line extends React.Component { - render(): JSX.Element - } - - interface CircleProps { - /** 百分比*/ - percent: number, - /** 内容的模板函数*/ - format?: (percent: any) => void, - /** 状态,可选:normal、exception*/ - status?: ProgressStatus | string, - /** 进度条线的宽度,单位是进度条画布宽度的百分比*/ - strokeWidth?: number, - /** 必填,进度条画布宽度,单位px。这里没有提供height属性设置,Line型高度就是strokeWidth,Circle型高度等于width*/ - width?: number - } - export class Circle extends React.Component { - render(): JSX.Element - } - /** - * #Progress - 展示操作的当前进度。 - - ## 何时使用 - - 在操作需要较长时间才能完成时,为用户显示该操作的当前进度和状态。 - - * 当一个操作会打断当前界面,或者需要在后台运行,且耗时可能超过2秒时; - * 当需要显示一个操作完成的百分比时。*/ - export const Progress: { - Line: typeof Line, - Circle: typeof Circle - } - - - // QueueAnim - interface QueueAnimProps { - /** 动画内置参数 `left` `right` `top` `bottom` `scale` `scaleBig` `scaleX` `scaleY`*/ - type?: string | Array, - /** 配置动画参数 如 `{opacity:[1, 0],translateY:[0, -30]}` 具体参考 [velocity](http://julian.com/research/velocity) 的写法*/ - animConfig?: Object | Array, - /** 整个动画的延时,以毫秒为单位*/ - delay?: number | Array, - /** 每个动画的时间,以毫秒为单位*/ - duration?: number | Array, - /** 每个动画的间隔时间,以毫秒为单位*/ - interval?: number | Array, - /** 出场时是否倒放,从最后一个 dom 开始往上播放 */ - leaveReverse?: boolean, - /** 动画的缓动函数,[查看详细](http://julian.com/research/velocity/#easing)*/ - ease?: string | Array, - /** 进出场动画进行中的类名*/ - animatingClassName?: Array, - /** QueueAnim 替换的标签名*/ - component?: string - } - /** - * #QueueAnim - 通过简单的配置对一组元素添加串行的进场动画效果。 - - ## 何时使用 - - - 从内容A到内容B的转变过程时能有效的吸引用户注意力,突出视觉中心,提高整体视觉效果。 - - - 小的信息元素排布或块状较多的情况下,根据一定的路径层次依次进场,区分维度层级,来凸显量级,使页面转场更加流畅和舒适,提高整体视觉效果和产品的质感。 - - - 特别适合首页和需要视觉展示效果的宣传页,以及单页应用的切换页面动效。 - */ - export class QueueAnim extends React.Component { - render(): JSX.Element - } - - - - - // Radio - enum RadioGroupSize { - large, - default, - small - } - interface RadioGroupProps { - /** 选项变化时的回调函数*/ - onChange?: (e: Event) => void, - /** 用于设置当前选中的值*/ - value?: string, - /** 默认选中的值*/ - defaultValue?: string, - /** 大小,只对按钮样式生效*/ - size?: RadioGroupSize | string - } - export class RadioGroup extends React.Component { - render(): JSX.Element - } - - - interface RadioProps { - /** 指定当前是否选中*/ - checked?: boolean, - /** 初始是否选中*/ - defaultChecked?: boolean, - /** 根据 value 进行比较,判断是否选中 */ - value?: any - } - /** - * #Radio - 单选框。 - - ## 何时使用 - - - 用于在多个备选项中选中单个状态。 - - 和 Select 的区别是,Radio 所有选项默认可见,方便用户在比较中选择,因此选项不宜过多。 - */ - export class Radio extends React.Component { - static Group: typeof RadioGroup - static Button: typeof Button - render(): JSX.Element - } - - - - // Select - interface SelectOptionProps { - /** 是否禁用*/ - disabled?: boolean, - /** 如果 react 需要你设置此项,此项值与 value 的值相同,然后可以省略 value 设置*/ - key?: string, - /** 默认根据此属性值进行筛选*/ - value: string - } - export class SelectOption extends React.Component { - render(): JSX.Element - } - - interface SelectOptGroupProps { - /** 组名*/ - label: string | React.ReactNode, - key?: string - } - export class SelectOptGroup extends React.Component { - render(): JSX.Element - } - - interface SelectProps { - /** 指定当前选中的条目*/ - value?: string | Array, - /** 指定默认选中的条目*/ - defaultValue?: string | Array, - /** 支持多选*/ - multiple?: boolean, - /** 支持清除, 单选模式有效*/ - allowClear?: boolean, - /** 是否根据输入项进行筛选,可为一个函数,返回满足要求的 option 即可*/ - filterOption?: boolean | Function, - /** 可以把随意输入的条目作为 tag,输入项不需要与下拉选项匹配*/ - tags?: boolean, - /** 被选中时调用,参数为选中项的 value 值 */ - onSelect?: (value: any, option: any) => void, - /** 取消选中时调用,参数为选中项的 option value 值,仅在 multiple 或 tags 模式下生效*/ - onDeselect?: (value: any, option: any) => void, - /** 选中option,或input的value变化(combobox 模式下)时,调用此函数*/ - onChange?: (value: any, label: any) => void, - /** 文本框值变化时回调*/ - onSearch?: (value: string) => void, - /** 选择框默认文字*/ - placeholder?: string, - /** 搜索框默认文字*/ - searchPlaceholder?: string, - /** 当下拉列表为空时显示的内容*/ - notFoundContent?: string, - /** 下拉菜单和选择器同宽*/ - dropdownMatchSelectWidth?: boolean, - /** 搜索时过滤对应的 option 属性,如设置为 children 表示对内嵌内容进行搜索*/ - optionFilterProp?: string, - /** 输入框自动提示模式*/ - combobox?: SVGSymbolElement, - /** 选择框大小,可选 `large` `small` */ - size?: string, - /** 在下拉中显示搜索框*/ - showSearch?: boolean, - /** 是否禁用*/ - disabled?: boolean, - style?: Object - } - /** - * #Select - 类似 Select2 的选择器。 - - ## 何时使用 - - 弹出一个下拉菜单给用户选择操作,用于代替原生的选择器,或者需要一个更优雅的多选器时。*/ - export class Select extends React.Component { - static Option: typeof SelectOption - static OptGroup: typeof SelectOptGroup - render(): JSX.Element - } - - - - // Slider - interface SliderProps { - /** 最小值*/ - min?: number, - /** 最大值*/ - max?: number, - /** 步长,取值必须大于 0,并且可被 (max - min) 整除。当 `marks` 不为空对象时,可以设置 `step` 为 `null`,此时 Slider 的可选值仅有 marks 标出来的部分。*/ - step?: number, - /** 分段标记,key 的类型必须为 `Number` 且取值在闭区间 [min, max] 内*/ - marks?: { key: number, value: any }, - /** 设置当前取值。当 `range` 为 `false` 时,使用 `Number`,否则用 `[Number, Number]`*/ - value?: number | Array, - /** 设置当前取值。当 `range` 为 `false` 时,使用 `Number`,否则用 `[Number, Number]`*/ - defaultValue?: number | Array, - /** `marks` 不为空对象时有效,值为 true 时表示值为包含关系,false 表示并列*/ - included?: boolean, - /** 值为 `true` 时,滑块为禁用状态*/ - disabled?: boolean, - /** 当 `range` 为 `true` 时,该属性可以设置是否允许两个滑块交换位置。*/ - allowCross?: boolean, - /** 当 Slider 的值发生改变时,会触发 onChange 事件,并把改变后的值作为参数传入。*/ - onChange?: Function, - /** 与 `onmouseup` 触发时机一致,把当前值作为参数传入。*/ - onAfterChange?: Function, - /** Slider 会把当前值传给 `tipFormatter`,并在 Tooltip 中显示 `tipFormatter` 的返回值,若为 null,则隐藏 Tooltip。*/ - tipFormatter?: Function | any, - range?: boolean - } - /** - * #Slider - 滑动型输入器,展示当前值和可选范围。 - - ## 何时使用 - - 当用户需要在数值区间/自定义区间内进行选择时,可为连续或离散值。*/ - export class Slider extends React.Component { - render(): JSX.Element - } - - - - - // Spin - interface SpinProps { - /** spin组件中点的大小,可选值为 small default large*/ - size?: string, - /** 用于内嵌其他组件的模式,可以关闭 loading 效果*/ - spining?: boolean - } - /** - * #Spin - 用于页面和区块的加载中状态。 - - ## 何时使用 - - 页面局部处于等待异步数据或正在渲染过程时,合适的加载动效会有效缓解用户的焦虑。 - */ - export class Spin extends React.Component { - render(): JSX.Element - } - - - - - // Steps - enum StepStatus { - wait, process, finish - } - interface StepProps { - /** 可选参数,指定状态。当不配置该属性时,会使用父Steps元素的current来自动指定状态。*/ - status?: StepStatus | string, - /** 必要参数,标题。*/ - title: string | React.ReactNode, - /** 可选参数,步骤的详情描述。*/ - description?: string | React.ReactNode, - /** 可选参数,步骤的Icon。如果不指定,则使用默认的样式。*/ - icon?: string | React.ReactNode - } - export class Step extends React.Component { - render(): JSX.Element - } - - interface StepsProps { - /** 可选参数,指定当前处理正在执行状态的步骤,从0开始记数。在子Step元素中,可以通过status属性覆盖状态。*/ - current?: number, - /** 可选参数,指定大小(目前只支持普通和迷你两种大小)。 small, default */ - size?: string, - /** 可选参数,指定步骤条方向(目前支持水平和竖直两种方向,默认水平方向)。*/ - direction?: string, - /** 可选参数,指定步骤的详细描述文字的最大宽度。*/ - maxDescriptionWidth?: number - - } - /** - * #Steps - 引导用户按照流程完成任务的导航条。 - - ## 何时使用 - - 当任务复杂或者存在先后关系时,将其分解成一系列步骤,从而简化任务。*/ - export class Steps extends React.Component { - static Step: typeof Step - render(): JSX.Element - } - - - - // Switch - interface SwitchProps { - /** 指定当前是否选中*/ - checked?: boolean, - /** 初始是否选中*/ - defaultChecked?: boolean, - /** 变化时回调函数*/ - onChange?: (checked: boolean) => void, - /** 选中时的内容*/ - checkedChildren?: React.ReactNode, - /** 非选中时的内容*/ - unCheckedChildren?: React.ReactNode, - /** 开关大小*/ - size?: string - } - /** - * #Switch - 开关选择器。 - - ## 何时使用 - - - 需要表示开关状态/两种状态之间的切换时; - - 和 `checkbox `的区别是,切换 `switch` 会直接触发状态改变,而 `checkbox` 一般用于状态标记,需要和提交操作配合。 - */ - export class Switch extends React.Component { - render(): JSX.Element - } - - - - - // Table - enum RowSelectionType { - checkbox, - radio - } - type SelectedRowKeys = Array - interface RowSelection { - type?: RowSelectionType | string, - selectedRowKeys?: SelectedRowKeys, - onChange?: (selectedRowKeys: SelectedRowKeys, selectedRows: any) => void, - getCheckboxProps?: (record: any) => void, - onSelect?: (record: any, selected: any, selectedRows: any) => void, - onSelectAll?: (rselectedecord: any, selectedRows: any, changeRows: any) => void - } - interface Columns { - /** React 需要的 key,建议设置*/ - key?: string, - /** 列头显示文字*/ - title?: string | React.ReactNode, - /** 列数据在数据项中对应的 key*/ - dataIndex?: string, - /** 生成复杂数据的渲染函数,参数分别为当前列的值,当前列数据,列索引,@return里面可以设置表格[行/列合并](#demo-colspan-rowspan)*/ - render?: (text?: any, record?: any, index?: number) => React.ReactNode, - /** 表头的筛选菜单项*/ - filters?: Array, - /** 本地模式下,确定筛选的运行函数*/ - onFilter?: Function, - /** 是否多选*/ - filterMultiple?: boolean, - /** 排序函数,本地排序使用一个函数,需要服务端排序可设为 true */ - sorter?: boolean | Function, - /** 表头列合并,设置为 0 时,不渲染*/ - colSpan?: number, - /** 列宽度*/ - width?: string | number, - /** 列的 className*/ - className?: string - } - interface TableProps { - /** 列表项是否可选择*/ - rowSelection?: RowSelection, - /** 分页器*/ - pagination?: Object, - /** 正常或迷你类型 : `default` or `small` */ - size?: string, - /** 数据数组*/ - dataSource: Array, - /** 表格列的配置描述*/ - columns: Columns, - /** 表格行 key 的取值*/ - rowKey?: (record: any, index: number) => string, - /** 额外的展开行*/ - expandedRowRender?: Function, - /** 默认展开的行*/ - defaultExpandedRowKeys?: Array, - /** 分页、排序、筛选变化时触发*/ - onChange?: (pagination: Object, filters: any, sorter: any) => void, - /** 页面是否加载中*/ - loading?: boolean, - /** 默认文案设置,目前包括排序、过滤、空数据文案: `{ filterConfirm: '确定', filterReset: '重置', emptyText: '暂无数据' }` */ - locale?: Object, - /** 展示树形数据时,每层缩进的宽度,以 px 为单位*/ - indentSize?: number, - /** 处理行点击事件*/ - onRowClick?: (record: any, index: number) => void, - /** 是否固定表头*/ - useFixedHeader?: boolean, - /** 是否展示外边框和列边框*/ - bordered?: boolean, - /** 是否显示表头*/ - showHeader?: boolean, - /** 表格底部自定义渲染函数*/ - footer?: (currentPageData: Object) => void - - } - /** - * #Table - 展示行列数据。 - - ## 何时使用 - - - 当有大量结构化的数据需要展现时; - - 当需要对数据进行排序、搜索、分页、自定义操作等复杂行为时。*/ - export class Table extends React.Component { - render(): JSX.Element - } - - - - // Tabs - interface TabPaneProps { - /** 选项卡头显示文字*/ - tab: React.ReactNode | string - } - export class TabPane extends React.Component { - render(): JSX.Element - } - - enum TabsType { - line, card, 'editable-card' - } - enum TabsPosition { - top, - right, - bottom, - left - } - interface TabsProps { - /** 当前激活 tab 面板的 key */ - activeKey?: string, - /** 初始化选中面板的 key,如果没有设置 activeKey*/ - defaultActiveKey?: string, - /** 切换面板的回调*/ - onChange?: Function, - /** tab 被点击的回调 */ - onTabClick?: Function, - /** tab bar 上额外的元素 */ - tabBarExtraContent?: React.ReactNode, - /** 页签的基本样式,可选 `line`、`card` `editable-card` 类型*/ - type?: TabsType | string, - /** 页签位置,可选值有 `top` `right` `bottom` `left`*/ - tabPosition?: TabsPosition | string, - /** 新增和删除页签的回调,在 `type="editable-card"` 时有效*/ - onEdit?: (targetKey: string, action: any) => void - } - /** - * #Tabs - 选项卡切换组件。 - - ## 何时使用 - - 提供平级的区域将大块内容进行收纳和展现,保持界面整洁。 - - Ant Design 依次提供了三级选项卡,分别用于不同的场景。 - - - 卡片式的页签,提供可关闭的样式,常用于容器顶部。 - - 标准线条式页签,用于容器内部的主功能切换,这是最常用的 Tabs。 - - [RadioButton](/components/radio/#demo-radiobutton) 可作为更次级的页签来使用。*/ - export class Tabs extends React.Component { - static TabPane: typeof TabPane - render(): JSX.Element - } - - - - - // Tag - interface TagProps { - /** 标签是否可以关闭*/ - closable?: boolean, - /** 关闭时的回调*/ - onClose?: Function, - /** 动画关闭后的回调*/ - afterClose?: Function, - /** 标签的色彩*/ - color?: string - } - /** - * #Tag - 进行标记和分类的小标签。 - - ## 何时使用 - - - 用于标记事物的属性和维度。 - - 进行分类。*/ - export class Tag extends React.Component { - render(): JSX.Element - } - - - - - - - // TimePicker - interface TimePickerProps { - /** 默认时间*/ - value?: string | Date, - /** 初始默认时间*/ - defaultValue?: string | Date, - /** 展示的时间格式 : "HH:mm:ss"、"HH:mm"、"mm:ss" */ - format?: string, - /** 时间发生变化的回调*/ - onChange?: (Date: Date) => void, - /** 禁用全部操作*/ - disabled?: boolean, - /** 没有值的时候显示的内容*/ - placeholder?: string, - /** 国际化配置*/ - locale?: Object, - /** 隐藏禁止选择的选项*/ - hideDisabledOptions?: boolean, - /** 禁止选择部分小时选项*/ - disabledHours?: Function, - /** 禁止选择部分分钟选项*/ - disabledMinutes?: Function, - /** 禁止选择部分秒选项*/ - disabledSeconds?: Function - - } - /** - * #TimePicker - 输入或选择时间的控件。 - - 何时使用 - -------- - - 当用户需要输入一个时间,可以点击标准输入框,弹出时间面板进行选择。 - */ - export class TimePicker extends React.Component { - render(): JSX.Element - } - - - - - // Timeline - interface TimeLineItemProps { - /** 指定圆圈颜色。*/ - color?: string - } - export class TimeLineItem extends React.Component { - render(): JSX.Element - } - - interface TimelineProps { - /** 指定最后一个幽灵节点是否存在或内容*/ - pending?: boolean | React.ReactNode - } - /** - * #Timeline - 垂直展示的时间流信息。 - - ## 何时使用 - - - 当有一系列信息需要从上至下按时间排列时; - - 需要有一条时间轴进行视觉上的串联时;*/ - export class Timeline extends React.Component { - static Item: typeof TimeLineItem - render(): JSX.Element - } - - - - // Tooltip - - interface TooltipProps { - /** 气泡框位置,可选 `top` `left` `right` `bottom` `topLeft` `topRight` `bottomLeft` `bottomRight` `leftTop` `leftBottom` `rightTop` `rightBottom`*/ - placement?: PopoverPlacement | string, - /** 提示文字*/ - title?: string | React.ReactNode - } - /** - * #Tooltip - 简单的文字提示气泡框。 - - ## 何时使用 - - 鼠标移入则显示提示,移出消失,气泡浮层不承载复杂文本和操作。 - - 可用来代替系统默认的 `title` 提示,提供一个`按钮/文字/操作`的文案解释。*/ - export class Tooltip extends React.Component { - render(): JSX.Element - } - - - - - - // Transfer - interface TransferProps { - /** 数据源*/ - dataSource: Array, - /** 每行数据渲染函数*/ - render?: (record: Object) => any, - /** 显示在右侧框数据的key集合*/ - targetKeys: Array, - /** 变化时回调函数*/ - onChange?: (targetKeys: any, direction: string, moveKeys: any) => void, - /** 两个穿梭框的自定义样式*/ - listStyle?: Object, - /** 自定义类*/ - className?: string, - /** 标题集合,顺序从左至右*/ - titles?: Array, - /** 操作文案集合,顺序从上至下*/ - operations?: Array, - /** 是否显示搜索框*/ - showSearch?: boolean, - /** 搜索框的默认值*/ - searchPlaceholder?: string, - /** 当列表为空时显示的内容*/ - notFoundContent?: React.ReactNode | string - /** 底部渲染函数*/ - footer?: (props: any) => any - } - /** - * #Transfer - 双栏穿梭选择框。 - - ## 何时使用 - - 用直观的方式在两栏中移动元素,完成选择行为。 - */ - export class Transfer extends React.Component { - render(): JSX.Element - } - - - - - - // Tree - interface TreeNodeProps { - disabled?: boolean, - disableCheckbox?: boolean, - title?: string | React.ReactNode, - key?: string, - isLeaf?: boolean - } - export class TreeNode extends React.Component { - render(): JSX.Element - } - - interface TreeProps { - showLine?: boolean, - className?: string, - /** 是否支持多选*/ - multiple?: boolean, - /** 是否支持选中*/ - checkable?: boolean, - /** 默认展开所有树节点*/ - defaultExpandAll?: boolean, - /** 默认展开指定的树节点*/ - defaultExpandedKeys?: Array, - /** (受控)展开指定的树节点*/ - expandedKeys?: Array, - /** (受控)选中复选框的树节点*/ - checkedKeys?: Array, - /** 默认选中复选框的树节点*/ - defaultCheckedKeys?: Array, - /** (受控)设置选中的树节点*/ - selectedKeys?: Array, - /** 默认选中的树节点*/ - defaultSelectedKeys?: Array, - /** 展开/收起节点时触发 */ - onExpand?: (node: any, expanded: any, expandedKeys: any) => void, - /** 点击复选框触发*/ - onCheck?: (checkedKeys: any, e: { checked: boolean, checkedNodes: any, node: any, event: Event }) => void, - /** 点击树节点触发*/ - onSelect?: (selectedKeys: any, e: { selected: boolean, selectedNodes: any, node: any, event: Event }) => void, - /** filter some treeNodes as you need. it should return true */ - filterTreeNode?: (node: any) => boolean, - /** 异步加载数据*/ - loadData?: (node: any) => void, - /** 响应右键点击*/ - onRightClick?: (options: { event: Event, node: any }) => void, - /** 设置节点可拖拽(IE>8)*/ - draggable?: boolean, - /** 开始拖拽时调用*/ - onDragStart?: (options: { event: Event, node: any }) => void, - /** dragenter 触发时调用*/ - onDragEnter?: (options: { event: Event, node: any, expandedKeys: any }) => void, - /** dragover 触发时调用 */ - onDragOver?: (options: { event: Event, node: any }) => void, - /** dragleave 触发时调用*/ - onDragLeave?: (options: { event: Event, node: any }) => void, - /** drop 触发时调用*/ - onDrop?: (options: { event: Event, node: any, dragNode: any, dragNodesKeys: any }) => void, - } - /** - * #Tree - * 文件夹、组织架构、生物分类、国家地区等等,世间万物的大多数结构都是树形结构。使用`树控件`可以完整展现其中的层级关系,并具有展开收起选择等交互功能。 - */ - export class Tree extends React.Component { - static TreeNode: typeof TreeNode - render(): JSX.Element - } - - - - - - // TreeSelect - interface TreeSelectTreeNodeProps { - disabled?: boolean, - /** 此项必须设置(其值在整个树范围内唯一)*/ - key: string, - /** 默认根据此属性值进行筛选*/ - value?: string, - /** 树节点显示的内容*/ - title?: React.ReactNode | string, - /** 是否是叶子节点*/ - isLeaf?: boolean - } - export class TreeSelectTreeNode extends React.Component { - render(): JSX.Element - } - - type TreeData = Array<{ value: any, label: string, children: TreeData }> - interface TreeSelectProps { - style?: Object, - /** 指定当前选中的条目*/ - value?: string | Array, - /** 指定默认选中的条目*/ - defaultValue?: string | Array, - /** 支持多选*/ - multiple?: boolean, - /** 可以把随意输入的条目作为 tag,输入项不需要与下拉选项匹配*/ - tags?: boolean, - /** 被选中时调用,参数为选中项的 value 值*/ - onSelect?: (value: any) => void, - /** 选中option,或input的value变化(combobox 模式下)时,调用此函数*/ - onChange?: (value: any, label: any) => void, - /** 显示清除按钮*/ - allowClear?: boolean, - /** 文本框值变化时回调*/ - onSearch?: (value: any) => void, - /** 选择框默认文字*/ - placeholder?: string, - /** 搜索框默认文字*/ - searchPlaceholder?: string, - /** 下拉菜单的样式*/ - dropdownStyle?: Object, - /** 下拉菜单和选择器同宽*/ - dropdownMatchSelectWidth?: boolean, - /** 输入框自动提示模式*/ - combobox?: boolean, - /** 选择框大小,可选 `large` `small`*/ - size?: string, - /** 在下拉中显示搜索框*/ - showSearch?: boolean, - /** 是否禁用*/ - disabled?: boolean, - /** 默认展开所有树节点*/ - treeDefaultExpandAll?: boolean, - /** 显示checkbox*/ - treeCheckable?: boolean, - /** 是否根据输入项进行筛选,返回值true*/ - filterTreeNode?: (treeNode: any) => boolean, - /** 输入项过滤对应的 treeNode 属性*/ - treeNodeFilterProp?: string, - /** 作为显示的prop设置*/ - treeNodeLabelProp?: string, - /** treeNodes数据,如果设置则不需要手动构造TreeNode节点(如果value在整个树范围内不唯一,需要设置`key`其值为整个树范围内的唯一id*/ - treeData?: TreeData, - /** 异步加载数据*/ - loadData?: (node: any) => void - } - /** - * #TreeSelect - 树型选择控件。 - - ## 何时使用 - - 类似 Select 的选择控件,可选择的数据结构是一个树形结构时,可以使用 TreeSelect,例如公司层级、学科系统、分类目录等等。 - */ - export class TreeSelect extends React.Component { - static TreeNode: typeof TreeSelectTreeNode - render(): JSX.Element - } - - - - - - - // Upload - interface UploadProps { - /** 可选参数, 上传的文件 */ - name?: string, - /** 必选参数, 上传的地址 */ - action: string, - /** 可选参数, 上传所需参数 */ - data?: Object, - /** 可选参数, 设置上传的请求头部,IE10 以上有效*/ - headers?: Object, - /** 可选参数, 是否展示 uploadList, 默认开启 */ - showUploadList?: boolean, - /** 可选参数, 是否支持多选文件,`ie10+` 支持。开启后按住 ctrl 可选择多个文件。*/ - multiple?: boolean, - /** 可选参数, 接受上传的文件类型, 详见 input accept Attribute */ - accept?: string, - /** 可选参数, 上传文件之前的钩子,参数为上传的文件,若返回 `false` 或者 Promise 则停止上传。**注意:该方法不支持老 IE**。*/ - beforeUpload?: Function, - /** 可选参数, 上传文件改变时的状态,详见 onChange */ - onChange?: (info: Object) => void, - /** 上传列表的内建样式,支持两种基本样式 `text` or `picture` */ - listType?: string, - /** 自定义类名*/ - className?: string - - } - /** - * #Upload - 文件选择上传和拖拽上传控件。 - - ## 何时使用 - - 上传是将信息(网页、文字、图片、视频等)通过网页或者上传工具发布到远程服务器上的过程。 - - - 当需要上传一个或一些文件时。 - - 当需要展现上传的进度时。 - - 当需要使用拖拽交互时。*/ - export class Upload extends React.Component { - render(): JSX.Element - } - - - - - - -} - - -// export all antd -declare module 'antd' { - export = Antd -} -// single export point -declare module 'antd/lib/Affix' { - export default Antd.Affix -} -declare module 'antd/lib/Button' { - export default Antd.Button -} -declare module 'antd/lib/Alert' { - export default Antd.Alert -} -declare module 'antd/lib/Badge' { - export default Antd.Badge -} -declare module 'antd/lib/Breadcrumb' { - export default Antd.Breadcrumb -} -declare module 'antd/lib/Calendar' { - export default Antd.Calendar -} -declare module 'antd/lib/Carousel' { - export default Antd.Carousel -} -declare module 'antd/lib/Cascader' { - export default Antd.Cascader -} -declare module 'antd/lib/Checkbox' { - export default Antd.Checkbox -} -declare module 'antd/lib/Collapse' { - export default Antd.Collapse -} -declare module 'antd/lib/DatePicker' { - export default Antd.DatePicker -} -declare module 'antd/lib/Dropdown' { - export default Antd.Dropdown -} -declare module 'antd/lib/Icon' { - export default Antd.Icon -} -declare module 'antd/lib/Form' { - export default Antd.Form -} -declare module 'antd/lib/Input' { - export default Antd.Input -} -declare module 'antd/lib/InputNumber' { - export default Antd.InputNumber -} -declare module 'antd/lib/Row' { - export default Antd.Row -} -declare module 'antd/lib/Col' { - export default Antd.Col -} -declare module 'antd/lib/Menu' { - export default Antd.Menu -} -declare module 'antd/lib/message' { - export default Antd.message -} -declare module 'antd/lib/Modal' { - export default Antd.Modal -} -declare module 'antd/lib/notification' { - export default Antd.notification -} -declare module 'antd/lib/Pagination' { - export default Antd.Pagination -} -declare module 'antd/lib/Popconfirm' { - export default Antd.Popconfirm -} -declare module 'antd/lib/Popover' { - export default Antd.Popover -} -declare module 'antd/lib/Progress' { - export default Antd.Progress -} -declare module 'antd/lib/QueueAnim' { - export default Antd.QueueAnim -} -declare module 'antd/lib/Radio' { - export default Antd.Radio -} -declare module 'antd/lib/Select' { - export default Antd.Select -} -declare module 'antd/lib/Slider' { - export default Antd.Slider -} -declare module 'antd/lib/Spin' { - export default Antd.Spin -} -declare module 'antd/lib/Steps' { - export default Antd.Steps -} -declare module 'antd/lib/Switch' { - export default Antd.Switch -} -declare module 'antd/lib/Table' { - export default Antd.Table -} -declare module 'antd/lib/Tabs' { - export default Antd.Tabs -} -declare module 'antd/lib/Tag' { - export default Antd.Tag -} -declare module 'antd/lib/TimePicker' { - export default Antd.TimePicker -} -declare module 'antd/lib/Timeline' { - export default Antd.Timeline -} -declare module 'antd/lib/Tooltip' { - export default Antd.Tooltip -} -declare module 'antd/lib/Transfer' { - export default Antd.Transfer -} -declare module 'antd/lib/Tree' { - export default Antd.Tree -} -declare module 'antd/lib/TreeSelect' { - export default Antd.TreeSelect -} -declare module 'antd/lib/Upload' { - export default Antd.Upload -} diff --git a/typings/globals/antd/typings.json b/typings/globals/antd/typings.json deleted file mode 100644 index 60e343a..0000000 --- a/typings/globals/antd/typings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "resolution": "main", - "tree": { - "src": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/9b5329839558a78550bf078c3e5f323c2f0f3b86/antd/index.d.ts", - "raw": "registry:dt/antd#0.12.10+20170123203653", - "typings": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/9b5329839558a78550bf078c3e5f323c2f0f3b86/antd/index.d.ts" - } -} diff --git a/typings/globals/electron/index.d.ts b/typings/globals/electron/index.d.ts deleted file mode 100644 index 3dc97d9..0000000 --- a/typings/globals/electron/index.d.ts +++ /dev/null @@ -1,6115 +0,0 @@ -// Generated by typings -// Source: https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/8978f926e21860801db49d1fd9d3448b121b11e9/electron/index.d.ts -declare namespace Electron { - - interface Event { - preventDefault: Function; - sender: NodeJS.EventEmitter; - } - - type Point = { - x: number; - y: number; - } - - type Size = { - width: number; - height: number; - } - - type Rectangle = { - x: number; - y: number; - width: number; - height: number; - } - - interface Destroyable { - /** - * Destroys the object. - */ - destroy(): void; - /** - * @returns Whether the object is destroyed. - */ - isDestroyed(): boolean; - } - - // https://github.com/electron/electron/blob/master/docs/api/app.md - - type VibrancyType = 'appearance-based' | 'light' | 'dark' | 'titlebar' | 'selection' | 'menu' | 'popover' | 'sidebar' | 'medium-light' | 'ultra-dark'; - - /** - * The app module is responsible for controlling the application's lifecycle. - */ - interface App extends NodeJS.EventEmitter { - /** - * Emitted when the application has finished basic startup. - * On Windows and Linux, the will-finish-launching event - * is the same as the ready event; on macOS, this event represents - * the applicationWillFinishLaunching notification of NSApplication. - * You would usually set up listeners for the open-file and open-url events here, - * and start the crash reporter and auto updater. - * - * In most cases, you should just do everything in the ready event handler. - */ - on(event: 'will-finish-launching', listener: Function): this; - /** - * Emitted when Electron has finished initialization. - */ - on(event: 'ready', listener: (event: Event, launchInfo: Object) => void): this; - /** - * Emitted when all windows have been closed. - * - * If you do not subscribe to this event and all windows are closed, - * the default behavior is to quit the app; however, if you subscribe, - * you control whether the app quits or not. - * If the user pressed Cmd + Q, or the developer called app.quit(), - * Electron will first try to close all the windows and then emit the will-quit event, - * and in this case the window-all-closed event would not be emitted. - */ - on(event: 'window-all-closed', listener: Function): this; - /** - * Emitted before the application starts closing its windows. - * Calling event.preventDefault() will prevent the default behaviour, which is terminating the application. - */ - on(event: 'before-quit', listener: (event: Event) => void): this; - /** - * Emitted when all windows have been closed and the application will quit. - * Calling event.preventDefault() will prevent the default behaviour, which is terminating the application. - */ - on(event: 'will-quit', listener: (event: Event) => void): this; - /** - * Emitted when the application is quitting. - */ - on(event: 'quit', listener: (event: Event, exitCode: number) => void): this; - /** - * Emitted when the user wants to open a file with the application. - * The open-file event is usually emitted when the application is already open - * and the OS wants to reuse the application to open the file. - * open-file is also emitted when a file is dropped onto the dock and the application - * is not yet running. Make sure to listen for the open-file event very early - * in your application startup to handle this case (even before the ready event is emitted). - * - * You should call event.preventDefault() if you want to handle this event. - * - * Note: This is only implemented on macOS. - */ - on(event: 'open-file', listener: (event: Event, url: string) => void): this; - /** - * Emitted when the user wants to open a URL with the application. - * The URL scheme must be registered to be opened by your application. - * - * You should call event.preventDefault() if you want to handle this event. - * - * Note: This is only implemented on macOS. - */ - on(event: 'open-url', listener: (event: Event, url: string) => void): this; - /** - * Emitted when the application is activated, which usually happens when clicks on the applications’s dock icon. - * Note: This is only implemented on macOS. - */ - on(event: 'activate', listener: Function): this; - /** - * Emitted during Handoff when an activity from a different device wants to be resumed. - * You should call event.preventDefault() if you want to handle this event. - */ - on(event: 'continue-activity', listener: (event: Event, type: string, userInfo: Object) => void): this; - /** - * Emitted when a browserWindow gets blurred. - */ - on(event: 'browser-window-blur', listener: (event: Event, browserWindow: BrowserWindow) => void): this; - /** - * Emitted when a browserWindow gets focused. - */ - on(event: 'browser-window-focus', listener: (event: Event, browserWindow: BrowserWindow) => void): this; - /** - * Emitted when a new browserWindow is created. - */ - on(event: 'browser-window-created', listener: (event: Event, browserWindow: BrowserWindow) => void): this; - /** - * Emitted when a new webContents is created. - */ - on(event: 'web-contents-created', listener: (event: Event, webContents: WebContents) => void): this; - /** - * Emitted when failed to verify the certificate for url, to trust the certificate - * you should prevent the default behavior with event.preventDefault() and call callback(true). - */ - on(event: 'certificate-error', listener: (event: Event, - webContents: WebContents, - url: string, - error: string, - certificate: Certificate, - callback: (trust: boolean) => void - ) => void): this; - /** - * Emitted when a client certificate is requested. - * - * The url corresponds to the navigation entry requesting the client certificate - * and callback needs to be called with an entry filtered from the list. - * Using event.preventDefault() prevents the application from using the first certificate from the store. - */ - on(event: 'select-client-certificate', listener: (event: Event, - webContents: WebContents, - url: string, - certificateList: Certificate[], - callback: (certificate: Certificate) => void - ) => void): this; - /** - * Emitted when webContents wants to do basic auth. - * - * The default behavior is to cancel all authentications, to override this - * you should prevent the default behavior with event.preventDefault() - * and call callback(username, password) with the credentials. - */ - on(event: 'login', listener: (event: Event, - webContents: WebContents, - request: LoginRequest, - authInfo: LoginAuthInfo, - callback: (username: string, password: string) => void - ) => void): this; - /** - * Emitted when the gpu process crashes. - */ - on(event: 'gpu-process-crashed', listener: (event: Event, killed: boolean) => void): this; - /** - * Emitted when Chrome's accessibility support changes. - * - * Note: This API is only available on macOS and Windows. - */ - on(event: 'accessibility-support-changed', listener: (event: Event, accessibilitySupportEnabled: boolean) => void): this; - on(event: string, listener: Function): this; - /** - * Try to close all windows. The before-quit event will first be emitted. - * If all windows are successfully closed, the will-quit event will be emitted - * and by default the application would be terminated. - * - * This method guarantees all beforeunload and unload handlers are correctly - * executed. It is possible that a window cancels the quitting by returning - * false in beforeunload handler. - */ - quit(): void; - /** - * Exits immediately with exitCode. - * All windows will be closed immediately without asking user - * and the before-quit and will-quit events will not be emitted. - */ - exit(exitCode?: number): void; - /** - * Relaunches the app when current instance exits. - * - * By default the new instance will use the same working directory - * and command line arguments with current instance. - * When args is specified, the args will be passed as command line arguments instead. - * When execPath is specified, the execPath will be executed for relaunch instead of current app. - * - * Note that this method does not quit the app when executed, you have to call app.quit - * or app.exit after calling app.relaunch to make the app restart. - * - * When app.relaunch is called for multiple times, multiple instances - * will be started after current instance exited. - */ - relaunch(options?: { - args?: string[], - execPath?: string - }): void; - /** - * @returns Whether Electron has finished initializing. - */ - isReady(): boolean; - /** - * On Linux, focuses on the first visible window. - * On macOS, makes the application the active app. - * On Windows, focuses on the application’s first window. - */ - focus(): void; - /** - * Hides all application windows without minimizing them. - * Note: This is only implemented on macOS. - */ - hide(): void; - /** - * Shows application windows after they were hidden. Does not automatically focus them. - * Note: This is only implemented on macOS. - */ - show(): void; - /** - * Returns the current application directory. - */ - getAppPath(): string; - /** - * @returns The path to a special directory or file associated with name. - * On failure an Error would throw. - */ - getPath(name: AppPathName): string; - /** - * Overrides the path to a special directory or file associated with name. - * If the path specifies a directory that does not exist, the directory will - * be created by this method. On failure an Error would throw. - * - * You can only override paths of names defined in app.getPath. - * - * By default web pages' cookies and caches will be stored under userData - * directory, if you want to change this location, you have to override the - * userData path before the ready event of app module gets emitted. - */ - setPath(name: AppPathName, path: string): void; - /** - * @returns The version of loaded application, if no version is found in - * application's package.json, the version of current bundle or executable. - */ - getVersion(): string; - /** - * @returns The current application's name, the name in package.json would be used. - * Usually the name field of package.json is a short lowercased name, according to - * the spec of npm modules. So usually you should also specify a productName field, - * which is your application's full capitalized name, and it will be preferred over - * name by Electron. - */ - getName(): string; - /** - * Overrides the current application's name. - */ - setName(name: string): void; - /** - * @returns The current application locale. - */ - getLocale(): string; - /** - * Adds path to recent documents list. - * - * This list is managed by the system, on Windows you can visit the list from - * task bar, and on macOS you can visit it from dock menu. - * - * Note: This is only implemented on macOS and Windows. - */ - addRecentDocument(path: string): void; - /** - * Clears the recent documents list. - * - * Note: This is only implemented on macOS and Windows. - */ - clearRecentDocuments(): void; - /** - * Sets the current executable as the default handler for a protocol (aka URI scheme). - * Once registered, all links with your-protocol:// will be opened with the current executable. - * The whole link, including protocol, will be passed to your application as a parameter. - * - * On Windows you can provide optional parameters path, the path to your executable, - * and args, an array of arguments to be passed to your executable when it launches. - * - * @param protocol The name of your protocol, without ://. - * @param path Defaults to process.execPath. - * @param args Defaults to an empty array. - * - * Note: This is only implemented on macOS and Windows. - * On macOS, you can only register protocols that have been added to your app's info.plist. - */ - setAsDefaultProtocolClient(protocol: string, path?: string, args?: string[]): boolean; - /** - * Removes the current executable as the default handler for a protocol (aka URI scheme). - * - * @param protocol The name of your protocol, without ://. - * @param path Defaults to process.execPath. - * @param args Defaults to an empty array. - * - * Note: This is only implemented on macOS and Windows. - */ - removeAsDefaultProtocolClient(protocol: string, path?: string, args?: string[]): boolean; - /** - * @param protocol The name of your protocol, without ://. - * @param path Defaults to process.execPath. - * @param args Defaults to an empty array. - * - * @returns Whether the current executable is the default handler for a protocol (aka URI scheme). - * - * Note: This is only implemented on macOS and Windows. - */ - isDefaultProtocolClient(protocol: string, path?: string, args?: string[]): boolean; - /** - * Adds tasks to the Tasks category of JumpList on Windows. - * - * Note: This API is only available on Windows. - */ - setUserTasks(tasks: Task[]): boolean; - /** - * Note: This API is only available on Windows. - */ - getJumpListSettings(): JumpListSettings; - /** - * Sets or removes a custom Jump List for the application. - * - * If categories is null the previously set custom Jump List (if any) will be replaced - * by the standard Jump List for the app (managed by Windows). - * - * Note: This API is only available on Windows. - */ - setJumpList(categories: JumpListCategory[]): SetJumpListResult; - /** - * This method makes your application a Single Instance Application instead of allowing - * multiple instances of your app to run, this will ensure that only a single instance - * of your app is running, and other instances signal this instance and exit. - */ - makeSingleInstance(callback: (args: string[], workingDirectory: string) => void): boolean; - /** - * Releases all locks that were created by makeSingleInstance. This will allow - * multiple instances of the application to once again run side by side. - */ - releaseSingleInstance(): void; - /** - * Creates an NSUserActivity and sets it as the current activity. - * The activity is eligible for Handoff to another device afterward. - * - * @param type Uniquely identifies the activity. Maps to NSUserActivity.activityType. - * @param userInfo App-specific state to store for use by another device. - * @param webpageURL The webpage to load in a browser if no suitable app is - * installed on the resuming device. The scheme must be http or https. - * - * Note: This API is only available on macOS. - */ - setUserActivity(type: string, userInfo: Object, webpageURL?: string): void; - /** - * @returns The type of the currently running activity. - * - * Note: This API is only available on macOS. - */ - getCurrentActivityType(): string; - /** - * Changes the Application User Model ID to id. - * - * Note: This is only implemented on Windows. - */ - setAppUserModelId(id: string): void; - /** - * Imports the certificate in pkcs12 format into the platform certificate store. - * @param callback Called with the result of import operation, a value of 0 indicates success - * while any other value indicates failure according to chromium net_error_list. - * - * Note: This API is only available on Linux. - */ - importCertificate(options: ImportCertificateOptions, callback: (result: number) => void): void; - /** - * Disables hardware acceleration for current app. - * This method can only be called before app is ready. - */ - disableHardwareAcceleration(): void; - /** - * @returns whether current desktop environment is Unity launcher. (Linux) - * - * Note: This API is only available on Linux. - */ - isUnityRunning(): boolean; - /** - * Returns a Boolean, true if Chrome's accessibility support is enabled, false otherwise. - * This API will return true if the use of assistive technologies, such as screen readers, - * has been detected. - * See https://www.chromium.org/developers/design-documents/accessibility for more details. - * - * Note: This API is only available on macOS and Windows. - */ - isAccessibilitySupportEnabled(): boolean; - /** - * @returns an Object with the login item settings of the app. - * - * Note: This API is only available on macOS and Windows. - */ - getLoginItemSettings(): LoginItemSettings; - /** - * Set the app's login item settings. - * - * Note: This API is only available on macOS and Windows. - */ - setLoginItemSettings(settings: LoginItemSettings): void; - /** - * Set the about panel options. This will override the values defined in the app's .plist file. - * See the Apple docs for more details. - * - * Note: This API is only available on macOS. - */ - setAboutPanelOptions(options: AboutPanelOptions): void; - commandLine: CommandLine; - /** - * Note: This API is only available on macOS. - */ - dock: Dock; - } - - type AppPathName = 'home'|'appData'|'userData'|'temp'|'exe'|'module'|'desktop'|'documents'|'downloads'|'music'|'pictures'|'videos'|'pepperFlashSystemPlugin'; - - interface ImportCertificateOptions { - /** - * Path for the pkcs12 file. - */ - certificate: string; - /** - * Passphrase for the certificate. - */ - password: string; - } - - interface CommandLine { - /** - * Append a switch [with optional value] to Chromium's command line. - * - * Note: This will not affect process.argv, and is mainly used by developers - * to control some low-level Chromium behaviors. - */ - appendSwitch(_switch: string, value?: string): void; - /** - * Append an argument to Chromium's command line. The argument will quoted properly. - * - * Note: This will not affect process.argv. - */ - appendArgument(value: string): void; - } - - interface Dock { - /** - * When critical is passed, the dock icon will bounce until either the - * application becomes active or the request is canceled. - * - * When informational is passed, the dock icon will bounce for one second. - * However, the request remains active until either the application becomes - * active or the request is canceled. - * - * @param type The default is informational. - * @returns An ID representing the request. - */ - bounce(type?: 'critical' | 'informational'): number; - /** - * Cancel the bounce of id. - * - * Note: This API is only available on macOS. - */ - cancelBounce(id: number): void; - /** - * Bounces the Downloads stack if the filePath is inside the Downloads folder. - * - * Note: This API is only available on macOS. - */ - downloadFinished(filePath: string): void; - /** - * Sets the string to be displayed in the dock’s badging area. - * - * Note: This API is only available on macOS. - */ - setBadge(text: string): void; - /** - * Returns the badge string of the dock. - * - * Note: This API is only available on macOS. - */ - getBadge(): string; - /** - * Sets the counter badge for current app. Setting the count to 0 will hide the badge. - * - * @returns True when the call succeeded, otherwise returns false. - * - * Note: This API is only available on macOS and Linux. - */ - setBadgeCount(count: number): boolean; - /** - * @returns The current value displayed in the counter badge. - * - * Note: This API is only available on macOS and Linux. - */ - getBadgeCount(): number; - /** - * Hides the dock icon. - * - * Note: This API is only available on macOS. - */ - hide(): void; - /** - * Shows the dock icon. - * - * Note: This API is only available on macOS. - */ - show(): void; - /** - * @returns Whether the dock icon is visible. - * The app.dock.show() call is asynchronous so this method might not return true immediately after that call. - * - * Note: This API is only available on macOS. - */ - isVisible(): boolean; - /** - * Sets the application dock menu. - * - * Note: This API is only available on macOS. - */ - setMenu(menu: Menu): void; - /** - * Sets the image associated with this dock icon. - * - * Note: This API is only available on macOS. - */ - setIcon(icon: NativeImage | string): void; - } - - interface Task { - /** - * Path of the program to execute, usually you should specify process.execPath - * which opens current program. - */ - program: string; - /** - * The arguments of command line when program is executed. - */ - arguments: string; - /** - * The string to be displayed in a JumpList. - */ - title: string; - /** - * Description of this task. - */ - description?: string; - /** - * The absolute path to an icon to be displayed in a JumpList, it can be - * arbitrary resource file that contains an icon, usually you can specify - * process.execPath to show the icon of the program. - */ - iconPath: string; - /** - * The icon index in the icon file. If an icon file consists of two or more - * icons, set this value to identify the icon. If an icon file consists of - * one icon, this value is 0. - */ - iconIndex?: number; - } - - /** - * ok - Nothing went wrong. - * error - One or more errors occured, enable runtime logging to figure out the likely cause. - * invalidSeparatorError - An attempt was made to add a separator to a custom category in the Jump List. - * Separators are only allowed in the standard Tasks category. - * fileTypeRegistrationError - An attempt was made to add a file link to the Jump List - * for a file type the app isn't registered to handle. - * customCategoryAccessDeniedError - Custom categories can't be added to the Jump List - * due to user privacy or group policy settings. - */ - type SetJumpListResult = 'ok' | 'error' | 'invalidSeparatorError' | 'fileTypeRegistrationError' | 'customCategoryAccessDeniedError'; - - interface JumpListSettings { - /** - * The minimum number of items that will be shown in the Jump List. - */ - minItems: number; - /** - * Items that the user has explicitly removed from custom categories in the Jump List. - */ - removedItems: JumpListItem[]; - } - - interface JumpListCategory { - /** - * tasks - Items in this category will be placed into the standard Tasks category. - * frequent - Displays a list of files frequently opened by the app, the name of the category and its items are set by Windows. - * recent - Displays a list of files recently opened by the app, the name of the category and its items are set by Windows. - * custom - Displays tasks or file links, name must be set by the app. - */ - type?: 'tasks' | 'frequent' | 'recent' | 'custom'; - /** - * Must be set if type is custom, otherwise it should be omitted. - */ - name?: string; - /** - * Array of JumpListItem objects if type is tasks or custom, otherwise it should be omitted. - */ - items?: JumpListItem[]; - } - - interface JumpListItem { - /** - * task - A task will launch an app with specific arguments. - * separator - Can be used to separate items in the standard Tasks category. - * file - A file link will open a file using the app that created the Jump List. - */ - type: 'task' | 'separator' | 'file'; - /** - * Path of the file to open, should only be set if type is file. - */ - path?: string; - /** - * Path of the program to execute, usually you should specify process.execPath which opens the current program. - * Should only be set if type is task. - */ - program?: string; - /** - * The command line arguments when program is executed. Should only be set if type is task. - */ - args?: string; - /** - * The text to be displayed for the item in the Jump List. Should only be set if type is task. - */ - title?: string; - /** - * Description of the task (displayed in a tooltip). Should only be set if type is task. - */ - description?: string; - /** - * The absolute path to an icon to be displayed in a Jump List, which can be an arbitrary - * resource file that contains an icon (e.g. .ico, .exe, .dll). - * You can usually specify process.execPath to show the program icon. - */ - iconPath?: string; - /** - * The index of the icon in the resource file. If a resource file contains multiple icons - * this value can be used to specify the zero-based index of the icon that should be displayed - * for this task. If a resource file contains only one icon, this property should be set to zero. - */ - iconIndex?: number; - } - - interface LoginItemSettings { - /** - * True if the app is set to open at login. - */ - openAtLogin: boolean; - /** - * True if the app is set to open as hidden at login. This setting is only supported on macOS. - */ - openAsHidden: boolean; - /** - * True if the app was opened at login automatically. This setting is only supported on macOS. - */ - wasOpenedAtLogin?: boolean; - /** - * True if the app was opened as a hidden login item. This indicates that the app should not - * open any windows at startup. This setting is only supported on macOS. - */ - wasOpenedAsHidden?: boolean; - /** - * True if the app was opened as a login item that should restore the state from the previous session. - * This indicates that the app should restore the windows that were open the last time the app was closed. - * This setting is only supported on macOS. - */ - restoreState?: boolean; - } - - interface AboutPanelOptions { - /** - * The app's name. - */ - applicationName?: string; - /** - * The app's version. - */ - applicationVersion?: string; - /** - * Copyright information. - */ - copyright?: string; - /** - * Credit information. - */ - credits?: string; - /** - * The app's build version number. - */ - version?: string; - } - - // https://github.com/electron/electron/blob/master/docs/api/auto-updater.md - - /** - * This module provides an interface for the Squirrel auto-updater framework. - */ - interface AutoUpdater extends NodeJS.EventEmitter { - /** - * Emitted when there is an error while updating. - */ - on(event: 'error', listener: (error: Error) => void): this; - /** - * Emitted when checking if an update has started. - */ - on(event: 'checking-for-update', listener: Function): this; - /** - * Emitted when there is an available update. The update is downloaded automatically. - */ - on(event: 'update-available', listener: Function): this; - /** - * Emitted when there is no available update. - */ - on(event: 'update-not-available', listener: Function): this; - /** - * Emitted when an update has been downloaded. - * Note: On Windows only releaseName is available. - */ - on(event: 'update-downloaded', listener: (event: Event, releaseNotes: string, releaseName: string, releaseDate: Date, updateURL: string) => void): this; - on(event: string, listener: Function): this; - /** - * Set the url and initialize the auto updater. - */ - setFeedURL(url: string, requestHeaders?: Headers): void; - /** - * @returns The current update feed URL. - */ - getFeedURL(): string; - /** - * Ask the server whether there is an update, you have to call setFeedURL - * before using this API - */ - checkForUpdates(): void; - /** - * Restarts the app and installs the update after it has been downloaded. - * It should only be called after update-downloaded has been emitted. - */ - quitAndInstall(): void; - } - - // https://github.com/electron/electron/blob/master/docs/api/browser-window.md - - /** - * The BrowserWindow class gives you ability to create a browser window. - * You can also create a window without chrome by using Frameless Window API. - */ - class BrowserWindow extends NodeJS.EventEmitter implements Destroyable { - /** - * Emitted when the document changed its title, - * calling event.preventDefault() would prevent the native window’s title to change. - */ - on(event: 'page-title-updated', listener: (event: Event, title: string) => void): this; - /** - * Emitted when the window is going to be closed. It’s emitted before the beforeunload - * and unload event of the DOM. Calling event.preventDefault() will cancel the close. - */ - on(event: 'close', listener: (event: Event) => void): this; - /** - * Emitted when the window is closed. After you have received this event - * you should remove the reference to the window and avoid using it anymore. - */ - on(event: 'closed', listener: Function): this; - /** - * Emitted when the web page becomes unresponsive. - */ - on(event: 'unresponsive', listener: Function): this; - /** - * Emitted when the unresponsive web page becomes responsive again. - */ - on(event: 'responsive', listener: Function): this; - /** - * Emitted when the window loses focus. - */ - on(event: 'blur', listener: Function): this; - /** - * Emitted when the window gains focus. - */ - on(event: 'focus', listener: Function): this; - /** - * Emitted when the window is shown. - */ - on(event: 'show', listener: Function): this; - /** - * Emitted when the window is hidden. - */ - on(event: 'hide', listener: Function): this; - /** - * Emitted when the web page has been rendered and window can be displayed without visual flash. - */ - on(event: 'ready-to-show', listener: Function): this; - /** - * Emitted when window is maximized. - */ - on(event: 'maximize', listener: Function): this; - /** - * Emitted when the window exits from maximized state. - */ - on(event: 'unmaximize', listener: Function): this; - /** - * Emitted when the window is minimized. - */ - on(event: 'minimize', listener: Function): this; - /** - * Emitted when the window is restored from minimized state. - */ - on(event: 'restore', listener: Function): this; - /** - * Emitted when the window is getting resized. - */ - on(event: 'resize', listener: Function): this; - /** - * Emitted when the window is getting moved to a new position. - */ - on(event: 'move', listener: Function): this; - /** - * Emitted when the window enters full screen state. - */ - on(event: 'enter-full-screen', listener: Function): this; - /** - * Emitted when the window leaves full screen state. - */ - on(event: 'leave-full-screen', listener: Function): this; - /** - * Emitted when the window enters full screen state triggered by HTML API. - */ - on(event: 'enter-html-full-screen', listener: Function): this; - /** - * Emitted when the window leaves full screen state triggered by HTML API. - */ - on(event: 'leave-html-full-screen', listener: Function): this; - /** - * Emitted when an App Command is invoked. These are typically related - * to keyboard media keys or browser commands, as well as the "Back" / - * "Forward" buttons built into some mice on Windows. - * Note: This is only implemented on Windows. - */ - on(event: 'app-command', listener: (event: Event, command: string) => void): this; - /** - * Emitted when scroll wheel event phase has begun. - * Note: This is only implemented on macOS. - */ - on(event: 'scroll-touch-begin', listener: Function): this; - /** - * Emitted when scroll wheel event phase has ended. - * Note: This is only implemented on macOS. - */ - on(event: 'scroll-touch-end', listener: Function): this; - /** - * Emitted when scroll wheel event phase filed upon reaching the edge of element. - * Note: This is only implemented on macOS. - */ - on(event: 'scroll-touch-edge', listener: Function): this; - /** - * Emitted on 3-finger swipe. - * Note: This is only implemented on macOS. - */ - on(event: 'swipe', listener: (event: Event, direction: SwipeDirection) => void): this; - on(event: string, listener: Function): this; - /** - * Creates a new BrowserWindow with native properties as set by the options. - */ - constructor(options?: BrowserWindowOptions); - /** - * @returns All opened browser windows. - */ - static getAllWindows(): BrowserWindow[]; - /** - * @returns The window that is focused in this application. - */ - static getFocusedWindow(): BrowserWindow; - /** - * Find a window according to the webContents it owns. - */ - static fromWebContents(webContents: WebContents): BrowserWindow; - /** - * Find a window according to its ID. - */ - static fromId(id: number): BrowserWindow; - /** - * Adds devtools extension located at path. The extension will be remembered - * so you only need to call this API once, this API is not for programming use. - * @returns The extension's name. - * - * Note: This API cannot be called before the ready event of the app module is emitted. - */ - static addDevToolsExtension(path: string): string; - /** - * Remove a devtools extension. - * @param name The name of the devtools extension to remove. - * - * Note: This API cannot be called before the ready event of the app module is emitted. - */ - static removeDevToolsExtension(name: string): void; - /** - * @returns devtools extensions. - * - * Note: This API cannot be called before the ready event of the app module is emitted. - */ - static getDevToolsExtensions(): DevToolsExtensions; - /** - * The WebContents object this window owns, all web page related events and - * operations would be done via it. - * Note: Users should never store this object because it may become null when - * the renderer process (web page) has crashed. - */ - webContents: WebContents; - /** - * Get the unique ID of this window. - */ - id: number; - /** - * Force closing the window, the unload and beforeunload event won't be emitted - * for the web page, and close event would also not be emitted for this window, - * but it would guarantee the closed event to be emitted. - * You should only use this method when the renderer process (web page) has crashed. - */ - destroy(): void; - /** - * Try to close the window, this has the same effect with user manually clicking - * the close button of the window. The web page may cancel the close though, - * see the close event. - */ - close(): void; - /** - * Focus on the window. - */ - focus(): void; - /** - * Remove focus on the window. - */ - blur(): void; - /** - * @returns Whether the window is focused. - */ - isFocused(): boolean; - /** - * @returns Whether the window is destroyed. - */ - isDestroyed(): boolean; - /** - * Shows and gives focus to the window. - */ - show(): void; - /** - * Shows the window but doesn't focus on it. - */ - showInactive(): void; - /** - * Hides the window. - */ - hide(): void; - /** - * @returns Whether the window is visible to the user. - */ - isVisible(): boolean; - /** - * @returns Whether the window is a modal window. - */ - isModal(): boolean; - /** - * Maximizes the window. - */ - maximize(): void; - /** - * Unmaximizes the window. - */ - unmaximize(): void; - /** - * @returns Whether the window is maximized. - */ - isMaximized(): boolean; - /** - * Minimizes the window. On some platforms the minimized window will be - * shown in the Dock. - */ - minimize(): void; - /** - * Restores the window from minimized state to its previous state. - */ - restore(): void; - /** - * @returns Whether the window is minimized. - */ - isMinimized(): boolean; - /** - * Sets whether the window should be in fullscreen mode. - */ - setFullScreen(flag: boolean): void; - /** - * @returns Whether the window is in fullscreen mode. - */ - isFullScreen(): boolean; - /** - * This will have a window maintain an aspect ratio. - * The extra size allows a developer to have space, specified in pixels, - * not included within the aspect ratio calculations. - * This API already takes into account the difference between a window’s size and its content size. - * - * Note: This API is available only on macOS. - */ - setAspectRatio(aspectRatio: number, extraSize?: Size): void; - /** - * Uses Quick Look to preview a file at a given path. - * - * @param path The absolute path to the file to preview with QuickLook. - * @param displayName The name of the file to display on the Quick Look modal view. - * Note: This API is available only on macOS. - */ - previewFile(path: string, displayName?: string): void; - /** - * Resizes and moves the window to width, height, x, y. - */ - setBounds(options: Rectangle, animate?: boolean): void; - /** - * @returns The window's width, height, x and y values. - */ - getBounds(): Rectangle; - /** - * Resizes and moves the window's client area (e.g. the web page) to width, height, x, y. - */ - setContentBounds(options: Rectangle, animate?: boolean): void; - /** - * @returns The window's client area (e.g. the web page) width, height, x and y values. - */ - getContentBounds(): Rectangle; - /** - * Resizes the window to width and height. - */ - setSize(width: number, height: number, animate?: boolean): void; - /** - * @returns The window's width and height. - */ - getSize(): number[]; - /** - * Resizes the window's client area (e.g. the web page) to width and height. - */ - setContentSize(width: number, height: number, animate?: boolean): void; - /** - * @returns The window's client area's width and height. - */ - getContentSize(): number[]; - /** - * Sets the minimum size of window to width and height. - */ - setMinimumSize(width: number, height: number): void; - /** - * @returns The window's minimum width and height. - */ - getMinimumSize(): number[]; - /** - * Sets the maximum size of window to width and height. - */ - setMaximumSize(width: number, height: number): void; - /** - * @returns The window's maximum width and height. - */ - getMaximumSize(): number[]; - /** - * Sets whether the window can be manually resized by user. - */ - setResizable(resizable: boolean): void; - /** - * @returns Whether the window can be manually resized by user. - */ - isResizable(): boolean; - /** - * Sets whether the window can be moved by user. On Linux does nothing. - * Note: This API is available only on macOS and Windows. - */ - setMovable(movable: boolean): void; - /** - * Note: This API is available only on macOS and Windows. - * @returns Whether the window can be moved by user. On Linux always returns true. - */ - isMovable(): boolean; - /** - * Sets whether the window can be manually minimized by user. On Linux does nothing. - * Note: This API is available only on macOS and Windows. - */ - setMinimizable(minimizable: boolean): void; - /** - * Note: This API is available only on macOS and Windows. - * @returns Whether the window can be manually minimized by user. On Linux always returns true. - */ - isMinimizable(): boolean; - /** - * Sets whether the window can be manually maximized by user. On Linux does nothing. - * Note: This API is available only on macOS and Windows. - */ - setMaximizable(maximizable: boolean): void; - /** - * Note: This API is available only on macOS and Windows. - * @returns Whether the window can be manually maximized by user. On Linux always returns true. - */ - isMaximizable(): boolean; - /** - * Sets whether the maximize/zoom window button toggles fullscreen mode or maximizes the window. - */ - setFullScreenable(fullscreenable: boolean): void; - /** - * @returns Whether the maximize/zoom window button toggles fullscreen mode or maximizes the window. - */ - isFullScreenable(): boolean; - /** - * Sets whether the window can be manually closed by user. On Linux does nothing. - * Note: This API is available only on macOS and Windows. - */ - setClosable(closable: boolean): void; - /** - * Note: This API is available only on macOS and Windows. - * @returns Whether the window can be manually closed by user. On Linux always returns true. - */ - isClosable(): boolean; - /** - * Sets whether the window should show always on top of other windows. After - * setting this, the window is still a normal window, not a toolbox window - * which can not be focused on. - */ - setAlwaysOnTop(flag: boolean, level?: WindowLevel): void; - /** - * @returns Whether the window is always on top of other windows. - */ - isAlwaysOnTop(): boolean; - /** - * Moves window to the center of the screen. - */ - center(): void; - /** - * Moves window to x and y. - */ - setPosition(x: number, y: number, animate?: boolean): void; - /** - * @returns The window's current position. - */ - getPosition(): number[]; - /** - * Changes the title of native window to title. - */ - setTitle(title: string): void; - /** - * Note: The title of web page can be different from the title of the native window. - * @returns The title of the native window. - */ - getTitle(): string; - /** - * Changes the attachment point for sheets on macOS. - * Note: This API is available only on macOS. - */ - setSheetOffset(offsetY: number, offsetX?: number): void; - /** - * Starts or stops flashing the window to attract user's attention. - */ - flashFrame(flag: boolean): void; - /** - * Makes the window do not show in Taskbar. - */ - setSkipTaskbar(skip: boolean): void; - /** - * Enters or leaves the kiosk mode. - */ - setKiosk(flag: boolean): void; - /** - * @returns Whether the window is in kiosk mode. - */ - isKiosk(): boolean; - /** - * The native type of the handle is HWND on Windows, NSView* on macOS, - * and Window (unsigned long) on Linux. - * @returns The platform-specific handle of the window as Buffer. - */ - getNativeWindowHandle(): Buffer; - /** - * Hooks a windows message. The callback is called when the message is received in the WndProc. - * Note: This API is available only on Windows. - */ - hookWindowMessage(message: number, callback: Function): void; - /** - * @returns Whether the message is hooked. - */ - isWindowMessageHooked(message: number): boolean; - /** - * Unhook the window message. - */ - unhookWindowMessage(message: number): void; - /** - * Unhooks all of the window messages. - */ - unhookAllWindowMessages(): void; - /** - * Sets the pathname of the file the window represents, and the icon of the - * file will show in window's title bar. - * Note: This API is available only on macOS. - */ - setRepresentedFilename(filename: string): void; - /** - * Note: This API is available only on macOS. - * @returns The pathname of the file the window represents. - */ - getRepresentedFilename(): string; - /** - * Specifies whether the window’s document has been edited, and the icon in - * title bar will become grey when set to true. - * Note: This API is available only on macOS. - */ - setDocumentEdited(edited: boolean): void; - /** - * Note: This API is available only on macOS. - * @returns Whether the window's document has been edited. - */ - isDocumentEdited(): boolean; - focusOnWebView(): void; - blurWebView(): void; - /** - * Captures the snapshot of page within rect, upon completion the callback - * will be called. Omitting the rect would capture the whole visible page. - * Note: Be sure to read documents on remote buffer in remote if you are going - * to use this API in renderer process. - * @param callback Supplies the image that stores data of the snapshot. - */ - capturePage(rect: Rectangle, callback: (image: NativeImage) => void): void; - /** - * Captures the snapshot of page within rect, upon completion the callback - * will be called. Omitting the rect would capture the whole visible page. - * Note: Be sure to read documents on remote buffer in remote if you are going - * to use this API in renderer process. - * @param callback Supplies the image that stores data of the snapshot. - */ - capturePage(callback: (image: NativeImage) => void): void; - /** - * Same as webContents.loadURL(url). - */ - loadURL(url: string, options?: LoadURLOptions): void; - /** - * Same as webContents.reload. - */ - reload(): void; - /** - * Sets the menu as the window top menu. - * Note: This API is not available on macOS. - */ - setMenu(menu: Menu): void; - /** - * Sets the progress value in the progress bar. - * On Linux platform, only supports Unity desktop environment, you need to - * specify the *.desktop file name to desktopName field in package.json. - * By default, it will assume app.getName().desktop. - * @param progress Valid range is [0, 1.0]. If < 0, the progress bar is removed. - * If greater than 0, it becomes indeterminate. - */ - setProgressBar(progress: number, options?: { - /** - * Mode for the progress bar. - * Note: This is only implemented on Windows. - */ - mode: 'none' | 'normal' | 'indeterminate' | 'error' | 'paused' - }): void; - /** - * Sets a 16px overlay onto the current Taskbar icon, usually used to convey - * some sort of application status or to passively notify the user. - * Note: This API is only available on Windows 7 or above. - * @param overlay The icon to display on the bottom right corner of the Taskbar - * icon. If this parameter is null, the overlay is cleared - * @param description Provided to Accessibility screen readers. - */ - setOverlayIcon(overlay: NativeImage, description: string): void; - /** - * Sets whether the window should have a shadow. On Windows and Linux does nothing. - * Note: This API is available only on macOS. - */ - setHasShadow(hasShadow: boolean): void; - /** - * Note: This API is available only on macOS. - * @returns whether the window has a shadow. On Windows and Linux always returns true. - */ - hasShadow(): boolean; - /** - * Add a thumbnail toolbar with a specified set of buttons to the thumbnail image - * of a window in a taskbar button layout. - * @returns Whether the thumbnail has been added successfully. - * - * Note: This API is available only on Windows. - */ - setThumbarButtons(buttons: ThumbarButton[]): boolean; - /** - * Sets the region of the window to show as the thumbnail image displayed when hovering - * over the window in the taskbar. You can reset the thumbnail to be the entire window - * by specifying an empty region: {x: 0, y: 0, width: 0, height: 0}. - * - * Note: This API is available only on Windows. - */ - setThumbnailClip(region: Rectangle): boolean; - /** - * Sets the toolTip that is displayed when hovering over the window thumbnail in the taskbar. - * Note: This API is available only on Windows. - */ - setThumbnailToolTip(toolTip: string): boolean; - /** - * Same as webContents.showDefinitionForSelection(). - * Note: This API is available only on macOS. - */ - showDefinitionForSelection(): void; - /** - * Changes window icon. - * Note: This API is not available on macOS. - */ - setIcon(icon: NativeImage): void; - /** - * Sets whether the window menu bar should hide itself automatically. Once set - * the menu bar will only show when users press the single Alt key. - * If the menu bar is already visible, calling setAutoHideMenuBar(true) won't - * hide it immediately. - */ - setAutoHideMenuBar(hide: boolean): void; - /** - * @returns Whether menu bar automatically hides itself. - */ - isMenuBarAutoHide(): boolean; - /** - * Sets whether the menu bar should be visible. If the menu bar is auto-hide, - * users can still bring up the menu bar by pressing the single Alt key. - */ - setMenuBarVisibility(visibile: boolean): void; - /** - * @returns Whether the menu bar is visible. - */ - isMenuBarVisible(): boolean; - /** - * Sets whether the window should be visible on all workspaces. - * Note: This API does nothing on Windows. - */ - setVisibleOnAllWorkspaces(visible: boolean): void; - /** - * Note: This API always returns false on Windows. - * @returns Whether the window is visible on all workspaces. - */ - isVisibleOnAllWorkspaces(): boolean; - /** - * Makes the window ignore all mouse events. - * - * All mouse events happened in this window will be passed to the window below this window, - * but if this window has focus, it will still receive keyboard events. - */ - setIgnoreMouseEvents(ignore: boolean): void; - /** - * Prevents the window contents from being captured by other apps. - * - * On macOS it sets the NSWindow's sharingType to NSWindowSharingNone. - * On Windows it calls SetWindowDisplayAffinity with WDA_MONITOR. - */ - setContentProtection(enable: boolean): void; - /** - * Changes whether the window can be focused. - * Note: This API is available only on Windows. - */ - setFocusable(focusable: boolean): void; - /** - * Sets parent as current window's parent window, - * passing null will turn current window into a top-level window. - * Note: This API is not available on Windows. - */ - setParentWindow(parent: BrowserWindow): void; - /** - * @returns The parent window. - */ - getParentWindow(): BrowserWindow; - /** - * @returns All child windows. - */ - getChildWindows(): BrowserWindow[]; - /** - * Adds a vibrancy effect to the browser window. Passing null or - * an empty string will remove the vibrancy effect on the window. - * - * Note: This API is available only on macOS. - */ - setVibrancy(type: VibrancyType): void; - } - - type WindowLevel = 'normal' | 'floating' | 'torn-off-menu' | 'modal-panel' | 'main-menu' | 'status' | 'pop-up-menu' | 'screen-saver' | 'dock'; - type SwipeDirection = 'up' | 'right' | 'down' | 'left'; - type ThumbarButtonFlags = 'enabled' | 'disabled' | 'dismissonclick' | 'nobackground' | 'hidden' | 'noninteractive'; - - interface ThumbarButton { - icon: NativeImage | string; - click: Function; - tooltip?: string; - flags?: ThumbarButtonFlags[]; - } - - interface DevToolsExtensions { - [name: string]: { - name: string; - value: string; - } - } - - interface WebPreferences { - /** - * Whether to enable DevTools. - * If it is set to false, can not use BrowserWindow.webContents.openDevTools() to open DevTools. - * Default: true. - */ - devTools?: boolean; - /** - * Whether node integration is enabled. - * Default: true. - */ - nodeIntegration?: boolean; - /** - * Specifies a script that will be loaded before other scripts run in the page. - * This script will always have access to node APIs no matter whether node integration is turned on or off. - * The value should be the absolute file path to the script. - * When node integration is turned off, the preload script can reintroduce - * Node global symbols back to the global scope. - */ - preload?: string; - /** - * Sets the session used by the page. Instead of passing the Session object directly, - * you can also choose to use the partition option instead, which accepts a partition string. - * When both session and partition are provided, session would be preferred. - * Default: the default session. - */ - session?: Session; - /** - * Sets the session used by the page according to the session’s partition string. - * If partition starts with persist:, the page will use a persistent session available - * to all pages in the app with the same partition. if there is no persist: prefix, - * the page will use an in-memory session. By assigning the same partition, - * multiple pages can share the same session. - * Default: the default session. - */ - partition?: string; - /** - * The default zoom factor of the page, 3.0 represents 300%. - * Default: 1.0. - */ - zoomFactor?: number; - /** - * Enables JavaScript support. - * Default: true. - */ - javascript?: boolean; - /** - * When setting false, it will disable the same-origin policy (Usually using testing - * websites by people), and set allowDisplayingInsecureContent and allowRunningInsecureContent - * to true if these two options are not set by user. - * Default: true. - */ - webSecurity?: boolean; - /** - * Allow an https page to display content like images from http URLs. - * Default: false. - */ - allowDisplayingInsecureContent?: boolean; - /** - * Allow a https page to run JavaScript, CSS or plugins from http URLs. - * Default: false. - */ - allowRunningInsecureContent?: boolean; - /** - * Enables image support. - * Default: true. - */ - images?: boolean; - /** - * Make TextArea elements resizable. - * Default: true. - */ - textAreasAreResizable?: boolean; - /** - * Enables WebGL support. - * Default: true. - */ - webgl?: boolean; - /** - * Enables WebAudio support. - * Default: true. - */ - webaudio?: boolean; - /** - * Whether plugins should be enabled. - * Default: false. - */ - plugins?: boolean; - /** - * Enables Chromium’s experimental features. - * Default: false. - */ - experimentalFeatures?: boolean; - /** - * Enables Chromium’s experimental canvas features. - * Default: false. - */ - experimentalCanvasFeatures?: boolean; - /** - * Enables DirectWrite font rendering system on Windows. - * Default: true. - */ - directWrite?: boolean; - /** - * Enables scroll bounce (rubber banding) effect on macOS. - * Default: false. - */ - scrollBounce?: boolean; - /** - * A list of feature strings separated by ",", like CSSVariables,KeyboardEventKey to enable. - */ - blinkFeatures?: string; - /** - * A list of feature strings separated by ",", like CSSVariables,KeyboardEventKey to disable. - */ - disableBlinkFeatures?: string; - /** - * Sets the default font for the font-family. - */ - defaultFontFamily?: { - /** - * Default: Times New Roman. - */ - standard?: string; - /** - * Default: Times New Roman. - */ - serif?: string; - /** - * Default: Arial. - */ - sansSerif?: string; - /** - * Default: Courier New. - */ - monospace?: string; - }; - /** - * Default: 16. - */ - defaultFontSize?: number; - /** - * Default: 13. - */ - defaultMonospaceFontSize?: number; - /** - * Default: 0. - */ - minimumFontSize?: number; - /** - * Default: ISO-8859-1. - */ - defaultEncoding?: string; - /** - * Whether to throttle animations and timers when the page becomes background. - * Default: true. - */ - backgroundThrottling?: boolean; - /** - * Whether to enable offscreen rendering for the browser window. - * Default: false. - */ - offscreen?: boolean; - /** - * Whether to enable Chromium OS-level sandbox. - * Default: false. - */ - sandbox?: boolean; - } - - interface BrowserWindowOptions { - /** - * Window’s width in pixels. - * Default: 800. - */ - width?: number; - /** - * Window’s height in pixels. - * Default: 600. - */ - height?: number; - /** - * Window’s left offset from screen. - * Default: center the window. - */ - x?: number; - /** - * Window’s top offset from screen. - * Default: center the window. - */ - y?: number; - /** - * The width and height would be used as web page’s size, which means - * the actual window’s size will include window frame’s size and be slightly larger. - * Default: false. - */ - useContentSize?: boolean; - /** - * Show window in the center of the screen. - * Default: true - */ - center?: boolean; - /** - * Window’s minimum width. - * Default: 0. - */ - minWidth?: number; - /** - * Window’s minimum height. - * Default: 0. - */ - minHeight?: number; - /** - * Window’s maximum width. - * Default: no limit. - */ - maxWidth?: number; - /** - * Window’s maximum height. - * Default: no limit. - */ - maxHeight?: number; - /** - * Whether window is resizable. - * Default: true. - */ - resizable?: boolean; - /** - * Whether window is movable. - * Note: This is not implemented on Linux. - * Default: true. - */ - movable?: boolean; - /** - * Whether window is minimizable. - * Note: This is not implemented on Linux. - * Default: true. - */ - minimizable?: boolean; - /** - * Whether window is maximizable. - * Note: This is not implemented on Linux. - * Default: true. - */ - maximizable?: boolean; - /** - * Whether window is closable. - * Note: This is not implemented on Linux. - * Default: true. - */ - closable?: boolean; - /** - * Whether the window can be focused. - * On Windows setting focusable: false also implies setting skipTaskbar: true. - * On Linux setting focusable: false makes the window stop interacting with wm, - * so the window will always stay on top in all workspaces. - * Default: true. - */ - focusable?: boolean; - /** - * Whether the window should always stay on top of other windows. - * Default: false. - */ - alwaysOnTop?: boolean; - /** - * Whether the window should show in fullscreen. - * When explicitly set to false the fullscreen button will be hidden or disabled on macOS. - * Default: false. - */ - fullscreen?: boolean; - /** - * Whether the window can be put into fullscreen mode. - * On macOS, also whether the maximize/zoom button should toggle full screen mode or maximize window. - * Default: true. - */ - fullscreenable?: boolean; - /** - * Whether to show the window in taskbar. - * Default: false. - */ - skipTaskbar?: boolean; - /** - * The kiosk mode. - * Default: false. - */ - kiosk?: boolean; - /** - * Default window title. - * Default: "Electron". - */ - title?: string; - /** - * The window icon, when omitted on Windows the executable’s icon would be used as window icon. - */ - icon?: NativeImage|string; - /** - * Whether window should be shown when created. - * Default: true. - */ - show?: boolean; - /** - * Specify false to create a Frameless Window. - * Default: true. - */ - frame?: boolean; - /** - * Specify parent window. - * Default: null. - */ - parent?: BrowserWindow; - /** - * Whether this is a modal window. This only works when the window is a child window. - * Default: false. - */ - modal?: boolean; - /** - * Whether the web view accepts a single mouse-down event that simultaneously activates the window. - * Default: false. - */ - acceptFirstMouse?: boolean; - /** - * Whether to hide cursor when typing. - * Default: false. - */ - disableAutoHideCursor?: boolean; - /** - * Auto hide the menu bar unless the Alt key is pressed. - * Default: true. - */ - autoHideMenuBar?: boolean; - /** - * Enable the window to be resized larger than screen. - * Default: false. - */ - enableLargerThanScreen?: boolean; - /** - * Window’s background color as Hexadecimal value, like #66CD00 or #FFF or #80FFFFFF (alpha is supported). - * Default: #FFF (white). - */ - backgroundColor?: string; - /** - * Whether window should have a shadow. - * Note: This is only implemented on macOS. - * Default: true. - */ - hasShadow?: boolean; - /** - * Forces using dark theme for the window. - * Note: Only works on some GTK+3 desktop environments. - * Default: false. - */ - darkTheme?: boolean; - /** - * Makes the window transparent. - * Default: false. - */ - transparent?: boolean; - /** - * The type of window, default is normal window. - */ - type?: BrowserWindowType; - /** - * The style of window title bar. - */ - titleBarStyle?: 'default' | 'hidden' | 'hidden-inset'; - /** - * Use WS_THICKFRAME style for frameless windows on Windows - */ - thickFrame?: boolean; - /** - * Add a type of vibrancy effect to the window, only on macOS - */ - vibrancy?: VibrancyType; - /** - * Settings of web page’s features. - */ - webPreferences?: WebPreferences; - } - - type BrowserWindowType = BrowserWindowTypeLinux | BrowserWindowTypeMac | BrowserWindowTypeWindows; - type BrowserWindowTypeLinux = 'desktop' | 'dock' | 'toolbar' | 'splash' | 'notification'; - type BrowserWindowTypeMac = 'desktop' | 'textured'; - type BrowserWindowTypeWindows = 'toolbar'; - - // https://github.com/electron/electron/blob/master/docs/api/clipboard.md - - /** - * The clipboard module provides methods to perform copy and paste operations. - */ - interface Clipboard { - /** - * @returns The contents of the clipboard as plain text. - */ - readText(type?: ClipboardType): string; - /** - * Writes the text into the clipboard as plain text. - */ - writeText(text: string, type?: ClipboardType): void; - /** - * @returns The contents of the clipboard as markup. - */ - readHTML(type?: ClipboardType): string; - /** - * Writes markup to the clipboard. - */ - writeHTML(markup: string, type?: ClipboardType): void; - /** - * @returns The contents of the clipboard as a NativeImage. - */ - readImage(type?: ClipboardType): NativeImage; - /** - * Writes the image into the clipboard. - */ - writeImage(image: NativeImage, type?: ClipboardType): void; - /** - * @returns The contents of the clipboard as RTF. - */ - readRTF(type?: ClipboardType): string; - /** - * Writes the text into the clipboard in RTF. - */ - writeRTF(text: string, type?: ClipboardType): void; - /** - * Clears everything in clipboard. - */ - clear(type?: ClipboardType): void; - /** - * @returns Array available formats for the clipboard type. - */ - availableFormats(type?: ClipboardType): string[]; - /** - * Returns whether the clipboard supports the format of specified data. - * Note: This API is experimental and could be removed in future. - * @returns Whether the clipboard has data in the specified format. - */ - has(format: string, type?: ClipboardType): boolean; - /** - * Reads the data in the clipboard of the specified format. - * Note: This API is experimental and could be removed in future. - */ - read(format: string, type?: ClipboardType): string | NativeImage; - /** - * Writes data to the clipboard. - */ - write(data: { text: string; bookmark?: string; } | { rtf: string; } | { html: string; } | { image: NativeImage; }, type?: ClipboardType): void; - /** - * @returns An Object containing title and url keys representing the bookmark in the clipboard. - * - * Note: This API is available on macOS and Windows. - */ - readBookmark(): Bookmark; - /** - * Writes the title and url into the clipboard as a bookmark. - * - * Note: This API is available on macOS and Windows. - */ - writeBookmark(title: string, url: string, type?: ClipboardType): void; - /** - * The text on the find pasteboard. This method uses synchronous IPC when called from the renderer process. - * The cached value is reread from the find pasteboard whenever the application is activated. - * - * Note: This API is available on macOS. - */ - readFindText(): string; - /** - * Writes the text into the find pasteboard as plain text. - * This method uses synchronous IPC when called from the renderer process. - * - * Note: This API is available on macOS. - */ - writeFindText(text: string): void; - } - - type ClipboardType = '' | 'selection'; - - interface Bookmark { - title: string; - url: string; - } - - // https://github.com/electron/electron/blob/master/docs/api/content-tracing.md - - /** - * The content-tracing module is used to collect tracing data generated by the underlying Chromium content module. - * This module does not include a web interface so you need to open chrome://tracing/ - * in a Chrome browser and load the generated file to view the result. - */ - interface ContentTracing { - /** - * Get a set of category groups. The category groups can change as new code paths are reached. - * - * @param callback Called once all child processes have acknowledged the getCategories request. - */ - getCategories(callback: (categoryGroups: string[]) => void): void; - /** - * Start recording on all processes. Recording begins immediately locally and asynchronously - * on child processes as soon as they receive the EnableRecording request. - * - * @param callback Called once all child processes have acknowledged the startRecording request. - */ - startRecording(options: ContentTracingOptions, callback: Function): void; - /** - * Stop recording on all processes. Child processes typically are caching trace data and - * only rarely flush and send trace data back to the main process. That is because it may - * be an expensive operation to send the trace data over IPC, and we would like to avoid - * much runtime overhead of tracing. So, to end tracing, we must asynchronously ask all - * child processes to flush any pending trace data. - * - * @param resultFilePath Trace data will be written into this file if it is not empty, - * or into a temporary file. - * @param callback Called once all child processes have acknowledged the stopRecording request. - */ - stopRecording(resultFilePath: string, callback: (filePath: string) => void): void; - /** - * Start monitoring on all processes. Monitoring begins immediately locally and asynchronously - * on child processes as soon as they receive the startMonitoring request. - * - * @param callback Called once all child processes have acked to the startMonitoring request. - */ - startMonitoring(options: ContentTracingOptions, callback: Function): void; - /** - * Stop monitoring on all processes. - * - * @param callback Called once all child processes have acknowledged the stopMonitoring request. - */ - stopMonitoring(callback: Function): void; - /** - * Get the current monitoring traced data. Child processes typically are caching trace data - * and only rarely flush and send trace data back to the main process. That is because it may - * be an expensive operation to send the trace data over IPC, and we would like to avoid much - * runtime overhead of tracing. So, to end tracing, we must asynchronously ask all child - * processes to flush any pending trace data. - * - * @param callback Called once all child processes have acknowledged the captureMonitoringSnapshot request. - */ - captureMonitoringSnapshot(resultFilePath: string, callback: (filePath: string) => void): void; - /** - * Get the maximum usage across processes of trace buffer as a percentage of the full state. - * - * @param callback Called when the TraceBufferUsage value is determined. - */ - getTraceBufferUsage(callback: Function): void; - /** - * @param callback Called every time the given event occurs on any process. - */ - setWatchEvent(categoryName: string, eventName: string, callback: Function): void; - /** - * Cancel the watch event. This may lead to a race condition with the watch event callback if tracing is enabled. - */ - cancelWatchEvent(): void; - } - - interface ContentTracingOptions { - /** - * Filter to control what category groups should be traced. - * A filter can have an optional - prefix to exclude category groups - * that contain a matching category. Having both included and excluded - * category patterns in the same list is not supported. - * - * Examples: - * test_MyTest* - * test_MyTest*,test_OtherStuff - * -excluded_category1,-excluded_category2 - */ - categoryFilter: string; - /** - * Controls what kind of tracing is enabled, it is a comma-delimited list. - * - * Possible options are: - * record-until-full - * record-continuously - * trace-to-console - * enable-sampling - * enable-systrace - * - * The first 3 options are trace recoding modes and hence mutually exclusive. - * If more than one trace recording modes appear in the traceOptions string, - * the last one takes precedence. If none of the trace recording modes are specified, - * recording mode is record-until-full. - * - * The trace option will first be reset to the default option (record_mode set - * to record-until-full, enable_sampling and enable_systrace set to false) - * before options parsed from traceOptions are applied on it. - */ - traceOptions: string; - } - - // https://github.com/electron/electron/blob/master/docs/api/crash-reporter.md - - /** - * The crash-reporter module enables sending your app's crash reports. - */ - interface CrashReporter { - /** - * You are required to call this method before using other crashReporter APIs. - * - * Note: On macOS, Electron uses a new crashpad client, which is different from breakpad - * on Windows and Linux. To enable the crash collection feature, you are required to call - * the crashReporter.start API to initialize crashpad in the main process and in each - * renderer process from which you wish to collect crash reports. - */ - start(options: CrashReporterStartOptions): void; - /** - * @returns The crash report. When there was no crash report - * sent or the crash reporter is not started, null will be returned. - */ - getLastCrashReport(): CrashReport; - /** - * @returns All uploaded crash reports. - */ - getUploadedReports(): CrashReport[]; - } - - interface CrashReporterStartOptions { - /** - * Default: app.getName() - */ - productName?: string; - companyName: string; - /** - * URL that crash reports would be sent to as POST. - */ - submitURL: string; - /** - * Send the crash report without user interaction. - * Default: true. - */ - autoSubmit?: boolean; - /** - * Default: false. - */ - ignoreSystemCrashHandler?: boolean; - /** - * An object you can define that will be sent along with the report. - * Only string properties are sent correctly, nested objects are not supported. - */ - extra?: {[prop: string]: string}; - } - - interface CrashReport { - id: string; - date: Date; - } - - // https://github.com/electron/electron/blob/master/docs/api/desktop-capturer.md - - /** - * The desktopCapturer module can be used to get available sources - * that can be used to be captured with getUserMedia. - */ - interface DesktopCapturer { - /** - * Starts a request to get all desktop sources. - * - * Note: There is no guarantee that the size of source.thumbnail is always - * the same as the thumnbailSize in options. It also depends on the scale of the screen or window. - */ - getSources(options: DesktopCapturerOptions, callback: (error: Error, sources: DesktopCapturerSource[]) => any): void; - } - - interface DesktopCapturerOptions { - /** - * The types of desktop sources to be captured. - */ - types?: ('screen' | 'window')[]; - /** - * The suggested size that thumbnail should be scaled. - * Default: {width: 150, height: 150} - */ - thumbnailSize?: Size; - } - - interface DesktopCapturerSource { - /** - * The id of the captured window or screen used in navigator.webkitGetUserMedia. - * The format looks like window:XX or screen:XX where XX is a random generated number. - */ - id: string; - /** - * The described name of the capturing screen or window. - * If the source is a screen, the name will be Entire Screen or Screen ; - * if it is a window, the name will be the window’s title. - */ - name: string; - /** - * A thumbnail image. - */ - thumbnail: NativeImage; - } - - // https://github.com/electron/electron/blob/master/docs/api/dialog.md - - /** - * The dialog module provides APIs to show native system dialogs, such as opening files or alerting, - * so web applications can deliver the same user experience as native applications. - */ - interface Dialog { - /** - * Note: On Windows and Linux an open dialog can not be both a file selector and a directory selector, - * so if you set properties to ['openFile', 'openDirectory'] on these platforms, a directory selector will be shown. - * - * @param callback If supplied, the API call will be asynchronous. - * @returns On success, returns an array of file paths chosen by the user, - * otherwise returns undefined. - */ - showOpenDialog(browserWindow: BrowserWindow, options: OpenDialogOptions, callback?: (fileNames: string[]) => void): string[]; - /** - * Note: On Windows and Linux an open dialog can not be both a file selector and a directory selector, - * so if you set properties to ['openFile', 'openDirectory'] on these platforms, a directory selector will be shown. - * - * @param callback If supplied, the API call will be asynchronous. - * @returns On success, returns an array of file paths chosen by the user, - * otherwise returns undefined. - */ - showOpenDialog(options: OpenDialogOptions, callback?: (fileNames: string[]) => void): string[]; - /** - * @param callback If supplied, the API call will be asynchronous. - * @returns On success, returns the path of file chosen by the user, otherwise - * returns undefined. - */ - showSaveDialog(browserWindow: BrowserWindow, options: SaveDialogOptions, callback?: (fileName: string) => void): string; - /** - * @param callback If supplied, the API call will be asynchronous. - * @returns On success, returns the path of file chosen by the user, otherwise - * returns undefined. - */ - showSaveDialog(options: SaveDialogOptions, callback?: (fileName: string) => void): string; - /** - * Shows a message box. It will block until the message box is closed. - * @param callback If supplied, the API call will be asynchronous. - * @returns The index of the clicked button. - */ - showMessageBox(browserWindow: BrowserWindow, options: ShowMessageBoxOptions, callback?: (response: number) => void): number; - /** - * Shows a message box. It will block until the message box is closed. - * @param callback If supplied, the API call will be asynchronous. - * @returns The index of the clicked button. - */ - showMessageBox(options: ShowMessageBoxOptions, callback?: (response: number) => void): number; - /** - * Displays a modal dialog that shows an error message. - * - * This API can be called safely before the ready event the app module emits, - * it is usually used to report errors in early stage of startup. - * If called before the app readyevent on Linux, the message will be emitted to stderr, - * and no GUI dialog will appear. - */ - showErrorBox(title: string, content: string): void; - } - - interface OpenDialogOptions { - title?: string; - defaultPath?: string; - /** - * Custom label for the confirmation button, when left empty the default label will be used. - */ - buttonLabel?: string; - /** - * File types that can be displayed or selected. - */ - filters?: { - name: string; - /** - * Extensions without wildcards or dots (e.g. 'png' is good but '.png' and '*.png' are bad). - * To show all files, use the '*' wildcard (no other wildcard is supported). - */ - extensions: string[]; - }[]; - /** - * Contains which features the dialog should use. - */ - properties?: ('openFile' | 'openDirectory' | 'multiSelections' | 'createDirectory' | 'showHiddenFiles')[]; - } - - interface SaveDialogOptions { - title?: string; - defaultPath?: string; - /** - * Custom label for the confirmation button, when left empty the default label will be used. - */ - buttonLabel?: string; - /** - * File types that can be displayed, see dialog.showOpenDialog for an example. - */ - filters?: { - name: string; - extensions: string[]; - }[]; - } - - interface ShowMessageBoxOptions { - /** - * On Windows, "question" displays the same icon as "info", unless you set an icon using the "icon" option. - */ - type?: 'none' | 'info' | 'error' | 'question' | 'warning'; - /** - * Texts for buttons. On Windows, an empty array will result in one button labeled "OK". - */ - buttons?: string[]; - /** - * Index of the button in the buttons array which will be selected by default when the message box opens. - */ - defaultId?: number; - /** - * Title of the message box (some platforms will not show it). - */ - title?: string; - /** - * Contents of the message box. - */ - message?: string; - /** - * Extra information of the message. - */ - detail?: string; - icon?: NativeImage; - /** - * The value will be returned when user cancels the dialog instead of clicking the buttons of the dialog. - * By default it is the index of the buttons that have "cancel" or "no" as label, - * or 0 if there is no such buttons. On macOS and Windows the index of "Cancel" button - * will always be used as cancelId, not matter whether it is already specified. - */ - cancelId?: number; - /** - * On Windows Electron will try to figure out which one of the buttons are common buttons - * (like "Cancel" or "Yes"), and show the others as command links in the dialog. - * This can make the dialog appear in the style of modern Windows apps. - * If you don’t like this behavior, you can set noLink to true. - */ - noLink?: boolean; - } - - // https://github.com/electron/electron/blob/master/docs/api/download-item.md - - /** - * DownloadItem represents a download item in Electron. - */ - interface DownloadItem extends NodeJS.EventEmitter { - /** - * Emitted when the download has been updated and is not done. - */ - on(event: 'updated', listener: (event: Event, state: 'progressing' | 'interrupted') => void): this; - /** - * Emits when the download is in a terminal state. This includes a completed download, - * a cancelled download (via downloadItem.cancel()), and interrupted download that can’t be resumed. - */ - on(event: 'done', listener: (event: Event, state: 'completed' | 'cancelled' | 'interrupted') => void): this; - on(event: string, listener: Function): this; - /** - * Set the save file path of the download item. - * Note: The API is only available in session’s will-download callback function. - * If user doesn’t set the save path via the API, Electron will use the original - * routine to determine the save path (Usually prompts a save dialog). - */ - setSavePath(path: string): void; - /** - * @returns The save path of the download item. - * This will be either the path set via downloadItem.setSavePath(path) or the path selected from the shown save dialog. - */ - getSavePath(): string; - /** - * Pauses the download. - */ - pause(): void; - /** - * @returns Whether the download is paused. - */ - isPaused(): boolean; - /** - * Resumes the download that has been paused. - */ - resume(): void; - /** - * @returns Whether the download can resume. - */ - canResume(): boolean; - /** - * Cancels the download operation. - */ - cancel(): void; - /** - * @returns The origin url where the item is downloaded from. - */ - getURL(): string; - /** - * @returns The mime type. - */ - getMimeType(): string; - /** - * @returns Whether the download has user gesture. - */ - hasUserGesture(): boolean; - /** - * @returns The file name of the download item. - * Note: The file name is not always the same as the actual one saved in local disk. - * If user changes the file name in a prompted download saving dialog, - * the actual name of saved file will be different. - */ - getFilename(): string; - /** - * @returns The total size in bytes of the download item. If the size is unknown, it returns 0. - */ - getTotalBytes(): number; - /** - * @returns The received bytes of the download item. - */ - getReceivedBytes(): number; - /** - * @returns The Content-Disposition field from the response header. - */ - getContentDisposition(): string; - /** - * @returns The current state. - */ - getState(): 'progressing' | 'completed' | 'cancelled' | 'interrupted'; - } - - // https://github.com/electron/electron/blob/master/docs/api/global-shortcut.md - - /** - * The globalShortcut module can register/unregister a global keyboard shortcut - * with the operating system so that you can customize the operations for various shortcuts. - * Note: The shortcut is global; it will work even if the app does not have the keyboard focus. - * You should not use this module until the ready event of the app module is emitted. - */ - interface GlobalShortcut { - /** - * Registers a global shortcut of accelerator. - * @param accelerator Represents a keyboard shortcut. It can contain modifiers - * and key codes, combined by the "+" character. - * @param callback Called when the registered shortcut is pressed by the user. - */ - register(accelerator: string, callback: Function): void; - /** - * @param accelerator Represents a keyboard shortcut. It can contain modifiers - * and key codes, combined by the "+" character. - * @returns Whether the accelerator is registered. - */ - isRegistered(accelerator: string): boolean; - /** - * Unregisters the global shortcut of keycode. - * @param accelerator Represents a keyboard shortcut. It can contain modifiers - * and key codes, combined by the "+" character. - */ - unregister(accelerator: string): void; - /** - * Unregisters all the global shortcuts. - */ - unregisterAll(): void; - } - - // https://github.com/electron/electron/blob/master/docs/api/ipc-main.md - - /** - * The ipcMain module handles asynchronous and synchronous messages - * sent from a renderer process (web page). - * Messages sent from a renderer will be emitted to this module. - */ - interface IpcMain extends NodeJS.EventEmitter { - addListener(channel: string, listener: IpcMainEventListener): this; - on(channel: string, listener: IpcMainEventListener): this; - once(channel: string, listener: IpcMainEventListener): this; - removeListener(channel: string, listener: IpcMainEventListener): this; - removeAllListeners(channel?: string): this; - } - - type IpcMainEventListener = (event: IpcMainEvent, ...args: any[]) => void; - - interface IpcMainEvent { - /** - * Set this to the value to be returned in a synchronous message. - */ - returnValue?: any; - /** - * Returns the webContents that sent the message, you can call sender.send - * to reply to the asynchronous message. - */ - sender: WebContents; - } - - // https://github.com/electron/electron/blob/master/docs/api/ipc-renderer.md - - /** - * The ipcRenderer module provides a few methods so you can send synchronous - * and asynchronous messages from the render process (web page) to the main process. - * You can also receive replies from the main process. - */ - interface IpcRenderer extends NodeJS.EventEmitter { - addListener(channel: string, listener: IpcRendererEventListener): this; - on(channel: string, listener: IpcRendererEventListener): this; - once(channel: string, listener: IpcRendererEventListener): this; - removeListener(channel: string, listener: IpcRendererEventListener): this; - removeAllListeners(channel?: string): this; - /** - * Send ...args to the renderer via channel in asynchronous message, the main - * process can handle it by listening to the channel event of ipc module. - */ - send(channel: string, ...args: any[]): void; - /** - * Send ...args to the renderer via channel in synchronous message, and returns - * the result sent from main process. The main process can handle it by listening - * to the channel event of ipc module, and returns by setting event.returnValue. - * Note: Usually developers should never use this API, since sending synchronous - * message would block the whole renderer process. - * @returns The result sent from the main process. - */ - sendSync(channel: string, ...args: any[]): any; - /** - * Like ipc.send but the message will be sent to the host page instead of the main process. - * This is mainly used by the page in to communicate with host page. - */ - sendToHost(channel: string, ...args: any[]): void; - } - - type IpcRendererEventListener = (event: IpcRendererEvent, ...args: any[]) => void; - - interface IpcRendererEvent { - /** - * You can call sender.send to reply to the asynchronous message. - */ - sender: IpcRenderer; - } - - // https://github.com/electron/electron/blob/master/docs/api/menu-item.md - // https://github.com/electron/electron/blob/master/docs/api/accelerator.md - - /** - * The MenuItem allows you to add items to an application or context menu. - */ - class MenuItem { - /** - * Create a new menu item. - */ - constructor(options: MenuItemOptions); - - click: (menuItem: MenuItem, browserWindow: BrowserWindow, event: Event) => void; - /** - * Read-only property. - */ - type: MenuItemType; - /** - * Read-only property. - */ - role: MenuItemRole | MenuItemRoleMac; - /** - * Read-only property. - */ - accelerator: string; - /** - * Read-only property. - */ - icon: NativeImage | string; - /** - * Read-only property. - */ - submenu: Menu | MenuItemOptions[]; - - label: string; - sublabel: string; - enabled: boolean; - visible: boolean; - checked: boolean; - } - - type MenuItemType = 'normal' | 'separator' | 'submenu' | 'checkbox' | 'radio'; - type MenuItemRole = 'undo' | 'redo' | 'cut' | 'copy' | 'paste' | 'pasteandmatchstyle' | 'selectall' | 'delete' | 'minimize' | 'close' | 'quit' | 'togglefullscreen' | 'resetzoom' | 'zoomin' | 'zoomout' | 'reload' | 'toggledevtools'; - type MenuItemRoleMac = 'about' | 'hide' | 'hideothers' | 'unhide' | 'startspeaking' | 'stopspeaking' | 'front' | 'zoom' | 'window' | 'help' | 'services'; - - interface MenuItemOptions { - /** - * Callback when the menu item is clicked. - */ - click?: (menuItem: MenuItem, browserWindow: BrowserWindow) => void; - /** - * Can be normal, separator, submenu, checkbox or radio. - */ - type?: MenuItemType; - label?: string; - sublabel?: string; - /** - * An accelerator is string that represents a keyboard shortcut, it can contain - * multiple modifiers and key codes, combined by the + character. - * - * Examples: - * CommandOrControl+A - * CommandOrControl+Shift+Z - * - * Platform notice: - * On Linux and Windows, the Command key would not have any effect, - * you can use CommandOrControl which represents Command on macOS and Control on - * Linux and Windows to define some accelerators. - * - * Use Alt instead of Option. The Option key only exists on macOS, whereas - * the Alt key is available on all platforms. - * - * The Super key is mapped to the Windows key on Windows and Linux and Cmd on macOS. - * - * Available modifiers: - * Command (or Cmd for short) - * Control (or Ctrl for short) - * CommandOrControl (or CmdOrCtrl for short) - * Alt - * Option - * AltGr - * Shift - * Super - * - * Available key codes: - * 0 to 9 - * A to Z - * F1 to F24 - * Punctuations like ~, !, @, #, $, etc. - * Plus - * Space - * Tab - * Backspace - * Delete - * Insert - * Return (or Enter as alias) - * Up, Down, Left and Right - * Home and End - * PageUp and PageDown - * Escape (or Esc for short) - * VolumeUp, VolumeDown and VolumeMute - * MediaNextTrack, MediaPreviousTrack, MediaStop and MediaPlayPause - * PrintScreen - */ - accelerator?: string; - /** - * In Electron for the APIs that take images, you can pass either file paths - * or NativeImage instances. When passing null, an empty image will be used. - */ - icon?: NativeImage|string; - /** - * If false, the menu item will be greyed out and unclickable. - */ - enabled?: boolean; - /** - * If false, the menu item will be entirely hidden. - */ - visible?: boolean; - /** - * Should only be specified for 'checkbox' or 'radio' type menu items. - */ - checked?: boolean; - /** - * Should be specified for submenu type menu item, when it's specified the - * type: 'submenu' can be omitted for the menu item - */ - submenu?: Menu|MenuItemOptions[]; - /** - * Unique within a single menu. If defined then it can be used as a reference - * to this item by the position attribute. - */ - id?: string; - /** - * This field allows fine-grained definition of the specific location within - * a given menu. - */ - position?: string; - /** - * Define the action of the menu item, when specified the click property will be ignored - */ - role?: MenuItemRole | MenuItemRoleMac; - } - - // https://github.com/electron/electron/blob/master/docs/api/menu.md - - /** - * The Menu class is used to create native menus that can be used as application - * menus and context menus. This module is a main process module which can be used - * in a render process via the remote module. - * - * Each menu consists of multiple menu items, and each menu item can have a submenu. - */ - class Menu extends NodeJS.EventEmitter { - /** - * Creates a new menu. - */ - constructor(); - /** - * Sets menu as the application menu on macOS. On Windows and Linux, the menu - * will be set as each window's top menu. - */ - static setApplicationMenu(menu: Menu): void; - /** - * @returns The application menu if set, or null if not set. - */ - static getApplicationMenu(): Menu; - /** - * Sends the action to the first responder of application. - * This is used for emulating default Cocoa menu behaviors, - * usually you would just use the role property of MenuItem. - * - * Note: This method is macOS only. - */ - static sendActionToFirstResponder(action: string): void; - /** - * @param template Generally, just an array of options for constructing MenuItem. - * You can also attach other fields to element of the template, and they will - * become properties of the constructed menu items. - */ - static buildFromTemplate(template: MenuItemOptions[]): Menu; - /** - * Pops up this menu as a context menu in the browserWindow. You can optionally - * provide a (x,y) coordinate to place the menu at, otherwise it will be placed - * at the current mouse cursor position. - * @param x Horizontal coordinate where the menu will be placed. - * @param y Vertical coordinate where the menu will be placed. - */ - popup(browserWindow?: BrowserWindow, x?: number, y?: number): void; - /** - * Appends the menuItem to the menu. - */ - append(menuItem: MenuItem): void; - /** - * Inserts the menuItem to the pos position of the menu. - */ - insert(position: number, menuItem: MenuItem): void; - /** - * @returns an array containing the menu’s items. - */ - items: MenuItem[]; - } - - // https://github.com/electron/electron/blob/master/docs/api/native-image.md - - /** - * This class is used to represent an image. - */ - class NativeImage { - /** - * Creates an empty NativeImage instance. - */ - static createEmpty(): NativeImage; - /** - * Creates a new NativeImage instance from file located at path. - * This method returns an empty image if the path does not exist, cannot be read, or is not a valid image. - */ - static createFromPath(path: string): NativeImage; - /** - * Creates a new NativeImage instance from buffer. - * @param scaleFactor 1.0 by default. - */ - static createFromBuffer(buffer: Buffer, scaleFactor?: number): NativeImage; - /** - * Creates a new NativeImage instance from dataURL - */ - static createFromDataURL(dataURL: string): NativeImage; - /** - * @returns Buffer that contains the image's PNG encoded data. - */ - toPNG(): Buffer; - /** - * @returns Buffer that contains the image's JPEG encoded data. - */ - toJPEG(quality: number): Buffer; - /** - * @returns Buffer that contains a copy of the image's raw bitmap pixel data. - */ - toBitmap(): Buffer; - /** - * @returns Buffer that contains the image's raw bitmap pixel data. - * - * The difference between getBitmap() and toBitmap() is, getBitmap() does not copy the bitmap data, - * so you have to use the returned Buffer immediately in current event loop tick, - * otherwise the data might be changed or destroyed. - */ - getBitmap(): Buffer; - /** - * @returns The data URL of the image. - */ - toDataURL(): string; - /** - * The native type of the handle is NSImage* on macOS. - * Note: This is only implemented on macOS. - * @returns The platform-specific handle of the image as Buffer. - */ - getNativeHandle(): Buffer; - /** - * @returns Whether the image is empty. - */ - isEmpty(): boolean; - /** - * @returns The size of the image. - */ - getSize(): Size; - /** - * Marks the image as template image. - */ - setTemplateImage(option: boolean): void; - /** - * Returns a boolean whether the image is a template image. - */ - isTemplateImage(): boolean; - } - - // https://github.com/electron/electron/blob/master/docs/api/net.md - - /** - * The net module is a client-side API for issuing HTTP(S) requests. - * It is similar to the HTTP and HTTPS modules of Node.js but uses Chromium’s native - * networking library instead of the Node.js implementation, offering better support - * for web proxies. - * The following is a non-exhaustive list of why you may consider using the net module - * instead of the native Node.js modules: - * - Automatic management of system proxy configuration, support of the wpad protocol - * and proxy pac configuration files. - * - Automatic tunneling of HTTPS requests. - * - Support for authenticating proxies using basic, digest, NTLM, Kerberos or negotiate - * authentication schemes. - * - Support for traffic monitoring proxies: Fiddler-like proxies used for access control - * and monitoring. - * - * The net module API has been specifically designed to mimic, as closely as possible, - * the familiar Node.js API. The API components including classes, methods, - * properties and event names are similar to those commonly used in Node.js. - * - * The net API can be used only after the application emits the ready event. - * Trying to use the module before the ready event will throw an error. - */ - interface Net extends NodeJS.EventEmitter { - /** - * @param options The ClientRequest constructor options. - * @param callback A one time listener for the response event. - * - * @returns a ClientRequest instance using the provided options which are directly - * forwarded to the ClientRequest constructor. - */ - request(options: string | RequestOptions, callback?: (response: IncomingMessage) => void): ClientRequest; - } - - /** - * The RequestOptions interface allows to define various options for an HTTP request. - */ - interface RequestOptions { - /** - * The HTTP request method. Defaults to the GET method. - */ - method?: string; - /** - * The request URL. Must be provided in the absolute form with the protocol - * scheme specified as http or https. - */ - url?: string; - /** - * The Session instance with which the request is associated. - */ - session?: Session; - /** - * The name of the partition with which the request is associated. - * Defaults to the empty string. The session option prevails on partition. - * Thus if a session is explicitly specified, partition is ignored. - */ - partition?: string; - /** - * The protocol scheme in the form ‘scheme:’. Currently supported values are ‘http:’ or ‘https:’. - * Defaults to ‘http:’. - */ - protocol?: 'http:' | 'https:'; - /** - * The server host provided as a concatenation of the hostname and the port number ‘hostname:port’. - */ - host?: string; - /** - * The server host name. - */ - hostname?: string; - /** - * The server’s listening port number. - */ - port?: number; - /** - * The path part of the request URL. - */ - path?: string; - /** - * A map specifying extra HTTP header name/value. - */ - headers?: { [key: string]: any }; - } - - /** - * The ClientRequest class represents an HTTP request. - */ - class ClientRequest extends NodeJS.EventEmitter { - /** - * Emitted when an HTTP response is received for the request. - */ - on(event: 'response', listener: (response: IncomingMessage) => void): this; - /** - * Emitted when an authenticating proxy is asking for user credentials. - * The callback function is expected to be called back with user credentials. - * Providing empty credentials will cancel the request and report an authentication - * error on the response object. - */ - on(event: 'login', listener: (authInfo: LoginAuthInfo, callback: (username?: string, password?: string) => void) => void): this; - /** - * Emitted just after the last chunk of the request’s data has been written into - * the request object. - */ - on(event: 'finish', listener: () => void): this; - /** - * Emitted when the request is aborted. The abort event will not be fired if the - * request is already closed. - */ - on(event: 'abort', listener: () => void): this; - /** - * Emitted when the net module fails to issue a network request. - * Typically when the request object emits an error event, a close event will - * subsequently follow and no response object will be provided. - */ - on(event: 'error', listener: (error: Error) => void): this; - /** - * Emitted as the last event in the HTTP request-response transaction. - * The close event indicates that no more events will be emitted on either the - * request or response objects. - */ - on(event: 'close', listener: () => void): this; - on(event: string, listener: Function): this; - /** - * A Boolean specifying whether the request will use HTTP chunked transfer encoding or not. - * Defaults to false. The property is readable and writable, however it can be set only before - * the first write operation as the HTTP headers are not yet put on the wire. - * Trying to set the chunkedEncoding property after the first write will throw an error. - * - * Using chunked encoding is strongly recommended if you need to send a large request - * body as data will be streamed in small chunks instead of being internally buffered - * inside Electron process memory. - */ - chunkedEncoding: boolean; - /** - * @param options If options is a String, it is interpreted as the request URL. - * If it is an object, it is expected to be a RequestOptions. - * @param callback A one time listener for the response event. - */ - constructor(options: string | RequestOptions, callback?: (response: IncomingMessage) => void); - /** - * Adds an extra HTTP header. The header name will issued as it is without lowercasing. - * It can be called only before first write. Calling this method after the first write - * will throw an error. - * @param name An extra HTTP header name. - * @param value An extra HTTP header value. - */ - setHeader(name: string, value: string): void; - /** - * @param name Specify an extra header name. - * @returns The value of a previously set extra header name. - */ - getHeader(name: string): string; - /** - * Removes a previously set extra header name. This method can be called only before first write. - * Trying to call it after the first write will throw an error. - * @param name Specify an extra header name. - */ - removeHeader(name: string): void; - /** - * Adds a chunk of data to the request body. The first write operation may cause the - * request headers to be issued on the wire. - * After the first write operation, it is not allowed to add or remove a custom header. - * @param chunk A chunk of the request body’s data. If it is a string, it is converted - * into a Buffer using the specified encoding. - * @param encoding Used to convert string chunks into Buffer objects. Defaults to ‘utf-8’. - * @param callback Called after the write operation ends. - */ - write(chunk: string | Buffer, encoding?: string, callback?: Function): boolean; - /** - * Sends the last chunk of the request data. Subsequent write or end operations will not be allowed. - * The finish event is emitted just after the end operation. - * @param chunk A chunk of the request body’s data. If it is a string, it is converted into - * a Buffer using the specified encoding. - * @param encoding Used to convert string chunks into Buffer objects. Defaults to ‘utf-8’. - * @param callback Called after the write operation ends. - * - */ - end(chunk?: string | Buffer, encoding?: string, callback?: Function): boolean; - /** - * Cancels an ongoing HTTP transaction. If the request has already emitted the close event, - * the abort operation will have no effect. - * Otherwise an ongoing event will emit abort and close events. - * Additionally, if there is an ongoing response object,it will emit the aborted event. - */ - abort(): void - } - - /** - * An IncomingMessage represents an HTTP response. - */ - interface IncomingMessage extends NodeJS.ReadableStream { - /** - * The data event is the usual method of transferring response data into applicative code. - */ - on(event: 'data', listener: (chunk: Buffer) => void): this; - /** - * Indicates that response body has ended. - */ - on(event: 'end', listener: () => void): this; - /** - * Emitted when a request has been canceled during an ongoing HTTP transaction. - */ - on(event: 'aborted', listener: () => void): this; - /** - * Emitted when an error was encountered while streaming response data events. - * For instance, if the server closes the underlying while the response is still - * streaming, an error event will be emitted on the response object and a close - * event will subsequently follow on the request object. - */ - on(event: 'error', listener: (error: Error) => void): this; - on(event: string, listener: Function): this; - /** - * An Integer indicating the HTTP response status code. - */ - statusCode: number; - /** - * A String representing the HTTP status message. - */ - statusMessage: string; - /** - * An object representing the response HTTP headers. The headers object is formatted as follows: - * - All header names are lowercased. - * - Each header name produces an array-valued property on the headers object. - * - Each header value is pushed into the array associated with its header name. - */ - headers: { - [key: string]: string[] - }; - /** - * A string indicating the HTTP protocol version number. Typical values are ‘1.0’ or ‘1.1’. - */ - httpVersion: string; - /** - * An integer-valued read-only property that returns the HTTP major version number. - */ - httpVersionMajor: number; - /** - * An integer-valued read-only property that returns the HTTP minor version number. - */ - httpVersionMinor: number; - } - - // https://github.com/electron/electron/blob/master/docs/api/power-monitor.md - - /** - * The power-monitor module is used to monitor power state changes. - * You should not use this module until the ready event of the app module is emitted. - */ - interface PowerMonitor extends NodeJS.EventEmitter { - /** - * Emitted when the system is suspending. - */ - on(event: 'suspend', listener: Function): this; - /** - * Emitted when system is resuming. - */ - on(event: 'resume', listener: Function): this; - /** - * Emitted when the system changes to AC power. - */ - on(event: 'on-ac', listener: Function): this; - /** - * Emitted when system changes to battery power. - */ - on(event: 'on-battery', listener: Function): this; - on(event: string, listener: Function): this; - } - - // https://github.com/electron/electron/blob/master/docs/api/power-save-blocker.md - - /** - * The powerSaveBlocker module is used to block the system from entering - * low-power (sleep) mode and thus allowing the app to keep the system and screen active. - */ - interface PowerSaveBlocker { - /** - * Starts preventing the system from entering lower-power mode. - * @returns The blocker ID that is assigned to this power blocker. - * Note: prevent-display-sleep has higher has precedence over prevent-app-suspension. - */ - start(type: 'prevent-app-suspension' | 'prevent-display-sleep'): number; - /** - * @param id The power save blocker id returned by powerSaveBlocker.start. - * Stops the specified power save blocker. - */ - stop(id: number): void; - /** - * @param id The power save blocker id returned by powerSaveBlocker.start. - * @returns Whether the corresponding powerSaveBlocker has started. - */ - isStarted(id: number): boolean; - } - - // https://github.com/electron/electron/blob/master/docs/api/protocol.md - - /** - * The protocol module can register a custom protocol or intercept an existing protocol. - */ - interface Protocol { - /** - * Registers custom schemes as standard schemes. - */ - registerStandardSchemes(schemes: string[]): void; - /** - * Registers custom schemes to handle service workers. - */ - registerServiceWorkerSchemes(schemes: string[]): void; - /** - * Registers a protocol of scheme that will send the file as a response. - */ - registerFileProtocol(scheme: string, handler: FileProtocolHandler, completion?: (error: Error) => void): void; - /** - * Registers a protocol of scheme that will send a Buffer as a response. - */ - registerBufferProtocol(scheme: string, handler: BufferProtocolHandler, completion?: (error: Error) => void): void; - /** - * Registers a protocol of scheme that will send a String as a response. - */ - registerStringProtocol(scheme: string, handler: StringProtocolHandler, completion?: (error: Error) => void): void; - /** - * Registers a protocol of scheme that will send an HTTP request as a response. - */ - registerHttpProtocol(scheme: string, handler: HttpProtocolHandler, completion?: (error: Error) => void): void; - /** - * Unregisters the custom protocol of scheme. - */ - unregisterProtocol(scheme: string, completion?: (error: Error) => void): void; - /** - * The callback will be called with a boolean that indicates whether there is already a handler for scheme. - */ - isProtocolHandled(scheme: string, callback: (handled: boolean) => void): void; - /** - * Intercepts scheme protocol and uses handler as the protocol’s new handler which sends a file as a response. - */ - interceptFileProtocol(scheme: string, handler: FileProtocolHandler, completion?: (error: Error) => void): void; - /** - * Intercepts scheme protocol and uses handler as the protocol’s new handler which sends a Buffer as a response. - */ - interceptBufferProtocol(scheme: string, handler: BufferProtocolHandler, completion?: (error: Error) => void): void; - /** - * Intercepts scheme protocol and uses handler as the protocol’s new handler which sends a String as a response. - */ - interceptStringProtocol(scheme: string, handler: StringProtocolHandler, completion?: (error: Error) => void): void; - /** - * Intercepts scheme protocol and uses handler as the protocol’s new handler which sends a new HTTP request as a response. - */ - interceptHttpProtocol(scheme: string, handler: HttpProtocolHandler, completion?: (error: Error) => void): void; - /** - * Remove the interceptor installed for scheme and restore its original handler. - */ - uninterceptProtocol(scheme: string, completion?: (error: Error) => void): void; - } - - type FileProtocolHandler = (request: ProtocolRequest, callback: FileProtocolCallback) => void; - type BufferProtocolHandler = (request: ProtocolRequest, callback: BufferProtocolCallback) => void; - type StringProtocolHandler = (request: ProtocolRequest, callback: StringProtocolCallback) => void; - type HttpProtocolHandler = (request: ProtocolRequest, callback: HttpProtocolCallback) => void; - - interface ProtocolRequest { - url: string; - referrer: string; - method: string; - uploadData?: { - /** - * Content being sent. - */ - bytes: Buffer, - /** - * Path of file being uploaded. - */ - file: string, - /** - * UUID of blob data. Use session.getBlobData method to retrieve the data. - */ - blobUUID: string; - }[]; - } - - interface ProtocolCallback { - (error: number): void; - (obj: { - error: number - }): void; - (): void; - } - - interface FileProtocolCallback extends ProtocolCallback { - (filePath: string): void; - (obj: { - path: string - }): void; - } - - interface BufferProtocolCallback extends ProtocolCallback { - (buffer: Buffer): void; - (obj: { - data: Buffer, - mimeType: string, - charset?: string - }): void; - } - - interface StringProtocolCallback extends ProtocolCallback { - (str: string): void; - (obj: { - data: string, - mimeType: string, - charset?: string - }): void; - } - - interface HttpProtocolCallback extends ProtocolCallback { - (redirectRequest: { - url: string; - method: string; - session?: Object; - uploadData?: { - contentType: string; - data: string; - }; - }): void; - } - - // https://github.com/electron/electron/blob/master/docs/api/remote.md - - /** - * The remote module provides a simple way to do inter-process communication (IPC) - * between the renderer process (web page) and the main process. - */ - interface Remote extends CommonElectron { - /** - * @returns The object returned by require(module) in the main process. - */ - require(module: string): any; - /** - * @returns The BrowserWindow object which this web page belongs to. - */ - getCurrentWindow(): BrowserWindow; - /** - * @returns The WebContents object of this web page. - */ - getCurrentWebContents(): WebContents; - /** - * @returns The global variable of name (e.g. global[name]) in the main process. - */ - getGlobal(name: string): any; - /** - * Returns the process object in the main process. This is the same as - * remote.getGlobal('process'), but gets cached. - */ - process: NodeJS.Process; - } - - // https://github.com/electron/electron/blob/master/docs/api/screen.md - - /** - * The Display object represents a physical display connected to the system. - * A fake Display may exist on a headless system, or a Display may correspond to a remote, virtual display. - */ - interface Display { - /** - * Unique identifier associated with the display. - */ - id: number; - bounds: Rectangle; - workArea: Rectangle; - size: Size; - workAreaSize: Size; - /** - * Output device’s pixel scale factor. - */ - scaleFactor: number; - /** - * Can be 0, 90, 180, 270, represents screen rotation in clock-wise degrees. - */ - rotation: number; - touchSupport: 'available' | 'unavailable' | 'unknown'; - } - - type DisplayMetrics = 'bounds' | 'workArea' | 'scaleFactor' | 'rotation'; - - /** - * The screen module retrieves information about screen size, displays, cursor position, etc. - * You can not use this module until the ready event of the app module is emitted. - */ - interface Screen extends NodeJS.EventEmitter { - /** - * Emitted when newDisplay has been added. - */ - on(event: 'display-added', listener: (event: Event, newDisplay: Display) => void): this; - /** - * Emitted when oldDisplay has been removed. - */ - on(event: 'display-removed', listener: (event: Event, oldDisplay: Display) => void): this; - /** - * Emitted when one or more metrics change in a display. - */ - on(event: 'display-metrics-changed', listener: (event: Event, display: Display, changedMetrics: DisplayMetrics[]) => void): this; - on(event: string, listener: Function): this; - /** - * @returns The current absolute position of the mouse pointer. - */ - getCursorScreenPoint(): Point; - /** - * @returns The primary display. - */ - getPrimaryDisplay(): Display; - /** - * @returns An array of displays that are currently available. - */ - getAllDisplays(): Display[]; - /** - * @returns The display nearest the specified point. - */ - getDisplayNearestPoint(point: Point): Display; - /** - * @returns The display that most closely intersects the provided bounds. - */ - getDisplayMatching(rect: Rectangle): Display; - } - - // https://github.com/electron/electron/blob/master/docs/api/session.md - - /** - * The session module can be used to create new Session objects. - * You can also access the session of existing pages by using - * the session property of webContents which is a property of BrowserWindow. - */ - class Session extends NodeJS.EventEmitter { - /** - * @returns a new Session instance from partition string. - */ - static fromPartition(partition: string, options?: FromPartitionOptions): Session; - /** - * @returns the default session object of the app. - */ - static defaultSession: Session; - /** - * Emitted when Electron is about to download item in webContents. - * Calling event.preventDefault() will cancel the download - * and item will not be available from next tick of the process. - */ - on(event: 'will-download', listener: (event: Event, item: DownloadItem, webContents: WebContents) => void): this; - on(event: string, listener: Function): this; - /** - * The cookies gives you ability to query and modify cookies. - */ - cookies: SessionCookies; - /** - * @returns the session’s current cache size. - */ - getCacheSize(callback: (size: number) => void): void; - /** - * Clears the session’s HTTP cache. - */ - clearCache(callback: Function): void; - /** - * Clears the data of web storages. - */ - clearStorageData(callback: Function): void; - /** - * Clears the data of web storages. - */ - clearStorageData(options: ClearStorageDataOptions, callback: Function): void; - /** - * Writes any unwritten DOMStorage data to disk. - */ - flushStorageData(): void; - /** - * Sets the proxy settings. - */ - setProxy(config: ProxyConfig, callback: Function): void; - /** - * Resolves the proxy information for url. - */ - resolveProxy(url: URL, callback: (proxy: string) => void): void; - /** - * Sets download saving directory. - * By default, the download directory will be the Downloads under the respective app folder. - */ - setDownloadPath(path: string): void; - /** - * Emulates network with the given configuration for the session. - */ - enableNetworkEmulation(options: NetworkEmulationOptions): void; - /** - * Disables any network emulation already active for the session. - * Resets to the original network configuration. - */ - disableNetworkEmulation(): void; - /** - * Sets the certificate verify proc for session, the proc will be called - * whenever a server certificate verification is requested. - * - * Calling setCertificateVerifyProc(null) will revert back to default certificate verify proc. - */ - setCertificateVerifyProc(proc: ((hostname: string, cert: Certificate, callback: (accepted: boolean) => void) => void) | null): void; - /** - * Sets the handler which can be used to respond to permission requests for the session. - */ - setPermissionRequestHandler(handler: (webContents: WebContents, permission: Permission, callback: (allow: boolean) => void) => void): void; - /** - * Clears the host resolver cache. - */ - clearHostResolverCache(callback: Function): void; - /** - * Dynamically sets whether to always send credentials for HTTP NTLM or Negotiate authentication. - * @param domains Comma-seperated list of servers for which integrated authentication is enabled. - */ - allowNTLMCredentialsForDomains(domains: string): void; - /** - * Overrides the userAgent and acceptLanguages for this session. - * The acceptLanguages must a comma separated ordered list of language codes, for example "en-US,fr,de,ko,zh-CN,ja". - * This doesn't affect existing WebContents, and each WebContents can use webContents.setUserAgent to override the session-wide user agent. - */ - setUserAgent(userAgent: string, acceptLanguages?: string): void; - /** - * @returns The user agent for this session. - */ - getUserAgent(): string; - /** - * Returns the blob data associated with the identifier. - */ - getBlobData(identifier: string, callback: (result: Buffer) => void): void; - /** - * The webRequest API set allows to intercept and modify contents of a request at various stages of its lifetime. - */ - webRequest: WebRequest; - /** - * @returns An instance of protocol module for this session. - */ - protocol: Protocol; - } - - type Permission = 'media' | 'geolocation' | 'notifications' | 'midiSysex' | 'pointerLock' | 'fullscreen' | 'openExternal'; - - interface FromPartitionOptions { - /** - * Whether to enable cache. - */ - cache?: boolean; - } - - interface ClearStorageDataOptions { - /** - * Should follow window.location.origin’s representation scheme://host:port. - */ - origin?: string; - /** - * The types of storages to clear. - */ - storages?: ('appcache' | 'cookies' | 'filesystem' | 'indexdb' | 'localstorage' | 'shadercache' | 'websql' | 'serviceworkers')[]; - /** - * The types of quotas to clear. - */ - quotas?: ('temporary' | 'persistent' | 'syncable')[]; - } - - interface ProxyConfig { - /** - * The URL associated with the PAC file. - */ - pacScript: string; - /** - * Rules indicating which proxies to use. - */ - proxyRules: string; - /** - * Rules indicating which URLs should bypass the proxy settings. - */ - proxyBypassRules: string; - } - - interface NetworkEmulationOptions { - /** - * Whether to emulate network outage. - * Default: false. - */ - offline?: boolean; - /** - * RTT in ms. - * Default: 0, which will disable latency throttling. - */ - latency?: number; - /** - * Download rate in Bps. - * Default: 0, which will disable download throttling. - */ - downloadThroughput?: number; - /** - * Upload rate in Bps. - * Default: 0, which will disable upload throttling. - */ - uploadThroughput?: number; - } - - interface CookieFilter { - /** - * Retrieves cookies which are associated with url. Empty implies retrieving cookies of all urls. - */ - url?: string; - /** - * Filters cookies by name. - */ - name?: string; - /** - * Retrieves cookies whose domains match or are subdomains of domains. - */ - domain?: string; - /** - * Retrieves cookies whose path matches path. - */ - path?: string; - /** - * Filters cookies by their Secure property. - */ - secure?: boolean; - /** - * Filters out session or persistent cookies. - */ - session?: boolean; - } - - interface Cookie { - /** - * Emitted when a cookie is changed because it was added, edited, removed, or expired. - */ - on(event: 'changed', listener: (event: Event, cookie: Cookie, cause: CookieChangedCause) => void): this; - on(event: string, listener: Function): this; - /** - * The name of the cookie. - */ - name: string; - /** - * The value of the cookie. - */ - value: string; - /** - * The domain of the cookie. - */ - domain: string; - /** - * Whether the cookie is a host-only cookie. - */ - hostOnly: string; - /** - * The path of the cookie. - */ - path: string; - /** - * Whether the cookie is marked as secure. - */ - secure: boolean; - /** - * Whether the cookie is marked as HTTP only. - */ - httpOnly: boolean; - /** - * Whether the cookie is a session cookie or a persistent cookie with an expiration date. - */ - session: boolean; - /** - * The expiration date of the cookie as the number of seconds since the UNIX epoch. - * Not provided for session cookies. - */ - expirationDate?: number; - } - - type CookieChangedCause = 'explicit' | 'overwrite' | 'expired' | 'evicted' | 'expired-overwrite'; - - interface CookieDetails { - /** - * The URL associated with the cookie. - */ - url: string; - /** - * The name of the cookie. - * Default: empty. - */ - name?: string; - /** - * The value of the cookie. - * Default: empty. - */ - value?: string; - /** - * The domain of the cookie. - * Default: empty. - */ - domain?: string; - /** - * The path of the cookie. - * Default: empty. - */ - path?: string; - /** - * Whether the cookie should be marked as secure. - * Default: false. - */ - secure?: boolean; - /** - * Whether the cookie should be marked as HTTP only. - * Default: false. - */ - httpOnly?: boolean; - /** - * The expiration date of the cookie as the number of seconds since the UNIX epoch. - * If omitted, the cookie becomes a session cookie. - */ - expirationDate?: number; - } - - interface SessionCookies { - /** - * Sends a request to get all cookies matching filter. - */ - get(filter: CookieFilter, callback: (error: Error, cookies: Cookie[]) => void): void; - /** - * Sets the cookie with details. - */ - set(details: CookieDetails, callback: (error: Error) => void): void; - /** - * Removes the cookies matching url and name. - */ - remove(url: string, name: string, callback: (error: Error) => void): void; - } - - /** - * Each API accepts an optional filter and a listener, the listener will be called when the API's event has happened. - * Passing null as listener will unsubscribe from the event. - * - * The filter will be used to filter out the requests that do not match the URL patterns. - * If the filter is omitted then all requests will be matched. - * - * For certain events the listener is passed with a callback, - * which should be called with an response object when listener has done its work. - */ - interface WebRequest { - /** - * The listener will be called when a request is about to occur. - */ - onBeforeRequest(listener: (details: WebRequest.BeforeRequestDetails, callback: WebRequest.BeforeRequestCallback) => void): void; - /** - * The listener will be called when a request is about to occur. - */ - onBeforeRequest(filter: WebRequest.Filter, listener: (details: WebRequest.BeforeRequestDetails, callback: WebRequest.BeforeRequestCallback) => void): void; - /** - * The listener will be called before sending an HTTP request, once the request headers are available. - * This may occur after a TCP connection is made to the server, but before any http data is sent. - */ - onBeforeSendHeaders(listener: (details: WebRequest.BeforeSendHeadersDetails, callback: WebRequest.BeforeSendHeadersCallback) => void): void; - /** - * The listener will be called before sending an HTTP request, once the request headers are available. - * This may occur after a TCP connection is made to the server, but before any http data is sent. - */ - onBeforeSendHeaders(filter: WebRequest.Filter, listener: (details: WebRequest.BeforeSendHeadersDetails, callback: WebRequest.BeforeSendHeadersCallback) => void): void; - /** - * The listener will be called just before a request is going to be sent to the server, - * modifications of previous onBeforeSendHeaders response are visible by the time this listener is fired. - */ - onSendHeaders(listener: (details: WebRequest.SendHeadersDetails) => void): void; - /** - * The listener will be called just before a request is going to be sent to the server, - * modifications of previous onBeforeSendHeaders response are visible by the time this listener is fired. - */ - onSendHeaders(filter: WebRequest.Filter, listener: (details: WebRequest.SendHeadersDetails) => void): void; - /** - * The listener will be called when HTTP response headers of a request have been received. - */ - onHeadersReceived(listener: (details: WebRequest.HeadersReceivedDetails, callback: WebRequest.HeadersReceivedCallback) => void): void; - /** - * The listener will be called when HTTP response headers of a request have been received. - */ - onHeadersReceived(filter: WebRequest.Filter, listener: (details: WebRequest.HeadersReceivedDetails, callback: WebRequest.HeadersReceivedCallback) => void): void; - /** - * The listener will be called when first byte of the response body is received. - * For HTTP requests, this means that the status line and response headers are available. - */ - onResponseStarted(listener: (details: WebRequest.ResponseStartedDetails) => void): void; - /** - * The listener will be called when first byte of the response body is received. - * For HTTP requests, this means that the status line and response headers are available. - */ - onResponseStarted(filter: WebRequest.Filter, listener: (details: WebRequest.ResponseStartedDetails) => void): void; - /** - * The listener will be called when a server initiated redirect is about to occur. - */ - onBeforeRedirect(listener: (details: WebRequest.BeforeRedirectDetails) => void): void; - /** - * The listener will be called when a server initiated redirect is about to occur. - */ - onBeforeRedirect(filter: WebRequest.Filter, listener: (details: WebRequest.BeforeRedirectDetails) => void): void; - /** - * The listener will be called when a request is completed. - */ - onCompleted(listener: (details: WebRequest.CompletedDetails) => void): void; - /** - * The listener will be called when a request is completed. - */ - onCompleted(filter: WebRequest.Filter, listener: (details: WebRequest.CompletedDetails) => void): void; - /** - * The listener will be called when an error occurs. - */ - onErrorOccurred(listener: (details: WebRequest.ErrorOccurredDetails) => void): void; - /** - * The listener will be called when an error occurs. - */ - onErrorOccurred(filter: WebRequest.Filter, listener: (details: WebRequest.ErrorOccurredDetails) => void): void; - } - - namespace WebRequest { - interface Filter { - urls: string[]; - } - - interface Details { - id: number; - url: string; - method: string; - resourceType: string; - timestamp: number; - } - - interface UploadData { - /** - * Content being sent. - */ - bytes: Buffer; - /** - * Path of file being uploaded. - */ - file: string; - /** - * UUID of blob data. Use session.getBlobData method to retrieve the data. - */ - blobUUID: string; - } - - interface BeforeRequestDetails extends Details { - uploadData?: UploadData[]; - } - - type BeforeRequestCallback = (response: { - cancel?: boolean; - /** - * The original request is prevented from being sent or completed, and is instead redirected to the given URL. - */ - redirectURL?: string; - }) => void; - - interface BeforeSendHeadersDetails extends Details { - requestHeaders: Headers; - } - - type BeforeSendHeadersCallback = (response: { - cancel?: boolean; - /** - * When provided, request will be made with these headers. - */ - requestHeaders?: Headers; - }) => void; - - interface SendHeadersDetails extends Details { - requestHeaders: Headers; - } - - interface HeadersReceivedDetails extends Details { - statusLine: string; - statusCode: number; - responseHeaders: Headers; - } - - type HeadersReceivedCallback = (response: { - cancel?: boolean; - /** - * When provided, the server is assumed to have responded with these headers. - */ - responseHeaders?: Headers; - /** - * Should be provided when overriding responseHeaders to change header status - * otherwise original response header's status will be used. - */ - statusLine?: string; - }) => void; - - interface ResponseStartedDetails extends Details { - responseHeaders: Headers; - fromCache: boolean; - statusCode: number; - statusLine: string; - } - - interface BeforeRedirectDetails extends Details { - redirectURL: string; - statusCode: number; - ip?: string; - fromCache: boolean; - responseHeaders: Headers; - } - - interface CompletedDetails extends Details { - responseHeaders: Headers; - fromCache: boolean; - statusCode: number; - statusLine: string; - } - - interface ErrorOccurredDetails extends Details { - fromCache: boolean; - error: string; - } - } - - // https://github.com/electron/electron/blob/master/docs/api/shell.md - - /** - * The shell module provides functions related to desktop integration. - */ - interface Shell { - /** - * Show the given file in a file manager. If possible, select the file. - * @returns Whether the item was successfully shown. - */ - showItemInFolder(fullPath: string): boolean; - /** - * Open the given file in the desktop's default manner. - * @returns Whether the item was successfully shown. - */ - openItem(fullPath: string): boolean; - /** - * Open the given external protocol URL in the desktop's default manner - * (e.g., mailto: URLs in the default mail user agent). - * @returns Whether an application was available to open the URL. - */ - openExternal(url: string, options?: { - /** - * Bring the opened application to the foreground. - * Default: true. - */ - activate: boolean; - }): boolean; - /** - * Move the given file to trash. - * @returns Whether the item was successfully moved to the trash. - */ - moveItemToTrash(fullPath: string): boolean; - /** - * Play the beep sound. - */ - beep(): void; - /** - * Creates or updates a shortcut link at shortcutPath. - * - * Note: This API is available only on Windows. - */ - writeShortcutLink(shortcutPath: string, options: ShortcutLinkOptions): boolean; - /** - * Creates or updates a shortcut link at shortcutPath. - * - * Note: This API is available only on Windows. - */ - writeShortcutLink(shortcutPath: string, operation: 'create' | 'update' | 'replace', options: ShortcutLinkOptions): boolean; - /** - * Resolves the shortcut link at shortcutPath. - * An exception will be thrown when any error happens. - * - * Note: This API is available only on Windows. - */ - readShortcutLink(shortcutPath: string): ShortcutLinkOptions; - } - - interface ShortcutLinkOptions { - /** - * The target to launch from this shortcut. - */ - target: string; - /** - * The working directory. - * Default: empty. - */ - cwd?: string; - /** - * The arguments to be applied to target when launching from this shortcut. - * Default: empty. - */ - args?: string; - /** - * The description of the shortcut. - * Default: empty. - */ - description?: string; - /** - * The path to the icon, can be a DLL or EXE. icon and iconIndex have to be set together. - * Default: empty, which uses the target's icon. - */ - icon?: string; - /** - * The resource ID of icon when icon is a DLL or EXE. - * Default: 0. - */ - iconIndex?: number; - /** - * The Application User Model ID. - * Default: empty. - */ - appUserModelId?: string; - } - - // https://github.com/electron/electron/blob/master/docs/api/system-preferences.md - - type SystemColor = - '3d-dark-shadow' | // Dark shadow for three-dimensional display elements. - '3d-face' | // Face color for three-dimensional display elements and for dialog box backgrounds. - '3d-highlight' | // Highlight color for three-dimensional display elements. - '3d-light' | // Light color for three-dimensional display elements. - '3d-shadow' | // Shadow color for three-dimensional display elements. - 'active-border' | // Active window border. - 'active-caption' | // Active window title bar. Specifies the left side color in the color gradient of an active window's title bar if the gradient effect is enabled. - 'active-caption-gradient' | // Right side color in the color gradient of an active window's title bar. - 'app-workspace' | // Background color of multiple document interface (MDI) applications. - 'button-text' | // Text on push buttons. - 'caption-text' | // Text in caption, size box, and scroll bar arrow box. - 'desktop' | // Desktop background color. - 'disabled-text' | // Grayed (disabled) text. - 'highlight' | // Item(s) selected in a control. - 'highlight-text' | // Text of item(s) selected in a control. - 'hotlight' | // Color for a hyperlink or hot-tracked item. - 'inactive-border' | // Inactive window border. - 'inactive-caption' | // Inactive window caption. Specifies the left side color in the color gradient of an inactive window's title bar if the gradient effect is enabled. - 'inactive-caption-gradient' | // Right side color in the color gradient of an inactive window's title bar. - 'inactive-caption-text' | // Color of text in an inactive caption. - 'info-background' | // Background color for tooltip controls. - 'info-text' | // Text color for tooltip controls. - 'menu' | // Menu background. - 'menu-highlight' | // The color used to highlight menu items when the menu appears as a flat menu. - 'menubar' | // The background color for the menu bar when menus appear as flat menus. - 'menu-text' | // Text in menus. - 'scrollbar' | // Scroll bar gray area. - 'window' | // Window background. - 'window-frame' | // Window frame. - 'window-text'; // Text in windows. - - /** - * Get system preferences. - */ - interface SystemPreferences { - /** - * Note: This is only implemented on Windows. - */ - on(event: 'accent-color-changed', listener: (event: Event, newColor: string) => void): this; - /** - * Note: This is only implemented on Windows. - */ - on(event: 'color-changed', listener: (event: Event) => void): this; - /** - * Note: This is only implemented on Windows. - */ - on(event: 'inverted-color-scheme-changed', listener: ( - event: Event, - /** - * @param invertedColorScheme true if an inverted color scheme, such as a high contrast theme, is being used, false otherwise. - */ - invertedColorScheme: boolean - ) => void): this; - on(event: string, listener: Function): this; - /** - * @returns Whether the system is in Dark Mode. - * - * Note: This is only implemented on macOS. - */ - isDarkMode(): boolean; - /** - * @returns Whether the Swipe between pages setting is on. - * - * Note: This is only implemented on macOS. - */ - isSwipeTrackingFromScrollEventsEnabled(): boolean; - /** - * Posts event as native notifications of macOS. - * The userInfo contains the user information dictionary sent along with the notification. - * - * Note: This is only implemented on macOS. - */ - postNotification(event: string, userInfo: Object): void; - /** - * Posts event as native notifications of macOS. - * The userInfo contains the user information dictionary sent along with the notification. - * - * Note: This is only implemented on macOS. - */ - postLocalNotification(event: string, userInfo: Object): void; - /** - * Subscribes to native notifications of macOS, callback will be called when the corresponding event happens. - * The id of the subscriber is returned, which can be used to unsubscribe the event. - * - * Note: This is only implemented on macOS. - */ - subscribeNotification(event: string, callback: (event: Event, userInfo: Object) => void): number; - /** - * Removes the subscriber with id. - * - * Note: This is only implemented on macOS. - */ - unsubscribeNotification(id: number): void; - /** - * Same as subscribeNotification, but uses NSNotificationCenter for local defaults. - */ - subscribeLocalNotification(event: string, callback: (event: Event, userInfo: Object) => void): number; - /** - * Same as unsubscribeNotification, but removes the subscriber from NSNotificationCenter. - */ - unsubscribeLocalNotification(id: number): void; - /** - * Get the value of key in system preferences. - * - * Note: This is only implemented on macOS. - */ - getUserDefault(key: string, type: 'string' | 'boolean' | 'integer' | 'float' | 'double' | 'url' | 'array' | 'dictionary'): any; - /** - * @returns Whether DWM composition (Aero Glass) is enabled. - * - * Note: This is only implemented on Windows. - */ - isAeroGlassEnabled(): boolean; - /** - * @returns The users current system wide color preference in the form of an RGBA hexadecimal string. - * - * Note: This is only implemented on Windows. - */ - getAccentColor(): string; - /** - * @returns true if an inverted color scheme, such as a high contrast theme, is active, false otherwise. - * - * Note: This is only implemented on Windows. - */ - isInvertedColorScheme(): boolean; - /** - * @returns The system color setting in RGB hexadecimal form (#ABCDEF). See the Windows docs for more details. - * - * Note: This is only implemented on Windows. - */ - getColor(color: SystemColor): string; - } - - // https://github.com/electron/electron/blob/master/docs/api/tray.md - - /** - * A Tray represents an icon in an operating system's notification area. - */ - class Tray extends NodeJS.EventEmitter implements Destroyable { - /** - * Emitted when the tray icon is clicked. - * Note: The bounds payload is only implemented on macOS and Windows. - */ - on(event: 'click', listener: (modifiers: Modifiers, bounds: Rectangle) => void): this; - /** - * Emitted when the tray icon is right clicked. - * Note: This is only implemented on macOS and Windows. - */ - on(event: 'right-click', listener: (modifiers: Modifiers, bounds: Rectangle) => void): this; - /** - * Emitted when the tray icon is double clicked. - * Note: This is only implemented on macOS and Windows. - */ - on(event: 'double-click', listener: (modifiers: Modifiers, bounds: Rectangle) => void): this; - /** - * Emitted when the tray balloon shows. - * Note: This is only implemented on Windows. - */ - on(event: 'balloon-show', listener: Function): this; - /** - * Emitted when the tray balloon is clicked. - * Note: This is only implemented on Windows. - */ - on(event: 'balloon-click', listener: Function): this; - /** - * Emitted when the tray balloon is closed because of timeout or user manually closes it. - * Note: This is only implemented on Windows. - */ - on(event: 'balloon-closed', listener: Function): this; - /** - * Emitted when any dragged items are dropped on the tray icon. - * Note: This is only implemented on macOS. - */ - on(event: 'drop', listener: Function): this; - /** - * Emitted when dragged files are dropped in the tray icon. - * Note: This is only implemented on macOS - */ - on(event: 'drop-files', listener: (event: Event, files: string[]) => void): this; - /** - * Emitted when dragged text is dropped in the tray icon. - * Note: This is only implemented on macOS - */ - on(event: 'drop-text', listener: (event: Event, text: string) => void): this; - /** - * Emitted when a drag operation enters the tray icon. - * Note: This is only implemented on macOS - */ - on(event: 'drag-enter', listener: Function): this; - /** - * Emitted when a drag operation exits the tray icon. - * Note: This is only implemented on macOS - */ - on(event: 'drag-leave', listener: Function): this; - /** - * Emitted when a drag operation ends on the tray or ends at another location. - * Note: This is only implemented on macOS - */ - on(event: 'drag-end', listener: Function): this; - on(event: string, listener: Function): this; - /** - * Creates a new tray icon associated with the image. - */ - constructor(image: NativeImage|string); - /** - * Destroys the tray icon immediately. - */ - destroy(): void; - /** - * Sets the image associated with this tray icon. - */ - setImage(image: NativeImage|string): void; - /** - * Sets the image associated with this tray icon when pressed. - */ - setPressedImage(image: NativeImage): void; - /** - * Sets the hover text for this tray icon. - */ - setToolTip(toolTip: string): void; - /** - * Sets the title displayed aside of the tray icon in the status bar. - * Note: This is only implemented on macOS. - */ - setTitle(title: string): void; - /** - * Sets when the tray's icon background becomes highlighted. - * Note: This is only implemented on macOS. - */ - setHighlightMode(mode: 'selection' | 'always' | 'never'): void; - /** - * Displays a tray balloon. - * Note: This is only implemented on Windows. - */ - displayBalloon(options?: { - icon?: NativeImage; - title?: string; - content?: string; - }): void; - /** - * Pops up the context menu of tray icon. When menu is passed, - * the menu will showed instead of the tray's context menu. - * The position is only available on Windows, and it is (0, 0) by default. - * Note: This is only implemented on macOS and Windows. - */ - popUpContextMenu(menu?: Menu, position?: Point): void; - /** - * Sets the context menu for this icon. - */ - setContextMenu(menu: Menu): void; - /** - * @returns The bounds of this tray icon. - */ - getBounds(): Rectangle; - /** - * @returns Whether the tray icon is destroyed. - */ - isDestroyed(): boolean; - } - - interface Modifiers { - altKey: boolean; - shiftKey: boolean; - ctrlKey: boolean; - metaKey: boolean; - } - - interface DragItem { - /** - * The absolute path of the file to be dragged - */ - file: string; - /** - * The image showing under the cursor when dragging. - */ - icon: NativeImage; - } - - // https://github.com/electron/electron/blob/master/docs/api/web-contents.md - - interface WebContentsStatic { - /** - * @returns An array of all WebContents instances. This will contain web contents for all windows, - * webviews, opened devtools, and devtools extension background pages. - */ - getAllWebContents(): WebContents[]; - /** - * @returns The web contents that is focused in this application, otherwise returns null. - */ - getFocusedWebContents(): WebContents; - /** - * Find a WebContents instance according to its ID. - */ - fromId(id: number): WebContents; - } - - /** - * A WebContents is responsible for rendering and controlling a web page. - */ - interface WebContents extends NodeJS.EventEmitter { - /** - * Emitted when the navigation is done, i.e. the spinner of the tab has stopped spinning, - * and the onload event was dispatched. - */ - on(event: 'did-finish-load', listener: Function): this; - /** - * This event is like did-finish-load but emitted when the load failed or was cancelled, - * e.g. window.stop() is invoked. - */ - on(event: 'did-fail-load', listener: (event: Event, errorCode: number, errorDescription: string, validatedURL: string, isMainFrame: boolean) => void): this; - /** - * Emitted when a frame has done navigation. - */ - on(event: 'did-frame-finish-load', listener: (event: Event, isMainFrame: boolean) => void): this; - /** - * Corresponds to the points in time when the spinner of the tab started spinning. - */ - on(event: 'did-start-loading', listener: Function): this; - /** - * Corresponds to the points in time when the spinner of the tab stopped spinning. - */ - on(event: 'did-stop-loading', listener: Function): this; - /** - * Emitted when details regarding a requested resource are available. - * status indicates the socket connection to download the resource. - */ - on(event: 'did-get-response-details', listener: (event: Event, - status: boolean, - newURL: string, - originalURL: string, - httpResponseCode: number, - requestMethod: string, - referrer: string, - headers: Headers, - resourceType: string - ) => void): this; - /** - * Emitted when a redirect is received while requesting a resource. - */ - on(event: 'did-get-redirect-request', listener: (event: Event, - oldURL: string, - newURL: string, - isMainFrame: boolean, - httpResponseCode: number, - requestMethod: string, - referrer: string, - headers: Headers - ) => void): this; - /** - * Emitted when the document in the given frame is loaded. - */ - on(event: 'dom-ready', listener: (event: Event) => void): this; - /** - * Emitted when page receives favicon URLs. - */ - on(event: 'page-favicon-updated', listener: (event: Event, favicons: string[]) => void): this; - /** - * Emitted when the page requests to open a new window for a url. - * It could be requested by window.open or an external link like . - * - * By default a new BrowserWindow will be created for the url. - * - * Calling event.preventDefault() will prevent creating new windows. - */ - on(event: 'new-window', listener: (event: Event, - url: string, - frameName: string, - disposition: NewWindowDisposition, - options: BrowserWindowOptions - ) => void): this; - /** - * Emitted when a user or the page wants to start navigation. - * It can happen when the window.location object is changed or a user clicks a link in the page. - * - * This event will not emit when the navigation is started programmatically with APIs like - * webContents.loadURL and webContents.back. - * - * It is also not emitted for in-page navigations, such as clicking anchor links - * or updating the window.location.hash. Use did-navigate-in-page event for this purpose. - * - * Calling event.preventDefault() will prevent the navigation. - */ - on(event: 'will-navigate', listener: (event: Event, url: string) => void): this; - /** - * Emitted when a navigation is done. - * - * This event is not emitted for in-page navigations, such as clicking anchor links - * or updating the window.location.hash. Use did-navigate-in-page event for this purpose. - */ - on(event: 'did-navigate', listener: (event: Event, url: string) => void): this; - /** - * Emitted when an in-page navigation happened. - * - * When in-page navigation happens, the page URL changes but does not cause - * navigation outside of the page. Examples of this occurring are when anchor links - * are clicked or when the DOM hashchange event is triggered. - */ - on(event: 'did-navigate-in-page', listener: (event: Event, url: string, isMainFrame: boolean) => void): this; - /** - * Emitted when the renderer process has crashed. - */ - on(event: 'crashed', listener: (event: Event, killed: boolean) => void): this; - /** - * Emitted when a plugin process has crashed. - */ - on(event: 'plugin-crashed', listener: (event: Event, name: string, version: string) => void): this; - /** - * Emitted when webContents is destroyed. - */ - on(event: 'destroyed', listener: Function): this; - /** - * Emitted when DevTools is opened. - */ - on(event: 'devtools-opened', listener: Function): this; - /** - * Emitted when DevTools is closed. - */ - on(event: 'devtools-closed', listener: Function): this; - /** - * Emitted when DevTools is focused / opened. - */ - on(event: 'devtools-focused', listener: Function): this; - /** - * Emitted when failed to verify the certificate for url. - * The usage is the same with the "certificate-error" event of app. - */ - on(event: 'certificate-error', listener: (event: Event, - url: string, - error: string, - certificate: Certificate, - callback: (trust: boolean) => void - ) => void): this; - /** - * Emitted when a client certificate is requested. - * The usage is the same with the "select-client-certificate" event of app. - */ - on(event: 'select-client-certificate', listener: (event: Event, - url: string, - certificateList: Certificate[], - callback: (certificate: Certificate) => void - ) => void): this; - /** - * Emitted when webContents wants to do basic auth. - * The usage is the same with the "login" event of app. - */ - on(event: 'login', listener: (event: Event, - request: LoginRequest, - authInfo: LoginAuthInfo, - callback: (username: string, password: string) => void - ) => void): this; - /** - * Emitted when a result is available for webContents.findInPage request. - */ - on(event: 'found-in-page', listener: (event: Event, result: FoundInPageResult) => void): this; - /** - * Emitted when media starts playing. - */ - on(event: 'media-started-playing', listener: Function): this; - /** - * Emitted when media is paused or done playing. - */ - on(event: 'media-paused', listener: Function): this; - /** - * Emitted when a page’s theme color changes. This is usually due to encountering a meta tag: - * - */ - on(event: 'did-change-theme-color', listener: Function): this; - /** - * Emitted when mouse moves over a link or the keyboard moves the focus to a link. - */ - on(event: 'update-target-url', listener: (event: Event, url: string) => void): this; - /** - * Emitted when the cursor’s type changes. - * If the type parameter is custom, the image parameter will hold the custom cursor image - * in a NativeImage, and scale, size and hotspot will hold additional information about the custom cursor. - */ - on(event: 'cursor-changed', listener: (event: Event, type: CursorType, image?: NativeImage, scale?: number, size?: Size, hotspot?: Point) => void): this; - /** - * Emitted when there is a new context menu that needs to be handled. - */ - on(event: 'context-menu', listener: (event: Event, params: ContextMenuParams) => void): this; - /** - * Emitted when bluetooth device needs to be selected on call to navigator.bluetooth.requestDevice. - * To use navigator.bluetooth api webBluetooth should be enabled. - * If event.preventDefault is not called, first available device will be selected. - * callback should be called with deviceId to be selected, - * passing empty string to callback will cancel the request. - */ - on(event: 'select-bluetooth-device', listener: (event: Event, deviceList: BluetoothDevice[], callback: (deviceId: string) => void) => void): this; - /** - * Emitted when a new frame is generated. Only the dirty area is passed in the buffer. - */ - on(event: 'paint', listener: (event: Event, dirtyRect: Rectangle, image: NativeImage) => void): this; - on(event: string, listener: Function): this; - /** - * Loads the url in the window. - * @param url Must contain the protocol prefix (e.g., the http:// or file://). - */ - loadURL(url: string, options?: LoadURLOptions): void; - /** - * Initiates a download of the resource at url without navigating. - * The will-download event of session will be triggered. - */ - downloadURL(url: string): void; - /** - * @returns The URL of current web page. - */ - getURL(): string; - /** - * @returns The title of web page. - */ - getTitle(): string; - /** - * @returns Whether the web page is destroyed. - */ - isDestroyed(): boolean; - /** - * @returns Whether the web page is focused. - */ - isFocused(): boolean; - /** - * @returns Whether web page is still loading resources. - */ - isLoading(): boolean; - /** - * @returns Whether the main frame (and not just iframes or frames within it) is still loading. - */ - isLoadingMainFrame(): boolean; - /** - * @returns Whether web page is waiting for a first-response for the main - * resource of the page. - */ - isWaitingForResponse(): boolean; - /** - * Stops any pending navigation. - */ - stop(): void; - /** - * Reloads current page. - */ - reload(): void; - /** - * Reloads current page and ignores cache. - */ - reloadIgnoringCache(): void; - /** - * @returns Whether the web page can go back. - */ - canGoBack(): boolean; - /** - * @returns Whether the web page can go forward. - */ - canGoForward(): boolean; - /** - * @returns Whether the web page can go to offset. - */ - canGoToOffset(offset: number): boolean; - /** - * Clears the navigation history. - */ - clearHistory(): void; - /** - * Makes the web page go back. - */ - goBack(): void; - /** - * Makes the web page go forward. - */ - goForward(): void; - /** - * Navigates to the specified absolute index. - */ - goToIndex(index: number): void; - /** - * Navigates to the specified offset from the "current entry". - */ - goToOffset(offset: number): void; - /** - * @returns Whether the renderer process has crashed. - */ - isCrashed(): boolean; - /** - * Overrides the user agent for this page. - */ - setUserAgent(userAgent: string): void; - /** - * @returns The user agent for this web page. - */ - getUserAgent(): string; - /** - * Injects CSS into this page. - */ - insertCSS(css: string): void; - /** - * Evaluates code in page. - * @param code Code to evaluate. - * - * @returns Promise - */ - executeJavaScript(code: string, userGesture?: boolean, callback?: (result: any) => void): Promise; - /** - * Mute the audio on the current web page. - */ - setAudioMuted(muted: boolean): void; - /** - * @returns Whether this page has been muted. - */ - isAudioMuted(): boolean; - /** - * Changes the zoom factor to the specified factor. - * Zoom factor is zoom percent divided by 100, so 300% = 3.0. - */ - setZoomFactor(factor: number): void; - /** - * Sends a request to get current zoom factor. - */ - getZoomFactor(callback: (zoomFactor: number) => void): void; - /** - * Changes the zoom level to the specified level. - * The original size is 0 and each increment above or below represents - * zooming 20% larger or smaller to default limits of 300% and 50% of original size, respectively. - */ - setZoomLevel(level: number): void; - /** - * Sends a request to get current zoom level. - */ - getZoomLevel(callback: (zoomLevel: number) => void): void; - /** - * Sets the maximum and minimum zoom level. - */ - setVisualZoomLevelLimits(minimumLevel: number, maximumLevel: number): void; - /** - * Sets the maximum and minimum layout-based (i.e. non-visual) zoom level. - */ - setLayoutZoomLevelLimits(minimumLevel: number, maximumLevel: number): void; - /** - * Executes the editing command undo in web page. - */ - undo(): void; - /** - * Executes the editing command redo in web page. - */ - redo(): void; - /** - * Executes the editing command cut in web page. - */ - cut(): void; - /** - * Executes the editing command copy in web page. - */ - copy(): void; - /** - * Copy the image at the given position to the clipboard. - */ - copyImageAt(x: number, y: number): void; - /** - * Executes the editing command paste in web page. - */ - paste(): void; - /** - * Executes the editing command pasteAndMatchStyle in web page. - */ - pasteAndMatchStyle(): void; - /** - * Executes the editing command delete in web page. - */ - delete(): void; - /** - * Executes the editing command selectAll in web page. - */ - selectAll(): void; - /** - * Executes the editing command unselect in web page. - */ - unselect(): void; - /** - * Executes the editing command replace in web page. - */ - replace(text: string): void; - /** - * Executes the editing command replaceMisspelling in web page. - */ - replaceMisspelling(text: string): void; - /** - * Inserts text to the focused element. - */ - insertText(text: string): void; - /** - * Starts a request to find all matches for the text in the web page. - * The result of the request can be obtained by subscribing to found-in-page event. - * @returns The request id used for the request. - */ - findInPage(text: string, options?: FindInPageOptions): number; - /** - * Stops any findInPage request for the webContents with the provided action. - */ - stopFindInPage(action: StopFindInPageAtion): void; - /** - * Checks if any serviceworker is registered. - */ - hasServiceWorker(callback: (hasServiceWorker: boolean) => void): void; - /** - * Unregisters any serviceworker if present. - */ - unregisterServiceWorker(callback: (isFulfilled: boolean) => void): void; - /** - * Prints window's web page. When silent is set to false, Electron will pick up system's default printer and default settings for printing. - * Calling window.print() in web page is equivalent to call WebContents.print({silent: false, printBackground: false}). - * Note: On Windows, the print API relies on pdf.dll. If your application doesn't need print feature, you can safely remove pdf.dll in saving binary size. - */ - print(options?: PrintOptions): void; - /** - * Prints windows' web page as PDF with Chromium's preview printing custom settings. - */ - printToPDF(options: PrintToPDFOptions, callback: (error: Error, data: Buffer) => void): void; - /** - * Adds the specified path to DevTools workspace. - */ - addWorkSpace(path: string): void; - /** - * Removes the specified path from DevTools workspace. - */ - removeWorkSpace(path: string): void; - /** - * Opens the developer tools. - */ - openDevTools(options?: { - /** - * Opens the devtools with specified dock state. Defaults to last used dock state. - */ - mode?: 'right' | 'bottom' | 'undocked' | 'detach' - }): void; - /** - * Closes the developer tools. - */ - closeDevTools(): void; - /** - * Returns whether the developer tools are opened. - */ - isDevToolsOpened(): boolean; - /** - * Returns whether the developer tools are focussed. - */ - isDevToolsFocused(): boolean; - /** - * Toggle the developer tools. - */ - toggleDevTools(): void; - /** - * Starts inspecting element at position (x, y). - */ - inspectElement(x: number, y: number): void; - /** - * Opens the developer tools for the service worker context. - */ - inspectServiceWorker(): void; - /** - * Send args.. to the web page via channel in asynchronous message, the web page - * can handle it by listening to the channel event of ipc module. - * Note: - * 1. The IPC message handler in web pages do not have a event parameter, - * which is different from the handlers on the main process. - * 2. There is no way to send synchronous messages from the main process - * to a renderer process, because it would be very easy to cause dead locks. - */ - send(channel: string, ...args: any[]): void; - /** - * Enable device emulation with the given parameters. - */ - enableDeviceEmulation(parameters: DeviceEmulationParameters): void; - /** - * Disable device emulation. - */ - disableDeviceEmulation(): void; - /** - * Sends an input event to the page. - */ - sendInputEvent(event: SendInputEvent): void; - /** - * Begin subscribing for presentation events and captured frames, - * The callback will be called when there is a presentation event. - */ - beginFrameSubscription(onlyDirty: boolean, callback: BeginFrameSubscriptionCallback): void; - /** - * Begin subscribing for presentation events and captured frames, - * The callback will be called when there is a presentation event. - */ - beginFrameSubscription(callback: BeginFrameSubscriptionCallback): void; - /** - * End subscribing for frame presentation events. - */ - endFrameSubscription(): void; - /** - * @returns If the process of saving page has been initiated successfully. - */ - savePage(fullPath: string, saveType: 'HTMLOnly' | 'HTMLComplete' | 'MHTML', callback?: (eror: Error) => void): boolean; - /** - * Shows pop-up dictionary that searches the selected word on the page. - * Note: This API is available only on macOS. - */ - showDefinitionForSelection(): void; - /** - * @returns Whether offscreen rendering is enabled. - */ - isOffscreen(): boolean; - /** - * If offscreen rendering is enabled and not painting, start painting. - */ - startPainting(): void; - /** - * If offscreen rendering is enabled and painting, stop painting. - */ - stopPainting(): void; - /** - * If offscreen rendering is enabled returns whether it is currently painting. - */ - isPainting(): boolean; - /** - * If offscreen rendering is enabled sets the frame rate to the specified number. - * Only values between 1 and 60 are accepted. - */ - setFrameRate(fps: number): void; - /** - * If offscreen rendering is enabled returns the current frame rate. - */ - getFrameRate(): number; - /** - * If offscreen rendering is enabled invalidates the frame and generates a new one through the 'paint' event. - */ - invalidate(): void; - /** - * Sets the item as dragging item for current drag-drop operation. - */ - startDrag(item: DragItem): void; - /** - * Captures a snapshot of the page within rect. - */ - capturePage(callback: (image: NativeImage) => void): void; - /** - * Captures a snapshot of the page within rect. - */ - capturePage(rect: Rectangle, callback: (image: NativeImage) => void): void; - /** - * @returns The unique ID of this WebContents. - */ - id: number; - /** - * @returns The session object used by this webContents. - */ - session: Session; - /** - * @returns The WebContents that might own this WebContents. - */ - hostWebContents: WebContents; - /** - * @returns The WebContents of DevTools for this WebContents. - * Note: Users should never store this object because it may become null - * when the DevTools has been closed. - */ - devToolsWebContents: WebContents; - /** - * @returns Debugger API - */ - debugger: Debugger; - } - - interface BeginFrameSubscriptionCallback { - ( - /** - * The frameBuffer is a Buffer that contains raw pixel data. - * On most machines, the pixel data is effectively stored in 32bit BGRA format, - * but the actual representation depends on the endianness of the processor - * (most modern processors are little-endian, on machines with big-endian - * processors the data is in 32bit ARGB format). - */ - frameBuffer: Buffer, - /** - * The dirtyRect is an object with x, y, width, height properties that describes which part of the page was repainted. - * If onlyDirty is set to true, frameBuffer will only contain the repainted area. onlyDirty defaults to false. - */ - dirtyRect?: Rectangle - ): void - } - - interface ContextMenuParams { - /** - * x coordinate - */ - x: number; - /** - * y coordinate - */ - y: number; - /** - * URL of the link that encloses the node the context menu was invoked on. - */ - linkURL: string; - /** - * Text associated with the link. May be an empty string if the contents of the link are an image. - */ - linkText: string; - /** - * URL of the top level page that the context menu was invoked on. - */ - pageURL: string; - /** - * URL of the subframe that the context menu was invoked on. - */ - frameURL: string; - /** - * Source URL for the element that the context menu was invoked on. - * Elements with source URLs are images, audio and video. - */ - srcURL: string; - /** - * Type of the node the context menu was invoked on. - */ - mediaType: 'none' | 'image' | 'audio' | 'video' | 'canvas' | 'file' | 'plugin'; - /** - * Parameters for the media element the context menu was invoked on. - */ - mediaFlags: { - /** - * Whether the media element has crashed. - */ - inError: boolean; - /** - * Whether the media element is paused. - */ - isPaused: boolean; - /** - * Whether the media element is muted. - */ - isMuted: boolean; - /** - * Whether the media element has audio. - */ - hasAudio: boolean; - /** - * Whether the media element is looping. - */ - isLooping: boolean; - /** - * Whether the media element's controls are visible. - */ - isControlsVisible: boolean; - /** - * Whether the media element's controls are toggleable. - */ - canToggleControls: boolean; - /** - * Whether the media element can be rotated. - */ - canRotate: boolean; - } - /** - * Whether the context menu was invoked on an image which has non-empty contents. - */ - hasImageContents: boolean; - /** - * Whether the context is editable. - */ - isEditable: boolean; - /** - * These flags indicate whether the renderer believes it is able to perform the corresponding action. - */ - editFlags: { - /** - * Whether the renderer believes it can undo. - */ - canUndo: boolean; - /** - * Whether the renderer believes it can redo. - */ - canRedo: boolean; - /** - * Whether the renderer believes it can cut. - */ - canCut: boolean; - /** - * Whether the renderer believes it can copy - */ - canCopy: boolean; - /** - * Whether the renderer believes it can paste. - */ - canPaste: boolean; - /** - * Whether the renderer believes it can delete. - */ - canDelete: boolean; - /** - * Whether the renderer believes it can select all. - */ - canSelectAll: boolean; - } - /** - * Text of the selection that the context menu was invoked on. - */ - selectionText: string; - /** - * Title or alt text of the selection that the context was invoked on. - */ - titleText: string; - /** - * The misspelled word under the cursor, if any. - */ - misspelledWord: string; - /** - * The character encoding of the frame on which the menu was invoked. - */ - frameCharset: string; - /** - * If the context menu was invoked on an input field, the type of that field. - */ - inputFieldType: 'none' | 'plainText' | 'password' | 'other'; - /** - * Input source that invoked the context menu. - */ - menuSourceType: 'none' | 'mouse' | 'keyboard' | 'touch' | 'touchMenu'; - } - - interface BluetoothDevice { - deviceName: string; - deviceId: string; - } - - interface Headers { - [key: string]: string; - } - - type NewWindowDisposition = 'default' | 'foreground-tab' | 'background-tab' | 'new-window' | 'save-to-disk' | 'other'; - - /** - * Specifies the action to take place when ending webContents.findInPage request. - * 'clearSelection' - Clear the selection. - * 'keepSelection' - Translate the selection into a normal selection. - * 'activateSelection' - Focus and click the selection node. - */ - type StopFindInPageAtion = 'clearSelection' | 'keepSelection' | 'activateSelection'; - - type CursorType = 'default' | 'crosshair' | 'pointer' | 'text' | 'wait' | 'help' | 'e-resize' | 'n-resize' | 'ne-resize' | 'nw-resize' | 's-resize' | 'se-resize' | 'sw-resize' | 'w-resize' | 'ns-resize' | 'ew-resize' | 'nesw-resize' | 'nwse-resize' | 'col-resize' | 'row-resize' | 'm-panning' | 'e-panning' | 'n-panning' | 'ne-panning' | 'nw-panning' | 's-panning' | 'se-panning' |'sw-panning' | 'w-panning' | 'move' | 'vertical-text' | 'cell' | 'context-menu' | 'alias' | 'progress' | 'nodrop' | 'copy' | 'none' | 'not-allowed' | 'zoom-in' | 'zoom-out' | 'grab' | 'grabbing' | 'custom'; - - interface LoadURLOptions { - /** - * HTTP Referrer URL. - */ - httpReferrer?: string; - /** - * User agent originating the request. - */ - userAgent?: string; - /** - * Extra headers separated by "\n" - */ - extraHeaders?: string; - /** - * POST data - */ - postData?: (UploadRawData | UploadFileSystem | UploadBlob)[]; - } - - interface UploadRawData { - /** - * rawData - */ - type: 'rawData'; - /** - * Data to be uploaded. - */ - bytes: Buffer; - } - - interface UploadFileSystem { - /** - * fileSystem - */ - type: 'fileSystem'; - /** - * FileSystem url to read data for upload. - */ - fileSystemURL: string; - /** - * Defaults to 0. - */ - offset: number; - /** - * Number of bytes to read from offset. Defaults to 0. - */ - length: number; - /** - * Last Modification time in number of seconds sine the UNIX epoch. - */ - modificationTime: number; - } - - interface UploadBlob { - /** - * blob - */ - type: 'blob'; - /** - * UUID of blob data to upload. - */ - blobUUID: string; - } - - interface PrintOptions { - /** - * Don't ask user for print settings. - * Defaults: false. - */ - silent?: boolean; - /** - * Also prints the background color and image of the web page. - * Defaults: false. - */ - printBackground?: boolean; - } - - interface PrintToPDFOptions { - /** - * Specify the type of margins to use. - * 0 - default - * 1 - none - * 2 - minimum - * Default: 0 - */ - marginsType?: number; - /** - * Specify page size of the generated PDF. - * Default: A4. - */ - pageSize?: 'A3' | 'A4' | 'A5' | 'Legal' | 'Letter' | 'Tabloid' | Size; - /** - * Whether to print CSS backgrounds. - * Default: false. - */ - printBackground?: boolean; - /** - * Whether to print selection only. - * Default: false. - */ - printSelectionOnly?: boolean; - /** - * true for landscape, false for portrait. - * Default: false. - */ - landscape?: boolean; - } - - interface Certificate { - /** - * PEM encoded data. - */ - data: string; - /** - * Issuer principal - */ - issuer: CertificatePrincipal; - /** - * Issuer's Common Name. - */ - issuerName: string; - /** - * Issuer certificate (if not self-signed) - */ - issuerCert: Certificate; - /** - * Subject principal - */ - subject: CertificatePrincipal; - /** - * Subject's Common Name. - */ - subjectName: string; - /** - * Hex value represented string. - */ - serialNumber: string; - /** - * Start date of the certificate being valid in seconds. - */ - validStart: number; - /** - * End date of the certificate being valid in seconds. - */ - validExpiry: number; - /** - * Fingerprint of the certificate. - */ - fingerprint: string; - } - - interface CertificatePrincipal { - /** - * Common Name - */ - commonName: string; - /** - * Organization names - */ - organizations: string[]; - /** - * Organization Unit names - */ - organizationUnits: string[]; - /** - * Locality - */ - locality: string; - /** - * State or province - */ - state: string; - /** - * Country or region - */ - country: string; - } - - interface LoginRequest { - method: string; - url: string; - referrer: string; - } - - interface LoginAuthInfo { - isProxy: boolean; - scheme: string; - host: string; - port: number; - realm: string; - } - - interface FindInPageOptions { - /** - * Whether to search forward or backward, defaults to true - */ - forward?: boolean; - /** - * Whether the operation is first request or a follow up, defaults to false. - */ - findNext?: boolean; - /** - * Whether search should be case-sensitive, defaults to false. - */ - matchCase?: boolean; - /** - * Whether to look only at the start of words. defaults to false. - */ - wordStart?: boolean; - /** - * When combined with wordStart, accepts a match in the middle of a word - * if the match begins with an uppercase letter followed by a lowercase - * or non-letter. Accepts several other intra-word matches, defaults to false. - */ - medialCapitalAsWordStart?: boolean; - } - - interface FoundInPageResult { - requestId: number; - /** - * Indicates if more responses are to follow. - */ - finalUpdate: boolean; - /** - * Position of the active match. - */ - activeMatchOrdinal?: number; - /** - * Number of Matches. - */ - matches?: number; - /** - * Coordinates of first match region. - */ - selectionArea?: Rectangle; - } - - interface DeviceEmulationParameters { - /** - * Specify the screen type to emulated - * Default: desktop - */ - screenPosition?: 'desktop' | 'mobile'; - /** - * Set the emulated screen size (screenPosition == mobile) - */ - screenSize?: Size; - /** - * Position the view on the screen (screenPosition == mobile) - * Default: {x: 0, y: 0} - */ - viewPosition?: Point; - /** - * Set the device scale factor (if zero defaults to original device scale factor) - * Default: 0 - */ - deviceScaleFactor: number; - /** - * Set the emulated view size (empty means no override). - */ - viewSize?: Size; - /** - * Whether emulated view should be scaled down if necessary to fit into available space - * Default: false - */ - fitToView?: boolean; - /** - * Offset of the emulated view inside available space (not in fit to view mode) - * Default: {x: 0, y: 0} - */ - offset?: Point; - /** - * Scale of emulated view inside available space (not in fit to view mode) - * Default: 1 - */ - scale: number; - } - - interface SendInputEvent { - type: 'mouseDown' | 'mouseUp' | 'mouseEnter' | 'mouseLeave' | 'contextMenu' | 'mouseWheel' | 'mouseMove' | 'keyDown' | 'keyUp' | 'char'; - modifiers: ('shift' | 'control' | 'alt' | 'meta' | 'isKeypad' | 'isAutoRepeat' | 'leftButtonDown' | 'middleButtonDown' | 'rightButtonDown' | 'capsLock' | 'numLock' | 'left' | 'right')[]; - } - - interface SendInputKeyboardEvent extends SendInputEvent { - keyCode: string; - } - - interface SendInputMouseEvent extends SendInputEvent { - x: number; - y: number; - button?: 'left' | 'middle' | 'right'; - globalX?: number; - globalY?: number; - movementX?: number; - movementY?: number; - clickCount?: number; - } - - interface SendInputMouseWheelEvent extends SendInputEvent { - deltaX?: number; - deltaY?: number; - wheelTicksX?: number; - wheelTicksY?: number; - accelerationRatioX?: number; - accelerationRatioY?: number; - hasPreciseScrollingDeltas?: boolean; - canScroll?: boolean; - } - - /** - * Debugger API serves as an alternate transport for remote debugging protocol. - */ - interface Debugger extends NodeJS.EventEmitter { - /** - * Attaches the debugger to the webContents. - * @param protocolVersion Requested debugging protocol version. - */ - attach(protocolVersion?: string): void; - /** - * @returns Whether a debugger is attached to the webContents. - */ - isAttached(): boolean; - /** - * Detaches the debugger from the webContents. - */ - detach(): void; - /** - * Send given command to the debugging target. - * @param method Method name, should be one of the methods defined by the remote debugging protocol. - * @param commandParams JSON object with request parameters. - * @param callback Response defined by the ‘returns’ attribute of the command description in the remote debugging protocol. - */ - sendCommand(method: string, commandParams?: any, callback?: (error: Error, result: any) => void): void; - /** - * Emitted when debugging session is terminated. This happens either when - * webContents is closed or devtools is invoked for the attached webContents. - */ - on(event: 'detach', listener: (event: Event, reason: string) => void): this; - /** - * Emitted whenever debugging target issues instrumentation event. - * Event parameters defined by the ‘parameters’ attribute in the remote debugging protocol. - */ - on(event: 'message', listener: (event: Event, method: string, params: any) => void): this; - on(event: string, listener: Function): this; - } - - // https://github.com/electron/electron/blob/master/docs/api/web-frame.md - - /** - * The web-frame module allows you to customize the rendering of the current web page. - */ - interface WebFrame { - /** - * Changes the zoom factor to the specified factor, zoom factor is - * zoom percent / 100, so 300% = 3.0. - */ - setZoomFactor(factor: number): void; - /** - * @returns The current zoom factor. - */ - getZoomFactor(): number; - /** - * Changes the zoom level to the specified level, 0 is "original size", and each - * increment above or below represents zooming 20% larger or smaller to default - * limits of 300% and 50% of original size, respectively. - */ - setZoomLevel(level: number): void; - /** - * @returns The current zoom level. - */ - getZoomLevel(): number; - /** - * Sets the maximum and minimum zoom level. - */ - setVisualZoomLevelLimits(minimumLevel: number, maximumLevel: number): void; - /** - * Sets the maximum and minimum layout-based (i.e. non-visual) zoom level. - */ - setLayoutZoomLevelLimits(minimumLevel: number, maximumLevel: number): void; - /** - * Sets a provider for spell checking in input fields and text areas. - */ - setSpellCheckProvider(language: string, autoCorrectWord: boolean, provider: { - /** - * @returns Whether the word passed is correctly spelled. - */ - spellCheck: (text: string) => boolean; - }): void; - /** - * Sets the scheme as secure scheme. Secure schemes do not trigger mixed content - * warnings. For example, https and data are secure schemes because they cannot be - * corrupted by active network attackers. - */ - registerURLSchemeAsSecure(scheme: string): void; - /** - * Resources will be loaded from this scheme regardless of the current page’s Content Security Policy. - */ - registerURLSchemeAsBypassingCSP(scheme: string): void; - /** - * Registers the scheme as secure, bypasses content security policy for resources, - * allows registering ServiceWorker and supports fetch API. - */ - registerURLSchemeAsPrivileged(scheme: string, options?: RegisterURLSchemeOptions): void; - /** - * Inserts text to the focused element. - */ - insertText(text: string): void; - /** - * Evaluates `code` in page. - * In the browser window some HTML APIs like `requestFullScreen` can only be - * invoked by a gesture from the user. Setting `userGesture` to `true` will remove - * this limitation. - * - * @returns Promise - */ - executeJavaScript(code: string, userGesture?: boolean, callback?: (result: any) => void): Promise; - /** - * @returns Object describing usage information of Blink’s internal memory caches. - */ - getResourceUsage(): ResourceUsages; - /** - * Attempts to free memory that is no longer being used (like images from a previous navigation). - */ - clearCache(): void; - } - - interface ResourceUsages { - fonts: ResourceUsage; - images: ResourceUsage; - cssStyleSheets: ResourceUsage; - xslStyleSheets: ResourceUsage; - scripts: ResourceUsage; - other: ResourceUsage; - } - - interface ResourceUsage { - count: number; - decodedSize: number; - liveSize: number; - purgeableSize: number; - purgedSize: number; - size: number; - } - - interface RegisterURLSchemeOptions { - secure?: boolean; - bypassCSP?: boolean; - allowServiceWorkers?: boolean; - supportFetchAPI?: boolean; - corsEnabled?: boolean; - } - - // https://github.com/electron/electron/blob/master/docs/api/web-view-tag.md - - /** - * Use the webview tag to embed 'guest' content (such as web pages) in your Electron app. - * The guest content is contained within the webview container. - * An embedded page within your app controls how the guest content is laid out and rendered. - * - * Unlike an iframe, the webview runs in a separate process than your app. - * It doesn't have the same permissions as your web page and all interactions between your app - * and embedded content will be asynchronous. This keeps your app safe from the embedded content. - */ - interface WebViewElement extends HTMLElement { - /** - * Returns the visible URL. Writing to this attribute initiates top-level navigation. - * Assigning src its own value will reload the current page. - * The src attribute can also accept data URLs, such as data:text/plain,Hello, world!. - */ - src: string; - /** - * If "on", the webview container will automatically resize within the bounds specified - * by the attributes minwidth, minheight, maxwidth, and maxheight. - * These constraints do not impact the webview unless autosize is enabled. - * When autosize is enabled, the webview container size cannot be less than - * the minimum values or greater than the maximum. - */ - autosize: string; - /** - * If "on", the guest page in webview will have node integration and can use node APIs - * like require and process to access low level system resources. - */ - nodeintegration: string; - /** - * If "on", the guest page in webview will be able to use browser plugins. - */ - plugins: string; - /** - * Specifies a script that will be loaded before other scripts run in the guest page. - * The protocol of script's URL must be either file: or asar:, - * because it will be loaded by require in guest page under the hood. - * - * When the guest page doesn't have node integration this script will still have access to all Node APIs, - * but global objects injected by Node will be deleted after this script has finished executing. - */ - preload: string; - /** - * Sets the referrer URL for the guest page. - */ - httpreferrer: string; - /** - * Sets the user agent for the guest page before the page is navigated to. - * Once the page is loaded, use the setUserAgent method to change the user agent. - */ - useragent: string; - /** - * If "on", the guest page will have web security disabled. - */ - disablewebsecurity: string; - /** - * Sets the session used by the page. If partition starts with persist:, - * the page will use a persistent session available to all pages in the app with the same partition. - * If there is no persist: prefix, the page will use an in-memory session. - * By assigning the same partition, multiple pages can share the same session. - * If the partition is unset then default session of the app will be used. - * - * This value can only be modified before the first navigation, - * since the session of an active renderer process cannot change. - * Subsequent attempts to modify the value will fail with a DOM exception. - */ - partition: string; - /** - * If "on", the guest page will be allowed to open new windows. - */ - allowpopups: string; - /** - * A list of strings which specifies the web preferences to be set on the webview, separated by ,. - */ - webpreferences: string; - /** - * A list of strings which specifies the blink features to be enabled separated by ,. - */ - blinkfeatures: string; - /** - * A list of strings which specifies the blink features to be disabled separated by ,. - */ - disableblinkfeatures: string; - /** - * A value that links the webview to a specific webContents. - * When a webview first loads a new webContents is created and this attribute is set - * to its instance identifier. Setting this attribute on a new or existing webview connects - * it to the existing webContents that currently renders in a different webview. - * - * The existing webview will see the destroy event and will then create a new webContents when a new url is loaded. - */ - guestinstance: string; - /** - * Loads the url in the webview, the url must contain the protocol prefix, e.g. the http:// or file://. - */ - loadURL(url: string, options?: LoadURLOptions): void; - /** - * @returns URL of guest page. - */ - getURL(): string; - /** - * @returns The title of guest page. - */ - getTitle(): string; - /** - * @returns Whether the web page is destroyed. - */ - isDestroyed(): boolean; - /** - * @returns Whether the web page is focused. - */ - isFocused(): boolean; - /** - * @returns Whether guest page is still loading resources. - */ - isLoading(): boolean; - /** - * Returns a boolean whether the guest page is waiting for a first-response for the main resource of the page. - */ - isWaitingForResponse(): boolean; - /** - * Stops any pending navigation. - */ - stop(): void; - /** - * Reloads the guest page. - */ - reload(): void; - /** - * Reloads the guest page and ignores cache. - */ - reloadIgnoringCache(): void; - /** - * @returns Whether the guest page can go back. - */ - canGoBack(): boolean; - /** - * @returns Whether the guest page can go forward. - */ - canGoForward(): boolean; - /** - * @returns Whether the guest page can go to offset. - */ - canGoToOffset(offset: number): boolean; - /** - * Clears the navigation history. - */ - clearHistory(): void; - /** - * Makes the guest page go back. - */ - goBack(): void; - /** - * Makes the guest page go forward. - */ - goForward(): void; - /** - * Navigates to the specified absolute index. - */ - goToIndex(index: number): void; - /** - * Navigates to the specified offset from the "current entry". - */ - goToOffset(offset: number): void; - /** - * @returns Whether the renderer process has crashed. - */ - isCrashed(): boolean; - /** - * Overrides the user agent for the guest page. - */ - setUserAgent(userAgent: string): void; - /** - * @returns The user agent for guest page. - */ - getUserAgent(): string; - /** - * Injects CSS into the guest page. - */ - insertCSS(css: string): void; - /** - * Evaluates code in page. If userGesture is set, it will create the user gesture context in the page. - * HTML APIs like requestFullScreen, which require user action, can take advantage of this option for automation. - * - * @returns Promise - */ - executeJavaScript(code: string, userGesture?: boolean, callback?: (result: any) => void): Promise; - /** - * Opens a DevTools window for guest page. - */ - openDevTools(): void; - /** - * Closes the DevTools window of guest page. - */ - closeDevTools(): void; - /** - * @returns Whether guest page has a DevTools window attached. - */ - isDevToolsOpened(): boolean; - /** - * @returns Whether DevTools window of guest page is focused. - */ - isDevToolsFocused(): boolean; - /** - * Starts inspecting element at position (x, y) of guest page. - */ - inspectElement(x: number, y: number): void; - /** - * Opens the DevTools for the service worker context present in the guest page. - */ - inspectServiceWorker(): void; - /** - * Set guest page muted. - */ - setAudioMuted(muted: boolean): void; - /** - * @returns Whether guest page has been muted. - */ - isAudioMuted(): boolean; - /** - * Executes editing command undo in page. - */ - undo(): void; - /** - * Executes editing command redo in page. - */ - redo(): void; - /** - * Executes editing command cut in page. - */ - cut(): void; - /** - * Executes editing command copy in page. - */ - copy(): void; - /** - * Executes editing command paste in page. - */ - paste(): void; - /** - * Executes editing command pasteAndMatchStyle in page. - */ - pasteAndMatchStyle(): void; - /** - * Executes editing command delete in page. - */ - delete(): void; - /** - * Executes editing command selectAll in page. - */ - selectAll(): void; - /** - * Executes editing command unselect in page. - */ - unselect(): void; - /** - * Executes editing command replace in page. - */ - replace(text: string): void; - /** - * Executes editing command replaceMisspelling in page. - */ - replaceMisspelling(text: string): void; - /** - * Inserts text to the focused element. - */ - insertText(text: string): void; - /** - * Starts a request to find all matches for the text in the web page. - * The result of the request can be obtained by subscribing to found-in-page event. - * @returns The request id used for the request. - */ - findInPage(text: string, options?: FindInPageOptions): number; - /** - * Stops any findInPage request for the webview with the provided action. - */ - stopFindInPage(action: StopFindInPageAtion): void; - /** - * Prints webview's web page. Same with webContents.print([options]). - */ - print(options?: PrintOptions): void; - /** - * Prints webview's web page as PDF, Same with webContents.printToPDF(options, callback) - */ - printToPDF(options: PrintToPDFOptions, callback: (error: Error, data: Buffer) => void): void; - /** - * Send an asynchronous message to renderer process via channel, you can also send arbitrary arguments. - * The renderer process can handle the message by listening to the channel event with the ipcRenderer module. - * See webContents.send for examples. - */ - send(channel: string, ...args: any[]): void; - /** - * Sends an input event to the page. - * See webContents.sendInputEvent for detailed description of event object. - */ - sendInputEvent(event: SendInputEvent): void - /** - * Changes the zoom factor to the specified factor. - * Zoom factor is zoom percent divided by 100, so 300% = 3.0. - */ - setZoomFactor(factor: number): void; - /** - * Changes the zoom level to the specified level. - * The original size is 0 and each increment above or below represents - * zooming 20% larger or smaller to default limits of 300% and 50% of original size, respectively. - */ - setZoomLevel(level: number): void; - /** - * Shows pop-up dictionary that searches the selected word on the page. - * Note: This API is available only on macOS. - */ - showDefinitionForSelection(): void; - /** - * @returns The WebContents associated with this webview. - */ - getWebContents(): WebContents; - /** - * Captures a snapshot of the webview's page. Same as webContents.capturePage([rect, ]callback). - */ - capturePage(callback: (image: NativeImage) => void): void; - /** - * Captures a snapshot of the webview's page. Same as webContents.capturePage([rect, ]callback). - */ - capturePage(rect: Rectangle, callback: (image: NativeImage) => void): void; - /** - * Fired when a load has committed. This includes navigation within the current document - * as well as subframe document-level loads, but does not include asynchronous resource loads. - */ - addEventListener(type: 'load-commit', listener: (event: WebViewElement.LoadCommitEvent) => void, useCapture?: boolean): void; - /** - * Fired when the navigation is done, i.e. the spinner of the tab will stop spinning, and the onload event is dispatched. - */ - addEventListener(type: 'did-finish-load', listener: (event: WebViewElement.Event) => void, useCapture?: boolean): void; - /** - * This event is like did-finish-load, but fired when the load failed or was cancelled, e.g. window.stop() is invoked. - */ - addEventListener(type: 'did-fail-load', listener: (event: WebViewElement.DidFailLoadEvent) => void, useCapture?: boolean): void; - /** - * Fired when a frame has done navigation. - */ - addEventListener(type: 'did-frame-finish-load', listener: (event: WebViewElement.DidFrameFinishLoadEvent) => void, useCapture?: boolean): void; - /** - * Corresponds to the points in time when the spinner of the tab starts spinning. - */ - addEventListener(type: 'did-start-loading', listener: (event: WebViewElement.Event) => void, useCapture?: boolean): void; - /** - * Corresponds to the points in time when the spinner of the tab stops spinning. - */ - addEventListener(type: 'did-stop-loading', listener: (event: WebViewElement.Event) => void, useCapture?: boolean): void; - /** - * Fired when details regarding a requested resource is available. - * status indicates socket connection to download the resource. - */ - addEventListener(type: 'did-get-response-details', listener: (event: WebViewElement.DidGetResponseDetails) => void, useCapture?: boolean): void; - /** - * Fired when a redirect was received while requesting a resource. - */ - addEventListener(type: 'did-get-redirect-request', listener: (event: WebViewElement.DidGetRedirectRequestEvent) => void, useCapture?: boolean): void; - /** - * Fired when document in the given frame is loaded. - */ - addEventListener(type: 'dom-ready', listener: (event: WebViewElement.Event) => void, useCapture?: boolean): void; - /** - * Fired when page title is set during navigation. explicitSet is false when title is synthesized from file URL. - */ - addEventListener(type: 'page-title-updated', listener: (event: WebViewElement.PageTitleUpdatedEvent) => void, useCapture?: boolean): void; - /** - * Fired when page receives favicon URLs. - */ - addEventListener(type: 'page-favicon-updated', listener: (event: WebViewElement.PageFaviconUpdatedEvent) => void, useCapture?: boolean): void; - /** - * Fired when page enters fullscreen triggered by HTML API. - */ - addEventListener(type: 'enter-html-full-screen', listener: (event: WebViewElement.Event) => void, useCapture?: boolean): void; - /** - * Fired when page leaves fullscreen triggered by HTML API. - */ - addEventListener(type: 'leave-html-full-screen', listener: (event: WebViewElement.Event) => void, useCapture?: boolean): void; - /** - * Fired when the guest window logs a console message. - */ - addEventListener(type: 'console-message', listener: (event: WebViewElement.ConsoleMessageEvent) => void, useCapture?: boolean): void; - /** - * Fired when a result is available for webview.findInPage request. - */ - addEventListener(type: 'found-in-page', listener: (event: WebViewElement.FoundInPageEvent) => void, useCapture?: boolean): void; - /** - * Fired when the guest page attempts to open a new browser window. - */ - addEventListener(type: 'new-window', listener: (event: WebViewElement.NewWindowEvent) => void, useCapture?: boolean): void; - /** - * Emitted when a user or the page wants to start navigation. - * It can happen when the window.location object is changed or a user clicks a link in the page. - * - * This event will not emit when the navigation is started programmatically with APIs - * like .loadURL and .back. - * - * It is also not emitted during in-page navigation, such as clicking anchor links - * or updating the window.location.hash. Use did-navigate-in-page event for this purpose. - * - * Calling event.preventDefault() does NOT have any effect. - */ - addEventListener(type: 'will-navigate', listener: (event: WebViewElement.WillNavigateEvent) => void, useCapture?: boolean): void; - /** - * Emitted when a navigation is done. - * - * This event is not emitted for in-page navigations, such as clicking anchor links - * or updating the window.location.hash. Use did-navigate-in-page event for this purpose. - */ - addEventListener(type: 'did-navigate', listener: (event: WebViewElement.DidNavigateEvent) => void, useCapture?: boolean): void; - /** - * Emitted when an in-page navigation happened. - * - * When in-page navigation happens, the page URL changes but does not cause - * navigation outside of the page. Examples of this occurring are when anchor links - * are clicked or when the DOM hashchange event is triggered. - */ - addEventListener(type: 'did-navigate-in-page', listener: (event: WebViewElement.DidNavigateInPageEvent) => void, useCapture?: boolean): void; - /** - * Fired when the guest page attempts to close itself. - */ - addEventListener(type: 'close', listener: (event: WebViewElement.Event) => void, useCapture?: boolean): void; - /** - * Fired when the guest page has sent an asynchronous message to embedder page. - */ - addEventListener(type: 'ipc-message', listener: (event: WebViewElement.IpcMessageEvent) => void, useCapture?: boolean): void; - /** - * Fired when the renderer process is crashed. - */ - addEventListener(type: 'crashed', listener: (event: WebViewElement.Event) => void, useCapture?: boolean): void; - /** - * Fired when the gpu process is crashed. - */ - addEventListener(type: 'gpu-crashed', listener: (event: WebViewElement.Event) => void, useCapture?: boolean): void; - /** - * Fired when a plugin process is crashed. - */ - addEventListener(type: 'plugin-crashed', listener: (event: WebViewElement.PluginCrashedEvent) => void, useCapture?: boolean): void; - /** - * Fired when the WebContents is destroyed. - */ - addEventListener(type: 'destroyed', listener: (event: WebViewElement.Event) => void, useCapture?: boolean): void; - /** - * Emitted when media starts playing. - */ - addEventListener(type: 'media-started-playing', listener: (event: WebViewElement.Event) => void, useCapture?: boolean): void; - /** - * Emitted when media is paused or done playing. - */ - addEventListener(type: 'media-paused', listener: (event: WebViewElement.Event) => void, useCapture?: boolean): void; - /** - * Emitted when a page's theme color changes. This is usually due to encountering a meta tag: - * - */ - addEventListener(type: 'did-change-theme-color', listener: (event: WebViewElement.DidChangeThemeColorEvent) => void, useCapture?: boolean): void; - /** - * Emitted when mouse moves over a link or the keyboard moves the focus to a link. - */ - addEventListener(type: 'update-target-url', listener: (event: WebViewElement.UpdateTargetUrlEvent) => void, useCapture?: boolean): void; - /** - * Emitted when DevTools is opened. - */ - addEventListener(type: 'devtools-opened', listener: (event: WebViewElement.Event) => void, useCapture?: boolean): void; - /** - * Emitted when DevTools is closed. - */ - addEventListener(type: 'devtools-closed', listener: (event: WebViewElement.Event) => void, useCapture?: boolean): void; - /** - * Emitted when DevTools is focused / opened. - */ - addEventListener(type: 'devtools-focused', listener: (event: WebViewElement.Event) => void, useCapture?: boolean): void; - addEventListener(type: string, listener: (event: WebViewElement.Event) => void, useCapture?: boolean): void; - } - - namespace WebViewElement { - type Event = ElectronPrivate.GlobalEvent; - - interface LoadCommitEvent extends Event { - url: string; - isMainFrame: boolean; - } - - interface DidFailLoadEvent extends Event { - errorCode: number; - errorDescription: string; - validatedURL: string; - isMainFrame: boolean; - } - - interface DidFrameFinishLoadEvent extends Event { - isMainFrame: boolean; - } - - interface DidGetResponseDetails extends Event { - status: boolean; - newURL: string; - originalURL: string; - httpResponseCode: number; - requestMethod: string; - referrer: string; - headers: Headers; - resourceType: string; - } - - interface DidGetRedirectRequestEvent extends Event { - oldURL: string; - newURL: string; - isMainFrame: boolean; - httpResponseCode: number; - requestMethod: string; - referrer: string; - headers: Headers; - } - - interface PageTitleUpdatedEvent extends Event { - title: string; - explicitSet: string; - } - - interface PageFaviconUpdatedEvent extends Event { - favicons: string[]; - } - - interface ConsoleMessageEvent extends Event { - level: number; - message: string; - line: number; - sourceId: string; - } - - interface FoundInPageEvent extends Event { - result: FoundInPageResult; - } - - interface NewWindowEvent extends Event { - url: string; - frameName: string; - disposition: NewWindowDisposition; - options: BrowserWindowOptions; - } - - interface WillNavigateEvent extends Event { - url: string; - } - - interface DidNavigateEvent extends Event { - url: string; - } - - interface DidNavigateInPageEvent extends Event { - url: string; - isMainFrame: boolean; - } - - interface IpcMessageEvent extends Event { - channel: string; - args: any[]; - } - - interface PluginCrashedEvent extends Event { - name: string; - version: string; - } - - interface DidChangeThemeColorEvent extends Event { - themeColor: string; - } - - interface UpdateTargetUrlEvent extends Event { - url: string; - } - } - - /** - * The BrowserWindowProxy object is returned from window.open and provides limited functionality with the child window. - */ - interface BrowserWindowProxy { - /** - * Removes focus from the child window. - */ - blur(): void; - /** - * Forcefully closes the child window without calling its unload event. - */ - close(): void; - /** - * Set to true after the child window gets closed. - */ - closed: boolean; - /** - * Evaluates the code in the child window. - */ - eval(code: string): void; - /** - * Focuses the child window (brings the window to front). - */ - focus(): void; - /** - * Sends a message to the child window with the specified origin or * for no origin preference. - * In addition to these methods, the child window implements window.opener object with no - * properties and a single method. - */ - postMessage(message: string, targetOrigin: string): void; - /** - * Invokes the print dialog on the child window. - */ - print(): void; - } - - // https://github.com/electron/electron/blob/master/docs/api/synopsis.md - - interface CommonElectron { - clipboard: Electron.Clipboard; - crashReporter: Electron.CrashReporter; - nativeImage: typeof Electron.NativeImage; - shell: Electron.Shell; - - app: Electron.App; - autoUpdater: Electron.AutoUpdater; - BrowserWindow: typeof Electron.BrowserWindow; - contentTracing: Electron.ContentTracing; - dialog: Electron.Dialog; - ipcMain: Electron.IpcMain; - globalShortcut: Electron.GlobalShortcut; - Menu: typeof Electron.Menu; - MenuItem: typeof Electron.MenuItem; - net: Electron.Net; - powerMonitor: Electron.PowerMonitor; - powerSaveBlocker: Electron.PowerSaveBlocker; - protocol: Electron.Protocol; - screen: Electron.Screen; - session: typeof Electron.Session; - systemPreferences: Electron.SystemPreferences; - Tray: typeof Electron.Tray; - webContents: Electron.WebContentsStatic; - } - - interface ElectronMainAndRenderer extends CommonElectron { - desktopCapturer: Electron.DesktopCapturer; - ipcRenderer: Electron.IpcRenderer; - remote: Electron.Remote; - webFrame: Electron.WebFrame; - } -} - -declare namespace ElectronPrivate { - type GlobalEvent = Event; -} - -interface Document { - createElement(tagName: 'webview'): Electron.WebViewElement; -} - -// https://github.com/electron/electron/blob/master/docs/api/window-open.md - -interface Window { - /** - * Creates a new window. - */ - open(url: string, frameName?: string, features?: string): Electron.BrowserWindowProxy; -} - -// https://github.com/electron/electron/blob/master/docs/api/file-object.md - -interface File { - /** - * Exposes the real path of the filesystem. - */ - path: string; -} - -// https://github.com/electron/electron/blob/master/docs/api/process.md - -declare namespace NodeJS { - - interface ProcessVersions { - /** - * Electron's version string. - */ - electron: string; - /** - * Chrome's version string. - */ - chrome: string; - } - - interface Process { - /** - * Setting this to true can disable the support for asar archives in Node's built-in modules. - */ - noAsar?: boolean; - /** - * Process's type - */ - type: 'browser' | 'renderer'; - /** - * Path to JavaScript source code. - */ - resourcesPath: string; - /** - * For Mac App Store build, this value is true, for other builds it is undefined. - */ - mas?: boolean; - /** - * If the app is running as a Windows Store app (appx), this value is true, for other builds it is undefined. - */ - windowsStore?: boolean; - /** - * When app is started by being passed as parameter to the default app, - * this value is true in the main process, otherwise it is undefined. - */ - defaultApp?: boolean; - /** - * Emitted when Electron has loaded its internal initialization script - * and is beginning to load the web page or the main script. - */ - on(event: 'loaded', listener: Function): this; - on(event: string, listener: Function): this; - /** - * Causes the main thread of the current process crash; - */ - crash(): void; - /** - * Causes the main thread of the current process hang. - */ - hang(): void; - /** - * Sets the file descriptor soft limit to maxDescriptors or the OS hard limit, - * whichever is lower for the current process. - * - * Note: This API is only available on macOS and Linux. - */ - setFdLimit(maxDescriptors: number): void; - /** - * @returns Object giving memory usage statistics about the current process. - * Note: All statistics are reported in Kilobytes. - */ - getProcessMemoryInfo(): ProcessMemoryInfo; - /** - * @returns Object giving memory usage statistics about the entire system. - * Note: All statistics are reported in Kilobytes. - */ - getSystemMemoryInfo(): SystemMemoryInfo; - } - - interface ProcessMemoryInfo { - /** - * The amount of memory currently pinned to actual physical RAM. - */ - workingSetSize: number; - /** - * The maximum amount of memory that has ever been pinned to actual physical RAM. - */ - peakWorkingSetSize: number; - /** - * The amount of memory not shared by other processes, such as JS heap or HTML content. - */ - privateBytes: number; - /** - * The amount of memory shared between processes, typically memory consumed by the Electron code itself. - */ - sharedBytes: number; - } - - interface SystemMemoryInfo { - /** - * The total amount of physical memory available to the system. - */ - total: number; - /** - * The total amount of memory not being used by applications or disk cache. - */ - free: number; - /** - * The total amount of swap memory available to the system. - */ - swapTotal: number; - /** - * The free amount of swap memory available to the system. - */ - swapFree: number; - } -} - -declare module 'electron' { - var electron: Electron.ElectronMainAndRenderer; - export = electron; -} - -interface NodeRequireFunction { - (moduleName: 'electron'): Electron.ElectronMainAndRenderer; -} diff --git a/typings/globals/electron/typings.json b/typings/globals/electron/typings.json deleted file mode 100644 index bb769b9..0000000 --- a/typings/globals/electron/typings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "resolution": "main", - "tree": { - "src": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/8978f926e21860801db49d1fd9d3448b121b11e9/electron/index.d.ts", - "raw": "registry:dt/electron#1.4.8+20170202141310", - "typings": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/8978f926e21860801db49d1fd9d3448b121b11e9/electron/index.d.ts" - } -} diff --git a/typings/globals/mocha/index.d.ts b/typings/globals/mocha/index.d.ts deleted file mode 100644 index a9e4ce5..0000000 --- a/typings/globals/mocha/index.d.ts +++ /dev/null @@ -1,230 +0,0 @@ -// Generated by typings -// Source: https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/1a428e1fdb71c76e88da0b27f5a9df1e96294001/mocha/index.d.ts -interface MochaSetupOptions { - //milliseconds to wait before considering a test slow - slow?: number; - - // timeout in milliseconds - timeout?: number; - - // ui name "bdd", "tdd", "exports" etc - ui?: string; - - //array of accepted globals - globals?: any[]; - - // reporter instance (function or string), defaults to `mocha.reporters.Spec` - reporter?: any; - - // bail on the first test failure - bail?: boolean; - - // ignore global leaks - ignoreLeaks?: boolean; - - // grep string or regexp to filter tests with - grep?: any; -} - -declare var mocha: Mocha; -declare var describe: Mocha.IContextDefinition; -declare var xdescribe: Mocha.IContextDefinition; -// alias for `describe` -declare var context: Mocha.IContextDefinition; -// alias for `describe` -declare var suite: Mocha.IContextDefinition; -declare var it: Mocha.ITestDefinition; -declare var xit: Mocha.ITestDefinition; -// alias for `it` -declare var test: Mocha.ITestDefinition; -declare var specify: Mocha.ITestDefinition; - -// Used with the --delay flag; see https://mochajs.org/#hooks -declare function run(): void; - -interface MochaDone { - (error?: any): any; -} - -declare function setup(callback: (this: Mocha.IBeforeAndAfterContext, done: MochaDone) => any): void; -declare function teardown(callback: (this: Mocha.IBeforeAndAfterContext, done: MochaDone) => any): void; -declare function suiteSetup(callback: (this: Mocha.IHookCallbackContext, done: MochaDone) => any): void; -declare function suiteTeardown(callback: (this: Mocha.IHookCallbackContext, done: MochaDone) => any): void; -declare function before(callback: (this: Mocha.IHookCallbackContext, done: MochaDone) => any): void; -declare function before(description: string, callback: (this: Mocha.IHookCallbackContext, done: MochaDone) => any): void; -declare function after(callback: (this: Mocha.IHookCallbackContext, done: MochaDone) => any): void; -declare function after(description: string, callback: (this: Mocha.IHookCallbackContext, done: MochaDone) => any): void; -declare function beforeEach(callback: (this: Mocha.IBeforeAndAfterContext, done: MochaDone) => any): void; -declare function beforeEach(description: string, callback: (this: Mocha.IBeforeAndAfterContext, done: MochaDone) => any): void; -declare function afterEach(callback: (this: Mocha.IBeforeAndAfterContext, done: MochaDone) => any): void; -declare function afterEach(description: string, callback: (this: Mocha.IBeforeAndAfterContext, done: MochaDone) => any): void; - -declare class Mocha { - currentTest: Mocha.ITestDefinition; - constructor(options?: { - grep?: RegExp; - ui?: string; - reporter?: string; - timeout?: number; - reporterOptions?: any; - slow?: number; - bail?: boolean; - }); - - /** Setup mocha with the given options. */ - setup(options: MochaSetupOptions): Mocha; - bail(value?: boolean): Mocha; - addFile(file: string): Mocha; - /** Sets reporter by name, defaults to "spec". */ - reporter(name: string): Mocha; - /** Sets reporter constructor, defaults to mocha.reporters.Spec. */ - reporter(reporter: (runner: Mocha.IRunner, options: any) => any): Mocha; - ui(value: string): Mocha; - grep(value: string): Mocha; - grep(value: RegExp): Mocha; - invert(): Mocha; - ignoreLeaks(value: boolean): Mocha; - checkLeaks(): Mocha; - /** - * Function to allow assertion libraries to throw errors directly into mocha. - * This is useful when running tests in a browser because window.onerror will - * only receive the 'message' attribute of the Error. - */ - throwError(error: Error): void; - /** Enables growl support. */ - growl(): Mocha; - globals(value: string): Mocha; - globals(values: string[]): Mocha; - useColors(value: boolean): Mocha; - useInlineDiffs(value: boolean): Mocha; - timeout(value: number): Mocha; - slow(value: number): Mocha; - enableTimeouts(value: boolean): Mocha; - asyncOnly(value: boolean): Mocha; - noHighlighting(value: boolean): Mocha; - /** Runs tests and invokes `onComplete()` when finished. */ - run(onComplete?: (failures: number) => void): Mocha.IRunner; -} - -// merge the Mocha class declaration with a module -declare namespace Mocha { - interface ISuiteCallbackContext { - timeout(ms: number): void; - retries(n: number): void; - slow(ms: number): void; - } - - interface IHookCallbackContext { - skip(): void; - timeout(ms: number): void; - [index: string]: any; - } - - - interface ITestCallbackContext { - skip(): void; - timeout(ms: number): void; - retries(n: number): void; - slow(ms: number): void; - [index: string]: any; - } - - /** Partial interface for Mocha's `Runnable` class. */ - interface IRunnable { - title: string; - fn: Function; - async: boolean; - sync: boolean; - timedOut: boolean; - } - - /** Partial interface for Mocha's `Suite` class. */ - interface ISuite { - parent: ISuite; - title: string; - - fullTitle(): string; - } - - /** Partial interface for Mocha's `Test` class. */ - interface ITest extends IRunnable { - parent: ISuite; - pending: boolean; - state: 'failed'|'passed'|undefined; - - fullTitle(): string; - } - - interface IBeforeAndAfterContext extends IHookCallbackContext { - currentTest: ITest; - } - - - /** Partial interface for Mocha's `Runner` class. */ - interface IRunner { } - - interface IContextDefinition { - (description: string, callback: (this: ISuiteCallbackContext) => void): ISuite; - only(description: string, callback: (this: ISuiteCallbackContext) => void): ISuite; - skip(description: string, callback: (this: ISuiteCallbackContext) => void): void; - timeout(ms: number): void; - } - - interface ITestDefinition { - (expectation: string, callback?: (this: ITestCallbackContext, done: MochaDone) => any): ITest; - only(expectation: string, callback?: (this: ITestCallbackContext, done: MochaDone) => any): ITest; - skip(expectation: string, callback?: (this: ITestCallbackContext, done: MochaDone) => any): void; - timeout(ms: number): void; - state: "failed" | "passed"; - } - - export module reporters { - export class Base { - stats: { - suites: number; - tests: number; - passes: number; - pending: number; - failures: number; - }; - - constructor(runner: IRunner); - } - - export class Doc extends Base { } - export class Dot extends Base { } - export class HTML extends Base { } - export class HTMLCov extends Base { } - export class JSON extends Base { } - export class JSONCov extends Base { } - export class JSONStream extends Base { } - export class Landing extends Base { } - export class List extends Base { } - export class Markdown extends Base { } - export class Min extends Base { } - export class Nyan extends Base { } - export class Progress extends Base { - /** - * @param options.open String used to indicate the start of the progress bar. - * @param options.complete String used to indicate a complete test on the progress bar. - * @param options.incomplete String used to indicate an incomplete test on the progress bar. - * @param options.close String used to indicate the end of the progress bar. - */ - constructor(runner: IRunner, options?: { - open?: string; - complete?: string; - incomplete?: string; - close?: string; - }); - } - export class Spec extends Base { } - export class TAP extends Base { } - export class XUnit extends Base { - constructor(runner: IRunner, options?: any); - } - } -} - -declare module "mocha" { - export = Mocha; -} diff --git a/typings/globals/mocha/typings.json b/typings/globals/mocha/typings.json deleted file mode 100644 index 235edad..0000000 --- a/typings/globals/mocha/typings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "resolution": "main", - "tree": { - "src": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/1a428e1fdb71c76e88da0b27f5a9df1e96294001/mocha/index.d.ts", - "raw": "registry:dt/mocha#2.2.5+20170204022515", - "typings": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/1a428e1fdb71c76e88da0b27f5a9df1e96294001/mocha/index.d.ts" - } -} diff --git a/typings/globals/node/index.d.ts b/typings/globals/node/index.d.ts deleted file mode 100644 index ed20108..0000000 --- a/typings/globals/node/index.d.ts +++ /dev/null @@ -1,3630 +0,0 @@ -// Generated by typings -// Source: https://raw.githubusercontent.com/types/env-node/a5f9e16f769422e801156d494c45453670fc73cc/6.0/node.d.ts -interface NodeError { - /** - * Returns a string describing the point in the code at which the Error was instantiated. - * - * For example: - * - * ``` - * Error: Things keep happening! - * at /home/gbusey/file.js:525:2 - * at Frobnicator.refrobulate (/home/gbusey/business-logic.js:424:21) - * at Actor. (/home/gbusey/actors.js:400:8) - * at increaseSynergy (/home/gbusey/actors.js:701:6) - * ``` - * - * The first line is formatted as : , and is followed by a series of stack frames (each line beginning with "at "). Each frame describes a call site within the code that lead to the error being generated. V8 attempts to display a name for each function (by variable name, function name, or object method name), but occasionally it will not be able to find a suitable name. If V8 cannot determine a name for the function, only location information will be displayed for that frame. Otherwise, the determined function name will be displayed with location information appended in parentheses. - */ - stack?: string; - - /** - * Returns the string description of error as set by calling new Error(message). The message passed to the constructor will also appear in the first line of the stack trace of the Error, however changing this property after the Error object is created may not change the first line of the stack trace. - * - * ``` - * const err = new Error('The message'); - * console.log(err.message); - * // Prints: The message - * ``` - */ - message: string; -} - -interface Error extends NodeError { } - -interface ErrorConstructor { - /** - * Creates a `.stack` property on `targetObject`, which when accessed returns a string representing the location in the code at which `Error.captureStackTrace()`` was called. - * - * ```js - * const myObject = {}; - * Error.captureStackTrace(myObject); - * myObject.stack // similar to `new Error().stack` - * ``` - * - * The first line of the trace, instead of being prefixed with `ErrorType : message`, will be the result of calling `targetObject.toString()``. - * - * The optional constructorOpt argument accepts a function. If given, all frames above constructorOpt, including constructorOpt, will be omitted from the generated stack trace. - * - * The constructorOpt argument is useful for hiding implementation details of error generation from an end user. For instance: - * - * ```js - * function MyError() { - * Error.captureStackTrace(this, MyError); - * } - * - * // Without passing MyError to captureStackTrace, the MyError - * // frame would should up in the .stack property. by passing - * // the constructor, we omit that frame and all frames above it. - * new MyError().stack - * ``` - */ - captureStackTrace(targetObject: T, constructorOpt?: new () => T): void; - - /** - * The Error.stackTraceLimit property specifies the number of stack frames collected by a stack trace (whether generated by `new Error().stack` or `Error.captureStackTrace(obj))``. - * - * The default value is 10 but may be set to any valid JavaScript number. Changes will affect any stack trace captured after the value has been changed. - * - * If set to a non-number value, or set to a negative number, stack traces will not capture any frames. - */ - stackTraceLimit: number; -} - -/************************************************ -* * -* GLOBAL * -* * -************************************************/ -declare var process: NodeJS.Process; -declare var global: NodeJS.Global; - -declare var __filename: string; -declare var __dirname: string; - -declare function setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): NodeJS.Timer; -declare function clearTimeout(timeoutId: NodeJS.Timer): void; -declare function setInterval(callback: (...args: any[]) => void, ms: number, ...args: any[]): NodeJS.Timer; -declare function clearInterval(intervalId: NodeJS.Timer): void; -declare function setImmediate(callback: (...args: any[]) => void, ...args: any[]): any; -declare function clearImmediate(immediateId: any): void; - -interface NodeRequireFunction { - (id: string): any; -} - -interface NodeRequire extends NodeRequireFunction { - resolve(id: string): string; - cache: { [filename: string]: NodeModule }; - extensions: NodeExtensions; - main: any; -} - -interface NodeExtensions { - '.js': (m: NodeModule, filename: string) => any; - '.json': (m: NodeModule, filename: string) => any; - '.node': (m: NodeModule, filename: string) => any; - [ext: string]: (m: NodeModule, filename: string) => any; -} - -declare var require: NodeRequire; - -declare class NodeModule { - static runMain(): void; - static wrap(code: string): string; - static _nodeModulePaths(path: string): string[]; - static _load(request: string, parent?: NodeModule, isMain?: boolean): any; - static _resolveFilename(request: string, parent?: NodeModule, isMain?: boolean): string; - static _extensions: NodeExtensions; - - constructor(filename: string); - _compile(code: string, filename: string): string; - - id: string; - parent: NodeModule; - filename: string; - paths: string[]; - children: NodeModule[]; - exports: any; - loaded: boolean; - require: NodeRequireFunction; -} - -declare var module: NodeModule; - -// Same as module.exports -declare var exports: any; -declare var SlowBuffer: { - new (str: string, encoding?: string): Buffer; - new (size: number): Buffer; - new (size: Uint8Array): Buffer; - new (array: any[]): Buffer; - prototype: Buffer; - isBuffer(obj: any): boolean; - byteLength(string: string, encoding?: string): number; - concat(list: Buffer[], totalLength?: number): Buffer; -}; - -// Console class (compatible with TypeScript `lib.d.ts`). -declare interface Console { - log(msg: any, ...params: any[]): void; - info(msg: any, ...params: any[]): void; - warn(msg: any, ...params: any[]): void; - error(msg: any, ...params: any[]): void; - dir(value: any, ...params: any[]): void; - time(timerName?: string): void; - timeEnd(timerName?: string): void; - trace(msg: any, ...params: any[]): void; - assert(test?: boolean, msg?: string, ...params: any[]): void; - - Console: new (stdout: NodeJS.WritableStream) => Console; -} - -declare var console: Console; - -declare class Buffer extends Uint8Array { - [index: number]: number; - /** - * Allocates a new buffer containing the given {str}. - * - * @param str String to store in buffer. - * @param encoding encoding to use, optional. Default is 'utf8' - */ - constructor(str: string, encoding?: string); - /** - * Allocates a new buffer of {size} octets. - * - * @param size count of octets to allocate. - */ - constructor(size: number); - /** - * Allocates a new buffer containing the given {array} of octets. - * - * @param array The octets to store. - */ - constructor(array: Uint8Array); - /** - * Produces a Buffer backed by the same allocated memory as - * the given {ArrayBuffer}. - * - * - * @param arrayBuffer The ArrayBuffer with which to share memory. - */ - constructor(arrayBuffer: ArrayBuffer); - /** - * Allocates a new buffer containing the given {array} of octets. - * - * @param array The octets to store. - */ - constructor(array: any[]); - /** - * Copies the passed {buffer} data onto a new {Buffer} instance. - * - * @param buffer The buffer to copy. - */ - constructor(buffer: Buffer); - /** - * Allocates a new Buffer using an {array} of octets. - * - * @param array - */ - static from(array: any[]): Buffer; - /** - * When passed a reference to the .buffer property of a TypedArray instance, - * the newly created Buffer will share the same allocated memory as the TypedArray. - * The optional {byteOffset} and {length} arguments specify a memory range - * within the {arrayBuffer} that will be shared by the Buffer. - * - * @param arrayBuffer The .buffer property of a TypedArray or a new ArrayBuffer() - * @param byteOffset - * @param length - */ - static from(arrayBuffer: ArrayBuffer, byteOffset?: number, length?: number): Buffer; - /** - * Copies the passed {buffer} data onto a new Buffer instance. - * - * @param buffer - */ - static from(buffer: Buffer): Buffer; - /** - * Creates a new Buffer containing the given JavaScript string {str}. - * If provided, the {encoding} parameter identifies the character encoding. - * If not provided, {encoding} defaults to 'utf8'. - * - * @param str - */ - static from(str: string, encoding?: string): Buffer; - /** - * Allocates a new `Buffer` of `size` bytes. If `fill` is `undefined`, the `Buffer` will be _zero-filled_. - * - * @param size The desired length of the new `Buffer` - * @param fill A value to pre-fill the new `Buffer` with. Default: `0` - * @param encoding If `fill` is a string, this is its encoding. Default: `'utf8'` - */ - static alloc(size: number, fill?: string | Buffer | number, encoding?: string): Buffer; - /** - * Allocates a new _non-zero-filled_ `Buffer` of `size` bytes. The `size` must be less than or equal to the value of `buffer.kMaxLength`. Otherwise, a `RangeError` is thrown. A zero-length `Buffer` will be created if `size <= 0`. - * - * The underlying memory for `Buffer` instances created in this way is not initialized. The contents of the newly created `Buffer` are unknown and _may contain sensitive data_. Use `buf.fill(0)` to initialize such `Buffer` instances to zeroes. - * - * @param size The desired length of the new `Buffer` - */ - static allocUnsafe(size: number): Buffer; - /** - * Returns `true` if `obj` is a Buffer, `false` otherwise. - */ - static isBuffer(obj: any): obj is Buffer; - /** - * Returns `true` if `encoding` contains a supported character encoding, or `false` otherwise. - * - * @param encoding A character encoding name to check. - */ - static isEncoding(encoding: string): boolean; - /** - * Gives the actual byte length of a string. encoding defaults to 'utf8'. - * This is not the same as String.prototype.length since that returns the number of characters in a string. - * - * @param string string to test. - * @param encoding encoding used to evaluate (defaults to 'utf8') - */ - static byteLength(string: string, encoding?: string): number; - /** - * Returns a buffer which is the result of concatenating all the buffers in the list together. - * - * If the list has no items, or if the totalLength is 0, then it returns a zero-length buffer. - * If the list has exactly one item, then the first item of the list is returned. - * If the list has more than one item, then a new Buffer is created. - * - * @param list An array of Buffer objects to concatenate - * @param totalLength Total length of the buffers when concatenated. - * If totalLength is not provided, it is read from the buffers in the list. However, this adds an additional loop to the function, so it is faster to provide the length explicitly. - */ - static concat(list: Buffer[], totalLength?: number): Buffer; - /** - * The same as buf1.compare(buf2). - */ - compare(buf1: Buffer, buf2: Buffer): number; - write(string: string, offset?: number, length?: number, encoding?: string): number; - toString(encoding?: string, start?: number, end?: number): string; - toJSON(): any; - equals(otherBuffer: Buffer): boolean; - compare(otherBuffer: Buffer): number; - copy(targetBuffer: Buffer, targetStart?: number, sourceStart?: number, sourceEnd?: number): number; - slice(start?: number, end?: number): Buffer; - writeUIntLE(value: number, offset: number, byteLength: number, noAssert?: boolean): number; - writeUIntBE(value: number, offset: number, byteLength: number, noAssert?: boolean): number; - writeIntLE(value: number, offset: number, byteLength: number, noAssert?: boolean): number; - writeIntBE(value: number, offset: number, byteLength: number, noAssert?: boolean): number; - readUIntLE(offset: number, byteLength: number, noAssert?: boolean): number; - readUIntBE(offset: number, byteLength: number, noAssert?: boolean): number; - readIntLE(offset: number, byteLength: number, noAssert?: boolean): number; - readIntBE(offset: number, byteLength: number, noAssert?: boolean): number; - readUInt8(offset: number, noAssert?: boolean): number; - readUInt16LE(offset: number, noAssert?: boolean): number; - readUInt16BE(offset: number, noAssert?: boolean): number; - readUInt32LE(offset: number, noAssert?: boolean): number; - readUInt32BE(offset: number, noAssert?: boolean): number; - readInt8(offset: number, noAssert?: boolean): number; - readInt16LE(offset: number, noAssert?: boolean): number; - readInt16BE(offset: number, noAssert?: boolean): number; - readInt32LE(offset: number, noAssert?: boolean): number; - readInt32BE(offset: number, noAssert?: boolean): number; - readFloatLE(offset: number, noAssert?: boolean): number; - readFloatBE(offset: number, noAssert?: boolean): number; - readDoubleLE(offset: number, noAssert?: boolean): number; - readDoubleBE(offset: number, noAssert?: boolean): number; - writeUInt8(value: number, offset: number, noAssert?: boolean): number; - writeUInt16LE(value: number, offset: number, noAssert?: boolean): number; - writeUInt16BE(value: number, offset: number, noAssert?: boolean): number; - writeUInt32LE(value: number, offset: number, noAssert?: boolean): number; - writeUInt32BE(value: number, offset: number, noAssert?: boolean): number; - writeInt8(value: number, offset: number, noAssert?: boolean): number; - writeInt16LE(value: number, offset: number, noAssert?: boolean): number; - writeInt16BE(value: number, offset: number, noAssert?: boolean): number; - writeInt32LE(value: number, offset: number, noAssert?: boolean): number; - writeInt32BE(value: number, offset: number, noAssert?: boolean): number; - writeFloatLE(value: number, offset: number, noAssert?: boolean): number; - writeFloatBE(value: number, offset: number, noAssert?: boolean): number; - writeDoubleLE(value: number, offset: number, noAssert?: boolean): number; - writeDoubleBE(value: number, offset: number, noAssert?: boolean): number; - fill(value: any, offset?: number, end?: number): this; - indexOf(value: string | number | Buffer, byteOffset?: number, encoding?: string): number; - lastIndexOf(value: string | number | Buffer, byteOffset?: number, encoding?: string): number; - swap16(): this; - swap32(): this; - swap64(): this; - includes(value: string | number | Buffer, byteOffset?: number, encoding?: string): boolean; - entries(): IterableIterator<[number, number]>; - keys(): IterableIterator; - values(): IterableIterator; -} - -/************************************************ -* * -* GLOBAL INTERFACES * -* * -************************************************/ -declare namespace NodeJS { - export interface ErrnoException extends Error { - errno?: number; - code?: string; - path?: string; - syscall?: string; - stack?: string; - } - - export interface EventEmitter { - addListener(event: string, listener: Function): this; - on(event: string, listener: Function): this; - once(event: string, listener: Function): this; - prependListener(event: string, listener: Function): this; - prependOnceListener(event: string, listener: Function): this; - removeListener(event: string, listener: Function): this; - removeAllListeners(event?: string): this; - setMaxListeners(n: number): this; - getMaxListeners(): number; - listeners(event: string): Function[]; - emit(event: string, ...args: any[]): boolean; - eventNames(): string[]; - listenerCount(type: string): number; - } - - export interface ReadableStream extends EventEmitter { - readable: boolean; - read(size?: number): string | Buffer; - setEncoding(encoding: string): this; - isPaused(): boolean; - pause(): this; - resume(): this; - pipe(destination: T, options?: { end?: boolean; }): T; - unpipe(destination?: T): void; - unshift(chunk: string): void; - unshift(chunk: Buffer): void; - wrap(oldStream: ReadableStream): ReadableStream; - } - - export interface WritableStream extends EventEmitter { - writable: boolean; - setDefaultEncoding(encoding: string): this; - write(buffer: Buffer | string, cb?: Function): boolean; - write(str: string, encoding?: string, cb?: Function): boolean; - end(): void; - end(buffer: Buffer, cb?: Function): void; - end(str: string, cb?: Function): void; - end(str: string, encoding?: string, cb?: Function): void; - } - - export interface ReadWriteStream extends ReadableStream, WritableStream { } - - export interface Events extends EventEmitter { } - - export interface Domain extends Events { - run(fn: Function): void; - add(emitter: Events): void; - remove(emitter: Events): void; - bind(cb: (err: Error, data: any) => any): any; - intercept(cb: (data: any) => any): any; - dispose(): void; - - addListener(event: string, listener: Function): this; - on(event: string, listener: Function): this; - once(event: string, listener: Function): this; - removeListener(event: string, listener: Function): this; - removeAllListeners(event?: string): this; - } - - export interface MemoryUsage { - rss: number; - heapTotal: number; - heapUsed: number; - } - - export interface Env { - PATH: string; - [key: string]: string; - } - - export interface Versions { - http_parser: string; - node: string; - v8: string; - ares: string; - uv: string; - zlib: string; - modules: string; - openssl: string; - } - - export interface Process extends EventEmitter { - stdout: WritableStream; - stderr: WritableStream; - stdin: ReadableStream; - argv: string[]; - argv0: string; - /** - * The process.execArgv property returns the set of Node.js-specific command-line options passed when the Node.js process was launched. These options do not appear in the array returned by the process.argv property, and do not include the Node.js executable, the name of the script, or any options following the script name. These options are useful in order to spawn child processes with the same execution environment as the parent. - */ - execArgv: string[]; - execPath: string; - abort(): void; - chdir(directory: string): void; - cwd(): string; - env: Env; - exit(code?: number): void; - exitCode?: number; - getgid(): number; - setgid(id: number): void; - setgid(id: string): void; - getuid(): number; - setuid(id: number): void; - setuid(id: string): void; - version: string; - versions: Versions; - config: { - target_defaults: { - cflags: any[]; - default_configuration: string; - defines: string[]; - include_dirs: string[]; - libraries: string[]; - }; - variables: { - clang: number; - host_arch: string; - node_install_npm: boolean; - node_install_waf: boolean; - node_prefix: string; - node_shared_openssl: boolean; - node_shared_v8: boolean; - node_shared_zlib: boolean; - node_use_dtrace: boolean; - node_use_etw: boolean; - node_use_openssl: boolean; - target_arch: string; - v8_no_strict_aliasing: number; - v8_use_snapshot: boolean; - visibility: string; - }; - }; - kill(pid: number, signal?: string | number): void; - pid: number; - title: string; - arch: string; - platform: string; - memoryUsage(): MemoryUsage; - nextTick(callback: Function): void; - umask(mask?: number): number; - uptime(): number; - hrtime(time?: [number, number]): [number, number]; - domain: Domain; - - // Worker - send?(message: any, sendHandle?: any): void; - disconnect(): void; - connected: boolean; - } - - export interface Global { - Array: typeof Array; - ArrayBuffer: typeof ArrayBuffer; - Boolean: typeof Boolean; - Buffer: typeof Buffer; - DataView: typeof DataView; - Date: typeof Date; - Error: typeof Error; - EvalError: typeof EvalError; - Float32Array: typeof Float32Array; - Float64Array: typeof Float64Array; - Function: typeof Function; - GLOBAL: Global; - Infinity: typeof Infinity; - Int16Array: typeof Int16Array; - Int32Array: typeof Int32Array; - Int8Array: typeof Int8Array; - Intl: typeof Intl; - JSON: typeof JSON; - Map: MapConstructor; - Math: typeof Math; - NaN: typeof NaN; - Number: typeof Number; - Object: typeof Object; - Promise: Function; - RangeError: typeof RangeError; - ReferenceError: typeof ReferenceError; - RegExp: typeof RegExp; - Set: SetConstructor; - String: typeof String; - Symbol: Function; - SyntaxError: typeof SyntaxError; - TypeError: typeof TypeError; - URIError: typeof URIError; - Uint16Array: typeof Uint16Array; - Uint32Array: typeof Uint32Array; - Uint8Array: typeof Uint8Array; - Uint8ClampedArray: Function; - WeakMap: WeakMapConstructor; - WeakSet: WeakSetConstructor; - clearImmediate: (immediateId: any) => void; - clearInterval: (intervalId: NodeJS.Timer) => void; - clearTimeout: (timeoutId: NodeJS.Timer) => void; - console: typeof console; - decodeURI: typeof decodeURI; - decodeURIComponent: typeof decodeURIComponent; - encodeURI: typeof encodeURI; - encodeURIComponent: typeof encodeURIComponent; - escape: (str: string) => string; - eval: typeof eval; - global: Global; - isFinite: typeof isFinite; - isNaN: typeof isNaN; - parseFloat: typeof parseFloat; - parseInt: typeof parseInt; - process: Process; - root: Global; - setImmediate: (callback: (...args: any[]) => void, ...args: any[]) => any; - setInterval: (callback: (...args: any[]) => void, ms: number, ...args: any[]) => NodeJS.Timer; - setTimeout: (callback: (...args: any[]) => void, ms: number, ...args: any[]) => NodeJS.Timer; - undefined: typeof undefined; - unescape: (str: string) => string; - gc: () => void; - v8debug?: any; - } - - export interface Timer { - ref(): void; - unref(): void; - _called: boolean; - _onTimeout: Function; - _timerArgs?: any[]; - } - - export interface Immediate { - _argv?: any[]; - _callback: Function; - _onImmediate: Function; - } -} - -/************************************************ -* * -* MODULES * -* * -************************************************/ -declare module "buffer" { - export var INSPECT_MAX_BYTES: number; - export var kMaxLength: number; - - export type Encoding = "ascii" | "latin1" | "binary" | "utf8" | "utf-8" | "ucs2" | "ucs-2" | "utf16le" | "utf-16le" | "hex" | "base64"; - - var BuffType: typeof Buffer; - var SlowBuffType: typeof SlowBuffer; - - export { BuffType as Buffer, SlowBuffType as SlowBuffer }; -} - -declare module "querystring" { - export interface StringifyOptions { - encodeURIComponent?: Function; - } - - export interface ParseOptions { - maxKeys?: number; - decodeURIComponent?: Function; - } - - export function stringify(obj: T, sep?: string, eq?: string, options?: StringifyOptions): string; - export function parse(str: string, sep?: string, eq?: string, options?: ParseOptions): any; - export function parse(str: string, sep?: string, eq?: string, options?: ParseOptions): T; - export function escape(str: string): string; - export function unescape(str: string): string; -} - -declare module "events" { - export class EventEmitter implements NodeJS.EventEmitter { - static EventEmitter: EventEmitter; - static listenerCount(emitter: EventEmitter, event: string): number; // deprecated - static defaultMaxListeners: number; - - addListener(event: string, listener: (...args: any[]) => void): this; - on(event: string, listener: (...args: any[]) => void): this; - once(event: string, listener: (...args: any[]) => void): this; - prependListener(event: string, listener: (...args: any[]) => void): this; - prependOnceListener(event: string, listener: (...args: any[]) => void): this; - removeListener(event: string, listener: (...args: any[]) => void): this; - removeAllListeners(event?: string): this; - setMaxListeners(n: number): this; - getMaxListeners(): number; - listeners(event: string): Array<(...args: any[]) => void>; - listenerCount(event: string): number; - emit(event: string, ...args: any[]): boolean; - eventNames(): string[]; - } - - export interface Listener { - on(event: E, listener: L): this; - once(event: E, listener: L): this; - addListener(event: E, listener: L): this; - removeListener(event: E, listener: L): this; - listeners(event: E): L[]; - } -} - -declare module "http" { - import * as events from "events"; - import * as net from "net"; - import * as stream from "stream"; - - export interface OutgoingHeaders { - [header: string]: number | string | string[]; - } - - export interface IncomingHeaders { - [header: string]: string | string[]; - } - - export interface RequestOptions { - protocol?: string; - host?: string; - hostname?: string; - family?: number; - port?: number | string; - localAddress?: string; - socketPath?: string; - method?: string; - path?: string; - headers?: OutgoingHeaders; - auth?: string; - agent?: Agent | boolean; - } - - export class Server extends net.Server { - constructor(req: IncomingMessage, res: ServerResponse); - setTimeout(msecs: number, callback: Function): void; - maxHeadersCount: number; - timeout: number; - listening: boolean; - } - - export class OutgoingMessage extends stream.Writable { - finished: boolean; - sendDate: boolean; - headersSent: boolean; - - constructor(); - setTimeout(msecs: number, callback?: () => void): this; - setHeader(name: string, value: number | string | string[]): void; - getHeader(name: string): number | string | string[] | undefined; - removeHeader(name: string): void; - addTrailers(headers: OutgoingHeaders): void; - } - - export class ServerResponse extends OutgoingMessage { - statusCode: number; - statusMessage: string; - - constructor(req: IncomingMessage); - writeContinue(cb?: () => void): void; - writeHead(statusCode: number, statusText?: string, headers?: OutgoingHeaders): void; - writeHead(statusCode: number, headers?: OutgoingHeaders): void; - assignSocket(socket: stream.Writable): void; - detachSocket(socket: stream.Writable): void; - } - - export class ClientRequest extends OutgoingMessage { - constructor(options: string | RequestOptions, cb?: (res: IncomingMessage) => void); - abort(): void; - setNoDelay(noDelay?: boolean): void; - setSocketKeepAlive(enable?: boolean, initialDelay?: number): void; - } - - export class IncomingMessage extends stream.Readable { - httpVersion: string; - headers: IncomingHeaders; - rawHeaders: string[]; - trailers: IncomingHeaders; - rawTrailers: string[]; - /** - * Only valid for request obtained from http.Server. - */ - method?: string; - /** - * Only valid for request obtained from http.Server. - */ - url?: string; - /** - * Only valid for response obtained from http.ClientRequest. - */ - statusCode?: number; - /** - * Only valid for response obtained from http.ClientRequest. - */ - statusMessage?: string; - socket: net.Socket; - - constructor(socket: net.Socket); - setTimeout(msecs: number, callback?: () => void): this; - destroy(error?: Error): void; - } - - export interface AgentOptions { - /** - * Keep sockets around in a pool to be used by other requests in the future. Default = false - */ - keepAlive?: boolean; - /** - * When using HTTP KeepAlive, how often to send TCP KeepAlive packets over sockets being kept alive. Default = 1000. - * Only relevant if keepAlive is set to true. - */ - keepAliveMsecs?: number; - /** - * Maximum number of sockets to allow per host. Default for Node 0.10 is 5, default for Node 0.12 is Infinity - */ - maxSockets?: number; - /** - * Maximum number of sockets to leave open in a free state. Only relevant if keepAlive is set to true. Default = 256. - */ - maxFreeSockets?: number; - } - - export class Agent { - maxSockets: number; - sockets: any; - requests: any; - - constructor(opts?: AgentOptions); - - /** - * Destroy any sockets that are currently in use by the agent. - * It is usually not necessary to do this. However, if you are using an agent with KeepAlive enabled, - * then it is best to explicitly shut down the agent when you know that it will no longer be used. Otherwise, - * sockets may hang open for quite a long time before the server terminates them. - */ - destroy(): void; - } - - export var METHODS: string[]; - - export var STATUS_CODES: { - [errorCode: number]: string; - [errorCode: string]: string; - }; - - export function createServer(requestListener?: (request: IncomingMessage, response: ServerResponse) => void): Server; - export function createClient(port?: number, host?: string): any; - export function request(options: string | RequestOptions, callback?: (res: IncomingMessage) => void): ClientRequest; - export function get(options: string | RequestOptions, callback?: (res: IncomingMessage) => void): ClientRequest; - export var globalAgent: Agent; -} - -declare module "cluster" { - import * as child from "child_process"; - import * as events from "events"; - - export interface ClusterSettings { - exec?: string; - args?: string[]; - silent?: boolean; - } - - export interface Address { - address: string; - port: number; - addressType: string; - } - - export class Worker extends events.EventEmitter { - id: string; - process: child.ChildProcess; - suicide: boolean; - send(message: any, sendHandle?: any): boolean; - kill(signal?: string): void; - destroy(signal?: string): void; - disconnect(): void; - isConnected(): boolean; - isDead(): boolean; - } - - export var settings: ClusterSettings; - export var isMaster: boolean; - export var isWorker: boolean; - export function setupMaster(settings?: ClusterSettings): void; - export function fork(env?: any): Worker; - export function disconnect(callback?: Function): void; - export var worker: Worker; - export var workers: { - [index: string]: Worker - }; - - // Event emitter - export function addListener(event: string, listener: Function): void; - export function on(event: "disconnect", listener: (worker: Worker) => void): void; - export function on(event: "exit", listener: (worker: Worker, code: number, signal: string) => void): void; - export function on(event: "fork", listener: (worker: Worker) => void): void; - export function on(event: "listening", listener: (worker: Worker, address: any) => void): void; - export function on(event: "message", listener: (worker: Worker, message: any) => void): void; - export function on(event: "online", listener: (worker: Worker) => void): void; - export function on(event: "setup", listener: (settings: any) => void): void; - export function on(event: string, listener: Function): any; - export function once(event: string, listener: Function): void; - export function removeListener(event: string, listener: Function): void; - export function removeAllListeners(event?: string): void; - export function setMaxListeners(n: number): void; - export function listeners(event: string): Function[]; - export function emit(event: string, ...args: any[]): boolean; -} - -declare module "zlib" { - import * as stream from "stream"; - - export interface ZlibOptions { chunkSize?: number; windowBits?: number; level?: number; memLevel?: number; strategy?: number; dictionary?: any; } - export interface ZlibCallback { (error: Error, result: any): void } - - export interface Gzip extends stream.Transform { } - export interface Gunzip extends stream.Transform { } - export interface Deflate extends stream.Transform { } - export interface Inflate extends stream.Transform { } - export interface DeflateRaw extends stream.Transform { } - export interface InflateRaw extends stream.Transform { } - export interface Unzip extends stream.Transform { } - - export function createGzip(options?: ZlibOptions): Gzip; - export function createGunzip(options?: ZlibOptions): Gunzip; - export function createDeflate(options?: ZlibOptions): Deflate; - export function createInflate(options?: ZlibOptions): Inflate; - export function createDeflateRaw(options?: ZlibOptions): DeflateRaw; - export function createInflateRaw(options?: ZlibOptions): InflateRaw; - export function createUnzip(options?: ZlibOptions): Unzip; - - export function deflate(buf: Buffer | string, callback?: ZlibCallback): void; - export function deflate(buf: Buffer | string, options: ZlibOptions, callback?: ZlibCallback): void; - export function deflateSync(buf: Buffer | string, options?: ZlibOptions): any; - export function deflateRaw(buf: Buffer | string, callback?: ZlibCallback): void; - export function deflateRaw(buf: Buffer | string, options: ZlibOptions, callback?: ZlibCallback): void; - export function deflateRawSync(buf: Buffer | string, options?: ZlibOptions): any; - export function gzip(buf: Buffer | string, callback?: ZlibCallback): void; - export function gzip(buf: Buffer | string, options: ZlibOptions, callback?: ZlibCallback): void; - export function gzipSync(buf: Buffer | string, options?: ZlibOptions): any; - export function gunzip(buf: Buffer | string, callback?: ZlibCallback): void; - export function gunzip(buf: Buffer | string, options: ZlibOptions, callback?: ZlibCallback): void; - export function gunzipSync(buf: Buffer | string, options?: ZlibOptions): any; - export function inflate(buf: Buffer | string, callback?: ZlibCallback): void; - export function inflate(buf: Buffer | string, options: ZlibOptions, callback?: ZlibCallback): void; - export function inflateSync(buf: Buffer | string, options?: ZlibOptions): any; - export function inflateRaw(buf: Buffer | string, callback?: ZlibCallback): void; - export function inflateRaw(buf: Buffer | string, options: ZlibOptions, callback?: ZlibCallback): void; - export function inflateRawSync(buf: Buffer | string, options?: ZlibOptions): any; - export function unzip(buf: Buffer | string, callback?: ZlibCallback): void; - export function unzip(buf: Buffer | string, options: ZlibOptions, callback?: ZlibCallback): void; - export function unzipSync(buf: Buffer | string, options?: ZlibOptions): any; - - // Constants - export var Z_NO_FLUSH: number; - export var Z_PARTIAL_FLUSH: number; - export var Z_SYNC_FLUSH: number; - export var Z_FULL_FLUSH: number; - export var Z_FINISH: number; - export var Z_BLOCK: number; - export var Z_TREES: number; - export var Z_OK: number; - export var Z_STREAM_END: number; - export var Z_NEED_DICT: number; - export var Z_ERRNO: number; - export var Z_STREAM_ERROR: number; - export var Z_DATA_ERROR: number; - export var Z_MEM_ERROR: number; - export var Z_BUF_ERROR: number; - export var Z_VERSION_ERROR: number; - export var Z_NO_COMPRESSION: number; - export var Z_BEST_SPEED: number; - export var Z_BEST_COMPRESSION: number; - export var Z_DEFAULT_COMPRESSION: number; - export var Z_FILTERED: number; - export var Z_HUFFMAN_ONLY: number; - export var Z_RLE: number; - export var Z_FIXED: number; - export var Z_DEFAULT_STRATEGY: number; - export var Z_BINARY: number; - export var Z_TEXT: number; - export var Z_ASCII: number; - export var Z_UNKNOWN: number; - export var Z_DEFLATED: number; - export var Z_NULL: number; -} - -declare module "os" { - export interface CpuInfo { - model: string; - speed: number; - times: { - user: number; - nice: number; - sys: number; - idle: number; - irq: number; - }; - } - - export interface NetworkInterfaceInfo { - address: string; - netmask: string; - family: string; - mac: string; - internal: boolean; - } - - export function tmpdir(): string; - export function homedir(): string; - export function endianness(): "BE" | "LE"; - export function hostname(): string; - export function type(): string; - export function platform(): string; - export function arch(): string; - export function release(): string; - export function uptime(): number; - export function loadavg(): number[]; - export function totalmem(): number; - export function freemem(): number; - export function cpus(): CpuInfo[]; - export function networkInterfaces(): { [index: string]: NetworkInterfaceInfo[] }; - export function userInfo(options?: { encoding: 'buffer' }): { username: Buffer, uid: number, gid: number, shell: Buffer | null, homedir: Buffer } - export function userInfo(options?: { encoding: string }): { username: string, uid: number, gid: number, shell: string | null, homedir: string } - export var EOL: string; -} - -declare module "https" { - import * as tls from "tls"; - import * as events from "events"; - import * as http from "http"; - - export interface ServerOptions { - pfx?: any; - key?: any; - passphrase?: string; - cert?: any; - ca?: any; - crl?: any; - ciphers?: string; - honorCipherOrder?: boolean; - requestCert?: boolean; - rejectUnauthorized?: boolean; - NPNProtocols?: any; - SNICallback?: (servername: string) => any; - } - - export interface RequestOptions extends http.RequestOptions { - pfx?: string | Buffer; - key?: string | Buffer; - passphrase?: string; - cert?: string | Buffer; - ca?: string | Buffer | string[] | Buffer[]; - ciphers?: string; - rejectUnauthorized?: boolean; - secureProtocol?: string; - } - - export interface AgentOptions extends http.AgentOptions { - /** - * Certificate, Private key and CA certificates to use for SSL. Default `null`. - */ - pfx?: string | Buffer; - /** - * Private key to use for SSL. Default `null`. - */ - key?: string | Buffer | string[] | Buffer[]; - /** - * A string of passphrase for the private key or pfx. Default `null`. - */ - passphrase?: string; - /** - * Public x509 certificate to use. Default `null`. - */ - cert?: string | Buffer | string[] | Buffer[]; - /** - * A string, `Buffer`, array of strings, or array of `Buffer`s of trusted certificates in PEM format. If this is omitted several well known "root" CAs (like VeriSign) will be used. These are used to authorize connections. - */ - ca?: string | Buffer | string[] | Buffer[]; - /** - * A string describing the ciphers to use or exclude. Consult https://www.openssl.org/docs/apps/ciphers.html#CIPHER-LIST-FORMAT for details on the format. - */ - ciphers?: string; - /** - * If `true`, the server certificate is verified against the list of supplied CAs. An `'error'` event is emitted if verification fails. Verification happens at the connection level, before the HTTP request is sent. Default `true`. - */ - rejectUnauthorized?: boolean; - /** - * Servername for SNI (Server Name Indication) TLS extension. - */ - servername?: string; - /** - * The SSL method to use, e.g. `SSLv3_method` to force SSL version 3. The possible values depend on your installation of OpenSSL and are defined in the constant SSL_METHODS. - */ - secureProtocol?: string; - maxCachedSessions?: number; - } - - export class Agent extends http.Agent { - constructor(options?: AgentOptions); - } - - export class Server extends tls.Server { } - - export function createServer(options: ServerOptions, requestListener?: Function): Server; - export function request(options: string | RequestOptions, callback?: (res: http.IncomingMessage) => void): http.ClientRequest; - export function get(options: string | RequestOptions, callback?: (res: http.IncomingMessage) => void): http.ClientRequest; - export var globalAgent: Agent; -} - -declare module "punycode" { - export function decode(string: string): string; - export function encode(string: string): string; - export function toUnicode(domain: string): string; - export function toASCII(domain: string): string; - export var ucs2: ucs2; - interface ucs2 { - decode(string: string): number[]; - encode(codePoints: number[]): string; - } - export var version: any; -} - -declare module "repl" { - import { EventEmitter } from "events"; - import { Interface } from "readline"; - - export interface ReplOptions { - prompt?: string; - input?: NodeJS.ReadableStream; - output?: NodeJS.WritableStream; - terminal?: boolean; - eval?: Function; - useColors?: boolean; - useGlobal?: boolean; - ignoreUndefined?: boolean; - writer?: Function; - completer?: Function; - replMode?: symbol; - breakEvalOnSigint?: boolean; - } - - export function start(options: ReplOptions): REPLServer; - - export type REPLCommand = (this: REPLServer, rest: string) => void; - - export class REPLServer extends Interface { - inputStream: NodeJS.ReadableStream; - outputStream: NodeJS.WritableStream; - useColors: boolean; - commands: { - [command: string]: REPLCommand; - }; - defineCommand(keyword: string, cmd: REPLCommand | { help: string, action: REPLCommand }): void; - displayPrompt(preserveCursor?: boolean): void; - setPrompt(prompt: string): void; - turnOffEditorMode(): void; - } - - export class Recoverable extends SyntaxError { - err: Error; - constructor(err: Error); - } -} - -declare module "readline" { - import * as events from "events"; - import * as stream from "stream"; - - export interface Key { - sequence?: string; - name?: string; - ctrl?: boolean; - meta?: boolean; - shift?: boolean; - } - - export class Interface extends events.EventEmitter { - setPrompt(prompt: string): void; - prompt(preserveCursor?: boolean): void; - question(query: string, callback: (answer: string) => void): void; - pause(): this; - resume(): this; - close(): void; - write(data: string | Buffer, key?: Key): void; - } - - export interface Completer { - (line: string): CompleterResult; - (line: string, callback: (err: any, result: CompleterResult) => void): any; - } - - export interface CompleterResult { - completions: string[]; - line: string; - } - - export interface InterfaceOptions { - input: NodeJS.ReadableStream; - output?: NodeJS.WritableStream; - completer?: Completer; - terminal?: boolean; - historySize?: number; - } - - export function createInterface(input: NodeJS.ReadableStream, output?: NodeJS.WritableStream, completer?: Completer, terminal?: boolean): Interface; - export function createInterface(options: InterfaceOptions): Interface; - - export function cursorTo(stream: NodeJS.WritableStream, x: number, y: number): void; - export function moveCursor(stream: NodeJS.WritableStream, dx: number | string, dy: number | string): void; - export function clearLine(stream: NodeJS.WritableStream, dir: number): void; - export function clearScreenDown(stream: NodeJS.WritableStream): void; -} - -declare module "vm" { - export interface Context { } - - export interface ScriptOptions { - filename?: string; - lineOffset?: number; - columnOffset?: number; - displayErrors?: boolean; - timeout?: number; - cachedData?: Buffer; - produceCachedData?: boolean; - } - - export interface RunInNewContextOptions { - filename?: string; - lineOffset?: number; - columnOffset?: number; - displayErrors?: boolean; - timeout?: number; - } - - export interface RunInContextOptions extends RunInNewContextOptions { - breakOnSigint?: boolean; - } - - export class Script { - constructor(code: string, options?: string | ScriptOptions); - runInContext(contextifiedSandbox: Context, options?: RunInContextOptions): any; - runInNewContext(sandbox?: Context, options?: RunInNewContextOptions): any; - runInThisContext(options?: RunInNewContextOptions): any; - } - - export function createContext(sandbox?: Context): Context; - export function isContext(sandbox: Context): boolean; - export function runInContext(code: string, contextifiedSandbox: Context, options?: string | RunInNewContextOptions): any; - export function runInDebugContext(code: string): any; - export function runInNewContext(code: string, sandbox?: Context, options?: string | RunInNewContextOptions): any; - export function runInThisContext(code: string, options?: string | RunInNewContextOptions): any; - /** - * @deprecated - */ - export function createScript(code: string, options?: string | ScriptOptions): Script; -} - -declare module "child_process" { - import * as events from "events"; - import * as stream from "stream"; - import * as buffer from "buffer"; - import * as net from "net"; - - export class ChildProcess extends events.EventEmitter implements - events.Listener<'close', (code: number, signal: string) => void>, - events.Listener<'error', (error: Error) => void>, - events.Listener<'exit', ((code: number, signal: string | null) => void) | ((code: number | null, signal: string) => void)>, - events.Listener<'message', (message: any, sendHandle?: net.Socket | net.Server) => void>, - events.Listener<'disconnect', () => void> { - stdin: stream.Writable; - stdout: stream.Readable; - stderr: stream.Readable; - stdio: [stream.Writable, stream.Readable, stream.Readable]; - pid: number; - kill(signal?: string): void; - send(message: any, sendHandle?: any): boolean; - connected: boolean; - disconnect(): void; - unref(): void; - } - - export interface SpawnOptions { - cwd?: string; - env?: any; - stdio?: any; - detached?: boolean; - uid?: number; - gid?: number; - shell?: boolean | string; - } - - export function spawn(command: string, args?: string[], options?: SpawnOptions): ChildProcess; - - export interface ExecOptions { - cwd?: string; - env?: any; - shell?: string; - timeout?: number; - maxBuffer?: number; - killSignal?: string; - uid?: number; - gid?: number; - encoding?: buffer.Encoding | 'buffer'; - } - - export function exec(command: string, callback?: (error: Error, stdout: string, stderr: string) => void): ChildProcess; - export function exec(command: string, options: ExecOptions & { encoding: 'buffer' }, callback?: (error: Error, stdout: Buffer, stderr: Buffer) => void): ChildProcess; - export function exec(command: string, options: ExecOptions, callback?: (error: Error, stdout: string, stderr: string) => void): ChildProcess; - - export interface ExecFileOptions { - cwd?: string; - env?: any; - timeout?: number; - maxBuffer?: number; - killSignal?: string; - uid?: number; - gid?: number; - encoding?: buffer.Encoding | 'buffer'; - } - - export function execFile(file: string, callback?: (error: Error, stdout: string, stderr: string) => void): ChildProcess; - export function execFile(file: string, options?: ExecFileOptions & { encoding: 'buffer' }, callback?: (error: Error, stdout: Buffer, stderr: Buffer) => void): ChildProcess; - export function execFile(file: string, options?: ExecFileOptions, callback?: (error: Error, stdout: string, stderr: string) => void): ChildProcess; - export function execFile(file: string, args?: string[], callback?: (error: Error, stdout: string, stderr: string) => void): ChildProcess; - export function execFile(file: string, args?: string[], options?: ExecFileOptions & { encoding: 'buffer' }, callback?: (error: Error, stdout: Buffer, stderr: Buffer) => void): ChildProcess; - export function execFile(file: string, args?: string[], options?: ExecFileOptions, callback?: (error: Error, stdout: string, stderr: string) => void): ChildProcess; - - export interface ForkOptions { - cwd?: string; - env?: any; - execPath?: string; - execArgv?: string[]; - silent?: boolean; - uid?: number; - gid?: number; - } - - export function fork(modulePath: string, args?: string[], options?: ForkOptions): ChildProcess; - - export interface SpawnSyncOptions { - cwd?: string; - input?: string | Buffer; - stdio?: any; - env?: any; - uid?: number; - gid?: number; - timeout?: number; - killSignal?: string; - maxBuffer?: number; - shell?: boolean | string; - encoding?: buffer.Encoding | 'buffer'; - } - - export interface SpawnSyncReturns { - pid: number; - output: string[]; - stdout: T; - stderr: T; - status: number; - signal: string; - error: Error; - } - export function spawnSync(command: string): SpawnSyncReturns; - export function spawnSync(command: string, options?: SpawnSyncOptions & { encoding: 'buffer' }): SpawnSyncReturns; - export function spawnSync(command: string, options?: SpawnSyncOptions): SpawnSyncReturns; - export function spawnSync(command: string, args?: string[], options?: SpawnSyncOptions & { encoding: 'buffer' }): SpawnSyncReturns; - export function spawnSync(command: string, args?: string[], options?: SpawnSyncOptions): SpawnSyncReturns; - - export interface ExecSyncOptions { - cwd?: string; - input?: string | Buffer; - stdio?: any; - env?: any; - shell?: string; - uid?: number; - gid?: number; - timeout?: number; - killSignal?: string; - maxBuffer?: number; - encoding?: buffer.Encoding | 'buffer'; - } - - export function execSync(command: string): Buffer; - export function execSync(command: string, options?: ExecSyncOptions & { encoding: 'buffer' }): Buffer; - export function execSync(command: string, options?: ExecSyncOptions): Buffer; - - export interface ExecFileSyncOptions { - cwd?: string; - input?: string | Buffer; - stdio?: any; - env?: any; - uid?: number; - gid?: number; - timeout?: number; - killSignal?: string; - maxBuffer?: number; - encoding?: buffer.Encoding | 'buffer'; - } - - export function execFileSync(command: string): Buffer; - export function execFileSync(command: string, options?: ExecFileSyncOptions & { encoding: 'buffer' }): Buffer; - export function execFileSync(command: string, options?: ExecFileSyncOptions): Buffer; - export function execFileSync(command: string, args?: string[], options?: ExecFileSyncOptions & { encoding: 'buffer' }): Buffer; - export function execFileSync(command: string, args?: string[], options?: ExecFileSyncOptions): Buffer; -} - -declare module "url" { - export interface Url { - href?: string; - protocol?: string; - auth?: string; - hostname?: string; - port?: string; - host?: string; - pathname?: string; - search?: string; - query?: string | any; - slashes?: boolean; - hash?: string; - path?: string; - } - - export function parse(urlStr: string, parseQueryString?: boolean, slashesDenoteHost?: boolean): Url; - export function format(url: Url | string): string; - export function resolve(from: string, to: string): string; -} - -declare module "dns" { - export function lookup(domain: string, family: number, callback: (err: Error, address: string, family: number) => void): string; - export function lookup(domain: string, callback: (err: Error, address: string, family: number) => void): string; - export function resolve(domain: string, rrtype: string, callback: (err: Error, addresses: string[]) => void): string[]; - export function resolve(domain: string, callback: (err: Error, addresses: string[]) => void): string[]; - export function resolve4(domain: string, callback: (err: Error, addresses: string[]) => void): string[]; - export function resolve6(domain: string, callback: (err: Error, addresses: string[]) => void): string[]; - export function resolveMx(domain: string, callback: (err: Error, addresses: string[]) => void): string[]; - export function resolveTxt(domain: string, callback: (err: Error, addresses: string[]) => void): string[]; - export function resolveSrv(domain: string, callback: (err: Error, addresses: string[]) => void): string[]; - export function resolveNs(domain: string, callback: (err: Error, addresses: string[]) => void): string[]; - export function resolveCname(domain: string, callback: (err: Error, addresses: string[]) => void): string[]; - export function reverse(ip: string, callback: (err: Error, domains: string[]) => void): string[]; - - export const NODATA: 'ENODATA'; - export const FORMERR: 'EFORMERR'; - export const SERVFAIL: 'ESERVFAIL'; - export const NOTFOUND: 'ENOTFOUND'; - export const NOTIMP: 'ENOTIMP'; - export const REFUSED: 'EREFUSED'; - export const BADQUERY: 'EBADQUERY'; - export const BADNAME: 'EBADNAME'; - export const BADFAMILY: 'EBADFAMILY'; - export const BADRESP: 'EBADRESP'; - export const CONNREFUSED: 'ECONNREFUSED'; - export const TIMEOUT: 'ETIMEOUT'; - export const EOF: 'EOF'; - export const FILE: 'EFILE'; - export const NOMEM: 'ENOMEM'; - export const DESTRUCTION: 'EDESTRUCTION'; - export const BADSTR: 'EBADSTR'; - export const BADFLAGS: 'EBADFLAGS'; - export const NONAME: 'ENONAME'; - export const BADHINTS: 'EBADHINTS'; - export const NOTINITIALIZED: 'ENOTINITIALIZED'; - export const LOADIPHLPAPI: 'ELOADIPHLPAPI'; - export const ADDRGETNETWORKPARAMS: 'EADDRGETNETWORKPARAMS'; - export const CANCELLED: 'ECANCELLED'; -} - -declare module "net" { - import * as stream from "stream"; - - export class Socket extends stream.Duplex { - constructor(options?: { fd?: string; type?: string; allowHalfOpen?: boolean; }); - - connect(port: number, host?: string, connectionListener?: Function): void; - connect(path: string, connectionListener?: Function): void; - bufferSize: number; - destroy(): void; - setTimeout(timeout: number, callback?: Function): void; - setNoDelay(noDelay?: boolean): void; - setKeepAlive(enable?: boolean, initialDelay?: number): void; - address(): { port: number; family: string; address: string; }; - unref(): void; - ref(): void; - - remoteAddress: string; - remoteFamily: string; - remotePort: number; - localAddress: string; - localPort: number; - bytesRead: number; - bytesWritten: number; - } - - export interface ListenOptions { - port?: number; - host?: string; - backlog?: number; - path?: string; - exclusive?: boolean; - } - - export class Server extends Socket { - listen(port: number, hostname?: string, backlog?: number, listeningListener?: Function): this; - listen(port: number, hostname?: string, listeningListener?: Function): this; - listen(port: number, backlog?: number, listeningListener?: Function): this; - listen(port: number, listeningListener?: Function): this; - listen(path: string, backlog?: number, listeningListener?: Function): this; - listen(path: string, listeningListener?: Function): this; - listen(handle: any, backlog?: number, listeningListener?: Function): this; - listen(handle: any, listeningListener?: Function): this; - listen(options: ListenOptions, listeningListener?: Function): this; - close(callback?: () => void): this; - address(): { port: number; family: string; address: string; }; - getConnections(cb: (error: Error, count: number) => void): void; - ref(): this; - unref(): this; - maxConnections: number; - connections: number; - } - - export function createServer(connectionListener?: (socket: Socket) => void): Server; - export function createServer(options?: { allowHalfOpen?: boolean; }, connectionListener?: (socket: Socket) => void): Server; - export function connect(options: { port: number, host?: string, localAddress?: string, localPort?: string, family?: number, allowHalfOpen?: boolean; }, connectionListener?: Function): Socket; - export function connect(port: number, host?: string, connectionListener?: Function): Socket; - export function connect(path: string, connectionListener?: Function): Socket; - export function createConnection(options: { port: number, host?: string, localAddress?: string, localPort?: string, family?: number, allowHalfOpen?: boolean; }, connectionListener?: Function): Socket; - export function createConnection(port: number, host?: string, connectionListener?: Function): Socket; - export function createConnection(path: string, connectionListener?: Function): Socket; - export function isIP(input: string): number; - export function isIPv4(input: string): boolean; - export function isIPv6(input: string): boolean; -} - -declare module "dgram" { - import * as events from "events"; - - export interface RemoteInfo { - address: string; - port: number; - size: number; - } - - export interface AddressInfo { - address: string; - family: string; - port: number; - } - - export interface BindOptions { - port: number; - address?: string; - exclusive?: boolean; - } - - export interface SocketOptions { - type: string; - reuseAddr?: boolean; - } - - export function createSocket(type: string | SocketOptions, callback?: (msg: Buffer, rinfo: RemoteInfo) => void): Socket; - - export class Socket extends events.EventEmitter { - send(msg: Buffer | string | Array, offset: number, length: number, port: number, address: string, callback?: (error: Error, bytes: number) => void): void; - send(msg: Buffer | string | Array, port: number, address: string, callback?: (error: Error, bytes: number) => void): void; - bind(port: number, address?: string, callback?: () => void): void; - bind(options: BindOptions, callback?: () => void): void; - close(callback?: () => void): void; - setTTL(ttl: number): void; - address(): AddressInfo; - setBroadcast(flag: boolean): void; - setMulticastTTL(ttl: number): void; - setMulticastLoopback(flag: boolean): void; - addMembership(multicastAddress: string, multicastInterface?: string): void; - dropMembership(multicastAddress: string, multicastInterface?: string): void; - ref(): void; - unref(): void; - } -} - -declare module "fs" { - import * as stream from "stream"; - import * as events from "events"; - import * as buffer from "buffer"; - - /** - * Objects returned from `fs.stat()`, `fs.lstat()` and `fs.fstat()` and their synchronous counterparts are of this type. - */ - export class Stats { - isFile(): boolean; - isDirectory(): boolean; - isBlockDevice(): boolean; - isCharacterDevice(): boolean; - isSymbolicLink(): boolean; - isFIFO(): boolean; - isSocket(): boolean; - dev: number; - ino: number; - mode: number; - nlink: number; - uid: number; - gid: number; - rdev: number; - size: number; - blksize: number; - blocks: number; - /** - * "Access Time" - Time when file data last accessed. Changed by the `mknod(2)`, `utimes(2)`, and `read(2)` system calls. - */ - atime: Date; - /** - * "Modified Time" - Time when file data last modified. Changed by the `mknod(2)`, `utimes(2)`, and `write(2)` system calls. - */ - mtime: Date; - /** - * "Change Time" - Time when file status was last changed (inode data modification). Changed by the `chmod(2)`, `chown(2)`, `link(2)`, `mknod(2)`, `rename(2)`, `unlink(2)`,` utimes(2)`, `read(2)`, and `write(2)` system calls. - */ - ctime: Date; - /** - * "Birth Time" - Time of file creation. Set once when the file is created. On filesystems where birthtime is not available, this field may instead hold either the `ctime` or `1970-01-01T00:00Z` (ie, unix epoch timestamp `0`). Note that this value may be greater than `atime` or `mtime` in this case. On Darwin and other FreeBSD variants, also set if the `atime` is explicitly set to an earlier value than the current `birthtime` using the `utimes(2)` system call. - */ - birthtime: Date; - } - - export type WatchListener = (eventType: string, filename?: string | Buffer) => void; - - /** - * Objects returned from fs.watch() are of this type. - */ - export class FSWatcher extends events.EventEmitter implements - events.Listener<'change', WatchListener> { - close(): void; - } - - export class ReadStream extends stream.Readable implements - events.Listener<'open', (fd: number) => void>, - events.Listener<'close', () => void> { - bytesRead: number; - path: string | Buffer; - close(): void; - destroy(): void; - } - - export class WriteStream extends stream.Writable implements - events.Listener<'open', (fd: number) => void>, - events.Listener<'close', () => void> { - close(): void; - bytesWritten: number; - path: string | Buffer; - } - - export const F_OK: number; - export const R_OK: number; - export const W_OK: number; - export const X_OK: number; - - export const constants: { - O_RDONLY: number; - O_WRONLY: number; - O_RDWR: number; - S_IFMT: number; - S_IFREG: number; - S_IFDIR: number; - S_IFCHR: number; - S_IFBLK: number; - S_IFIFO: number; - S_IFLNK: number; - S_IFSOCK: number; - O_CREAT: number; - O_EXCL: number; - O_NOCTTY: number; - O_TRUNC: number; - O_APPEND: number; - O_DIRECTORY: number; - O_NOFOLLOW: number; - O_SYNC: number; - O_SYMLINK: number; - O_NONBLOCK: number; - S_IRWXU: number; - S_IRUSR: number; - S_IWUSR: number; - S_IXUSR: number; - S_IRWXG: number; - S_IRGRP: number; - S_IWGRP: number; - S_IXGRP: number; - S_IRWXO: number; - S_IROTH: number; - S_IWOTH: number; - S_IXOTH: number; - F_OK: number; - R_OK: number; - W_OK: number; - X_OK: number; - [key: string]: number; - } - - /** - * Tests a user's permissions for the file or directory specified by `path`. The `mode` argument is an optional integer that specifies the accessibility checks to be performed. The following constants define the possible values of `mode`. It is possible to create a mask consisting of the bitwise OR of two or more values. - */ - export function access(path: string | Buffer, callback: (err: NodeJS.ErrnoException | null) => void): void; - export function access(path: string | Buffer, mode: number, callback: (err: NodeJS.ErrnoException | null) => void): void; - - /** - * Synchronous version of `fs.access()`. This throws if any accessibility checks fail, and does nothing otherwise. - */ - export function accessSync(path: string | Buffer, mode?: number): void; - - export interface AppendFileOptions { - encoding?: buffer.Encoding; - mode?: number; - flag?: string; - } - - /** - * Asynchronously append data to a file, creating the file if it does not yet exist. `data` can be a string or a buffer. - */ - export function appendFile(file: string | Buffer | number, data: string | Buffer, callback: (err: NodeJS.ErrnoException | null) => void): void; - export function appendFile(file: string | Buffer | number, data: string | Buffer, options: buffer.Encoding | AppendFileOptions | null, callback: (err: NodeJS.ErrnoException | null) => void): void; - - /** - * The synchronous version of `fs.appendFile()`. - */ - export function appendFileSync(file: string | Buffer | number, data: string | Buffer, options?: AppendFileOptions | null): void; - - /** - * Asynchronous chmod(2). - */ - export function chmod(path: string | Buffer, mode: number, callback: (err: NodeJS.ErrnoException | null) => void): void; - - /** - * Synchronous chmod(2). - */ - export function chmodSync(path: string | Buffer, mode: number): void; - - /** - * Asynchronous chown(2). - */ - export function chown(path: string | Buffer, uid: number, gid: number, callback: (err: NodeJS.ErrnoException | null) => void): void; - - /** - * Synchronous chown(2). - */ - export function chownSync(path: string | Buffer, uid: number, gid: number): void; - - /** - * Asynchronous close(2). - */ - export function close(fd: number, callback: (err: NodeJS.ErrnoException | null) => void): void; - - /** - * Synchronous close(2). - */ - export function closeSync(fd: number): void; - - export interface ReadStreamOptions { - flags?: string; - encoding?: buffer.Encoding; - fd?: number; - mode?: number; - autoClose?: boolean; - start?: number; - end?: number; - } - - /** - * Returns a new ReadStream object. - * - * Be aware that, unlike the default value set for `highWaterMark` on a readable stream (16 kb), the stream returned by this method has a default value of 64 kb for the same parameter. - */ - export function createReadStream(path: string | Buffer, options?: ReadStreamOptions | null): ReadStream; - - export interface WriteStreamOptions { - flags?: string; - defaultEncoding?: buffer.Encoding; - fd?: number; - mode?: number; - autoClose?: boolean; - start: number; - end: number; - } - - /** - * Returns a new WriteStream object. - */ - export function createWriteStream(path: string | Buffer, options?: WriteStreamOptions | null): WriteStream; - - /** - * Test whether or not the given path exists by checking with the file system. Then call the `callback` argument with either true or false. - * - * @deprecated - */ - export function exists(path: string | Buffer, callback: (exists: boolean) => void): void; - - /** - * Synchronous version of `fs.exists()`. Returns true if the file exists, false otherwise. - */ - export function existsSync(path: string | Buffer): boolean; - - /** - * Asynchronous fchmod(2). - */ - export function fchmod(fd: number, mode: number, callback: (err: NodeJS.ErrnoException | null) => void): void; - - /** - * Synchronous fchmod(2). - */ - export function fchmodSync(fd: number, mode: number): void; - - /** - * Asynchronous fchown(2). - */ - export function fchown(fd: number, uid: number, gid: number, callback: (err: NodeJS.ErrnoException | null) => void): void; - - /** - * Synchronous fchown(2). - */ - export function fchownSync(fd: number, uid: number, gid: number): void; - - /** - * Asynchronous fdatasync(2). - */ - export function fdatasync(fd: number, callback: (err: NodeJS.ErrnoException | null) => void): void; - - /** - * Synchronous fdatasync(2). - */ - export function fdatasyncSync(fd: number): void; - - /** - * Asynchronous fstat(2). - */ - export function fstat(fd: number, callback: (err: NodeJS.ErrnoException | null, stats: Stats) => void): void; - - /** - * Synchronous fstat(2). - */ - export function fstatSync(fd: number): Stats; - - /** - * Asynchronous fsync(2). - */ - export function fsync(fd: number, callback: (err: NodeJS.ErrnoException | null) => void): void; - - /** - * Synchronous fsync(2). - */ - export function fsyncSync(fd: number): void; - - /** - * Asynchronous ftruncate(2). - * - * If the file referred to by the file descriptor was larger than `len` bytes, only the first `len` bytes will be retained in the file. - * - * If the file previously was shorter than `len` bytes, it is extended, and the extended part is filled with null bytes ('\0'). - */ - export function ftruncate(fd: number, len: number | null | undefined, callback: (err: NodeJS.ErrnoException | null) => void): void; - - /** - * Synchronous ftruncate(2). - */ - export function ftruncateSync(fd: number, len?: number | null): void; - - /** - * Change the file timestamps of a file referenced by the supplied file descriptor. - */ - export function futimes(fd: number, atime: number, mtime: number, callback: (err: NodeJS.ErrnoException | null) => void): void; - - /** - * Synchronous version of `fs.futimes()`. - */ - export function futimesSync(fd: number, atime: number, mtime: number): void; - - /** - * Asynchronous lchmod(2). - * - * Only available on Mac OS X. - * - * @deprecated - */ - export function lchmod(path: string | Buffer, mode: number, callback: (err: NodeJS.ErrnoException | null) => void): void; - - /** - * Synchronous lchmod(2). - * - * @deprecated - */ - export function lchmodSync(path: string | Buffer, mode: number): void; - - /** - * Asynchronous lchown(2). - * - * @deprecated - */ - export function lchown(path: string | Buffer, uid: number, gid: number, callback: (err: NodeJS.ErrnoException | null) => void): void; - - /** - * Synchronous lchown(2). - * - * @deprecated - */ - export function lchownSync(path: string | Buffer, uid: number, gid: number): void; - - /** - * Asynchronous link(2). - */ - export function link(existingPath: string | Buffer, newPath: string | Buffer, callback: (err: NodeJS.ErrnoException | null) => void): void; - - /** - * Synchronous link(2). - */ - export function linkSync(existingPath: string | Buffer, newPath: string | Buffer): void; - - /** - * Asynchronous lstat(2). `lstat()` is identical to `stat()`, except that if `path` is a symbolic link, then the link itself is stat-ed, not the file that it refers to. - */ - export function lstat(path: string | Buffer, callback: (err: NodeJS.ErrnoException | null, stats: Stats) => void): void; - - /** - * Synchronous lstat(2). - */ - export function lstatSync(path: string | Buffer): Stats; - - /** - * Asynchronous mkdir(2). `mode` defaults to `0o777`. - */ - export function mkdir(path: string | Buffer, callback: (err: NodeJS.ErrnoException | null) => void): void; - export function mkdir(path: string | Buffer, mode: number, callback: (err: NodeJS.ErrnoException | null) => void): void; - - /** - * Synchronous mkdir(2). - */ - export function mkdirSync(path: string | Buffer, mode?: number): void; - - export interface MkdtempOptions { - encoding: buffer.Encoding; - } - - /** - * Creates a unique temporary directory. - * - * Generates six random characters to be appended behind a required prefix to create a unique temporary directory. - * - * The created folder path is passed as a string to the callback's second parameter. - */ - export function mkdtemp(prefix: string, callback: (err: NodeJS.ErrnoException | null, dir: string) => void): void; - export function mkdtemp(prefix: string, options: buffer.Encoding | MkdtempOptions | null, callback: (err: NodeJS.ErrnoException | null, dir: string) => void): void; - - /** - * The synchronous version of fs.mkdtemp(). Returns the created folder path. - */ - export function mkdtempSync(prefix: string, options?: buffer.Encoding | MkdtempOptions | null): string; - - /** - * Asynchronous file open. See open(2). `flags` can be: - * - * 'r' - Open file for reading. An exception occurs if the file does not exist. - * - * 'r+' - Open file for reading and writing. An exception occurs if the file does not exist. - * - * 'rs+' - Open file for reading and writing in synchronous mode. Instructs the operating system to bypass the local file system cache. - * - * This is primarily useful for opening files on NFS mounts as it allows you to skip the potentially stale local cache. It has a very real impact on I/O performance so don't use this flag unless you need it. - * - * Note that this doesn't turn `fs.open()` into a synchronous blocking call. If that's what you want then you should be using `fs.openSync()` - * - * 'w' - Open file for writing. The file is created (if it does not exist) or truncated (if it exists). - * - * 'wx' - Like `'w'` but fails if `path` exists. - * - * 'w+' - Open file for reading and writing. The file is created (if it does not exist) or truncated (if it exists). - * - * 'wx+' - Like `'w+'` but fails if `path` exists. - * - * 'a' - Open file for appending. The file is created if it does not exist. - * - * 'ax' - Like 'a' but fails if `path` exists. - * - * 'a+' - Open file for reading and appending. The file is created if it does not exist. - * - * 'ax+' - Like 'a+' but fails if `path` exists. - * - * `mode` sets the file mode (permission and sticky bits), but only if the file was created. It defaults to `0666`, readable and writable. - */ - export function open(path: string | Buffer, flags: string | number, callback: (err: NodeJS.ErrnoException | null, fd: number) => void): void; - export function open(path: string | Buffer, flags: string | number, mode: number, callback: (err: NodeJS.ErrnoException | null, fd: number) => void): void; - - /** - * Synchronous version of `fs.open()`. - */ - export function openSync(path: string | Buffer, flags: string | number, mode?: number): number; - - /** - * Read data from the file specified by fd. - * - * @param buffer is the buffer that the data will be written to. - * @param offset is the offset in the buffer to start writing at. - * @param length is an integer specifying the number of bytes to read. - * @param position is an integer specifying where to begin reading from in the file. If position is null, data will be read from the current file position. - */ - export function read(fd: number, buffer: string | Buffer, offset: number, length: number, position: number, callback: (err: NodeJS.ErrnoException | null, bytesRead: number, buffer: Buffer) => void): void; - - export interface ReaddirOptions { - encoding?: buffer.Encoding | 'buffer'; - } - - /** - * Asynchronous readdir(3). Reads the contents of a directory. - * - * @param files is an array of the names of the files in the directory excluding '.' and '..'. - */ - export function readdir(path: string | Buffer, callback: (err: NodeJS.ErrnoException | null, files: string[]) => void): void; - export function readdir(path: string | Buffer, options: 'buffer' | (ReadFileOptions & { encoding: 'buffer' }), callback: (err: NodeJS.ErrnoException | null, files: Buffer[]) => void): void; - export function readdir(path: string | Buffer, options: buffer.Encoding | ReaddirOptions | null, callback: (err: NodeJS.ErrnoException | null, files: string[]) => void): void; - - /** - * Synchronous readdir(3). Returns an array of filenames excluding '.' and '..'. - */ - export function readdirSync(path: string | Buffer): string[]; - export function readdirSync(path: string | Buffer, options: 'buffer' | (ReaddirOptions & { encoding: 'buffer' })): Buffer[]; - export function readdirSync(path: string | Buffer, options: buffer.Encoding | ReaddirOptions | null): string[]; - - export interface ReadFileOptions { - encoding?: buffer.Encoding | 'buffer'; - flag?: string; - } - - /** - * Asynchronously reads the entire contents of a file. - */ - export function readFile(file: string | Buffer | number, callback: (err: NodeJS.ErrnoException | null, data: Buffer) => void): void; - export function readFile(file: string | Buffer | number, options: buffer.Encoding | (ReadFileOptions & { encoding: buffer.Encoding }), callback: (err: NodeJS.ErrnoException | null, data: string) => void): void; - export function readFile(file: string | Buffer | number, options: 'buffer' | ReadFileOptions | null, callback: (err: NodeJS.ErrnoException | null, data: Buffer) => void): void; - - /** - * Synchronous version of `fs.readFile`. - */ - export function readFileSync(file: string | Buffer | number): Buffer; - export function readFileSync(file: string | Buffer | number, options: buffer.Encoding | (ReadFileOptions & { encoding: buffer.Encoding })): string; - export function readFileSync(file: string | Buffer | number, options: 'buffer' | ReadFileOptions | null): Buffer; - - export interface ReadlinkOptions { - encoding?: buffer.Encoding | 'buffer'; - } - - /** - * Asynchronous readlink(2). - */ - export function readlink(path: string | Buffer, callback: (err: NodeJS.ErrnoException | null, linkString: string) => void): void; - export function readlink(path: string | Buffer, options: 'buffer' | (ReadlinkOptions & { encoding: 'buffer' }), callback: (err: NodeJS.ErrnoException | null, linkString: Buffer) => void): void; - export function readlink(path: string | Buffer, options: buffer.Encoding | ReadlinkOptions | null, callback: (err: NodeJS.ErrnoException | null, linkString: Buffer) => void): void; - - /** - * Synchronous readlink(2). - */ - export function readlinkSync(path: string | Buffer): string; - export function readlinkSync(path: string | Buffer, options: 'buffer' | (ReadlinkOptions & { encoding: 'buffer' })): Buffer; - export function readlinkSync(path: string | Buffer, options: buffer.Encoding | ReadlinkOptions | null): string; - - /** - * Synchronous version of `fs.read()`. - */ - export function readSync(fd: number, buffer: string | Buffer, offset: number, length: number, position: number): number; - - export interface RealpathOptions { - encoding?: buffer.Encoding | 'buffer'; - } - - /** - * Asynchronous realpath(3). May use `process.cwd` to resolve relative paths. - * - * Only paths that can be converted to UTF8 strings are supported. - */ - export function realpath(path: string | Buffer, callback: (err: NodeJS.ErrnoException | null, resolvedPath: string) => void): void; - export function realpath(path: string | Buffer, options: 'buffer' | (RealpathOptions & { encoding: 'buffer' }), callback: (err: NodeJS.ErrnoException | null, resolvedPath: Buffer) => void): void; - export function realpath(path: string | Buffer, options: buffer.Encoding | RealpathOptions | null, callback: (err: NodeJS.ErrnoException | null, resolvedPath: Buffer) => void): void; - - /** - * Synchronous realpath(3). Returns the resolved path. - * - * Only paths that can be converted to UTF8 strings are supported. - */ - export function realpathSync(path: string | Buffer): string; - export function realpathSync(path: string | Buffer, options: 'buffer' | (RealpathOptions & { encoding: 'buffer' })): Buffer; - export function realpathSync(path: string | Buffer, options: buffer.Encoding | RealpathOptions | null): string; - - /** - * Asynchronous rename(2). - */ - export function rename(oldPath: string | Buffer, newPath: string | Buffer, callback: (err: NodeJS.ErrnoException | null) => void): void; - - /** - * Synchronous rename(2). - */ - export function renameSync(oldPath: string | Buffer, newPath: string | Buffer): void; - - /** - * Asynchronous rmdir(2). - */ - export function rmdir(path: string | Buffer, callback: (err: NodeJS.ErrnoException | null) => void): void; - - /** - * Synchronous rmdir(2). - */ - export function rmdirSync(path: string | Buffer): void; - - /** - * Asynchronous stat(2). - * - * In case of an error, the `err.code` will be one of Common System Errors. - * - * Using `fs.stat()` to check for the existence of a file before calling `fs.open()`, `fs.readFile()` or `fs.writeFile()` is not recommended. Instead, user code should open/read/write the file directly and handle the error raised if the file is not available. - * - * To check if a file exists without manipulating it afterwards, `fs.access()` is recommended. - */ - export function stat(path: string | Buffer, callback: (err: NodeJS.ErrnoException | null, stats: Stats) => void): void; - - /** - * Synchronous stat(2). - */ - export function statSync(path: string | Buffer): Stats; - - /** - * Asynchronous symlink(2). The type argument is only available on Windows (ignored on other platforms). Note that Windows junction points require the destination path to be absolute. When using `'junction'`, the target argument will automatically be normalized to absolute path. - */ - export function symlink(target: string | Buffer, path: string | Buffer, callback: (err: NodeJS.ErrnoException | null) => void): void; - export function symlink(target: string | Buffer, path: string | Buffer, type: 'dir' | 'file' | 'junction', callback: (err: NodeJS.ErrnoException | null) => void): void; - - /** - * Synchronous symlink(2). - */ - export function symlinkSync(target: string | Buffer, path: string | Buffer, type?: 'dir' | 'file' | 'junction'): void; - - /** - * Asynchronous truncate(2). - */ - export function truncate(path: string | Buffer, len: number, callback: (err: NodeJS.ErrnoException | null) => void): void; - - /** - * Synchronous truncate(2). - */ - export function truncateSync(path: string | Buffer, len?: number): void; - - /** - * Asynchronous unlink(2). - */ - export function unlink(path: string | Buffer, callback: (err: NodeJS.ErrnoException | null) => void): void; - - /** - * Synchronous unlink(2). - */ - export function unlinkSync(path: string | Buffer): void; - - /** - * Stop watching for changes on `filename`. If `listener` is specified, only that particular listener is removed. Otherwise, _all_ listeners are removed and you have effectively stopped watching `filename`. - * - * Calling `fs.unwatchFile()` with a filename that is not being watched is a no-op, not an error. - * - * Note: `fs.watch()` is more efficient than `fs.watchFile()` and `fs.unwatchFile()`. `fs.watch()` should be used instead of `fs.watchFile()` and `fs.unwatchFile()` when possible. - */ - export function unwatchFile(filename: string | Buffer, listener?: WatchListener): void; - - /** - * Change file timestamps of the file referenced by the supplied path. - * - * Note: the arguments `atime` and `mtime` of the following related functions follow these rules: - * - * - The value should be a Unix timestamp in seconds. For example, `Date.now()` returns milliseconds, so it should be divided by 1000 before passing it in. - * If the value is a numeric string like `'123456789'`, the value will get converted to the corresponding number. - * If the value is `NaN` or `Infinity`, the value will get converted to `Date.now() / 1000`. - */ - export function utimes(path: string | Buffer, atime: number, mtime: number, callback: (err: NodeJS.ErrnoException | null) => void): void; - - /** - * Synchronous version of `fs.utimes()`. - */ - export function utimesSync(path: string | Buffer, atime: number, mtime: number): void; - - export interface WatchOptions { - /** - * Indicates whether the process should continue to run as long as files are being watched. default = `true`. - */ - persistent?: boolean; - /** - * Indicates whether all subdirectories should be watched, or only the current directory. The applies when a directory is specified, and only on supported platforms (See Caveats). default = `false`. - */ - recursive?: boolean; - /** - * Specifies the character encoding to be used for the filename passed to the listener. default = `'utf8'`. - */ - encoding?: buffer.Encoding; - } - - /** - * Watch for changes on `filename`, where `filename` is either a file or a directory. The returned object is a `fs.FSWatcher`. - * - * Please note the listener callback is attached to the `'change'` event fired by `fs.FSWatcher`, but they are not the same thing. - */ - export function watch(filename: string | Buffer): FSWatcher; - export function watch(filename: string | Buffer, options: buffer.Encoding | WatchOptions | null): FSWatcher; - export function watch(filename: string | Buffer, listener: WatchListener): FSWatcher; - export function watch(filename: string | Buffer, options: buffer.Encoding | WatchOptions | null, listener: WatchListener): FSWatcher; - - export interface WatchFileOptions { - /** - * Indicates whether the process should continue to run as long as files are being watched - */ - persistent: boolean; - /** - * Indicates how often the target should be polled in milliseconds. The default is `5007`. - */ - interval: number; - } - - /** - * Watch for changes on filename. The callback listener will be called each time the file is accessed. - * - * Note: when an `fs.watchFile` operation results in an `ENOENT` error, it will invoke the listener once, with all the fields zeroed (or, for dates, the Unix Epoch). In Windows, `blksize` and `blocks` fields will be `undefined`, instead of zero. If the file is created later on, the listener will be called again, with the latest stat objects. - * - * Note: `fs.watch()` is more efficient than `fs.watchFile` and `fs.unwatchFile`. `fs.watch` should be used instead of `fs.watchFile` and `fs.unwatchFile` when possible. - */ - export function watchFile(filename: string | Buffer, listener: (curr: Stats, prev: Stats) => void): void; - export function watchFile(filename: string | Buffer, options: WatchFileOptions | null, listener: (curr: Stats, prev: Stats) => void): void; - - /** - * Write `buffer` to the file specified by `fd`. - * - * `offset` and `length` determine the part of the buffer to be written. - * - * `position` refers to the offset from the beginning of the file where this data should be written. If `typeof position !== 'number'`, the data will be written at the current position. See pwrite(2). - * - * Note that it is unsafe to use `fs.write` multiple times on the same file without waiting for the callback. For this scenario, `fs.createWriteStream` is strongly recommended. - * - * On Linux, positional writes don't work when the file is opened in append mode. The kernel ignores the position argument and always appends the data to the end of the file. - */ - export function write(fd: number, buffer: string | Buffer, offset: number, length: number, callback: (err: NodeJS.ErrnoException | null, written: number, buffer: Buffer) => void): void; - export function write(fd: number, buffer: string | Buffer, offset: number, length: number, position: number, callback: (err: NodeJS.ErrnoException | null, written: number, buffer: Buffer) => void): void; - export function write(fd: number, data: string | Buffer, callback: (err: NodeJS.ErrnoException | null, written: number, string: string) => void): void; - export function write(fd: number, data: string | Buffer, position: number, callback: (err: NodeJS.ErrnoException | null, written: number, string: string) => void): void; - export function write(fd: number, data: string | Buffer, position: number, encoding: buffer.Encoding, callback: (err: NodeJS.ErrnoException | null, written: number, string: string) => void): void; - - export interface WriteFileOptions { - encoding?: buffer.Encoding; - mode?: number; - flag?: string; - } - - /** - * Asynchronously writes data to a file, replacing the file if it already exists. - * - * Note that it is unsafe to use `fs.writeFile` multiple times on the same file without waiting for the callback. For this scenario, `fs.createWriteStream` is strongly recommended. - * - * Note: If a file descriptor is specified as the `file`, it will not be closed automatically. - */ - export function writeFile(file: string | Buffer | number, data: string | Buffer, callback: (err: NodeJS.ErrnoException | null) => void): void; - export function writeFile(file: string | Buffer | number, data: string | Buffer, options: buffer.Encoding | WriteFileOptions | null, callback: (err: NodeJS.ErrnoException | null) => void): void; - - /** - * The synchronous version of `fs.writeFile()`. - */ - export function writeFileSync(file: string | Buffer | number, data: string | Buffer, options?: buffer.Encoding | WriteFileOptions | null): void; - - /** - * Synchronous `fs.write`. - */ - export function writeSync(fd: number, buffer: string | Buffer, offset: number, length: number, position?: number): void; - export function writeSync(fd: number, data: string | Buffer, position?: number, encoding?: buffer.Encoding): void; -} - -declare module "path" { - - /** - * A parsed path object generated by path.parse() or consumed by path.format(). - */ - export interface ParsedPath { - /** - * The root of the path such as '/' or 'c:\' - */ - root: string; - /** - * The full directory path such as '/home/user/dir' or 'c:\path\dir' - */ - dir: string; - /** - * The file name including extension (if any) such as 'index.html' - */ - base: string; - /** - * The file extension (if any) such as '.html' - */ - ext: string; - /** - * The file name without extension (if any) such as 'index' - */ - name: string; - } - - /** - * Normalize a string path, reducing '..' and '.' parts. - * When multiple slashes are found, they're replaced by a single one; when the path contains a trailing slash, it is preserved. On Windows backslashes are used. - * - * @param p string path to normalize. - */ - export function normalize(p: string): string; - /** - * Join all arguments together and normalize the resulting path. - * Arguments must be strings. In v0.8, non-string arguments were silently ignored. In v0.10 and up, an exception is thrown. - * - * @param paths string paths to join. - */ - export function join(...paths: string[]): string; - /** - * The right-most parameter is considered {to}. Other parameters are considered an array of {from}. - * - * Starting from leftmost {from} paramter, resolves {to} to an absolute path. - * - * If {to} isn't already absolute, {from} arguments are prepended in right to left order, until an absolute path is found. If after using all {from} paths still no absolute path is found, the current working directory is used as well. The resulting path is normalized, and trailing slashes are removed unless the path gets resolved to the root directory. - * - * @param pathSegments string paths to join. Non-string arguments are ignored. - */ - export function resolve(...pathSegments: string[]): string; - /** - * Determines whether {path} is an absolute path. An absolute path will always resolve to the same location, regardless of the working directory. - * - * @param path path to test. - */ - export function isAbsolute(path: string): boolean; - /** - * Solve the relative path from {from} to {to}. - * At times we have two absolute paths, and we need to derive the relative path from one to the other. This is actually the reverse transform of path.resolve. - * - * @param from - * @param to - */ - export function relative(from: string, to: string): string; - /** - * Return the directory name of a path. Similar to the Unix dirname command. - * - * @param p the path to evaluate. - */ - export function dirname(p: string): string; - /** - * Return the last portion of a path. Similar to the Unix basename command. - * Often used to extract the file name from a fully qualified path. - * - * @param p the path to evaluate. - * @param ext optionally, an extension to remove from the result. - */ - export function basename(p: string, ext?: string): string; - /** - * Return the extension of the path, from the last '.' to end of string in the last portion of the path. - * If there is no '.' in the last portion of the path or the first character of it is '.', then it returns an empty string - * - * @param p the path to evaluate. - */ - export function extname(p: string): string; - /** - * The platform-specific file separator. '\\' or '/'. - */ - export var sep: string; - /** - * The platform-specific file delimiter. ';' or ':'. - */ - export var delimiter: string; - /** - * Returns an object from a path string - the opposite of format(). - * - * @param pathString path to evaluate. - */ - export function parse(pathString: string): ParsedPath; - /** - * Returns a path string from an object - the opposite of parse(). - * - * @param pathString path to evaluate. - */ - export function format(pathObject: ParsedPath): string; - - export module posix { - export function normalize(p: string): string; - export function join(...paths: string[]): string; - export function resolve(...pathSegments: string[]): string; - export function isAbsolute(p: string): boolean; - export function relative(from: string, to: string): string; - export function dirname(p: string): string; - export function basename(p: string, ext?: string): string; - export function extname(p: string): string; - export var sep: string; - export var delimiter: string; - export function parse(p: string): ParsedPath; - export function format(pP: ParsedPath): string; - } - - export module win32 { - export function normalize(p: string): string; - export function join(...paths: string[]): string; - export function resolve(...pathSegments: string[]): string; - export function isAbsolute(p: string): boolean; - export function relative(from: string, to: string): string; - export function dirname(p: string): string; - export function basename(p: string, ext?: string): string; - export function extname(p: string): string; - export var sep: string; - export var delimiter: string; - export function parse(p: string): ParsedPath; - export function format(pP: ParsedPath): string; - } -} - -declare module "string_decoder" { - import * as buffer from "buffer"; - - export class StringDecoder { - /** - * @param encoding The character encoding the `StringDecoder` will use. Defaults to `'utf8'`. - */ - constructor(encoding?: buffer.Encoding); - /** - * Returns a decoded string, ensuring that any incomplete multibyte characters at the end of the `Buffer` are omitted from the returned string and stored in an internal buffer for the next call to `stringDecoder.write()` or `stringDecoder.end()`. - * - * @param buffer A `Buffer` containing the bytes to decode. - */ - write(buffer: Buffer): string; - /** - * Returns any remaining input stored in the internal buffer as a string. Bytes representing incomplete UTF-8 and UTF-16 characters will be replaced with substitution characters appropriate for the character encoding. - * - * If the `buffer` argument is provided, one final call to `stringDecoder.write()` is performed before returning the remaining input. - * - * @param buffer A `Buffer` containing the bytes to decode. - */ - end(buffer?: Buffer): string; - } -} - -declare module "tls" { - import * as crypto from "crypto"; - import * as net from "net"; - import * as stream from "stream"; - - export var CLIENT_RENEG_LIMIT: number; - export var CLIENT_RENEG_WINDOW: number; - export var SLAB_BUFFER_SIZE: number; - export var DEFAULT_CIPHERS: string; - export var DEFAULT_ECDH_CURVE: string; - - export class Server extends net.Server { - /** - * The `server.addContext()` method adds a secure context that will be used if the client request's SNS hostname matches the supplied `hostname` (or wildcard). - * - * @param hostname A SNI hostname or wildcard (e.g. `'*'`) - * @param options An object containing any of the possible properties from the `tls.createSecureContext()` options arguments - */ - addContext(hostName: string, options: SecureContextOptions): void; - /** - * Returns a `Buffer` instance holding the keys currently used for encryption/decryption of the TLS Session Tickets. - */ - getTicketKeys(): Buffer; - /** - * Updates the keys for encryption/decryption of the TLS Session Tickets. - * - * Note: The key's Buffer should be 48 bytes long. See ticketKeys option in tls.createServer for more information on how it is used. - * - * Note: Changes to the ticket keys are effective only for future server connections. Existing or currently pending server connections will use the previous keys. - */ - setTicketKeys(keys: Buffer): void; - /** - * Returns the current number of concurrent connections on the server. - */ - connections: number; - } - - export interface Certificate { - /** - * Country code. - */ - C: string; - /** - * Street. - */ - ST: string; - /** - * Locality. - */ - L: string; - /** - * Organization. - */ - O: string; - /** - * Organizational unit. - */ - OU: string; - /** - * Common name. - */ - CN: string; - } - - export interface Cipher { - /** - * The cipher name. - */ - name: string; - /** - * SSL/TLS protocol version. - */ - version: string; - } - - export interface EphemeralKeyInfo { - type: 'DH' | 'ECDH'; - name?: string; - size: number; - } - - export interface PeerCertificate { - subject: Certificate; - issuerInfo: Certificate; - issuer: Certificate; - raw: Buffer; - valid_from: string; - valid_to: string; - fingerprint: string; - serialNumber: string; - } - - export interface TLSSocketOptions { - /** - * An optional TLS context object from `tls.createSecureContext()`. - */ - secureContext?: SecureContext; - /** - * If true the TLS socket will be instantiated in server-mode. Defaults to `false`. - */ - isServer?: boolean; - /** - * An optional net.Server instance. - */ - server?: net.Server; - /** - * Optional, see `tls.createServer()`. - */ - requestCert?: boolean; - /** - * Optional, see `tls.createServer()`. - */ - rejectUnauthorized?: boolean; - /** - * Optional, see `tls.createServer()`. - */ - NPNProtocols?: string[] | Buffer; - /** - * Optional, see `tls.createServer()`. - */ - ALPNProtocols?: string[] | Buffer; - /** - * Optional, see `tls.createServer()`. - */ - SNICallback?: (servername: string, cb: (err: Error | null, ctx: SecureContext) => void) => void; - /** - * An optional Buffer instance containing a TLS session. - */ - session?: Buffer; - /** - * If `true`, specifies that the OCSP status request extension will be added to the client hello and an 'OCSPResponse' event will be emitted on the socket before establishing a secure communication - */ - requestOCSP?: boolean; - } - - export interface RenegotiateOptions { - rejectUnauthorized?: boolean; - requestCert?: boolean; - } - - export class TLSSocket extends net.Socket { - /** - * Construct a new `tls.TLSSocket` object from an existing TCP socket. - */ - constructor(socket: net.Socket, options?: TLSSocketOptions); - /** - * Returns `true` if the peer certificate was signed by one of the CAs specified when creating the `tls.TLSSocket` instance, otherwise `false`. - */ - authorized: boolean; - /** - * Returns the reason why the peer's certificate was not been verified. This property is set only when `tlsSocket.authorized === false`. - */ - authorizationError?: Error; - /** - * Always returns `true`. This may be used to distinguish TLS sockets from regular `net.Socket` instances. - */ - encrypted: true; - /** - * Returns an object representing the cipher name and the SSL/TLS protocol version that first defined the cipher. - */ - getCipher(): Cipher; - /** - * Returns an object representing the type, name, and size of parameter of an ephemeral key exchange in Perfect Forward Secrecy on a client connection. It returns an empty object when the key exchange is not ephemeral. As this is only supported on a client socket; `null` is returned if called on a server socket. The supported types are `'DH'` and `'ECDH'`. The `name` property is available only when type is `'ECDH'`. - */ - getEphemeralKeyInfo(): EphemeralKeyInfo; - /** - * Returns an object representing the peer's certificate. The returned object has some properties corresponding to the fields of the certificate. - * - * @param detailed Specify `true` to request that the full certificate chain with the `issuer` property be returned; false to return only the top certificate without the `issuer` property. - */ - getPeerCertificate(detailed?: boolean): PeerCertificate; - /** - * Returns a string containing the negotiated SSL/TLS protocol version of the current connection. The value `'unknown'` will be returned for connected sockets that have not completed the handshaking process. The value `null` will be returned for server sockets or disconnected client sockets. - */ - getProtocol(): string | null; - /** - * Returns the ASN.1 encoded TLS session or `undefined` if no session was negotiated. Can be used to speed up handshake establishment when reconnecting to the server. - */ - getSession(): Buffer | undefined; - /** - * Returns the TLS session ticket or `undefined` if no session was negotiated. - * - * Note: This only works with client TLS sockets. Useful only for debugging, for session reuse `provide` session option to `tls.connect()`. - */ - getTLSTicket(): Buffer | undefined; - /** - * Returns the string representation of the local IP address. - */ - localAddress: string; - /** - * Returns the numeric representation of the local port. - */ - localPort: number; - /** - * Returns the string representation of the remote IP address. For example, `'74.125.127.100'` or `'2001:4860:a005::68'`. - */ - remoteAddress: string; - /** - * Returns the string representation of the remote IP family. `'IPv4'` or `'IPv6'`. - */ - remoteFamily: string; - /** - * The numeric representation of the remote port. For example, 443. - */ - remotePort: number; - /** - * The `tlsSocket.renegotiate()` method initiates a TLS renegotiation process. - * - * Note: This method can be used to request a peer's certificate after the secure connection has been established. - * - * Note: When running as the server, the socket will be destroyed with an error after `handshakeTimeout` timeout. - */ - renegotiate(options: RenegotiateOptions, callback: (err: Error | null) => any): any; - /** - * The `tlsSocket.setMaxSendFragment()` method sets the maximum TLS fragment size. Returns `true` if setting the limit succeeded; false otherwise. - * - * Smaller fragment sizes decrease the buffering latency on the client: larger fragments are buffered by the TLS layer until the entire fragment is received and its integrity is verified; large fragments can span multiple roundtrips and their processing can be delayed due to packet loss or reordering. However, smaller fragments add extra TLS framing bytes and CPU overhead, which may decrease overall server throughput. - * - * @param size The maximum TLS fragment size. Defaults to `16384`. The maximum value is `16384`. - */ - setMaxSendFragment(size: number): boolean; - } - - export interface ConnectOptions { - /** - * Host the client should connect to. - */ - host?: string; - /** - * Port the client should connect to. - */ - port?: number | string; - /** - * Establish secure connection on a given socket rather than creating a new socket. If this option is specified, `host` and `port` are ignored. - */ - socket?: net.Socket; - /** - * Creates unix socket connection to path. If this option is specified, `host` and `port` are ignored. - */ - path?: string; - /** - * A `string` or `Buffer` containing the private key, certificate, and CA certs of the client in PFX or PKCS12 format. - */ - pfx?: string | Buffer; - /** - * A string, `Buffer`, array of strings, or array of `Buffer`s containing the private key of the client in PEM format. - */ - key?: string | Buffer | string[] | Buffer[]; - /** - * A string containing the passphrase for the private key or pfx. - */ - passphrase?: string; - /** - * A string, `Buffer`, array of strings, or array of `Buffer`s containing the certificate key of the client in PEM format. - */ - cert?: string | Buffer | string[] | Buffer[]; - /** - * A string, `Buffer`, array of strings, or array of `Buffer`s of trusted certificates in PEM format. If this is omitted several well known "root" CAs (like VeriSign) will be used. These are used to authorize connections. - */ - ca?: string | Buffer | string[] | Buffer[]; - /** - * A string describing the ciphers to use or exclude, separated by `:`. Uses the same default cipher suite as `tls.createServer()`. - */ - ciphers?: string; - /** - * If true, the server certificate is verified against the list of supplied CAs. An `'error'` event is emitted if verification fails; `err.code` contains the OpenSSL error code. Defaults to `true`. - */ - rejectUnauthorized?: boolean; - /** - * An array of strings or `Buffer`s containing supported NPN protocols. `Buffer`s should have the format `[len][name][len][name]...` e.g. `0x05hello0x05world`, where the first byte is the length of the next protocol name. Passing an array is usually much simpler, e.g. `['hello', 'world']`. - */ - NPNProtocols?: string[] | Buffer[]; - /** - * An array of strings or `Buffer`s containing the supported ALPN protocols. `Buffer`s should have the format `[len][name][len][name]...` e.g. `0x05hello0x05world`, where the first byte is the length of the next protocol name. Passing an array is usually much simpler: `['hello', 'world']`.) - */ - ALPNProtocols?: string[] | Buffer[]; - /** - * Server name for the SNI (Server Name Indication) TLS extension. - */ - servername?: string; - /** - * A callback function to be used when checking the server's hostname against the certificate. This should throw an error if verification fails. The method should return `undefined` if the `servername` and `cert` are verified. - */ - checkServerIdentity?: (servername: string, cert: Buffer) => void; - /** - * The SSL method to use, e.g., `SSLv3_method` to force SSL version 3. The possible values depend on the version of OpenSSL installed in the environment and are defined in the constant SSL_METHODS. - */ - secureProtocol?: string; - /** - * An optional TLS context object as returned by from `tls.createSecureContext( ... )`. It can be used for caching client certificates, keys, and CA certificates. - */ - secureContext?: SecureContext; - /** - * A `Buffer` instance, containing TLS session. - */ - session?: Buffer; - /** - * Minimum size of the DH parameter in bits to accept a TLS connection. When a server offers a DH parameter with a size less than `minDHSize`, the TLS connection is destroyed and an error is thrown. Defaults to `1024`. - */ - minDHSize?: number; - } - - export interface SecureContextOptions { - /** - * A string or `Buffer` holding the PFX or PKCS12 encoded private key, certificate, and CA certificates. - */ - pfx?: string | Buffer; - /** - * The private key of the server in PEM format. To support multiple keys using different algorithms, an array can be provided either as an array of key strings or as an array of objects in the format `{pem: key, passphrase: passphrase}`. This option is required for ciphers that make use of private keys. - */ - key?: string | string[] | Buffer | Array<{ pem: string | string[] | Buffer, passphrase: string }>; - /** - * A string containing the passphrase for the private key or pfx. - */ - passphrase?: string; - /** - * A string containing the PEM encoded certificate. - */ - cert?: string | Buffer | string[] | Buffer[]; - /** - * A string, `Buffer`, array of strings, or array of `Buffer`s of trusted certificates in PEM format. If omitted, several well known "root" CAs (like VeriSign) will be used. These are used to authorize connections. - */ - ca?: string | Buffer | string[] | Buffer[]; - /** - * Either a string or array of strings of PEM encoded CRLs (Certificate Revocation List). - */ - crl?: string | string[]; - /** - * A string describing the ciphers to use or exclude. Consult https://www.openssl.org/docs/apps/ciphers.html#CIPHER-LIST-FORMAT for details on the format. - */ - ciphers?: string; - /** - * If `true`, when a cipher is being selected, the server's preferences will be used instead of the client preferences. - */ - honorCipherOrder?: boolean; - } - - export interface CreateServerOptions { - /** - * A `string` or `Buffer` containing the private key, certificate and CA certs of the server in PFX or PKCS12 format. (Mutually exclusive with the `key`, `cert`, and `ca` options.) - */ - pfx?: string | Buffer; - /** - * The private key of the server in PEM format. To support multiple keys using different algorithms an array can be provided either as a plain array of key strings or an array of objects in the format `{pem: key, passphrase: passphrase}`. This option is required for ciphers that make use of private keys. - */ - key?: string | string[] | Buffer | Array<{ pem: string | string[] | Buffer, passphrase: string }>; - /** - * A string containing the passphrase for the private key or pfx. - */ - passphrase?: string; - /** - * A string containing the PEM encoded certificate. - */ - cert?: string | Buffer | string[] | Buffer[]; - /** - * A string, `Buffer`, array of strings, or array of `Buffer`s of trusted certificates in PEM format. If omitted, several well known "root" CAs (like VeriSign) will be used. These are used to authorize connections. - */ - ca?: string | Buffer | string[] | Buffer[]; - /** - * Either a string or array of strings of PEM encoded CRLs (Certificate Revocation List). - */ - crl?: string | string[]; - /** - * A string describing the ciphers to use or exclude, separated by `:`. - */ - ciphers?: string; - /** - * A string describing a named curve to use for ECDH key agreement or false to disable ECDH. Defaults to `prime256v1` (NIST P-256). Use crypto.getCurves() to obtain a list of available curve names. On recent releases, `openssl ecparam -list_curves` will also display the name and description of each available elliptic curve. - */ - ecdhCurve?: string; - /** - * A string or `Buffer` containing Diffie Hellman parameters, required for Perfect Forward Secrecy. Use `openssl dhparam` to create the parameters. The key length must be greater than or equal to 1024 bits, otherwise an error will be thrown. It is strongly recommended to use 2048 bits or larger for stronger security. If omitted or invalid, the parameters are silently discarded and DHE ciphers will not be available. - */ - dhparam?: string | Buffer; - /** - * Abort the connection if the SSL/TLS handshake does not finish in the specified number of milliseconds. Defaults to `120` seconds. A `'clientError'` is emitted on the `tls.Server` object whenever a handshake times out. - */ - handshakeTimeout?: number; - /** - * When choosing a cipher, use the server's preferences instead of the client preferences. Defaults to `true`. - */ - honorCipherOrder?: boolean; - /** - * If `true` the server will request a certificate from clients that connect and attempt to verify that certificate. Defaults to `false`. - */ - requestCert?: boolean; - /** - * If `true` the server will reject any connection which is not authorized with the list of supplied CAs. This option only has an effect if `requestCert` is `true`. Defaults to `false`. - */ - rejectUnauthorized?: boolean; - /** - * An array of strings or a `Buffer` naming possible NPN protocols. (Protocols should be ordered by their priority.) - */ - NPNProtocols?: string[] | Buffer; - /** - * An array of strings or a `Buffer` naming possible ALPN protocols. (Protocols should be ordered by their priority.) When the server receives both NPN and ALPN extensions from the client, ALPN takes precedence over NPN and the server does not send an NPN extension to the client. - */ - ALPNProtocols?: string[] | Buffer; - /** - * A function that will be called if the client supports SNI TLS extension. Two arguments will be passed when called: `servername` and `cb`. `SNICallback` should invoke `cb(null, ctx)`, where `ctx` is a SecureContext instance. (`tls.createSecureContext(...)` can be used to get a proper SecureContext.) If `SNICallback` wasn't provided the default callback with high-level API will be used (see below). - */ - SNICallback?: (servername: string, cb: (err: Error | null, ctx: SecureContext) => void) => void; - /** - * An integer specifying the number of seconds after which the TLS session identifiers and TLS session tickets created by the server will time out. See SSL_CTX_set_timeout for more details. - */ - sessionTimeout?: number; - /** - * A 48-byte `Buffer` instance consisting of a 16-byte prefix, a 16-byte HMAC key, and a 16-byte AES key. This can be used to accept TLS session tickets on multiple instances of the TLS server. Note that this is automatically shared between `cluster` module workers. - */ - ticketKeys?: Buffer; - /** - * A string containing an opaque identifier for session resumption. If `requestCert` is true, the default is a 128 bit truncated SHA1 hash value generated from the command-line. Otherwise, a default is not provided. - */ - sessionIdContext?: string; - /** - * The SSL method to use, e.g., `SSLv3_method` to force SSL version 3. The possible values depend on the version of OpenSSL installed in the environment and are defined in the constant SSL_METHODS. - */ - secureProtocol?: string; - } - - export interface SecureContext { - context: any; - } - - /** - * Creates a new tls.Server. The secureConnectionListener, if provided, is automatically set as a listener for the `'secureConnection'` event. - */ - export function createServer(options: CreateServerOptions, secureConnectionListener?: (socket: TLSSocket) => void): Server; - - /** - * Creates a new client connection to the given `port` and `host` or `options.port` and `options.host`. (If `host` is omitted, it defaults to `localhost`.) - */ - export function connect(options: ConnectOptions, callback?: () => void): TLSSocket; - export function connect(port: number, options?: ConnectOptions, callback?: () => void): TLSSocket; - export function connect(port: number, host?: string, options?: ConnectOptions, callback?: () => void): TLSSocket; - - /** - * The `tls.createSecureContext()` method creates a credentials object. - * - * If the `'ca'` option is not given, then Node.js will use the default publicly trusted list of CAs as given in http://mxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/builtins/certdata.txt. - */ - export function createSecureContext(options: SecureContextOptions): SecureContext; - - /** - * Returns an array with the names of the supported SSL ciphers. - */ - export function getCiphers(): string[]; -} - -declare module "crypto" { - import * as stream from "stream"; - - export var constants: { - defaultCipherList: string; - defaultCoreCipherList: string; - [key: string]: string | number; - } - - export function getCiphers(): string[]; - export function getCurves(): string[]; - export function getHashes(): string[]; - - export class Certificate { - constructor(); - exportChallenge(spkac: string | Buffer, encoding?: string): string; - exportPublicKey(spkac: string | Buffer, encoding?: string): Buffer; - verifySpkac(spkac: Buffer): boolean; - } - - export function createHash(algorithm: string): Hash; - - export class Hash extends stream.Transform { - update(data: string | Buffer, input_encoding?: string): Hash; - digest(encoding: 'buffer'): Buffer; - digest(encoding: string): string; - digest(): Buffer; - } - - export function createHmac(algorithm: string, key: string | Buffer): Hmac; - - export class Hmac extends stream.Transform { - update(data: string | Buffer, input_encoding?: string): Hmac; - digest(encoding: 'buffer'): Buffer; - digest(encoding: string): string; - digest(): Buffer; - } - - export function createCipher(algorithm: string, password: string | Buffer): Cipher; - export function createCipheriv(algorithm: string, key: string | Buffer, iv: string | Buffer): Cipher; - - export class Cipher extends stream.Transform { - update(data: Buffer): Buffer; - update(data: string, input_encoding: "utf8" | "ascii" | "binary" | "latin1"): Buffer; - update(data: Buffer, input_encoding: any, output_encoding: "binary" | "latin1" | "base64" | "hex"): string; - update(data: string, input_encoding: "utf8" | "ascii" | "binary" | "latin1", output_encoding: "binary" | "latin1" | "base64" | "hex"): string; - final(): Buffer; - final(output_encoding: string): string; - setAAD(buffer: Buffer): void; - setAutoPadding(auto_padding: boolean): void; - getAuthTag(): Buffer; - } - - export function createDecipher(algorithm: string, password: string | Buffer): Decipher; - export function createDecipheriv(algorithm: string, key: string | Buffer, iv: string | Buffer): Decipher; - - export class Decipher extends stream.Transform { - update(data: Buffer): Buffer; - update(data: string, input_encoding: "binary" | "latin1" | "base64" | "hex"): Buffer; - update(data: Buffer, input_encoding: any, output_encoding: "utf8" | "ascii" | "binary" | "latin1"): string; - update(data: string, input_encoding: "binary" | "latin1" | "base64" | "hex", output_encoding: "utf8" | "ascii" | "binary" | "latin1"): string; - final(): Buffer; - final(output_encoding: string): string; - setAAD(buffer: Buffer): void; - setAutoPadding(auto_padding: boolean): void; - setAuthTag(tag: Buffer): void; - } - - export function createSign(algorithm: string): Signer; - - export class Signer extends stream.Writable { - update(data: string | Buffer): void; - sign(private_key: string): Buffer; - sign(private_key: string, output_format: string): string; - } - - export function createVerify(algorith: string): Verify; - - export class Verify extends stream.Writable { - update(data: string | Buffer): void; - verify(object: string, signature: string, signature_format?: string): boolean; - } - - export function createDiffieHellman(prime: number, prime_encoding?: string, generator?: number | string | Buffer, generator_encoding?: string): DiffieHellman; - export function createDiffieHellman(prime_length: number, generator?: number | string | Buffer): DiffieHellman; - export function getDiffieHellman(group_name: string): DiffieHellman; - - export class DiffieHellman { - verifyError: number; - computeSecret(other_public_key: string, input_encoding?: string, output_encoding?: string): string; - generateKeys(encoding?: string): string; - getPrime(encoding?: string): string; - getGenerator(encoding?: string): string; - getPublicKey(encoding?: string): string; - getPrivateKey(encoding?: string): string; - setPublicKey(public_key: string, encoding?: string): void; - setPrivateKey(public_key: string, encoding?: string): void; - } - - export function createECDH(curve_name: string): ECDH; - - export class ECDH { - computeSecret(other_public_key: string, input_encoding?: string, output_encoding?: string): string; - generateKeys(encoding?: string, format?: string): string; - getPrivateKey(encoding?: string): string; - getPublicKey(encoding?: string, format?: string): string; - setPrivateKey(private_key: string, encoding?: string): void; - } - - export function pbkdf2(password: string | Buffer, salt: string | Buffer, iterations: number, keylen: number, callback: (err: Error, derivedKey: Buffer) => void): void; - export function pbkdf2(password: string | Buffer, salt: string | Buffer, iterations: number, keylen: number, digest: string, callback: (err: Error, derivedKey: Buffer) => void): void; - - export function pbkdf2Sync(password: string | Buffer, salt: string | Buffer, iterations: number, keylen: number): Buffer; - export function pbkdf2Sync(password: string | Buffer, salt: string | Buffer, iterations: number, keylen: number, digest: string): Buffer; - - export function randomBytes(size: number): Buffer; - export function randomBytes(size: number, callback: (err: Error, buf: Buffer) => void): void; - - export function pseudoRandomBytes(size: number): Buffer; - export function pseudoRandomBytes(size: number, callback: (err: Error, buf: Buffer) => void): void; - - export interface RsaKey { - key: string; - passphrase?: string, - padding?: number; - } - - export function timingSafeEqual(a: Buffer, b: Buffer): boolean; - export function publicEncrypt(public_key: string | RsaKey, buffer: Buffer): Buffer; - export function privateEncrypt(private_key: string | RsaKey, buffer: Buffer): Buffer; - export function publicDecrypt(public_key: string | RsaKey, buffer: Buffer): Buffer; - export function privateDecrypt(private_key: string | RsaKey, buffer: Buffer): Buffer; - - export function setEngine(engine: string, flags?: number): void; -} - -declare module "stream" { - import * as events from "events"; - - export class Stream extends events.EventEmitter { - pipe(destination: T, options?: { end?: boolean; }): T; - } - - export interface ReadableOptions { - highWaterMark?: number; - encoding?: string; - objectMode?: boolean; - read?: (this: Readable, size?: number) => any; - } - - export class Readable extends events.EventEmitter implements NodeJS.ReadableStream { - readable: boolean; - constructor(opts?: ReadableOptions); - _read(size: number): void; - read(size?: number): any; - isPaused(): boolean; - setEncoding(encoding: string): this; - pause(): this; - resume(): this; - pipe(destination: T, options?: { end?: boolean; }): T; - unpipe(destination?: T): void; - unshift(chunk: any): void; - wrap(oldStream: NodeJS.ReadableStream): NodeJS.ReadableStream; - push(chunk: any, encoding?: string): boolean; - } - - export interface WritableOptions { - highWaterMark?: number; - decodeStrings?: boolean; - objectMode?: boolean; - write?: (chunk: string | Buffer, encoding: string, callback: Function) => any; - writev?: (chunks: { chunk: string | Buffer, encoding: string }[], callback: Function) => any; - } - - export class Writable extends events.EventEmitter implements NodeJS.WritableStream { - writable: boolean; - constructor(opts?: WritableOptions); - setDefaultEncoding(encoding: string): this; - _write(chunk: any, encoding: string, callback: Function): void; - write(chunk: any, cb?: Function): boolean; - write(chunk: any, encoding?: string, cb?: Function): boolean; - end(): void; - end(chunk: any, cb?: Function): void; - end(chunk: any, encoding?: string, cb?: Function): void; - } - - export interface DuplexOptions extends ReadableOptions, WritableOptions { - allowHalfOpen?: boolean; - readableObjectMode?: boolean; - writableObjectMode?: boolean; - } - - // Note: Duplex extends both Readable and Writable. - export class Duplex extends Readable implements Writable { - writable: boolean; - constructor(opts?: DuplexOptions); - setDefaultEncoding(encoding: string): this; - _write(chunk: any, encoding: string, callback: Function): void; - write(chunk: any, cb?: Function): boolean; - write(chunk: any, encoding?: string, cb?: Function): boolean; - end(): void; - end(chunk: any, cb?: Function): void; - end(chunk: any, encoding?: string, cb?: Function): void; - } - - export interface TransformOptions extends ReadableOptions, WritableOptions { - write?: (chunk: string | Buffer, encoding: string, callback: Function) => any; - writev?: (chunks: { chunk: string | Buffer, encoding: string }[], callback: Function) => any; - } - - export class Transform extends Duplex { - constructor(opts?: TransformOptions); - _transform(chunk: any, encoding: string, callback: Function): void; - } - - export class PassThrough extends Transform { } -} - -declare module "util" { - /** - * The `util.debuglog()` method is used to create a function that conditionally writes debug messages to `stderr` based on the existence of the `NODE_DEBUG` environment variable. If the `section` name appears within the value of that environment variable, then the returned function operates similar to console.error(). If not, then the returned function is a no-op. - */ - export function debuglog(section: string): (msg: any, ...args: any[]) => void; - - export interface InspectOptions { - /** - * If `true`, the `object`'s non-enumerable symbols and properties will be included in the formatted result. Defaults to `false`. - */ - showHidden?: boolean; - /** - * Specifies the number of times to recurse while formatting the `object`. This is useful for inspecting large complicated objects. Defaults to `2`. To make it recurse indefinitely pass `null`. - */ - depth?: number | null; - /** - * If `true`, the output will be styled with ANSI color codes. Defaults to `false`. Colors are customizable, see "Customizing util.inspect colors". - */ - colors?: boolean; - /** - * If `false`, then custom `inspect(depth, opts)` functions exported on the object being inspected will not be called. Defaults to `true`. - */ - customInspect?: boolean; - /** - * If `true`, then objects and functions that are `Proxy` objects will be introspected to show their `target` and `handler` objects. Defaults to `false`. - */ - showProxy?: boolean; - /** - * Specifies the maximum number of array and `TypedArray` elements to include when formatting. Defaults to `100`. Set to `null` to show all array elements. Set to `0` or negative to show no array elements. - */ - maxArrayLength?: number | null; - /** - * The length at which an object's keys are split across multiple lines. Set to `Infinity` to format an object as a single line. Defaults to `60` for legacy compatibility. - */ - breakLength?: number; - } - - /** - * The `util.inspect()` method returns a string representation of object that is primarily useful for debugging. - */ - export function inspect(object: any, showHidden?: boolean, depth?: number | null, color?: boolean): string; - export function inspect(object: any, options: InspectOptions): string; - - export namespace inspect { - export var colors: { - bold: [number, number]; - italic: [number, number]; - underline: [number, number]; - inverse: [number, number]; - white: [number, number]; - grey: [number, number]; - black: [number, number]; - blue: [number, number]; - cyan: [number, number]; - green: [number, number]; - magenta: [number, number]; - red: [number, number]; - yellow: [number, number]; - } - - export var styles: { - special: string; - number: string; - boolean: string; - undefined: string; - null: string; - string: string; - symbol: string; - date: string; - regexp: string; - }; - - export var custom: symbol; - } - - /** - * The `util.deprecate()` method wraps the given function or class in such a way that it is marked as deprecated. - */ - export function deprecate(fn: T, string: string): T; - - /** - * The `util.format()` method returns a formatted string using the first argument as a printf-like format. - */ - export function format(format: any, ...param: any[]): string; - - /** - * Inherit the prototype methods from one constructor into another. The prototype of constructor will be set to a new object created from superConstructor. - */ - export function inherits(constructor: any, superConstructor: any): void; - - /** - * Deprecated predecessor of `console.error`. - * - * @deprecated - */ - export function debug(string: string): void; - - /** - * Deprecated predecessor of `console.error`. - * - * @deprecated - */ - export function error(...strings: string[]): void; - - /** - * Internal alias for `Array.isArray`. - * - * @deprecated - */ - export function isArray(object: any): object is any[]; - - /** - * Returns `true` if the given `object` is a `Boolean`. Otherwise, returns `false`. - * - * @deprecated - */ - export function isBoolean(object: any): object is boolean; - - /** - * Returns `true` if the given `object` is a `Buffer`. Otherwise, returns `false`. - * - * @deprecated - */ - export function isBuffer(object: any): object is Buffer; - - /** - * Returns `true` if the given `object` is a `Date`. Otherwise, returns `false`. - * - * @deprecated - */ - export function isDate(object: any): object is Date; - - /** - * Returns `true` if the given `object` is an `Error`. Otherwise, returns `false`. - * - * @deprecated - */ - export function isError(object: any): object is Error; - - /** - * Returns `true` if the given `object` is a `Function`. Otherwise, returns `false`. - * - * @deprecated - */ - export function isFunction(object: any): object is Function; - - /** - * Returns `true` if the given `object` is strictly `null`. Otherwise, returns `false`. - * - * @deprecated - */ - export function isNull(object: any): object is null; - - /** - * Returns `true` if the given `object` is `null` or `undefined`. Otherwise, returns `false`. - * - * @deprecated - */ - export function isNullOrUndefined(object: any): object is null | undefined; - - /** - * Returns `true` if the given `object` is a `Number`. Otherwise, returns `false`. - * - * @deprecated - */ - export function isNumber(object: any): object is number; - - /** - * Returns true if the given `object` is strictly an `Object` and not a `Function`. Otherwise, returns `false`. - * - * @deprecated - */ - export function isObject(object: any): object is Object; - - /** - * Returns true if the given `object` is a primitive type. Otherwise, returns `false`. - * - * @deprecated - */ - export function isPrimitive(object: any): object is string | number | boolean | null | undefined; - - /** - * Returns true if the given `object` is a `RegExp`. Otherwise, returns `false`. - * - * @deprecated - */ - export function isRegExp(object: any): object is RegExp; - - /** - * Returns true if the given `object` is a `String`. Otherwise, returns `false`. - * - * @deprecated - */ - export function isString(object: any): object is string; - - /** - * Returns true if the given `object` is a `Symbol`. Otherwise, returns `false`. - * - * @deprecated - */ - export function isSymbol(object: any): object is symbol; - - /** - * Returns true if the given `object` is `undefined`. Otherwise, returns `false`. - * - * @deprecated - */ - export function isUndefined(object: any): object is symbol; - - /** - * The `util.log()` method prints the given `string` to `stdout` with an included timestamp. - * - * @deprecated - */ - export function log(string: string): void; - - /** - * Deprecated predecessor of `console.log`. - * - * @deprecated - */ - export function print(strings: string[]): void; - - /** - * Deprecated predecessor of `console.log`. - * - * @deprecated - */ - export function puts(strings: string[]): void; - - /** - * The `util._extend()` method was never intended to be used outside of internal Node.js modules. The community found and used it anyway. - * - * It is deprecated and should not be used in new code. JavaScript comes with very similar built-in functionality through `Object.assign()`. - * - * @deprecated - */ - export function _extend(target: T, source: U): T & U; -} - -declare module "assert" { - function internal(value: any, message?: string): void; - namespace internal { - export class AssertionError implements Error { - name: string; - message: string; - actual: any; - expected: any; - operator: string; - generatedMessage: boolean; - - constructor(options?: { - message?: string; actual?: any; expected?: any; - operator?: string; stackStartFunction?: Function - }); - } - - export function fail(actual?: any, expected?: any, message?: string, operator?: string): void; - export function ok(value: any, message?: string): void; - export function equal(actual: any, expected: any, message?: string): void; - export function notEqual(actual: any, expected: any, message?: string): void; - export function deepEqual(actual: any, expected: any, message?: string): void; - export function notDeepEqual(acutal: any, expected: any, message?: string): void; - export function strictEqual(actual: any, expected: any, message?: string): void; - export function notStrictEqual(actual: any, expected: any, message?: string): void; - export function deepStrictEqual(actual: any, expected: any, message?: string): void; - export function notDeepStrictEqual(actual: any, expected: any, message?: string): void; - export var throws: { - (block: Function, message?: string): void; - (block: Function, error: Function, message?: string): void; - (block: Function, error: RegExp, message?: string): void; - (block: Function, error: (err: any) => boolean, message?: string): void; - }; - - export var doesNotThrow: { - (block: Function, message?: string): void; - (block: Function, error: Function, message?: string): void; - (block: Function, error: RegExp, message?: string): void; - (block: Function, error: (err: any) => boolean, message?: string): void; - }; - - export function ifError(value: any): void; - } - - export = internal; -} - -declare module "tty" { - import * as net from "net"; - - export function isatty(fd: number): boolean; - export interface ReadStream extends net.Socket { - isRaw: boolean; - setRawMode(mode: boolean): void; - isTTY: boolean; - } - export interface WriteStream extends net.Socket { - columns: number; - rows: number; - isTTY: boolean; - } -} - -declare module "domain" { - import * as events from "events"; - - export class Domain extends events.EventEmitter implements NodeJS.Domain { - run(fn: Function): void; - add(emitter: events.EventEmitter): void; - remove(emitter: events.EventEmitter): void; - bind(cb: (err: Error, data: any) => any): any; - intercept(cb: (data: any) => any): any; - dispose(): void; - members: any[]; - enter(): void; - exit(): void; - } - - export function create(): Domain; -} - -declare module "constants" { - export var E2BIG: number; - export var EACCES: number; - export var EADDRINUSE: number; - export var EADDRNOTAVAIL: number; - export var EAFNOSUPPORT: number; - export var EAGAIN: number; - export var EALREADY: number; - export var EBADF: number; - export var EBADMSG: number; - export var EBUSY: number; - export var ECANCELED: number; - export var ECHILD: number; - export var ECONNABORTED: number; - export var ECONNREFUSED: number; - export var ECONNRESET: number; - export var EDEADLK: number; - export var EDESTADDRREQ: number; - export var EDOM: number; - export var EEXIST: number; - export var EFAULT: number; - export var EFBIG: number; - export var EHOSTUNREACH: number; - export var EIDRM: number; - export var EILSEQ: number; - export var EINPROGRESS: number; - export var EINTR: number; - export var EINVAL: number; - export var EIO: number; - export var EISCONN: number; - export var EISDIR: number; - export var ELOOP: number; - export var EMFILE: number; - export var EMLINK: number; - export var EMSGSIZE: number; - export var ENAMETOOLONG: number; - export var ENETDOWN: number; - export var ENETRESET: number; - export var ENETUNREACH: number; - export var ENFILE: number; - export var ENOBUFS: number; - export var ENODATA: number; - export var ENODEV: number; - export var ENOENT: number; - export var ENOEXEC: number; - export var ENOLCK: number; - export var ENOLINK: number; - export var ENOMEM: number; - export var ENOMSG: number; - export var ENOPROTOOPT: number; - export var ENOSPC: number; - export var ENOSR: number; - export var ENOSTR: number; - export var ENOSYS: number; - export var ENOTCONN: number; - export var ENOTDIR: number; - export var ENOTEMPTY: number; - export var ENOTSOCK: number; - export var ENOTSUP: number; - export var ENOTTY: number; - export var ENXIO: number; - export var EOPNOTSUPP: number; - export var EOVERFLOW: number; - export var EPERM: number; - export var EPIPE: number; - export var EPROTO: number; - export var EPROTONOSUPPORT: number; - export var EPROTOTYPE: number; - export var ERANGE: number; - export var EROFS: number; - export var ESPIPE: number; - export var ESRCH: number; - export var ETIME: number; - export var ETIMEDOUT: number; - export var ETXTBSY: number; - export var EWOULDBLOCK: number; - export var EXDEV: number; - export var WSAEINTR: number; - export var WSAEBADF: number; - export var WSAEACCES: number; - export var WSAEFAULT: number; - export var WSAEINVAL: number; - export var WSAEMFILE: number; - export var WSAEWOULDBLOCK: number; - export var WSAEINPROGRESS: number; - export var WSAEALREADY: number; - export var WSAENOTSOCK: number; - export var WSAEDESTADDRREQ: number; - export var WSAEMSGSIZE: number; - export var WSAEPROTOTYPE: number; - export var WSAENOPROTOOPT: number; - export var WSAEPROTONOSUPPORT: number; - export var WSAESOCKTNOSUPPORT: number; - export var WSAEOPNOTSUPP: number; - export var WSAEPFNOSUPPORT: number; - export var WSAEAFNOSUPPORT: number; - export var WSAEADDRINUSE: number; - export var WSAEADDRNOTAVAIL: number; - export var WSAENETDOWN: number; - export var WSAENETUNREACH: number; - export var WSAENETRESET: number; - export var WSAECONNABORTED: number; - export var WSAECONNRESET: number; - export var WSAENOBUFS: number; - export var WSAEISCONN: number; - export var WSAENOTCONN: number; - export var WSAESHUTDOWN: number; - export var WSAETOOMANYREFS: number; - export var WSAETIMEDOUT: number; - export var WSAECONNREFUSED: number; - export var WSAELOOP: number; - export var WSAENAMETOOLONG: number; - export var WSAEHOSTDOWN: number; - export var WSAEHOSTUNREACH: number; - export var WSAENOTEMPTY: number; - export var WSAEPROCLIM: number; - export var WSAEUSERS: number; - export var WSAEDQUOT: number; - export var WSAESTALE: number; - export var WSAEREMOTE: number; - export var WSASYSNOTREADY: number; - export var WSAVERNOTSUPPORTED: number; - export var WSANOTINITIALISED: number; - export var WSAEDISCON: number; - export var WSAENOMORE: number; - export var WSAECANCELLED: number; - export var WSAEINVALIDPROCTABLE: number; - export var WSAEINVALIDPROVIDER: number; - export var WSAEPROVIDERFAILEDINIT: number; - export var WSASYSCALLFAILURE: number; - export var WSASERVICE_NOT_FOUND: number; - export var WSATYPE_NOT_FOUND: number; - export var WSA_E_NO_MORE: number; - export var WSA_E_CANCELLED: number; - export var WSAEREFUSED: number; - export var SIGHUP: number; - export var SIGINT: number; - export var SIGILL: number; - export var SIGABRT: number; - export var SIGFPE: number; - export var SIGKILL: number; - export var SIGSEGV: number; - export var SIGTERM: number; - export var SIGBREAK: number; - export var SIGWINCH: number; - export var SSL_OP_ALL: number; - export var SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION: number; - export var SSL_OP_CIPHER_SERVER_PREFERENCE: number; - export var SSL_OP_CISCO_ANYCONNECT: number; - export var SSL_OP_COOKIE_EXCHANGE: number; - export var SSL_OP_CRYPTOPRO_TLSEXT_BUG: number; - export var SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS: number; - export var SSL_OP_EPHEMERAL_RSA: number; - export var SSL_OP_LEGACY_SERVER_CONNECT: number; - export var SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER: number; - export var SSL_OP_MICROSOFT_SESS_ID_BUG: number; - export var SSL_OP_MSIE_SSLV2_RSA_PADDING: number; - export var SSL_OP_NETSCAPE_CA_DN_BUG: number; - export var SSL_OP_NETSCAPE_CHALLENGE_BUG: number; - export var SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG: number; - export var SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG: number; - export var SSL_OP_NO_COMPRESSION: number; - export var SSL_OP_NO_QUERY_MTU: number; - export var SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION: number; - export var SSL_OP_NO_SSLv2: number; - export var SSL_OP_NO_SSLv3: number; - export var SSL_OP_NO_TICKET: number; - export var SSL_OP_NO_TLSv1: number; - export var SSL_OP_NO_TLSv1_1: number; - export var SSL_OP_NO_TLSv1_2: number; - export var SSL_OP_PKCS1_CHECK_1: number; - export var SSL_OP_PKCS1_CHECK_2: number; - export var SSL_OP_SINGLE_DH_USE: number; - export var SSL_OP_SINGLE_ECDH_USE: number; - export var SSL_OP_SSLEAY_080_CLIENT_DH_BUG: number; - export var SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG: number; - export var SSL_OP_TLS_BLOCK_PADDING_BUG: number; - export var SSL_OP_TLS_D5_BUG: number; - export var SSL_OP_TLS_ROLLBACK_BUG: number; - export var ENGINE_METHOD_DSA: number; - export var ENGINE_METHOD_DH: number; - export var ENGINE_METHOD_RAND: number; - export var ENGINE_METHOD_ECDH: number; - export var ENGINE_METHOD_ECDSA: number; - export var ENGINE_METHOD_CIPHERS: number; - export var ENGINE_METHOD_DIGESTS: number; - export var ENGINE_METHOD_STORE: number; - export var ENGINE_METHOD_PKEY_METHS: number; - export var ENGINE_METHOD_PKEY_ASN1_METHS: number; - export var ENGINE_METHOD_ALL: number; - export var ENGINE_METHOD_NONE: number; - export var DH_CHECK_P_NOT_SAFE_PRIME: number; - export var DH_CHECK_P_NOT_PRIME: number; - export var DH_UNABLE_TO_CHECK_GENERATOR: number; - export var DH_NOT_SUITABLE_GENERATOR: number; - export var NPN_ENABLED: number; - export var RSA_PKCS1_PADDING: number; - export var RSA_SSLV23_PADDING: number; - export var RSA_NO_PADDING: number; - export var RSA_PKCS1_OAEP_PADDING: number; - export var RSA_X931_PADDING: number; - export var RSA_PKCS1_PSS_PADDING: number; - export var POINT_CONVERSION_COMPRESSED: number; - export var POINT_CONVERSION_UNCOMPRESSED: number; - export var POINT_CONVERSION_HYBRID: number; - export var O_RDONLY: number; - export var O_WRONLY: number; - export var O_RDWR: number; - export var S_IFMT: number; - export var S_IFREG: number; - export var S_IFDIR: number; - export var S_IFCHR: number; - export var S_IFBLK: number; - export var S_IFIFO: number; - export var S_IFSOCK: number; - export var S_IRWXU: number; - export var S_IRUSR: number; - export var S_IWUSR: number; - export var S_IXUSR: number; - export var S_IRWXG: number; - export var S_IRGRP: number; - export var S_IWGRP: number; - export var S_IXGRP: number; - export var S_IRWXO: number; - export var S_IROTH: number; - export var S_IWOTH: number; - export var S_IXOTH: number; - export var S_IFLNK: number; - export var O_CREAT: number; - export var O_EXCL: number; - export var O_NOCTTY: number; - export var O_DIRECTORY: number; - export var O_NOATIME: number; - export var O_NOFOLLOW: number; - export var O_SYNC: number; - export var O_SYMLINK: number; - export var O_DIRECT: number; - export var O_NONBLOCK: number; - export var O_TRUNC: number; - export var O_APPEND: number; - export var F_OK: number; - export var R_OK: number; - export var W_OK: number; - export var X_OK: number; - export var UV_UDP_REUSEADDR: number; -} - -declare module "module" { - export = NodeModule; -} - -declare module "process" { - export = process; -} - -declare module "timers" { - export function setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): NodeJS.Timer; - export function setInterval(callback: (...args: any[]) => void, ms: number, ...args: any[]): NodeJS.Timer; - export function setImmediate(callback: (...args: any[]) => void, ...args: any[]): NodeJS.Immediate; - export function clearTimeout(timeoutId: NodeJS.Timer): void; - export function clearInterval(intervalId: NodeJS.Timer): void; - export function clearImmediate(immediateId: NodeJS.Immediate): void; -} diff --git a/typings/globals/node/typings.json b/typings/globals/node/typings.json deleted file mode 100644 index c03028d..0000000 --- a/typings/globals/node/typings.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "resolution": "main", - "tree": { - "src": "https://raw.githubusercontent.com/types/env-node/a5f9e16f769422e801156d494c45453670fc73cc/6.0/typings.json", - "raw": "registry:env/node#6.0.0+20170213133316", - "version": "6", - "files": [ - "node.d.ts" - ], - "name": "node" - } -} diff --git a/typings/globals/redux/index.d.ts b/typings/globals/redux/index.d.ts deleted file mode 100644 index ec275cd..0000000 --- a/typings/globals/redux/index.d.ts +++ /dev/null @@ -1,401 +0,0 @@ -// Generated by typings -// Source: https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/15ddcf312782faf9e7fdfe724a3a29382a5825d7/redux/redux.d.ts -declare namespace Redux { - /** - * An *action* is a plain object that represents an intention to change the - * state. Actions are the only way to get data into the store. Any data, - * whether from UI events, network callbacks, or other sources such as - * WebSockets needs to eventually be dispatched as actions. - * - * Actions must have a `type` field that indicates the type of action being - * performed. Types can be defined as constants and imported from another - * module. It’s better to use strings for `type` than Symbols because strings - * are serializable. - * - * Other than `type`, the structure of an action object is really up to you. - * If you’re interested, check out Flux Standard Action for recommendations on - * how actions should be constructed. - */ - interface Action { - type: any; - } - - - /* reducers */ - - /** - * A *reducer* (also called a *reducing function*) is a function that accepts - * an accumulation and a value and returns a new accumulation. They are used - * to reduce a collection of values down to a single value - * - * Reducers are not unique to Redux—they are a fundamental concept in - * functional programming. Even most non-functional languages, like - * JavaScript, have a built-in API for reducing. In JavaScript, it's - * `Array.prototype.reduce()`. - * - * In Redux, the accumulated value is the state object, and the values being - * accumulated are actions. Reducers calculate a new state given the previous - * state and an action. They must be *pure functions*—functions that return - * the exact same output for given inputs. They should also be free of - * side-effects. This is what enables exciting features like hot reloading and - * time travel. - * - * Reducers are the most important concept in Redux. - * - * *Do not put API calls into reducers.* - * - * @template S State object type. - */ - type Reducer = (state: S, action: A) => S; - - /** - * Object whose values correspond to different reducer functions. - */ - interface ReducersMapObject { - [key: string]: Reducer; - } - - /** - * Turns an object whose values are different reducer functions, into a single - * reducer function. It will call every child reducer, and gather their results - * into a single state object, whose keys correspond to the keys of the passed - * reducer functions. - * - * @template S Combined state object type. - * - * @param reducers An object whose values correspond to different reducer - * functions that need to be combined into one. One handy way to obtain it - * is to use ES6 `import * as reducers` syntax. The reducers may never - * return undefined for any action. Instead, they should return their - * initial state if the state passed to them was undefined, and the current - * state for any unrecognized action. - * - * @returns A reducer function that invokes every reducer inside the passed - * object, and builds a state object with the same shape. - */ - function combineReducers(reducers: ReducersMapObject): Reducer; - - - /* store */ - - /** - * A *dispatching function* (or simply *dispatch function*) is a function that - * accepts an action or an async action; it then may or may not dispatch one - * or more actions to the store. - * - * We must distinguish between dispatching functions in general and the base - * `dispatch` function provided by the store instance without any middleware. - * - * The base dispatch function *always* synchronously sends an action to the - * store’s reducer, along with the previous state returned by the store, to - * calculate a new state. It expects actions to be plain objects ready to be - * consumed by the reducer. - * - * Middleware wraps the base dispatch function. It allows the dispatch - * function to handle async actions in addition to actions. Middleware may - * transform, delay, ignore, or otherwise interpret actions or async actions - * before passing them to the next middleware. - */ - interface Dispatch { - (action: A): A; - } - - /** - * Function to remove listener added by `Store.subscribe()`. - */ - interface Unsubscribe { - (): void; - } - - /** - * A store is an object that holds the application’s state tree. - * There should only be a single store in a Redux app, as the composition - * happens on the reducer level. - * - * @template S State object type. - */ - interface Store { - /** - * Dispatches an action. It is the only way to trigger a state change. - * - * The `reducer` function, used to create the store, will be called with the - * current state tree and the given `action`. Its return value will be - * considered the **next** state of the tree, and the change listeners will - * be notified. - * - * The base implementation only supports plain object actions. If you want - * to dispatch a Promise, an Observable, a thunk, or something else, you - * need to wrap your store creating function into the corresponding - * middleware. For example, see the documentation for the `redux-thunk` - * package. Even the middleware will eventually dispatch plain object - * actions using this method. - * - * @param action A plain object representing “what changed”. It is a good - * idea to keep actions serializable so you can record and replay user - * sessions, or use the time travelling `redux-devtools`. An action must - * have a `type` property which may not be `undefined`. It is a good idea - * to use string constants for action types. - * - * @returns For convenience, the same action object you dispatched. - * - * Note that, if you use a custom middleware, it may wrap `dispatch()` to - * return something else (for example, a Promise you can await). - */ - dispatch: Dispatch; - - /** - * Reads the state tree managed by the store. - * - * @returns The current state tree of your application. - */ - getState(): S; - - /** - * Adds a change listener. It will be called any time an action is - * dispatched, and some part of the state tree may potentially have changed. - * You may then call `getState()` to read the current state tree inside the - * callback. - * - * You may call `dispatch()` from a change listener, with the following - * caveats: - * - * 1. The subscriptions are snapshotted just before every `dispatch()` call. - * If you subscribe or unsubscribe while the listeners are being invoked, - * this will not have any effect on the `dispatch()` that is currently in - * progress. However, the next `dispatch()` call, whether nested or not, - * will use a more recent snapshot of the subscription list. - * - * 2. The listener should not expect to see all states changes, as the state - * might have been updated multiple times during a nested `dispatch()` before - * the listener is called. It is, however, guaranteed that all subscribers - * registered before the `dispatch()` started will be called with the latest - * state by the time it exits. - * - * @param listener A callback to be invoked on every dispatch. - * @returns A function to remove this change listener. - */ - subscribe(listener: () => void): Unsubscribe; - - /** - * Replaces the reducer currently used by the store to calculate the state. - * - * You might need this if your app implements code splitting and you want to - * load some of the reducers dynamically. You might also need this if you - * implement a hot reloading mechanism for Redux. - * - * @param nextReducer The reducer for the store to use instead. - */ - replaceReducer(nextReducer: Reducer): void; - } - - /** - * A store creator is a function that creates a Redux store. Like with - * dispatching function, we must distinguish the base store creator, - * `createStore(reducer, preloadedState)` exported from the Redux package, from - * store creators that are returned from the store enhancers. - * - * @template S State object type. - */ - interface StoreCreator { - (reducer: Reducer, enhancer?: StoreEnhancer): Store; - (reducer: Reducer, preloadedState: S, enhancer?: StoreEnhancer): Store; - } - - /** - * A store enhancer is a higher-order function that composes a store creator - * to return a new, enhanced store creator. This is similar to middleware in - * that it allows you to alter the store interface in a composable way. - * - * Store enhancers are much the same concept as higher-order components in - * React, which are also occasionally called “component enhancers”. - * - * Because a store is not an instance, but rather a plain-object collection of - * functions, copies can be easily created and modified without mutating the - * original store. There is an example in `compose` documentation - * demonstrating that. - * - * Most likely you’ll never write a store enhancer, but you may use the one - * provided by the developer tools. It is what makes time travel possible - * without the app being aware it is happening. Amusingly, the Redux - * middleware implementation is itself a store enhancer. - */ - type StoreEnhancer = (next: StoreEnhancerStoreCreator) => StoreEnhancerStoreCreator; - type GenericStoreEnhancer = (next: StoreEnhancerStoreCreator) => StoreEnhancerStoreCreator; - type StoreEnhancerStoreCreator = (reducer: Reducer, preloadedState?: S) => Store; - - /** - * Creates a Redux store that holds the state tree. - * The only way to change the data in the store is to call `dispatch()` on it. - * - * There should only be a single store in your app. To specify how different - * parts of the state tree respond to actions, you may combine several - * reducers - * into a single reducer function by using `combineReducers`. - * - * @template S State object type. - * - * @param reducer A function that returns the next state tree, given the - * current state tree and the action to handle. - * - * @param [preloadedState] The initial state. You may optionally specify it to - * hydrate the state from the server in universal apps, or to restore a - * previously serialized user session. If you use `combineReducers` to - * produce the root reducer function, this must be an object with the same - * shape as `combineReducers` keys. - * - * @param [enhancer] The store enhancer. You may optionally specify it to - * enhance the store with third-party capabilities such as middleware, time - * travel, persistence, etc. The only store enhancer that ships with Redux - * is `applyMiddleware()`. - * - * @returns A Redux store that lets you read the state, dispatch actions and - * subscribe to changes. - */ - const createStore: StoreCreator; - - - /* middleware */ - - interface MiddlewareAPI { - dispatch: Dispatch; - getState(): S; - } - - /** - * A middleware is a higher-order function that composes a dispatch function - * to return a new dispatch function. It often turns async actions into - * actions. - * - * Middleware is composable using function composition. It is useful for - * logging actions, performing side effects like routing, or turning an - * asynchronous API call into a series of synchronous actions. - */ - interface Middleware { - (api: MiddlewareAPI): (next: Dispatch) => Dispatch; - } - - /** - * Creates a store enhancer that applies middleware to the dispatch method - * of the Redux store. This is handy for a variety of tasks, such as - * expressing asynchronous actions in a concise manner, or logging every - * action payload. - * - * See `redux-thunk` package as an example of the Redux middleware. - * - * Because middleware is potentially asynchronous, this should be the first - * store enhancer in the composition chain. - * - * Note that each middleware will be given the `dispatch` and `getState` - * functions as named arguments. - * - * @param middlewares The middleware chain to be applied. - * @returns A store enhancer applying the middleware. - */ - function applyMiddleware(...middlewares: Middleware[]): GenericStoreEnhancer; - - - /* action creators */ - - /** - * An *action creator* is, quite simply, a function that creates an action. Do - * not confuse the two terms—again, an action is a payload of information, and - * an action creator is a factory that creates an action. - * - * Calling an action creator only produces an action, but does not dispatch - * it. You need to call the store’s `dispatch` function to actually cause the - * mutation. Sometimes we say *bound action creators* to mean functions that - * call an action creator and immediately dispatch its result to a specific - * store instance. - * - * If an action creator needs to read the current state, perform an API call, - * or cause a side effect, like a routing transition, it should return an - * async action instead of an action. - * - * @template A Returned action type. - */ - interface ActionCreator { - (...args: any[]): A; - } - - /** - * Object whose values are action creator functions. - */ - interface ActionCreatorsMapObject { - [key: string]: ActionCreator; - } - - /** - * Turns an object whose values are action creators, into an object with the - * same keys, but with every function wrapped into a `dispatch` call so they - * may be invoked directly. This is just a convenience method, as you can call - * `store.dispatch(MyActionCreators.doSomething())` yourself just fine. - * - * For convenience, you can also pass a single function as the first argument, - * and get a function in return. - * - * @param actionCreator An object whose values are action creator functions. - * One handy way to obtain it is to use ES6 `import * as` syntax. You may - * also pass a single function. - * - * @param dispatch The `dispatch` function available on your Redux store. - * - * @returns The object mimicking the original object, but with every action - * creator wrapped into the `dispatch` call. If you passed a function as - * `actionCreator`, the return value will also be a single function. - */ - function bindActionCreators>(actionCreator: A, dispatch: Dispatch): A; - - function bindActionCreators< - A extends ActionCreator, - B extends ActionCreator - >(actionCreator: A, dispatch: Dispatch): B; - - function bindActionCreators(actionCreators: M, dispatch: Dispatch): M; - - function bindActionCreators< - M extends ActionCreatorsMapObject, - N extends ActionCreatorsMapObject - >(actionCreators: M, dispatch: Dispatch): N; - - - /* compose */ - - /** - * Composes single-argument functions from right to left. The rightmost - * function can take multiple arguments as it provides the signature for the - * resulting composite function. - * - * @param funcs The functions to compose. - * @returns R function obtained by composing the argument functions from right - * to left. For example, `compose(f, g, h)` is identical to doing - * `(...args) => f(g(h(...args)))`. - */ - function compose(): (a: R, ...args: any[]) => R; - - function compose( - f1: (b: A) => R, - f2: (...args: any[]) => A - ): (...args: any[]) => R; - - function compose( - f1: (b: B) => R, - f2: (a: A) => B, - f3: (...args: any[]) => A - ): (...args: any[]) => R; - - function compose( - f1: (b: C) => R, - f2: (a: B) => C, - f3: (a: A) => B, - f4: (...args: any[]) => A - ): (...args: any[]) => R; - - function compose( - f1: (a: any) => R, - ...funcs: Function[] - ): (...args: any[]) => R; -} - -declare module "redux" { - export = Redux; -} diff --git a/typings/globals/redux/typings.json b/typings/globals/redux/typings.json deleted file mode 100644 index 2a3e626..0000000 --- a/typings/globals/redux/typings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "resolution": "main", - "tree": { - "src": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/15ddcf312782faf9e7fdfe724a3a29382a5825d7/redux/redux.d.ts", - "raw": "registry:dt/redux#3.5.2+20160703092728", - "typings": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/15ddcf312782faf9e7fdfe724a3a29382a5825d7/redux/redux.d.ts" - } -} diff --git a/typings/index.d.ts b/typings/index.d.ts deleted file mode 100644 index feb4f38..0000000 --- a/typings/index.d.ts +++ /dev/null @@ -1,9 +0,0 @@ -/// -/// -/// -/// -/// -/// -/// -/// -/// diff --git a/typings/modules/extract-text-webpack-plugin/index.d.ts b/typings/modules/extract-text-webpack-plugin/index.d.ts deleted file mode 100644 index 4b6ce81..0000000 --- a/typings/modules/extract-text-webpack-plugin/index.d.ts +++ /dev/null @@ -1,53 +0,0 @@ -// Generated by typings -// Source: https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/df177d2915be6639a2d30d39805985ea9a3e10e6/extract-text-webpack-plugin/index.d.ts -declare module 'extract-text-webpack-plugin' { -// Type definitions for extract-text-webpack-plugin 2.0.0 -// Project: https://github.com/webpack/extract-text-webpack-plugin -// Definitions by: flying-sheep -// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped - -import { Plugin, OldLoader } from 'webpack' - -/** - * extract-text-webpack-plugin has no support for .options instead of .query yet. - * See https://github.com/webpack/extract-text-webpack-plugin/issues/281 - */ -type Loader = string | OldLoader - -interface ExtractPluginOptions { - /** the filename of the result file. May contain `[name]`, `[id]` and `[contenthash]` */ - filename: string - /** extract from all additional chunks too (by default it extracts only from the initial chunk(s)) */ - allChunks?: boolean - /** disables the plugin */ - disable?: boolean - /** Unique ident for this plugin instance. (For advanced usage only, by default automatically generated) */ - id?: string -} - -interface ExtractOptions { - /** the loader(s) that should be used for converting the resource to a css exporting module */ - loader: Loader | Loader[] - /** the loader(s) that should be used when the css is not extracted (i.e. in an additional chunk when `allChunks: false`) */ - fallbackLoader?: Loader | Loader[] - /** override the `publicPath` setting for this loader */ - publicPath?: string -} - -/** - * Use an `ExtractTextPlugin` instance and a loader returned by `extract` in concert to write files to disk instead of loading them into others. - * Usage example at https://github.com/webpack/extract-text-webpack-plugin#usage-example-with-css - */ -interface ExtractTextPlugin extends Plugin { - /** Create a plugin instance defining the extraction target file(s) for the files loaded by `extract` */ - new (options: string | ExtractPluginOptions): ExtractTextPlugin - /** - * Creates an extracting loader from an existing loader. - * Use the resulting loader in `module.rules`/`module.loaders`. - */ - extract: (loader: Loader | Loader[] | ExtractOptions) => Loader -} - -const extractTextPlugin: ExtractTextPlugin -export = extractTextPlugin -} diff --git a/typings/modules/extract-text-webpack-plugin/typings.json b/typings/modules/extract-text-webpack-plugin/typings.json deleted file mode 100644 index 4be4156..0000000 --- a/typings/modules/extract-text-webpack-plugin/typings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "resolution": "main", - "tree": { - "src": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/df177d2915be6639a2d30d39805985ea9a3e10e6/extract-text-webpack-plugin/index.d.ts", - "raw": "registry:dt/extract-text-webpack-plugin#2.0.0+20161115081840", - "typings": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/df177d2915be6639a2d30d39805985ea9a3e10e6/extract-text-webpack-plugin/index.d.ts" - } -} diff --git a/typings/modules/react-dom/index.d.ts b/typings/modules/react-dom/index.d.ts deleted file mode 100644 index 48d43ba..0000000 --- a/typings/modules/react-dom/index.d.ts +++ /dev/null @@ -1,67 +0,0 @@ -// Generated by typings -// Source: https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/47f5a06ab00097373ee387f9b5ebad6d90d9cae9/react-dom/index.d.ts -declare module 'react-dom' { -// Type definitions for React (react-dom) 0.14 -// Project: http://facebook.github.io/react/ -// Definitions by: Asana , AssureSign , Microsoft -// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// TypeScript Version: 2.1 - -export as namespace ReactDOM; -export = ReactDOM; - -import { ReactInstance, Component, ComponentState, - ReactElement, SFCElement, CElement, - DOMAttributes, DOMElement } from 'react'; - -namespace ReactDOM { - function findDOMNode(instance: ReactInstance): E; - function findDOMNode(instance: ReactInstance): Element; - - function render

, T extends Element>( - element: DOMElement, - container: Element | null, - callback?: (element: T) => any): T; - function render

( - element: SFCElement

, - container: Element | null, - callback?: () => any): void; - function render>( - element: CElement, - container: Element | null, - callback?: (component: T) => any): T; - function render

( - element: ReactElement

, - container: Element | null, - callback?: (component?: Component | Element) => any): Component | Element | void; - - function unmountComponentAtNode(container: Element): boolean; - - var version: string; - - function unstable_batchedUpdates(callback: (a: A, b: B) => any, a: A, b: B): void; - function unstable_batchedUpdates(callback: (a: A) => any, a: A): void; - function unstable_batchedUpdates(callback: () => any): void; - - function unstable_renderSubtreeIntoContainer

, T extends Element>( - parentComponent: Component, - element: DOMElement, - container: Element, - callback?: (element: T) => any): T; - function unstable_renderSubtreeIntoContainer>( - parentComponent: Component, - element: CElement, - container: Element, - callback?: (component: T) => any): T; - function render

( - parentComponent: Component, - element: SFCElement

, - container: Element, - callback?: () => any): void; - function unstable_renderSubtreeIntoContainer

( - parentComponent: Component, - element: ReactElement

, - container: Element, - callback?: (component?: Component | Element) => any): Component | Element | void; -} -} diff --git a/typings/modules/react-dom/typings.json b/typings/modules/react-dom/typings.json deleted file mode 100644 index cae6e92..0000000 --- a/typings/modules/react-dom/typings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "resolution": "main", - "tree": { - "src": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/47f5a06ab00097373ee387f9b5ebad6d90d9cae9/react-dom/index.d.ts", - "raw": "registry:dt/react-dom#0.14.0+20170207010524", - "typings": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/47f5a06ab00097373ee387f9b5ebad6d90d9cae9/react-dom/index.d.ts" - } -} diff --git a/typings/modules/react-redux/index.d.ts b/typings/modules/react-redux/index.d.ts deleted file mode 100644 index 9af5e1c..0000000 --- a/typings/modules/react-redux/index.d.ts +++ /dev/null @@ -1,107 +0,0 @@ -// Generated by typings -// Source: https://raw.githubusercontent.com/andrew-w-ross/typings-redux/master/redux.d.ts -declare module '~react-redux~redux' { -module redux { - //This should be extended - export interface IAction { - type: string | number; - } - - export interface IActionGeneric extends IAction { - payload?: TPayload; - error?: Error; - meta?: any; - } - - export interface IReducer { - (state: TState, action: IAction): TState; - } - - export interface IReducerMap { - [key: string]: IReducerMap | IReducer - } - - export interface IDispatch { - (action: IAction): IAction; - } - - export interface IMiddlewareStore { - getState(): TState; - - dispatch: IDispatch; - } - - export interface IStore extends IMiddlewareStore { - subscribe(listener: (state: TState) => any): () => void; - - replaceReducer(nextReducer: IReducer): void; - } - - export interface IMiddleware { - (middlewareStore: IMiddlewareStore): (next: IDispatch) => IDispatch; - } - - export interface ICreateStoreGeneric { - (reducer: IReducer, initialState?: TState): IStore; - } - - export interface IStoreEnhancerGeneric { - (createStore: ICreateStoreGeneric): ICreateStoreGeneric; - } - - export function createStore(reducer: IReducer, initialState?: TState): IStore; - - export function combineReducers(reducers: IReducerMap): IReducer; - export function combineReducers(reducers: IReducerMap): IReducer; - - export function applyMiddleware(...middlewares: IMiddleware[]): IStoreEnhancerGeneric; - - export function bindActionCreators(actionCreators: TActionCreator, dispatch: IDispatch): TActionCreator; - - export function compose(...functions: { (arg: TArg): TArg }[]): (arg: TArg) => TArg; - export function compose(...functions: { (arg: any): any }[]): (arg: any) => any; -} - -export = redux; -} - -// Generated by typings -// Source: https://raw.githubusercontent.com/andrew-w-ross/typings-react-redux/21202533f75a73d4fa4c50e0357aaf23739fcabb/react-redux.d.ts -declare module 'react-redux' { - -import * as React from 'react'; -import {IStore, IDispatch} from '~react-redux~redux'; - -module ReactRedux { - - export class Provider extends React.Component<{store:IStore},{}>{} - - export interface IMapStateToProps { - (state: any, ownProps?: any): Object; - } - - export interface IMapDispatchToProps { - (dispatch: IDispatch, ownProps?: any): Object; - } - - export interface IConnectOptions { - pure?: boolean; - withRef?: boolean; - } - - type ComponentConstructor

= React.ComponentClass

| React.StatelessComponent

- - function wrapWithConnect>( - component: T - ): T - - export function connect( - mapStateToProps?: IMapStateToProps, - mapDispatchToProps?: IMapDispatchToProps | Object, - mergeProps?: (stateProps: Object, dispatchProps: Object, ownProps: Object) => Object, - options?: IConnectOptions - ): typeof wrapWithConnect; -} - -export = ReactRedux; -} diff --git a/typings/modules/react-redux/typings.json b/typings/modules/react-redux/typings.json deleted file mode 100644 index 13023eb..0000000 --- a/typings/modules/react-redux/typings.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "resolution": "main", - "tree": { - "src": "https://raw.githubusercontent.com/andrew-w-ross/typings-react-redux/21202533f75a73d4fa4c50e0357aaf23739fcabb/typings.json", - "raw": "registry:npm/react-redux#4.4.0+20160614222153", - "main": "react-redux.d.ts", - "dependencies": { - "redux": { - "src": "https://raw.githubusercontent.com/andrew-w-ross/typings-redux/master/typings.json", - "raw": "github:andrew-w-ross/typings-redux", - "main": "redux.d.ts", - "name": "redux" - } - }, - "name": "react-redux" - } -} diff --git a/typings/modules/react/index.d.ts b/typings/modules/react/index.d.ts deleted file mode 100644 index 4599786..0000000 --- a/typings/modules/react/index.d.ts +++ /dev/null @@ -1,2858 +0,0 @@ -// Generated by typings -// Source: https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/b7ebd9c00eba1d557aac93d3e8b6d93c10b59a1a/react/index.d.ts -declare module 'react' { -// Type definitions for React v15.0 -// Project: http://facebook.github.io/react/ -// Definitions by: Asana , AssureSign , Microsoft , John Reilly , Benoit Benezech , Patricio Zavolinsky , Digiguru -// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// TypeScript Version: 2.1 - -export = React; -export as namespace React; - -namespace React { - - // - // React Elements - // ---------------------------------------------------------------------- - - type ReactType = string | ComponentClass | StatelessComponent; - - type Key = string | number; - type Ref = string | ((instance: T) => any); - type ComponentState = {} | void; - - interface Attributes { - key?: Key; - } - interface ClassAttributes extends Attributes { - ref?: Ref; - } - - interface ReactElement

{ - type: string | ComponentClass

| SFC

; - props: P; - key: Key | null; - } - - interface SFCElement

extends ReactElement

{ - type: SFC

; - } - - type CElement> = ComponentElement; - interface ComponentElement> extends ReactElement

{ - type: ComponentClass

; - ref?: Ref; - } - - type ClassicElement

= CElement>; - - interface DOMElement

, T extends Element> extends ReactElement

{ - type: string; - ref: Ref; - } - - interface ReactHTMLElement extends DOMElement, T> { - } - - interface ReactSVGElement extends DOMElement, SVGElement> { - } - - // - // Factories - // ---------------------------------------------------------------------- - - interface Factory

{ - (props?: Attributes & P, ...children: ReactNode[]): ReactElement

; - } - - interface SFCFactory

{ - (props?: Attributes & P, ...children: ReactNode[]): SFCElement

; - } - - interface ComponentFactory> { - (props?: ClassAttributes & P, ...children: ReactNode[]): CElement; - } - - type CFactory> = ComponentFactory; - type ClassicFactory

= CFactory>; - - interface DOMFactory

, T extends Element> { - (props?: ClassAttributes & P | null, ...children: ReactNode[]): DOMElement; - } - - interface HTMLFactory extends DOMFactory, T> { - } - - interface ChangeTargetHTMLFactory extends DOMFactory, T> { - } - - interface SVGFactory extends DOMFactory, SVGElement> { - } - - // - // React Nodes - // http://facebook.github.io/react/docs/glossary.html - // ---------------------------------------------------------------------- - - type ReactText = string | number; - type ReactChild = ReactElement | ReactText; - - // Should be Array but type aliases cannot be recursive - type ReactFragment = {} | Array; - type ReactNode = ReactChild | ReactFragment | boolean | null | undefined; - - // - // Top Level API - // ---------------------------------------------------------------------- - - function createClass(spec: ComponentSpec): ClassicComponentClass

; - - function createFactory

, T extends Element>( - type: string): DOMFactory; - function createFactory

(type: SFC

): SFCFactory

; - function createFactory

( - type: ClassType, ClassicComponentClass

>): CFactory>; - function createFactory, C extends ComponentClass

>( - type: ClassType): CFactory; - function createFactory

(type: ComponentClass

): Factory

; - - function createElement

, T extends Element>( - type: string, - props?: ClassAttributes & P, - ...children: ReactNode[]): DOMElement; - function createElement

( - type: SFC

, - props?: Attributes & P, - ...children: ReactNode[]): SFCElement

; - function createElement

( - type: ClassType, ClassicComponentClass

>, - props?: ClassAttributes> & P, - ...children: ReactNode[]): CElement>; - function createElement, C extends ComponentClass

>( - type: ClassType, - props?: ClassAttributes & P, - ...children: ReactNode[]): CElement; - function createElement

( - type: ComponentClass

, - props?: Attributes & P, - ...children: ReactNode[]): ReactElement

; - - function cloneElement

, T extends Element>( - element: DOMElement, - props?: ClassAttributes & P, - ...children: ReactNode[]): DOMElement; - function cloneElement

( - element: SFCElement

, - props?: Q, // should be Q & Attributes, but then Q is inferred as {} - ...children: ReactNode[]): SFCElement

; - function cloneElement

>( - element: CElement, - props?: Q, // should be Q & ClassAttributes - ...children: ReactNode[]): CElement; - function cloneElement

( - element: ReactElement

, - props?: Q, // should be Q & Attributes - ...children: ReactNode[]): ReactElement

; - - function isValidElement

(object: {}): object is ReactElement

; - - var DOM: ReactDOM; - var PropTypes: ReactPropTypes; - var Children: ReactChildren; - var version: string; - - // - // Component API - // ---------------------------------------------------------------------- - - type ReactInstance = Component | Element; - - // Base component for plain JS classes - class Component implements ComponentLifecycle { - constructor(props?: P, context?: any); - setState(f: (prevState: S, props: P) => Pick, callback?: () => any): void; - setState(state: Pick, callback?: () => any): void; - forceUpdate(callBack?: () => any): void; - render(): JSX.Element | null; - - // React.Props is now deprecated, which means that the `children` - // property is not available on `P` by default, even though you can - // always pass children as variadic arguments to `createElement`. - // In the future, if we can define its call signature conditionally - // on the existence of `children` in `P`, then we should remove this. - props: Readonly<{ children?: ReactNode }> & Readonly

; - state: Readonly; - context: any; - refs: { - [key: string]: ReactInstance - }; - } - - class PureComponent extends Component { } - - interface ClassicComponent extends Component { - replaceState(nextState: S, callback?: () => any): void; - isMounted(): boolean; - getInitialState?(): S; - } - - interface ChildContextProvider { - getChildContext(): CC; - } - - // - // Class Interfaces - // ---------------------------------------------------------------------- - - type SFC

= StatelessComponent

; - interface StatelessComponent

{ - (props: P & { children?: ReactNode }, context?: any): ReactElement; - propTypes?: ValidationMap

; - contextTypes?: ValidationMap; - defaultProps?: Partial

; - displayName?: string; - } - - interface ComponentClass

{ - new (props?: P, context?: any): Component; - propTypes?: ValidationMap

; - contextTypes?: ValidationMap; - childContextTypes?: ValidationMap; - defaultProps?: Partial

; - displayName?: string; - } - - interface ClassicComponentClass

extends ComponentClass

{ - new (props?: P, context?: any): ClassicComponent; - getDefaultProps?(): P; - } - - /** - * We use an intersection type to infer multiple type parameters from - * a single argument, which is useful for many top-level API defs. - * See https://github.com/Microsoft/TypeScript/issues/7234 for more info. - */ - type ClassType, C extends ComponentClass

> = - C & - (new (props?: P, context?: any) => T) & - (new (props?: P, context?: any) => { props: P }); - - // - // Component Specs and Lifecycle - // ---------------------------------------------------------------------- - - interface ComponentLifecycle { - componentWillMount?(): void; - componentDidMount?(): void; - componentWillReceiveProps?(nextProps: P, nextContext: any): void; - shouldComponentUpdate?(nextProps: P, nextState: S, nextContext: any): boolean; - componentWillUpdate?(nextProps: P, nextState: S, nextContext: any): void; - componentDidUpdate?(prevProps: P, prevState: S, prevContext: any): void; - componentWillUnmount?(): void; - } - - interface Mixin extends ComponentLifecycle { - mixins?: Mixin; - statics?: { - [key: string]: any; - }; - - displayName?: string; - propTypes?: ValidationMap; - contextTypes?: ValidationMap; - childContextTypes?: ValidationMap; - - getDefaultProps?(): P; - getInitialState?(): S; - } - - interface ComponentSpec extends Mixin { - render(): ReactElement | null; - - [propertyName: string]: any; - } - - // - // Event System - // ---------------------------------------------------------------------- - - interface SyntheticEvent { - bubbles: boolean; - currentTarget: EventTarget & T; - cancelable: boolean; - defaultPrevented: boolean; - eventPhase: number; - isTrusted: boolean; - nativeEvent: Event; - preventDefault(): void; - isDefaultPrevented(): boolean; - stopPropagation(): void; - isPropagationStopped(): boolean; - persist(): void; - // If you thought this should be `EventTarget & T`, see https://github.com/DefinitelyTyped/DefinitelyTyped/pull/12239 - target: EventTarget; - timeStamp: Date; - type: string; - } - - interface ClipboardEvent extends SyntheticEvent { - clipboardData: DataTransfer; - } - - interface CompositionEvent extends SyntheticEvent { - data: string; - } - - interface DragEvent extends MouseEvent { - dataTransfer: DataTransfer; - } - - interface FocusEvent extends SyntheticEvent { - relatedTarget: EventTarget; - } - - interface FormEvent extends SyntheticEvent { - } - - interface ChangeEvent extends SyntheticEvent { - target: EventTarget & T; - } - - interface KeyboardEvent extends SyntheticEvent { - altKey: boolean; - charCode: number; - ctrlKey: boolean; - getModifierState(key: string): boolean; - key: string; - keyCode: number; - locale: string; - location: number; - metaKey: boolean; - repeat: boolean; - shiftKey: boolean; - which: number; - } - - interface MouseEvent extends SyntheticEvent { - altKey: boolean; - button: number; - buttons: number; - clientX: number; - clientY: number; - ctrlKey: boolean; - getModifierState(key: string): boolean; - metaKey: boolean; - pageX: number; - pageY: number; - relatedTarget: EventTarget; - screenX: number; - screenY: number; - shiftKey: boolean; - } - - interface TouchEvent extends SyntheticEvent { - altKey: boolean; - changedTouches: TouchList; - ctrlKey: boolean; - getModifierState(key: string): boolean; - metaKey: boolean; - shiftKey: boolean; - targetTouches: TouchList; - touches: TouchList; - } - - interface UIEvent extends SyntheticEvent { - detail: number; - view: AbstractView; - } - - interface WheelEvent extends MouseEvent { - deltaMode: number; - deltaX: number; - deltaY: number; - deltaZ: number; - } - - interface AnimationEvent extends SyntheticEvent { - animationName: string; - pseudoElement: string; - elapsedTime: number; - } - - interface TransitionEvent extends SyntheticEvent { - propertyName: string; - pseudoElement: string; - elapsedTime: number; - } - - // - // Event Handler Types - // ---------------------------------------------------------------------- - - interface EventHandler> { - (event: E): void; - } - - type ReactEventHandler = EventHandler>; - - type ClipboardEventHandler = EventHandler>; - type CompositionEventHandler = EventHandler>; - type DragEventHandler = EventHandler>; - type FocusEventHandler = EventHandler>; - type FormEventHandler = EventHandler>; - type ChangeEventHandler = EventHandler>; - type KeyboardEventHandler = EventHandler>; - type MouseEventHandler = EventHandler>; - type TouchEventHandler = EventHandler>; - type UIEventHandler = EventHandler>; - type WheelEventHandler = EventHandler>; - type AnimationEventHandler = EventHandler>; - type TransitionEventHandler = EventHandler>; - - // - // Props / DOM Attributes - // ---------------------------------------------------------------------- - - /** - * @deprecated. This was used to allow clients to pass `ref` and `key` - * to `createElement`, which is no longer necessary due to intersection - * types. If you need to declare a props object before passing it to - * `createElement` or a factory, use `ClassAttributes`: - * - * ```ts - * var b: Button; - * var props: ButtonProps & ClassAttributes

-
+
Backup:
-
+
Restore:
-
+
Feedback: -
-
- © 2017-{`${new Date().getFullYear()} StarCabinet`} -
+
© 2017-{`${new Date().getFullYear()} StarCabinet`}
{ state = { desc: true, by: CONSTANTS.ORDER_BY_DEFAULT diff --git a/src/renderer/containers/app.tsx b/src/renderer/containers/app.tsx index 06cf16d..d46d858 100644 --- a/src/renderer/containers/app.tsx +++ b/src/renderer/containers/app.tsx @@ -1,9 +1,16 @@ import { connect } from "react-redux"; import App from "../components/app"; import Actions from "../actions"; +import IState from "../interface/IState"; + +export interface AppProps { + offline: boolean; + listenNetworkChange: () => void; + diListenNetworkChange: () => void; +} // Redux connection -const mapStateToProps = state => { +const mapStateToProps = (state: IState) => { return { offline: state.offline.value }; diff --git a/src/renderer/containers/filterBar.tsx b/src/renderer/containers/filterBar.tsx index 663c101..77d7b09 100644 --- a/src/renderer/containers/filterBar.tsx +++ b/src/renderer/containers/filterBar.tsx @@ -1,6 +1,15 @@ import { connect } from "react-redux"; import FilterBar from "../components/filterBar"; import Actions from "../actions"; +import IState from "../interface/IState"; +import { IFilterConditionState } from "../interface/IConditional"; +import { IRepoFetchingStatus } from "../interface/IRepo"; + +export interface FilterBarProps { + filter: IFilterConditionState; + fetchStatus: IRepoFetchingStatus; + onUpdateFilterCondition: (filter: IFilterConditionState) => void; +} // Redux connection const mapStateToProps = state => { diff --git a/src/renderer/containers/loginPage.tsx b/src/renderer/containers/loginPage.tsx index df3d916..47cd329 100644 --- a/src/renderer/containers/loginPage.tsx +++ b/src/renderer/containers/loginPage.tsx @@ -1,9 +1,16 @@ import { connect } from "react-redux"; import LoginPage from "../components/loginPage"; import Actions from "../actions"; +import IState from "../interface/IState"; +import { ICredentialsState, ILoginResultState } from "../interface/IAccount"; + +export interface LoginPageProps { + credentials: ICredentialsState; + loginResult: ILoginResultState; +} // Redux connection -const mapStateToProps = state => { +const mapStateToProps = (state: IState) => { return { credentials: state.credentials, loginResult: state.loginResult diff --git a/src/renderer/containers/mainDetailPane.tsx b/src/renderer/containers/mainDetailPane.tsx index 05ad8eb..9d30eeb 100644 --- a/src/renderer/containers/mainDetailPane.tsx +++ b/src/renderer/containers/mainDetailPane.tsx @@ -1,13 +1,12 @@ import { connect } from "react-redux"; import MainDetailPane from "../components/mainDetailPane"; -import Actions from "../actions"; // Redux connection -const mapStateToProps = state => { +const mapStateToProps = () => { return {}; }; -const mapDispatchToProps = dispatch => { +const mapDispatchToProps = () => { return {}; }; diff --git a/src/renderer/containers/mainGroupAvatar.tsx b/src/renderer/containers/mainGroupAvatar.tsx index bb14fc8..46a0b81 100644 --- a/src/renderer/containers/mainGroupAvatar.tsx +++ b/src/renderer/containers/mainGroupAvatar.tsx @@ -1,8 +1,14 @@ import { connect } from "react-redux"; import MainGroupAvatar from "../components/mainGroupAvatar"; +import IState from "../interface/IState"; +import IProfile from "../interface/IProfile"; + +export interface MainGroupAvatarProps { + profile: IProfile; +} // Redux connection -const mapStateToProps = state => { +const mapStateToProps = (state: IState) => { return { profile: state.profile }; diff --git a/src/renderer/containers/mainGroupFooter.tsx b/src/renderer/containers/mainGroupFooter.tsx index 0d885a1..e02ce4e 100644 --- a/src/renderer/containers/mainGroupFooter.tsx +++ b/src/renderer/containers/mainGroupFooter.tsx @@ -1,9 +1,16 @@ import { connect } from "react-redux"; import MainGroupFooter from "../components/mainGroupFooter"; import Actions from "../actions"; +import IState from "../interface/IState"; +import { ICategoryCreateResult } from "../interface/ICategory"; + +export interface MainGroupFooterProps { + catAdd: ICategoryCreateResult; + onAddNewCategory: (name: string) => void; +} // Redux connection -const mapStateToProps = state => { +const mapStateToProps = (state: IState) => { return { catAdd: state.catAdd }; diff --git a/src/renderer/containers/mainGroupNavs.tsx b/src/renderer/containers/mainGroupNavs.tsx index 3acce12..f7662fe 100644 --- a/src/renderer/containers/mainGroupNavs.tsx +++ b/src/renderer/containers/mainGroupNavs.tsx @@ -1,9 +1,23 @@ import { connect } from "react-redux"; import MainGroupNavs from "../components/mainGroupNavs"; import Actions from "../actions"; +import IState from "../interface/IState"; +import { IGroupConditionState } from "../interface/IConditional"; +import ILanguage from "../interface/ILanguage"; +import ICategory from "../interface/ICategory"; +import { IRepoFetchingStatus } from "../interface/IRepo"; + +export interface MainGroupNavsProps { + group: IGroupConditionState; + languages: ILanguage[]; + categories: ICategory[]; + fetchStatus: IRepoFetchingStatus; + onUpdateGroupCondition: (group: IGroupConditionState) => void; + onDeleteCategory: (id: number) => void; +} // Redux connection -const mapStateToProps = state => { +const mapStateToProps = (state: IState) => { return { group: state.group, languages: state.languages, diff --git a/src/renderer/containers/mainGroupPane.tsx b/src/renderer/containers/mainGroupPane.tsx index aa12051..b5977b2 100644 --- a/src/renderer/containers/mainGroupPane.tsx +++ b/src/renderer/containers/mainGroupPane.tsx @@ -2,11 +2,11 @@ import { connect } from "react-redux"; import MainGroupPane from "../components/mainGroupPane"; // Redux connection -const mapStateToProps = _state => { +const mapStateToProps = () => { return {}; }; -const mapDispatchToProps = _dispatch => { +const mapDispatchToProps = () => { return {}; }; diff --git a/src/renderer/containers/mainListPane.tsx b/src/renderer/containers/mainListPane.tsx index 7f747fc..0e5dacb 100644 --- a/src/renderer/containers/mainListPane.tsx +++ b/src/renderer/containers/mainListPane.tsx @@ -1,13 +1,12 @@ import { connect } from "react-redux"; import MainListPane from "../components/mainListPane"; -import Actions from "../actions"; // Redux connection -const mapStateToProps = state => { +const mapStateToProps = () => { return {}; }; -const mapDispatchToProps = dispatch => { +const mapDispatchToProps = () => { return {}; }; diff --git a/src/renderer/containers/mainPage.tsx b/src/renderer/containers/mainPage.tsx index 60aecb8..9155903 100644 --- a/src/renderer/containers/mainPage.tsx +++ b/src/renderer/containers/mainPage.tsx @@ -1,9 +1,30 @@ import { connect } from "react-redux"; import MainPage from "../components/mainPage"; import Actions from "../actions"; +import IState from "../interface/IState"; +import { + ISearchConditionState, + IFilterConditionState, + IOrderConditionState, + IGroupConditionState +} from "../interface/IConditional"; +import { ICredentialsState } from "../interface/IAccount"; + +export interface MainPageProps { + search: ISearchConditionState; + order: IOrderConditionState; + filter: IFilterConditionState; + group: IGroupConditionState; + onGetLocalCredentials: () => Promise; + onGetRxDB: (dbName: string) => void; + onNeedUpdateReposList: () => void; + onGetMyProfile: () => void; + onGetCategories: () => void; + onFetchStarredRepos: () => void; +} // Redux connection -const mapStateToProps = state => { +const mapStateToProps = (state: IState) => { return { search: state.search, order: state.order, diff --git a/src/renderer/containers/mainSearchBox.tsx b/src/renderer/containers/mainSearchBox.tsx index 3e3e3b9..8d00ca0 100644 --- a/src/renderer/containers/mainSearchBox.tsx +++ b/src/renderer/containers/mainSearchBox.tsx @@ -1,9 +1,19 @@ import { connect } from "react-redux"; import MainSearchBox from "../components/mainSearchBox"; import Actions from "../actions"; +import IState from "../interface/IState"; +import { ISearchConditionState } from "../interface/IConditional"; +import IRepo, { IRepoFetchingStatus } from "../interface/IRepo"; + +export interface MainSearchBoxProps { + search: ISearchConditionState; + fetchStatus: IRepoFetchingStatus; + repos: { [key: string]: IRepo }; + onUpdateSearchCondition: (search: ISearchConditionState) => void; +} // Redux connection -const mapStateToProps = state => { +const mapStateToProps = (state: IState) => { return { search: state.search, fetchStatus: state.fetchStatus, diff --git a/src/renderer/containers/refreshIndicator.tsx b/src/renderer/containers/refreshIndicator.tsx index bd99705..51063eb 100644 --- a/src/renderer/containers/refreshIndicator.tsx +++ b/src/renderer/containers/refreshIndicator.tsx @@ -1,9 +1,20 @@ import { connect } from "react-redux"; import RefreshIndicator from "../components/refreshIndicator"; import Actions from "../actions"; +import IState from "../interface/IState"; +import { IRepoFetchingStatus } from "../interface/IRepo"; +import IOfflineState from "../interface/IOffline"; + +export interface RefreshIndicatorProps { + fetchStatus: IRepoFetchingStatus; + offline: IOfflineState; + increase: number; + onRefresh: () => void; + onClearIncreaseProp: () => void; +} // Redux connection -const mapStateToProps = state => { +const mapStateToProps = (state: IState) => { return { fetchStatus: state.fetchStatus, offline: state.offline.value, diff --git a/src/renderer/containers/repoClassifyTool.tsx b/src/renderer/containers/repoClassifyTool.tsx index 1a0b0f3..5c1ecda 100644 --- a/src/renderer/containers/repoClassifyTool.tsx +++ b/src/renderer/containers/repoClassifyTool.tsx @@ -1,9 +1,19 @@ import { connect } from "react-redux"; import RepoClassifyTool from "../components/repoClassifyTool"; import Actions from "../actions"; +import IState from "../interface/IState"; +import ICategory from "../interface/ICategory"; +import IRepo from "../interface/IRepo"; + +export interface RepoClassifyToolProps { + repo: IRepo; + categories: ICategory[]; + onGetCategoriesForRepo: (id: number) => void; + onUpdateRepoCategories: (id: number, catIds: number[]) => void; +} // Redux connection -const mapStateToProps = state => { +const mapStateToProps = (state: IState) => { return { categories: state.categories }; diff --git a/src/renderer/containers/repoContributorsBar.tsx b/src/renderer/containers/repoContributorsBar.tsx index 2ad0a21..d76dedf 100644 --- a/src/renderer/containers/repoContributorsBar.tsx +++ b/src/renderer/containers/repoContributorsBar.tsx @@ -1,9 +1,17 @@ import { connect } from "react-redux"; import RepoContributorsBar from "../components/repoContributorsBar"; import Actions from "../actions"; +import IState from "../interface/IState"; +import IRepo from "../interface/IRepo"; + +export interface RepoContributorsBarProps { + selectedRepo: IRepo | null; + onFetchRepoContributors: (repo: IRepo) => void; + onGetRepoContributors: (id: number) => void; +} // Redux connection -const mapStateToProps = state => { +const mapStateToProps = (state: IState) => { return { selectedRepo: state.selectedRepo }; diff --git a/src/renderer/containers/repoDetail.tsx b/src/renderer/containers/repoDetail.tsx index a59c5f5..637fa28 100644 --- a/src/renderer/containers/repoDetail.tsx +++ b/src/renderer/containers/repoDetail.tsx @@ -1,14 +1,20 @@ import { connect } from "react-redux"; import RepoDetail from "../components/repoDetail"; +import IState from "../interface/IState"; +import IRepo from "../interface/IRepo"; + +export interface RepoDetailProps { + selectedRepo: IRepo | null; +} // Redux connection -const mapStateToProps = state => { +const mapStateToProps = (state: IState) => { return { selectedRepo: state.selectedRepo }; }; -const mapDispatchToProps = _dispatch => { +const mapDispatchToProps = () => { return {}; }; diff --git a/src/renderer/containers/repoDetailToolbar.tsx b/src/renderer/containers/repoDetailToolbar.tsx index 5a795e1..81de0fb 100644 --- a/src/renderer/containers/repoDetailToolbar.tsx +++ b/src/renderer/containers/repoDetailToolbar.tsx @@ -1,9 +1,21 @@ import { connect } from "react-redux"; import RepoDetailToolbar from "../components/repoDetailToolbar"; import Actions from "../actions"; +import IState from "../interface/IState"; +import IRepo from "../interface/IRepo"; +import ICategory from "../interface/ICategory"; + +export interface RepoDetailToolbarProps { + categories: ICategory[]; + selectedRepo: IRepo | null; + onStarStarCabinet: () => void; + onUpdateRepoNote: (id: number, note: string) => void; + onChangeRepoFlag: (id: number, hasFlag: boolean) => void; + onChangeRepoReadStatus: (id: number, read: boolean) => void; +} // Redux connection -const mapStateToProps = state => { +const mapStateToProps = (state: IState) => { return { categories: state.categories, selectedRepo: state.selectedRepo diff --git a/src/renderer/containers/repoReadme.tsx b/src/renderer/containers/repoReadme.tsx index fdb20ef..1df367a 100644 --- a/src/renderer/containers/repoReadme.tsx +++ b/src/renderer/containers/repoReadme.tsx @@ -1,9 +1,16 @@ import { connect } from "react-redux"; import RepoReadme from "../components/repoReadme"; import Actions from "../actions"; +import IState from "../interface/IState"; +import IRepo from "../interface/IRepo"; + +export interface RepoReadmeProps { + selectedRepo: IRepo | null; + onFetchRepoReadMe: (repo: IRepo) => void; +} // Redux connection -const mapStateToProps = state => { +const mapStateToProps = (state: IState) => { return { selectedRepo: state.selectedRepo }; diff --git a/src/renderer/containers/repoTagsBar.tsx b/src/renderer/containers/repoTagsBar.tsx index 3eded5c..25cd4e2 100644 --- a/src/renderer/containers/repoTagsBar.tsx +++ b/src/renderer/containers/repoTagsBar.tsx @@ -1,9 +1,18 @@ import { connect } from "react-redux"; import RepoTagsBar from "../components/repoTagsBar"; import Actions from "../actions"; +import IState from "../interface/IState"; +import IRepo from "../interface/IRepo"; + +export interface RepoTagsBarProps { + selectedRepo: IRepo | null; + onAddTagForRepo: (id: number, tagName: string) => void; + onRemoveTagForRepo: (id: number, tagName: string) => void; + onGetTagsForRepo: (id: number) => void; +} // Redux connection -const mapStateToProps = state => { +const mapStateToProps = (state: IState) => { return { selectedRepo: state.selectedRepo }; diff --git a/src/renderer/containers/reposList.tsx b/src/renderer/containers/reposList.tsx index 5ff29d6..0fcb285 100644 --- a/src/renderer/containers/reposList.tsx +++ b/src/renderer/containers/reposList.tsx @@ -1,9 +1,18 @@ import { connect } from "react-redux"; import ReposList from "../components/reposList"; import Actions from "../actions"; +import IState from "../interface/IState"; +import IRepo from "../interface/IRepo"; + +export interface ReposListProps { + repos: { [key: string]: IRepo }; + selectedRepo: IRepo | null; + onSelectRepo: (repo: IRepo) => void; + onRateRepo: (id: number, score: number) => void; +} // Redux connection -const mapStateToProps = state => { +const mapStateToProps = (state: IState) => { return { repos: state.repos, selectedRepo: state.selectedRepo diff --git a/src/renderer/containers/settingPage.tsx b/src/renderer/containers/settingPage.tsx index f545577..4a82a78 100644 --- a/src/renderer/containers/settingPage.tsx +++ b/src/renderer/containers/settingPage.tsx @@ -1,9 +1,20 @@ import { connect } from "react-redux"; import SettingPage from "../components/settingPage"; import Actions from "../actions"; +import IState from "../interface/IState"; +import IProfile from "../interface/IProfile"; +import { RxDatabase } from "rxdb"; + +export interface SettingPageProps { + profile: IProfile; + db: RxDatabase; + onGetLocalCredentials: () => void; + onGetMyProfile: () => void; + onGetRxDB: (dbName: string) => void; +} // Redux connection -const mapStateToProps = state => { +const mapStateToProps = (state: IState) => { return { profile: state.profile, db: state.db diff --git a/src/renderer/containers/sortBar.tsx b/src/renderer/containers/sortBar.tsx index 969c3bc..341681e 100644 --- a/src/renderer/containers/sortBar.tsx +++ b/src/renderer/containers/sortBar.tsx @@ -1,9 +1,19 @@ import { connect } from "react-redux"; import SortBar from "../components/sortBar"; import Actions from "../actions"; +import IState from "../interface/IState"; +import { IOrderConditionState } from "../interface/IConditional"; +import IRepo, { IRepoFetchingStatus } from "../interface/IRepo"; + +export interface SortBarProps { + order: IOrderConditionState; + fetchStatus: IRepoFetchingStatus; + repos: { [key: string]: IRepo }; + onUpdateOrderCondition: (order: IOrderConditionState) => void; +} // Redux connection -const mapStateToProps = state => { +const mapStateToProps = (state: IState) => { return { order: state.order, fetchStatus: state.fetchStatus, diff --git a/src/renderer/interface/ICategory.ts b/src/renderer/interface/ICategory.ts index e7458db..66e2fd5 100644 --- a/src/renderer/interface/ICategory.ts +++ b/src/renderer/interface/ICategory.ts @@ -1,4 +1,4 @@ -export interface ICategory { +export default interface ICategory { id: number; name: string; description: string; @@ -7,7 +7,7 @@ export interface ICategory { createdTime: string; updatedAt: string; updatedTime: number; -} +}; export interface ICategoryCreateResult { category?: ICategory; diff --git a/src/renderer/interface/IOffline.ts b/src/renderer/interface/IOffline.ts new file mode 100644 index 0000000..8cd995d --- /dev/null +++ b/src/renderer/interface/IOffline.ts @@ -0,0 +1,4 @@ +export default interface IOfflineState { + value: boolean | null; + time: number; +}; diff --git a/src/renderer/interface/IRepo.ts b/src/renderer/interface/IRepo.ts index c59210a..743f9e4 100644 --- a/src/renderer/interface/IRepo.ts +++ b/src/renderer/interface/IRepo.ts @@ -77,4 +77,9 @@ export default interface IRepo { note: string; defaultOrder: number; readme: string; +}; + +export interface IRepoFetchingStatus { + fetching: boolean; + success: boolean | null; } diff --git a/src/renderer/interface/IState.ts b/src/renderer/interface/IState.ts new file mode 100644 index 0000000..197fa66 --- /dev/null +++ b/src/renderer/interface/IState.ts @@ -0,0 +1,33 @@ +import IRepo, { IRepoFetchingStatus } from "../interface/IRepo"; +import IProfile from "../interface/IProfile"; +import IOfflineState from "../interface/IOffline"; +import ILanguage from "../interface/ILanguage"; +import { + ISearchConditionState, + IFilterConditionState, + IOrderConditionState, + IGroupConditionState +} from "../interface/IConditional"; +import ICategory, { ICategoryCreateResult } from "../interface/ICategory"; +import { ICredentialsState, ILoginResultState } from "../interface/IAccount"; +import { RxDatabase } from "rxdb"; + +export default interface IState { + routing: any; + offline: IOfflineState; + db: RxDatabase; + credentials: ICredentialsState; + profile: IProfile | null; + loginResult: ILoginResultState; + search: ISearchConditionState; + order: IOrderConditionState; + filter: IFilterConditionState; + group: IGroupConditionState; + repos: { [key: string]: IRepo }; + increase: number; + languages: ILanguage[]; + categories: ICategory[]; + fetchStatus: IRepoFetchingStatus; + catAdd: ICategoryCreateResult; + selectedRepo: IRepo | null; +}; diff --git a/src/renderer/reducers/categories.ts b/src/renderer/reducers/categories.ts index 3015e09..a7d138a 100644 --- a/src/renderer/reducers/categories.ts +++ b/src/renderer/reducers/categories.ts @@ -1,6 +1,6 @@ import * as CONSTANTS from "../constants"; import IAction from "../interface/IAction"; -import { ICategory, ICategoryCreateResult } from "../interface/ICategory"; +import ICategory, { ICategoryCreateResult } from "../interface/ICategory"; const categoriesDefaultState: ICategory[] = []; diff --git a/src/renderer/reducers/db.ts b/src/renderer/reducers/db.ts index 14fa56d..6de7174 100644 --- a/src/renderer/reducers/db.ts +++ b/src/renderer/reducers/db.ts @@ -1,13 +1,14 @@ import * as CONSTANTS from "../constants"; import IAction from "../interface/IAction"; +import { RxDatabase } from "rxdb"; -export const dbConnectReducer = (state = null, action: IAction) => { +export const dbConnectReducer = (state = null, action: IAction): RxDatabase => { switch (action.type) { case CONSTANTS.DB_CONNECTED: return action.payload.db; case CONSTANTS.DB_DISCONNECTED: - return null; + return null as any; default: - return state; + return state as any; } }; diff --git a/src/renderer/reducers/languages.ts b/src/renderer/reducers/languages.ts index a26f12b..dd3e950 100644 --- a/src/renderer/reducers/languages.ts +++ b/src/renderer/reducers/languages.ts @@ -1,9 +1,11 @@ import * as CONSTANTS from "../constants"; +import IAction from "../interface/IAction"; +import ILanguage from "../interface/ILanguage"; -export const languagesReducer = (state = [], action) => { +export const languagesReducer = (state = [], action: IAction): ILanguage[] => { switch (action.type) { case CONSTANTS.QUERY_LANGUAGES_LIST_SUCCESS: - return action.languages; + return action.payload.languages; case CONSTANTS.QUERY_LANGUAGES_LIST_FAIL: default: return state; diff --git a/src/renderer/reducers/network.ts b/src/renderer/reducers/network.ts index 3fe7723..10bb118 100644 --- a/src/renderer/reducers/network.ts +++ b/src/renderer/reducers/network.ts @@ -1,11 +1,13 @@ import * as CONSTANTS from "../constants"; +import IAction from "../interface/IAction"; +import IOfflineState from "../interface/IOffline"; -let initialState = { +let initialState: IOfflineState = { value: navigator.onLine ? null : true, // null for first time online value time: 0 }; -export const offlineReducer = (state = initialState, action) => { +export const offlineReducer = (state = initialState, action: IAction): IOfflineState => { switch (action.type) { case CONSTANTS.APP_OFFLINE: return { diff --git a/src/renderer/reducers/profile.ts b/src/renderer/reducers/profile.ts index b8649da..9c56d74 100644 --- a/src/renderer/reducers/profile.ts +++ b/src/renderer/reducers/profile.ts @@ -1,9 +1,11 @@ import * as CONSTANTS from "../constants"; +import IAction from "../interface/IAction"; +import IProfile from "../interface/IProfile"; -export const profileReducer = (state = null, action) => { +export const profileReducer = (state = null, action: IAction): IProfile | null => { switch (action.type) { case CONSTANTS.QUERY_MY_PROFILE_SUCCESS: - return action.profile; + return action.payload.profile; case CONSTANTS.QUERY_MY_PROFILE_FAIL: default: return state; diff --git a/src/renderer/reducers/repo.ts b/src/renderer/reducers/repo.ts index 7b4f147..0159a13 100644 --- a/src/renderer/reducers/repo.ts +++ b/src/renderer/reducers/repo.ts @@ -1,6 +1,10 @@ import * as CONSTANTS from "../constants"; +import IAction from "../interface/IAction"; +import IRepo from "../interface/IRepo"; +import ITag from "../interface/ITag"; +import ICategory from "../interface/ICategory"; -export const selectedRepoReducer = (state = null, action) => { +export const selectedRepoReducer = (state = null, action: IAction): IRepo | null => { switch (action.type) { case CONSTANTS.SELECT_ONE_REPO: case CONSTANTS.UPDATE_SELECTED_REPO_SUCCESS: @@ -8,25 +12,25 @@ export const selectedRepoReducer = (state = null, action) => { // case CONSTANTS.REMOVE_TAG_FOR_REPO_SUCCESS: // case CONSTANTS.UPDATE_REPO_CATEGORIES_SUCCESS: // case CONSTANTS.UPDATE_REPO_CONTRIBUTORS_SUCCESS: - return action.repo; + return action.payload.repo; default: return state; } }; -export const selectedRepoTagsReducer = (state = [], action) => { +export const selectedRepoTagsReducer = (state = [], action: IAction): ITag[] => { switch (action.type) { case CONSTANTS.QUERY_REPO_TAGS_SUCCESS: - return action.tags; + return action.payload.tags; default: return state; } }; -export const selectedRepoCatsReducer = (state = [], action) => { +export const selectedRepoCatsReducer = (state = [], action: IAction): ICategory[] => { switch (action.type) { case CONSTANTS.QUERY_REPO_CATEGORIES_SUCCESS: - return action.categories; + return action.payload.categories; default: return state; } diff --git a/src/renderer/reducers/repos.ts b/src/renderer/reducers/repos.ts index 32446e0..7414216 100644 --- a/src/renderer/reducers/repos.ts +++ b/src/renderer/reducers/repos.ts @@ -1,20 +1,22 @@ import * as CONSTANTS from "../constants"; +import IAction from "../interface/IAction"; +import IRepo, { IRepoFetchingStatus } from "../interface/IRepo"; -export const reposListReducer = (state = {}, action) => { +export const reposListReducer = (state = {}, action: IAction): { [key: string]: IRepo } => { switch (action.type) { case CONSTANTS.QUERY_REPOS_LIST_SUCCESS: case CONSTANTS.REPLACE_REPOS_LIST_ITEM: - return action.repos; + return action.payload.repos; case CONSTANTS.QUERY_REPOS_LIST_FAIL: default: return state; } }; -export const reposIncreaseReducer = (state = 0, action) => { +export const reposIncreaseReducer = (state = 0, action: IAction): number => { switch (action.type) { case CONSTANTS.FETCH_REPOS_LIST_SUCCESS: - return action.increase; + return action.payload.increase; case CONSTANTS.CLEAR_INCREASE_PROP: return 0; default: @@ -29,8 +31,8 @@ const initialFetchState = { export const fetchingReposStatusReducer = ( state = initialFetchState, - action -) => { + action: IAction +): IRepoFetchingStatus => { switch (action.type) { case CONSTANTS.FETCH_REPOS_LIST: return { From fda982f6ff7af0d4d057ded5c044937c0c250e2d Mon Sep 17 00:00:00 2001 From: wuxueqian Date: Sun, 31 Dec 2017 19:18:22 +0800 Subject: [PATCH 07/25] add components interfaces --- src/renderer/interface/ICategory.ts | 2 +- src/renderer/interface/IOffline.ts | 2 +- src/renderer/interface/IRepo.ts | 2 +- src/renderer/interface/IState.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/renderer/interface/ICategory.ts b/src/renderer/interface/ICategory.ts index 66e2fd5..14db77b 100644 --- a/src/renderer/interface/ICategory.ts +++ b/src/renderer/interface/ICategory.ts @@ -7,7 +7,7 @@ export default interface ICategory { createdTime: string; updatedAt: string; updatedTime: number; -}; +} export interface ICategoryCreateResult { category?: ICategory; diff --git a/src/renderer/interface/IOffline.ts b/src/renderer/interface/IOffline.ts index 8cd995d..7cef474 100644 --- a/src/renderer/interface/IOffline.ts +++ b/src/renderer/interface/IOffline.ts @@ -1,4 +1,4 @@ export default interface IOfflineState { value: boolean | null; time: number; -}; +} diff --git a/src/renderer/interface/IRepo.ts b/src/renderer/interface/IRepo.ts index 743f9e4..48673e6 100644 --- a/src/renderer/interface/IRepo.ts +++ b/src/renderer/interface/IRepo.ts @@ -77,7 +77,7 @@ export default interface IRepo { note: string; defaultOrder: number; readme: string; -}; +} export interface IRepoFetchingStatus { fetching: boolean; diff --git a/src/renderer/interface/IState.ts b/src/renderer/interface/IState.ts index 197fa66..1b39fb9 100644 --- a/src/renderer/interface/IState.ts +++ b/src/renderer/interface/IState.ts @@ -30,4 +30,4 @@ export default interface IState { fetchStatus: IRepoFetchingStatus; catAdd: ICategoryCreateResult; selectedRepo: IRepo | null; -}; +} From 3a2520ba107d4faef67350ff4dd0d52ea82fd3d2 Mon Sep 17 00:00:00 2001 From: wuxueqian Date: Mon, 1 Jan 2018 16:01:45 +0800 Subject: [PATCH 08/25] update --- .babelrc | 16 +- manifest.json | 1 + package.json | 14 +- .../assets/styles/global/iconfont.css | 13 +- src/renderer/components/app.tsx | 4 +- src/renderer/components/filterBar.tsx | 9 +- src/renderer/components/loginPage.tsx | 19 +- src/renderer/components/mainDetailPane.tsx | 2 +- src/renderer/components/mainGroupAvatar.tsx | 2 +- src/renderer/components/mainGroupFooter.tsx | 37 +- src/renderer/components/mainGroupNavs.tsx | 26 +- src/renderer/components/mainGroupPane.tsx | 3 +- src/renderer/components/mainListPane.tsx | 3 +- src/renderer/components/mainPage.tsx | 4 +- src/renderer/components/mainSearchBox.tsx | 4 +- src/renderer/components/refreshIndicator.tsx | 2 +- src/renderer/components/repoClassifyTool.tsx | 6 +- .../components/repoContributorsBar.tsx | 3 +- src/renderer/components/repoDetail.tsx | 8 +- src/renderer/components/repoDetailToolbar.tsx | 19 +- src/renderer/components/repoLinksTool.tsx | 4 +- src/renderer/components/repoListItem.tsx | 9 +- src/renderer/components/repoNoteTool.tsx | 16 +- src/renderer/components/repoReadme.tsx | 32 +- src/renderer/components/repoTagsBar.tsx | 49 +- src/renderer/components/reposList.tsx | 23 +- src/renderer/components/settingPage.tsx | 14 +- src/renderer/components/sortBar.tsx | 2 +- src/renderer/containers/filterBar.tsx | 1 - src/renderer/containers/loginPage.tsx | 5 + src/renderer/containers/repoClassifyTool.tsx | 2 +- src/renderer/containers/repoDetailToolbar.tsx | 2 +- src/renderer/containers/repoTagsBar.tsx | 3 +- src/renderer/containers/settingPage.tsx | 3 +- src/renderer/index.tsx | 8 +- src/renderer/interface/ICategory.ts | 1 + src/renderer/interface/ILanguage.ts | 1 + src/renderer/interface/IProfile.ts | 5 +- src/renderer/interface/IRepo.ts | 7 + venders-config.json | 1 + webpack/base.conf.babel.js | 30 +- webpack/dev.conf.babel.js | 8 +- webpack/prod.conf.babel.js | 12 +- yarn.lock | 799 +++++++----------- 44 files changed, 523 insertions(+), 709 deletions(-) create mode 100644 manifest.json create mode 100644 venders-config.json diff --git a/.babelrc b/.babelrc index b79d0e9..2e35a68 100644 --- a/.babelrc +++ b/.babelrc @@ -1,17 +1,5 @@ { - "presets": ["react", "es2015", "es2017", "stage-2"], - "plugins": [ - "transform-runtime", - "transform-decorators-legacy", - "transform-object-rest-spread", - [ - "transform-async-to-module-method", - { - "module": "bluebird", - "method": "coroutine" - } - ], - ["import", { "libraryName": "antd", "style": true }] - ], + "presets": ["react", "es2015", "es2017"], + "plugins": [["import", { "libraryName": "antd", "style": true }]], "comments": false } diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..bbb765c --- /dev/null +++ b/manifest.json @@ -0,0 +1 @@ +{"name":"venders_809c01c9","content":{"../node_modules/core-js/modules/es6.typed.int16-array.js":{"id":"qtRy","meta":{}},"../node_modules/react-dom/index.js":{"id":"O27J","meta":{}},"../node_modules/react-router/es/index.js":{"id":"CIox","meta":{"harmonyModule":true},"exports":["Router","Link","IndexLink","withRouter","IndexRedirect","IndexRoute","Redirect","Route","createRoutes","RouterContext","locationShape","routerShape","match","useRouterHistory","formatPattern","applyRouterMiddleware","browserHistory","hashHistory","createMemoryHistory"]},"../node_modules/react-router-dom/es/index.js":{"id":"F8kA","meta":{"harmonyModule":true},"exports":["BrowserRouter","HashRouter","Link","MemoryRouter","NavLink","Prompt","Redirect","Route","Router","StaticRouter","Switch","matchPath","withRouter"]},"../node_modules/babel-polyfill/lib/index.js":{"id":"j1ja","meta":{}},"../node_modules/classnames/index.js":{"id":"HW6M","meta":{}},"../node_modules/react-document-meta/dist/index.js":{"id":"K7g+","meta":{}},"../node_modules/moment/moment.js":{"id":"PJh5","meta":{}},"../node_modules/bluebird/js/browser/bluebird.js":{"id":"0Qa9","meta":{}},"../node_modules/process/browser.js":{"id":"W2nU","meta":{}},"../node_modules/webpack/buildin/global.js":{"id":"DuR2","meta":{}},"../node_modules/timers-browserify/main.js":{"id":"162o","meta":{}},"../node_modules/setimmediate/setImmediate.js":{"id":"mypn","meta":{}},"../node_modules/webpack/buildin/module.js":{"id":"3IRH","meta":{}},"../node_modules/moment/locale recursive ^\\.\\/.*$":{"id":"uslO","meta":{}},"../node_modules/moment/locale/af.js":{"id":"3CJN","meta":{}},"../node_modules/moment/locale/ar.js":{"id":"3MVc","meta":{}},"../node_modules/moment/locale/ar-dz.js":{"id":"tkWw","meta":{}},"../node_modules/moment/locale/ar-kw.js":{"id":"j8cJ","meta":{}},"../node_modules/moment/locale/ar-ly.js":{"id":"wPpW","meta":{}},"../node_modules/moment/locale/ar-ma.js":{"id":"dURR","meta":{}},"../node_modules/moment/locale/ar-sa.js":{"id":"7OnE","meta":{}},"../node_modules/moment/locale/ar-tn.js":{"id":"BEem","meta":{}},"../node_modules/moment/locale/az.js":{"id":"eHwN","meta":{}},"../node_modules/moment/locale/be.js":{"id":"3hfc","meta":{}},"../node_modules/moment/locale/bg.js":{"id":"lOED","meta":{}},"../node_modules/moment/locale/bm.js":{"id":"hng5","meta":{}},"../node_modules/moment/locale/bn.js":{"id":"aM0x","meta":{}},"../node_modules/moment/locale/bo.js":{"id":"w2Hs","meta":{}},"../node_modules/moment/locale/br.js":{"id":"OSsP","meta":{}},"../node_modules/moment/locale/bs.js":{"id":"aqvp","meta":{}},"../node_modules/moment/locale/ca.js":{"id":"wIgY","meta":{}},"../node_modules/moment/locale/cs.js":{"id":"ssxj","meta":{}},"../node_modules/moment/locale/cv.js":{"id":"N3vo","meta":{}},"../node_modules/moment/locale/cy.js":{"id":"ZFGz","meta":{}},"../node_modules/moment/locale/da.js":{"id":"YBA/","meta":{}},"../node_modules/moment/locale/de.js":{"id":"DOkx","meta":{}},"../node_modules/moment/locale/de-at.js":{"id":"8v14","meta":{}},"../node_modules/moment/locale/de-ch.js":{"id":"Frex","meta":{}},"../node_modules/moment/locale/dv.js":{"id":"rIuo","meta":{}},"../node_modules/moment/locale/el.js":{"id":"CFqe","meta":{}},"../node_modules/moment/locale/en-au.js":{"id":"Sjoy","meta":{}},"../node_modules/moment/locale/en-ca.js":{"id":"Tqun","meta":{}},"../node_modules/moment/locale/en-gb.js":{"id":"hPuz","meta":{}},"../node_modules/moment/locale/en-ie.js":{"id":"ALEw","meta":{}},"../node_modules/moment/locale/en-nz.js":{"id":"dyB6","meta":{}},"../node_modules/moment/locale/eo.js":{"id":"Nd3h","meta":{}},"../node_modules/moment/locale/es.js":{"id":"LT9G","meta":{}},"../node_modules/moment/locale/es-do.js":{"id":"7MHZ","meta":{}},"../node_modules/moment/locale/es-us.js":{"id":"INcR","meta":{}},"../node_modules/moment/locale/et.js":{"id":"XlWM","meta":{}},"../node_modules/moment/locale/eu.js":{"id":"sqLM","meta":{}},"../node_modules/moment/locale/fa.js":{"id":"2pmY","meta":{}},"../node_modules/moment/locale/fi.js":{"id":"nS2h","meta":{}},"../node_modules/moment/locale/fo.js":{"id":"OVPi","meta":{}},"../node_modules/moment/locale/fr.js":{"id":"tzHd","meta":{}},"../node_modules/moment/locale/fr-ca.js":{"id":"bXQP","meta":{}},"../node_modules/moment/locale/fr-ch.js":{"id":"VK9h","meta":{}},"../node_modules/moment/locale/fy.js":{"id":"g7KF","meta":{}},"../node_modules/moment/locale/gd.js":{"id":"nLOz","meta":{}},"../node_modules/moment/locale/gl.js":{"id":"FuaP","meta":{}},"../node_modules/moment/locale/gom-latn.js":{"id":"+27R","meta":{}},"../node_modules/moment/locale/gu.js":{"id":"rtsW","meta":{}},"../node_modules/moment/locale/he.js":{"id":"Nzt2","meta":{}},"../node_modules/moment/locale/hi.js":{"id":"ETHv","meta":{}},"../node_modules/moment/locale/hr.js":{"id":"V4qH","meta":{}},"../node_modules/moment/locale/hu.js":{"id":"xne+","meta":{}},"../node_modules/moment/locale/hy-am.js":{"id":"GrS7","meta":{}},"../node_modules/moment/locale/id.js":{"id":"yRTJ","meta":{}},"../node_modules/moment/locale/is.js":{"id":"upln","meta":{}},"../node_modules/moment/locale/it.js":{"id":"FKXc","meta":{}},"../node_modules/moment/locale/ja.js":{"id":"ORgI","meta":{}},"../node_modules/moment/locale/jv.js":{"id":"JwiF","meta":{}},"../node_modules/moment/locale/ka.js":{"id":"RnJI","meta":{}},"../node_modules/moment/locale/kk.js":{"id":"j+vx","meta":{}},"../node_modules/moment/locale/km.js":{"id":"5j66","meta":{}},"../node_modules/moment/locale/kn.js":{"id":"gEQe","meta":{}},"../node_modules/moment/locale/ko.js":{"id":"eBB/","meta":{}},"../node_modules/moment/locale/ky.js":{"id":"6cf8","meta":{}},"../node_modules/moment/locale/lb.js":{"id":"z3hR","meta":{}},"../node_modules/moment/locale/lo.js":{"id":"nE8X","meta":{}},"../node_modules/moment/locale/lt.js":{"id":"/6P1","meta":{}},"../node_modules/moment/locale/lv.js":{"id":"jxEH","meta":{}},"../node_modules/moment/locale/me.js":{"id":"svD2","meta":{}},"../node_modules/moment/locale/mi.js":{"id":"gEU3","meta":{}},"../node_modules/moment/locale/mk.js":{"id":"Ab7C","meta":{}},"../node_modules/moment/locale/ml.js":{"id":"oo1B","meta":{}},"../node_modules/moment/locale/mr.js":{"id":"5vPg","meta":{}},"../node_modules/moment/locale/ms.js":{"id":"ooba","meta":{}},"../node_modules/moment/locale/ms-my.js":{"id":"G++c","meta":{}},"../node_modules/moment/locale/mt.js":{"id":"oCzW","meta":{}},"../node_modules/moment/locale/my.js":{"id":"F+2e","meta":{}},"../node_modules/moment/locale/nb.js":{"id":"FlzV","meta":{}},"../node_modules/moment/locale/ne.js":{"id":"/mhn","meta":{}},"../node_modules/moment/locale/nl.js":{"id":"3K28","meta":{}},"../node_modules/moment/locale/nl-be.js":{"id":"Bp2f","meta":{}},"../node_modules/moment/locale/nn.js":{"id":"C7av","meta":{}},"../node_modules/moment/locale/pa-in.js":{"id":"pfs9","meta":{}},"../node_modules/moment/locale/pl.js":{"id":"7LV+","meta":{}},"../node_modules/moment/locale/pt.js":{"id":"ZoSI","meta":{}},"../node_modules/moment/locale/pt-br.js":{"id":"AoDM","meta":{}},"../node_modules/moment/locale/ro.js":{"id":"wT5f","meta":{}},"../node_modules/moment/locale/ru.js":{"id":"ulq9","meta":{}},"../node_modules/moment/locale/sd.js":{"id":"fW1y","meta":{}},"../node_modules/moment/locale/se.js":{"id":"5Omq","meta":{}},"../node_modules/moment/locale/si.js":{"id":"Lgqo","meta":{}},"../node_modules/moment/locale/sk.js":{"id":"OUMt","meta":{}},"../node_modules/moment/locale/sl.js":{"id":"2s1U","meta":{}},"../node_modules/moment/locale/sq.js":{"id":"V0td","meta":{}},"../node_modules/moment/locale/sr.js":{"id":"f4W3","meta":{}},"../node_modules/moment/locale/sr-cyrl.js":{"id":"c1x4","meta":{}},"../node_modules/moment/locale/ss.js":{"id":"7Q8x","meta":{}},"../node_modules/moment/locale/sv.js":{"id":"Fpqq","meta":{}},"../node_modules/moment/locale/sw.js":{"id":"DSXN","meta":{}},"../node_modules/moment/locale/ta.js":{"id":"+7/x","meta":{}},"../node_modules/moment/locale/te.js":{"id":"Nlnz","meta":{}},"../node_modules/moment/locale/tet.js":{"id":"gUgh","meta":{}},"../node_modules/moment/locale/th.js":{"id":"XzD+","meta":{}},"../node_modules/moment/locale/tl-ph.js":{"id":"3LKG","meta":{}},"../node_modules/moment/locale/tlh.js":{"id":"m7yE","meta":{}},"../node_modules/moment/locale/tr.js":{"id":"k+5o","meta":{}},"../node_modules/moment/locale/tzl.js":{"id":"iNtv","meta":{}},"../node_modules/moment/locale/tzm.js":{"id":"FRPF","meta":{}},"../node_modules/moment/locale/tzm-latn.js":{"id":"krPU","meta":{}},"../node_modules/moment/locale/uk.js":{"id":"ntHu","meta":{}},"../node_modules/moment/locale/ur.js":{"id":"uSe8","meta":{}},"../node_modules/moment/locale/uz.js":{"id":"XU1s","meta":{}},"../node_modules/moment/locale/uz-latn.js":{"id":"/bsm","meta":{}},"../node_modules/moment/locale/vi.js":{"id":"0X8Q","meta":{}},"../node_modules/moment/locale/x-pseudo.js":{"id":"e/KL","meta":{}},"../node_modules/moment/locale/yo.js":{"id":"YXlc","meta":{}},"../node_modules/moment/locale/zh-cn.js":{"id":"Vz2w","meta":{}},"../node_modules/moment/locale/zh-hk.js":{"id":"ZUyn","meta":{}},"../node_modules/moment/locale/zh-tw.js":{"id":"BbgG","meta":{}},"../node_modules/prop-types/index.js":{"id":"KSGD","meta":{}},"../node_modules/react-dom/server.browser.js":{"id":"rNU7","meta":{}},"../node_modules/react-side-effect/lib/index.js":{"id":"vAAJ","meta":{}},"../node_modules/react-document-meta/dist/utils.js":{"id":"Dwhq","meta":{}},"../node_modules/react-document-meta/dist/dom.js":{"id":"xSJz","meta":{}},"../node_modules/exenv/index.js":{"id":"u4m+","meta":{}},"../node_modules/shallowequal/index.js":{"id":"Ngpj","meta":{}},"../node_modules/react-dom/cjs/react-dom-server.browser.production.min.js":{"id":"HHS1","meta":{}},"../node_modules/object-assign/index.js":{"id":"BEQ0","meta":{}},"../node_modules/fbjs/lib/emptyFunction.js":{"id":"e6+Q","meta":{}},"../node_modules/fbjs/lib/emptyObject.js":{"id":"TJez","meta":{}},"../node_modules/fbjs/lib/hyphenateStyleName.js":{"id":"mL1Z","meta":{}},"../node_modules/fbjs/lib/memoizeStringOnly.js":{"id":"Jl+d","meta":{}},"../node_modules/fbjs/lib/hyphenate.js":{"id":"APD3","meta":{}},"../node_modules/prop-types/factoryWithThrowingShims.js":{"id":"Q4WQ","meta":{}},"../node_modules/fbjs/lib/invariant.js":{"id":"cxPT","meta":{}},"../node_modules/prop-types/lib/ReactPropTypesSecret.js":{"id":"gt/O","meta":{}},"../node_modules/core-js/shim.js":{"id":"4M2W","meta":{}},"../node_modules/regenerator-runtime/runtime.js":{"id":"SldL","meta":{}},"../node_modules/core-js/fn/regexp/escape.js":{"id":"Wwne","meta":{}},"../node_modules/core-js/modules/core.regexp.escape.js":{"id":"r2E/","meta":{}},"../node_modules/core-js/modules/_core.js":{"id":"7gX0","meta":{}},"../node_modules/core-js/modules/_export.js":{"id":"Ds5P","meta":{}},"../node_modules/core-js/modules/_replacer.js":{"id":"nqOf","meta":{}},"../node_modules/core-js/modules/_global.js":{"id":"OzIq","meta":{}},"../node_modules/core-js/modules/_hide.js":{"id":"2p1q","meta":{}},"../node_modules/core-js/modules/_redefine.js":{"id":"R3AP","meta":{}},"../node_modules/core-js/modules/_ctx.js":{"id":"rFzY","meta":{}},"../node_modules/core-js/modules/_a-function.js":{"id":"XSOZ","meta":{}},"../node_modules/core-js/modules/_has.js":{"id":"WBcL","meta":{}},"../node_modules/core-js/modules/_uid.js":{"id":"ulTY","meta":{}},"../node_modules/core-js/modules/_object-dp.js":{"id":"lDLk","meta":{}},"../node_modules/core-js/modules/_property-desc.js":{"id":"fU25","meta":{}},"../node_modules/core-js/modules/_descriptors.js":{"id":"bUqO","meta":{}},"../node_modules/core-js/modules/_fails.js":{"id":"zgIt","meta":{}},"../node_modules/core-js/modules/_an-object.js":{"id":"DIVP","meta":{}},"../node_modules/core-js/modules/_ie8-dom-define.js":{"id":"xZa+","meta":{}},"../node_modules/core-js/modules/_to-primitive.js":{"id":"s4j0","meta":{}},"../node_modules/core-js/modules/_is-object.js":{"id":"UKM+","meta":{}},"../node_modules/core-js/modules/_dom-create.js":{"id":"jhxf","meta":{}},"../node_modules/core-js/modules/es6.symbol.js":{"id":"A0n/","meta":{}},"../node_modules/core-js/modules/es6.object.create.js":{"id":"i68Q","meta":{}},"../node_modules/core-js/modules/es6.object.define-property.js":{"id":"QzLV","meta":{}},"../node_modules/core-js/modules/es6.object.define-properties.js":{"id":"Hhm4","meta":{}},"../node_modules/core-js/modules/es6.object.get-own-property-descriptor.js":{"id":"C+4B","meta":{}},"../node_modules/core-js/modules/es6.object.get-prototype-of.js":{"id":"W4Z6","meta":{}},"../node_modules/core-js/modules/es6.object.keys.js":{"id":"tJwI","meta":{}},"../node_modules/core-js/modules/es6.object.get-own-property-names.js":{"id":"eC2H","meta":{}},"../node_modules/core-js/modules/es6.object.freeze.js":{"id":"VTn2","meta":{}},"../node_modules/core-js/modules/es6.object.seal.js":{"id":"W/IU","meta":{}},"../node_modules/core-js/modules/es6.object.prevent-extensions.js":{"id":"Y5ex","meta":{}},"../node_modules/core-js/modules/es6.object.is-frozen.js":{"id":"WpPb","meta":{}},"../node_modules/core-js/modules/es6.object.is-sealed.js":{"id":"+yjc","meta":{}},"../node_modules/core-js/modules/es6.object.is-extensible.js":{"id":"gPva","meta":{}},"../node_modules/core-js/modules/es6.object.assign.js":{"id":"n12u","meta":{}},"../node_modules/core-js/modules/es6.object.is.js":{"id":"nRs1","meta":{}},"../node_modules/core-js/modules/es6.object.set-prototype-of.js":{"id":"jrHM","meta":{}},"../node_modules/core-js/modules/es6.object.to-string.js":{"id":"gYYG","meta":{}},"../node_modules/core-js/modules/es6.function.bind.js":{"id":"3QrE","meta":{}},"../node_modules/core-js/modules/es6.function.name.js":{"id":"EuXz","meta":{}},"../node_modules/core-js/modules/es6.function.has-instance.js":{"id":"PbPd","meta":{}},"../node_modules/core-js/modules/es6.parse-int.js":{"id":"S+E/","meta":{}},"../node_modules/core-js/modules/es6.parse-float.js":{"id":"EvFb","meta":{}},"../node_modules/core-js/modules/es6.number.constructor.js":{"id":"QBuC","meta":{}},"../node_modules/core-js/modules/es6.number.to-fixed.js":{"id":"QWLi","meta":{}},"../node_modules/core-js/modules/es6.number.to-precision.js":{"id":"ZRJK","meta":{}},"../node_modules/core-js/modules/es6.number.epsilon.js":{"id":"Stuz","meta":{}},"../node_modules/core-js/modules/es6.number.is-finite.js":{"id":"yuXV","meta":{}},"../node_modules/core-js/modules/es6.number.is-integer.js":{"id":"XtiL","meta":{}},"../node_modules/core-js/modules/es6.number.is-nan.js":{"id":"LG56","meta":{}},"../node_modules/core-js/modules/es6.number.is-safe-integer.js":{"id":"A1ng","meta":{}},"../node_modules/core-js/modules/es6.number.max-safe-integer.js":{"id":"WiIn","meta":{}},"../node_modules/core-js/modules/es6.number.min-safe-integer.js":{"id":"aJ2J","meta":{}},"../node_modules/core-js/modules/es6.number.parse-float.js":{"id":"altv","meta":{}},"../node_modules/core-js/modules/es6.number.parse-int.js":{"id":"dULJ","meta":{}},"../node_modules/core-js/modules/es6.math.acosh.js":{"id":"v2lb","meta":{}},"../node_modules/core-js/modules/es6.math.asinh.js":{"id":"7Jvp","meta":{}},"../node_modules/core-js/modules/es6.math.atanh.js":{"id":"lyhN","meta":{}},"../node_modules/core-js/modules/es6.math.cbrt.js":{"id":"kBOG","meta":{}},"../node_modules/core-js/modules/es6.math.clz32.js":{"id":"xONB","meta":{}},"../node_modules/core-js/modules/es6.math.cosh.js":{"id":"LlNE","meta":{}},"../node_modules/core-js/modules/es6.math.expm1.js":{"id":"9xIj","meta":{}},"../node_modules/core-js/modules/es6.math.fround.js":{"id":"m6Yj","meta":{}},"../node_modules/core-js/modules/es6.math.hypot.js":{"id":"wrs0","meta":{}},"../node_modules/core-js/modules/es6.math.imul.js":{"id":"Lqg1","meta":{}},"../node_modules/core-js/modules/es6.math.log10.js":{"id":"1ip3","meta":{}},"../node_modules/core-js/modules/es6.math.log1p.js":{"id":"pWGb","meta":{}},"../node_modules/core-js/modules/es6.math.log2.js":{"id":"N4KQ","meta":{}},"../node_modules/core-js/modules/es6.math.sign.js":{"id":"Hl+4","meta":{}},"../node_modules/core-js/modules/es6.math.sinh.js":{"id":"MjHD","meta":{}},"../node_modules/core-js/modules/es6.math.tanh.js":{"id":"SRCy","meta":{}},"../node_modules/core-js/modules/es6.math.trunc.js":{"id":"H0mh","meta":{}},"../node_modules/core-js/modules/es6.string.from-code-point.js":{"id":"bqOW","meta":{}},"../node_modules/core-js/modules/es6.string.raw.js":{"id":"F3sI","meta":{}},"../node_modules/core-js/modules/es6.string.trim.js":{"id":"mhn7","meta":{}},"../node_modules/core-js/modules/es6.string.iterator.js":{"id":"1A13","meta":{}},"../node_modules/core-js/modules/es6.string.code-point-at.js":{"id":"Racj","meta":{}},"../node_modules/core-js/modules/es6.string.ends-with.js":{"id":"Y1S0","meta":{}},"../node_modules/core-js/modules/es6.string.includes.js":{"id":"Gh7F","meta":{}},"../node_modules/core-js/modules/es6.string.repeat.js":{"id":"tqSY","meta":{}},"../node_modules/core-js/modules/es6.string.starts-with.js":{"id":"CvWX","meta":{}},"../node_modules/core-js/modules/es6.string.anchor.js":{"id":"8Np7","meta":{}},"../node_modules/core-js/modules/es6.string.big.js":{"id":"R4pa","meta":{}},"../node_modules/core-js/modules/es6.string.blink.js":{"id":"4RlI","meta":{}},"../node_modules/core-js/modules/es6.string.bold.js":{"id":"iM2X","meta":{}},"../node_modules/core-js/modules/es6.string.fixed.js":{"id":"J+j9","meta":{}},"../node_modules/core-js/modules/es6.string.fontcolor.js":{"id":"82of","meta":{}},"../node_modules/core-js/modules/es6.string.fontsize.js":{"id":"X/Hz","meta":{}},"../node_modules/core-js/modules/es6.string.italics.js":{"id":"eVIH","meta":{}},"../node_modules/core-js/modules/es6.string.link.js":{"id":"UJiG","meta":{}},"../node_modules/core-js/modules/es6.string.small.js":{"id":"SU+a","meta":{}},"../node_modules/core-js/modules/es6.string.strike.js":{"id":"5iw+","meta":{}},"../node_modules/core-js/modules/es6.string.sub.js":{"id":"EWrS","meta":{}},"../node_modules/core-js/modules/es6.string.sup.js":{"id":"J2ob","meta":{}},"../node_modules/core-js/modules/es6.date.now.js":{"id":"QaEu","meta":{}},"../node_modules/core-js/modules/es6.date.to-json.js":{"id":"8fhx","meta":{}},"../node_modules/core-js/modules/es6.date.to-iso-string.js":{"id":"UbXY","meta":{}},"../node_modules/core-js/modules/es6.date.to-string.js":{"id":"Rk41","meta":{}},"../node_modules/core-js/modules/es6.date.to-primitive.js":{"id":"4Q0w","meta":{}},"../node_modules/core-js/modules/es6.array.is-array.js":{"id":"IMUI","meta":{}},"../node_modules/core-js/modules/es6.array.from.js":{"id":"beEN","meta":{}},"../node_modules/core-js/modules/es6.array.of.js":{"id":"xMpm","meta":{}},"../node_modules/core-js/modules/es6.array.join.js":{"id":"j42X","meta":{}},"../node_modules/core-js/modules/es6.array.slice.js":{"id":"81dZ","meta":{}},"../node_modules/core-js/modules/es6.array.sort.js":{"id":"uDYd","meta":{}},"../node_modules/core-js/modules/es6.array.for-each.js":{"id":"CEO+","meta":{}},"../node_modules/core-js/modules/es6.array.map.js":{"id":"w6W7","meta":{}},"../node_modules/core-js/modules/es6.array.filter.js":{"id":"fOdq","meta":{}},"../node_modules/core-js/modules/es6.array.some.js":{"id":"wVdn","meta":{}},"../node_modules/core-js/modules/es6.array.every.js":{"id":"Nkrw","meta":{}},"../node_modules/core-js/modules/es6.array.reduce.js":{"id":"wnRD","meta":{}},"../node_modules/core-js/modules/es6.array.reduce-right.js":{"id":"lkT3","meta":{}},"../node_modules/core-js/modules/es6.array.index-of.js":{"id":"+CM9","meta":{}},"../node_modules/core-js/modules/es6.array.last-index-of.js":{"id":"oHKp","meta":{}},"../node_modules/core-js/modules/es6.array.copy-within.js":{"id":"9vc3","meta":{}},"../node_modules/core-js/modules/es6.array.fill.js":{"id":"No4x","meta":{}},"../node_modules/core-js/modules/es6.array.find.js":{"id":"WpTh","meta":{}},"../node_modules/core-js/modules/es6.array.find-index.js":{"id":"U6qc","meta":{}},"../node_modules/core-js/modules/es6.array.species.js":{"id":"Q/CP","meta":{}},"../node_modules/core-js/modules/es6.array.iterator.js":{"id":"WgSQ","meta":{}},"../node_modules/core-js/modules/es6.regexp.constructor.js":{"id":"lnZN","meta":{}},"../node_modules/core-js/modules/es6.regexp.to-string.js":{"id":"FaZr","meta":{}},"../node_modules/core-js/modules/es6.regexp.flags.js":{"id":"pd+2","meta":{}},"../node_modules/core-js/modules/es6.regexp.match.js":{"id":"MfeA","meta":{}},"../node_modules/core-js/modules/es6.regexp.replace.js":{"id":"VjuZ","meta":{}},"../node_modules/core-js/modules/es6.regexp.search.js":{"id":"qwQ3","meta":{}},"../node_modules/core-js/modules/es6.regexp.split.js":{"id":"mJx5","meta":{}},"../node_modules/core-js/modules/es6.promise.js":{"id":"y9m4","meta":{}},"../node_modules/core-js/modules/es6.map.js":{"id":"MsuQ","meta":{}},"../node_modules/core-js/modules/es6.set.js":{"id":"dSUw","meta":{}},"../node_modules/core-js/modules/es6.weak-map.js":{"id":"ZDXm","meta":{}},"../node_modules/core-js/modules/es6.weak-set.js":{"id":"V/H1","meta":{}},"../node_modules/core-js/modules/es6.typed.array-buffer.js":{"id":"9mmO","meta":{}},"../node_modules/core-js/modules/es6.typed.data-view.js":{"id":"1uLP","meta":{}},"../node_modules/core-js/modules/es6.typed.int8-array.js":{"id":"52Wt","meta":{}},"../node_modules/core-js/modules/es6.typed.uint8-array.js":{"id":"TFWu","meta":{}},"../node_modules/core-js/modules/es6.typed.uint8-clamped-array.js":{"id":"MyjO","meta":{}},"../node_modules/react/index.js":{"id":"GiK3","meta":{}},"../node_modules/core-js/modules/es6.typed.uint16-array.js":{"id":"THnP","meta":{}},"../node_modules/core-js/modules/es6.typed.int32-array.js":{"id":"K0JP","meta":{}},"../node_modules/core-js/modules/es6.typed.uint32-array.js":{"id":"NfZy","meta":{}},"../node_modules/core-js/modules/es6.typed.float32-array.js":{"id":"dTzs","meta":{}},"../node_modules/core-js/modules/es6.typed.float64-array.js":{"id":"+vXH","meta":{}},"../node_modules/core-js/modules/es6.reflect.apply.js":{"id":"CVR+","meta":{}},"../node_modules/core-js/modules/es6.reflect.construct.js":{"id":"vmSu","meta":{}},"../node_modules/core-js/modules/es6.reflect.define-property.js":{"id":"4ZU1","meta":{}},"../node_modules/core-js/modules/es6.reflect.delete-property.js":{"id":"yx1U","meta":{}},"../node_modules/core-js/modules/es6.reflect.enumerate.js":{"id":"X7aK","meta":{}},"../node_modules/core-js/modules/es6.reflect.get.js":{"id":"SPtU","meta":{}},"../node_modules/core-js/modules/es6.reflect.get-own-property-descriptor.js":{"id":"A52B","meta":{}},"../node_modules/core-js/modules/es6.reflect.get-prototype-of.js":{"id":"PuTd","meta":{}},"../node_modules/core-js/modules/es6.reflect.has.js":{"id":"dm+7","meta":{}},"../node_modules/core-js/modules/es6.reflect.is-extensible.js":{"id":"JG34","meta":{}},"../node_modules/core-js/modules/es6.reflect.own-keys.js":{"id":"Rw4K","meta":{}},"../node_modules/core-js/modules/es6.reflect.prevent-extensions.js":{"id":"9mGU","meta":{}},"../node_modules/core-js/modules/es6.reflect.set.js":{"id":"bUY0","meta":{}},"../node_modules/core-js/modules/es6.reflect.set-prototype-of.js":{"id":"mTp7","meta":{}},"../node_modules/core-js/modules/es7.array.includes.js":{"id":"gbyG","meta":{}},"../node_modules/core-js/modules/es7.array.flat-map.js":{"id":"oF0V","meta":{}},"../node_modules/core-js/modules/es7.array.flatten.js":{"id":"v90c","meta":{}},"../node_modules/core-js/modules/es7.string.at.js":{"id":"+2+s","meta":{}},"../node_modules/core-js/modules/es7.string.pad-start.js":{"id":"smQ+","meta":{}},"../node_modules/core-js/modules/es7.string.pad-end.js":{"id":"m8F4","meta":{}},"../node_modules/core-js/modules/es7.string.trim-left.js":{"id":"xn9I","meta":{}},"../node_modules/core-js/modules/es7.string.trim-right.js":{"id":"LRL/","meta":{}},"../node_modules/core-js/modules/es7.string.match-all.js":{"id":"sc7i","meta":{}},"../node_modules/core-js/modules/es7.symbol.async-iterator.js":{"id":"9Yib","meta":{}},"../node_modules/core-js/modules/es7.symbol.observable.js":{"id":"vu/c","meta":{}},"../node_modules/core-js/modules/es7.object.get-own-property-descriptors.js":{"id":"zmx7","meta":{}},"../node_modules/core-js/modules/es7.object.values.js":{"id":"YVn/","meta":{}},"../node_modules/core-js/modules/es7.object.entries.js":{"id":"FKfb","meta":{}},"../node_modules/core-js/modules/es7.object.define-getter.js":{"id":"oYp4","meta":{}},"../node_modules/core-js/modules/es7.object.define-setter.js":{"id":"dxQb","meta":{}},"../node_modules/core-js/modules/es7.object.lookup-getter.js":{"id":"xCpI","meta":{}},"../node_modules/core-js/modules/es7.object.lookup-setter.js":{"id":"AkTE","meta":{}},"../node_modules/core-js/modules/es7.map.to-json.js":{"id":"h7Xi","meta":{}},"../node_modules/core-js/modules/es7.set.to-json.js":{"id":"arGp","meta":{}},"../node_modules/core-js/modules/es7.map.of.js":{"id":"JJ3w","meta":{}},"../node_modules/core-js/modules/es7.set.of.js":{"id":"qZb+","meta":{}},"../node_modules/core-js/modules/es7.weak-map.of.js":{"id":"La7N","meta":{}},"../node_modules/core-js/modules/es7.weak-set.of.js":{"id":"BOYP","meta":{}},"../node_modules/core-js/modules/es7.map.from.js":{"id":"4rmF","meta":{}},"../node_modules/core-js/modules/es7.set.from.js":{"id":"Ygg6","meta":{}},"../node_modules/core-js/modules/es7.weak-map.from.js":{"id":"6Xxs","meta":{}},"../node_modules/core-js/modules/es7.weak-set.from.js":{"id":"qdHU","meta":{}},"../node_modules/core-js/modules/es7.global.js":{"id":"DQfQ","meta":{}},"../node_modules/core-js/modules/es7.system.global.js":{"id":"j/Lv","meta":{}},"../node_modules/core-js/modules/es7.error.is-error.js":{"id":"U+VG","meta":{}},"../node_modules/core-js/modules/es7.math.clamp.js":{"id":"X6NR","meta":{}},"../node_modules/core-js/modules/es7.math.deg-per-rad.js":{"id":"W0pi","meta":{}},"../node_modules/core-js/modules/es7.math.degrees.js":{"id":"taNN","meta":{}},"../node_modules/core-js/modules/es7.math.fscale.js":{"id":"vnWP","meta":{}},"../node_modules/core-js/modules/es7.math.iaddh.js":{"id":"R3KI","meta":{}},"../node_modules/core-js/modules/es7.math.isubh.js":{"id":"6iMJ","meta":{}},"../node_modules/core-js/modules/es7.math.imulh.js":{"id":"B3Xn","meta":{}},"../node_modules/core-js/modules/es7.math.rad-per-deg.js":{"id":"3s83","meta":{}},"../node_modules/core-js/modules/es7.math.radians.js":{"id":"F1ui","meta":{}},"../node_modules/core-js/modules/es7.math.scale.js":{"id":"uEEG","meta":{}},"../node_modules/core-js/modules/es7.math.umulh.js":{"id":"i039","meta":{}},"../node_modules/core-js/modules/es7.math.signbit.js":{"id":"H7zx","meta":{}},"../node_modules/core-js/modules/es7.promise.finally.js":{"id":"+Mt+","meta":{}},"../node_modules/core-js/modules/es7.promise.try.js":{"id":"QcWB","meta":{}},"../node_modules/core-js/modules/es7.reflect.define-metadata.js":{"id":"yJ2x","meta":{}},"../node_modules/core-js/modules/es7.reflect.delete-metadata.js":{"id":"3q4u","meta":{}},"../node_modules/core-js/modules/es7.reflect.get-metadata.js":{"id":"NHaJ","meta":{}},"../node_modules/core-js/modules/es7.reflect.get-metadata-keys.js":{"id":"v3hU","meta":{}},"../node_modules/core-js/modules/es7.reflect.get-own-metadata.js":{"id":"zZHq","meta":{}},"../node_modules/core-js/modules/es7.reflect.get-own-metadata-keys.js":{"id":"vsh6","meta":{}},"../node_modules/core-js/modules/es7.reflect.has-metadata.js":{"id":"8WbS","meta":{}},"../node_modules/core-js/modules/es7.reflect.has-own-metadata.js":{"id":"yOtE","meta":{}},"../node_modules/core-js/modules/es7.reflect.metadata.js":{"id":"EZ+5","meta":{}},"../node_modules/core-js/modules/es7.asap.js":{"id":"aM0T","meta":{}},"../node_modules/core-js/modules/es7.observable.js":{"id":"nh2o","meta":{}},"../node_modules/core-js/modules/web.timers.js":{"id":"v8VU","meta":{}},"../node_modules/core-js/modules/web.immediate.js":{"id":"dich","meta":{}},"../node_modules/core-js/modules/web.dom.iterable.js":{"id":"fx22","meta":{}},"../node_modules/core-js/modules/_object-keys.js":{"id":"Qh14","meta":{}},"../node_modules/core-js/modules/_iterators.js":{"id":"bN1p","meta":{}},"../node_modules/core-js/modules/_wks.js":{"id":"kkCw","meta":{}},"../node_modules/core-js/modules/_shared.js":{"id":"VWgF","meta":{}},"../node_modules/core-js/modules/_object-keys-internal.js":{"id":"ReGu","meta":{}},"../node_modules/core-js/modules/_enum-bug-keys.js":{"id":"QKXm","meta":{}},"../node_modules/core-js/modules/_to-iobject.js":{"id":"PHqh","meta":{}},"../node_modules/core-js/modules/_array-includes.js":{"id":"ot5s","meta":{}},"../node_modules/core-js/modules/_shared-key.js":{"id":"mZON","meta":{}},"../node_modules/core-js/modules/_to-length.js":{"id":"BbyF","meta":{}},"../node_modules/core-js/modules/_to-absolute-index.js":{"id":"zo/l","meta":{}},"../node_modules/core-js/modules/_to-integer.js":{"id":"oeih","meta":{}},"../node_modules/core-js/modules/_iobject.js":{"id":"Q6Nf","meta":{}},"../node_modules/core-js/modules/_defined.js":{"id":"/whu","meta":{}},"../node_modules/core-js/modules/_cof.js":{"id":"ydD5","meta":{}},"../node_modules/core-js/modules/_task.js":{"id":"Sejc","meta":{}},"../node_modules/core-js/modules/_invoke.js":{"id":"PHCx","meta":{}},"../node_modules/core-js/modules/_html.js":{"id":"d075","meta":{}},"../node_modules/core-js/modules/_user-agent.js":{"id":"41xE","meta":{}},"../node_modules/core-js/modules/_microtask.js":{"id":"g36u","meta":{}},"../node_modules/core-js/modules/_an-instance.js":{"id":"9GpA","meta":{}},"../node_modules/core-js/modules/_redefine-all.js":{"id":"A16L","meta":{}},"../node_modules/core-js/modules/_for-of.js":{"id":"vmSO","meta":{}},"../node_modules/core-js/modules/_set-species.js":{"id":"CEne","meta":{}},"../node_modules/core-js/modules/_iter-call.js":{"id":"XvUs","meta":{}},"../node_modules/core-js/modules/_is-array-iter.js":{"id":"9vb1","meta":{}},"../node_modules/core-js/modules/core.get-iterator-method.js":{"id":"SHe9","meta":{}},"../node_modules/core-js/modules/_classof.js":{"id":"wC1N","meta":{}},"../node_modules/core-js/modules/_metadata.js":{"id":"wCso","meta":{}},"../node_modules/core-js/modules/_object-gpo.js":{"id":"KOrd","meta":{}},"../node_modules/core-js/modules/_to-object.js":{"id":"FryR","meta":{}},"../node_modules/core-js/modules/_array-from-iterable.js":{"id":"QG7u","meta":{}},"../node_modules/core-js/modules/_new-promise-capability.js":{"id":"w6Dh","meta":{}},"../node_modules/core-js/modules/_perform.js":{"id":"SDXa","meta":{}},"../node_modules/core-js/modules/_species-constructor.js":{"id":"7O1s","meta":{}},"../node_modules/core-js/modules/_promise-resolve.js":{"id":"nphH","meta":{}},"../node_modules/core-js/modules/_math-scale.js":{"id":"WY8G","meta":{}},"../node_modules/core-js/modules/_math-fround.js":{"id":"g/m8","meta":{}},"../node_modules/core-js/modules/_math-sign.js":{"id":"cwmK","meta":{}},"../node_modules/core-js/modules/_set-collection-from.js":{"id":"iKpr","meta":{}},"../node_modules/core-js/modules/_set-collection-of.js":{"id":"0j1G","meta":{}},"../node_modules/core-js/modules/_collection-to-json.js":{"id":"XXBo","meta":{}},"../node_modules/core-js/modules/_object-gopd.js":{"id":"x9zv","meta":{}},"../node_modules/core-js/modules/_object-forced-pam.js":{"id":"dm6P","meta":{}},"../node_modules/core-js/modules/_library.js":{"id":"V3l/","meta":{}},"../node_modules/core-js/modules/_object-pie.js":{"id":"Y1aA","meta":{}},"../node_modules/core-js/modules/_object-to-array.js":{"id":"lKE8","meta":{}},"../node_modules/core-js/modules/_own-keys.js":{"id":"YUr7","meta":{}},"../node_modules/core-js/modules/_create-property.js":{"id":"bSML","meta":{}},"../node_modules/core-js/modules/_object-gopn.js":{"id":"WcO1","meta":{}},"../node_modules/core-js/modules/_object-gops.js":{"id":"Y1N3","meta":{}},"../node_modules/core-js/modules/_wks-define.js":{"id":"3g/S","meta":{}},"../node_modules/core-js/modules/_wks-ext.js":{"id":"M8WE","meta":{}},"../node_modules/core-js/modules/_is-regexp.js":{"id":"u0PK","meta":{}},"../node_modules/core-js/modules/_flags.js":{"id":"0pGU","meta":{}},"../node_modules/core-js/modules/_iter-create.js":{"id":"IRJ3","meta":{}},"../node_modules/core-js/modules/_object-create.js":{"id":"7ylX","meta":{}},"../node_modules/core-js/modules/_set-to-string-tag.js":{"id":"yYvK","meta":{}},"../node_modules/core-js/modules/_object-dps.js":{"id":"twxM","meta":{}},"../node_modules/core-js/modules/_string-trim.js":{"id":"Ymdd","meta":{}},"../node_modules/core-js/modules/_string-ws.js":{"id":"Xduv","meta":{}},"../node_modules/core-js/modules/_string-pad.js":{"id":"2VSL","meta":{}},"../node_modules/core-js/modules/_string-repeat.js":{"id":"xAdt","meta":{}},"../node_modules/core-js/modules/_string-at.js":{"id":"49qz","meta":{}},"../node_modules/core-js/modules/_flatten-into-array.js":{"id":"IFpc","meta":{}},"../node_modules/core-js/modules/_array-species-create.js":{"id":"plSV","meta":{}},"../node_modules/core-js/modules/_add-to-unscopables.js":{"id":"RhFG","meta":{}},"../node_modules/core-js/modules/_array-species-constructor.js":{"id":"boo2","meta":{}},"../node_modules/core-js/modules/_is-array.js":{"id":"XO1R","meta":{}},"../node_modules/core-js/modules/_set-proto.js":{"id":"gvDt","meta":{}},"../node_modules/core-js/modules/_bind.js":{"id":"ZtwE","meta":{}},"../node_modules/core-js/modules/_typed-array.js":{"id":"77Ug","meta":{}},"../node_modules/core-js/modules/_typed.js":{"id":"07k+","meta":{}},"../node_modules/core-js/modules/_typed-buffer.js":{"id":"LrcN","meta":{}},"../node_modules/core-js/modules/_to-index.js":{"id":"8D8H","meta":{}},"../node_modules/core-js/modules/_array-methods.js":{"id":"LhTa","meta":{}},"../node_modules/core-js/modules/_iter-detect.js":{"id":"qkyc","meta":{}},"../node_modules/core-js/modules/_array-fill.js":{"id":"zCYm","meta":{}},"../node_modules/core-js/modules/_array-copy-within.js":{"id":"DPsE","meta":{}},"../node_modules/core-js/modules/_collection-weak.js":{"id":"fJSx","meta":{}},"../node_modules/core-js/modules/_validate-collection.js":{"id":"zq/X","meta":{}},"../node_modules/core-js/modules/_collection.js":{"id":"0Rih","meta":{}},"../node_modules/core-js/modules/_meta.js":{"id":"1aA0","meta":{}},"../node_modules/core-js/modules/_inherit-if-required.js":{"id":"kic5","meta":{}},"../node_modules/core-js/modules/_object-assign.js":{"id":"oYd7","meta":{}},"../node_modules/core-js/modules/_collection-strong.js":{"id":"Dgii","meta":{}},"../node_modules/core-js/modules/_iter-define.js":{"id":"uc2A","meta":{}},"../node_modules/core-js/modules/_iter-step.js":{"id":"KB1o","meta":{}},"../node_modules/core-js/modules/_fix-re-wks.js":{"id":"Vg1y","meta":{}},"../node_modules/core-js/modules/_strict-method.js":{"id":"NNrz","meta":{}},"../node_modules/core-js/modules/_array-reduce.js":{"id":"FkIZ","meta":{}},"../node_modules/core-js/modules/_date-to-primitive.js":{"id":"jB26","meta":{}},"../node_modules/core-js/modules/_date-to-iso-string.js":{"id":"Y7Tz","meta":{}},"../node_modules/core-js/modules/_string-html.js":{"id":"y325","meta":{}},"../node_modules/core-js/modules/_string-context.js":{"id":"kqpo","meta":{}},"../node_modules/core-js/modules/_fails-is-regexp.js":{"id":"1ETD","meta":{}},"../node_modules/core-js/modules/_math-expm1.js":{"id":"x78i","meta":{}},"../node_modules/core-js/modules/_math-log1p.js":{"id":"Rz2z","meta":{}},"../node_modules/core-js/modules/_parse-int.js":{"id":"OgTs","meta":{}},"../node_modules/core-js/modules/_parse-float.js":{"id":"8t38","meta":{}},"../node_modules/core-js/modules/_is-integer.js":{"id":"n982","meta":{}},"../node_modules/core-js/modules/_a-number-value.js":{"id":"fS0v","meta":{}},"../node_modules/core-js/modules/_same-value.js":{"id":"4IZP","meta":{}},"../node_modules/core-js/modules/_object-sap.js":{"id":"3i66","meta":{}},"../node_modules/core-js/modules/_object-gopn-ext.js":{"id":"bG/2","meta":{}},"../node_modules/core-js/modules/_enum-keys.js":{"id":"C+Ps","meta":{}},"../node_modules/react-router-dom/es/BrowserRouter.js":{"id":"8QhD","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/react-router-dom/es/HashRouter.js":{"id":"nT98","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/react-router-dom/es/Link.js":{"id":"yL62","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/react-router-dom/es/MemoryRouter.js":{"id":"XLvd","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/react-router-dom/es/NavLink.js":{"id":"3r6y","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/react-router-dom/es/Prompt.js":{"id":"52Em","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/react-router-dom/es/Redirect.js":{"id":"PGPo","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/react-router-dom/es/Route.js":{"id":"MfZD","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/react-router-dom/es/Router.js":{"id":"dCLN","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/react-router-dom/es/StaticRouter.js":{"id":"9uhF","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/react-router-dom/es/Switch.js":{"id":"6cJI","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/react-router-dom/es/matchPath.js":{"id":"yt5j","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/react-router-dom/es/withRouter.js":{"id":"tfLY","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/react-router-dom/node_modules/react-router/es/withRouter.js":{"id":"iow2","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/hoist-non-react-statics/index.js":{"id":"hYij","meta":{}},"../node_modules/react-router-dom/node_modules/react-router/es/Route.js":{"id":"bxKl","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/warning/browser.js":{"id":"GvBW","meta":{}},"../node_modules/invariant/browser.js":{"id":"crWv","meta":{}},"../node_modules/react-router-dom/node_modules/react-router/es/matchPath.js":{"id":"D8xD","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/react-router-dom/node_modules/path-to-regexp/index.js":{"id":"xuzU","meta":{}},"../node_modules/isarray/index.js":{"id":"sOR5","meta":{}},"../node_modules/react-router-dom/node_modules/react-router/es/Switch.js":{"id":"DSfN","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/react-router-dom/node_modules/react-router/es/StaticRouter.js":{"id":"dB1f","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/history/PathUtils.js":{"id":"Izpu","meta":{}},"../node_modules/react-router-dom/node_modules/react-router/es/Router.js":{"id":"I23E","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/react-router-dom/node_modules/react-router/es/Redirect.js":{"id":"Feli","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/history/es/index.js":{"id":"wrym","meta":{"harmonyModule":true},"exports":["createBrowserHistory","createHashHistory","createMemoryHistory","createLocation","locationsAreEqual","parsePath","createPath"]},"../node_modules/history/es/createBrowserHistory.js":{"id":"xuWB","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/history/es/createHashHistory.js":{"id":"k5k7","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/history/es/createMemoryHistory.js":{"id":"o1/Q","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/history/es/LocationUtils.js":{"id":"Iauv","meta":{"harmonyModule":true},"exports":["createLocation","locationsAreEqual"]},"../node_modules/history/es/PathUtils.js":{"id":"okyF","meta":{"harmonyModule":true},"exports":["addLeadingSlash","stripLeadingSlash","hasBasename","stripBasename","stripTrailingSlash","parsePath","createPath"]},"../node_modules/resolve-pathname/index.js":{"id":"Wpbd","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/value-equal/index.js":{"id":"FKtm","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/history/es/createTransitionManager.js":{"id":"IiIQ","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/history/es/DOMUtils.js":{"id":"iSqa","meta":{"harmonyModule":true},"exports":["canUseDOM","addEventListener","removeEventListener","getConfirmation","supportsHistory","supportsPopStateOnHashChange","supportsGoWithoutReloadUsingHash","isExtraneousPopstateEvent"]},"../node_modules/react-router-dom/node_modules/react-router/es/Prompt.js":{"id":"ENGX","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/react-router-dom/node_modules/react-router/es/MemoryRouter.js":{"id":"6fZ9","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/history/createMemoryHistory.js":{"id":"HSnN","meta":{}},"../node_modules/history/LocationUtils.js":{"id":"xIPz","meta":{}},"../node_modules/history/createTransitionManager.js":{"id":"tqq1","meta":{}},"../node_modules/history/createHashHistory.js":{"id":"kjbi","meta":{}},"../node_modules/history/DOMUtils.js":{"id":"zFGm","meta":{}},"../node_modules/history/createBrowserHistory.js":{"id":"ciQf","meta":{}},"../node_modules/react-router/es/Router.js":{"id":"twkG","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/react-router/es/Link.js":{"id":"ABxT","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/react-router/es/IndexLink.js":{"id":"BBPh","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/react-router/es/withRouter.js":{"id":"vC7t","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/react-router/es/IndexRedirect.js":{"id":"dC3n","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/react-router/es/IndexRoute.js":{"id":"s+O2","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/react-router/es/Redirect.js":{"id":"1S3F","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/react-router/es/Route.js":{"id":"s4hp","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/react-router/es/RouteUtils.js":{"id":"NycN","meta":{"harmonyModule":true},"exports":["isReactChildren","createRouteFromReactElement","createRoutesFromReactChildren","createRoutes"]},"../node_modules/react-router/es/RouterContext.js":{"id":"r6Es","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/react-router/es/PropTypes.js":{"id":"afjn","meta":{"harmonyModule":true},"exports":["routerShape","locationShape"]},"../node_modules/react-router/es/match.js":{"id":"N5Mq","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/react-router/es/useRouterHistory.js":{"id":"UvA0","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/react-router/es/PatternUtils.js":{"id":"UYe+","meta":{"harmonyModule":true},"exports":["compilePattern","matchPattern","getParamNames","getParams","formatPattern"]},"../node_modules/react-router/es/applyRouterMiddleware.js":{"id":"fJzy","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/react-router/es/browserHistory.js":{"id":"79A3","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/react-router/es/hashHistory.js":{"id":"OhKW","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/react-router/es/createMemoryHistory.js":{"id":"w6N+","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/react-router/node_modules/history/lib/useQueries.js":{"id":"teWx","meta":{}},"../node_modules/react-router/node_modules/history/lib/useBasename.js":{"id":"SOiI","meta":{}},"../node_modules/react-router/node_modules/history/lib/createMemoryHistory.js":{"id":"Mmla","meta":{}},"../node_modules/react-router/node_modules/history/lib/LocationUtils.js":{"id":"a2BU","meta":{}},"../node_modules/react-router/node_modules/history/lib/PathUtils.js":{"id":"lFM1","meta":{}},"../node_modules/react-router/node_modules/history/lib/createHistory.js":{"id":"6kDn","meta":{}},"../node_modules/react-router/node_modules/history/lib/Actions.js":{"id":"Y4sZ","meta":{}},"../node_modules/react-router/node_modules/history/lib/AsyncUtils.js":{"id":"rMmN","meta":{}},"../node_modules/react-router/node_modules/history/lib/runTransitionHook.js":{"id":"Kwm3","meta":{}},"../node_modules/query-string/index.js":{"id":"OAwv","meta":{}},"../node_modules/strict-uri-encode/index.js":{"id":"rprB","meta":{}},"../node_modules/react-router/node_modules/history/lib/createHashHistory.js":{"id":"CK0t","meta":{}},"../node_modules/react-router/es/createRouterHistory.js":{"id":"vAwi","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/react-router/node_modules/history/lib/ExecutionEnvironment.js":{"id":"3qHv","meta":{}},"../node_modules/react-router/node_modules/history/lib/DOMUtils.js":{"id":"2inJ","meta":{}},"../node_modules/react-router/node_modules/history/lib/HashProtocol.js":{"id":"ip+G","meta":{}},"../node_modules/react-router/node_modules/history/lib/BrowserProtocol.js":{"id":"8hnC","meta":{}},"../node_modules/react-router/node_modules/history/lib/DOMStateStorage.js":{"id":"t+J7","meta":{}},"../node_modules/react-router/node_modules/history/lib/createBrowserHistory.js":{"id":"1Kzh","meta":{}},"../node_modules/react-router/node_modules/history/lib/RefreshProtocol.js":{"id":"NSk9","meta":{}},"../node_modules/react-router/es/routerWarning.js":{"id":"oMLH","meta":{"harmonyModule":true},"exports":["default","_resetWarned"]},"../node_modules/react-router/es/createTransitionManager.js":{"id":"TWV5","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/react-router/es/RouterUtils.js":{"id":"23h0","meta":{"harmonyModule":true},"exports":["createRouterObject","assignRouterState"]},"../node_modules/react-router/es/computeChangedRoutes.js":{"id":"RVWm","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/react-router/es/TransitionUtils.js":{"id":"iHu5","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/react-router/es/isActive.js":{"id":"eNQj","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/react-router/es/getComponents.js":{"id":"JYO/","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/react-router/es/matchRoutes.js":{"id":"B7i9","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/react-router/es/AsyncUtils.js":{"id":"yN4y","meta":{"harmonyModule":true},"exports":["loopAsync","mapAsync"]},"../node_modules/react-router/es/PromiseUtils.js":{"id":"l5hK","meta":{"harmonyModule":true},"exports":["isPromise"]},"../node_modules/create-react-class/index.js":{"id":"DT0+","meta":{}},"../node_modules/react-router/es/getRouteParams.js":{"id":"gnG3","meta":{"harmonyModule":true},"exports":["default"]},"../node_modules/react-router/es/ContextUtils.js":{"id":"auDf","meta":{"harmonyModule":true},"exports":["ContextProvider","ContextSubscriber"]},"../node_modules/create-react-class/factory.js":{"id":"wqO5","meta":{}},"../node_modules/react-router/es/InternalPropTypes.js":{"id":"wXat","meta":{"harmonyModule":true},"exports":["falsy","history","component","components","route","routes"]},"../node_modules/react-router/node_modules/hoist-non-react-statics/index.js":{"id":"T+2Y","meta":{}},"../node_modules/react-dom/cjs/react-dom.production.min.js":{"id":"/OLF","meta":{}},"../node_modules/fbjs/lib/ExecutionEnvironment.js":{"id":"czSA","meta":{}},"../node_modules/fbjs/lib/EventListener.js":{"id":"o+pC","meta":{}},"../node_modules/fbjs/lib/getActiveElement.js":{"id":"9U7y","meta":{}},"../node_modules/fbjs/lib/shallowEqual.js":{"id":"sgb3","meta":{}},"../node_modules/fbjs/lib/containsNode.js":{"id":"2B9T","meta":{}},"../node_modules/fbjs/lib/focusNode.js":{"id":"JTgD","meta":{}},"../node_modules/fbjs/lib/isTextNode.js":{"id":"uO0E","meta":{}},"../node_modules/fbjs/lib/isNode.js":{"id":"f2RQ","meta":{}},"../node_modules/react/cjs/react.production.min.js":{"id":"vttU","meta":{}}}} \ No newline at end of file diff --git a/package.json b/package.json index 91aa5f4..87731ec 100644 --- a/package.json +++ b/package.json @@ -82,7 +82,9 @@ "@types/node": "^8.5.2", "@types/react": "^16.0.31", "@types/webpack-env": "^1.13.3", + "assets-webpack-plugin": "^3.5.1", "babel-loader": "^7.1.2", + "babel-plugin-import": "^1.6.3", "babel-preset-es2015": "^6.24.1", "babel-preset-react": "^6.24.1", "babel-register": "^6.26.0", @@ -99,11 +101,8 @@ "lint-staged": "^6.0.0", "mkdirp": "^0.5.1", "optimize-css-assets-webpack-plugin": "^3.2.0", - "postcss-cssnext": "^3.0.2", "postcss-loader": "^2.0.9", - "postcss-smart-import": "^0.7.6", "pre-commit": "^1.2.2", - "precss": "^2.0.0", "prettier": "^1.9.2", "redux-logger": "^3.0.6", "style-loader": "^0.19.1", @@ -124,6 +123,8 @@ }, "dependencies": { "antd": "^3.0.0-rc.4", + "babel-polyfill": "^6.26.0", + "babel-preset-es2017": "^6.24.1", "bluebird": "^3.5.1", "blueimp-md5": "^2.10.0", "classnames": "^2.2.5", @@ -131,12 +132,17 @@ "github-api": "^3.0.0", "github-markdown-css": "^2.9.0", "keytar": "^3.0.2", + "moment": "^2.20.1", "pouchdb-adapter-idb": "6.1.2", + "react": "^16.2.0", + "react-copy-to-clipboard": "^5.0.1", + "react-document-meta": "^2.1.2", "react-dom": "^16.2.0", + "react-markdown": "^3.1.4", "react-redux": "^5.0.6", "react-router": "^3.0.0", + "react-router-dom": "^4.2.2", "react-router-redux": "^4.0.8", - "react-router-scroll": "^0.4.4", "redux": "^3.6.0", "redux-thunk": "^2.2.0", "rxdb": "^6.0.1" diff --git a/src/renderer/assets/styles/global/iconfont.css b/src/renderer/assets/styles/global/iconfont.css index ec25d3b..7540d94 100644 --- a/src/renderer/assets/styles/global/iconfont.css +++ b/src/renderer/assets/styles/global/iconfont.css @@ -1,13 +1,10 @@ @font-face { font-family: "anticon"; - src: url("../../assets/fonts/iconfont.eot?t=1479642802629"); /* IE9*/ - src: url("../../assets/fonts/iconfont.eot?t=1479642802629#iefix") - format("embedded-opentype"), - url("../../assets/fonts/iconfont.woff?t=1479642802629") format("woff"), - url("../../assets/fonts/iconfont.ttf?t=1479642802629") - format("truetype"), - url("../../assets/fonts/iconfont.svg?t=1479642802629#anticon") - format("svg"); /* iOS 4.1- */ + src: url("../../fonts/iconfont.eot?t=1479642802629"); /* IE9*/ + src: url("../../fonts/iconfont.eot?t=1479642802629#iefix") format("embedded-opentype"), + url("../../fonts/iconfont.woff?t=1479642802629") format("woff"), + url("../../fonts/iconfont.ttf?t=1479642802629") format("truetype"), + url("../../fonts/iconfont.svg?t=1479642802629#anticon") format("svg"); /* iOS 4.1- */ } .anticon { diff --git a/src/renderer/components/app.tsx b/src/renderer/components/app.tsx index 80b5527..37debcc 100644 --- a/src/renderer/components/app.tsx +++ b/src/renderer/components/app.tsx @@ -1,9 +1,9 @@ import React from "react"; -import offlineTitle from "../utils/offlineTitle"; import { message } from "antd"; +import offlineTitle from "../utils/offlineTitle"; import { AppProps } from "../containers/app"; -require("../styles/global/global.less"); +require("../assets/styles/global/global.less"); interface AppState {} diff --git a/src/renderer/components/filterBar.tsx b/src/renderer/components/filterBar.tsx index 29b0951..9620846 100644 --- a/src/renderer/components/filterBar.tsx +++ b/src/renderer/components/filterBar.tsx @@ -3,15 +3,10 @@ import classNames from "classnames"; import { Icon, Menu, Dropdown, Checkbox } from "antd"; import * as CONSTANTS from "../constants"; import { FilterBarProps } from "../containers/filterBar"; +import { IFilterConditionState } from "../interface/IConditional"; const styles = require("../assets/styles/main.less"); -interface FilterCondition { - hasFlag: boolean; - hasNote: boolean; - unread: boolean; -} - interface FilterBarState { filters: string[]; } @@ -45,7 +40,7 @@ export default class FilterBar extends React.Component -1, hasNote: filters.indexOf(CONSTANTS.FILTER_OPTION_HAS_NOTE) > -1, unread: filters.indexOf(CONSTANTS.FILTER_OPTION_UNREAD) > -1 diff --git a/src/renderer/components/loginPage.tsx b/src/renderer/components/loginPage.tsx index eb41d93..c7d57de 100644 --- a/src/renderer/components/loginPage.tsx +++ b/src/renderer/components/loginPage.tsx @@ -1,12 +1,12 @@ import React from "react"; -import * as EVENTS from "../../shared/events"; -import * as SHAREDCONSTANTS from "../../shared/constants"; +import classNames from "classnames"; import { ipcRenderer } from "electron"; import { Input, Icon, Button, message } from "antd"; -import classNames from "classnames"; +import * as EVENTS from "../../shared/events"; +import * as SHAREDCONSTANTS from "../../shared/constants"; import { LoginPageProps } from "../containers/loginPage"; -const styles = require("./assets/styles/login.less"); +const styles = require("../assets/styles/login.less"); message.config({ top: 60, @@ -152,11 +152,12 @@ export default class LoginPage extends React.Component - {this.props.loginResult.success === true && ( -
- {this.props.loginResult.profile.name} -
- )} + {this.props.loginResult.success === true && + this.props.loginResult.profile && ( +
+ {this.props.loginResult.profile.name} +
+ )}
{this.props.loginResult.success !== true && (
diff --git a/src/renderer/components/mainDetailPane.tsx b/src/renderer/components/mainDetailPane.tsx index 964e2d1..b249598 100644 --- a/src/renderer/components/mainDetailPane.tsx +++ b/src/renderer/components/mainDetailPane.tsx @@ -3,7 +3,7 @@ import classNames from "classnames"; import RepoDetailToolbar from "../containers/repoDetailToolbar"; import RepoDetail from "../containers/repoDetail"; -const styles = require("../styles/main.less"); +const styles = require("../assets/styles/main.less"); // right part of the main window - for displaying selected repo detail export default class MainDetailPane extends React.Component<{}> { diff --git a/src/renderer/components/mainGroupAvatar.tsx b/src/renderer/components/mainGroupAvatar.tsx index 6a28980..6e40253 100644 --- a/src/renderer/components/mainGroupAvatar.tsx +++ b/src/renderer/components/mainGroupAvatar.tsx @@ -1,7 +1,7 @@ import React from "react"; import { MainGroupAvatarProps } from "../containers/mainGroupAvatar"; -const styles = require("../styles/main.less"); +const styles = require("../assets/styles/main.less"); const defaultAvatar = require("../assets/images/avatar-default.png"); diff --git a/src/renderer/components/mainGroupFooter.tsx b/src/renderer/components/mainGroupFooter.tsx index 1baa449..1547090 100644 --- a/src/renderer/components/mainGroupFooter.tsx +++ b/src/renderer/components/mainGroupFooter.tsx @@ -5,15 +5,26 @@ import * as EVENTS from "../../shared/events"; import { ipcRenderer } from "electron"; import { MainGroupFooterProps } from "../containers/mainGroupFooter"; -const styles = require("../styles/main.less"); +const styles = require("../assets/styles/main.less"); -export default class MainGroupFooter extends React.Component { +interface MainGroupFooterState { + modalVisible: boolean; + submitting: boolean; + error: string | null; + categoryName: string; +} + +export default class MainGroupFooter extends React.Component< + MainGroupFooterProps, + MainGroupFooterState +> { constructor(props) { super(props); this.state = { modalVisible: false, submitting: false, - error: null + error: null, + categoryName: "" }; } @@ -33,9 +44,15 @@ export default class MainGroupFooter extends React.Component { + this.setState({ + categoryName: e.target.value.trim() + }); + }; + submitCatName = () => { - const catName = this.catNameInput.refs.input.value; // TODO validate cat name - if (!catName) { + const { categoryName } = this.state; + if (!categoryName) { this.setState({ error: "Please input category name" }); @@ -45,7 +62,7 @@ export default class MainGroupFooter extends React.Component { - this.props.onAddNewCategory(catName); + this.props.onAddNewCategory(categoryName); }, 2000); }; @@ -63,10 +80,10 @@ export default class MainGroupFooter extends React.Component { - this.catNameInput = node; - }} + onChange={this.onInputCategoryName} />
diff --git a/src/renderer/components/mainGroupNavs.tsx b/src/renderer/components/mainGroupNavs.tsx index 7124ad6..a3cb183 100644 --- a/src/renderer/components/mainGroupNavs.tsx +++ b/src/renderer/components/mainGroupNavs.tsx @@ -4,17 +4,27 @@ import { Menu, Icon } from "antd"; import * as CONSTANTS from "../constants"; import { MainGroupNavsProps } from "../containers/mainGroupNavs"; -const styles = require("../styles/main.less"); +const styles = require("../assets/styles/main.less"); const SubMenu = Menu.SubMenu; -const noSubsCatKeys = [CONSTANTS.GROUP_TYPE_ALL, CONSTANTS.GROUP_TYPE_UNKNOWN]; -const hasSubsCatKeys = [CONSTANTS.GROUP_TYPE_LANGUAGE, CONSTANTS.GROUP_TYPE_CATEGORY]; +// const noSubsCatKeys = [CONSTANTS.GROUP_TYPE_ALL, CONSTANTS.GROUP_TYPE_UNKNOWN]; +// const hasSubsCatKeys = [CONSTANTS.GROUP_TYPE_LANGUAGE, CONSTANTS.GROUP_TYPE_CATEGORY]; -export default class MainGroupNavs extends React.Component { - state = { - current: CONSTANTS.GROUP_TYPE_ALL, - openKeys: [CONSTANTS.GROUP_TYPE_ALL] - }; +interface MainGroupNavsState { + current: string; + openKeys: string[]; + stopBubble: boolean; +} + +export default class MainGroupNavs extends React.Component { + constructor(props) { + super(props); + this.state = { + current: CONSTANTS.GROUP_TYPE_ALL, + openKeys: [CONSTANTS.GROUP_TYPE_ALL], + stopBubble: false + }; + } handleClick = e => { if (this.state.stopBubble || !this.props.fetchStatus || this.props.fetchStatus.fetching) { diff --git a/src/renderer/components/mainGroupPane.tsx b/src/renderer/components/mainGroupPane.tsx index 163f79d..ff25260 100644 --- a/src/renderer/components/mainGroupPane.tsx +++ b/src/renderer/components/mainGroupPane.tsx @@ -5,9 +5,8 @@ import MainGroupAvatar from "../containers/mainGroupAvatar"; import MainGroupNavs from "../containers/mainGroupNavs"; import MainGroupFooter from "../containers/mainGroupFooter"; -const styles = require("../styles/main.less"); +const styles = require("../assets/styles/main.less"); -// left part of the main window export default class MainGroupPane extends React.Component<{}> { render() { return ( diff --git a/src/renderer/components/mainListPane.tsx b/src/renderer/components/mainListPane.tsx index af7d4df..228014e 100644 --- a/src/renderer/components/mainListPane.tsx +++ b/src/renderer/components/mainListPane.tsx @@ -5,9 +5,8 @@ import SortBar from "../containers/sortBar"; import ReposList from "../containers/reposList"; import FilterBar from "../containers/filterBar"; -const styles = require("../styles/main.less"); +const styles = require("../assets/styles/main.less"); -// middle part of the main window export default class MainListPane extends React.Component<{}> { render() { return ( diff --git a/src/renderer/components/mainPage.tsx b/src/renderer/components/mainPage.tsx index a955d3b..e3df947 100644 --- a/src/renderer/components/mainPage.tsx +++ b/src/renderer/components/mainPage.tsx @@ -7,7 +7,7 @@ import deepEqual from "deep-equal"; import dbName from "../utils/dbName"; import { MainPageProps } from "../containers/mainPage"; -const styles = require("../styles/main.less"); +const styles = require("../assets/styles/main.less"); export default class MainPage extends React.Component { componentWillMount() { @@ -20,8 +20,6 @@ export default class MainPage extends React.Component { this.props.onGetMyProfile(); this.props.onGetCategories(); this.props.onFetchStarredRepos(); - // this.props.onNeedUpdateReposList() - // .then((repos) => console.dir(repos)) }); } diff --git a/src/renderer/components/mainSearchBox.tsx b/src/renderer/components/mainSearchBox.tsx index d95403f..18fae50 100644 --- a/src/renderer/components/mainSearchBox.tsx +++ b/src/renderer/components/mainSearchBox.tsx @@ -4,7 +4,7 @@ import * as CONSTANTS from "../constants"; import { Input, Radio, message } from "antd"; import { MainSearchBoxProps } from "../containers/mainSearchBox"; -const styles = require("../styles/main.less"); +const styles = require("../assets/styles/main.less"); const Search = Input.Search; const RadioButton = Radio.Button; @@ -101,7 +101,7 @@ export default class MainSearchBox extends React.Component {
All diff --git a/src/renderer/components/refreshIndicator.tsx b/src/renderer/components/refreshIndicator.tsx index ad0e392..0cf2293 100644 --- a/src/renderer/components/refreshIndicator.tsx +++ b/src/renderer/components/refreshIndicator.tsx @@ -3,7 +3,7 @@ import classNames from "classnames"; import { Icon, Tooltip, notification } from "antd"; import { RefreshIndicatorProps } from "../containers/refreshIndicator"; -const styles = require("../styles/main.less"); +const styles = require("../assets/styles/main.less"); export default class RefreshIndicator extends React.Component { refresh = () => { diff --git a/src/renderer/components/repoClassifyTool.tsx b/src/renderer/components/repoClassifyTool.tsx index 3b97445..3c3c7af 100644 --- a/src/renderer/components/repoClassifyTool.tsx +++ b/src/renderer/components/repoClassifyTool.tsx @@ -1,10 +1,10 @@ import React from "react"; import classNames from "classnames"; -import { Icon, Tooltip, Popover, Button, Input, Checkbox } from "antd"; +import { Icon, Tooltip, Popover, Checkbox } from "antd"; import SCLogger from "../utils/logHelper"; import { RepoClassifyToolProps } from "../containers/RepoClassifyTool"; -const styles = require("../styles/main.less"); +const styles = require("../assets/styles/main.less"); const CheckboxGroup = Checkbox.Group; @@ -20,7 +20,7 @@ export default class RepoClassifyTool extends React.Component parseInt(item)) + this.state.categorySelection.map(item => parseInt(item, 10)) ); }; diff --git a/src/renderer/components/repoContributorsBar.tsx b/src/renderer/components/repoContributorsBar.tsx index 5910997..aecabc5 100644 --- a/src/renderer/components/repoContributorsBar.tsx +++ b/src/renderer/components/repoContributorsBar.tsx @@ -1,10 +1,9 @@ import React from "react"; import classNames from "classnames"; import { Tooltip } from "antd"; -import SCLogger from "../utils/logHelper"; import { RepoContributorsBarProps } from "../containers/repoContributorsBar"; -const styles = require("../styles/main.less"); +const styles = require("../assets/styles/main.less"); export default class RepoContributorsBar extends React.Component { componentWillReceiveProps(nextProps) { diff --git a/src/renderer/components/repoDetail.tsx b/src/renderer/components/repoDetail.tsx index fd0e0c2..d1c7c68 100644 --- a/src/renderer/components/repoDetail.tsx +++ b/src/renderer/components/repoDetail.tsx @@ -1,12 +1,13 @@ import React from "react"; import classNames from "classnames"; -import { Icon, Tooltip } from "antd"; +import { Icon } from "antd"; +import * as moment from "moment"; import RepoContributorsBar from "../containers/repoContributorsBar"; import RepoTagsBar from "../containers/repoTagsBar"; import RepoReadme from "../containers/repoReadme"; import { RepoDetailProps } from "../containers/repoDetail"; -const styles = require("../styles/main.less"); +const styles = require("../assets/styles/main.less"); export default class RepoDetail extends React.Component { render() { @@ -15,8 +16,7 @@ export default class RepoDetail extends React.Component { } const fullName = this.props.selectedRepo.fullName; const namePieces = fullName.split("/"); - let pushTime = new Date(this.props.selectedRepo.pushedAt); - pushTime = pushTime.toLocaleDateString() + " " + pushTime.toLocaleTimeString(); + const pushTime = moment(this.props.selectedRepo.pushedAt).format("YYYY-MM-DD HH:mm"); return (
diff --git a/src/renderer/components/repoDetailToolbar.tsx b/src/renderer/components/repoDetailToolbar.tsx index 36c3e52..695bc27 100644 --- a/src/renderer/components/repoDetailToolbar.tsx +++ b/src/renderer/components/repoDetailToolbar.tsx @@ -1,16 +1,16 @@ import React from "react"; import classNames from "classnames"; -import { Icon, Tooltip, Popover, Button, message } from "antd"; +import { Icon, Tooltip, message } from "antd"; import RepoLinksTool from "./repoLinksTool"; import RepoNoteTool from "./repoNoteTool"; import RepoClassifyTool from "../containers/repoClassifyTool"; import { RepoDetailToolbarProps } from "../containers/repoDetailToolbar"; +import IRepo from "../interface/IRepo"; -const styles = require("../styles/main.less"); +const styles = require("../assets/styles/main.less"); export default class RepoDetailToolbar extends React.Component { viewInGithub = () => { - console.log(this.props.selectedRepo); if (this.props.selectedRepo) { const url = this.props.selectedRepo.htmlUrl; window.open(url, "_blank"); @@ -31,16 +31,21 @@ export default class RepoDetailToolbar extends React.Component { const repo = this.props.selectedRepo; - this.props.onChangeRepoReadStatus(repo.id, !repo.read); + if (repo) { + this.props.onChangeRepoReadStatus(repo.id, !repo.read); + } }; changeRepoFlag = () => { const repo = this.props.selectedRepo; - this.props.onChangeRepoFlag(repo.id, !repo.flag); + if (repo) { + this.props.onChangeRepoFlag(repo.id, !repo.flag); + } }; render() { - let readIcon, flagIcon; + let readIcon; + let flagIcon; if (this.props.selectedRepo) { readIcon = ( - + diff --git a/src/renderer/components/repoLinksTool.tsx b/src/renderer/components/repoLinksTool.tsx index adaf2a9..3f318fd 100644 --- a/src/renderer/components/repoLinksTool.tsx +++ b/src/renderer/components/repoLinksTool.tsx @@ -2,9 +2,9 @@ import React from "react"; import classNames from "classnames"; import { Icon, Tooltip, Popover, Input } from "antd"; import CopyToClipboard from "react-copy-to-clipboard"; -import IRepo, { IRepoFetchingStatus } from "../interface/IRepo"; +import IRepo from "../interface/IRepo"; -const styles = require("../styles/main.less"); +const styles = require("../assets/styles/main.less"); interface RepoLinksToolProps { repo: IRepo; diff --git a/src/renderer/components/repoListItem.tsx b/src/renderer/components/repoListItem.tsx index 97ba9e7..1e5b8aa 100644 --- a/src/renderer/components/repoListItem.tsx +++ b/src/renderer/components/repoListItem.tsx @@ -4,7 +4,7 @@ import { Rate, Icon, Row, Col } from "antd"; import SCLogger from "../utils/logHelper"; import IRepo from "../interface/IRepo"; -const styles = require("../styles/main.less"); +const styles = require("../assets/styles/main.less"); interface RepoListItemProps { repo: IRepo; @@ -45,14 +45,9 @@ export default class RepoListItem extends React.Component { selected: this.props.repo.id === nextProps.selectedRepo.id }); } - // if (nextProps.repo) { - // this.setState({ - // score: nextProps.repo.score - // }) - // } } - shouldComponentUpdate(nextProps, nextState) { + shouldComponentUpdate(_nextProps, nextState) { if (nextState.selected !== this.state.selected || nextState.score !== this.state.score) { return true; } diff --git a/src/renderer/components/repoNoteTool.tsx b/src/renderer/components/repoNoteTool.tsx index 9b13191..c119e10 100644 --- a/src/renderer/components/repoNoteTool.tsx +++ b/src/renderer/components/repoNoteTool.tsx @@ -1,9 +1,9 @@ import React from "react"; import classNames from "classnames"; -import { Icon, Tooltip, Popover, Button, message, Input } from "antd"; +import { Icon, Tooltip, Popover, Input } from "antd"; import IRepo from "../interface/IRepo"; -const styles = require("../styles/main.less"); +const styles = require("../assets/styles/main.less"); interface RepoNoteToolProps { repo: IRepo | null; @@ -20,7 +20,10 @@ export default class RepoNoteTool extends React.Component { this.setState({ visible: false }); - this.props.updateNote(this.props.repo.id, this.state.note); + const { repo } = this.props; + if (repo) { + this.props.updateNote(repo.id, this.state.note); + } }; handleVisibleChange = visible => { @@ -54,12 +57,7 @@ export default class RepoNoteTool extends React.Component { ); const content = (
- +
); diff --git a/src/renderer/components/repoReadme.tsx b/src/renderer/components/repoReadme.tsx index f81982d..18f87c0 100644 --- a/src/renderer/components/repoReadme.tsx +++ b/src/renderer/components/repoReadme.tsx @@ -5,18 +5,21 @@ import ReactMarkdown from "react-markdown"; import { RepoReadmeProps } from "../containers/repoReadme"; import "github-markdown-css"; -const styles = require("../styles/main.less"); +const styles = require("../assets/styles/main.less"); export default class RepoReadme extends React.Component { transformImageUri = url => { const regex = /http(s?):\/\//i; if (!regex.test(url)) { const repo = this.props.selectedRepo; - let prefix = - "https://raw.githubusercontent.com/" + repo.fullName + "/" + repo.defaultBranch; - url.indexOf(".") !== 0 && (prefix += "/"); - - return prefix + url; + if (repo) { + let prefix = + "https://raw.githubusercontent.com/" + repo.fullName + "/" + repo.defaultBranch; + if (url.indexOf(".") !== 0) { + prefix += "/"; + } + return prefix + url; + } } return url; }; @@ -25,14 +28,21 @@ export default class RepoReadme extends React.Component { // and also for relative src should be replaced replaceImageSrc = content => { const repo = this.props.selectedRepo; - let prefix = - "https://raw.githubusercontent.com/" + repo.fullName + "/" + repo.defaultBranch + "/"; - return content.replace(/( { - state = { - tags: [], - inputVisible: false, - inputValue: "" - }; +interface RepoTagsBarState { + tags: string[]; + inputVisible: boolean; + inputValue: string; +} + +export default class RepoTagsBar extends React.Component { + private input: HTMLInputElement; + + constructor(props) { + super(props); + this.state = { + tags: [], + inputVisible: false, + inputValue: "" + }; + } handleClose = removedTag => { const tags = this.state.tags.filter(tag => tag !== removedTag); this.setState({ tags }); - // remove tag in db - this.props.onRemoveTagForRepo(this.props.selectedRepo.id, removedTag); + const { selectedRepo } = this.props; + if (selectedRepo) { + // remove tag in db + this.props.onRemoveTagForRepo(selectedRepo.id, removedTag); + } }; showInput = () => { @@ -29,13 +42,15 @@ export default class RepoTagsBar extends React.Component { }; handleInputConfirm = () => { - const state = this.state; - const inputValue = state.inputValue; - let tags = state.tags; + const { inputValue } = this.state; + const { selectedRepo } = this.props; + let tags: string[] = this.state.tags; if (inputValue && tags.indexOf(inputValue) === -1) { tags = [...tags, inputValue]; // save new tag in db - this.props.onAddTagForRepo(this.props.selectedRepo.id, inputValue); + if (selectedRepo) { + this.props.onAddTagForRepo(selectedRepo.id, inputValue); + } } this.setState({ tags, @@ -79,13 +94,13 @@ export default class RepoTagsBar extends React.Component { return (
{/* */} - {tags.map((tag, index) => { + {tags.map(tag => { const isLongTag = tag.length > 20; const tagElem = ( this.handleClose(tag)} > {isLongTag ? `${tag.slice(0, 20)}...` : tag} diff --git a/src/renderer/components/reposList.tsx b/src/renderer/components/reposList.tsx index 5ae1fec..cca574f 100644 --- a/src/renderer/components/reposList.tsx +++ b/src/renderer/components/reposList.tsx @@ -3,20 +3,23 @@ import classNames from "classnames"; import RepoItem from "../components/repoListItem"; import { ReposListProps } from "../containers/reposList"; -const styles = require("../styles/main.less"); +const styles = require("../assets/styles/main.less"); // repos list wrapper export default class ReposList extends React.Component { render() { - const repoItems = Object.values(this.props.repos).map(repo => ( - - )); + const { repos } = this.props; + const repoItems = Object.keys(repos) + .map(key => repos[key]) + .map(repo => ( + + )); return (
{repoItems} diff --git a/src/renderer/components/settingPage.tsx b/src/renderer/components/settingPage.tsx index 6682d11..321b0dc 100644 --- a/src/renderer/components/settingPage.tsx +++ b/src/renderer/components/settingPage.tsx @@ -1,9 +1,5 @@ import React from "react"; -import { Link } from "react-router"; -import * as EVENTS from "../../shared/events"; -import * as SHAREDCONSTANTS from "../../shared/constants"; -import { ipcRenderer } from "electron"; -import { Upload, Icon, Button, message, Modal } from "antd"; +import { Icon, Button, message, Modal } from "antd"; import classNames from "classnames"; import dbName from "../utils/dbName"; import { starsDataExportHandler, starsDataImportHandler } from "../utils/data"; @@ -13,7 +9,7 @@ import { SettingPageProps } from "../containers/settingPage"; const defaultAvatar = require("../assets/images/avatar-default.png"); -const styles = require("../styles/setting.less"); +const styles = require("../assets/styles/setting.less"); export default class SettingPage extends React.Component { state = { @@ -113,8 +109,6 @@ export default class SettingPage extends React.Component { }); } - componentWillReceiveProps(nextProps) {} - render() { return (
@@ -133,7 +127,7 @@ export default class SettingPage extends React.Component { {this.props.profile && ( {this.props.profile.name} )} -
@@ -151,7 +145,7 @@ export default class SettingPage extends React.Component {
Feedback: -
diff --git a/src/renderer/components/sortBar.tsx b/src/renderer/components/sortBar.tsx index 14a8420..52b905c 100644 --- a/src/renderer/components/sortBar.tsx +++ b/src/renderer/components/sortBar.tsx @@ -4,7 +4,7 @@ import { Icon, Menu, Dropdown, Checkbox } from "antd"; import * as CONSTANTS from "../constants"; import { SortBarProps } from "../containers/sortBar"; -const styles = require("../styles/main.less"); +const styles = require("../assets/styles/main.less"); export default class SortBar extends React.Component { state = { diff --git a/src/renderer/containers/filterBar.tsx b/src/renderer/containers/filterBar.tsx index 77d7b09..f798129 100644 --- a/src/renderer/containers/filterBar.tsx +++ b/src/renderer/containers/filterBar.tsx @@ -1,7 +1,6 @@ import { connect } from "react-redux"; import FilterBar from "../components/filterBar"; import Actions from "../actions"; -import IState from "../interface/IState"; import { IFilterConditionState } from "../interface/IConditional"; import { IRepoFetchingStatus } from "../interface/IRepo"; diff --git a/src/renderer/containers/loginPage.tsx b/src/renderer/containers/loginPage.tsx index 47cd329..61197ce 100644 --- a/src/renderer/containers/loginPage.tsx +++ b/src/renderer/containers/loginPage.tsx @@ -7,6 +7,11 @@ import { ICredentialsState, ILoginResultState } from "../interface/IAccount"; export interface LoginPageProps { credentials: ICredentialsState; loginResult: ILoginResultState; + onGetLocalCredentials: (autoSignin: boolean) => Promise; + onRequestLogin: ( + credentials: ICredentialsState, + cb: (success: boolean, msg: string) => void + ) => void; } // Redux connection diff --git a/src/renderer/containers/repoClassifyTool.tsx b/src/renderer/containers/repoClassifyTool.tsx index 5c1ecda..b9333fe 100644 --- a/src/renderer/containers/repoClassifyTool.tsx +++ b/src/renderer/containers/repoClassifyTool.tsx @@ -8,7 +8,7 @@ import IRepo from "../interface/IRepo"; export interface RepoClassifyToolProps { repo: IRepo; categories: ICategory[]; - onGetCategoriesForRepo: (id: number) => void; + onGetCategoriesForRepo: (id: number) => Promise; onUpdateRepoCategories: (id: number, catIds: number[]) => void; } diff --git a/src/renderer/containers/repoDetailToolbar.tsx b/src/renderer/containers/repoDetailToolbar.tsx index 81de0fb..54b43cf 100644 --- a/src/renderer/containers/repoDetailToolbar.tsx +++ b/src/renderer/containers/repoDetailToolbar.tsx @@ -8,7 +8,7 @@ import ICategory from "../interface/ICategory"; export interface RepoDetailToolbarProps { categories: ICategory[]; selectedRepo: IRepo | null; - onStarStarCabinet: () => void; + onStarStarCabinet: () => Promise; onUpdateRepoNote: (id: number, note: string) => void; onChangeRepoFlag: (id: number, hasFlag: boolean) => void; onChangeRepoReadStatus: (id: number, read: boolean) => void; diff --git a/src/renderer/containers/repoTagsBar.tsx b/src/renderer/containers/repoTagsBar.tsx index 25cd4e2..432e7b6 100644 --- a/src/renderer/containers/repoTagsBar.tsx +++ b/src/renderer/containers/repoTagsBar.tsx @@ -3,12 +3,13 @@ import RepoTagsBar from "../components/repoTagsBar"; import Actions from "../actions"; import IState from "../interface/IState"; import IRepo from "../interface/IRepo"; +import ITag from "../interface/ITag"; export interface RepoTagsBarProps { selectedRepo: IRepo | null; onAddTagForRepo: (id: number, tagName: string) => void; onRemoveTagForRepo: (id: number, tagName: string) => void; - onGetTagsForRepo: (id: number) => void; + onGetTagsForRepo: (id: number) => Promise; } // Redux connection diff --git a/src/renderer/containers/settingPage.tsx b/src/renderer/containers/settingPage.tsx index 4a82a78..e4aba0f 100644 --- a/src/renderer/containers/settingPage.tsx +++ b/src/renderer/containers/settingPage.tsx @@ -4,11 +4,12 @@ import Actions from "../actions"; import IState from "../interface/IState"; import IProfile from "../interface/IProfile"; import { RxDatabase } from "rxdb"; +import { ICredentialsState } from "../interface/IAccount"; export interface SettingPageProps { profile: IProfile; db: RxDatabase; - onGetLocalCredentials: () => void; + onGetLocalCredentials: () => Promise; onGetMyProfile: () => void; onGetRxDB: (dbName: string) => void; } diff --git a/src/renderer/index.tsx b/src/renderer/index.tsx index 1c3cb39..ea0aa70 100644 --- a/src/renderer/index.tsx +++ b/src/renderer/index.tsx @@ -1,12 +1,12 @@ import React from "react"; import ReactDOM from "react-dom"; -import { Router, hashHistory, applyRouterMiddleware } from "react-router"; +import { Router, hashHistory } from "react-router"; import { Provider } from "react-redux"; import { syncHistoryWithStore } from "react-router-redux"; -import { useScroll } from "react-router-scroll"; -import configureStore from "./store/configureStore"; import routes from "./routes"; +const configureStore = require("./store/configureStore"); + declare var window; const store = configureStore(); @@ -23,7 +23,7 @@ if (module.hot) { ReactDOM.render( - + , document.getElementById("app") ); diff --git a/src/renderer/interface/ICategory.ts b/src/renderer/interface/ICategory.ts index 14db77b..9f37fad 100644 --- a/src/renderer/interface/ICategory.ts +++ b/src/renderer/interface/ICategory.ts @@ -3,6 +3,7 @@ export default interface ICategory { name: string; description: string; repos: number[]; + reposCount: number; createdAt: string; createdTime: string; updatedAt: string; diff --git a/src/renderer/interface/ILanguage.ts b/src/renderer/interface/ILanguage.ts index 13bb643..e231ec6 100644 --- a/src/renderer/interface/ILanguage.ts +++ b/src/renderer/interface/ILanguage.ts @@ -3,4 +3,5 @@ export default interface ILanguage { name: string; description: string; repos: number[]; + reposCount: number; } diff --git a/src/renderer/interface/IProfile.ts b/src/renderer/interface/IProfile.ts index b3cbb3d..271a4ae 100644 --- a/src/renderer/interface/IProfile.ts +++ b/src/renderer/interface/IProfile.ts @@ -1,4 +1,7 @@ export default interface IProfile { + name: string; + avatar_url: string; + id: number; login: string; avatarUrl: string; @@ -16,7 +19,7 @@ export default interface IProfile { receivedEventsUrl: string; type: string; siteAdmin: boolean; - name: string; + // name: string; company: string; blog: string; location: string; diff --git a/src/renderer/interface/IRepo.ts b/src/renderer/interface/IRepo.ts index 48673e6..dc776d0 100644 --- a/src/renderer/interface/IRepo.ts +++ b/src/renderer/interface/IRepo.ts @@ -1,3 +1,7 @@ +import ICategory from "./ICategory"; +import IAuthor from "./IAuthor"; +import ITag from "./ITag"; + export default interface IRepo { id: number; name: string; @@ -77,6 +81,9 @@ export default interface IRepo { note: string; defaultOrder: number; readme: string; + _categories: ICategory[]; + _contributors: IAuthor[]; + _tags: ITag[]; } export interface IRepoFetchingStatus { diff --git a/venders-config.json b/venders-config.json new file mode 100644 index 0000000..9a90191 --- /dev/null +++ b/venders-config.json @@ -0,0 +1 @@ +{"venders":{"js":"/assets/js/venders.809c01c9.js"}} \ No newline at end of file diff --git a/webpack/base.conf.babel.js b/webpack/base.conf.babel.js index 8748998..f8246f4 100644 --- a/webpack/base.conf.babel.js +++ b/webpack/base.conf.babel.js @@ -1,7 +1,6 @@ import path from "path"; import webpack from "webpack"; import SimpleProgressWebpackPlugin from "customized-progress-webpack-plugin"; -import CopyWebpackPlugin from "copy-webpack-plugin"; import HtmlWebpackPlugin from "html-webpack-plugin"; import pkg from "../package.json"; @@ -18,10 +17,6 @@ const getPlugins = function(morePlugins) { ), new webpack.HashedModuleIdsPlugin(), new SimpleProgressWebpackPlugin({ format: "compact" }), - new CopyWebpackPlugin([ - { from: "src/favicon.ico", to: path.resolve(__dirname, "../dist") }, - { from: "src/robots.txt", to: path.resolve(__dirname, "../dist") } - ]), new webpack.DllReferencePlugin({ context: __dirname, manifest: require("../manifest.json") @@ -30,22 +25,17 @@ const getPlugins = function(morePlugins) { name: "app" }), new HtmlWebpackPlugin({ - filename: path.resolve(__dirname, "../dist/index.html"), - template: "src/index.html", + filename: "../../app/dist/index.html", + template: "src/renderer/index.html", inject: true, - vendersName: vendersConfig.venders.js, - meta: "", - htmlDom: "", - state: "" - }), - new HtmlWebpackPlugin({ - filename: path.resolve(__dirname, "../dist/index.ejs"), - template: "src/index.html", - inject: true, - vendersName: vendersConfig.venders.js, - meta: "<%- meta %>", - htmlDom: "<%- markup %>", - state: "" + minify: { + removeComments: true, + collapseWhitespace: true, + removeAttributeQuotes: true + // more options: + // https://github.com/kangax/html-minifier#options-quick-reference + }, + bodyClass: `platform_${process.platform}` }) ]; diff --git a/webpack/dev.conf.babel.js b/webpack/dev.conf.babel.js index de77844..22a6bdb 100644 --- a/webpack/dev.conf.babel.js +++ b/webpack/dev.conf.babel.js @@ -15,24 +15,24 @@ const loaders = [ { test: /\.css$/, include: [/global/, /node_modules/], - loader: "style-loader!css-loader?sourceMap!postcss-loader" + loader: "style-loader!css-loader?sourceMap" }, { test: /\.css$/, exclude: [/global/, /node_modules/], loader: - "style-loader!css-loader?modules&sourceMap&importLoaders=1&localIdentName=[local]_[name]__[hash:base64:5]!postcss-loader" + "style-loader!css-loader?modules&sourceMap&importLoaders=1&localIdentName=[local]_[name]__[hash:base64:5]" }, { test: /\.less$/, include: [/global/, /node_modules/], - loader: "style-loader!css-loader?sourceMap!postcss-loader!less-loader" + loader: "style-loader!css-loader?sourceMap!less-loader" }, { test: /\.less$/, exclude: [/global/, /node_modules/], loader: - "style-loader!css-loader?modules&sourceMap&importLoaders=1&localIdentName=[local]_[name]__[hash:base64:5]!postcss-loader!less-loader" + "style-loader!css-loader?modules&sourceMap&importLoaders=1&localIdentName=[local]_[name]__[hash:base64:5]!less-loader" } ]; diff --git a/webpack/prod.conf.babel.js b/webpack/prod.conf.babel.js index db17b5c..d7a317c 100644 --- a/webpack/prod.conf.babel.js +++ b/webpack/prod.conf.babel.js @@ -3,7 +3,6 @@ import webpack from "webpack"; import ExtractTextPlugin from "extract-text-webpack-plugin"; import OptimizeCssAssetsPlugin from "optimize-css-assets-webpack-plugin"; import baseConf from "./base.conf.babel"; -import { PUBLIC_ASSETS_URL } from "../env"; const plugins = [ new webpack.DefinePlugin({ @@ -34,7 +33,7 @@ const loaders = [ include: [/global/, /node_modules/], loader: ExtractTextPlugin.extract({ fallback: "style-loader", - use: "css-loader?sourceMap!postcss-loader" + use: "css-loader?sourceMap" }) }, { @@ -42,8 +41,7 @@ const loaders = [ exclude: [/global/, /node_modules/], loader: ExtractTextPlugin.extract({ fallback: "style-loader", - use: - "css-loader?modules&sourceMap&importLoaders=1&localIdentName=__[hash:base64:5]!postcss-loader" + use: "css-loader?modules&sourceMap&importLoaders=1&localIdentName=__[hash:base64:5]" }) }, { @@ -51,7 +49,7 @@ const loaders = [ include: [/global/, /node_modules/], loader: ExtractTextPlugin.extract({ fallback: "style-loader", - use: "css-loader?sourceMap!postcss-loader!less-loader" + use: "css-loader?sourceMap!less-loader" }) }, { @@ -60,7 +58,7 @@ const loaders = [ loader: ExtractTextPlugin.extract({ fallback: "style-loader", use: - "css-loader?modules&sourceMap&importLoaders=1&localIdentName=__[hash:base64:5]!postcss-loader!less-loader" + "css-loader?modules&sourceMap&importLoaders=1&localIdentName=__[hash:base64:5]!less-loader" }) } ]; @@ -71,7 +69,7 @@ const entry = { const output = { path: path.resolve(__dirname, "../app/dist/assets"), - publicPath: PUBLIC_ASSETS_URL, + publicPath: "/assets/", filename: "js/[name].[chunkhash:8].js", chunkFilename: "js/[name].[chunkhash:8].chunk.js" }; diff --git a/yarn.lock b/yarn.lock index 8ecd48f..886ead7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,9 +2,20 @@ # yarn lockfile v1 -"@std/esm@^0.16.0": - version "0.16.0" - resolved "https://registry.yarnpkg.com/@std/esm/-/esm-0.16.0.tgz#2a7a33ecb7f1701cebd4c87df6d0d945ed51f730" +"@babel/helper-module-imports@^7.0.0-beta.34": + version "7.0.0-beta.36" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.0.0-beta.36.tgz#a35c09ec39bbee47553e9688e444d30a12e51346" + dependencies: + "@babel/types" "7.0.0-beta.36" + lodash "^4.2.0" + +"@babel/types@7.0.0-beta.36": + version "7.0.0-beta.36" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0-beta.36.tgz#64f2004353de42adb72f9ebb4665fc35b5499d23" + dependencies: + esutils "^2.0.2" + lodash "^4.2.0" + to-fast-properties "^2.0.0" "@types/core-js@0.9.43": version "0.9.43" @@ -174,10 +185,6 @@ any-observable@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/any-observable/-/any-observable-0.2.0.tgz#c67870058003579009083f54ac0abafb5c33d242" -any-promise@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-0.1.0.tgz#830b680aa7e56f33451d4b049f3bd8044498ee27" - anymatch@^1.3.0: version "1.3.2" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a" @@ -295,6 +302,16 @@ assert@^1.1.1: dependencies: util "0.10.3" +assets-webpack-plugin@^3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/assets-webpack-plugin/-/assets-webpack-plugin-3.5.1.tgz#931ce0d66d42e88ed5e7f18d65522943c57a387d" + dependencies: + camelcase "^1.2.1" + escape-string-regexp "^1.0.3" + lodash.assign "^3.2.0" + lodash.merge "^3.3.2" + mkdirp "^0.5.1" + async-each@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" @@ -342,7 +359,7 @@ autoprefixer@^6.3.1: postcss "^5.2.16" postcss-value-parser "^3.2.3" -autoprefixer@^7.1.1, autoprefixer@^7.1.2: +autoprefixer@^7.1.2: version "7.2.3" resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-7.2.3.tgz#c2841e38b7940c2d0a9bbffd72c75f33637854f8" dependencies: @@ -481,6 +498,16 @@ babel-helper-regex@^6.24.1: babel-types "^6.26.0" lodash "^4.17.4" +babel-helper-remap-async-to-generator@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b" + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + babel-helper-replace-supers@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a" @@ -519,6 +546,16 @@ babel-plugin-check-es2015-constants@^6.22.0: dependencies: babel-runtime "^6.22.0" +babel-plugin-import@^1.6.3: + version "1.6.3" + resolved "https://registry.yarnpkg.com/babel-plugin-import/-/babel-plugin-import-1.6.3.tgz#f4deeac51ff9f997c9cf38e8d7d7b9142504eaf5" + dependencies: + "@babel/helper-module-imports" "^7.0.0-beta.34" + +babel-plugin-syntax-async-functions@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" + babel-plugin-syntax-flow@^6.18.0: version "6.18.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz#4c3ab20a2af26aa20cd25995c398c4eb70310c8d" @@ -527,6 +564,18 @@ babel-plugin-syntax-jsx@^6.3.13, babel-plugin-syntax-jsx@^6.8.0: version "6.18.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946" +babel-plugin-syntax-trailing-function-commas@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" + +babel-plugin-transform-async-to-generator@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" + dependencies: + babel-helper-remap-async-to-generator "^6.24.1" + babel-plugin-syntax-async-functions "^6.8.0" + babel-runtime "^6.22.0" + babel-plugin-transform-es2015-arrow-functions@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" @@ -743,6 +792,14 @@ babel-plugin-transform-strict-mode@^6.24.1: babel-runtime "^6.22.0" babel-types "^6.24.1" +babel-polyfill@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.26.0.tgz#379937abc67d7895970adc621f284cd966cf2153" + dependencies: + babel-runtime "^6.26.0" + core-js "^2.5.0" + regenerator-runtime "^0.10.5" + babel-preset-es2015@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz#d44050d6bc2c9feea702aaf38d727a0210538939" @@ -772,6 +829,13 @@ babel-preset-es2015@^6.24.1: babel-plugin-transform-es2015-unicode-regex "^6.24.1" babel-plugin-transform-regenerator "^6.24.1" +babel-preset-es2017@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-preset-es2017/-/babel-preset-es2017-6.24.1.tgz#597beadfb9f7f208bcfd8a12e9b2b29b8b2f14d1" + dependencies: + babel-plugin-syntax-trailing-function-commas "^6.22.0" + babel-plugin-transform-async-to-generator "^6.24.1" + babel-preset-flow@^6.23.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-preset-flow/-/babel-preset-flow-6.23.0.tgz#e71218887085ae9a24b5be4169affb599816c49d" @@ -849,10 +913,6 @@ bail@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/bail/-/bail-1.0.2.tgz#f7d6c1731630a9f9f0d4d35ed1f962e2074a1764" -balanced-match@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.1.0.tgz#b504bd05869b39259dd0c5efc35d843176dccc4a" - balanced-match@^0.4.2: version "0.4.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" @@ -1027,7 +1087,7 @@ browserslist@^1.3.6, browserslist@^1.5.2, browserslist@^1.7.6: caniuse-db "^1.0.30000639" electron-to-chromium "^1.2.7" -browserslist@^2.0.0, browserslist@^2.10.0: +browserslist@^2.10.0: version "2.10.0" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-2.10.0.tgz#bac5ee1cc69ca9d96403ffb8a3abdc5b6aed6346" dependencies: @@ -1079,10 +1139,6 @@ camel-case@3.0.x: no-case "^2.2.0" upper-case "^1.1.1" -camelcase-css@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/camelcase-css/-/camelcase-css-1.0.1.tgz#157c4238265f5cf94a1dffde86446552cbf3f705" - camelcase-keys@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" @@ -1098,7 +1154,7 @@ camelcase-keys@^4.0.0: map-obj "^2.0.0" quick-lru "^1.0.0" -camelcase@^1.0.2: +camelcase@^1.0.2, camelcase@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" @@ -1127,20 +1183,11 @@ caniuse-api@^1.5.2: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-api@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-2.0.0.tgz#b1ddb5a5966b16f48dc4998444d4bbc6c7d9d834" - dependencies: - browserslist "^2.0.0" - caniuse-lite "^1.0.0" - lodash.memoize "^4.1.2" - lodash.uniq "^4.5.0" - caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639: version "1.0.30000784" resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000784.tgz#1be95012d9489c7719074f81aee57dbdffe6361b" -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000780, caniuse-lite@^1.0.30000783: +caniuse-lite@^1.0.30000780, caniuse-lite@^1.0.30000783: version "1.0.30000784" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000784.tgz#129ced74e9a1280a441880b6cd2bce30ef59e6c0" @@ -1311,7 +1358,7 @@ collapse-white-space@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/collapse-white-space/-/collapse-white-space-1.0.3.tgz#4b906f670e5a963a87b76b0e1689643341b6023c" -color-convert@^1.3.0, color-convert@^1.8.2, color-convert@^1.9.0, color-convert@^1.9.1: +color-convert@^1.3.0, color-convert@^1.9.0: version "1.9.1" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.1.tgz#c1261107aeb2f294ebffec9ed9ecad529a6097ed" dependencies: @@ -1327,13 +1374,6 @@ color-string@^0.3.0: dependencies: color-name "^1.0.0" -color-string@^1.4.0, color-string@^1.5.2: - version "1.5.2" - resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.2.tgz#26e45814bc3c9a7cbd6751648a41434514a773a9" - dependencies: - color-name "^1.0.0" - simple-swizzle "^0.2.2" - color@^0.11.0: version "0.11.4" resolved "https://registry.yarnpkg.com/color/-/color-0.11.4.tgz#6d7b5c74fb65e841cd48792ad1ed5e07b904d764" @@ -1342,20 +1382,6 @@ color@^0.11.0: color-convert "^1.3.0" color-string "^0.3.0" -color@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/color/-/color-1.0.3.tgz#e48e832d85f14ef694fb468811c2d5cfe729b55d" - dependencies: - color-convert "^1.8.2" - color-string "^1.4.0" - -color@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color/-/color-2.0.1.tgz#e4ed78a3c4603d0891eba5430b04b86314f4c839" - dependencies: - color-convert "^1.9.1" - color-string "^1.5.2" - colormin@^1.0.5: version "1.1.2" resolved "https://registry.yarnpkg.com/colormin/-/colormin-1.1.2.tgz#ea2f7420a72b96881a38aae59ec124a6f7298133" @@ -1464,6 +1490,12 @@ cookie@0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" +copy-to-clipboard@^3: + version "3.0.8" + resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.0.8.tgz#f4e82f4a8830dce4666b7eb8ded0c9bcc313aba9" + dependencies: + toggle-selection "^1.0.3" + core-js@^1.0.0: version "1.2.7" resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" @@ -1590,15 +1622,6 @@ css-animation@1.x, css-animation@^1.2.5, css-animation@^1.3.2: babel-runtime "6.x" component-classes "^1.2.5" -css-color-function@~1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/css-color-function/-/css-color-function-1.3.3.tgz#8ed24c2c0205073339fafa004bc8c141fccb282e" - dependencies: - balanced-match "0.1.0" - color "^0.11.0" - debug "^3.1.0" - rgb "~0.1.0" - css-color-names@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" @@ -1639,10 +1662,6 @@ css-selector-tokenizer@^0.7.0: fastparse "^1.1.1" regexpu-core "^1.0.0" -css-unit-converter@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/css-unit-converter/-/css-unit-converter-1.1.1.tgz#d9b9281adcfd8ced935bdbaba83786897f64e996" - css-what@2.1: version "2.1.0" resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.0.tgz#9467d032c38cfaefb9f2d79501253062f87fa1bd" @@ -1917,10 +1936,6 @@ dom-converter@~0.1: dependencies: utila "~0.3" -dom-helpers@^3.2.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.3.1.tgz#fc1a4e15ffdf60ddde03a480a9c0fece821dd4a6" - dom-matches@>=1.0.1: version "2.0.0" resolved "https://registry.yarnpkg.com/dom-matches/-/dom-matches-2.0.0.tgz#d2728b416a87533980eb089b848d253cf23a758c" @@ -2181,7 +2196,7 @@ escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" -escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.3, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" @@ -2287,6 +2302,10 @@ execall@^1.0.0: dependencies: clone-regexp "^1.0.0" +exenv@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d" + exit-hook@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" @@ -2866,6 +2885,16 @@ history@^3.0.0: query-string "^4.2.2" warning "^3.0.0" +history@^4.7.2: + version "4.7.2" + resolved "https://registry.yarnpkg.com/history/-/history-4.7.2.tgz#22b5c7f31633c5b8021c7f4a8a954ac139ee8d5b" + dependencies: + invariant "^2.2.1" + loose-envify "^1.2.0" + resolve-pathname "^2.2.0" + value-equal "^0.4.0" + warning "^3.0.0" + hmac-drbg@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" @@ -2886,7 +2915,7 @@ hoist-non-react-statics@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz#aa448cf0986d55cc40773b17174b7dd066cb7cfb" -hoist-non-react-statics@^2.2.1, hoist-non-react-statics@^2.3.1: +hoist-non-react-statics@^2.2.1, hoist-non-react-statics@^2.3.0, hoist-non-react-statics@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.3.1.tgz#343db84c6018c650778898240135a1420ee22ce0" @@ -3174,10 +3203,6 @@ is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" -is-arrayish@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.1.tgz#c2dfc386abaa0c3e33c48db3fe87059e69065efd" - is-binary-path@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" @@ -3459,10 +3484,6 @@ isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" -isnumeric@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/isnumeric/-/isnumeric-0.2.0.tgz#a2347ba360de19e33d0ffd590fddf7755cbf2e64" - isobject@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" @@ -3809,13 +3830,56 @@ lodash-es@^4.2.0, lodash-es@^4.2.1: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.4.tgz#dcc1d7552e150a0640073ba9cb31d70f032950e7" +lodash._arraycopy@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz#76e7b7c1f1fb92547374878a562ed06a3e50f6e1" + +lodash._arrayeach@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz#bab156b2a90d3f1bbd5c653403349e5e5933ef9e" + +lodash._baseassign@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" + dependencies: + lodash._basecopy "^3.0.0" + lodash.keys "^3.0.0" + +lodash._basecopy@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" + +lodash._basefor@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash._basefor/-/lodash._basefor-3.0.3.tgz#7550b4e9218ef09fad24343b612021c79b4c20c2" + +lodash._bindcallback@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" + +lodash._createassigner@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11" + dependencies: + lodash._bindcallback "^3.0.0" + lodash._isiterateecall "^3.0.0" + lodash.restparam "^3.0.0" + lodash._getnative@^3.0.0: version "3.9.1" resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" -lodash._reinterpolate@~3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" +lodash._isiterateecall@^3.0.0: + version "3.0.9" + resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" + +lodash.assign@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-3.2.0.tgz#3ce9f0234b4b2223e296b8fa0ac1fee8ebca64fa" + dependencies: + lodash._baseassign "^3.0.0" + lodash._createassigner "^3.0.0" + lodash.keys "^3.0.0" lodash.camelcase@^4.3.0: version "4.3.0" @@ -3841,7 +3905,19 @@ lodash.isnull@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/lodash.isnull/-/lodash.isnull-3.0.0.tgz#fafbe59ea1dca27eed786534039dd84c2e07c56e" -lodash.keys@^3.1.2: +lodash.isplainobject@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-3.2.0.tgz#9a8238ae16b200432960cd7346512d0123fbf4c5" + dependencies: + lodash._basefor "^3.0.0" + lodash.isarguments "^3.0.0" + lodash.keysin "^3.0.0" + +lodash.istypedarray@^3.0.0: + version "3.0.6" + resolved "https://registry.yarnpkg.com/lodash.istypedarray/-/lodash.istypedarray-3.0.6.tgz#c9a477498607501d8e8494d283b87c39281cef62" + +lodash.keys@^3.0.0, lodash.keys@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" dependencies: @@ -3849,31 +3925,52 @@ lodash.keys@^3.1.2: lodash.isarguments "^3.0.0" lodash.isarray "^3.0.0" +lodash.keysin@^3.0.0: + version "3.0.8" + resolved "https://registry.yarnpkg.com/lodash.keysin/-/lodash.keysin-3.0.8.tgz#22c4493ebbedb1427962a54b445b2c8a767fb47f" + dependencies: + lodash.isarguments "^3.0.0" + lodash.isarray "^3.0.0" + lodash.memoize@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" +lodash.merge@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-3.3.2.tgz#0d90d93ed637b1878437bb3e21601260d7afe994" + dependencies: + lodash._arraycopy "^3.0.0" + lodash._arrayeach "^3.0.0" + lodash._createassigner "^3.0.0" + lodash._getnative "^3.0.0" + lodash.isarguments "^3.0.0" + lodash.isarray "^3.0.0" + lodash.isplainobject "^3.0.0" + lodash.istypedarray "^3.0.0" + lodash.keys "^3.0.0" + lodash.keysin "^3.0.0" + lodash.toplainobject "^3.0.0" + lodash.merge@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.0.tgz#69884ba144ac33fe699737a6086deffadd0f89c5" -lodash.template@^4.2.4: - version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.4.0.tgz#e73a0385c8355591746e020b99679c690e68fba0" - dependencies: - lodash._reinterpolate "~3.0.0" - lodash.templatesettings "^4.0.0" - -lodash.templatesettings@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz#2b4d4e95ba440d915ff08bc899e4553666713316" - dependencies: - lodash._reinterpolate "~3.0.0" +lodash.restparam@^3.0.0: + version "3.6.1" + resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" lodash.throttle@^4.0.0: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" +lodash.toplainobject@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash.toplainobject/-/lodash.toplainobject-3.0.0.tgz#28790ad942d293d78aa663a07ecf7f52ca04198d" + dependencies: + lodash._basecopy "^3.0.0" + lodash.keysin "^3.0.0" + lodash.uniq@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" @@ -4179,6 +4276,10 @@ moment@2.x, moment@^2.18.1: version "2.19.1" resolved "https://registry.yarnpkg.com/moment/-/moment-2.19.1.tgz#56da1a2d1cbf01d38b7e1afc31c10bcfa1929167" +moment@^2.20.1: + version "2.20.1" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.20.1.tgz#d6eb1a46cbcc14a2b2f9434112c1ff8907f313fd" + ms@0.7.2: version "0.7.2" resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" @@ -4455,10 +4556,6 @@ once@^1.3.0, once@^1.3.3: dependencies: wrappy "1" -onecolor@^3.0.4: - version "3.0.5" - resolved "https://registry.yarnpkg.com/onecolor/-/onecolor-3.0.5.tgz#36eff32201379efdf1180fb445e51a8e2425f9f6" - onetime@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" @@ -4662,6 +4759,12 @@ path-to-regexp@0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" +path-to-regexp@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.7.0.tgz#59fde0f435badacba103a84e9d3bc64e96b9937d" + dependencies: + isarray "0.0.1" + path-type@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" @@ -4722,27 +4825,12 @@ pinkie@^2.0.0: version "2.0.4" resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" -pixrem@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/pixrem/-/pixrem-4.0.1.tgz#2da4a1de6ec4423c5fc3794e930b81d4490ec686" - dependencies: - browserslist "^2.0.0" - postcss "^6.0.0" - reduce-css-calc "^1.2.7" - pkg-dir@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" dependencies: find-up "^2.1.0" -pleeease-filters@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/pleeease-filters/-/pleeease-filters-4.0.0.tgz#6632b2fb05648d2758d865384fbced79e1ccaec7" - dependencies: - onecolor "^3.0.4" - postcss "^6.0.1" - portfinder@^1.0.9: version "1.0.13" resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.13.tgz#bb32ecd87c27104ae6ee44b5a3ccbf0ebb1aede9" @@ -4751,33 +4839,6 @@ portfinder@^1.0.9: debug "^2.2.0" mkdirp "0.5.x" -postcss-advanced-variables@1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/postcss-advanced-variables/-/postcss-advanced-variables-1.2.2.tgz#90a6213262e66a050a368b4a9c5d4778d72dbd74" - dependencies: - postcss "^5.0.10" - -postcss-apply@^0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/postcss-apply/-/postcss-apply-0.8.0.tgz#14e544bbb5cb6f1c1e048857965d79ae066b1343" - dependencies: - babel-runtime "^6.23.0" - balanced-match "^0.4.2" - postcss "^6.0.0" - -postcss-atroot@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/postcss-atroot/-/postcss-atroot-0.1.3.tgz#6752c0230c745140549345b2b0e30ebeda01a405" - dependencies: - postcss "^5.0.5" - -postcss-attribute-case-insensitive@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-2.0.0.tgz#94dc422c8f90997f16bd33a3654bbbec084963b4" - dependencies: - postcss "^6.0.0" - postcss-selector-parser "^2.2.3" - postcss-calc@^5.2.0: version "5.3.1" resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-5.3.1.tgz#77bae7ca928ad85716e2fda42f261bf7c1d65b5e" @@ -4786,80 +4847,6 @@ postcss-calc@^5.2.0: postcss-message-helpers "^2.0.0" reduce-css-calc "^1.2.6" -postcss-calc@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-6.0.1.tgz#3d24171bbf6e7629d422a436ebfe6dd9511f4330" - dependencies: - css-unit-converter "^1.1.1" - postcss "^6.0.0" - postcss-selector-parser "^2.2.2" - reduce-css-calc "^2.0.0" - -postcss-color-function@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-color-function/-/postcss-color-function-4.0.1.tgz#402b3f2cebc3f6947e618fb6be3654fbecef6444" - dependencies: - css-color-function "~1.3.3" - postcss "^6.0.1" - postcss-message-helpers "^2.0.0" - postcss-value-parser "^3.3.0" - -postcss-color-gray@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/postcss-color-gray/-/postcss-color-gray-4.1.0.tgz#e5581ed57eaa826fb652ca11b1e2b7b136a9f9df" - dependencies: - color "^2.0.1" - postcss "^6.0.14" - postcss-message-helpers "^2.0.0" - reduce-function-call "^1.0.2" - -postcss-color-hex-alpha@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/postcss-color-hex-alpha/-/postcss-color-hex-alpha-3.0.0.tgz#1e53e6c8acb237955e8fd08b7ecdb1b8b8309f95" - dependencies: - color "^1.0.3" - postcss "^6.0.1" - postcss-message-helpers "^2.0.0" - -postcss-color-hsl@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/postcss-color-hsl/-/postcss-color-hsl-2.0.0.tgz#12703666fa310430e3f30a454dac1386317d5844" - dependencies: - postcss "^6.0.1" - postcss-value-parser "^3.3.0" - units-css "^0.4.0" - -postcss-color-hwb@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/postcss-color-hwb/-/postcss-color-hwb-3.0.0.tgz#3402b19ef4d8497540c1fb5072be9863ca95571e" - dependencies: - color "^1.0.3" - postcss "^6.0.1" - postcss-message-helpers "^2.0.0" - reduce-function-call "^1.0.2" - -postcss-color-rebeccapurple@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-3.0.0.tgz#eebaf03d363b4300b96792bd3081c19ed66513d3" - dependencies: - postcss "^6.0.1" - postcss-value-parser "^3.3.0" - -postcss-color-rgb@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/postcss-color-rgb/-/postcss-color-rgb-2.0.0.tgz#14539c8a7131494b482e0dd1cc265ff6514b5263" - dependencies: - postcss "^6.0.1" - postcss-value-parser "^3.3.0" - -postcss-color-rgba-fallback@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/postcss-color-rgba-fallback/-/postcss-color-rgba-fallback-3.0.0.tgz#37d5c9353a07a09270912a82606bb42a0d702c04" - dependencies: - postcss "^6.0.6" - postcss-value-parser "^3.3.0" - rgb-hex "^2.1.0" - postcss-colormin@^2.1.8: version "2.2.2" resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-2.2.2.tgz#6631417d5f0e909a3d7ec26b24c8a8d1e4f96e4b" @@ -4875,62 +4862,6 @@ postcss-convert-values@^2.3.4: postcss "^5.0.11" postcss-value-parser "^3.1.2" -postcss-cssnext@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/postcss-cssnext/-/postcss-cssnext-3.0.2.tgz#63b77adb0b8a4c1d5ec32cd345539535a3417d48" - dependencies: - autoprefixer "^7.1.1" - caniuse-api "^2.0.0" - chalk "^2.0.1" - pixrem "^4.0.0" - pleeease-filters "^4.0.0" - postcss "^6.0.5" - postcss-apply "^0.8.0" - postcss-attribute-case-insensitive "^2.0.0" - postcss-calc "^6.0.0" - postcss-color-function "^4.0.0" - postcss-color-gray "^4.0.0" - postcss-color-hex-alpha "^3.0.0" - postcss-color-hsl "^2.0.0" - postcss-color-hwb "^3.0.0" - postcss-color-rebeccapurple "^3.0.0" - postcss-color-rgb "^2.0.0" - postcss-color-rgba-fallback "^3.0.0" - postcss-custom-media "^6.0.0" - postcss-custom-properties "^6.1.0" - postcss-custom-selectors "^4.0.1" - postcss-font-family-system-ui "^2.0.1" - postcss-font-variant "^3.0.0" - postcss-image-set-polyfill "^0.3.5" - postcss-initial "^2.0.0" - postcss-media-minmax "^3.0.0" - postcss-nesting "^4.0.1" - postcss-pseudo-class-any-link "^4.0.0" - postcss-pseudoelements "^5.0.0" - postcss-replace-overflow-wrap "^2.0.0" - postcss-selector-matches "^3.0.1" - postcss-selector-not "^3.0.1" - -postcss-custom-media@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/postcss-custom-media/-/postcss-custom-media-6.0.0.tgz#be532784110ecb295044fb5395a18006eb21a737" - dependencies: - postcss "^6.0.1" - -postcss-custom-properties@^6.1.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/postcss-custom-properties/-/postcss-custom-properties-6.2.0.tgz#5d929a7f06e9b84e0f11334194c0ba9a30acfbe9" - dependencies: - balanced-match "^1.0.0" - postcss "^6.0.13" - -postcss-custom-selectors@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-custom-selectors/-/postcss-custom-selectors-4.0.1.tgz#781382f94c52e727ef5ca4776ea2adf49a611382" - dependencies: - postcss "^6.0.1" - postcss-selector-matches "^3.0.0" - postcss-discard-comments@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-2.0.4.tgz#befe89fafd5b3dace5ccce51b76b81514be00e3d" @@ -4962,12 +4893,6 @@ postcss-discard-unused@^2.2.1: postcss "^5.0.14" uniqs "^2.0.0" -postcss-extend@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/postcss-extend/-/postcss-extend-1.0.5.tgz#5ea98bf787ba3cacf4df4609743f80a833b1d0e7" - dependencies: - postcss "^5.0.4" - postcss-filter-plugins@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/postcss-filter-plugins/-/postcss-filter-plugins-2.0.2.tgz#6d85862534d735ac420e4a85806e1f5d4286d84c" @@ -4975,21 +4900,6 @@ postcss-filter-plugins@^2.0.0: postcss "^5.0.4" uniqid "^4.0.0" -postcss-font-family-system-ui@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/postcss-font-family-system-ui/-/postcss-font-family-system-ui-2.1.1.tgz#1ee54246cd02b199755ebe5781b91188ed908006" - dependencies: - "@std/esm" "^0.16.0" - lodash "^4.17.4" - postcss "^6.0.1" - postcss-value-parser "^3.3.0" - -postcss-font-variant@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/postcss-font-variant/-/postcss-font-variant-3.0.0.tgz#08ccc88f6050ba82ed8ef2cc76c0c6a6b41f183e" - dependencies: - postcss "^6.0.1" - postcss-html@^0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/postcss-html/-/postcss-html-0.12.0.tgz#39b6adb4005dfc5464df7999c0f81c95bced7e50" @@ -4998,37 +4908,6 @@ postcss-html@^0.12.0: remark "^8.0.0" unist-util-find-all-after "^1.0.1" -postcss-image-set-polyfill@^0.3.5: - version "0.3.5" - resolved "https://registry.yarnpkg.com/postcss-image-set-polyfill/-/postcss-image-set-polyfill-0.3.5.tgz#0f193413700cf1f82bd39066ef016d65a4a18181" - dependencies: - postcss "^6.0.1" - postcss-media-query-parser "^0.2.3" - -postcss-import@^10.0.0: - version "10.0.0" - resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-10.0.0.tgz#4c85c97b099136cc5ea0240dc1dfdbfde4e2ebbe" - dependencies: - object-assign "^4.0.1" - postcss "^6.0.1" - postcss-value-parser "^3.2.3" - read-cache "^1.0.0" - resolve "^1.1.7" - -postcss-initial@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/postcss-initial/-/postcss-initial-2.0.0.tgz#72715f7336e0bb79351d99ee65c4a253a8441ba4" - dependencies: - lodash.template "^4.2.4" - postcss "^6.0.1" - -postcss-js@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-1.0.1.tgz#ffaf29226e399ea74b5dce02cab1729d7addbc7b" - dependencies: - camelcase-css "^1.0.1" - postcss "^6.0.11" - postcss-less@^1.1.0: version "1.1.3" resolved "https://registry.yarnpkg.com/postcss-less/-/postcss-less-1.1.3.tgz#6930525271bfe38d5793d33ac09c1a546b87bb51" @@ -5067,12 +4946,6 @@ postcss-loader@^2.0.9: postcss-load-config "^1.2.0" schema-utils "^0.3.0" -postcss-media-minmax@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/postcss-media-minmax/-/postcss-media-minmax-3.0.0.tgz#675256037a43ef40bc4f0760bfd06d4dc69d48d2" - dependencies: - postcss "^6.0.1" - postcss-media-query-parser@^0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz#27b39c6f4d94f81b1a73b8f76351c609e5cef244" @@ -5138,16 +5011,6 @@ postcss-minify-selectors@^2.0.4: postcss "^5.0.14" postcss-selector-parser "^2.0.0" -postcss-mixins@^6.0.1: - version "6.2.0" - resolved "https://registry.yarnpkg.com/postcss-mixins/-/postcss-mixins-6.2.0.tgz#fa9d2c2166b2ae7745956c727ab9dd2de4b96a40" - dependencies: - globby "^6.1.0" - postcss "^6.0.13" - postcss-js "^1.0.1" - postcss-simple-vars "^4.1.0" - sugarss "^1.0.0" - postcss-modules-extract-imports@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.0.tgz#66140ecece38ef06bf0d3e355d69bf59d141ea85" @@ -5175,19 +5038,6 @@ postcss-modules-values@^1.1.0: icss-replace-symbols "^1.1.0" postcss "^6.0.1" -postcss-nested@^2.0.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-2.1.2.tgz#04057281f9631fef684857fb0119bae04ede03c6" - dependencies: - postcss "^6.0.9" - postcss-selector-parser "^2.2.3" - -postcss-nesting@^4.0.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/postcss-nesting/-/postcss-nesting-4.2.1.tgz#0483bce338b3f0828ced90ff530b29b98b00300d" - dependencies: - postcss "^6.0.11" - postcss-normalize-charset@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-1.1.1.tgz#ef9ee71212d7fe759c78ed162f61ed62b5cb93f1" @@ -5210,34 +5060,6 @@ postcss-ordered-values@^2.1.0: postcss "^5.0.4" postcss-value-parser "^3.0.1" -postcss-partial-import@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/postcss-partial-import/-/postcss-partial-import-4.1.0.tgz#f6c3e78e7bbeda4d9dab96d360367b90b353f9a4" - dependencies: - glob "^7.1.1" - postcss-import "^10.0.0" - -postcss-property-lookup@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/postcss-property-lookup/-/postcss-property-lookup-1.2.1.tgz#30450a1361b7aae758bbedd5201fbe057bb8270b" - dependencies: - object-assign "^4.0.1" - postcss "^5.0.4" - tcomb "^2.5.1" - -postcss-pseudo-class-any-link@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-4.0.0.tgz#9152a0613d3450720513e8892854bae42d0ee68e" - dependencies: - postcss "^6.0.1" - postcss-selector-parser "^2.2.3" - -postcss-pseudoelements@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/postcss-pseudoelements/-/postcss-pseudoelements-5.0.0.tgz#eef194e8d524645ca520a949e95e518e812402cb" - dependencies: - postcss "^6.0.0" - postcss-reduce-idents@^2.2.2: version "2.4.0" resolved "https://registry.yarnpkg.com/postcss-reduce-idents/-/postcss-reduce-idents-2.4.0.tgz#c2c6d20cc958284f6abfbe63f7609bf409059ad3" @@ -5259,12 +5081,6 @@ postcss-reduce-transforms@^1.0.3: postcss "^5.0.8" postcss-value-parser "^3.0.1" -postcss-replace-overflow-wrap@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-2.0.0.tgz#794db6faa54f8db100854392a93af45768b4e25b" - dependencies: - postcss "^6.0.1" - postcss-reporter@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/postcss-reporter/-/postcss-reporter-5.0.0.tgz#a14177fd1342829d291653f2786efd67110332c3" @@ -5297,21 +5113,7 @@ postcss-scss@^1.0.2: dependencies: postcss "^6.0.3" -postcss-selector-matches@^3.0.0, postcss-selector-matches@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/postcss-selector-matches/-/postcss-selector-matches-3.0.1.tgz#e5634011e13950881861bbdd58c2d0111ffc96ab" - dependencies: - balanced-match "^0.4.2" - postcss "^6.0.1" - -postcss-selector-not@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/postcss-selector-not/-/postcss-selector-not-3.0.1.tgz#2e4db2f0965336c01e7cec7db6c60dff767335d9" - dependencies: - balanced-match "^0.4.2" - postcss "^6.0.1" - -postcss-selector-parser@^2.0.0, postcss-selector-parser@^2.2.2, postcss-selector-parser@^2.2.3: +postcss-selector-parser@^2.0.0, postcss-selector-parser@^2.2.2: version "2.2.3" resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-2.2.3.tgz#f9437788606c3c9acee16ffe8d8b16297f27bb90" dependencies: @@ -5327,28 +5129,6 @@ postcss-selector-parser@^3.1.0: indexes-of "^1.0.1" uniq "^1.0.1" -postcss-simple-vars@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/postcss-simple-vars/-/postcss-simple-vars-4.1.0.tgz#043248cfef8d3f51b3486a28c09f8375dbf1b2f9" - dependencies: - postcss "^6.0.9" - -postcss-smart-import@^0.7.6: - version "0.7.6" - resolved "https://registry.yarnpkg.com/postcss-smart-import/-/postcss-smart-import-0.7.6.tgz#259deb84aa28f138458218ecc0e9a84c61ada6a4" - dependencies: - babel-runtime "^6.26.0" - lodash "^4.17.4" - object-assign "^4.1.1" - postcss "^6.0.14" - postcss-sass "^0.2.0" - postcss-scss "^1.0.2" - postcss-value-parser "^3.3.0" - promise-each "^2.2.0" - read-cache "^1.0.0" - resolve "^1.5.0" - sugarss "^1.0.1" - postcss-svgo@^2.1.1: version "2.1.6" resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-2.1.6.tgz#b6df18aa613b666e133f08adb5219c2684ac108d" @@ -5387,7 +5167,7 @@ postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0 source-map "^0.5.6" supports-color "^3.2.3" -postcss@^6.0.0, postcss@^6.0.1, postcss@^6.0.11, postcss@^6.0.13, postcss@^6.0.14, postcss@^6.0.3, postcss@^6.0.5, postcss@^6.0.6, postcss@^6.0.8, postcss@^6.0.9: +postcss@^6.0.0, postcss@^6.0.1, postcss@^6.0.14, postcss@^6.0.3, postcss@^6.0.6, postcss@^6.0.8: version "6.0.14" resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.14.tgz#5534c72114739e75d0afcf017db853099f562885" dependencies: @@ -5623,27 +5403,6 @@ pre-commit@^1.2.2: spawn-sync "^1.0.15" which "1.2.x" -precss@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/precss/-/precss-2.0.0.tgz#7f567e3318e06d44c8fdbf9e58452e8358bf4b71" - dependencies: - postcss "^6.0.3" - postcss-advanced-variables "1.2.2" - postcss-atroot "^0.1.3" - postcss-color-function "^4.0.0" - postcss-custom-media "^6.0.0" - postcss-custom-properties "^6.1.0" - postcss-custom-selectors "^4.0.1" - postcss-extend "^1.0.5" - postcss-media-minmax "^3.0.0" - postcss-mixins "^6.0.1" - postcss-nested "^2.0.2" - postcss-nesting "^4.0.1" - postcss-partial-import "^4.1.0" - postcss-property-lookup "^1.2.1" - postcss-selector-matches "^3.0.1" - postcss-selector-not "^3.0.1" - prepend-http@^1.0.0: version "1.0.4" resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" @@ -5696,12 +5455,6 @@ progress-stream@^1.1.0: speedometer "~0.1.2" through2 "~0.2.3" -promise-each@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/promise-each/-/promise-each-2.2.0.tgz#3353174eff2694481037e04e01f77aa0fb6d1b60" - dependencies: - any-promise "^0.1.0" - promise@^7.1.1: version "7.3.1" resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" @@ -6176,6 +5929,20 @@ rc@^1.1.2, rc@^1.1.7: minimist "^1.2.0" strip-json-comments "~2.0.1" +react-copy-to-clipboard@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/react-copy-to-clipboard/-/react-copy-to-clipboard-5.0.1.tgz#8eae107bb400be73132ed3b6a7b4fb156090208e" + dependencies: + copy-to-clipboard "^3" + prop-types "^15.5.8" + +react-document-meta@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/react-document-meta/-/react-document-meta-2.1.2.tgz#891ccca08a416c3eefe015294cef56dad0f19d3f" + dependencies: + prop-types "^15.5.8" + react-side-effect "^1.1.0" + react-dom@^16.2.0: version "16.2.0" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.2.0.tgz#69003178601c0ca19b709b33a83369fe6124c044" @@ -6194,6 +5961,16 @@ react-lazy-load@^3.0.12: lodash.throttle "^4.0.0" prop-types "^15.5.8" +react-markdown@^3.1.4: + version "3.1.4" + resolved "https://registry.yarnpkg.com/react-markdown/-/react-markdown-3.1.4.tgz#4f37aa5ac4f78f64f93b41b12ad0c08e92eb1680" + dependencies: + prop-types "^15.6.0" + remark-parse "^4.0.0" + unified "^6.1.5" + unist-util-visit "^1.1.3" + xtend "^4.0.1" + react-redux@^5.0.6: version "5.0.6" resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-5.0.6.tgz#23ed3a4f986359d68b5212eaaa681e60d6574946" @@ -6205,18 +5982,21 @@ react-redux@^5.0.6: loose-envify "^1.1.0" prop-types "^15.5.10" +react-router-dom@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-4.2.2.tgz#c8a81df3adc58bba8a76782e946cbd4eae649b8d" + dependencies: + history "^4.7.2" + invariant "^2.2.2" + loose-envify "^1.3.1" + prop-types "^15.5.4" + react-router "^4.2.0" + warning "^3.0.0" + react-router-redux@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/react-router-redux/-/react-router-redux-4.0.8.tgz#227403596b5151e182377dab835b5d45f0f8054e" -react-router-scroll@^0.4.4: - version "0.4.4" - resolved "https://registry.yarnpkg.com/react-router-scroll/-/react-router-scroll-0.4.4.tgz#4d7b71c75b45ff296e4adca1e029a86e898a155d" - dependencies: - prop-types "^15.6.0" - scroll-behavior "^0.9.5" - warning "^3.0.0" - react-router@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/react-router/-/react-router-3.2.0.tgz#62b6279d589b70b34e265113e4c0a9261a02ed36" @@ -6229,6 +6009,25 @@ react-router@^3.0.0: prop-types "^15.5.6" warning "^3.0.0" +react-router@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/react-router/-/react-router-4.2.0.tgz#61f7b3e3770daeb24062dae3eedef1b054155986" + dependencies: + history "^4.7.2" + hoist-non-react-statics "^2.3.0" + invariant "^2.2.2" + loose-envify "^1.3.1" + path-to-regexp "^1.7.0" + prop-types "^15.5.4" + warning "^3.0.0" + +react-side-effect@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/react-side-effect/-/react-side-effect-1.1.3.tgz#512c25abe0dec172834c4001ec5c51e04d41bc5c" + dependencies: + exenv "^1.2.1" + shallowequal "^1.0.1" + react-slick@~0.15.4: version "0.15.4" resolved "https://registry.yarnpkg.com/react-slick/-/react-slick-0.15.4.tgz#6709c87b06e7640feeacc06711be42cc2066aabe" @@ -6241,11 +6040,14 @@ react-slick@~0.15.4: object-assign "^4.1.0" slick-carousel "^1.6.0" -read-cache@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774" +react@^16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/react/-/react-16.2.0.tgz#a31bd2dab89bff65d42134fa187f24d054c273ba" dependencies: - pify "^2.3.0" + fbjs "^0.8.16" + loose-envify "^1.1.0" + object-assign "^4.1.1" + prop-types "^15.6.0" read-pkg-up@^1.0.1: version "1.0.1" @@ -6345,7 +6147,7 @@ redent@^2.0.0: indent-string "^3.0.0" strip-indent "^2.0.0" -reduce-css-calc@^1.2.6, reduce-css-calc@^1.2.7: +reduce-css-calc@^1.2.6: version "1.3.0" resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz#747c914e049614a4c9cfbba629871ad1d2927716" dependencies: @@ -6353,14 +6155,7 @@ reduce-css-calc@^1.2.6, reduce-css-calc@^1.2.7: math-expression-evaluator "^1.2.14" reduce-function-call "^1.0.1" -reduce-css-calc@^2.0.0: - version "2.1.3" - resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-2.1.3.tgz#63c4c6325ffbbf4ea6c23f1d4deb47c3953f3b81" - dependencies: - css-unit-converter "^1.1.1" - postcss-value-parser "^3.3.0" - -reduce-function-call@^1.0.1, reduce-function-call@^1.0.2: +reduce-function-call@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/reduce-function-call/-/reduce-function-call-1.0.2.tgz#5a200bf92e0e37751752fe45b0ab330fd4b6be99" dependencies: @@ -6389,6 +6184,10 @@ regenerate@^1.2.1: version "1.3.3" resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.3.tgz#0c336d3980553d755c39b586ae3b20aa49c82b7f" +regenerator-runtime@^0.10.5: + version "0.10.5" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" + regenerator-runtime@^0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz#7e54fe5b5ccd5d6624ea6255c3473be090b802e1" @@ -6624,7 +6423,11 @@ resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" -resolve@^1.1.7, resolve@^1.3.2, resolve@^1.5.0: +resolve-pathname@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-2.2.0.tgz#7e9ae21ed815fd63ab189adeee64dc831eefa879" + +resolve@^1.3.2: version "1.5.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36" dependencies: @@ -6644,14 +6447,6 @@ restore-cursor@^2.0.0: onetime "^2.0.0" signal-exit "^3.0.2" -rgb-hex@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/rgb-hex/-/rgb-hex-2.1.0.tgz#c773c5fe2268a25578d92539a82a7a5ce53beda6" - -rgb@~0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/rgb/-/rgb-0.1.0.tgz#be27b291e8feffeac1bd99729721bfa40fc037b5" - right-align@^0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" @@ -6719,13 +6514,6 @@ schema-utils@^0.3.0: dependencies: ajv "^5.0.0" -scroll-behavior@^0.9.5: - version "0.9.5" - resolved "https://registry.yarnpkg.com/scroll-behavior/-/scroll-behavior-0.9.5.tgz#41da30b559da004eb48450f6cff6068c7696ff23" - dependencies: - dom-helpers "^3.2.1" - invariant "^2.2.2" - select-hose@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" @@ -6834,12 +6622,6 @@ signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" -simple-swizzle@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" - dependencies: - is-arrayish "^0.3.1" - single-line-log@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/single-line-log/-/single-line-log-1.1.2.tgz#c2f83f273a3e1a16edb0995661da0ed5ef033364" @@ -7190,7 +6972,7 @@ stylelint@^8.4.0: svg-tags "^1.0.0" table "^4.0.1" -sugarss@^1.0.0, sugarss@^1.0.1: +sugarss@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/sugarss/-/sugarss-1.0.1.tgz#be826d9003e0f247735f92365dc3fd7f1bae9e44" dependencies: @@ -7283,10 +7065,6 @@ tar@^2.2.1: fstream "^1.0.2" inherits "2" -tcomb@^2.5.1: - version "2.7.0" - resolved "https://registry.yarnpkg.com/tcomb/-/tcomb-2.7.0.tgz#10d62958041669a5d53567b9a4ee8cde22b1c2b0" - throttleit@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-0.0.2.tgz#cfedf88e60c00dd9697b61fdd2a8343a9b680eaf" @@ -7324,6 +7102,10 @@ to-fast-properties@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + to-integer-x@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/to-integer-x/-/to-integer-x-3.0.0.tgz#9f3b80e668c7f0ae45e6926b40d95f52c1addc74" @@ -7392,6 +7174,10 @@ to-string-x@^1.4.2: dependencies: is-symbol "^1.0.1" +toggle-selection@^1.0.3: + version "1.0.6" + resolved "https://registry.yarnpkg.com/toggle-selection/-/toggle-selection-1.0.6.tgz#6e45b1263f2017fa0acc7d89d78b15b8bf77da32" + toposort@^1.0.0: version "1.0.6" resolved "https://registry.yarnpkg.com/toposort/-/toposort-1.0.6.tgz#c31748e55d210effc00fdcdc7d6e68d7d7bb9cec" @@ -7578,7 +7364,7 @@ unherit@^1.0.4: inherits "^2.0.1" xtend "^4.0.1" -unified@^6.0.0: +unified@^6.0.0, unified@^6.1.5: version "6.1.6" resolved "https://registry.yarnpkg.com/unified/-/unified-6.1.6.tgz#5ea7f807a0898f1f8acdeefe5f25faa010cc42b1" dependencies: @@ -7630,19 +7416,12 @@ unist-util-stringify-position@^1.0.0, unist-util-stringify-position@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-1.1.1.tgz#3ccbdc53679eed6ecf3777dd7f5e3229c1b6aa3c" -unist-util-visit@^1.1.0: +unist-util-visit@^1.1.0, unist-util-visit@^1.1.3: version "1.3.0" resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-1.3.0.tgz#41ca7c82981fd1ce6c762aac397fc24e35711444" dependencies: unist-util-is "^2.1.1" -units-css@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/units-css/-/units-css-0.4.0.tgz#d6228653a51983d7c16ff28f8b9dc3b1ffed3a07" - dependencies: - isnumeric "^0.2.0" - viewport-dimensions "^0.2.0" - unload@^1.3.5: version "1.3.5" resolved "https://registry.yarnpkg.com/unload/-/unload-1.3.5.tgz#028b8a61dd5ef9b576a983c06e02776676523c4d" @@ -7729,6 +7508,10 @@ validate.io-undefined@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/validate.io-undefined/-/validate.io-undefined-1.0.3.tgz#7e27fcbb315b841e78243431897671929e20b7f4" +value-equal@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-0.4.0.tgz#c5bdd2f54ee093c04839d71ce2e4758a6890abc7" + vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" @@ -7764,10 +7547,6 @@ vfile@^2.0.0: unist-util-stringify-position "^1.0.0" vfile-message "^1.0.0" -viewport-dimensions@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/viewport-dimensions/-/viewport-dimensions-0.2.0.tgz#de740747db5387fd1725f5175e91bac76afdf36c" - vm-browserify@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73" From 5c5b4be7d84d8310716e48dc426b29421d977e76 Mon Sep 17 00:00:00 2001 From: wuxueqian Date: Mon, 1 Jan 2018 16:57:50 +0800 Subject: [PATCH 09/25] update --- package.json | 5 +- src/renderer/interface/IProfile.ts | 8 +- webpack/base.conf.babel.js | 5 +- webpack/prod.conf.babel.js | 39 +++++- yarn.lock | 211 ++++++++++++++++++++++------- 5 files changed, 208 insertions(+), 60 deletions(-) diff --git a/package.json b/package.json index 87731ec..17308bc 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ "build:dev": "rimraf dist && mkdirp dist && cross-env NODE_ENV=development npm run dll:dev && webpack --progress --hide-modules --config webpack/dev.conf.babel.js", "dev": "npm run build:dev && webpack-dev-server --config webpack/dev.conf.babel.js", "analyze": "cross-env ANALYZE_ENV=true npm run build", - "start": "electron .", + "start": "electron ./app", "pack": "npm run build && build --dir", "dist": "npm run build && build", "rebuild": "electron-rebuild", @@ -129,9 +129,10 @@ "blueimp-md5": "^2.10.0", "classnames": "^2.2.5", "electron": "^1.7.10", + "electron-rebuild": "^1.6.0", "github-api": "^3.0.0", "github-markdown-css": "^2.9.0", - "keytar": "^3.0.2", + "keytar": "^4.1.0", "moment": "^2.20.1", "pouchdb-adapter-idb": "6.1.2", "react": "^16.2.0", diff --git a/src/renderer/interface/IProfile.ts b/src/renderer/interface/IProfile.ts index 271a4ae..6b2bbc2 100644 --- a/src/renderer/interface/IProfile.ts +++ b/src/renderer/interface/IProfile.ts @@ -1,7 +1,4 @@ export default interface IProfile { - name: string; - avatar_url: string; - id: number; login: string; avatarUrl: string; @@ -19,7 +16,7 @@ export default interface IProfile { receivedEventsUrl: string; type: string; siteAdmin: boolean; - // name: string; + name: string; company: string; blog: string; location: string; @@ -38,4 +35,5 @@ export default interface IProfile { diskUsage: number; collaborators: number; twoFactorAuthentication: boolean; -} + avatar_url: string; +}; diff --git a/webpack/base.conf.babel.js b/webpack/base.conf.babel.js index f8246f4..3902b4d 100644 --- a/webpack/base.conf.babel.js +++ b/webpack/base.conf.babel.js @@ -7,6 +7,7 @@ import pkg from "../package.json"; const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin; const vendersConfig = require("../venders-config.json"); +const isDev = process.env.NODE_ENV !== "production"; const getPlugins = function(morePlugins) { let plugins = [ @@ -25,7 +26,9 @@ const getPlugins = function(morePlugins) { name: "app" }), new HtmlWebpackPlugin({ - filename: "../../app/dist/index.html", + filename: isDev + ? path.resolve(__dirname, "../dist/index.html") + : path.resolve(__dirname, "../app/dist/index.html"), template: "src/renderer/index.html", inject: true, minify: { diff --git a/webpack/prod.conf.babel.js b/webpack/prod.conf.babel.js index d7a317c..7e42bbf 100644 --- a/webpack/prod.conf.babel.js +++ b/webpack/prod.conf.babel.js @@ -74,8 +74,39 @@ const output = { chunkFilename: "js/[name].[chunkhash:8].chunk.js" }; -let config = baseConf(plugins, loaders); -config.entry = entry; -config.output = output; +let appConfig = baseConf(plugins, loaders); +appConfig.entry = entry; +appConfig.output = output; -export default config; +let electronProdConfig = { + node: { + __filename: false, + __dirname: false + }, + target: "electron-renderer", + entry: { + electron: ["babel-polyfill", "./src/main/index.js"] + }, + output: { + filename: "[name].js", // for Electron, the main entry name is fixed in package.json, hash should removed + chunkFilename: "[id].js", + path: path.resolve(__dirname, "../app/dist"), + publicPath: "./", + libraryTarget: "commonjs" // important for set externals // http://webpack.github.io/docs/configuration.html#externals + }, + resolve: { + extensions: [".js"] + }, + externals: ["keytar"], + module: { + rules: [ + { + test: /\.js$/, + loader: "babel-loader?presets[]=es2015", + exclude: /node_modules/ + } + ] + } +}; + +export default [appConfig, electronProdConfig]; diff --git a/yarn.lock b/yarn.lock index 886ead7..05fa708 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1288,7 +1288,7 @@ cli-cursor@^1.0.2: dependencies: restore-cursor "^1.0.1" -cli-cursor@^2.0.0: +cli-cursor@^2.0.0, cli-cursor@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" dependencies: @@ -1298,6 +1298,10 @@ cli-spinners@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-0.1.2.tgz#bb764d88e185fb9e1e6a2a1f19772318f605e31c" +cli-spinners@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-1.1.0.tgz#f1847b168844d917a671eb9d147e3df497c90d06" + cli-truncate@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-0.2.1.tgz#9f15cfbb0705005369216c626ac7d05ab90dd574" @@ -1390,7 +1394,7 @@ colormin@^1.0.5: css-color-names "0.0.4" has "^1.0.1" -colors@~1.1.2: +colors@^1.1.2, colors@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" @@ -1767,7 +1771,7 @@ debug@2.6.4: dependencies: ms "0.7.3" -debug@2.6.9, debug@^2.1.3, debug@^2.2.0, debug@^2.6.6, debug@^2.6.8: +debug@2.6.9, debug@^2.1.3, debug@^2.2.0, debug@^2.5.1, debug@^2.6.3, debug@^2.6.6, debug@^2.6.8: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" dependencies: @@ -2041,6 +2045,20 @@ electron-download@^3.0.1: semver "^5.3.0" sumchecker "^1.2.0" +electron-rebuild@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/electron-rebuild/-/electron-rebuild-1.6.0.tgz#e8d26f4d8e9fe5388df35864b3658e5cfd4dcb7e" + dependencies: + colors "^1.1.2" + debug "^2.6.3" + fs-extra "^3.0.1" + node-abi "^2.0.0" + node-gyp "^3.6.0" + ora "^1.2.0" + rimraf "^2.6.1" + spawn-rx "^2.0.10" + yargs "^7.0.2" + electron-releases@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/electron-releases/-/electron-releases-2.1.0.tgz#c5614bf811f176ce3c836e368a0625782341fd4e" @@ -2588,6 +2606,14 @@ fs-extra@^0.30.0: path-is-absolute "^1.0.0" rimraf "^2.2.8" +fs-extra@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-3.0.1.tgz#3794f378c58b342ea7dbbb23095109c4b3b62291" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^3.0.0" + universalify "^0.1.0" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -3594,6 +3620,12 @@ jsonfile@^2.1.0: optionalDependencies: graceful-fs "^4.1.6" +jsonfile@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-3.0.1.tgz#a5ecc6f65f53f662c4415c7675a0331d0992ec66" + optionalDependencies: + graceful-fs "^4.1.6" + jsonify@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" @@ -3611,11 +3643,11 @@ jsprim@^1.2.2: json-schema "0.2.3" verror "1.10.0" -keytar@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/keytar/-/keytar-3.0.2.tgz#4dc15dd3523fe30631f9d388578a40151a60586f" +keytar@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/keytar/-/keytar-4.1.0.tgz#9e3933e489d656de1a868e1293709313044989d7" dependencies: - nan "2.3.2" + nan "2.5.1" killable@^1.0.0: version "1.0.0" @@ -3881,6 +3913,10 @@ lodash.assign@^3.2.0: lodash._createassigner "^3.0.0" lodash.keys "^3.0.0" +lodash.assign@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" + lodash.camelcase@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" @@ -4307,9 +4343,9 @@ nan-x@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/nan-x/-/nan-x-1.0.0.tgz#0ee78e8d1cd0592d5b4260a5940154545c61c121" -nan@2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.3.2.tgz#4d4ecf17e1da4e989efb4f273d8d00201cad087e" +nan@2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.5.1.tgz#d5b01691253326a97a2bbee9e61c55d8d60351e2" nan@^2.3.0: version "2.8.0" @@ -4331,6 +4367,12 @@ no-case@^2.2.0: dependencies: lower-case "^1.1.1" +node-abi@^2.0.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.1.2.tgz#4da6caceb6685fcd31e7dd1994ef6bb7d0a9c0b2" + dependencies: + semver "^5.4.1" + node-fetch@^1.0.1: version "1.7.3" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" @@ -4342,6 +4384,24 @@ node-forge@0.6.33: version "0.6.33" resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.6.33.tgz#463811879f573d45155ad6a9f43dc296e8e85ebc" +node-gyp@^3.6.0: + version "3.6.2" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.6.2.tgz#9bfbe54562286284838e750eac05295853fa1c60" + dependencies: + fstream "^1.0.0" + glob "^7.0.3" + graceful-fs "^4.1.2" + minimatch "^3.0.2" + mkdirp "^0.5.0" + nopt "2 || 3" + npmlog "0 || 1 || 2 || 3 || 4" + osenv "0" + request "2" + rimraf "2" + semver "~5.3.0" + tar "^2.0.0" + which "1" + node-libs-browser@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.1.0.tgz#5f94263d404f6e44767d726901fff05478d600df" @@ -4386,6 +4446,12 @@ node-pre-gyp@^0.6.39: tar "^2.2.1" tar-pack "^3.4.0" +"nopt@2 || 3": + version "3.0.6" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" + dependencies: + abbrev "1" + nopt@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" @@ -4453,7 +4519,7 @@ npm-which@^3.0.1: npm-path "^2.0.2" which "^1.2.10" -npmlog@^4.0.2: +"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.2: version "4.1.2" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" dependencies: @@ -4592,6 +4658,15 @@ ora@^0.2.3: cli-spinners "^0.1.2" object-assign "^4.0.1" +ora@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/ora/-/ora-1.3.0.tgz#80078dd2b92a934af66a3ad72a5b910694ede51a" + dependencies: + chalk "^1.1.1" + cli-cursor "^2.1.0" + cli-spinners "^1.0.0" + log-symbols "^1.0.2" + original@>=0.0.5: version "1.0.0" resolved "https://registry.yarnpkg.com/original/-/original-1.0.0.tgz#9147f93fa1696d04be61e01bd50baeaca656bd3b" @@ -4628,7 +4703,7 @@ os-tmpdir@^1.0.0, os-tmpdir@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" -osenv@^0.1.4: +osenv@0, osenv@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644" dependencies: @@ -6322,6 +6397,33 @@ replace-ext@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.0.tgz#de63128373fcbf7c3ccfa4de5a480c45a67958eb" +request@2, request@^2.45.0: + version "2.83.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.83.0.tgz#ca0b65da02ed62935887808e6f510381034e3356" + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.6.0" + caseless "~0.12.0" + combined-stream "~1.0.5" + extend "~3.0.1" + forever-agent "~0.6.1" + form-data "~2.3.1" + har-validator "~5.0.3" + hawk "~6.0.2" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.17" + oauth-sign "~0.8.2" + performance-now "^2.1.0" + qs "~6.5.1" + safe-buffer "^5.1.1" + stringstream "~0.0.5" + tough-cookie "~2.3.3" + tunnel-agent "^0.6.0" + uuid "^3.1.0" + request@2.81.0: version "2.81.0" resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" @@ -6349,33 +6451,6 @@ request@2.81.0: tunnel-agent "^0.6.0" uuid "^3.0.0" -request@^2.45.0: - version "2.83.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.83.0.tgz#ca0b65da02ed62935887808e6f510381034e3356" - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.6.0" - caseless "~0.12.0" - combined-stream "~1.0.5" - extend "~3.0.1" - forever-agent "~0.6.1" - form-data "~2.3.1" - har-validator "~5.0.3" - hawk "~6.0.2" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.17" - oauth-sign "~0.8.2" - performance-now "^2.1.0" - qs "~6.5.1" - safe-buffer "^5.1.1" - stringstream "~0.0.5" - tough-cookie "~2.3.3" - tunnel-agent "^0.6.0" - uuid "^3.1.0" - require-coercible-to-string-x@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/require-coercible-to-string-x/-/require-coercible-to-string-x-1.0.0.tgz#367b3e9ca67e00324c411b0b498453a74cd5569e" @@ -6494,7 +6569,7 @@ rxdb@^6.0.1: unload "^1.3.5" url "^0.11.0" -rxjs@^5.4.2: +rxjs@^5.1.1, rxjs@^5.4.2: version "5.5.6" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.5.6.tgz#e31fb96d6fd2ff1fd84bcea8ae9c02d007179c02" dependencies: @@ -6524,10 +6599,14 @@ selfsigned@^1.9.1: dependencies: node-forge "0.6.33" -"semver@2 || 3 || 4 || 5", semver@^5.0.1, semver@^5.3.0: +"semver@2 || 3 || 4 || 5", semver@^5.0.1, semver@^5.3.0, semver@^5.4.1: version "5.4.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" +semver@~5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" + send@0.16.1: version "0.16.1" resolved "https://registry.yarnpkg.com/send/-/send-0.16.1.tgz#a70e1ca21d1382c11d0d9f6231deb281080d7ab3" @@ -6704,6 +6783,14 @@ spark-md5@3.0.0, spark-md5@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/spark-md5/-/spark-md5-3.0.0.tgz#3722227c54e2faf24b1dc6d933cc144e6f71bfef" +spawn-rx@^2.0.10: + version "2.0.12" + resolved "https://registry.yarnpkg.com/spawn-rx/-/spawn-rx-2.0.12.tgz#b6285294499426089beea0c3c1ec32d7fc57a376" + dependencies: + debug "^2.5.1" + lodash.assign "^4.2.0" + rxjs "^5.1.1" + spawn-sync@^1.0.15: version "1.0.15" resolved "https://registry.yarnpkg.com/spawn-sync/-/spawn-sync-1.0.15.tgz#b00799557eb7fb0c8376c29d44e8a1ea67e57476" @@ -7057,7 +7144,7 @@ tar-pack@^3.4.0: tar "^2.2.1" uid-number "^0.0.6" -tar@^2.2.1: +tar@^2.0.0, tar@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" dependencies: @@ -7422,6 +7509,10 @@ unist-util-visit@^1.1.0, unist-util-visit@^1.1.3: dependencies: unist-util-is "^2.1.1" +universalify@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.1.tgz#fa71badd4437af4c148841e3b3b165f9e9e590b7" + unload@^1.3.5: version "1.3.5" resolved "https://registry.yarnpkg.com/unload/-/unload-1.3.5.tgz#028b8a61dd5ef9b576a983c06e02776676523c4d" @@ -7702,15 +7793,15 @@ which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" -which@1.2.x: - version "1.2.14" - resolved "https://registry.yarnpkg.com/which/-/which-1.2.14.tgz#9a87c4378f03e827cecaf1acdf56c736c01c14e5" +which@1, which@^1.2.10, which@^1.2.9: + version "1.3.0" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a" dependencies: isexe "^2.0.0" -which@^1.2.10, which@^1.2.9: - version "1.3.0" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a" +which@1.2.x: + version "1.2.14" + resolved "https://registry.yarnpkg.com/which/-/which-1.2.14.tgz#9a87c4378f03e827cecaf1acdf56c736c01c14e5" dependencies: isexe "^2.0.0" @@ -7800,6 +7891,12 @@ yargs-parser@^4.2.0: dependencies: camelcase "^3.0.0" +yargs-parser@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0.tgz#275ecf0d7ffe05c77e64e7c86e4cd94bf0e1228a" + dependencies: + camelcase "^3.0.0" + yargs-parser@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-7.0.0.tgz#8d0ac42f16ea55debd332caf4c4038b3e3f5dfd9" @@ -7824,6 +7921,24 @@ yargs@^6.6.0: y18n "^3.2.1" yargs-parser "^4.2.0" +yargs@^7.0.2: + version "7.1.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.0.tgz#6ba318eb16961727f5d284f8ea003e8d6154d0c8" + dependencies: + camelcase "^3.0.0" + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + os-locale "^1.4.0" + read-pkg-up "^1.0.1" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^1.0.2" + which-module "^1.0.0" + y18n "^3.2.1" + yargs-parser "^5.0.0" + yargs@^8.0.2: version "8.0.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-8.0.2.tgz#6299a9055b1cefc969ff7e79c1d918dceb22c360" From 63126e1f7fe608b795e110f83d32f7edef4ef46e Mon Sep 17 00:00:00 2001 From: wuxueqian Date: Sat, 27 Jan 2018 17:35:20 +0800 Subject: [PATCH 10/25] prepare reconstruct whole project --- .babelrc | 12 +- .../2.0.12_0/_metadata/computed_hashes.json | 1 - .../2.0.12_0/_metadata/verified_contents.json | 1 - .../ReactDevTool/2.0.12_0/icons/icon128.png | Bin 3312 -> 0 bytes chrome/ReactDevTool/2.0.12_0/icons/icon48.png | Bin 3201 -> 0 bytes .../2.5.2_0/_metadata/computed_hashes.json | 1 + .../2.5.2_0/_metadata/verified_contents.json | 1 + .../{2.0.12_0 => 2.5.2_0}/build/backend.js | 1924 +- .../{2.0.12_0 => 2.5.2_0}/build/background.js | 24 +- .../build/contentScript.js | 2 +- .../{2.0.12_0 => 2.5.2_0}/build/inject.js | 54 +- .../{2.0.12_0 => 2.5.2_0}/build/main.js | 0 .../{2.0.12_0 => 2.5.2_0}/build/panel.js | 30372 +++++++++++----- .../2.5.2_0/icons/128-deadcode.png | Bin 0 -> 5201 bytes .../2.5.2_0/icons/128-development.png | Bin 0 -> 5201 bytes .../2.5.2_0/icons/128-disabled.png | Bin 0 -> 5853 bytes .../2.5.2_0/icons/128-outdated.png | Bin 0 -> 4162 bytes .../2.5.2_0/icons/128-production.png | Bin 0 -> 5325 bytes .../2.5.2_0/icons/128-unminified.png | Bin 0 -> 5201 bytes .../2.5.2_0/icons/16-deadcode.png | Bin 0 -> 638 bytes .../2.5.2_0/icons/16-development.png | Bin 0 -> 638 bytes .../2.5.2_0/icons/16-disabled.png | Bin 0 -> 522 bytes .../2.5.2_0/icons/16-outdated.png | Bin 0 -> 558 bytes .../2.5.2_0/icons/16-production.png | Bin 0 -> 594 bytes .../2.5.2_0/icons/16-unminified.png | Bin 0 -> 638 bytes .../2.5.2_0/icons/32-deadcode.png | Bin 0 -> 1318 bytes .../2.5.2_0/icons/32-development.png | Bin 0 -> 1318 bytes .../2.5.2_0/icons/32-disabled.png | Bin 0 -> 1269 bytes .../2.5.2_0/icons/32-outdated.png | Bin 0 -> 1095 bytes .../2.5.2_0/icons/32-production.png | Bin 0 -> 1301 bytes .../2.5.2_0/icons/32-unminified.png | Bin 0 -> 1318 bytes .../2.5.2_0/icons/48-deadcode.png | Bin 0 -> 2001 bytes .../2.5.2_0/icons/48-development.png | Bin 0 -> 2001 bytes .../2.5.2_0/icons/48-disabled.png | Bin 0 -> 1838 bytes .../2.5.2_0/icons/48-outdated.png | Bin 0 -> 1570 bytes .../2.5.2_0/icons/48-production.png | Bin 0 -> 2041 bytes .../2.5.2_0/icons/48-unminified.png | Bin 0 -> 2001 bytes .../ReactDevTool/2.5.2_0/icons/deadcode.svg | 1 + .../2.5.2_0/icons/development.svg | 1 + .../ReactDevTool/2.5.2_0/icons/disabled.svg | 1 + .../ReactDevTool/2.5.2_0/icons/outdated.svg | 1 + .../ReactDevTool/2.5.2_0/icons/production.svg | 1 + .../{2.0.12_0 => 2.5.2_0}/main.html | 1 + .../{2.0.12_0 => 2.5.2_0}/manifest.json | 19 +- .../{2.0.12_0 => 2.5.2_0}/panel.html | 11 +- .../ReactDevTool/2.5.2_0/popups/deadcode.html | 32 + .../2.5.2_0/popups/development.html | 28 + .../ReactDevTool/2.5.2_0/popups/disabled.html | 21 + .../ReactDevTool/2.5.2_0/popups/outdated.html | 29 + .../2.5.2_0/popups/production.html | 21 + chrome/ReactDevTool/2.5.2_0/popups/shared.js | 22 + .../2.5.2_0/popups/unminified.html | 31 + manifest.json | 2 +- package.json | 64 +- src/main/index.js | 7 +- src/main/windows/login.js | 23 +- src/main/windows/main.js | 12 +- src/main/windows/setting.js | 19 +- src/renderer/actions/accounts.ts | 78 - src/renderer/actions/categories.ts | 88 - src/renderer/actions/conditional.ts | 36 - src/renderer/actions/db.ts | 32 - src/renderer/actions/index.ts | 22 - src/renderer/actions/languages.ts | 29 - src/renderer/actions/network.ts | 38 - src/renderer/actions/profile.ts | 29 - src/renderer/actions/repo.ts | 490 - src/renderer/actions/repos.ts | 155 - src/renderer/components/app.tsx | 31 - src/renderer/components/filterBar.tsx | 96 - src/renderer/components/loginPage.tsx | 206 - src/renderer/components/mainDetailPane.tsx | 28 - src/renderer/components/mainGroupAvatar.tsx | 35 - src/renderer/components/mainGroupFooter.tsx | 141 - src/renderer/components/mainGroupNavs.tsx | 144 - src/renderer/components/mainGroupPane.tsx | 23 - src/renderer/components/mainListPane.tsx | 21 - src/renderer/components/mainPage.tsx | 50 - src/renderer/components/mainSearchBox.tsx | 119 - src/renderer/components/refreshIndicator.tsx | 59 - src/renderer/components/repoClassifyTool.tsx | 116 - .../components/repoContributorsBar.tsx | 42 - src/renderer/components/repoDetail.tsx | 45 - src/renderer/components/repoDetailToolbar.tsx | 101 - src/renderer/components/repoLinksTool.tsx | 88 - src/renderer/components/repoListItem.tsx | 105 - src/renderer/components/repoNoteTool.tsx | 78 - src/renderer/components/repoReadme.tsx | 89 - src/renderer/components/repoTagsBar.tsx | 131 - src/renderer/components/reposList.tsx | 29 - src/renderer/components/settingPage.tsx | 181 - src/renderer/components/sortBar.tsx | 102 - src/renderer/containers/app.tsx | 31 - src/renderer/containers/filterBar.tsx | 30 - src/renderer/containers/loginPage.tsx | 37 - src/renderer/containers/mainDetailPane.tsx | 14 - src/renderer/containers/mainGroupAvatar.tsx | 22 - src/renderer/containers/mainGroupFooter.tsx | 28 - src/renderer/containers/mainGroupNavs.tsx | 41 - src/renderer/containers/mainGroupPane.tsx | 14 - src/renderer/containers/mainListPane.tsx | 14 - src/renderer/containers/mainPage.tsx | 60 - src/renderer/containers/mainSearchBox.tsx | 33 - src/renderer/containers/refreshIndicator.tsx | 37 - src/renderer/containers/repoClassifyTool.tsx | 34 - .../containers/repoContributorsBar.tsx | 32 - src/renderer/containers/repoDetail.tsx | 22 - src/renderer/containers/repoDetailToolbar.tsx | 43 - src/renderer/containers/repoReadme.tsx | 28 - src/renderer/containers/repoTagsBar.tsx | 37 - src/renderer/containers/reposList.tsx | 34 - src/renderer/containers/settingPage.tsx | 40 - src/renderer/containers/sortBar.tsx | 33 - src/renderer/entries/Index.tsx | 17 + src/renderer/entries/Login.tsx | 17 + src/renderer/entries/Main.tsx | 17 + src/renderer/entries/NotFound.tsx | 17 + src/renderer/entries/Setting.tsx | 17 + src/renderer/index.html | 39 +- src/renderer/index.tsx | 27 +- src/renderer/interface/IAccount.ts | 11 - src/renderer/interface/IAction.ts | 5 - src/renderer/interface/IAuthor.ts | 21 - src/renderer/interface/ICategory.ts | 17 - src/renderer/interface/IConditional.ts | 20 - src/renderer/interface/ILanguage.ts | 7 - src/renderer/interface/IOffline.ts | 4 - src/renderer/interface/IProfile.ts | 39 - src/renderer/interface/IRepo.ts | 92 - src/renderer/interface/ISetting.ts | 4 - src/renderer/interface/IState.ts | 33 - src/renderer/interface/ITag.ts | 10 - src/renderer/reducers/accounts.ts | 50 - src/renderer/reducers/categories.ts | 37 - src/renderer/reducers/conditional.ts | 80 - src/renderer/reducers/db.ts | 14 - src/renderer/reducers/index.ts | 36 - src/renderer/reducers/languages.ts | 13 - src/renderer/reducers/network.ts | 25 - src/renderer/reducers/profile.ts | 13 - src/renderer/reducers/repo.ts | 37 - src/renderer/reducers/repos.ts | 55 - src/renderer/routes.tsx | 42 +- src/renderer/rxdb/database.ts | 124 - src/renderer/rxdb/dbExtension.ts | 57 - src/renderer/rxdb/dbHandler.ts | 821 - src/renderer/rxdb/schemas/authorSchema.ts | 74 - src/renderer/rxdb/schemas/categorySchema.ts | 42 - src/renderer/rxdb/schemas/languageSchema.ts | 30 - src/renderer/rxdb/schemas/meSchema.ts | 140 - src/renderer/rxdb/schemas/repoSchema.ts | 294 - src/renderer/rxdb/schemas/settingSchema.ts | 18 - src/renderer/rxdb/schemas/tagSchema.ts | 42 - src/renderer/store/configureDevStore.ts | 13 - src/renderer/store/configureProdStore.ts | 7 - src/renderer/store/configureStore.ts | 5 - src/renderer/utils/authentication.ts | 113 - src/renderer/utils/data.ts | 69 - src/renderer/utils/dbName.ts | 5 - src/renderer/utils/electronApp.ts | 10 - src/renderer/utils/githubClient.ts | 47 - src/renderer/utils/logHelper.ts | 10 - src/renderer/utils/offlineTitle.ts | 10 - tsconfig.json | 41 +- venders-config.json | 2 +- webpack/base.conf.babel.js | 7 +- webpack/dev.conf.babel.js | 9 +- webpack/dll.conf.babel.js | 16 +- webpack/main.conf.babel.js | 41 + webpack/prod.conf.babel.js | 50 +- yarn.lock | 1100 +- 171 files changed, 23312 insertions(+), 17161 deletions(-) delete mode 100644 chrome/ReactDevTool/2.0.12_0/_metadata/computed_hashes.json delete mode 100644 chrome/ReactDevTool/2.0.12_0/_metadata/verified_contents.json delete mode 100644 chrome/ReactDevTool/2.0.12_0/icons/icon128.png delete mode 100644 chrome/ReactDevTool/2.0.12_0/icons/icon48.png create mode 100644 chrome/ReactDevTool/2.5.2_0/_metadata/computed_hashes.json create mode 100644 chrome/ReactDevTool/2.5.2_0/_metadata/verified_contents.json rename chrome/ReactDevTool/{2.0.12_0 => 2.5.2_0}/build/backend.js (85%) rename chrome/ReactDevTool/{2.0.12_0 => 2.5.2_0}/build/background.js (62%) rename chrome/ReactDevTool/{2.0.12_0 => 2.5.2_0}/build/contentScript.js (92%) rename chrome/ReactDevTool/{2.0.12_0 => 2.5.2_0}/build/inject.js (62%) rename chrome/ReactDevTool/{2.0.12_0 => 2.5.2_0}/build/main.js (100%) rename chrome/ReactDevTool/{2.0.12_0 => 2.5.2_0}/build/panel.js (54%) create mode 100644 chrome/ReactDevTool/2.5.2_0/icons/128-deadcode.png create mode 100644 chrome/ReactDevTool/2.5.2_0/icons/128-development.png create mode 100644 chrome/ReactDevTool/2.5.2_0/icons/128-disabled.png create mode 100644 chrome/ReactDevTool/2.5.2_0/icons/128-outdated.png create mode 100644 chrome/ReactDevTool/2.5.2_0/icons/128-production.png create mode 100644 chrome/ReactDevTool/2.5.2_0/icons/128-unminified.png create mode 100644 chrome/ReactDevTool/2.5.2_0/icons/16-deadcode.png create mode 100644 chrome/ReactDevTool/2.5.2_0/icons/16-development.png create mode 100644 chrome/ReactDevTool/2.5.2_0/icons/16-disabled.png create mode 100644 chrome/ReactDevTool/2.5.2_0/icons/16-outdated.png create mode 100644 chrome/ReactDevTool/2.5.2_0/icons/16-production.png create mode 100644 chrome/ReactDevTool/2.5.2_0/icons/16-unminified.png create mode 100644 chrome/ReactDevTool/2.5.2_0/icons/32-deadcode.png create mode 100644 chrome/ReactDevTool/2.5.2_0/icons/32-development.png create mode 100644 chrome/ReactDevTool/2.5.2_0/icons/32-disabled.png create mode 100644 chrome/ReactDevTool/2.5.2_0/icons/32-outdated.png create mode 100644 chrome/ReactDevTool/2.5.2_0/icons/32-production.png create mode 100644 chrome/ReactDevTool/2.5.2_0/icons/32-unminified.png create mode 100644 chrome/ReactDevTool/2.5.2_0/icons/48-deadcode.png create mode 100644 chrome/ReactDevTool/2.5.2_0/icons/48-development.png create mode 100644 chrome/ReactDevTool/2.5.2_0/icons/48-disabled.png create mode 100644 chrome/ReactDevTool/2.5.2_0/icons/48-outdated.png create mode 100644 chrome/ReactDevTool/2.5.2_0/icons/48-production.png create mode 100644 chrome/ReactDevTool/2.5.2_0/icons/48-unminified.png create mode 100644 chrome/ReactDevTool/2.5.2_0/icons/deadcode.svg create mode 100644 chrome/ReactDevTool/2.5.2_0/icons/development.svg create mode 100644 chrome/ReactDevTool/2.5.2_0/icons/disabled.svg create mode 100644 chrome/ReactDevTool/2.5.2_0/icons/outdated.svg create mode 100644 chrome/ReactDevTool/2.5.2_0/icons/production.svg rename chrome/ReactDevTool/{2.0.12_0 => 2.5.2_0}/main.html (80%) rename chrome/ReactDevTool/{2.0.12_0 => 2.5.2_0}/manifest.json (70%) rename chrome/ReactDevTool/{2.0.12_0 => 2.5.2_0}/panel.html (96%) create mode 100644 chrome/ReactDevTool/2.5.2_0/popups/deadcode.html create mode 100644 chrome/ReactDevTool/2.5.2_0/popups/development.html create mode 100644 chrome/ReactDevTool/2.5.2_0/popups/disabled.html create mode 100644 chrome/ReactDevTool/2.5.2_0/popups/outdated.html create mode 100644 chrome/ReactDevTool/2.5.2_0/popups/production.html create mode 100644 chrome/ReactDevTool/2.5.2_0/popups/shared.js create mode 100644 chrome/ReactDevTool/2.5.2_0/popups/unminified.html delete mode 100644 src/renderer/actions/accounts.ts delete mode 100644 src/renderer/actions/categories.ts delete mode 100644 src/renderer/actions/conditional.ts delete mode 100644 src/renderer/actions/db.ts delete mode 100644 src/renderer/actions/index.ts delete mode 100644 src/renderer/actions/languages.ts delete mode 100644 src/renderer/actions/network.ts delete mode 100644 src/renderer/actions/profile.ts delete mode 100644 src/renderer/actions/repo.ts delete mode 100644 src/renderer/actions/repos.ts delete mode 100644 src/renderer/components/app.tsx delete mode 100644 src/renderer/components/filterBar.tsx delete mode 100644 src/renderer/components/loginPage.tsx delete mode 100644 src/renderer/components/mainDetailPane.tsx delete mode 100644 src/renderer/components/mainGroupAvatar.tsx delete mode 100644 src/renderer/components/mainGroupFooter.tsx delete mode 100644 src/renderer/components/mainGroupNavs.tsx delete mode 100644 src/renderer/components/mainGroupPane.tsx delete mode 100644 src/renderer/components/mainListPane.tsx delete mode 100644 src/renderer/components/mainPage.tsx delete mode 100644 src/renderer/components/mainSearchBox.tsx delete mode 100644 src/renderer/components/refreshIndicator.tsx delete mode 100644 src/renderer/components/repoClassifyTool.tsx delete mode 100644 src/renderer/components/repoContributorsBar.tsx delete mode 100644 src/renderer/components/repoDetail.tsx delete mode 100644 src/renderer/components/repoDetailToolbar.tsx delete mode 100644 src/renderer/components/repoLinksTool.tsx delete mode 100644 src/renderer/components/repoListItem.tsx delete mode 100644 src/renderer/components/repoNoteTool.tsx delete mode 100644 src/renderer/components/repoReadme.tsx delete mode 100644 src/renderer/components/repoTagsBar.tsx delete mode 100644 src/renderer/components/reposList.tsx delete mode 100644 src/renderer/components/settingPage.tsx delete mode 100644 src/renderer/components/sortBar.tsx delete mode 100644 src/renderer/containers/app.tsx delete mode 100644 src/renderer/containers/filterBar.tsx delete mode 100644 src/renderer/containers/loginPage.tsx delete mode 100644 src/renderer/containers/mainDetailPane.tsx delete mode 100644 src/renderer/containers/mainGroupAvatar.tsx delete mode 100644 src/renderer/containers/mainGroupFooter.tsx delete mode 100644 src/renderer/containers/mainGroupNavs.tsx delete mode 100644 src/renderer/containers/mainGroupPane.tsx delete mode 100644 src/renderer/containers/mainListPane.tsx delete mode 100644 src/renderer/containers/mainPage.tsx delete mode 100644 src/renderer/containers/mainSearchBox.tsx delete mode 100644 src/renderer/containers/refreshIndicator.tsx delete mode 100644 src/renderer/containers/repoClassifyTool.tsx delete mode 100644 src/renderer/containers/repoContributorsBar.tsx delete mode 100644 src/renderer/containers/repoDetail.tsx delete mode 100644 src/renderer/containers/repoDetailToolbar.tsx delete mode 100644 src/renderer/containers/repoReadme.tsx delete mode 100644 src/renderer/containers/repoTagsBar.tsx delete mode 100644 src/renderer/containers/reposList.tsx delete mode 100644 src/renderer/containers/settingPage.tsx delete mode 100644 src/renderer/containers/sortBar.tsx create mode 100644 src/renderer/entries/Index.tsx create mode 100644 src/renderer/entries/Login.tsx create mode 100644 src/renderer/entries/Main.tsx create mode 100644 src/renderer/entries/NotFound.tsx create mode 100644 src/renderer/entries/Setting.tsx delete mode 100644 src/renderer/interface/IAccount.ts delete mode 100644 src/renderer/interface/IAction.ts delete mode 100644 src/renderer/interface/IAuthor.ts delete mode 100644 src/renderer/interface/ICategory.ts delete mode 100644 src/renderer/interface/IConditional.ts delete mode 100644 src/renderer/interface/ILanguage.ts delete mode 100644 src/renderer/interface/IOffline.ts delete mode 100644 src/renderer/interface/IProfile.ts delete mode 100644 src/renderer/interface/IRepo.ts delete mode 100644 src/renderer/interface/ISetting.ts delete mode 100644 src/renderer/interface/IState.ts delete mode 100644 src/renderer/interface/ITag.ts delete mode 100644 src/renderer/reducers/accounts.ts delete mode 100644 src/renderer/reducers/categories.ts delete mode 100644 src/renderer/reducers/conditional.ts delete mode 100644 src/renderer/reducers/db.ts delete mode 100644 src/renderer/reducers/index.ts delete mode 100644 src/renderer/reducers/languages.ts delete mode 100644 src/renderer/reducers/network.ts delete mode 100644 src/renderer/reducers/profile.ts delete mode 100644 src/renderer/reducers/repo.ts delete mode 100644 src/renderer/reducers/repos.ts delete mode 100644 src/renderer/rxdb/database.ts delete mode 100644 src/renderer/rxdb/dbExtension.ts delete mode 100644 src/renderer/rxdb/dbHandler.ts delete mode 100644 src/renderer/rxdb/schemas/authorSchema.ts delete mode 100644 src/renderer/rxdb/schemas/categorySchema.ts delete mode 100644 src/renderer/rxdb/schemas/languageSchema.ts delete mode 100644 src/renderer/rxdb/schemas/meSchema.ts delete mode 100644 src/renderer/rxdb/schemas/repoSchema.ts delete mode 100644 src/renderer/rxdb/schemas/settingSchema.ts delete mode 100644 src/renderer/rxdb/schemas/tagSchema.ts delete mode 100644 src/renderer/store/configureDevStore.ts delete mode 100644 src/renderer/store/configureProdStore.ts delete mode 100644 src/renderer/store/configureStore.ts delete mode 100644 src/renderer/utils/authentication.ts delete mode 100644 src/renderer/utils/data.ts delete mode 100644 src/renderer/utils/dbName.ts delete mode 100644 src/renderer/utils/electronApp.ts delete mode 100644 src/renderer/utils/githubClient.ts delete mode 100644 src/renderer/utils/logHelper.ts delete mode 100644 src/renderer/utils/offlineTitle.ts create mode 100644 webpack/main.conf.babel.js diff --git a/.babelrc b/.babelrc index 2e35a68..95a7192 100644 --- a/.babelrc +++ b/.babelrc @@ -1,5 +1,15 @@ { - "presets": ["react", "es2015", "es2017"], + "presets": [ + "react", + [ + "env", + { + "targets": { + "browsers": ["chrome >= 58"] + } + } + ] + ], "plugins": [["import", { "libraryName": "antd", "style": true }]], "comments": false } diff --git a/chrome/ReactDevTool/2.0.12_0/_metadata/computed_hashes.json b/chrome/ReactDevTool/2.0.12_0/_metadata/computed_hashes.json deleted file mode 100644 index 9cca5b3..0000000 --- a/chrome/ReactDevTool/2.0.12_0/_metadata/computed_hashes.json +++ /dev/null @@ -1 +0,0 @@ -{"file_hashes":[{"block_hashes":["sviif16hMZ8f+0dAO8H9ZinltMYfSQr71PyTyOxj1kk=","s3Qw6hqmkGpYSjcFZJvZd8JEu9YJ7p3gGwvikEMutAg=","8mlVUWucxbAnWBySwJvm2jgHrJW3MSKnqzReW6pCxas=","7vdrEBxp+qShgNU8ZZoc0mOCqO9o9sopEytdsO/wi/4=","uqq/JehVp7LMmtOVWRdf+o2miNxXORURmPxHgFKooPY=","T37oVVOkGGdjHCYu9MB7KCwLA2+psApR5krA/+URfvo=","77mtkJ9NEAtZ2esmcUbT+xeRu7vPbNY4dKYmlU0ZmNs=","3sYgyi1OsmAvJAwb5uMKQhtd9TgVdk/nLj5PWpOmUbE=","1+8ZpncnWyJrqzYfA1JLq+cKNLelhXdKw85baNFLoAY=","KhBU4IhOWQLQMlnc7HNNJZ1FLeuCuWdICp0I4Bfaa0k=","/gsog0f/XKBqL2uXLu30hNsb8THFFf6BUtMpRGvd7ok=","XD23cW1/CumKN2YVcxh2881Bkg6SM8WuGeU8k7iV9XI=","krInVk2HPDpIMJpZ4gqdCcXEOF9q3QzsgMf5q/JPQx8=","6ZSq1UQuMmqVFX1hs1tben8g8yeOcEZimTOGSf7fGuE=","WuQVNkeQrjN026UxzgfjWIXI76JDLwGtlkME5g5Vf7A=","cEk6iJTWSsn/GjACUokROCpAl9SJGKAG+UyE7TvuU+8=","UXqu1XgW1XORcUXm217rau10SYgENyzTYkhCo4S+aig=","gnI1ks+w6/1naBEjNaYgwhr7FxuXrHCf3niM3R8jWVY=","nKoQsyFglYgtXu9HZuN4SydAtRA1ahsgVSYq9P3YebU=","l8Qxxz4Uq8sgQKbD28UmMhSssZyJlkAp+7Is4c0XjOs=","/FwcGh7me96Ln8XKfn6eU9P7NRLF/GaU5uI0D3q+UFM=","tgoEvZMw68wmfL1e6R+56WfysF+LvMsXpXDCVEoG5Ek=","uUuqxmyW5vLj0uO1fwE0diEtF86q973bhDglrNhWfQE=","9iC43t3fVvF/sL6RDIrXNW1wKrxdTBZCmZNuF0XBcVo=","Evl7wlVMup5Y220JGuP/AHQ7U4XH81Ws4k/NUEnuO/k=","kAffcKRLte3ysoLy+2CiCfbMQqZccFkZczwDsLTuZ3U=","fzZrwrTQCTJphnGLVqPY0GFECLTU6QMLOeBUsDYAu0U=","/ojxfrAplE0qucVTBe63iT9FIiczpuhujtOTHtX3svU=","z5oSfXSlem2g/7CBuw7IRiYmyIyGL4jvulKWIhwIM2s=","gf2hb9pdk8ow3jmcr0FOi0b1X6QTgKPR3ZDhvFcnj/M=","4AI6QFd3iWBscbhZnnHdNgWwOR/Z6Db2EaFPuZ2r5Sw=","KoAa7T0UIrmuVs19rtdD657k45aZUjPtbF1AWpgsJdQ=","i5Y0Fit389sUXnA5EGz0L858d5GrfMssHRT0wYHyZew=","huHiBkCSVisjcbCT9O40RqCbXtDCmdU6eSayn0QEv8Q=","Imjpj2Or1DdOrqHSBHo2/p+IzmfRIJB6r/4R0lfmX84=","xHn4APVCqC3gq91ljmCaHO73iGvN6wIvyrRDqFny2OE=","+FFDC+z5IuK4mX7TC7Mv0H7pUd6lkSPK3ehdbAzUwBg=","QAa/SopcvBcwAwDOtAlmqilu4rZOs2kFlmcoNrTrd7c=","5FSOQg5HzOQOWZHgvXoMmyoOBSERyettQgUZUYLWfD8=","/aIhR7ZR6DdRhIgbOE1oa45LjDxedzdL1p0fON3oClk=","DOJF93fcn3h8+bGfe85DMX3whDJjITOKnmNZM8C9HYw=","4QWRSKORXSwGrdv9C2zgjP/ZjKEbPtBLhSgZvIIGgKY=","dwaqM4Vnk6CKQ2he/HDm3wp24tQbBRokrVml8iSp+Qo=","yWzzOsPglfFkuvMFeh/oaBPVT07VCCNCisYiHF/2MgQ=","qjxNLKu1NXFT805qaP8BGruMMfB6SUrVrJTiygAsnaQ=","eLsDeljKywLamYfJ2Ui4Qf3KSUnhu6vrsPEYJuHQ36c=","XEc1+oXvy/xejOJq3uCh2R407jStDXFNIq90hOZSzP4=","Y214VN4v8LpZjuZrG4sstRr2remeP/sqzTLwAM9ZO3s=","Z2bY46sHOEA69wXFeAQV8yhi4w90GmOuHJI820LUqD0=","Yc7q08gLaceVvL3XSz1lLtcPZTY/t18KhdU77bd35AE=","+DQUXz3kg3TUlGZDTRkC2VBR6igsgYMSNQb+mvz7o2o=","MPc377wuX4QG1vthcj+78f0dgXndHJRzl88Uqd4pGrw=","8Z5t/KyBqZugj+PB4RHlLFtb1n0zO2YxrowYeKz6edg=","JW6cfZ9dcNPjSXcMzgMsFkfyMTA+QmZ1J+K34lCuqqA=","RWrbEPLd2O0zGqkuBNYPvMy4f4X8+HyBMB+FuVPtiIg=","FxlfBHfxNaBdrlBvpCfjqczSRTZA36HjpOFTgtsZQds=","74dUBeRSW67sfSUru9cJqrjrA6S1F6nk4zojJtNf5CE=","2X95A132L1GN4VS9Y8kuwg7LJmOjHDdF3Dh8uKb6Dsk=","Pz9GlLXXkgYTqw1Fp6ZvjYx8wItx0stsfInCdm+ShjU=","GMWRM+trdpm4Xs+HsgJiB2FgvRP26OgsmFDnoPLb70Y=","Ewi0QVBuCBFuvYPkBy2lPF+PE/9AhQDkHQg4rbOGF+E=","bT/GqdnAKu7c9PWzrIHz7L+2LnaGNlqPiI2u6/oE4+w=","CqTiPewEp/8G6Rr0j47wAxnzYe0VTXwjO+N0iC1zVHI=","egaVkAuKP3mqd0kYcqqp6tEmOaxtETZ3tc7NuOvfaic=","zs1l2uK4L6NFF1qQZ17UTOtwquY2V7bS/RbIYQST+cA=","hRuDT7LXgpT1XzORZxZ7FQDsnD9ZSuZoCSvlOMUza3A=","2qvETt8V3gaa+Lpw9O4wm7jiJ5h7LYRuoDhcK6c8I/E=","bpNznUjmK5qumB7WPR7nPIRvd+xQ3+T5clKxFKuYKvw=","W1VyObLtLTLz8LIJm2mmMx8IyJ4PSiPOmOQ8FhdilAk=","N3jjydxh+OPF/4nO482lZEKG5h0PAq4WOL/lgdDfFbs=","ONO76MCNAinPiq+1FNjMiVv+YVGC0Hq8daQnxJX4fp4=","VOt1QrxnvNz+CNuZVlRUIhe1otwLTy5DzavOwEYgdtc=","w+Yys9JhzwG1O+zGxXzgNNrz9C9Fcm9mHkphm5XOsKw=","AevEuepRhovsxkrgI4o3bmL69Bx3yGmJN38Ddg4ewew=","ao9bkedMn8b3NdWVjMJWT1jXw8o/71Rr63Ntb2gJacE="],"block_size":4096,"path":"build/backend.js"},{"block_hashes":["R21ABjrmW7qeIQZiPJr+4NtCwMAB30tblSkqEE2MUOA="],"block_size":4096,"path":"build/background.js"},{"block_hashes":["J3jAu+7DEWwRvMzo3kFAOb8Z2Px5hEtmmTnJv6q5c+k="],"block_size":4096,"path":"build/contentScript.js"},{"block_hashes":["YVHQeu7X4qe3HHWni5iN5RN6Ay7jFyCDeUVhgPvIq4Y=","ZjKIrybyFX6bVON3UYC6gJETDydCDFePV875a/sY4As="],"block_size":4096,"path":"build/inject.js"},{"block_hashes":["z+V57jiha3j3dD7OiUseoQtHfnw12EpUTXNTz/wpnDg="],"block_size":4096,"path":"build/main.js"},{"block_hashes":["BguO+RrNp3V2Gwib6VdjY6T0z+l4nHQ4MdvO4QXoioc=","mXCI7TUrtdnnbkIhTGe+kbDBhDsRyQZ0akBpFBdypWY=","J2/g2zdnC7RE3Ohg61r3DMhQx84iQ9A6xSW8VYBbZP4=","+oJthuB/iLSI1I0vEPXx2IIwILo8OCns3izhqnojyn8=","62TjFFKlSfPxOw00qFgemGlBbqVyNF50BUS3S+lp+7g=","cx60TXOwX9jI+gVD7feH7ftlzK5c65nwX12xzGrljUs=","j3N3UQP/gE4p1pRgniikWXhK+ed2g01UJBhoGC3LY8U=","iYszUPctnjHEaRv8tkSPJSW8ezyeMoS0z8C5fFAnCNs=","//kkF4RrC8WMQDPEt4l55BD5dsgi11PuQmgFMqfVHfA=","KFF44cMgPxkjTFMab8lnkuaPKJ78BaojHp4zjcaA6A8=","5AAmGkaPFCHgutmYpYve2WJjcTkIH8jy8FbUDXgND2M=","1NObAGI+VPn8aToVD83FsM/B/apxG9EEY8VZWfvMWGc=","HL5rcsUylnt6iKW5B+PPA208ydYg1kkJ83Km9HBhopA=","MpXuIoazwBGOd7LYmXvITwpk7iUIQYomgMNgoHeKnJI=","ERwnK3LhQ7FcQ3gGG1SZD+lalAK7ieNY3t6or0tj3vI=","E+JVgfaszAujUBGU7K/ugj1At+1TrQWRdzAnpjfi/r8=","zaypCvgzYAz3wEIz+AwdC9yPhwq9k56ia2LCn1FS7j4=","VHovkF3Qavvzs+zmo4aib7G5P1O6iWGBIcXozG9JMZ4=","NdePi/gJ/KrFVhXfYCKsd7tl8m1uhupDIVPwF5g/ua4=","WkLP/0NGmT0Gp80fxzi3UV+lk5IuvxUN6159O2tCo5E=","V4aI3CKbE3gD9tf3fqzNsv2Wzc9pCYxHvV7+EQmDQE0=","rGHV7z7rIbp2RL06H9npx7TPKG9nHfXZEaeebTsMhiE=","T92qRmqcjmA2oBRVCI7x7GpRrqtvzEtwOGqmQtmCEE4=","Lb41zrBREJXLiWDE62bY9/kIysRkEuXNPOmauGBgAUg=","QgbYiORdQMHRUalaFdEsFCCCyMTVvmONcBcCJZO0pso=","g7P2c50L0SAQTWY2uBhj6G4+kQLTVqIeVaBBjRViu1Y=","rAn6u7nZ38Iqxs9EXiqtn6Qcd3l6SxQ57llkGvRRZBM=","6QkuoRaVun9Lpz24KwxBQEK7m08rVNuktPWo2ASXaQY=","4osYAb1JArZiD1AixOH8tuiETBkgDRCb9sNt5XOIHaY=","I0sUv90rus6A+TrPt57HiI1ahkMSoGDJJgS35SYhLdc=","/IjC6wYAsM0wAF5oC6UjSSm1Xtl3Xqpb3745V9ExiCI=","94xYjsGUpeZzX1HCCisG7xDDNTJmKDNOiwNtfNgPRGE=","CXx73+sMgCImKLGXXfiGHTwzjUTNVc4L9kVl2ZEP2fw=","hGf35WeJzJkuRR+uvGRQQcnUvSqxl29UQ3QEvq/LxbI=","K7CfzOm3gJK/snvMsuzcklU6KgcFNW28r/bmkFgovO8=","EeRbaCoTH45tNLW12c3e/Q6YHPdGIEb6MAYxlZ6vNFU=","JogvD3sIiwSzmvZHm/6XOyQdWeUpltsaIV1lN8O+iS8=","uBFxlMmW8btJ6t3VG12SIRJKa3kyCnDo1knP32p+Yps=","r+UP5ISf/8m7vGXzENw9vlWi7WBy3tWkLzh5mMoZTms=","l3zuQcgT5EgzPpAIntwmHu6E7kZVRnyi7RL2UmFsBcs=","y8fHU/1golw98QxrjmBmFYSl/CfWsYaRPzjK3OAkXVI=","0/OccTM2x+Vmqra+02J2DXXaoUTmb7Wvwx9bHK59Ey4=","zuvR7pklOJ+BBAs/9nbRTVz8IxoTGHK9a/sp+qcuIjg=","+B3bu4luvp6C4xyQEpDB1TbWFKbRJ60OYPjqkefXCAg=","AkUZGnooUymzo3S0jH5aPtxon7gko1ePErdvfhHzVBw=","ev+3EiiOW/yHaMPT2uqmSEZrLklbBrGENnsrmGrpIjI=","Kbd4Zt5evnKL9lrj3Bz2n0vVFfoC2RlvrB2Gif8XYJI=","e+zTdT0wBoBt8V4NwyrsXgDKSWNbxEPZ7axE9fIlSEo=","hNiVDEJ78+2cl/7gOE/b0Cr75hc9ifXiK3huS/zaE4E=","TWG56jKCF5baq81fM/8JuGFIrLWAJbqzV5JC3QN2pqE=","YRX/kRldEF9FyBJEsz3ssh+g2OqCpR5KOEbYBtt52Qo=","TGkHM38T0kxQMO7DxEELTyZMC6516uXdwjUwKQOpLNk=","zJ0+kINRpxmizRdqCPPM0y4Y7enL2A4mtUANYBxau6o=","k1KuwJHyZjKvR7G6WXfcUGK0k6B8XGwAa88hnImr/0k=","d2s5yej0ZphJrhM5jzZ7CulYMo8w+2LhIlGk2SCmm/E=","JPmydiAWO+W5eVpp9RJmy8OhIaOfgNZAr9G5vV9/dCs=","r90C9vH40ZqSMPbLszOsahAl1IG1Jlvh3gVJTUUWTxI=","nmrC0MhUcjLSI9xjvnj0m+Dvt30h1boD1XgJNAiYQeo=","wLiPRbXTY13JEs7ggOoj82oK98r6mHlh6WshV/TU8PU=","lGesxDXg7N+eSG0nPMHuZsgcalxkYihPLOuoEv/zjZI=","f07q26964ZddoAIBcNaYkOrqqYFVJTHjf916SnqA3Yg=","ep9B3A0qQ4ACy8StNKDAq3fKFaTnqWWux+qw2Z0sTHg=","BoNtvyBWGd2VAsX7QgdKu2Wjsbo4R3gQ3OrEeapdSL8=","1+65pRl5XrSvqUiBB0lE702fSbVR4nDbzLcxvArdxNo=","bnA0rNLrMzlOnqiMFWJ5eqf5j9VlaPGoymEBYrBF7CM=","6Bne6mx1dt16pH5mwBKSz+jEPsF4Um10yUnOuZtuMVo=","wZ2H9/X6SGZLhbIOuTfD/7Tv+W7DEuLis8VWkaI9q/8=","/bklHh29Ij1IY5gIvQx7uqDI5bHUWvbHcthqUPF6msA=","6ELUmC2lDayr4upHYJeLuQOkqy1Rx9HLZOqVXGoSGc0=","171YWaD7jwxBtqJG7y9KqEdJbt0ucVndG3iY3TRmGqI=","ntNfF+IqLCJTHA9kWdJutK4vE5zbgDdRycEEqUDSGcc=","5Rrmr2ANEnQWt/ix0NMBY83z1FATT5YemceT7AxTt9o=","BqNIUnwe1RTd7rDUYzhJN6jl7Q0I1ibgYh/JQSZDWes=","8S50lYIauStywXdv9ek8mzSOoSw5D6wercDQeATyJl8=","S1w6hu7x4e+2OVNq9B7SlPjM26UZMhM6lA5Tg3NWmRw=","PKeTUAQgeGuqDIk9BPVzBL8Z0bjihU6L63PNRAVesro=","Wj/9Rud/nFGa24UnBeAR0JeijXy7Boy60mDLE9yLx00=","hu8/5izsWoEvi2wzFm74Bb4DSV2TMaDqlYoQEzrzn5Q=","hhVSFkG62e4dC5XIOJ4NE7mR/hiE4TPa62GISbZQVv8=","Iujki1+jg1O8m1s964GV93oXsh59DlV0yMP/V+E6pXI=","Ld1PXp7mq7h1vn/IryFvLkpXaOoDBXZlVCemi3qxuCc=","pA0CjpmKpUGE/h8jK+ba78m5YzP2B3YZo6JfaULZluo=","Podr8xBoiel4kREKmhIclWgo/Vb5pvtEZuIOn3u+o08=","Bd0Z0HXXicuHVxsHtztPmNLwckufXIk6pesf08bDgDU=","35hpUocFoiEA3z6hHkj1iXikT+2AXW1abzDB05uJSXQ=","z9owO4hQU9ZfFQtAnC4ebRpOsZBBXa1TV2Iuq69F4ws=","pcTsRE+3lTQ3d74rSTHjFOuFoQRtE0Lj7aIwVtGvB2g=","6R08duBFUqkc4liZ9kayyVkpmdV987YlkZFcIE50qfs=","CtnB4/L2CxwZ4wOpEezxD1IdfThEd/ajIMGCYZTrDh0=","auq5IMfMOKoonLF3AtwHGckjWfmccp4fMCwm3yw9pcQ=","20w8+obCHBRUfrObCq2ZtTQ9+Y9nroQtPcodAN9nQ2w=","scdXg8046G6LD2u3ZJHlGev82w/FcVYehR25aQjK6ic=","U/rG9xiTajqTBgxUckdiae89FDjUTANc3Co8V02O/Zs=","UYL6pMtvVokgWgAGcB8+hOVRXQYOHbyH9vkP4zF6158=","EZHwSxSTdAvrZMcyfAbs56/MO3JaYuvKaYE6cPqP/nU=","8gPA7xCeBnyrw16XZcsca/iMQAxZ7GOXU0sFtFsiH9Y=","p2Y9vVnJ1fjyKQIoidIcxsp2VGWOO1fnfVvTX2NgRS4=","EjfHeb8JFkXX0xAiECZICvIks/B3CGXIRPP3zAcMjUo=","kFbrlgHVnEV6LbH9cOqcIwB5OEV+vg/sWWWvQwuxmlU=","AoziyKHEPN1YOtvidPJh1lBtGhMmsfFYOPELY8U0F38=","tcOBOhG/pOnRSNjz6vwVV//A0Cfme/8OfpF4bDLvz9I=","wU0IVP8B1kydMoNZ21Dej/1iTGYXJ+CUKvugrmMOIIQ=","xRVQSFIBSL4dDGOomaYbZgUUR1JshCXU/3Wl1C1y7aA=","EH133dd5kgeiGd5sknxVMGximZXl7Kukt9jQTi/9kyU=","bNr9lGpgQJAOnzOKW46McyCARJkwsjaxYQkf4N3zSis=","m4X/DMzekIclCFKOPHq08NUn6jA0fw5UR8ZFLfMG4pA=","vLouS7WmP5jPvieqX1JEw9FadIdLnyw9bpbndvX4ts8=","OUz4BsqoL0jNja5XSJIwCmnCse5s1J4UqmjbPqcvXK8=","G+zCMvBuMlgUROBHlOY7RgkkrUHsvrlyeD/DkZlMCD4=","O6mBwouI+WM0mW5RuIynG0iFVIm0A9e5RU1SuFaHr+U=","pUczYflbW6mkfRqFGZ5ph3dzya/21PsboUJUSR8/Snc=","yI7GEu2nJtNQnR6UR6zRjY3hz5lKZanUwTRdeIrgBI4=","3u2AhjyR6GtfY9T+MxT0duhUOwwmEFfgxaKm1mWDCyo=","3qCszgs6YyvqSdefMrcxwuMgxMvDlw9yL5D8ceWhHjM=","X8Y7eFU4vuMTNmA4UhlmizyoI1D3v6HJQbR7vwbni5M=","zZhknjRnx7Fl4rFUVahVFZ/0kkq4XoBGRJhjuZzKxRo=","2ZPu8LCpXkNmvtKSc8IHzWgxjrFTmvW8RAF5mrdis/A=","LWU0qcAZT03SneB8EixjtQC6v3NJOPw/CSc3OOSJ0T8=","4dnfycY0smms2uBfwpII2vyWBkfTgsGE7mc9ANkjkws=","Hd5LJCP8HezKxVLobvQE/UlX/DcHz4eK21BiGjKT8c8=","76Q9KTGqdWhNXNTTTZv/uFAU1r5hnJtquZkTxHnBY/Y=","N0OTI6KUlQBU589HTDy3UGCBEvVqrqVgcfDC0qGDzj4=","QjmTw5xZkyw9H5LmxPIwUPHV7LWF9yI9cLJ6dQ+ciGY=","NbR5K9JzEYoCcjJnqX84ysuD56L+Qf89thql39csq98=","t9mYSvAMbhFUpzug0sLwdFm33Z1GzI3iS6cFMNDaVus=","W7IJUf3FEQpeGD8vIpMVew2S7VqSJo4E5eq5h0rgylg=","Zy2PnOwuWzRDxjex2NMAdV4kPWyxq1UAWdJnyCitMZ8=","ohhJ2n4ajPSfaG2Ay8u08mMCfu8K2sHA5C+9d8vA2Ec=","C8MRxI3Mf3oyHDVsvmC3zE9v8XTM6V8E89jqHrpEV8A=","/qdGTmtjVKoKORiGwHCeZX2mZeRKQ8xr6tgPiH9nBoc=","OvrD/KCpKpUi19N23ghhzXRR6CnRkAYFkNVnLrJHIcw=","rTNW9YrAzJV4RU5tgq4+z3whJJ1HqZJThvrq5ah0cpQ=","BWrvW2N6XaoxXZAcfjLQFx5IGw1/8LbcyF+hf+VfiWE=","7qTUUK2+rSDEqGbLBSiLuEjXgmFQQi79YvIoH6SDr9c=","m4sjv7hOATmu41f/PRq3++cdYSEADsk4rj1gbdXs7Lo=","O6T/7KiqO0m7zM4tC76WMCoA+dfCHwNh4Kx6rC5NI2I=","+UU1VdbJhKrfxrIT8xJPO3Rki0j4SR5HgtulUZeYeS4=","Ki3DZhrFfgleuiqsA/MJjYLplRL3F5JC9/A6ecsPiXA=","ON7t0gSOhXiRvFas14lJLR9f+CbUNQT/jM3DFD8OCVs=","3/7gdphB6k1D+tEAwXM2KZY0BljB3MO68XYX9R5fbVk=","PHqjHriBGoL8i++ULOKvWbSo7pvXS9gA/S0b8KfzCfA=","O2lGrbbrbO8vrOAoe5H/XRqTcocZwu0Nh9IiJAvLfew=","7N9isXFnai9eqUlXuFMuwdRRcp9OGq8IK7RKBw+dTyc=","bkxMRtYgF/G2iHtOPLwWJ3qcrdCxR1IvEirCSLjYPeM=","LSj60hAmAlmbAO4SOZdj5cg13tulTBmKI0Iz5IKkSO8=","qw5mI35KjCFlMshbrLXsXelfpRSn22m2jYhmXRPNsTo=","jQn0YkOvruCzhBV2qlNjaJYzK7EtUhIFG/LyZjYTbJQ=","b5wGfX7qCTq4TAa/+6ZEkYYcU7xqFHs8679dtQrtKtQ=","NktICQygUO66ZzkdWgtiyvpsFcC75pN5Nil/hA3kC44=","alqHBvf4f+qx3VsB6QS/lY230W54eY3H2SEt4qZjQg4=","AbnJcGPG7WwZUv7sikQaw9QwE78aGj9vHuHx7eJ4xII=","M+AQEFMseSBfBBZHPwfD5jkJsFTVFLE5HHKDZJl+f6c=","I4r7uMzeVQAwDXjwesTvEbsGBPys5kW5WORTEdYK96k=","c993veHxR3UKtTnsfOWuE3N8i1B/BwYtR9mh1PTs/5w=","dyBLMeW3THR38qrQlATSc1ssQfLUYbkvZGPt+QIkQgY=","rybEcpQGq9z/JUtTfEtwVFfHDxT3rvjwCcwkHN1VL/0=","nP1K7iddlRdkzcvy6DWvBrXRGF+PMPRvwIZttIAJFLY=","F92P2fLoA3Bg+XMq20BqRLS+F2pRe57aros+4yAbkjQ=","8J+gs0crtBv5UYECzKcly4GwzbExmO42mPPQBsaqb94=","IJa73pMaaYHS2r6hySCsNr00/7TcVjDeICk48MEBUJ0=","/zVdiVKPCjUDovy4F7pt8JNswpoJyi+EBn+blP//s0I=","qGJUbXHNjT+vwiSix9FnSrhcvewVLRA5CeQrc3362Nc=","qpbOAapf8jgsFNiYjWU6ZjbH253nP4+gZpg+/8664M8=","eDCLnwI+9f3eal42T+pTE0HBX3UoAqAg4VPXomeKa5M=","Ng9+gNJs70gBZkmelDIqIdScvFf/9qKHkYClBrG7juM=","wNHLv22uuZTGnh4shnWYE6PsYuG4cef/eVI4hDC4rzs=","357iEvXXOrm0CZRo5XdIyazHEzHQBtk+je8YfhBg1hE=","gHp4KhQL4mnS5AJBBNR5mtdU3zzO8x8Bxd+jG1luGc0=","q4wtbi0+tCMjV+lLsgE7KsKUsiPZUPcJVrigUWCWfwo=","iPNx9PlJi+HX0bFXZDSp8Pn9ohv2tV8LccmdJmGiWdI=","dEvsPJrBAxOE4RA1dnwWs6+rNFgpObYh9pfHwWWheqQ=","6ZucA24pGWE0yuLwkUYOyaXttxAM8iKSPkcpcAI5Z5Y=","z+R6bzqq47vDB4tcwZ25O/ONI4g6nmPLIJ4lymWOGP4=","o6rdWnI2JxDn4AgYv2uHiDEhr2GkrBRR+dHf/uOk8ZE=","1BOPMuGeju8bCceF+zh5jA1VGD1hLUVkryR94yQvf3I=","ADZeo9ot0oGGEyFCLSh5EHZp1Q+FPj69H9mmrlDaBmU=","WCsR1B4U67uHUVIDFN7moKX7mmtQdbFklLI5ar7droU=","xhQz1PaTMCDLg3Suzm97W3nAHM8+KHg20kdg9wUagqs=","uxn3uOI5E3ogAhNZg0zHtrP0qVwarbGApo0e47wK/YM=","9lncgyrWdf1RGeqUGBXnwKrQCca0sFsGw/44M0XcI8A="],"block_size":4096,"path":"build/panel.js"},{"block_hashes":["O5Bnq1RwRWKpgAe3xKw/qzoLetO+MTjQl9qKxbVz/ow="],"block_size":4096,"path":"main.html"},{"block_hashes":["fTLG1fs71dbK3kBdXDtfZiZcDw7l2ZGiyeS8gRqVq1Q="],"block_size":4096,"path":"panel.html"}],"version":2} \ No newline at end of file diff --git a/chrome/ReactDevTool/2.0.12_0/_metadata/verified_contents.json b/chrome/ReactDevTool/2.0.12_0/_metadata/verified_contents.json deleted file mode 100644 index 0d8bdb9..0000000 --- a/chrome/ReactDevTool/2.0.12_0/_metadata/verified_contents.json +++ /dev/null @@ -1 +0,0 @@ -[{"description":"treehash per file","signed_content":{"payload":"eyJjb250ZW50X2hhc2hlcyI6W3siYmxvY2tfc2l6ZSI6NDA5NiwiZGlnZXN0Ijoic2hhMjU2IiwiZmlsZXMiOlt7InBhdGgiOiJidWlsZC9iYWNrZW5kLmpzIiwicm9vdF9oYXNoIjoiS01QOEUtNHpaUXFVald1eUNEM1QwSl9SSlZ3dmg4QXU0SUp6QUJicnFwYyJ9LHsicGF0aCI6ImJ1aWxkL2JhY2tncm91bmQuanMiLCJyb290X2hhc2giOiJSMjFBQmpybVc3cWVJUVppUEpyLTROdEN3TUFCMzB0YmxTa3FFRTJNVU9BIn0seyJwYXRoIjoiYnVpbGQvY29udGVudFNjcmlwdC5qcyIsInJvb3RfaGFzaCI6IkozakF1LTdERVd3UnZNem8za0ZBT2I4WjJQeDVoRXRtbVRuSnY2cTVjLWsifSx7InBhdGgiOiJidWlsZC9pbmplY3QuanMiLCJyb290X2hhc2giOiJXS1NtTE1BVUpuUjlwLU5fbjdhcUlkTWpSeW5YNUNPeGNwT19BcW1EMGtJIn0seyJwYXRoIjoiYnVpbGQvbWFpbi5qcyIsInJvb3RfaGFzaCI6InotVjU3amloYTNqM2REN09pVXNlb1F0SGZudzEyRXBVVFhOVHpfd3BuRGcifSx7InBhdGgiOiJidWlsZC9wYW5lbC5qcyIsInJvb3RfaGFzaCI6IkFPSWhBb1B2ZjRyUy1rOTJoU3VBYmZJclFpa2I1TG1GcElpOWZ6RDRJRzQifSx7InBhdGgiOiJpY29ucy9pY29uMTI4LnBuZyIsInJvb3RfaGFzaCI6ImVaN2FyZEt5dHpNZW1MMGtMX3Fnb3JoU2VlNGpfTmFyMC1iZzR1Y1QwTWsifSx7InBhdGgiOiJpY29ucy9pY29uNDgucG5nIiwicm9vdF9oYXNoIjoibjdYX2xURkVZWl8ydzFVVUcwRkFOUXRQR2l5bU5KNzNPOW5uRUhVTXB3USJ9LHsicGF0aCI6Im1haW4uaHRtbCIsInJvb3RfaGFzaCI6Ik81Qm5xMVJ3UldLcGdBZTN4S3dfcXpvTGV0Ty1NVGpRbDlxS3hiVnpfb3cifSx7ImNhbm9uaWNhbF9qc29uX3Jvb3RfaGFzaCI6IjNGalY3RHh4UnV0TlBoZEhFUVpSYWwwbE93MTl0M2xGNi12YkRCVWJ2cFEiLCJwYXRoIjoibWFuaWZlc3QuanNvbiIsInJvb3RfaGFzaCI6InlBZDVVWHNLZmxYbkZpNzlYS00xTXpKZUg3Uk9DOGpleHYtLVFlQWo5MWcifSx7InBhdGgiOiJwYW5lbC5odG1sIiwicm9vdF9oYXNoIjoiZlRMRzFmczcxZGJLM2tCZFhEdGZaaVpjRHc3bDJaR2l5ZVM4Z1JxVnExUSJ9XSwiZm9ybWF0IjoidHJlZWhhc2giLCJoYXNoX2Jsb2NrX3NpemUiOjQwOTZ9XSwiaXRlbV9pZCI6ImZta2FkbWFwZ29mYWRvcGxqYmpma2FwZGtvaWVuaWhpIiwiaXRlbV92ZXJzaW9uIjoiMi4wLjEyIiwicHJvdG9jb2xfdmVyc2lvbiI6MX0","signatures":[{"header":{"kid":"publisher"},"protected":"eyJhbGciOiJSUzI1NiJ9","signature":"IbEsrUQljjRQhIGbjU8tbP0t8jb6sVNmxqJZbi-WapEOmozrMb9499__X3T-yRObM8eQe-qxwUDlABtYLG-CGdVM87V7rSQGEDojDeIRwjYyN-5CalfMX-MdKLzRo7ZShPDQnAlf8QHTeYqY7n3noi70yaQHdOYWlC1PJr7TuTMWcTXyavmejv2MET8bEpwKdSDOs3XVOitMronU3c08ccr9okZiWm99-ZznLXbh3DNlCdQGo9dAfjhX2VBOjwNBYGjDztFtduRfylRqnEb7o_F91W-Ak5qei_Z6qMz6qg8IQHIFa22DvvkL8vxGxch0TmVGqG_k9WZG46h00xz8xg"},{"header":{"kid":"webstore"},"protected":"eyJhbGciOiJSUzI1NiJ9","signature":"SIrQaR8xdUjQzVq8n-m9UOZ624BANEmuSpvj5kprIOWrP9eBnKXbYwIgbxBu5UNtykWfP-PPcoE30eZFGjH5KEYanou5ugFJpTeWBIadTlcIIweZsJYcK2XQMOzcJh9EAAMl1_wY4EXO95eUPLXzmgpyrto0LD-7y6Ec8WKB5zk8GDwm1kAEihkRpBZ4cygdfvfFg0swovq0ppm9qO9SljswA-Ur9V3VYdPvFCXSo48TxhrXVoHxVNbtZOp0MFREJHZKUozQoN8RJzfFwgo8ycZTsPYEWmnnRwY1_ZF0_ky3Nxkc_G3WaS_Y89mXybl6Jj_h2KnpHC-V-wONauz1Vg"}]}}] \ No newline at end of file diff --git a/chrome/ReactDevTool/2.0.12_0/icons/icon128.png b/chrome/ReactDevTool/2.0.12_0/icons/icon128.png deleted file mode 100644 index 6cea622f322559305a379f1985bb60e62e4d86b0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3312 zcmc&%`9G9vAAUweLL}Mu?PSTmlo)#rCwapVnInWmmr5Rp$;m8)fy^c6v8|R))Yi;ry z_Ua>*?Q0&;(aHaWQpXdUVs)wxgI@dH!(Ksb)lvi=)|~)6p6X#kFBHE{N`#y&=tl-)fjWtf`pE z{LeYhWB!xlMzgw?f@IU%hu?5sD_gBS-|8Ly{%rWqA6o3U^8<)wbyZ0veN1sZp^Rsd zT14B3AU#hqy|M^!{2Q+mFQ3gk4JpxW?;X|7uMh?R!KntV(b*x~o5G9`y-j`{oREV+ ziL2;U^v=xIjMY?Y=c>i~gz9`vZ#LddUhyk8hblf~@qil2?_U3_LnNdz<_5 z?uwhCqNt#;*<_M2t$VYK$l@F|^H&C(R8f=Cf8AL2mxGhTtU z;Qsst5(-dKDAK`I@(jBE;O}^dj*>5q#)`WCYiPVt<_wqbl)G$R#8KpnCsw2HL7`d=(ky?yjtcFM4Wpjrev|} zJMVjTpm{h%cXEud(X?9)JFh1^amtkbx$~VOfN}P<%ALH)iYhke^kF#X8A9a|Jts<% zW*nC=rPI@R{dx{Wkr0sPWE=L%ThCt^6Y<0_s`F-LVa88~T@#QzvE0+eW$|52{HZ(4 zssL2e>DqIq6i0Rdgg)Q>b0)8KoK-RBnL*ZjYpKCqQ{7je=$#gOW6Le^AW{>EA+qi3 zCN2-6WL43>EZz$ZD$6}8_gi?ECD&zW^e{>P>z3a+FqyK%tR@htx6W?>m4eG)NAxLz z26?}FXO!2?4vqUF4bUiT*|74zt_OlRetr5h#!k2~*+Ez^d+F55?I!Hmp$|gREn1%R zvoREyh#~d0IsLQ9DtGoc%D`U{*kq@raDcG0-^pKxRX)j{t%{$ zS{aB>5c60WI3c#KIFbV^2XLPkEoH2YFg6=nV9FUSkV(9{b60aO# z*pb0B$<%lIK0ycz^e@T^xwVY9adNb|geqL!_T-B(qDSeK8Tyx)EK!)cJk2>aYigL) zy6}4<+xETOk@lIcSySix;z09M0djac1sq;zYgK6T>D|5y#I~y%4(~Hp@_jK8v0)|A z_Hrtt9lt)6^qnli;`AX_rNQ8zmSN)~ACA}5@)goZjB8tIJVuZ#PR7w^KU4wQpl0n` ziXp}Z>7!H?2kNRo(sTU zab7R8UI6{)v;mFH@9z229|X|l-3rfiFEAu&kq6x#k5s2v21xj9V1q*A{5W1*1W-stlC8lx zf?aZ@~^)uE?=*U*<*8&PJerP#-hsMF|tf| zII&=v4JoJw=^uL}zev`3T&%#b46axg(Z_ij^^lD0*jX!ZUN9fL6P@p+R$!ioF1qdj z@Q~r(yijVSlgJd%jOJF3j&stAsrH)Y+cBJbE|+W1)vjS*K>%H>gy0$LA*3b?m_jG= znWtxaX1FkG4ao38Yc>-*7!6e3o=FHZZ7fn9bQ7o5t@J~Stz~aAt}fT{Y{Qu3RT>>9 zREY&T{d0SJa=`g>v#2eYzF=I)cJRHQsTVtlYaHib@5g1#kp|ex*!Z-LvTj+=iaYo9 zZ}{^@HGYWP%?@0S(%bBR(125)NZG3O5B@|hr_QBku?w} zRf}*#6`1G|Kx^0ofMXX#Yr6UQ@zoKLZ5A7_JuALp_K5Xsnf?3FsoQP{%SiRV?~9Dh zHiK&PQEQEi0o8SIPwEEuEk7bN7)fl9{8!S$&B9xgBslHP#xduw9Bh%8bY+^VNXeBV zuqrb}|-lUXE%w=+5>K!MC6TeXWaU1y`E3^>7|9BHGzSYcn*Td_= z(#a*X2U^~%ik5_Q-?B`I2mPw7wFOk&;tuh3Va7A35#RQpD0K^E_&YdlyZEkHfw6I9 zrOK$qI_hMIZMwqX;P>rLdlGyEw5-==`Ow&H^+ucfPJ>(mW%Ra|%swu;Q$h^z_!Krh zGA2nzu6`?38Jl)Z0mdcD{E?$?ScQsGN0njuZBJvGzpjd|{0O>`;M#cKW;DE#aMTor zd+|iQT;XxgKNLIGLHeeq*R4xlx`QQdcN_1(-8(Wq8Byp7FDo-@6r77hFmTM{TBp+`C=Xd*Gq)jxT!*EYfCNPeGeRqT9%*ndZ9!uH zrU465ji9~eg9_P#bNhRpCY2DAGd0pDWbS_fW37VapN<kD|l0Pm7v zVJEuy@}sMtjqWFN%SsC{GAlu+47_84&Kq0zKuIE*&&I~pDDN3XyN@^%emTW0DW5;W(T_@f30!5u5K;bR|J#DZ7^0L^?^FH(? zZ~X(hK>D%>kcTad!q@^SVmBzdTVw^h4eZ#mV=1y_i?J!nBtRRYzrXg`CV$2v{eK(qq9Px3fa%y+ZUa^FwJVY&{F02z z^8+f;Mcs99T(|AHr&E)a1KD#R2TaE%D65?A>t`esC9J5d7&^C$t7HwG8a7e28;PzR zj(E??mI=UcFv2VGL56}6)@_R?)e864@)(YFASd?afJ7H%%Vanh;oYfI^an!XT{@oR zLh1-}#T>J_47Z9oVt%bH8s4gx>n11SNzNrxq~pmQ^W=xCd^CT9tf3QAwLPN=(6ygK zY&tfYtnhyNEd7BH`C65mg)9I^V+lqhz2e)enXmbM_7RTjij_1S8(EV0;qW0Yq>hMh zm-P}0g_aJp}V{y+%Bw)klN1`qWTexJ=60uRLmo*sq~TK5VzaQl-Rvxxl$(ikXQt>3EXCK$wr_ZveDyyG!@yn9XHSB_FaR zp~(ui+aPP`e7^FC3#lVa#S(n+^a-}xK-rco4(tGcCM!f#KLC&PGJsI5NIn$Fhlavz zF2k~3W@h3zqmf>Ikvwx3BgcOy8 z)?7i|s_#gloH>$BPgpPV$fXCpsb=wJ|w!n%PIGEK$awGwvAz1!kFE}%i%vypJ6o8%d%c# zSuZgf>E-9?Gib7c;aIzl_jDV!Ma^zzt`~Ly*fk$}t0~ci?KZI725%oeCbHG9@7>_n z_ikX=7X5(`Zy!E}J5iVD?^-!CkY=v!(brX1}U~me;~B$yP%@B zRbzmBt;%X`o$+WN02Qm=nsY+{yiWKEIzR~zx6~Y)fUJ-T_mGY!nTYmvG%8=Kisy!H zajTeP-P-7Ad|2(~L_A4QQFn~(SLoOZ@Vp47<4KnF z694`5311dgC|l-^Z6!nds!zod{CND>j#d4`$}+FS2SxaA6>|W*JN>FCRa{x;QUaGhcJNxXNooqnwB*8IANZ8tLWy z@EDhu?lNC4v_(Vq_Lk$iyqTJ8JBXjJJmOmJF=eZH$N(;+j*yNg8H@B1QT-x9S2BwL z!uauMFNY#Apm|_3>wgrP zp@i?P%m*c^EDSzM|dMON!Dnl=w-b`!8GV^!4|`@ z_%yS~Z0;K_q$W9+ObHu*`|uw9S_t1O@4Wp%D%`_Qr%nlDF5RC)>gpn*bc<>z(S_ky zNL>=g`UZF@+(VCFBVViX&-dp9xVt$1GN%VdcI^LwK$xJSvQRGI_sM)yt&r{;WH=P% zrEm`b|NhN=me&LDt($+ zB<9x$%4*w*ciAK$E8JasO1@SV&uFgf=9*(O-PbQ1J{n69*rf;9TEsjXJ)0#!gymc^#kpjPyji90 zI&Dr!bWw9`P9}!hYQy>AF%f}+X|PmT+tq=k${GdJ0GbgvKRhPhjYfJonHZwx*gNK} zyAFA?D(u^8vlLaknJ*W_gPDmmKN=aQ=GdaA-Kx-QE$50kQAtlGhFG_oD|`9DS1jwL z9mX%~B`!bssE1eL*)pj)Ha}_=KyU8(a)GGY-K+xvS>ZQ}w}B>2 zGBc6p`vW6f$t4PvS$(&LrPBBPNQGZSgv8a*mF9mBEsr@Q~d4~Gvi6pR4P zed{q50E1eXw?>Zw@Vo3omi02}c#?EHNleu!Tc+sxreX=+NKJ~U&lPk0X7M(G7C!R5 z{@zbMP`Z578xCLOvvdK6d*bx?HBJwVFxk_`Ca|_qBOM>)Slr#AYfrgXE}%$0{63kQWAnFT(~L*^Sk_DY>%)6IHLD!& z8)&9wv&z~=jZ^)@{N4C8fBn(~J$?;nrT7PT=%NeF*UVNjJWExw>+or2k=w;p-e_Ta zuatW$=E@YII>;$Lb)Jl%iVa>jt*??2iEO6exEEjAH%jNnAMJxzKAUAB@$YQ zprQ)ysNQf0EB@#9108X%_hC?0ktIoN1!$ts-!6S6y0PBw08!P?P%t76xaXut#dv>v z+hVSmW5v*^SanJpHFT>^!8Euy{<7F!^@h{NvF_F*Kewe6#Y6Fn6!)ZB!EzfEOhbg$ z>)PHq`YPv=DGb}<()~Lk=O?rv?@pZ}sHn{5GJL#n6TeRuW4+%`sucji%x$${H`!NH zugMC7fhO`SZPdhmjHyk`6jL?Ail0v&&9khR=nsULnK+KsYSw2aj?*6qv8Gc%E9G}0@gQfsl! zTgM(`&I3E(xGn)j5&PG}GMyx*YGe()NvYJHmHvFKNv(Li|8C;x4k{`EMfty{7NN;; z&X)^ff?_B4@JJ*F1@2Af)9E^}Rt2^k$?aW-=b@pT0-VP{|kD6nP zM&kVNm;hWJt>~9zE{;v}%TqrP2=l``*O@ODxK+&Y;hpOOx&HFh54bosjbD=6bi`Cm zz-y10+v{=z!1q`0{p5qaKHA*eWZkwnnHVD0tJ-hPt72tEF8LW;`Yq$U`P_F>o-pFCQi z-f;Hiz`ic|yj#ktSVE9k+r`5{UIE&k$IVvPc6wk$;Gyl}k;3!k!gqU1>EV!ywZU*O z(nhK1R-O5BfiDXy&!qsjQ~2fvrXuj)mnmh^pO! z#PZ<4b|zyl9o|KsM;7c?$5uJeO}$rfWmgh+zurxw_kO=RG@do^W-BU+{ n?`HBvW$R7nx0OHp|5o`E used to "make a value available in the console" function Agent(global, capabilities) { _classCallCheck(this, Agent); var _this = _possibleConstructorReturn(this, (Agent.__proto__ || Object.getPrototypeOf(Agent)).call(this)); _this.global = global; - _this.reactElements = new Map(); - _this.ids = new WeakMap(); + _this.internalInstancesById = new Map(); + _this.idsByInternalInstances = new WeakMap(); _this.renderers = new Map(); _this.elementData = new Map(); _this.roots = new Set(); @@ -260,14 +256,15 @@ if (isReactDOM) { _this._updateScroll = _this._updateScroll.bind(_this); window.addEventListener('scroll', _this._onScroll.bind(_this), true); + window.addEventListener('click', _this._onClick.bind(_this), true); + window.addEventListener('mouseover', _this._onMouseOver.bind(_this), true); + window.addEventListener('resize', _this._onResize.bind(_this), true); } return _this; } // returns an "unsubscribe" function - // the window or global -> used to "make a value available in the console" - _createClass(Agent, [{ key: 'sub', @@ -317,6 +314,10 @@ bridge.on('selected', function (id) { return _this3.emit('selected', id); }); + bridge.on('setInspectEnabled', function (enabled) { + _this3._inspectEnabled = enabled; + _this3.emit('stopInspecting'); + }); bridge.on('shutdown', function () { return _this3.emit('shutdown'); }); @@ -337,6 +338,11 @@ // used to "view source in Sources pane" bridge.on('putSelectedInstance', function (id) { var node = _this3.elementData.get(id); + if (node) { + window.__REACT_DEVTOOLS_GLOBAL_HOOK__.$type = node.type; + } else { + window.__REACT_DEVTOOLS_GLOBAL_HOOK__.$type = null; + } if (node && node.publicInstance) { window.__REACT_DEVTOOLS_GLOBAL_HOOK__.$inst = node.publicInstance; } else { @@ -357,8 +363,8 @@ bridge.on('scrollToNode', function (id) { return _this3.scrollToNode(id); }); - bridge.on('bananaslugchange', function (value) { - return _this3.emit('bananaslugchange', value); + bridge.on('traceupdatesstatechange', function (value) { + return _this3.emit('traceupdatesstatechange', value); }); bridge.on('colorizerchange', function (value) { return _this3.emit('colorizerchange', value); @@ -383,6 +389,9 @@ this.on('setSelection', function (data) { return bridge.send('select', data); }); + this.on('setInspectEnabled', function (data) { + return bridge.send('setInspectEnabled', data); + }); } }, { key: 'scrollToNode', @@ -392,16 +401,16 @@ console.warn('unable to get the node for scrolling'); return; } - var element = node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement; - if (!element) { - console.warn('unable to get the element for scrolling'); + var domElement = node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement; + if (!domElement) { + console.warn('unable to get the domElement for scrolling'); return; } - if (typeof element.scrollIntoViewIfNeeded === 'function') { - element.scrollIntoViewIfNeeded(); - } else if (typeof element.scrollIntoView === 'function') { - element.scrollIntoView(); + if (typeof domElement.scrollIntoViewIfNeeded === 'function') { + domElement.scrollIntoViewIfNeeded(); + } else if (typeof domElement.scrollIntoView === 'function') { + domElement.scrollIntoView(); } this.highlight(id); } @@ -433,7 +442,7 @@ }, { key: 'getNodeForID', value: function getNodeForID(id) { - var component = this.reactElements.get(id); + var component = this.internalInstancesById.get(id); if (!component) { return null; } @@ -446,12 +455,20 @@ }, { key: 'selectFromDOMNode', value: function selectFromDOMNode(node, quiet) { + var offsetFromLeaf = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0; + var id = this.getIDForNode(node); if (!id) { return; } - this.emit('setSelection', { id: id, quiet: quiet }); + this.emit('setSelection', { id: id, quiet: quiet, offsetFromLeaf: offsetFromLeaf }); } + + // TODO: remove this method because it's breaking encapsulation. + // It was used by RN inspector but this required leaking Fibers to it. + // RN inspector will use selectFromDOMNode() instead now. + // Remove this method in a few months after this comment was added. + }, { key: 'selectFromReactInstance', value: function selectFromReactInstance(instance, quiet) { @@ -520,7 +537,7 @@ if (data && data.updater && data.updater.setInContext) { data.updater.setInContext(path, value); } else { - console.warn("trying to set state on a component that doesn't support it"); + console.warn("trying to set context on a component that doesn't support it"); } } }, { @@ -544,20 +561,20 @@ } }, { key: 'getId', - value: function getId(element) { - if ((typeof element === 'undefined' ? 'undefined' : _typeof(element)) !== 'object' || !element) { - return element; + value: function getId(internalInstance) { + if ((typeof internalInstance === 'undefined' ? 'undefined' : _typeof(internalInstance)) !== 'object' || !internalInstance) { + return internalInstance; } - if (!this.ids.has(element)) { - this.ids.set(element, guid()); - this.reactElements.set(this.ids.get(element), element); + if (!this.idsByInternalInstances.has(internalInstance)) { + this.idsByInternalInstances.set(internalInstance, guid()); + this.internalInstancesById.set(this.idsByInternalInstances.get(internalInstance), internalInstance); } - return this.ids.get(element); + return this.idsByInternalInstances.get(internalInstance); } }, { key: 'addRoot', - value: function addRoot(renderer, element) { - var id = this.getId(element); + value: function addRoot(renderer, internalInstance) { + var id = this.getId(internalInstance); this.roots.add(id); this.emit('root', id); } @@ -610,7 +627,7 @@ this.roots.delete(id); this.renderers.delete(id); this.emit('unmount', id); - this.ids.delete(component); + this.idsByInternalInstances.delete(component); } }, { key: '_onScroll', @@ -624,19 +641,49 @@ key: '_updateScroll', value: function _updateScroll() { this.emit('refreshMultiOverlay'); + this.emit('stopInspecting'); this._scrollUpdate = false; } + }, { + key: '_onClick', + value: function _onClick(event) { + if (!this._inspectEnabled) { + return; + } + + var id = this.getIDForNode(event.target); + if (!id) { + return; + } + + event.stopPropagation(); + event.preventDefault(); + + this.emit('setSelection', { id: id }); + this.emit('setInspectEnabled', false); + } + }, { + key: '_onMouseOver', + value: function _onMouseOver(event) { + if (this._inspectEnabled) { + var id = this.getIDForNode(event.target); + if (!id) { + return; + } + + this.highlight(id); + } + } + }, { + key: '_onResize', + value: function _onResize(event) { + this.emit('stopInspecting'); + } }]); return Agent; }(EventEmitter); - function getIn(base, path) { - return path.reduce(function (obj, attr) { - return obj ? obj[attr] : null; - }, base); - } - module.exports = Agent; /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(2), __webpack_require__(3), __webpack_require__(4), __webpack_require__(5))) @@ -1086,6 +1133,48 @@ /***/ }, /* 9 */ +/***/ function(module, exports) { + + 'use strict'; + + function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } + + /** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + + /** + * Retrieves the value from the path of nested objects + * @param {Object} base Base or root object for path + * @param {Array} path nested path + * @return {any} Value at end of path or `mull` + */ + function getIn(base, path) { + return path.reduce(function (obj, attr) { + if (obj) { + if (obj.hasOwnProperty(attr)) { + return obj[attr]; + } + if (typeof obj[Symbol.iterator] === 'function') { + // Convert iterable to array and return array[index] + return [].concat(_toConsumableArray(obj))[attr]; + } + } + + return null; + }, base); + } + + module.exports = getIn; + +/***/ }, +/* 10 */ /***/ function(module, exports, __webpack_require__) { /** @@ -1105,32 +1194,32 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - var BananaSlugAbstractNodeMeasurer = __webpack_require__(10); - var BananaSlugAbstractNodePresenter = __webpack_require__(15); - var BananaSlugWebNodeMeasurer = __webpack_require__(16); - var BananaSlugWebNodePresenter = __webpack_require__(17); + var TraceUpdatesAbstractNodeMeasurer = __webpack_require__(11); + var TraceUpdatesAbstractNodePresenter = __webpack_require__(16); + var TraceUpdatesWebNodeMeasurer = __webpack_require__(17); + var TraceUpdatesWebNodePresenter = __webpack_require__(18); var NODE_TYPE_COMPOSITE = 'Composite'; - var BananaSlugBackendManager = function () { - function BananaSlugBackendManager(agent) { - _classCallCheck(this, BananaSlugBackendManager); + var TraceUpdatesBackendManager = function () { + function TraceUpdatesBackendManager(agent) { + _classCallCheck(this, TraceUpdatesBackendManager); this._onMeasureNode = this._onMeasureNode.bind(this); var useDOM = agent.capabilities.dom; - this._measurer = useDOM ? new BananaSlugWebNodeMeasurer() : new BananaSlugAbstractNodeMeasurer(); + this._measurer = useDOM ? new TraceUpdatesWebNodeMeasurer() : new TraceUpdatesAbstractNodeMeasurer(); - this._presenter = useDOM ? new BananaSlugWebNodePresenter() : new BananaSlugAbstractNodePresenter(); + this._presenter = useDOM ? new TraceUpdatesWebNodePresenter() : new TraceUpdatesAbstractNodePresenter(); this._isActive = false; - agent.on('bananaslugchange', this._onBananaSlugChange.bind(this)); + agent.on('traceupdatesstatechange', this._onTraceUpdatesStateChange.bind(this)); agent.on('update', this._onUpdate.bind(this, agent)); agent.on('shutdown', this._shutdown.bind(this)); } - _createClass(BananaSlugBackendManager, [{ + _createClass(TraceUpdatesBackendManager, [{ key: '_onUpdate', value: function _onUpdate(agent, obj) { if (!this._isActive || !obj.publicInstance || !obj.id || obj.nodeType !== NODE_TYPE_COMPOSITE) { @@ -1150,8 +1239,8 @@ this._presenter.present(measurement); } }, { - key: '_onBananaSlugChange', - value: function _onBananaSlugChange(state) { + key: '_onTraceUpdatesStateChange', + value: function _onTraceUpdatesStateChange(state) { this._isActive = state.enabled; this._presenter.setEnabled(state.enabled); } @@ -1163,11 +1252,11 @@ } }]); - return BananaSlugBackendManager; + return TraceUpdatesBackendManager; }(); function init(agent) { - return new BananaSlugBackendManager(agent); + return new TraceUpdatesBackendManager(agent); } module.exports = { @@ -1175,7 +1264,7 @@ }; /***/ }, -/* 10 */ +/* 11 */ /***/ function(module, exports, __webpack_require__) { /** @@ -1198,8 +1287,8 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - var requestAnimationFrame = __webpack_require__(11); - var immutable = __webpack_require__(14); + var requestAnimationFrame = __webpack_require__(12); + var immutable = __webpack_require__(15); // How long the measurement can be cached in ms. var DURATION = 800; @@ -1224,9 +1313,9 @@ var _id = 100; - var BananaSlugAbstractNodeMeasurer = function () { - function BananaSlugAbstractNodeMeasurer() { - _classCallCheck(this, BananaSlugAbstractNodeMeasurer); + var TraceUpdatesAbstractNodeMeasurer = function () { + function TraceUpdatesAbstractNodeMeasurer() { + _classCallCheck(this, TraceUpdatesAbstractNodeMeasurer); // pending nodes to measure. this._nodes = new Map(); @@ -1246,7 +1335,7 @@ this._measureNodes = this._measureNodes.bind(this); } - _createClass(BananaSlugAbstractNodeMeasurer, [{ + _createClass(TraceUpdatesAbstractNodeMeasurer, [{ key: 'request', value: function request(node, callback) { var requestID = this._nodes.has(node) ? this._nodes.get(node) : String(_id++); @@ -1416,13 +1505,13 @@ } }]); - return BananaSlugAbstractNodeMeasurer; + return TraceUpdatesAbstractNodeMeasurer; }(); - module.exports = BananaSlugAbstractNodeMeasurer; + module.exports = TraceUpdatesAbstractNodeMeasurer; /***/ }, -/* 11 */ +/* 12 */ /***/ function(module, exports, __webpack_require__) { /* WEBPACK VAR INJECTION */(function(global) {/** @@ -1438,8 +1527,8 @@ 'use strict'; - var emptyFunction = __webpack_require__(12); - var nativeRequestAnimationFrame = __webpack_require__(13); + var emptyFunction = __webpack_require__(13); + var nativeRequestAnimationFrame = __webpack_require__(14); var lastTime = 0; @@ -1459,7 +1548,7 @@ /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) /***/ }, -/* 12 */ +/* 13 */ /***/ function(module, exports) { /** @@ -1502,7 +1591,7 @@ module.exports = emptyFunction; /***/ }, -/* 13 */ +/* 14 */ /***/ function(module, exports) { /* WEBPACK VAR INJECTION */(function(global) {/** @@ -1524,7 +1613,7 @@ /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) /***/ }, -/* 14 */ +/* 15 */ /***/ function(module, exports, __webpack_require__) { /* WEBPACK VAR INJECTION */(function(__webpack_provided_Object_dot_create, WeakMap, Map, Set) {/** @@ -6512,7 +6601,7 @@ /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(2), __webpack_require__(4), __webpack_require__(3), __webpack_require__(5))) /***/ }, -/* 15 */ +/* 16 */ /***/ function(module, exports, __webpack_require__) { /** @@ -6533,8 +6622,8 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - var immutable = __webpack_require__(14); - var requestAnimationFrame = __webpack_require__(11); + var immutable = __webpack_require__(15); + var requestAnimationFrame = __webpack_require__(12); // How long the measurement should be presented for. var DURATION = 250; @@ -6548,9 +6637,9 @@ hit: 0 }); - var BananaSlugAbstractNodePresenter = function () { - function BananaSlugAbstractNodePresenter() { - _classCallCheck(this, BananaSlugAbstractNodePresenter); + var TraceUpdatesAbstractNodePresenter = function () { + function TraceUpdatesAbstractNodePresenter() { + _classCallCheck(this, TraceUpdatesAbstractNodePresenter); this._pool = new Map(); this._drawing = false; @@ -6561,7 +6650,7 @@ this._redraw = this._redraw.bind(this); } - _createClass(BananaSlugAbstractNodePresenter, [{ + _createClass(TraceUpdatesAbstractNodePresenter, [{ key: 'present', value: function present(measurement) { if (!this._enabled) { @@ -6686,13 +6775,13 @@ } }]); - return BananaSlugAbstractNodePresenter; + return TraceUpdatesAbstractNodePresenter; }(); - module.exports = BananaSlugAbstractNodePresenter; + module.exports = TraceUpdatesAbstractNodePresenter; /***/ }, -/* 16 */ +/* 17 */ /***/ function(module, exports, __webpack_require__) { /* WEBPACK VAR INJECTION */(function(__webpack_provided_Object_dot_create) {/** @@ -6716,7 +6805,7 @@ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = __webpack_provided_Object_dot_create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - var BananaSlugAbstractNodeMeasurer = __webpack_require__(10); + var TraceUpdatesAbstractNodeMeasurer = __webpack_require__(11); var DUMMY = { bottom: 0, @@ -6731,16 +6820,16 @@ width: 0 }; - var BananaSlugWebNodeMeasurer = function (_BananaSlugAbstractNo) { - _inherits(BananaSlugWebNodeMeasurer, _BananaSlugAbstractNo); + var TraceUpdatesWebNodeMeasurer = function (_TraceUpdatesAbstract) { + _inherits(TraceUpdatesWebNodeMeasurer, _TraceUpdatesAbstract); - function BananaSlugWebNodeMeasurer() { - _classCallCheck(this, BananaSlugWebNodeMeasurer); + function TraceUpdatesWebNodeMeasurer() { + _classCallCheck(this, TraceUpdatesWebNodeMeasurer); - return _possibleConstructorReturn(this, (BananaSlugWebNodeMeasurer.__proto__ || Object.getPrototypeOf(BananaSlugWebNodeMeasurer)).apply(this, arguments)); + return _possibleConstructorReturn(this, (TraceUpdatesWebNodeMeasurer.__proto__ || Object.getPrototypeOf(TraceUpdatesWebNodeMeasurer)).apply(this, arguments)); } - _createClass(BananaSlugWebNodeMeasurer, [{ + _createClass(TraceUpdatesWebNodeMeasurer, [{ key: 'measureImpl', value: function measureImpl(node) { if (!node || typeof node.getBoundingClientRect !== 'function') { @@ -6767,14 +6856,14 @@ } }]); - return BananaSlugWebNodeMeasurer; - }(BananaSlugAbstractNodeMeasurer); + return TraceUpdatesWebNodeMeasurer; + }(TraceUpdatesAbstractNodeMeasurer); - module.exports = BananaSlugWebNodeMeasurer; + module.exports = TraceUpdatesWebNodeMeasurer; /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(2))) /***/ }, -/* 17 */ +/* 18 */ /***/ function(module, exports, __webpack_require__) { /* WEBPACK VAR INJECTION */(function(__webpack_provided_Object_dot_create) {/** @@ -6800,7 +6889,7 @@ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = __webpack_provided_Object_dot_create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - var BananaSlugAbstractNodePresenter = __webpack_require__(15); + var TraceUpdatesAbstractNodePresenter = __webpack_require__(16); var OUTLINE_COLOR = '#f0f0f0'; @@ -6838,21 +6927,21 @@ ctx.setLineDash([0]); } - var CANVAS_NODE_ID = 'BananaSlugWebNodePresenter'; + var CANVAS_NODE_ID = 'TraceUpdatesWebNodePresenter'; - var BananaSlugWebNodePresenter = function (_BananaSlugAbstractNo) { - _inherits(BananaSlugWebNodePresenter, _BananaSlugAbstractNo); + var TraceUpdatesWebNodePresenter = function (_TraceUpdatesAbstract) { + _inherits(TraceUpdatesWebNodePresenter, _TraceUpdatesAbstract); - function BananaSlugWebNodePresenter() { - _classCallCheck(this, BananaSlugWebNodePresenter); + function TraceUpdatesWebNodePresenter() { + _classCallCheck(this, TraceUpdatesWebNodePresenter); - var _this = _possibleConstructorReturn(this, (BananaSlugWebNodePresenter.__proto__ || Object.getPrototypeOf(BananaSlugWebNodePresenter)).call(this)); + var _this = _possibleConstructorReturn(this, (TraceUpdatesWebNodePresenter.__proto__ || Object.getPrototypeOf(TraceUpdatesWebNodePresenter)).call(this)); _this._canvas = null; return _this; } - _createClass(BananaSlugWebNodePresenter, [{ + _createClass(TraceUpdatesWebNodePresenter, [{ key: 'drawImpl', value: function drawImpl(pool) { this._ensureCanvas(); @@ -6926,17 +7015,17 @@ } }]); - return BananaSlugWebNodePresenter; - }(BananaSlugAbstractNodePresenter); + return TraceUpdatesWebNodePresenter; + }(TraceUpdatesAbstractNodePresenter); - module.exports = BananaSlugWebNodePresenter; + module.exports = TraceUpdatesWebNodePresenter; /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(2))) /***/ }, -/* 18 */ +/* 19 */ /***/ function(module, exports, __webpack_require__) { - /* WEBPACK VAR INJECTION */(function(Map) {/** + /* WEBPACK VAR INJECTION */(function(Map, __webpack_provided_Object_dot_create) {/** * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. * @@ -6956,16 +7045,25 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - var consts = __webpack_require__(19); - var hydrate = __webpack_require__(38); - var dehydrate = __webpack_require__(39); - var performanceNow = __webpack_require__(40); + var consts = __webpack_require__(20); + var hydrate = __webpack_require__(39); + var dehydrate = __webpack_require__(40); + var getIn = __webpack_require__(9); + var performanceNow = __webpack_require__(41); + + // Use the polyfill if the function is not native implementation + function getWindowFunction(name, polyfill) { + if (String(window[name]).indexOf('[native code]') === -1) { + return polyfill; + } + return window[name]; + } // Custom polyfill that runs the queue with a backoff. // If you change it, make sure it behaves reasonably well in Firefox. var lastRunTimeMS = 5; - var cancelIdleCallback = window.cancelIdleCallback || clearTimeout; - var requestIdleCallback = window.requestIdleCallback || function (cb, options) { + var cancelIdleCallback = getWindowFunction('cancelIdleCallback', clearTimeout); + var requestIdleCallback = getWindowFunction('requestIdleCallback', function (cb, options) { // Magic numbers determined by tweaking in Firefox. // There is no special meaning to them. var delayMS = 3000 * lastRunTimeMS; @@ -6984,7 +7082,7 @@ var endTime = performanceNow(); lastRunTimeMS = (endTime - startTime) / 1000; }, delayMS); - }; + }); /** * The bridge is responsible for serializing requests between the Agent and @@ -7317,15 +7415,52 @@ key: '_inspectResponse', value: function _inspectResponse(id, path, callback) { var inspectable = this._inspectables.get(id); - var result = {}; var cleaned = []; var proto = null; var protoclean = []; + if (inspectable) { var val = getIn(inspectable, path); var protod = false; var isFn = typeof val === 'function'; + + if (val && typeof val[Symbol.iterator] === 'function') { + var iterVal = __webpack_provided_Object_dot_create({}); // flow throws "object literal incompatible with object type" + var count = 0; + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for (var _iterator = val[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + var entry = _step.value; + + if (count > 100) { + // TODO: replace this if block with better logic to handle large iterables + break; + } + iterVal[count] = entry; + count++; + } + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator.return) { + _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } + + val = iterVal; + } + Object.getOwnPropertyNames(val).forEach(function (name) { if (name === '__proto__') { protod = true; @@ -7362,17 +7497,11 @@ return Bridge; }(); - function getIn(base, path) { - return path.reduce(function (obj, attr) { - return obj ? obj[attr] : null; - }, base); - } - module.exports = Bridge; - /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3), __webpack_require__(2))) /***/ }, -/* 19 */ +/* 20 */ /***/ function(module, exports, __webpack_require__) { /** @@ -7387,7 +7516,7 @@ */ 'use strict'; - var _Symbol = __webpack_require__(20); + var _Symbol = __webpack_require__(21); module.exports = { name: _Symbol('name'), @@ -7398,16 +7527,16 @@ }; /***/ }, -/* 20 */ +/* 21 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; - module.exports = __webpack_require__(21)() ? Symbol : __webpack_require__(22); + module.exports = __webpack_require__(22)() ? Symbol : __webpack_require__(23); /***/ }, -/* 21 */ +/* 22 */ /***/ function(module, exports) { 'use strict'; @@ -7431,15 +7560,15 @@ /***/ }, -/* 22 */ +/* 23 */ /***/ function(module, exports, __webpack_require__) { /* WEBPACK VAR INJECTION */(function(__webpack_provided_Object_dot_create) {// ES2015 Symbol polyfill for environments that do not support it (or partially support it_ 'use strict'; - var d = __webpack_require__(23) - , validateSymbol = __webpack_require__(36) + var d = __webpack_require__(24) + , validateSymbol = __webpack_require__(37) , create = __webpack_provided_Object_dot_create, defineProperties = Object.defineProperties , defineProperty = Object.defineProperty, objPrototype = Object.prototype @@ -7545,15 +7674,15 @@ /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(2))) /***/ }, -/* 23 */ +/* 24 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; - var assign = __webpack_require__(24) - , normalizeOpts = __webpack_require__(31) - , isCallable = __webpack_require__(32) - , contains = __webpack_require__(33) + var assign = __webpack_require__(25) + , normalizeOpts = __webpack_require__(32) + , isCallable = __webpack_require__(33) + , contains = __webpack_require__(34) , d; @@ -7614,18 +7743,18 @@ /***/ }, -/* 24 */ +/* 25 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; - module.exports = __webpack_require__(25)() + module.exports = __webpack_require__(26)() ? Object.assign - : __webpack_require__(26); + : __webpack_require__(27); /***/ }, -/* 25 */ +/* 26 */ /***/ function(module, exports) { 'use strict'; @@ -7640,13 +7769,13 @@ /***/ }, -/* 26 */ +/* 27 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; - var keys = __webpack_require__(27) - , value = __webpack_require__(30) + var keys = __webpack_require__(28) + , value = __webpack_require__(31) , max = Math.max; @@ -7668,18 +7797,18 @@ /***/ }, -/* 27 */ +/* 28 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; - module.exports = __webpack_require__(28)() + module.exports = __webpack_require__(29)() ? Object.keys - : __webpack_require__(29); + : __webpack_require__(30); /***/ }, -/* 28 */ +/* 29 */ /***/ function(module, exports) { 'use strict'; @@ -7693,7 +7822,7 @@ /***/ }, -/* 29 */ +/* 30 */ /***/ function(module, exports) { 'use strict'; @@ -7706,7 +7835,7 @@ /***/ }, -/* 30 */ +/* 31 */ /***/ function(module, exports) { 'use strict'; @@ -7718,7 +7847,7 @@ /***/ }, -/* 31 */ +/* 32 */ /***/ function(module, exports, __webpack_require__) { /* WEBPACK VAR INJECTION */(function(__webpack_provided_Object_dot_create) {'use strict'; @@ -7742,7 +7871,7 @@ /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(2))) /***/ }, -/* 32 */ +/* 33 */ /***/ function(module, exports) { // Deprecated @@ -7753,18 +7882,18 @@ /***/ }, -/* 33 */ +/* 34 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; - module.exports = __webpack_require__(34)() + module.exports = __webpack_require__(35)() ? String.prototype.contains - : __webpack_require__(35); + : __webpack_require__(36); /***/ }, -/* 34 */ +/* 35 */ /***/ function(module, exports) { 'use strict'; @@ -7778,7 +7907,7 @@ /***/ }, -/* 35 */ +/* 36 */ /***/ function(module, exports) { 'use strict'; @@ -7791,12 +7920,12 @@ /***/ }, -/* 36 */ +/* 37 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; - var isSymbol = __webpack_require__(37); + var isSymbol = __webpack_require__(38); module.exports = function (value) { if (!isSymbol(value)) throw new TypeError(value + " is not a symbol"); @@ -7805,7 +7934,7 @@ /***/ }, -/* 37 */ +/* 38 */ /***/ function(module, exports) { 'use strict'; @@ -7816,7 +7945,7 @@ /***/ }, -/* 38 */ +/* 39 */ /***/ function(module, exports, __webpack_require__) { /** @@ -7831,7 +7960,7 @@ */ 'use strict'; - var consts = __webpack_require__(19); + var consts = __webpack_require__(20); function hydrate(data, cleaned) { cleaned.forEach(function (path) { @@ -7854,7 +7983,7 @@ module.exports = hydrate; /***/ }, -/* 39 */ +/* 40 */ /***/ function(module, exports) { /** @@ -7869,6 +7998,67 @@ */ 'use strict'; + /** + * Get a enhanced/artificial type string based on the object instance + */ + + var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + + function getPropType(data) { + if (!data) { + return null; + } + var type = typeof data === 'undefined' ? 'undefined' : _typeof(data); + + if (type === 'object') { + if (data._reactFragment) { + return 'react_fragment'; + } + if (Array.isArray(data)) { + return 'array'; + } + if (ArrayBuffer.isView(data)) { + if (data instanceof DataView) { + return 'data_view'; + } + return 'typed_array'; + } + if (data instanceof ArrayBuffer) { + return 'array_buffer'; + } + if (typeof data[Symbol.iterator] === 'function') { + return 'iterator'; + } + if (Object.prototype.toString.call(data) === '[object Date]') { + return 'date'; + } + } + + return type; + } + + /** + * Generate the dehydrated metadata for complex object instances + */ + function createDehydrated(type, data, cleaned, path) { + var meta = {}; + + if (type === 'array' || type === 'typed_array') { + meta.length = data.length; + } + if (type === 'iterator' || type === 'typed_array') { + meta.readOnly = true; + } + + cleaned.push(path); + + return { + type: type, + meta: meta, + name: !data.constructor || data.constructor.name === 'Object' ? '' : data.constructor.name + }; + } + /** * Strip out complex data (instances, functions, and data nested > 2 levels * deep). The paths of the stripped out objects are appended to the `cleaned` @@ -7889,74 +8079,92 @@ * } * and cleaned = [["some", "attr"], ["other"]] */ + function dehydrate(data, cleaned) { + var path = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : []; + var level = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0; - var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; - function dehydrate(data, cleaned, path, level) { - level = level || 0; - path = path || []; - if (typeof data === 'function') { - cleaned.push(path); - return { - name: data.name, - type: 'function' - }; - } - if (!data || (typeof data === 'undefined' ? 'undefined' : _typeof(data)) !== 'object') { - if (typeof data === 'string' && data.length > 500) { - return data.slice(0, 500) + '...'; - } + var type = getPropType(data); + + switch (type) { + + case 'function': + cleaned.push(path); + return { + name: data.name, + type: 'function' + }; + + case 'string': + return data.length <= 500 ? data : data.slice(0, 500) + '...'; + // We have to do this assignment b/c Flow doesn't think "symbol" is // something typeof would return. Error 'unexpected predicate "symbol"' - var type = typeof data === 'undefined' ? 'undefined' : _typeof(data); - if (type === 'symbol') { + case 'symbol': cleaned.push(path); return { type: 'symbol', name: data.toString() }; - } - return data; - } - if (data._reactFragment) { + // React Fragments error if you try to inspect them. - return 'A react fragment'; - } - if (level > 2) { - cleaned.push(path); - return { - type: Array.isArray(data) ? 'array' : 'object', - name: !data.constructor || data.constructor.name === 'Object' ? '' : data.constructor.name, - meta: Array.isArray(data) ? { - length: data.length - } : null - }; - } - if (Array.isArray(data)) { - // $FlowFixMe path is not undefined. - return data.map(function (item, i) { - return dehydrate(item, cleaned, path.concat([i]), level + 1); - }); - } - // TODO when this is in the iframe window, we can just use Object - if (data.constructor && typeof data.constructor === 'function' && data.constructor.name !== 'Object') { - cleaned.push(path); - return { - name: data.constructor.name, - type: 'object' - }; - } - var res = {}; - for (var name in data) { - res[name] = dehydrate(data[name], cleaned, path.concat([name]), level + 1); + case 'react_fragment': + return 'A React Fragment'; + + // ArrayBuffers error if you try to inspect them. + case 'array_buffer': + case 'data_view': + cleaned.push(path); + return { + type: type, + name: type === 'data_view' ? 'DataView' : 'ArrayBuffer', + meta: { + length: data.byteLength, + uninspectable: true + } + }; + + case 'array': + if (level > 2) { + return createDehydrated(type, data, cleaned, path); + } + return data.map(function (item, i) { + return dehydrate(item, cleaned, path.concat([i]), level + 1); + }); + + case 'typed_array': + case 'iterator': + return createDehydrated(type, data, cleaned, path); + case 'date': + cleaned.push(path); + return { + name: data.toString(), + type: 'date', + meta: { + uninspectable: true + } + }; + case 'object': + if (level > 2 || data.constructor && typeof data.constructor === 'function' && data.constructor.name !== 'Object') { + return createDehydrated(type, data, cleaned, path); + } else { + + var res = {}; + for (var name in data) { + res[name] = dehydrate(data[name], cleaned, path.concat([name]), level + 1); + } + return res; + } + + default: + return data; } - return res; } module.exports = dehydrate; /***/ }, -/* 40 */ +/* 41 */ /***/ function(module, exports, __webpack_require__) { /** @@ -7973,7 +8181,7 @@ 'use strict'; - var performance = __webpack_require__(41); + var performance = __webpack_require__(42); var performanceNow; @@ -7995,7 +8203,7 @@ module.exports = performanceNow; /***/ }, -/* 41 */ +/* 42 */ /***/ function(module, exports, __webpack_require__) { /** @@ -8012,7 +8220,7 @@ 'use strict'; - var ExecutionEnvironment = __webpack_require__(42); + var ExecutionEnvironment = __webpack_require__(43); var performance; @@ -8023,7 +8231,7 @@ module.exports = performance || {}; /***/ }, -/* 42 */ +/* 43 */ /***/ function(module, exports) { /** @@ -8064,7 +8272,7 @@ module.exports = ExecutionEnvironment; /***/ }, -/* 43 */ +/* 44 */ /***/ function(module, exports, __webpack_require__) { /** @@ -8079,7 +8287,7 @@ */ 'use strict'; - var setupBackend = __webpack_require__(44); + var setupBackend = __webpack_require__(45); module.exports = function (hook, agent) { var subs = [hook.sub('renderer-attached', function (_ref) { @@ -8091,22 +8299,22 @@ helpers.walkTree(agent.onMounted.bind(agent, id), agent.addRoot.bind(agent, id)); }), hook.sub('root', function (_ref2) { var renderer = _ref2.renderer, - element = _ref2.element; - return agent.addRoot(renderer, element); + internalInstance = _ref2.internalInstance; + return agent.addRoot(renderer, internalInstance); }), hook.sub('mount', function (_ref3) { var renderer = _ref3.renderer, - element = _ref3.element, + internalInstance = _ref3.internalInstance, data = _ref3.data; - return agent.onMounted(renderer, element, data); + return agent.onMounted(renderer, internalInstance, data); }), hook.sub('update', function (_ref4) { var renderer = _ref4.renderer, - element = _ref4.element, + internalInstance = _ref4.internalInstance, data = _ref4.data; - return agent.onUpdated(element, data); + return agent.onUpdated(internalInstance, data); }), hook.sub('unmount', function (_ref5) { var renderer = _ref5.renderer, - element = _ref5.element; - return agent.onUnmounted(element); + internalInstance = _ref5.internalInstance; + return agent.onUnmounted(internalInstance); })]; var success = setupBackend(hook); @@ -8125,7 +8333,7 @@ }; /***/ }, -/* 44 */ +/* 45 */ /***/ function(module, exports, __webpack_require__) { /** @@ -8153,7 +8361,7 @@ */ 'use strict'; - var attachRenderer = __webpack_require__(45); + var attachRenderer = __webpack_require__(46); module.exports = function setupBackend(hook) { var oldReact = window.React && window.React.__internals; @@ -8186,7 +8394,7 @@ }; /***/ }, -/* 45 */ +/* 46 */ /***/ function(module, exports, __webpack_require__) { /* WEBPACK VAR INJECTION */(function(Map) {/** @@ -8201,9 +8409,9 @@ */ 'use strict'; - var getData = __webpack_require__(46); - var getData012 = __webpack_require__(49); - var attachRendererFiber = __webpack_require__(50); + var getData = __webpack_require__(47); + var getData012 = __webpack_require__(53); + var attachRendererFiber = __webpack_require__(54); /** * This takes care of patching the renderer to emit events on the global @@ -8267,13 +8475,13 @@ // React DOM if (renderer.Mount._renderNewRootComponent) { - oldRenderRoot = decorateResult(renderer.Mount, '_renderNewRootComponent', function (element) { - hook.emit('root', { renderer: rid, element: element }); + oldRenderRoot = decorateResult(renderer.Mount, '_renderNewRootComponent', function (internalInstance) { + hook.emit('root', { renderer: rid, internalInstance: internalInstance }); }); // React Native } else if (renderer.Mount.renderComponent) { - oldRenderComponent = decorateResult(renderer.Mount, 'renderComponent', function (element) { - hook.emit('root', { renderer: rid, element: element._reactInternalInstance }); + oldRenderComponent = decorateResult(renderer.Mount, 'renderComponent', function (internalInstance) { + hook.emit('root', { renderer: rid, internalInstance: internalInstance._reactInternalInstance }); }); } @@ -8292,37 +8500,37 @@ // (do we have access to DOMComponent here?) so that we don't have to // setTimeout. setTimeout(function () { - hook.emit('mount', { element: _this, data: getData012(_this), renderer: rid }); + hook.emit('mount', { internalInstance: _this, data: getData012(_this), renderer: rid }); }, 0); }, updateComponent: function updateComponent() { var _this2 = this; setTimeout(function () { - hook.emit('update', { element: _this2, data: getData012(_this2), renderer: rid }); + hook.emit('update', { internalInstance: _this2, data: getData012(_this2), renderer: rid }); }, 0); }, unmountComponent: function unmountComponent() { - hook.emit('unmount', { element: this, renderer: rid }); + hook.emit('unmount', { internalInstance: this, renderer: rid }); rootNodeIDMap.delete(this._rootNodeID, this); } }); } else if (renderer.Reconciler) { oldMethods = decorateMany(renderer.Reconciler, { - mountComponent: function mountComponent(element, rootID, transaction, context) { - var data = getData(element); - rootNodeIDMap.set(element._rootNodeID, element); - hook.emit('mount', { element: element, data: data, renderer: rid }); + mountComponent: function mountComponent(internalInstance, rootID, transaction, context) { + var data = getData(internalInstance); + rootNodeIDMap.set(internalInstance._rootNodeID, internalInstance); + hook.emit('mount', { internalInstance: internalInstance, data: data, renderer: rid }); }, - performUpdateIfNecessary: function performUpdateIfNecessary(element, nextChild, transaction, context) { - hook.emit('update', { element: element, data: getData(element), renderer: rid }); + performUpdateIfNecessary: function performUpdateIfNecessary(internalInstance, nextChild, transaction, context) { + hook.emit('update', { internalInstance: internalInstance, data: getData(internalInstance), renderer: rid }); }, - receiveComponent: function receiveComponent(element, nextChild, transaction, context) { - hook.emit('update', { element: element, data: getData(element), renderer: rid }); + receiveComponent: function receiveComponent(internalInstance, nextChild, transaction, context) { + hook.emit('update', { internalInstance: internalInstance, data: getData(internalInstance), renderer: rid }); }, - unmountComponent: function unmountComponent(element) { - hook.emit('unmount', { element: element, renderer: rid }); - rootNodeIDMap.delete(element._rootNodeID, element); + unmountComponent: function unmountComponent(internalInstance) { + hook.emit('unmount', { internalInstance: internalInstance, renderer: rid }); + rootNodeIDMap.delete(internalInstance._rootNodeID, internalInstance); } }); } @@ -8364,14 +8572,14 @@ } } - function walkNode(element, onMount, isPre013) { - var data = isPre013 ? getData012(element) : getData(element); + function walkNode(internalInstance, onMount, isPre013) { + var data = isPre013 ? getData012(internalInstance) : getData(internalInstance); if (data.children && Array.isArray(data.children)) { data.children.forEach(function (child) { return walkNode(child, onMount, isPre013); }); } - onMount(element, data); + onMount(internalInstance, data); } function decorateResult(obj, attr, fn) { @@ -8412,7 +8620,7 @@ /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) /***/ }, -/* 46 */ +/* 47 */ /***/ function(module, exports, __webpack_require__) { /** @@ -8431,13 +8639,14 @@ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; - var copyWithSet = __webpack_require__(47); - var getDisplayName = __webpack_require__(48); + var copyWithSet = __webpack_require__(48); + var getDisplayName = __webpack_require__(49); + var traverseAllChildrenImpl = __webpack_require__(50); /** * Convert a react internal instance to a sanitized data object. */ - function getData(element) { + function getData(internalInstance) { var children = null; var props = null; var state = null; @@ -8454,72 +8663,99 @@ // If the parent is a native node without rendered children, but with // multiple string children, then the `element` that gets passed in here is // a plain value -- a string or number. - if ((typeof element === 'undefined' ? 'undefined' : _typeof(element)) !== 'object') { + if ((typeof internalInstance === 'undefined' ? 'undefined' : _typeof(internalInstance)) !== 'object') { nodeType = 'Text'; - text = element + ''; - } else if (element._currentElement === null || element._currentElement === false) { + text = internalInstance + ''; + } else if (internalInstance._currentElement === null || internalInstance._currentElement === false) { nodeType = 'Empty'; - } else if (element._renderedComponent) { + } else if (internalInstance._renderedComponent) { nodeType = 'NativeWrapper'; - children = [element._renderedComponent]; - props = element._instance.props; - state = element._instance.state; - context = element._instance.context; + children = [internalInstance._renderedComponent]; + props = internalInstance._instance.props; + state = internalInstance._instance.state; + context = internalInstance._instance.context; if (context && Object.keys(context).length === 0) { context = null; } - } else if (element._renderedChildren) { - children = childrenList(element._renderedChildren); - } else if (element._currentElement && element._currentElement.props) { + } else if (internalInstance._renderedChildren) { + children = childrenList(internalInstance._renderedChildren); + } else if (internalInstance._currentElement && internalInstance._currentElement.props) { // This is a native node without rendered children -- meaning the children - // prop is just a string or (in the case of the
; + return ; } } diff --git a/src/renderer/entries/NotFound.tsx b/src/renderer/entries/NotFound.tsx index 4102a83..494c2bf 100644 --- a/src/renderer/entries/NotFound.tsx +++ b/src/renderer/entries/NotFound.tsx @@ -1,6 +1,5 @@ import * as React from "react"; - -// const styles = require("./index.less") +import NotFoundView from "../views/NotFound"; interface NotFoundEntryProps {} @@ -12,6 +11,6 @@ export default class NotFoundEntry extends React.ComponentNotFoundEntry
; + return ; } } diff --git a/src/renderer/entries/Setting.tsx b/src/renderer/entries/Setting.tsx index cbffc55..284db50 100644 --- a/src/renderer/entries/Setting.tsx +++ b/src/renderer/entries/Setting.tsx @@ -1,6 +1,5 @@ import * as React from "react"; - -// const styles = require("./index.less") +import SettingView from "../views/Setting"; interface SettingEntryProps {} @@ -12,6 +11,6 @@ export default class SettingEntry extends React.ComponentSettingEntry
; + return ; } } diff --git a/src/renderer/index.tsx b/src/renderer/index.tsx index c16fe3f..2948cba 100644 --- a/src/renderer/index.tsx +++ b/src/renderer/index.tsx @@ -2,14 +2,15 @@ import React from "react"; import ReactDOM from "react-dom"; import { Provider } from "mobx-react"; import MainRouter from "./routes"; +import getStore from "./store"; -// const configureStore = require("./store/configureStore"); +require("./assets/styles/global/global.less"); declare var window; -// const store = configureStore(); +const store = getStore(); -ReactDOM.render({MainRouter}, document.getElementById("app")); +ReactDOM.render({MainRouter}, document.getElementById("app")); // global debug mark window._DEBUG_ = process.env.NODE_ENV === "development"; diff --git a/src/renderer/interface/IAccount.ts b/src/renderer/interface/IAccount.ts new file mode 100644 index 0000000..9ab0228 --- /dev/null +++ b/src/renderer/interface/IAccount.ts @@ -0,0 +1,11 @@ +import IProfile from "./IProfile"; + +export interface ICredentialsState { + username: string; + password: string; +} + +export interface ILoginResultState { + success: boolean | null; + profile: IProfile | null; +} diff --git a/src/renderer/interface/IAction.ts b/src/renderer/interface/IAction.ts new file mode 100644 index 0000000..a7ec30e --- /dev/null +++ b/src/renderer/interface/IAction.ts @@ -0,0 +1,5 @@ +export default interface IAction { + type: string; + payload?: any; + error?: Error; +}; diff --git a/src/renderer/interface/IAuthor.ts b/src/renderer/interface/IAuthor.ts new file mode 100644 index 0000000..0f80031 --- /dev/null +++ b/src/renderer/interface/IAuthor.ts @@ -0,0 +1,21 @@ +export default interface IAuthor { + id: number; + login: string; + isOwner: boolean; + repoId: number; + avatarUrl: string; + gravatarId: string; + url: string; + htmlUrl: string; + followersUrl: string; + followingUrl: string; + gistsUrl: string; + starredUrl: string; + subscriptionsUrl: string; + organizationsUrl: string; + reposUrl: string; + eventsUrl: string; + receivedEventsUrl: string; + type: string; + siteAdmin: boolean; +} diff --git a/src/renderer/interface/ICategory.ts b/src/renderer/interface/ICategory.ts new file mode 100644 index 0000000..9f37fad --- /dev/null +++ b/src/renderer/interface/ICategory.ts @@ -0,0 +1,17 @@ +export default interface ICategory { + id: number; + name: string; + description: string; + repos: number[]; + reposCount: number; + createdAt: string; + createdTime: string; + updatedAt: string; + updatedTime: number; +} + +export interface ICategoryCreateResult { + category?: ICategory; + success: boolean; + error?: Error; +} diff --git a/src/renderer/interface/IConditional.ts b/src/renderer/interface/IConditional.ts new file mode 100644 index 0000000..3b41fc1 --- /dev/null +++ b/src/renderer/interface/IConditional.ts @@ -0,0 +1,20 @@ +export interface ISearchConditionState { + key: string; + field: string; +} + +export interface IFilterConditionState { + hasFlag: boolean; + hasNote: boolean; + unread: boolean; +} + +export interface IOrderConditionState { + by: string; + desc: boolean; +} + +export interface IGroupConditionState { + type: string; + id: string; +} diff --git a/src/renderer/interface/ILanguage.ts b/src/renderer/interface/ILanguage.ts new file mode 100644 index 0000000..e231ec6 --- /dev/null +++ b/src/renderer/interface/ILanguage.ts @@ -0,0 +1,7 @@ +export default interface ILanguage { + id: number; + name: string; + description: string; + repos: number[]; + reposCount: number; +} diff --git a/src/renderer/interface/IOffline.ts b/src/renderer/interface/IOffline.ts new file mode 100644 index 0000000..7cef474 --- /dev/null +++ b/src/renderer/interface/IOffline.ts @@ -0,0 +1,4 @@ +export default interface IOfflineState { + value: boolean | null; + time: number; +} diff --git a/src/renderer/interface/IProfile.ts b/src/renderer/interface/IProfile.ts new file mode 100644 index 0000000..6b2bbc2 --- /dev/null +++ b/src/renderer/interface/IProfile.ts @@ -0,0 +1,39 @@ +export default interface IProfile { + id: number; + login: string; + avatarUrl: string; + gravatarId: string; + url: string; + htmlUrl: string; + followersUrl: string; + followingUrl: string; + gistsUrl: string; + starredUrl: string; + subscriptionsUrl: string; + organizationsUrl: string; + reposUrl: string; + eventsUrl: string; + receivedEventsUrl: string; + type: string; + siteAdmin: boolean; + name: string; + company: string; + blog: string; + location: string; + hireable: boolean; + publicRepos: number; + publicGists: number; + followers: number; + following: number; + createdAt: string; + createdTime: number; + updatedAt: string; + updatedTime: number; + privateGists: number; + totalPrivateRepos: number; + ownedPrivateRepos: number; + diskUsage: number; + collaborators: number; + twoFactorAuthentication: boolean; + avatar_url: string; +}; diff --git a/src/renderer/interface/IRepo.ts b/src/renderer/interface/IRepo.ts new file mode 100644 index 0000000..dc776d0 --- /dev/null +++ b/src/renderer/interface/IRepo.ts @@ -0,0 +1,92 @@ +import ICategory from "./ICategory"; +import IAuthor from "./IAuthor"; +import ITag from "./ITag"; + +export default interface IRepo { + id: number; + name: string; + fullName: string; + owner: number; + private: boolean; + htmlUrl: string; + description: string; + fork: boolean; + url: string; + forksUrl: string; + keysUrl: string; + collaboratorsUrl: string; + teamsUrl: string; + hooksUrl: string; + issueEventsUrl: string; + eventsUrl: string; + assigneesUrl: string; + branchesUrl: string; + tagsUrl: string; + blobsUrl: string; + gitTagsUrl: string; + gitRefsUrl: string; + treesUrl: string; + statusesUrl: string; + languagesUrl: string; + stargazersUrl: string; + contributorsUrl: string; + subscribersUrl: string; + subscriptionUrl: string; + commitsUrl: string; + gitCommitsUrl: string; + commentsUrl: string; + issueCommentUrl: string; + contentsUrl: string; + compareUrl: string; + mergesUrl: string; + archiveUrl: string; + downloadsUrl: string; + issuesUrl: string; + pullsUrl: string; + milestonesUrl: string; + notificationsUrl: string; + labelsUrl: string; + releasesUrl: string; + deploymentsUrl: string; + createdAt: string; + createdTime: number; + updatedAt: string; + updatedTime: number; + pushedAt: string; + pushedTime: number; + gitUrl: string; + sshUrl: string; + cloneUrl: string; + svnUrl: string; + homePage: string; + size: number; + stargazersCount: number; + stars: number; + watchersCount: number; + lang: string; + hasIssues: boolean; + hasDownloads: boolean; + hasWiki: boolean; + hasPages: boolean; + forksCount: number; + mirrorUrl: string; + openIssuesCount: number; + forks: number; + openIssues: number; + watchers: number; + defaultBranch: string; + score: number; + flag: boolean; + read: boolean; + note: string; + defaultOrder: number; + readme: string; + _categories: ICategory[]; + _contributors: IAuthor[]; + _tags: ITag[]; +} + +export interface IRepoFetchingStatus { + fetching: boolean; + success: boolean | null; +} diff --git a/src/renderer/interface/ISetting.ts b/src/renderer/interface/ISetting.ts new file mode 100644 index 0000000..5e78bd0 --- /dev/null +++ b/src/renderer/interface/ISetting.ts @@ -0,0 +1,4 @@ +export default interface ISetting { + id: string; + value: string; +} diff --git a/src/renderer/interface/IState.ts b/src/renderer/interface/IState.ts new file mode 100644 index 0000000..1b39fb9 --- /dev/null +++ b/src/renderer/interface/IState.ts @@ -0,0 +1,33 @@ +import IRepo, { IRepoFetchingStatus } from "../interface/IRepo"; +import IProfile from "../interface/IProfile"; +import IOfflineState from "../interface/IOffline"; +import ILanguage from "../interface/ILanguage"; +import { + ISearchConditionState, + IFilterConditionState, + IOrderConditionState, + IGroupConditionState +} from "../interface/IConditional"; +import ICategory, { ICategoryCreateResult } from "../interface/ICategory"; +import { ICredentialsState, ILoginResultState } from "../interface/IAccount"; +import { RxDatabase } from "rxdb"; + +export default interface IState { + routing: any; + offline: IOfflineState; + db: RxDatabase; + credentials: ICredentialsState; + profile: IProfile | null; + loginResult: ILoginResultState; + search: ISearchConditionState; + order: IOrderConditionState; + filter: IFilterConditionState; + group: IGroupConditionState; + repos: { [key: string]: IRepo }; + increase: number; + languages: ILanguage[]; + categories: ICategory[]; + fetchStatus: IRepoFetchingStatus; + catAdd: ICategoryCreateResult; + selectedRepo: IRepo | null; +} diff --git a/src/renderer/interface/IStore.ts b/src/renderer/interface/IStore.ts new file mode 100644 index 0000000..080e7c5 --- /dev/null +++ b/src/renderer/interface/IStore.ts @@ -0,0 +1,5 @@ +import GlobalStore from "../store/GlobalStore"; + +export default interface IStore { + global: GlobalStore; +}; diff --git a/src/renderer/interface/ITag.ts b/src/renderer/interface/ITag.ts new file mode 100644 index 0000000..b3b9bd4 --- /dev/null +++ b/src/renderer/interface/ITag.ts @@ -0,0 +1,10 @@ +export default interface ITag { + id: number; + name: string; + description: string; + repos: number[]; + createdAt: string; + createdTime: number; + updatedAt: string; + updatedTime: number; +} diff --git a/src/renderer/rxdb/database.ts b/src/renderer/rxdb/database.ts new file mode 100644 index 0000000..537afe4 --- /dev/null +++ b/src/renderer/rxdb/database.ts @@ -0,0 +1,124 @@ +import * as RxDB from "rxdb"; +import { RxDatabase, RxCollectionCreator } from "rxdb"; +import logger from "../utils/logger"; +import { extendRxDB } from "./dbExtension"; +import repoSchema from "./schemas/repoSchema"; +import authorSchema from "./schemas/authorSchema"; +import meSchema from "./schemas/meSchema"; +import tagSchema from "./schemas/tagSchema"; +import categorySchema from "./schemas/categorySchema"; +import languageSchema from "./schemas/languageSchema"; +import settingSchema from "./schemas/settingSchema"; + +declare var window; + +RxDB.plugin(require("pouchdb-adapter-idb")); + +const collections: RxCollectionCreator[] = [ + { + name: "repos", + schema: repoSchema as any + }, + { + name: "authors", + schema: authorSchema + // sync: false + }, + { + name: "me", + schema: meSchema + // sync: false + }, + { + name: "tags", + schema: tagSchema as any, + methods: { + countRepos() { + return this.repos.length; + } + } + // sync: false + }, + { + name: "categories", + schema: categorySchema, + methods: { + countRepos() { + return this.repos.length; + } + } + // sync: false + }, + { + name: "languages", + schema: languageSchema, + methods: { + countRepos() { + return this.repos.length; + } + } + }, + { + name: "settings", + schema: settingSchema + // sync: false + } +]; + +let dbPromise: Promise; + +const _create = async function(dbName, _dispatch) { + logger.log(`DatabaseService: creating database ${dbName}..`); + + const db = await RxDB.create({ + name: dbName, + adapter: "idb", + password: "" + }); + + logger.log("DatabaseService: created database"); + // debug + if (window._DEBUG_) { + window.sc_db = db; + // db.$.subscribe(changeEvent => Logger(changeEvent)) + } + + // create collections + logger.log("DatabaseService: create collections"); + + const cols = await Promise.all(collections.map(colData => db.collection(colData))); + + cols.forEach(col => { + extendRxDB(col); + }); + + // hooks + logger.log("DatabaseService: add hooks"); + + // TODO + + // db.collections.repos.preInsert(function(docObj) { + // const color = docObj.color; + // return db.collections.heroes.findOne({color}).exec().then(has => { + // if (has != null) { + // alert('another hero already has the color ' + color); + // throw new Error('color already there') + // } + // return db + // }) + // }) + + // sync + // Logger('DatabaseService: sync') + + // collections.filter(col => col.sync).map(col => col.name).map(colName => db[colName].sync(syncURL + colName + '/')) + + return db; +}; + +export function get(dbName, dispatch = null) { + if (!dbPromise) { + dbPromise = _create(dbName, dispatch); + } + return dbPromise; +} diff --git a/src/renderer/rxdb/dbExtension.ts b/src/renderer/rxdb/dbExtension.ts new file mode 100644 index 0000000..a92504d --- /dev/null +++ b/src/renderer/rxdb/dbExtension.ts @@ -0,0 +1,57 @@ +import { default as clone } from "clone"; + +export const extendRxDB = $this => { + // only update specified fields, other fields use old data if existed + const upsertWithFields = async (json, fields: string[] = []) => { + json = clone(json); + const primary = json[$this.schema.primaryPath]; + if (!primary) { + throw new Error("RxCollection.upsertWithFields() does not work without primary"); + } + + const existing = await $this.findOne(primary).exec(); + if (existing) { + for (let prop in json) { + if (json.hasOwnProperty(prop) && fields.indexOf(prop) < 0) { + delete json[prop]; + } + } + + const data = existing._data; + json = Object.assign({}, data, json); + json._rev = existing._rev; + existing._data = json; + await existing.save(); + return existing; + } else { + const newDoc = await $this.insert(json); + return newDoc; + } + }; + + // ignore some fields when update + const upsertExcludeFields = async (json, fields = []) => { + json = clone(json); + const primary = json[$this.schema.primaryPath]; + if (!primary) { + throw new Error("RxCollection.upsertExcludeFields() does not work without primary"); + } + + const existing = await $this.findOne(primary).exec(); + if (existing) { + fields.forEach(field => { + delete json[field]; + }); + const data = Object.assign({}, existing._data, json); + data._rev = existing._rev; + existing._data = data; + await existing.save(); + return existing; + } else { + const newDoc = await $this.insert(json); + return newDoc; + } + }; + $this.upsertWithFields = upsertWithFields; + $this.upsertExcludeFields = upsertExcludeFields; +}; diff --git a/src/renderer/rxdb/dbHandler.ts b/src/renderer/rxdb/dbHandler.ts new file mode 100644 index 0000000..3ce963a --- /dev/null +++ b/src/renderer/rxdb/dbHandler.ts @@ -0,0 +1,821 @@ +import * as Database from "./database"; +import * as CONSTANTS from "../constants"; +import IRepo from "../interface/IRepo"; + +export default class DBHandler { + private dbName: string; + private RxDB; + + constructor(dbOrName) { + if (typeof dbOrName === "string") { + this.dbName = dbOrName; + } else { + this.RxDB = dbOrName; + } + } + + checkInstance = () => { + if (!this.RxDB) { + throw new Error("You must call `initDB()` first"); + } + }; + + initDB = async () => { + if (!this.RxDB) { + this.RxDB = await Database.get(this.dbName, null); + } + + return this; + }; + + upsertProfile = async profile => { + this.checkInstance(); + + let meCollection = this.RxDB.me; + const doc = await meCollection.upsert({ + key: profile.id.toString(), + id: profile.id, + login: profile.login, + avatarUrl: profile.avatar_url, + gravatarId: profile.gravatar_id, + url: profile.url, + htmlUrl: profile.html_url, + followersUrl: profile.followers_url, + followingUrl: profile.following_url, + gistsUrl: profile.gists_url, + starredUrl: profile.starred_url, + subscriptionsUrl: profile.subscriptions_url, + organizationsUrl: profile.organizations_url, + reposUrl: profile.repos_url, + eventsUrl: profile.events_url, + receivedEventsUrl: profile.received_events_url, + type: profile.type, + siteAdmin: profile.site_admin, + name: profile.name, + company: profile.company, + blog: profile.blog, + location: profile.location, + hireable: profile.hireable, + publicRepos: profile.public_repos, + publicGists: profile.public_gists, + followers: profile.followers, + following: profile.following, + createdAt: profile.created_at, + createdTime: Math.floor(new Date(profile.created_at).getTime() / 1000), + updatedAt: profile.updated_at, + updatedTime: Math.floor(new Date(profile.updated_at).getTime() / 1000), + privateGists: profile.private_gists, + totalPrivateRepos: profile.total_private_repos, + ownedPrivateRepos: profile.owned_private_repos, + diskUsage: profile.disk_usage, + collaborators: profile.collaborators, + twoFactorAuthentication: profile.two_factor_authentication, + plan: { + name: profile.plan.name, + space: profile.plan.space, + collaborators: profile.plan.collaborators, + privateRepos: profile.plan.private_repos + } + }); + + return doc; + }; + + getProfile = async (username = "") => { + this.checkInstance(); + + let meCollection = this.RxDB.me; + let query = meCollection.findOne(); + if (username) { + query = query.where("login").eq(username); + } + + let doc = await query.exec(); + return doc.toJSON(); + }; + + upsertRepos = async repos => { + this.checkInstance(); + + let reposCollection = this.RxDB.repos; + let inserts: any[] = []; + let index = 0; + let repoIds: string[] = []; + + repos.reverse(); + repos.forEach(repo => { + index++; + repoIds.push(repo.id); + inserts.push( + reposCollection.upsertExcludeFields( + { + key: repo.id.toString(), + id: repo.id, + name: repo.name, + fullName: repo.full_name, + owner: repo.owner.id, + private: repo.private, + htmlUrl: repo.html_url, + description: repo.description || "", + fork: repo.fork, + url: repo.url, + forksUrl: repo.forks_url, + keysUrl: repo.keys_url, + collaboratorsUrl: repo.collaborators_url, + teamsUrl: repo.teams_url, + hooksUrl: repo.hooks_url, + issueEventsUrl: repo.issue_events_url, + eventsUrl: repo.events_url, + assigneesUrl: repo.assignees_url, + branchesUrl: repo.branches_url, + tagsUrl: repo.tags_url, + blobsUrl: repo.blobs_url, + gitTagsUrl: repo.git_tags_url, + gitRefsUrl: repo.git_refs_url, + treesUrl: repo.trees_url, + statusesUrl: repo.statuses_url, + languagesUrl: repo.languages_url, + stargazersUrl: repo.stargazers_url, + contributorsUrl: repo.contributors_url, + subscribersUrl: repo.subscribers_url, + subscriptionUrl: repo.subscription_url, + commitsUrl: repo.commits_url, + gitCommitsUrl: repo.git_commits_url, + commentsUrl: repo.comments_url, + issueCommentUrl: repo.issue_comment_url, + contentsUrl: repo.contents_url, + compareUrl: repo.compare_url, + mergesUrl: repo.merges_url, + archiveUrl: repo.archive_url, + downloadsUrl: repo.downloads_url, + issuesUrl: repo.issues_url, + pullsUrl: repo.pulls_url, + milestonesUrl: repo.milestones_url, + notificationsUrl: repo.notifications_url, + labelsUrl: repo.labels_url, + releasesUrl: repo.releases_url, + deploymentsUrl: repo.deployments_url, + createdAt: repo.created_at, + createdTime: Math.floor(new Date(repo.created_at).getTime() / 1000), + updatedAt: repo.updated_at, + updatedTime: Math.floor(new Date(repo.updated_at).getTime() / 1000), + pushedAt: repo.pushed_at, + pushedTime: Math.floor(new Date(repo.pushed_at).getTime() / 1000), + gitUrl: repo.git_url, + sshUrl: repo.ssh_url, + cloneUrl: repo.clone_url, + svnUrl: repo.svn_url, + homePage: repo.homepage || "", + size: repo.size, + stargazersCount: repo.stargazers_count, + stars: repo.stargazers_count, + watchersCount: repo.watchers_count, + lang: repo.language || "Unknown", + hasIssues: repo.has_issues, + hasDownloads: repo.has_downloads, + hasWiki: repo.has_wiki, + hasPages: repo.has_pages, + forksCount: repo.forks_count, + // mirrorUrl: repo.mirror_url, + openIssuesCount: repo.open_issues_count, + forks: repo.forks, + openIssues: repo.open_issues, + watchers: repo.watchers, + defaultBranch: repo.default_branch, + permissions: repo.permissions, + score: 0, + flag: false, + read: false, + note: "", + readme: "", + defaultOrder: index + }, + ["score", "indexedScore", "flag", "read", "note", "readme"] + ) + ); + }); + + // now remove some repos in db but not in fetched data(they were unstarred) + await reposCollection.find({ id: { $nin: repoIds } }).remove(); + + const results: any[] = await Promise.all(inserts); + + return results.map(result => result.toJSON()); + }; + + getRepos = async conditions => { + this.checkInstance(); + + const reposCollection = this.RxDB.repos; + + let args: { [key: string]: any } = {}; + if (conditions.group) { + const id = conditions.group.id; // string + switch (conditions.group.type) { + case CONSTANTS.GROUP_TYPE_LANGUAGE: + args = { lang: { $eq: id } }; + // query = reposCollection.find(args) + break; + case CONSTANTS.GROUP_TYPE_CATEGORY: + // we should go to category table to find the repos list + const catsCollection = this.RxDB.categories; + const category = await catsCollection.findOne({ key: { $eq: id } }).exec(); + const repoIds = category.repos; + args = { id: { $in: repoIds } }; + // query = reposCollection.find(args) + break; + case CONSTANTS.GROUP_TYPE_UNKNOWN: + const catsCollection2 = this.RxDB.categories; + const categories = await catsCollection2.find().exec(); + let nrepoIds = []; + categories.forEach(cat => { + nrepoIds.concat(cat.repos); + }); + nrepoIds = Array.from(new Set(nrepoIds)); + args = { id: { $nin: nrepoIds } }; + // query = reposCollection.find(args) + break; + default: + // query = reposCollection.find() + } + } + + if (conditions.filter) { + if (conditions.filter.hasFlag) { + args.flag = { $eq: true }; + } + if (conditions.filter.hasNote) { + args.note = { $ne: "" }; + } + if (conditions.filter.unread) { + args.read = { $eq: false }; + } + } + + if (conditions.search && conditions.search.key) { + const key = conditions.search.key; + switch (conditions.search.field) { + case CONSTANTS.SEARCH_FIELD_REPO_NAME: + args.name = { $regex: new RegExp(key, "i") }; + // query = query.find(searchArgs) + break; + case CONSTANTS.SEARCH_FIELD_REPO_DESCRIPTION: + args.description = { $regex: new RegExp(key, "i") }; + // query = query.find(searchArgs) + break; + case CONSTANTS.SEARCH_FIELD_REPO_NOTE: + if (!args.note) { + args.note = { $regex: new RegExp(key, "i") }; + } else { + args.note = Object.assign({}, args.note, { + $regex: new RegExp(key, "i") + }); + } + // query = query.find(searchArgs) + break; + case CONSTANTS.SEARCH_FIELD_REPO_TAGS: + const tag = await this.RxDB.tags + .findOne({ + name: { $regex: new RegExp("^" + key + "$", "i") } + }) + .exec(); + const tagRepoIds = tag && tag.repos instanceof Array ? tag.repos : []; + if (args.id) { + const prevRepoIds = args.id.$in; + const postRepoIds = tagRepoIds.filter( + item => prevRepoIds.indexOf(item) > -1 + ); + args.id = { $in: postRepoIds }; + } else { + args.id = { $in: tagRepoIds }; + } + break; + case CONSTANTS.SEARCH_FIELD_ALL: // currently not include tags + default: + // query = query.find({$or: [{name: {$regex: new RegExp(key, 'i')}}, {description: {$regex: new RegExp(key, 'i')}}, {note: {$regex: new RegExp(key, 'i')}}]}) // TODO this does not work but no error + + // so use the bad way + let tempRepoIds: string[] = []; + const nameSearchDocs = await reposCollection + .find( + Object.assign({}, args, { + name: { $regex: new RegExp(key, "i") } + }) + ) + .exec(); + nameSearchDocs.forEach(nameSearchDoc => { + tempRepoIds.push(nameSearchDoc.id); + }); + + const introSearchDocs = await reposCollection + .find( + Object.assign({}, args, { + description: { $regex: new RegExp(key, "i") } + }) + ) + .exec(); + introSearchDocs.forEach(introSearchDoc => { + tempRepoIds.push(introSearchDoc.id); + }); + + const noteSearchDocs = await reposCollection + .find( + Object.assign({}, args, { + note: { $regex: new RegExp(key, "i") } + }) + ) + .exec(); + noteSearchDocs.forEach(noteSearchDoc => { + tempRepoIds.push(noteSearchDoc.id); + }); + + tempRepoIds = Array.from(new Set(tempRepoIds)); + if (args.id) { + args.id.$in = Array.from( + new Set(new Array().concat(args.id.$in, tempRepoIds)) + ); + } else { + args.id = { $in: tempRepoIds }; + } + // query = reposCollection.find(searchArgs) + } + } + + let query = reposCollection.find(args); + + if (conditions.order) { + const sc = conditions.order.desc ? -1 : 1; + query = query.sort({ [conditions.order.by]: sc }); + } + + let docs = await query.exec(); + + let repos: IRepo[] = []; + + docs.forEach(doc => { + let repo = doc.toJSON(); + repos.push(repo); + }); + + return repos; + }; + + upsertOwners = async repos => { + this.checkInstance(); + + const authorsCollection = this.RxDB.authors; + + let owners = {}; + repos.forEach(repo => { + // we need this step to remove duplicatives + // otherwise it will cause Document update conflict + repo.owner.repoId = repo.id; + owners["_" + repo.owner.id] = repo.owner; + }); + + let ownerIds: string[] = []; + let inserts: any[] = []; + for (let key in owners) { + if (!owners.hasOwnProperty(key)) { + continue; + } + let owner = owners[key]; + ownerIds.push(owner.id); + inserts.push( + authorsCollection.upsert({ + key: owner.repoId + "_" + owner.id, + id: owner.id, + login: owner.login, + avatarUrl: owner.avatar_url, + gravatarId: owner.gravatar_id, + url: owner.url, + htmlUrl: owner.html_url, + followersUrl: owner.followers_url, + followingUrl: owner.following_url, + gistsUrl: owner.gists_url, + starredUrl: owner.starred_url, + subscriptionsUrl: owner.subscriptions_url, + organizationsUrl: owner.organizations_url, + reposUrl: owner.repos_url, + eventsUrl: owner.events_url, + receivedEventsUrl: owner.received_events_url, + type: owner.type, + siteAdmin: owner.site_admin, + isOwner: true, + repoId: owner.repoId + }) + ); + } + + // now remove some owners in db but not in fetched data + await authorsCollection.find({ isOwner: { $eq: true }, id: { $nin: ownerIds } }).remove(); + + const results = await Promise.all(inserts); + + return results.map(result => result.toJSON()); + }; + + upsertContributors = async (repoId, contributors) => { + this.checkInstance(); + + const repo = await this.RxDB.repos.findOne({ id: { $eq: repoId } }).exec(); + if (!repo) { + return false; + } + + const authorsCollection = this.RxDB.authors; + + let contributorIds: string[] = []; + let inserts: any[] = []; + contributors.forEach(contributor => { + if (contributor.id !== repo.owner) { + contributorIds.push(contributor.id); + inserts.push( + authorsCollection.upsert({ + key: repoId + "_" + contributor.id, + id: contributor.id, + login: contributor.login, + avatarUrl: contributor.avatar_url, + gravatarId: contributor.gravatar_id, + url: contributor.url, + htmlUrl: contributor.html_url, + followersUrl: contributor.followers_url, + followingUrl: contributor.following_url, + gistsUrl: contributor.gists_url, + starredUrl: contributor.starred_url, + subscriptionsUrl: contributor.subscriptions_url, + organizationsUrl: contributor.organizations_url, + reposUrl: contributor.repos_url, + eventsUrl: contributor.events_url, + receivedEventsUrl: contributor.received_events_url, + type: contributor.type, + siteAdmin: contributor.site_admin, + isOwner: false, + repoId + // contributions + }) + ); + } + }); + + // now remove some contributors in db but not in fetched data + await authorsCollection + .find({ + repoId: { $eq: repoId }, + isOwner: { $eq: false }, + id: { $nin: contributorIds } + }) + .remove(); + + await Promise.all(inserts); + + return await this.getRepoContributors(repoId); + }; + + getRepoContributors = async repoId => { + this.checkInstance(); + + const authorsCollection = this.RxDB.authors; + const docs = await authorsCollection.find({ repoId: { $eq: repoId } }).exec(); + + return docs.map(doc => doc.toJSON()); + }; + + recordReposCount = async count => { + this.checkInstance(); + + const settingsCollection = this.RxDB.settings; + const doc = await settingsCollection.findOne({ id: { $eq: "reposCount" } }).exec(); + const oldCount = doc ? parseInt(doc.value, 10) : 0; + + if (doc) { + doc.value = count.toString(); + await doc.save(); + } else { + settingsCollection.upsert({ + id: "reposCount", + value: count.toString() + }); + } + + return count - oldCount; + }; + + upsertLanguages = async repos => { + this.checkInstance(); + + let langsCollection = this.RxDB.languages; + + // await langsCollection.find().remove() // clean the collection + + let langs: { [key: string]: string[] } = { + _Unknown: [] + }; + repos.forEach(repo => { + if (!repo.language) { + langs._Unknown.push(repo.id); + } else { + if (langs["_" + repo.language]) { + langs["_" + repo.language].push(repo.id); + } else { + langs["_" + repo.language] = [repo.id]; + } + } + }); + + let inserts: any[] = []; + let index = 1; + for (let key in langs) { + if (langs.hasOwnProperty(key)) { + inserts.push( + langsCollection.upsert({ + key: key.substr(1).toLowerCase(), + id: index, + name: key.substr(1), + repos: langs[key] + }) + ); + index++; + } + } + + return Promise.all(inserts); + }; + + getLanguages = async () => { + this.checkInstance(); + + let langsCollection = this.RxDB.languages; + + let query = langsCollection.find(); + + let docs = await query.exec(); + + let languages: any[] = []; + + docs.forEach(doc => { + let language = doc.toJSON(); + language.reposCount = doc.countRepos(); + languages.push(language); + }); + + return languages; + }; + + getCategories = async () => { + this.checkInstance(); + + let catsCollection = this.RxDB.categories; + + let query = catsCollection.find(); + + let docs = await query.exec(); + + let categories: any[] = []; + + docs.forEach(doc => { + let category = doc.toJSON(); + category.reposCount = doc.countRepos(); + categories.push(category); + }); + + return categories; + }; + + upsertCategory = async name => { + this.checkInstance(); + + let catsCollection = this.RxDB.categories; + + // let exist = await catsCollection.findOne({name: {$eq: name}}).exec() + + const regKey = "^" + name + "$"; + let exist = await catsCollection + .findOne({ name: { $regex: new RegExp(regKey, "i") } }) + .exec(); + + if (exist) { + throw new Error("Duplicative category name"); + } + + let docs = await catsCollection + .find() + .sort({ id: -1 }) + .limit(1) + .exec(); + const start = docs instanceof Array && docs.length > 0 ? docs[0].id + 1 : 1; + const date = new Date(); + + const category = { + key: start.toString(), + id: start, + name: name, + repos: [], + createdAt: date.toISOString(), + createdTime: Math.floor(date.getTime() / 1000) + }; + + let upsert = await catsCollection.upsert(category); + + return upsert; + }; + + deleteCategory = async id => { + this.checkInstance(); + + let catsCollection = this.RxDB.categories; + + try { + await catsCollection.find({ id: { $eq: id } }).remove(); + return id; + } catch (err) { + throw new Error(err); + } + }; + + _upsertTag = async name => { + // private, return RxDoc + this.checkInstance(); + + let tagsCollection = this.RxDB.tags; + + const regKey = "^" + name + "$"; + let exist = await tagsCollection + .findOne({ name: { $regex: new RegExp(regKey, "i") } }) + .exec(); + + if (exist) { + return exist; + } + + let docs = await tagsCollection + .find() + .sort({ id: -1 }) + .limit(1) + .exec(); + const start = docs instanceof Array && docs.length > 0 ? docs[0].id + 1 : 1; + const date = new Date(); + + const tag = { + key: start.toString(), + id: start, + name: name, + repos: [], + createdAt: date.toISOString(), + createdTime: Math.floor(date.getTime() / 1000) + }; + + let upsert = await tagsCollection.upsert(tag); + + return upsert; + }; + + getTags = async tagIds => { + this.checkInstance(); + + const tagsCollection = this.RxDB.tags; + const docs = await tagsCollection + .find({ id: { $in: tagIds } }) + .sort({ id: 1 }) + .exec(); + return docs.map(doc => doc.toJSON()); + }; + + getRepoTags = async repoId => { + this.checkInstance(); + + const tagsCollection = this.RxDB.tags; + const docs = await tagsCollection + .find({ repos: { $elemMatch: { $eq: repoId } } }) + .sort({ id: 1 }) + .exec(); + + return docs.map(doc => doc.toJSON()); + }; + + getRepoCategories = async repoId => { + this.checkInstance(); + + const catsCollection = this.RxDB.categories; + const docs = await catsCollection + .find({ repos: { $elemMatch: { $eq: repoId } } }) + .sort({ id: 1 }) + .exec(); + + return docs.map(doc => doc.toJSON()); + }; + + updateRepo = async obj => { + this.checkInstance(); + + if (!obj.id) { + return false; + } + + const reposCollection = this.RxDB.repos; + const id = obj.id; + let repo = await reposCollection.findOne({ id: { $eq: id } }).exec(); + if (!repo) { + throw new Error("The specified repo is not exist"); + } + + for (let prop in obj) { + if (prop !== "id" && obj.hasOwnProperty(prop)) { + repo[prop] = obj[prop]; // TODO validate the prop existed in schema + } + } + + repo.rxChange = Math.floor(new Date().getTime() / 1000); + await repo.save(); + + return repo.toJSON(); + }; + + updateRepoCategories = async (id, catIds) => { + this.checkInstance(); + + const catsCollection = this.RxDB.categories; + const categoryDocs = await catsCollection + .find({ id: { $in: catIds } }) + .sort({ id: 1 }) + .exec(); + + let updates: any[] = []; + let categories: any[] = []; + categoryDocs.forEach(categoryDoc => { + if (categoryDoc.repos.indexOf(id) < 0) { + let repoIds = categoryDoc.repos; + repoIds.push(id); + categoryDoc.repos = repoIds; + categoryDoc.updatedTime = Math.floor(new Date().getTime() / 1000); + updates.push(categoryDoc.save()); + } + categories.push(categoryDoc.toJSON()); + }); + + await Promise.all(updates); + const repo = await this.RxDB.repos.findOne({ id: { $eq: id } }).exec(); + + let repoObj = repo.toJSON(); + repoObj._categories = categories; + + return repoObj; + }; + + addRepoTag = async (id, tagName) => { + this.checkInstance(); + + const reposCollection = this.RxDB.repos; + let repo = await reposCollection.findOne({ id: { $eq: id } }).exec(); + if (!repo) { + throw new Error("The specified repo is not exist"); + } + + // fisrt upsert this tag into tags collection + let tag = await this._upsertTag(tagName); + let repoIds = tag.repos; + + if (repoIds.indexOf(id) < 0) { + repoIds.push(id); + } + + tag.repos = repoIds; + tag.updatedTime = Math.floor(new Date().getTime() / 1000); + await tag.save(); + + const repoTags = await this.getRepoTags(id); + let repoObj = repo.toJSON(); + repoObj._tags = repoTags; + + return repoObj; + }; + + removeRepoTag = async (id, tagName) => { + this.checkInstance(); + + const reposCollection = this.RxDB.repos; + let repo = await reposCollection.findOne({ id: { $eq: id } }).exec(); + if (!repo) { + throw new Error("The specified repo is not exist"); + } + + // fisrt get the tag + const tag = await this._upsertTag(tagName); + let repoIds = tag.repos; + if (repoIds instanceof Array) { + const repoIdIndex = repoIds.indexOf(id); + if (repoIdIndex > -1) { + repoIds.splice(repoIdIndex, 1); + } + } + tag.repos = repoIds; + tag.updatedTime = Math.floor(new Date().getTime() / 1000); + await tag.save(); + + const repoTags = await this.getRepoTags(id); + let repoObj = repo.toJSON(); + repoObj._tags = repoTags; + + return repoObj; + }; +} diff --git a/src/renderer/rxdb/schemas/authorSchema.ts b/src/renderer/rxdb/schemas/authorSchema.ts new file mode 100644 index 0000000..3d7e919 --- /dev/null +++ b/src/renderer/rxdb/schemas/authorSchema.ts @@ -0,0 +1,74 @@ +const authorSchema = { + title: "author schema", + description: "describes a single repository owner/other contributors", + version: 0, + type: "object", + properties: { + key: { + type: "string", + primary: true + }, + id: { + type: "integer", + index: true + }, + login: { + type: "string", + index: true + }, + isOwner: { + type: "boolean" // owner / other contributor + }, + repoId: { + type: "integer" + }, + avatarUrl: { + type: "string" + }, + gravatarId: { + type: "string" + }, + url: { + type: "string" + }, + htmlUrl: { + type: "string" + }, + followersUrl: { + type: "string" + }, + followingUrl: { + type: "string" + }, + gistsUrl: { + type: "string" + }, + starredUrl: { + type: "string" + }, + subscriptionsUrl: { + type: "string" + }, + organizationsUrl: { + type: "string" + }, + reposUrl: { + type: "string" + }, + eventsUrl: { + type: "string" + }, + receivedEventsUrl: { + type: "string" + }, + type: { + type: "string" + }, + siteAdmin: { + type: "boolean" + } + }, + required: ["id", "login"] +}; + +export default authorSchema; diff --git a/src/renderer/rxdb/schemas/categorySchema.ts b/src/renderer/rxdb/schemas/categorySchema.ts new file mode 100644 index 0000000..4d02b3b --- /dev/null +++ b/src/renderer/rxdb/schemas/categorySchema.ts @@ -0,0 +1,42 @@ +const SCCategorySchema = { + title: "SC Category schema", + description: "describes a single SC category", + version: 0, + type: "object", + properties: { + key: { + type: "string", + primary: true // just string of id + }, + id: { + type: "integer", + index: true + }, + name: { + type: "string" + }, + description: { + type: "string" + }, + repos: { + type: "array", + uniqueItems: true, + item: "integer" + }, + createdAt: { + type: "string" + }, + createdTime: { + type: "integer" + }, + updatedAt: { + type: "string" + }, + updatedTime: { + type: "integer" + } + }, + required: ["id", "name"] +}; + +export default SCCategorySchema; diff --git a/src/renderer/rxdb/schemas/languageSchema.ts b/src/renderer/rxdb/schemas/languageSchema.ts new file mode 100644 index 0000000..d5fb05c --- /dev/null +++ b/src/renderer/rxdb/schemas/languageSchema.ts @@ -0,0 +1,30 @@ +const LanguageSchema = { + title: "SC Language schema", + description: "describes a single language", + version: 0, + type: "object", + properties: { + key: { + type: "string", + primary: true // just string of id + }, + id: { + type: "integer", + index: true + }, + name: { + type: "string" + }, + description: { + type: "string" + }, + repos: { + type: "array", + uniqueItems: true, + item: "integer" + } + }, + required: ["id", "name"] +}; + +export default LanguageSchema; diff --git a/src/renderer/rxdb/schemas/meSchema.ts b/src/renderer/rxdb/schemas/meSchema.ts new file mode 100644 index 0000000..502fac5 --- /dev/null +++ b/src/renderer/rxdb/schemas/meSchema.ts @@ -0,0 +1,140 @@ +const meSchema = { + title: "me schema", + description: "describes me (current logged user)", + version: 0, + type: "object", + properties: { + key: { + type: "string", + primary: true // juse string of id + }, + id: { + type: "integer" + }, + login: { + type: "string" + }, + avatarUrl: { + type: "string" + }, + gravatarId: { + type: "string" + }, + url: { + type: "string" + }, + htmlUrl: { + type: "string" + }, + followersUrl: { + type: "string" + }, + followingUrl: { + type: "string" + }, + gistsUrl: { + type: "string" + }, + starredUrl: { + type: "string" + }, + subscriptionsUrl: { + type: "string" + }, + organizationsUrl: { + type: "string" + }, + reposUrl: { + type: "string" + }, + eventsUrl: { + type: "string" + }, + receivedEventsUrl: { + type: "string" + }, + type: { + type: "string" + }, + siteAdmin: { + type: "boolean" + }, + name: { + type: "string" + }, + company: { + type: "string" + }, + blog: { + type: "string" + }, + location: { + type: "string" + }, + hireable: { + type: "boolean" + }, + publicRepos: { + type: "integer" + }, + publicGists: { + type: "integer" + }, + followers: { + type: "integer" + }, + following: { + type: "integer" + }, + createdAt: { + type: "string" + }, + createdTime: { + type: "integer" + }, + updatedAt: { + type: "string" + }, + updatedTime: { + type: "integer" + }, + privateGists: { + type: "integer" + }, + totalPrivateRepos: { + type: "integer" + }, + ownedPrivateRepos: { + type: "integer" + }, + diskUsage: { + type: "integer" + }, + collaborators: { + type: "integer" + }, + twoFactorAuthentication: { + type: "boolean" + }, + plan: { + type: "object", + properties: { + name: { + type: "string" + }, + space: { + type: "integer" + }, + collaborators: { + type: "integer" + }, + privateRepos: { + type: "integer" + } + } + } + }, + required: ["id"] +}; + +export default meSchema; diff --git a/src/renderer/rxdb/schemas/repoSchema.ts b/src/renderer/rxdb/schemas/repoSchema.ts new file mode 100644 index 0000000..fa2b4fc --- /dev/null +++ b/src/renderer/rxdb/schemas/repoSchema.ts @@ -0,0 +1,294 @@ +const repoSchema = { + title: "repository schema", + description: "describes a single repository", + version: 0, + type: "object", + properties: { + key: { + type: "string", + primary: true // juse string of id + }, + id: { + type: "integer", + index: true + }, + name: { + type: "string" + }, + fullName: { + type: "string" + }, + owner: { + type: "integer" + }, + private: { + type: "boolean" + }, + htmlUrl: { + type: "string" + }, + description: { + type: "string" + }, + fork: { + type: "boolean" + }, + url: { + type: "string" + }, + forksUrl: { + type: "string" + }, + keysUrl: { + type: "string" + }, + collaboratorsUrl: { + type: "string" + }, + teamsUrl: { + type: "string" + }, + hooksUrl: { + type: "string" + }, + issueEventsUrl: { + type: "string" + }, + eventsUrl: { + type: "string" + }, + assigneesUrl: { + type: "string" + }, + branchesUrl: { + type: "string" + }, + tagsUrl: { + type: "string" + }, + blobsUrl: { + type: "string" + }, + gitTagsUrl: { + type: "string" + }, + gitRefsUrl: { + type: "string" + }, + treesUrl: { + type: "string" + }, + statusesUrl: { + type: "string" + }, + languagesUrl: { + type: "string" + }, + stargazersUrl: { + type: "string" + }, + contributorsUrl: { + type: "string" + }, + subscribersUrl: { + type: "string" + }, + subscriptionUrl: { + type: "string" + }, + commitsUrl: { + type: "string" + }, + gitCommitsUrl: { + type: "string" + }, + commentsUrl: { + type: "string" + }, + issueCommentUrl: { + type: "string" + }, + contentsUrl: { + type: "string" + }, + compareUrl: { + type: "string" + }, + mergesUrl: { + type: "string" + }, + archiveUrl: { + type: "string" + }, + downloadsUrl: { + type: "string" + }, + issuesUrl: { + type: "string" + }, + pullsUrl: { + type: "string" + }, + milestonesUrl: { + type: "string" + }, + notificationsUrl: { + type: "string" + }, + labelsUrl: { + type: "string" + }, + releasesUrl: { + type: "string" + }, + deploymentsUrl: { + type: "string" + }, + createdAt: { + type: "string" + }, + createdTime: { + type: "integer", + index: true + }, + updatedAt: { + type: "string" + }, + updatedTime: { + type: "integer", + index: true + }, + pushedAt: { + type: "string" + }, + pushedTime: { + type: "integer", + index: true + }, + gitUrl: { + type: "string" + }, + sshUrl: { + type: "string" + }, + cloneUrl: { + type: "string" + }, + svnUrl: { + type: "string" + }, + homePage: { + type: "string" + }, + size: { + type: "integer", + index: true + }, + stargazersCount: { + type: "integer" + }, + stars: { + type: "integer", + index: true + }, + watchersCount: { + type: "integer" + }, + lang: { + type: "string" + }, + hasIssues: { + type: "boolean" + }, + hasDownloads: { + type: "boolean" + }, + hasWiki: { + type: "boolean" + }, + hasPages: { + type: "boolean" + }, + forksCount: { + type: "integer" + }, + mirrorUrl: { + type: "string" + }, + openIssuesCount: { + type: "integer" + }, + forks: { + type: "integer", + index: true + }, + openIssues: { + type: "integer", + index: true + }, + watchers: { + type: "integer", + index: true + }, + defaultBranch: { + type: "string" + }, + permissions: { + type: "object", + properties: { + admin: { + type: "boolean" + }, + push: { + type: "boolean" + }, + pull: { + type: "boolean" + } + } + }, + score: { + type: "integer", // 0~5 + index: true + }, + flag: { + type: "boolean" + }, + read: { + type: "boolean" + }, + note: { + type: "string" + }, + defaultOrder: { + type: "integer", + index: true + }, + readme: { + type: "string" + }, + rxChange: { + // when update one field with a reference obj, rxdb doc's save method will deepEqual new doc and old one, but not works well, so we need this field with a absolute new value to speed up `doc.save()` + type: "integer" + } + }, + required: [ + "id", + "name", + "owner", + "htmlUrl", + "createdAt", + "createdTime", + "updatedAt", + "updatedTime", + "pushedAt", + "pushedTime", + "forks", + "watchers", + "stars", + "defaultBranch", + "openIssues" + ] +}; + +export default repoSchema; diff --git a/src/renderer/rxdb/schemas/settingSchema.ts b/src/renderer/rxdb/schemas/settingSchema.ts new file mode 100644 index 0000000..6a1301d --- /dev/null +++ b/src/renderer/rxdb/schemas/settingSchema.ts @@ -0,0 +1,18 @@ +const settingSchema = { + title: "setting schema", + description: "describes a app setting", + version: 0, + type: "object", + properties: { + id: { + type: "string", + primary: true + }, + value: { + type: "string" + } + }, + required: ["value"] +}; + +export default settingSchema; diff --git a/src/renderer/rxdb/schemas/tagSchema.ts b/src/renderer/rxdb/schemas/tagSchema.ts new file mode 100644 index 0000000..a0408a0 --- /dev/null +++ b/src/renderer/rxdb/schemas/tagSchema.ts @@ -0,0 +1,42 @@ +const SCTagSchema = { + title: "SC Tag schema", + description: "describes a single SC tag", + version: 0, + type: "object", + properties: { + key: { + type: "string", + primary: true // juse string of id + }, + id: { + type: "integer", + index: true + }, + name: { + type: "string" + }, + description: { + type: "string" + }, + repos: { + type: "array", + uniqueItems: true, + item: "integer" + }, + createdAt: { + type: "string" + }, + createdTime: { + type: "integer" + }, + updatedAt: { + type: "string" + }, + updatedTime: { + type: "integer" + } + }, + required: ["id"] +}; + +export default SCTagSchema; diff --git a/src/renderer/store/GlobalStore.ts b/src/renderer/store/GlobalStore.ts new file mode 100644 index 0000000..cdd97a4 --- /dev/null +++ b/src/renderer/store/GlobalStore.ts @@ -0,0 +1,16 @@ +import { observable, action } from "mobx"; +import moment from "moment"; + +export default class GlobalStore { + /** + * Network status + */ + @observable offline: boolean = false; + @observable offlineTime: number = 0; + + @action + setOffline = (offline: boolean) => { + this.offline = offline; + this.offlineTime = offline ? moment.now().valueOf() : 0; + }; +} diff --git a/src/renderer/store/index.ts b/src/renderer/store/index.ts new file mode 100644 index 0000000..4740e69 --- /dev/null +++ b/src/renderer/store/index.ts @@ -0,0 +1,9 @@ +import GlobalStore from "./GlobalStore"; + +export default function getStore() { + const store = { + global: new GlobalStore() + }; + + return store; +} diff --git a/src/renderer/utils/authentication.ts b/src/renderer/utils/authentication.ts new file mode 100644 index 0000000..c25d313 --- /dev/null +++ b/src/renderer/utils/authentication.ts @@ -0,0 +1,113 @@ +import GithubClient from "./githubClient"; +import * as EVENTS from "../../shared/events"; +import * as CONSTANTS from "../constants"; +import { ipcRenderer } from "electron"; +import Promise from "bluebird"; +import DBHandler from "../rxdb/dbHandler"; +import dbName from "./dbName"; + +export default class Authentication { + static getLocalCredentials() { + let promise = new Promise((resolve, reject) => { + let username = localStorage.getItem(CONSTANTS.LOCAL_STORAGE_USERNAME_KEY); + if (!username) { + reject(new Error("no local login record")); + } else { + ipcRenderer.send(EVENTS.GET_LOCAL_CREDENTIALS, username); + ipcRenderer.once(EVENTS.GET_LOCAL_CREDENTIALS_REPLY, (_event, arg) => { + if (!arg) { + reject(new Error("retrieve password from keychain failed")); + } + let credentials = JSON.parse(arg); + if (credentials.username && credentials.password) { + resolve(credentials); + } else { + reject(new Error("retrieve password from keychain failed")); + } + }); + } + }); + + return promise; + } + + static saveCredentialsToSystem(credentials) { + let promise = new Promise((resolve, reject) => { + localStorage.setItem(CONSTANTS.LOCAL_STORAGE_USERNAME_KEY, credentials.username); + ipcRenderer.send(EVENTS.SAVE_CREDENTIALS_TO_SYSTEM, JSON.stringify(credentials)); + ipcRenderer.once(EVENTS.SAVE_CREDENTIALS_TO_SYSTEM_REPLY, (_event, result) => { + if (result) { + resolve(credentials); + } else { + reject(new Error("save credentials to keychain failed")); + } + }); + }); + + return promise; + } + + static saveProfileToLocal(profile) { + let promise = new Promise(resolve => { + // localStorage.setItem(CONSTANTS.LOCAL_STORAGE_USER_PROFILE, JSON.stringify(profile)) + resolve(profile); + }); + + return promise; + } + + static deleteLocalCredentials() { + let promise = new Promise((resolve, reject) => { + let username = localStorage.getItem(CONSTANTS.LOCAL_STORAGE_USERNAME_KEY); + if (!username) { + resolve(""); + } else { + ipcRenderer.send(EVENTS.DELETE_LOCAL_CREDENTIALS, username); + ipcRenderer.once(EVENTS.DELETE_LOCAL_CREDENTIALS_REPLY, (_event, result) => { + result + ? resolve(username) + : reject(new Error("delete credentials from keychain failed")); + }); + } + }); + + return promise; + } + + static signInApp(credentials) { + let githubClient = new GithubClient(credentials); + return githubClient + .getMyProfile() + .then(profile => { + // success stuff + if (profile.login === credentials.username) { + // save credentials to windows credentials + let p1 = Authentication.saveCredentialsToSystem(credentials); + let p2 = Authentication.saveProfileToLocal(profile); + // init rxdb and save profile to db + const dbHandler = new DBHandler(dbName(credentials.username)); + let p3 = dbHandler.initDB().then(() => dbHandler.upsertProfile(profile)); + + // show main window now and close login window + setTimeout(() => { + ipcRenderer.send( + EVENTS.SHOW_MAIN_WIN_AND_CLOSE_LOGIN_WIN, + JSON.stringify(credentials) + ); + }, 3000); + + return Promise.all([p1, p2, p3]).then(() => profile); + } else { + return new Error("The token you provided does not match this account"); + } + }) + .catch(err => { + return err; + }); + } + + static signOutApp() { + localStorage.removeItem(CONSTANTS.LOCAL_STORAGE_USERNAME_KEY); + return Authentication.deleteLocalCredentials(); + } +} diff --git a/src/renderer/utils/data.ts b/src/renderer/utils/data.ts new file mode 100644 index 0000000..5c7775c --- /dev/null +++ b/src/renderer/utils/data.ts @@ -0,0 +1,69 @@ +import * as EVENTS from "../../shared/events"; +import { ipcRenderer } from "electron"; +import Promise from "bluebird"; + +export const starsDataExportHandler = db => { + return new Promise((resolve, reject) => { + ipcRenderer.send(EVENTS.SHOW_CHOOSE_DIRECTORY_DIALOG); + ipcRenderer.once(EVENTS.SHOW_CHOOSE_DIRECTORY_DIALOG_REPLG, (_event, path) => { + if (!path) { + reject(new Error("save path is empty")); + } + db + .dump() + .then(data => { + const filePath = path + "/" + db.name + ".json"; + ipcRenderer.send( + EVENTS.EXPORT_STARS_DATA, + JSON.stringify({ + path: filePath, + data: JSON.stringify(data) + }) + ); + ipcRenderer.once(EVENTS.EXPORT_STARS_DATA_SUCCESS_REPLY, () => { + resolve("data export successfully"); + }); + ipcRenderer.once(EVENTS.EXPORT_STARS_DATA_FAIL_REPLY, () => { + reject(new Error("data export failed")); + }); + }) + .catch(err => { + reject(new Error(err)); + }); + }); + }); +}; + +export const starsDataImportHandler = db => { + return new Promise((resolve, reject) => { + ipcRenderer.send(EVENTS.SHOW_CHOOSE_FILE_DIALOG); + ipcRenderer.once(EVENTS.SENT_IMPORT_STARS_DATA, (_event, data) => { + if (!data) { + reject(new Error("file is empty")); + } + + // clear current db first + Promise.all([ + db.repos.find().remove(), + db.authors.find().remove(), + db.me.find().remove(), + db.tags.find().remove(), + db.categories.find().remove(), + db.languages.find().remove(), + db.settings.find().remove() + ]) + .then(() => { + return db.importDump(JSON.parse(data)); + }) + .then(_data => { + resolve("data import successfully"); + }) + .catch(err => { + reject(new Error(err)); + }); + }); + ipcRenderer.once(EVENTS.READ_FILE_FAILED, () => { + reject(new Error("read file failed")); + }); + }); +}; diff --git a/src/renderer/utils/dbName.ts b/src/renderer/utils/dbName.ts new file mode 100644 index 0000000..4367306 --- /dev/null +++ b/src/renderer/utils/dbName.ts @@ -0,0 +1,5 @@ +import MD5 from "blueimp-md5"; + +export default function getDBName(username) { + return `scdb4${MD5(username)}`; // database name include username to differentiate +} diff --git a/src/renderer/utils/electronApp.ts b/src/renderer/utils/electronApp.ts new file mode 100644 index 0000000..6ec7f82 --- /dev/null +++ b/src/renderer/utils/electronApp.ts @@ -0,0 +1,10 @@ +import * as EVENTS from "../../shared/events"; +import { ipcRenderer } from "electron"; + +export const quitElectronApp = () => { + ipcRenderer.send(EVENTS.QUIT_APP); +}; + +export const restartElectronApp = () => { + ipcRenderer.send(EVENTS.RESTART_APP); +}; diff --git a/src/renderer/utils/githubClient.ts b/src/renderer/utils/githubClient.ts new file mode 100644 index 0000000..cad9221 --- /dev/null +++ b/src/renderer/utils/githubClient.ts @@ -0,0 +1,47 @@ +import GitHubApi from "github-api"; + +export default class GithubClient { + private client: GitHubApi; + private me; + + constructor(credentials) { + this.client = new GitHubApi({ + username: credentials.username, + token: credentials.password + }); + this.me = this.client.getUser(); + } + + _getRepoInstance = fullName => { + const namePieces = fullName.split("/"); + return this.client.getRepo(namePieces[0], namePieces[1]); + }; + + getMyProfile = () => { + return this.me.getProfile().then(ret => ret.data); + }; + + getStarredRepos = () => { + // return this.me.listStarredRepos() // this method only fetch repos sorted by 'updated', but we need the order of starred time desc + + // ugly hack + const user = this.me; + let requestOptions = user._getOptionsWithDefaults({ sort: "created" }); + return user._requestAllPages(user.__getScopedUrl("starred"), requestOptions, null); + }; + + starStarCabinet = () => { + const repo = this.client.getRepo("thundernet8", "StarCabinet"); + return repo.star(); + }; + + getRepoReadMe = (fullName, defaultBranch = "master") => { + const repo = this._getRepoInstance(fullName); + return repo.getReadme(defaultBranch, true).then(ret => ret.data); + }; + + getRepoContributors = fullName => { + const repo = this._getRepoInstance(fullName); + return repo.getContributors().then(ret => ret.data); + }; +} diff --git a/src/renderer/utils/logger.ts b/src/renderer/utils/logger.ts new file mode 100644 index 0000000..079f8ec --- /dev/null +++ b/src/renderer/utils/logger.ts @@ -0,0 +1,24 @@ +import moment from "moment"; + +declare var window; + +const ConsoleWrapper = { + log: (...args) => { + // only on debug mode + if (!window._DEBUG_) { + return; + } + console.log(`[${moment().format("YYYY-MM-DD HH:mm:ss")}]:`, ...args); + }, + + error: (...args) => { + // only on debug mode + if (!window._DEBUG_) { + return; + } + console.log(`[${moment().format("YYYY-MM-DD HH:mm:ss")}]:`); + console.error(...args); + } +}; + +export default ConsoleWrapper; diff --git a/src/renderer/utils/offlineTitle.ts b/src/renderer/utils/offlineTitle.ts new file mode 100644 index 0000000..1e42b9d --- /dev/null +++ b/src/renderer/utils/offlineTitle.ts @@ -0,0 +1,10 @@ +const offlineTitle = offline => { + if (offline) { + document.title += " (offline)"; + } else { + let title = document.title; + document.title = title.replace(" (offline)", ""); + } +}; + +export default offlineTitle; diff --git a/src/renderer/views/Login/index.tsx b/src/renderer/views/Login/index.tsx new file mode 100644 index 0000000..cadb66b --- /dev/null +++ b/src/renderer/views/Login/index.tsx @@ -0,0 +1,17 @@ +import * as React from "react"; + +const styles = require("./styles/index.less"); + +interface LoginViewProps {} + +interface LoginViewState {} + +export default class LoginView extends React.Component { + constructor(props) { + super(props); + } + + render() { + return
LoginView
; + } +} diff --git a/src/renderer/views/Login/styles/index.less b/src/renderer/views/Login/styles/index.less new file mode 100644 index 0000000..e69de29 diff --git a/src/renderer/views/Main/index.tsx b/src/renderer/views/Main/index.tsx new file mode 100644 index 0000000..59a599a --- /dev/null +++ b/src/renderer/views/Main/index.tsx @@ -0,0 +1,17 @@ +import * as React from "react"; + +const styles = require("./styles/index.less"); + +interface MainViewProps {} + +interface MainViewState {} + +export default class MainView extends React.Component { + constructor(props) { + super(props); + } + + render() { + return
MainView
; + } +} diff --git a/src/renderer/views/Main/styles/index.less b/src/renderer/views/Main/styles/index.less new file mode 100644 index 0000000..e69de29 diff --git a/src/renderer/views/NotFound/index.tsx b/src/renderer/views/NotFound/index.tsx new file mode 100644 index 0000000..ad99cb3 --- /dev/null +++ b/src/renderer/views/NotFound/index.tsx @@ -0,0 +1,17 @@ +import * as React from "react"; + +const styles = require("./styles/index.less"); + +interface NotFoundViewProps {} + +interface NotFoundViewState {} + +export default class NotFoundView extends React.Component { + constructor(props) { + super(props); + } + + render() { + return
NotFoundView
; + } +} diff --git a/src/renderer/views/NotFound/styles/index.less b/src/renderer/views/NotFound/styles/index.less new file mode 100644 index 0000000..e69de29 diff --git a/src/renderer/views/Setting/index.tsx b/src/renderer/views/Setting/index.tsx new file mode 100644 index 0000000..a0ffc79 --- /dev/null +++ b/src/renderer/views/Setting/index.tsx @@ -0,0 +1,17 @@ +import * as React from "react"; + +const styles = require("./styles/index.less"); + +interface SettingViewProps {} + +interface SettingViewState {} + +export default class SettingView extends React.Component { + constructor(props) { + super(props); + } + + render() { + return
SettingView
; + } +} diff --git a/src/renderer/views/Setting/styles/index.less b/src/renderer/views/Setting/styles/index.less new file mode 100644 index 0000000..e69de29 From 9e0363a5ab0bf2093fd58e9b79fe4678517576cc Mon Sep 17 00:00:00 2001 From: wuxueqian Date: Sat, 27 Jan 2018 22:48:01 +0800 Subject: [PATCH 15/25] fix login page --- package.json | 2 +- src/main/services/credentials.js | 31 ++-- src/main/windows/login.js | 4 +- src/renderer/assets/styles/login.less | 2 +- src/renderer/common/polyfill/Promise.ts | 12 ++ src/renderer/common/polyfill/index.ts | 1 + src/renderer/index.tsx | 1 + src/renderer/rxdb/dbHandler.ts | 11 +- src/renderer/store/GlobalStore.ts | 75 +++++++++ src/renderer/utils/authentication.ts | 38 ++--- src/renderer/views/Login/index.tsx | 180 ++++++++++++++++++++- src/renderer/views/Login/styles/index.less | 94 +++++++++++ tsconfig.json | 2 +- typings/index.d.ts | 3 + webpack/base.conf.babel.js | 1 + webpack/dev.conf.babel.js | 2 +- yarn.lock | 6 +- 17 files changed, 407 insertions(+), 58 deletions(-) create mode 100644 src/renderer/common/polyfill/Promise.ts create mode 100644 src/renderer/common/polyfill/index.ts create mode 100644 typings/index.d.ts diff --git a/package.json b/package.json index e249a4b..2bb0c7c 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,7 @@ "pre-commit": "lint-staged", "devDependencies": { "@types/keytar": "^4.0.1", - "@types/node": "^8.5.2", + "@types/node": "^9.4.0", "@types/react": "^16.0.31", "@types/react-router-dom": "^4.2.3", "@types/webpack-env": "^1.13.3", diff --git a/src/main/services/credentials.js b/src/main/services/credentials.js index 450b230..652d99f 100644 --- a/src/main/services/credentials.js +++ b/src/main/services/credentials.js @@ -4,20 +4,11 @@ import * as CONSTANTS from "../../shared/constants"; const keytar = require("keytar"); const mainGetLocalCredentials = username => { - let password = keytar.getPassword(CONSTANTS.APP, username); - return { - username, - password - }; + return keytar.getPassword(CONSTANTS.APP, username).then(password => ({ username, password })); }; const mainSaveCredentials = credentials => { - // return keytar.addPassword(CONSTANTS.APP, credentials.username, credentials.password) - return keytar.replacePassword( - CONSTANTS.APP, - credentials.username, - credentials.password - ); + return keytar.setPassword(CONSTANTS.APP, credentials.username, credentials.password); }; const mainDeleteCredentials = username => { @@ -26,22 +17,22 @@ const mainDeleteCredentials = username => { const handleCredentialsEvents = () => { ipcMain.on(EVENTS.GET_LOCAL_CREDENTIALS, (event, username) => { - let credentials = mainGetLocalCredentials(username); - event.sender.send( - EVENTS.GET_LOCAL_CREDENTIALS_REPLY, - JSON.stringify(credentials) - ); + mainGetLocalCredentials(username).then(credentials => { + event.sender.send(EVENTS.GET_LOCAL_CREDENTIALS_REPLY, JSON.stringify(credentials)); + }); }); ipcMain.on(EVENTS.SAVE_CREDENTIALS_TO_SYSTEM, (event, arg) => { let credentials = JSON.parse(arg); - let result = mainSaveCredentials(credentials); - event.sender.send(EVENTS.SAVE_CREDENTIALS_TO_SYSTEM_REPLY, result); + mainSaveCredentials(credentials).then(() => { + event.sender.send(EVENTS.SAVE_CREDENTIALS_TO_SYSTEM_REPLY, "ok"); + }); }); ipcMain.on(EVENTS.DELETE_LOCAL_CREDENTIALS, (event, username) => { - let result = mainDeleteCredentials(username); - event.sender.send(EVENTS.DELETE_LOCAL_CREDENTIALS_REPLY, !!result); + mainDeleteCredentials(username).then(result => { + event.sender.send(EVENTS.DELETE_LOCAL_CREDENTIALS_REPLY, !!result); + }); }); }; diff --git a/src/main/windows/login.js b/src/main/windows/login.js index e1e93da..210a152 100644 --- a/src/main/windows/login.js +++ b/src/main/windows/login.js @@ -7,8 +7,8 @@ let injectStyle = "body{background-color:transparent !important;}"; function createLoginWindow(wins) { let win = new BrowserWindow({ - width: 600, //288, - height: 800, //400, + width: 288, + height: 400, titleBarStyle: "hidden-inset", resizable: false, frame: process.platform === "darwin", // Specify false to create a Frameless Window. Default is true. diff --git a/src/renderer/assets/styles/login.less b/src/renderer/assets/styles/login.less index b25a3ca..e1ffe4d 100644 --- a/src/renderer/assets/styles/login.less +++ b/src/renderer/assets/styles/login.less @@ -6,7 +6,7 @@ left: 5px; right: 5px; bottom: 5px; - height: calc(100% - 10px); + height: ~"calc(100% - 10px)"; background: #f5f5fa; border-radius: 4px; box-shadow: 0 0 5px rgba(0, 0, 0, 0.2); diff --git a/src/renderer/common/polyfill/Promise.ts b/src/renderer/common/polyfill/Promise.ts new file mode 100644 index 0000000..bef445a --- /dev/null +++ b/src/renderer/common/polyfill/Promise.ts @@ -0,0 +1,12 @@ +Promise.prototype.finally = function(finaliser) { + return this.then( + result => { + finaliser(); + return result; + }, + reason => { + finaliser(); + throw new Error(reason); + } + ); +}; diff --git a/src/renderer/common/polyfill/index.ts b/src/renderer/common/polyfill/index.ts new file mode 100644 index 0000000..fdf4bc9 --- /dev/null +++ b/src/renderer/common/polyfill/index.ts @@ -0,0 +1 @@ +require("./Promise"); diff --git a/src/renderer/index.tsx b/src/renderer/index.tsx index 2948cba..b4f9fa6 100644 --- a/src/renderer/index.tsx +++ b/src/renderer/index.tsx @@ -4,6 +4,7 @@ import { Provider } from "mobx-react"; import MainRouter from "./routes"; import getStore from "./store"; +require("./common/polyfill"); require("./assets/styles/global/global.less"); declare var window; diff --git a/src/renderer/rxdb/dbHandler.ts b/src/renderer/rxdb/dbHandler.ts index 3ce963a..e319c20 100644 --- a/src/renderer/rxdb/dbHandler.ts +++ b/src/renderer/rxdb/dbHandler.ts @@ -1,3 +1,4 @@ +import moment from "moment"; import * as Database from "./database"; import * as CONSTANTS from "../constants"; import IRepo from "../interface/IRepo"; @@ -52,10 +53,10 @@ export default class DBHandler { type: profile.type, siteAdmin: profile.site_admin, name: profile.name, - company: profile.company, + company: profile.company || "", blog: profile.blog, location: profile.location, - hireable: profile.hireable, + hireable: !!profile.hireable, publicRepos: profile.public_repos, publicGists: profile.public_gists, followers: profile.followers, @@ -156,11 +157,11 @@ export default class DBHandler { releasesUrl: repo.releases_url, deploymentsUrl: repo.deployments_url, createdAt: repo.created_at, - createdTime: Math.floor(new Date(repo.created_at).getTime() / 1000), + createdTime: Math.floor(moment(repo.created_at).valueOf() / 1000), updatedAt: repo.updated_at, - updatedTime: Math.floor(new Date(repo.updated_at).getTime() / 1000), + updatedTime: Math.floor(moment(repo.updated_at).valueOf() / 1000), pushedAt: repo.pushed_at, - pushedTime: Math.floor(new Date(repo.pushed_at).getTime() / 1000), + pushedTime: Math.floor(moment(repo.pushed_at).valueOf() / 1000), gitUrl: repo.git_url, sshUrl: repo.ssh_url, cloneUrl: repo.clone_url, diff --git a/src/renderer/store/GlobalStore.ts b/src/renderer/store/GlobalStore.ts index cdd97a4..ed05b7e 100644 --- a/src/renderer/store/GlobalStore.ts +++ b/src/renderer/store/GlobalStore.ts @@ -1,5 +1,9 @@ import { observable, action } from "mobx"; import moment from "moment"; +import Authentication from "../utils/authentication"; +import { ICredentialsState } from "../interface/IAccount"; +import IProfile from "../interface/IProfile"; +import logger from "../utils/logger"; export default class GlobalStore { /** @@ -13,4 +17,75 @@ export default class GlobalStore { this.offline = offline; this.offlineTime = offline ? moment.now().valueOf() : 0; }; + + /** + * Login + */ + @observable credentials: ICredentialsState; + + @observable profile: IProfile; + + @observable isRequestingSignin: boolean = false; + + @action + setCredentials = (credentials: ICredentialsState) => { + this.credentials = credentials; + }; + + @action + setUsername = (username: string) => { + let { credentials } = this; + if (!credentials) { + credentials = { + username, + password: "" + }; + } else { + credentials.username = username; + } + this.credentials = Object.assign({}, credentials); + }; + + @action + setPassword = (password: string) => { + let { credentials } = this; + if (!credentials) { + credentials = { + username: "", + password + }; + } else { + credentials.password = password; + } + this.credentials = Object.assign({}, credentials); + }; + + @action + getLocalCredentials = () => { + return Authentication.getLocalCredentials() + .then(credentials => { + this.credentials = credentials; + return credentials; + }) + .catch(error => { + logger.log(error.message || error.toString()); + throw error; + }); + }; + + @action + signIn = (credentials: ICredentialsState) => { + if (this.isRequestingSignin) { + return Promise.reject(false); + } + this.isRequestingSignin = true; + return Authentication.signInApp(credentials) + .then(profile => { + this.profile = profile; + return profile; + }) + .finally(() => { + this.isRequestingSignin = false; + }); + }; } diff --git a/src/renderer/utils/authentication.ts b/src/renderer/utils/authentication.ts index c25d313..93c9697 100644 --- a/src/renderer/utils/authentication.ts +++ b/src/renderer/utils/authentication.ts @@ -2,13 +2,14 @@ import GithubClient from "./githubClient"; import * as EVENTS from "../../shared/events"; import * as CONSTANTS from "../constants"; import { ipcRenderer } from "electron"; -import Promise from "bluebird"; import DBHandler from "../rxdb/dbHandler"; import dbName from "./dbName"; +import { ICredentialsState } from "../interface/IAccount"; +import IProfile from "../interface/IProfile"; export default class Authentication { - static getLocalCredentials() { - let promise = new Promise((resolve, reject) => { + static getLocalCredentials(): Promise { + return new Promise((resolve, reject) => { let username = localStorage.getItem(CONSTANTS.LOCAL_STORAGE_USERNAME_KEY); if (!username) { reject(new Error("no local login record")); @@ -27,12 +28,10 @@ export default class Authentication { }); } }); - - return promise; } - static saveCredentialsToSystem(credentials) { - let promise = new Promise((resolve, reject) => { + static saveCredentialsToSystem(credentials): Promise { + return new Promise((resolve, reject) => { localStorage.setItem(CONSTANTS.LOCAL_STORAGE_USERNAME_KEY, credentials.username); ipcRenderer.send(EVENTS.SAVE_CREDENTIALS_TO_SYSTEM, JSON.stringify(credentials)); ipcRenderer.once(EVENTS.SAVE_CREDENTIALS_TO_SYSTEM_REPLY, (_event, result) => { @@ -43,21 +42,17 @@ export default class Authentication { } }); }); - - return promise; } - static saveProfileToLocal(profile) { - let promise = new Promise(resolve => { + static saveProfileToLocal(profile): Promise { + return new Promise(resolve => { // localStorage.setItem(CONSTANTS.LOCAL_STORAGE_USER_PROFILE, JSON.stringify(profile)) resolve(profile); }); - - return promise; } - static deleteLocalCredentials() { - let promise = new Promise((resolve, reject) => { + static deleteLocalCredentials(): Promise { + return new Promise((resolve, reject) => { let username = localStorage.getItem(CONSTANTS.LOCAL_STORAGE_USERNAME_KEY); if (!username) { resolve(""); @@ -65,22 +60,20 @@ export default class Authentication { ipcRenderer.send(EVENTS.DELETE_LOCAL_CREDENTIALS, username); ipcRenderer.once(EVENTS.DELETE_LOCAL_CREDENTIALS_REPLY, (_event, result) => { result - ? resolve(username) + ? resolve(username || "") : reject(new Error("delete credentials from keychain failed")); }); } }); - - return promise; } - static signInApp(credentials) { + static signInApp(credentials): Promise { let githubClient = new GithubClient(credentials); return githubClient .getMyProfile() .then(profile => { // success stuff - if (profile.login === credentials.username) { + if (profile && profile.login === credentials.username) { // save credentials to windows credentials let p1 = Authentication.saveCredentialsToSystem(credentials); let p2 = Authentication.saveProfileToLocal(profile); @@ -101,8 +94,9 @@ export default class Authentication { return new Error("The token you provided does not match this account"); } }) - .catch(err => { - return err; + .catch(error => { + console.log(error); + throw error; }); } diff --git a/src/renderer/views/Login/index.tsx b/src/renderer/views/Login/index.tsx index cadb66b..739b29d 100644 --- a/src/renderer/views/Login/index.tsx +++ b/src/renderer/views/Login/index.tsx @@ -1,17 +1,193 @@ import * as React from "react"; +import { observer, inject } from "mobx-react"; +import ClassNames from "classnames"; +import { ipcRenderer } from "electron"; +import { Input, Icon, Button, message } from "antd"; +import IStore from "../../interface/IStore"; +import * as EVENTS from "../../../shared/events"; +import * as CONSTANTS from "../../../shared/constants"; + +message.config({ + top: 60, + duration: 5 +}); const styles = require("./styles/index.less"); -interface LoginViewProps {} +interface LoginViewProps { + store?: IStore; +} interface LoginViewState {} +@inject("store") +@observer export default class LoginView extends React.Component { + private userNameInput: HTMLInputElement; + private passwordInput: HTMLInputElement; + constructor(props) { super(props); } + refUsernameInput = input => { + this.userNameInput = input; + }; + + refPasswordInput = input => { + this.passwordInput = input; + }; + + emitUsernameEmpty = () => { + const store = this.props.store!.global; + if (store.isRequestingSignin) { + return; + } + this.userNameInput.focus(); + store.setUsername(""); + }; + + emitPasswordEmpty = () => { + const store = this.props.store!.global; + if (store.isRequestingSignin) { + return; + } + this.passwordInput.focus(); + store.setPassword(""); + }; + + onInputUsername = e => { + const store = this.props.store!.global; + store.setUsername(e.target.value); + }; + + onInputPassword = e => { + const store = this.props.store!.global; + store.setPassword(e.target.value); + }; + + onSubmit = () => { + const store = this.props.store!.global; + if (store.isRequestingSignin) { + return; + } + this.setState({ submitting: true }); + store + .signIn(store.credentials) + .then(profile => { + if (profile) { + message.success("Login successfully"); + } + }) + .catch(error => { + message.error(error.message || error.toString()); + }); + }; + + closeLoginWindow() { + ipcRenderer.sendSync(EVENTS.CLOSE_LOGIN, ""); + } + + componentWillMount() { + const store = this.props.store!.global; + store + .getLocalCredentials() + .then(credentials => { + if (credentials) { + return store.signIn(credentials); + } + return null as any; + }) + .then(profile => { + if (profile) { + message.success("Login successfully"); + } + }) + .catch(error => { + message.error(error.message || error.toString()); + }); + } + render() { - return
LoginView
; + const { credentials, profile, isRequestingSignin } = this.props.store!.global; + const username = credentials ? credentials.username : ""; + const password = credentials ? credentials.password : ""; + const usernameSuffix = username ? ( + + ) : null; + const passwordSuffix = password ? ( + + ) : null; + + const btnDisabled = !username || !password || username.length < 2 || password.length < 5; + const avatar = profile ? profile.avatar_url : require("../../assets/images/icon.png"); + + return ( +
+
+
{CONSTANTS.APP}
+ + + + +
+
+ + {profile && ( +
+ {profile.name} +
+ )} +
+ {!profile && ( +
+
+ } + suffix={usernameSuffix} + value={username} + onChange={this.onInputUsername} + disabled={isRequestingSignin} + ref={this.refUsernameInput} + /> +
+
+ } + suffix={passwordSuffix} + value={password} + onChange={this.onInputPassword} + onPressEnter={this.onSubmit} + disabled={isRequestingSignin} + ref={this.refPasswordInput} + /> +
+
+ +
+
+ )} +
+ ); } } diff --git a/src/renderer/views/Login/styles/index.less b/src/renderer/views/Login/styles/index.less index e69de29..13b587e 100644 --- a/src/renderer/views/Login/styles/index.less +++ b/src/renderer/views/Login/styles/index.less @@ -0,0 +1,94 @@ +// Login Page + +.container { + position: absolute; + top: 5px; + left: 5px; + right: 5px; + bottom: 5px; + height: ~"calc(100% - 10px)"; + background: #f5f5fa; + border-radius: 4px; + box-shadow: 0 0 5px rgba(0, 0, 0, 0.2); + + > header { + -webkit-app-region: drag; + width: 260px; + height: 36px; + padding: 8px 10px; + line-height: 20px; + color: #343536; + font-size: 15px; + + > div { + display: inline-block; + } + } +} + +.close { + position: fixed; + display: inline-block; + width: 12px; + height: 12px; + top: 10px; + right: 10px; + cursor: pointer; + > i { + position: absolute; + display: inline-block; + width: 14px; + height: 1px; + background: #bbb; + top: 5px; + left: 0; + transform-origin: center; + transform: rotate(45deg); + &:last-child { + transform: rotate(-45deg); + } + } + &:hover { + > i { + background: #666; + } + } +} + +.logoWrapper { + position: relative; + padding: 30px 0; + height: 132px; +} + +.logo { + -webkit-user-drag: none; + width: 72px; + height: 72px; + position: absolute; + top: 30px; + left: 50%; + margin-left: -36px; + border-radius: 50%; +} + +.logoLogged { + top: 100px; + transform: scale(1.2); +} + +.name { + position: absolute; + top: 200px; + width: 100%; + font-size: 16px; + opacity: 0; +} + +.loginBox { + padding: 10px 20px; +} + +.loginBtn { + width: 100%; +} diff --git a/tsconfig.json b/tsconfig.json index 3180b9c..29adebe 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -13,5 +13,5 @@ "baseUrl": "./src", "allowJs": false }, - "exclude": ["node_modules", "dist", "**/*.spec.ts?", "**/*.d.ts"] + "exclude": ["node_modules", "dist", "**/*.spec.ts?"] } diff --git a/typings/index.d.ts b/typings/index.d.ts new file mode 100644 index 0000000..45277d9 --- /dev/null +++ b/typings/index.d.ts @@ -0,0 +1,3 @@ +interface Promise { + finally: (callback) => Promise; +} diff --git a/webpack/base.conf.babel.js b/webpack/base.conf.babel.js index e76b95c..b0c59e4 100644 --- a/webpack/base.conf.babel.js +++ b/webpack/base.conf.babel.js @@ -111,6 +111,7 @@ export default function(morePlugins, moreRules) { }, modules: ["node_modules", path.resolve(__dirname, "../src/renderer")] }, + target: "electron", module: { rules: getRules(moreRules) }, diff --git a/webpack/dev.conf.babel.js b/webpack/dev.conf.babel.js index 3d11d1e..a8b62c7 100644 --- a/webpack/dev.conf.babel.js +++ b/webpack/dev.conf.babel.js @@ -57,7 +57,7 @@ config.devServer = { host: "localhost", port: 9001, hot: true, - open: true, + open: false, historyApiFallback: { index: "index.html" } diff --git a/yarn.lock b/yarn.lock index 47c7583..9358020 100644 --- a/yarn.lock +++ b/yarn.lock @@ -33,9 +33,9 @@ version "7.0.52" resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.52.tgz#8990d3350375542b0c21a83cd0331e6a8fc86716" -"@types/node@^8.5.2": - version "8.5.2" - resolved "https://registry.yarnpkg.com/@types/node/-/node-8.5.2.tgz#83b8103fa9a2c2e83d78f701a9aa7c9539739aa5" +"@types/node@^9.4.0": + version "9.4.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-9.4.0.tgz#b85a0bcf1e1cc84eb4901b7e96966aedc6f078d1" "@types/react-router-dom@^4.2.3": version "4.2.3" From 174307570c528a130b377f1165c8d67e9fdd64aa Mon Sep 17 00:00:00 2001 From: wuxueqian Date: Sun, 28 Jan 2018 17:43:55 +0800 Subject: [PATCH 16/25] restore nav pane --- src/renderer/assets/styles/login.less | 94 ------- src/renderer/assets/styles/main.less | 166 +----------- src/renderer/components/FilterBar/index.tsx | 17 ++ .../components/MainDetailPane/index.tsx | 40 +++ .../MainDetailPane/styles/index.less | 6 + .../components/MainGroupAvatar/index.tsx | 56 ++++ .../MainGroupAvatar/styles/index.less | 20 ++ .../components/MainGroupFooter/index.tsx | 146 +++++++++++ .../MainGroupFooter/styles/index.less | 35 +++ .../components/MainGroupNavs/index.tsx | 96 +++++++ .../MainGroupNavs/styles/index.less | 39 +++ .../components/MainGroupPane/index.tsx | 31 +++ .../MainGroupPane/styles/index.less | 8 + .../components/MainListPane/index.tsx | 29 +++ .../components/MainListPane/styles/index.less | 9 + .../components/RefreshIndicator/index.tsx | 86 ++++++ .../RefreshIndicator/styles/index.less | 16 ++ src/renderer/components/RepoDetail/index.tsx | 17 ++ .../components/RepoDetailToolbar/index.tsx | 20 ++ src/renderer/components/ReposList/index.tsx | 17 ++ src/renderer/components/SearchBox/index.tsx | 17 ++ src/renderer/components/SortBar/index.tsx | 17 ++ src/renderer/constants/index.ts | 23 -- src/renderer/enum/GroupType.ts | 9 + src/renderer/enum/OrderBy.ts | 15 ++ src/renderer/enum/SearchType.ts | 11 + src/renderer/interface/IStore.ts | 4 +- src/renderer/rxdb/database.ts | 6 +- src/renderer/rxdb/dbHandler.ts | 21 +- src/renderer/store/GlobalStore.ts | 64 +++++ src/renderer/store/MainStore.ts | 246 ++++++++++++++++++ src/renderer/store/index.ts | 5 +- src/renderer/utils/authentication.ts | 10 +- src/renderer/utils/githubClient.ts | 2 +- src/renderer/views/Main/index.tsx | 15 +- src/renderer/views/Main/styles/index.less | 21 ++ 36 files changed, 1131 insertions(+), 303 deletions(-) delete mode 100644 src/renderer/assets/styles/login.less create mode 100644 src/renderer/components/FilterBar/index.tsx create mode 100644 src/renderer/components/MainDetailPane/index.tsx create mode 100644 src/renderer/components/MainDetailPane/styles/index.less create mode 100644 src/renderer/components/MainGroupAvatar/index.tsx create mode 100644 src/renderer/components/MainGroupAvatar/styles/index.less create mode 100644 src/renderer/components/MainGroupFooter/index.tsx create mode 100644 src/renderer/components/MainGroupFooter/styles/index.less create mode 100644 src/renderer/components/MainGroupNavs/index.tsx create mode 100644 src/renderer/components/MainGroupNavs/styles/index.less create mode 100644 src/renderer/components/MainGroupPane/index.tsx create mode 100644 src/renderer/components/MainGroupPane/styles/index.less create mode 100644 src/renderer/components/MainListPane/index.tsx create mode 100644 src/renderer/components/MainListPane/styles/index.less create mode 100644 src/renderer/components/RefreshIndicator/index.tsx create mode 100644 src/renderer/components/RefreshIndicator/styles/index.less create mode 100644 src/renderer/components/RepoDetail/index.tsx create mode 100644 src/renderer/components/RepoDetailToolbar/index.tsx create mode 100644 src/renderer/components/ReposList/index.tsx create mode 100644 src/renderer/components/SearchBox/index.tsx create mode 100644 src/renderer/components/SortBar/index.tsx create mode 100644 src/renderer/enum/GroupType.ts create mode 100644 src/renderer/enum/OrderBy.ts create mode 100644 src/renderer/enum/SearchType.ts create mode 100644 src/renderer/store/MainStore.ts diff --git a/src/renderer/assets/styles/login.less b/src/renderer/assets/styles/login.less deleted file mode 100644 index e1ffe4d..0000000 --- a/src/renderer/assets/styles/login.less +++ /dev/null @@ -1,94 +0,0 @@ -// Login Page - -.wrapper { - position: absolute; - top: 5px; - left: 5px; - right: 5px; - bottom: 5px; - height: ~"calc(100% - 10px)"; - background: #f5f5fa; - border-radius: 4px; - box-shadow: 0 0 5px rgba(0, 0, 0, 0.2); - - > header { - -webkit-app-region: drag; - width: 260px; - height: 36px; - padding: 8px 10px; - line-height: 20px; - color: #343536; - font-size: 15px; - - > div { - display: inline-block; - } - } -} - -.close { - position: fixed; - display: inline-block; - width: 12px; - height: 12px; - top: 10px; - right: 10px; - cursor: pointer; - > i { - position: absolute; - display: inline-block; - width: 14px; - height: 1px; - background: #bbb; - top: 5px; - left: 0; - transform-origin: center; - transform: rotate(45deg); - &:last-child { - transform: rotate(-45deg); - } - } - &:hover { - > i { - background: #666; - } - } -} - -.logoWrapper { - position: relative; - padding: 30px 0; - height: 132px; -} - -.logo { - -webkit-user-drag: none; - width: 72px; - height: 72px; - position: absolute; - top: 30px; - left: 50%; - margin-left: -36px; - border-radius: 50%; -} - -.logoLogged { - top: 100px; - transform: scale(1.2); -} - -.name { - position: absolute; - top: 200px; - width: 100%; - font-size: 16px; - opacity: 0; -} - -.loginBox { - padding: 10px 20px; -} - -.loginBtn { - width: 100%; -} diff --git a/src/renderer/assets/styles/main.less b/src/renderer/assets/styles/main.less index edc002e..8b31b50 100644 --- a/src/renderer/assets/styles/main.less +++ b/src/renderer/assets/styles/main.less @@ -1,51 +1,3 @@ -.main { - height: 100%; - overflow: hidden; - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; - font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", - "Helvetica Neue", Helvetica, Arial, sans-serif; - font-size: 14px; - line-height: 1.5; -} - -.container { - display: flex; - position: relative; - width: 100%; - height: 100%; - //border-top: 1px solid rgba(186, 208, 223, 0.36); -} - -.left { - position: relative; - width: 200px; - height: 100%; - background-color: rgba(39, 49, 67, 1); - // border-right: 1px solid rgba(186,208,223,0.72); - color: rgba(204, 204, 204, 1); -} - -.mid { - position: relative; - width: 300px; - height: 100%; - background-color: #fbfbfb; - border-right: 1px solid rgba(229, 229, 229, 1); - display: flex; - flex-direction: column; -} - -.right { - position: relative; - flex: 1; - height: 100%; - background-color: #fff; // rgba(246, 246, 247, 1); -} - .detailContent { height: 100%; background-repeat: no-repeat; @@ -55,120 +7,6 @@ padding-bottom: 40px; } -.indicatorWrap { - position: relative; - width: 100%; - height: 36px; -} - -.indicator { - position: absolute; - top: 12px; - right: 12px; - display: inline-block; - width: 14px; - height: 14px; - font-size: 14px; - cursor: pointer; -} - -.profileCard { - width: 100%; - text-align: center; - padding: 15px 0; -} - -.profileAvatar { - display: block; - margin: 0 auto; - width: 50px; - height: 50px; - border-radius: 50%; -} - -.profileName { - color: #eee; - font-size: 14px; - line-height: 1.5; - margin-top: 5px; -} - -.groupNav { - position: relative; -} - -.langItem { - padding-right: 32px !important; -} - -.catItem { - padding-right: 32px !important; - - &:hover { - .navDel { - opacity: 1; - } - } -} - -.navDel { - position: absolute; - top: 0; - left: 25px; - text-align: left; - padding: 0; - font-size: 12px; - line-height: 42px; - opacity: 0; -} - -.navBadge { - position: absolute; - top: 0; - right: 10px; - text-align: right; - padding: 0 6px; - font-size: 14px; - line-height: 42px; - color: #fafafa; -} - -.groupFooter { - position: absolute; - width: 100%; - height: 36px; - left: 0; - bottom: 0; -} - -.settingBtn { - width: 16px; - height: 16px; - font-size: 15px; - position: absolute; - top: 5px; - left: 16px; - cursor: pointer; - &:hover { - color: #eee; - } -} - -.addCatBtn { - width: 16px; - height: 16px; - font-size: 16px; - position: absolute; - top: 5px; - right: 16px; - transition: all 0.3s ease; - cursor: pointer; - &:hover { - color: #eee; - transform: rotate(90deg); - } -} - .searchBox { padding: 12px 10px; > span { @@ -500,8 +338,8 @@ } > .repoReadme { position: relative; - font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", - "Helvetica Neue", Helvetica, Arial, sans-serif !important; + font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", + Helvetica, Arial, sans-serif !important; font-size: 100%; } } diff --git a/src/renderer/components/FilterBar/index.tsx b/src/renderer/components/FilterBar/index.tsx new file mode 100644 index 0000000..096955f --- /dev/null +++ b/src/renderer/components/FilterBar/index.tsx @@ -0,0 +1,17 @@ +import * as React from "react"; + +// const styles = require("./index.less"); + +interface FilterBarProps {} + +interface FilterBarState {} + +export default class FilterBar extends React.Component { + constructor(props) { + super(props); + } + + render() { + return
FilterBar
; + } +} diff --git a/src/renderer/components/MainDetailPane/index.tsx b/src/renderer/components/MainDetailPane/index.tsx new file mode 100644 index 0000000..bc6d278 --- /dev/null +++ b/src/renderer/components/MainDetailPane/index.tsx @@ -0,0 +1,40 @@ +import * as React from "react"; +import ClassNames from "classnames"; +import RepoDetailToolbar from "../RepoDetailToolbar"; +import RepoDetail from "../RepoDetail"; + +const githubBg = require("../../assets/images/github-gray.png"); + +const styles = require("./styles/index.less"); + +interface MainDetailPaneProps {} + +interface MainDetailPaneState {} + +export default class MainDetailPane extends React.Component< + MainDetailPaneProps, + MainDetailPaneState +> { + constructor(props) { + super(props); + } + + render() { + return ( +
+
+ +
+
+ +
+
+ ); + } +} diff --git a/src/renderer/components/MainDetailPane/styles/index.less b/src/renderer/components/MainDetailPane/styles/index.less new file mode 100644 index 0000000..b0f69db --- /dev/null +++ b/src/renderer/components/MainDetailPane/styles/index.less @@ -0,0 +1,6 @@ +.right { + position: relative; + flex: 1; + height: 100%; + background-color: #fff; // rgba(246, 246, 247, 1); +} diff --git a/src/renderer/components/MainGroupAvatar/index.tsx b/src/renderer/components/MainGroupAvatar/index.tsx new file mode 100644 index 0000000..9edf3f7 --- /dev/null +++ b/src/renderer/components/MainGroupAvatar/index.tsx @@ -0,0 +1,56 @@ +import * as React from "react"; +import { observer, inject } from "mobx-react"; +import IStore from "../../interface/IStore"; + +const defaultAvatar = require("../../assets/images/avatar-default.png"); + +const styles = require("./styles/index.less"); + +interface MainGroupAvatarProps { + store?: IStore; +} + +interface MainGroupAvatarState {} + +@inject("store") +@observer +export default class MainGroupAvatar extends React.Component< + MainGroupAvatarProps, + MainGroupAvatarState +> { + constructor(props) { + super(props); + } + + get homepage() { + const globalStore = this.props.store!.global; + const { profile } = globalStore; + if (profile && profile.htmlUrl) { + return profile.htmlUrl; + } + return "javascript:;"; + } + + get avatar() { + const globalStore = this.props.store!.global; + const { profile } = globalStore; + if (profile && profile.avatarUrl) { + return profile.avatarUrl; + } + return defaultAvatar; + } + + render() { + const globalStore = this.props.store!.global; + const { profile } = globalStore; + + return ( +
+ + + + {profile &&

{profile.name}

} +
+ ); + } +} diff --git a/src/renderer/components/MainGroupAvatar/styles/index.less b/src/renderer/components/MainGroupAvatar/styles/index.less new file mode 100644 index 0000000..42d8bf2 --- /dev/null +++ b/src/renderer/components/MainGroupAvatar/styles/index.less @@ -0,0 +1,20 @@ +.profileCard { + width: 100%; + text-align: center; + padding: 15px 0; +} + +.profileAvatar { + display: block; + margin: 0 auto; + width: 50px; + height: 50px; + border-radius: 50%; +} + +.profileName { + color: #eee; + font-size: 14px; + line-height: 1.5; + margin-top: 5px; +} diff --git a/src/renderer/components/MainGroupFooter/index.tsx b/src/renderer/components/MainGroupFooter/index.tsx new file mode 100644 index 0000000..6ebd80e --- /dev/null +++ b/src/renderer/components/MainGroupFooter/index.tsx @@ -0,0 +1,146 @@ +import * as React from "react"; +import { observer, inject } from "mobx-react"; +import ClassNames from "classnames"; +import { Icon, Modal, Input, Alert } from "antd"; +import IStore from "../../interface/IStore"; +import * as EVENTS from "../../../shared/events"; +import { ipcRenderer } from "electron"; + +const styles = require("./styles/index.less"); + +interface MainGroupFooterProps { + store?: IStore; +} + +interface MainGroupFooterState { + modalVisible: boolean; + error: Error | string | null; + categoryName: string; + submitting: boolean; +} + +@inject("store") +@observer +export default class MainGroupFooter extends React.Component< + MainGroupFooterProps, + MainGroupFooterState +> { + constructor(props) { + super(props); + this.state = { + modalVisible: false, + error: null, + categoryName: "", + submitting: false + }; + } + + showAddCatDialog = () => { + if (this.state.modalVisible) { + return; + } + this.setState({ + modalVisible: true, + error: null + }); + }; + + closeAddCategoryDialog = () => { + this.setState({ + modalVisible: false, + categoryName: "" + }); + }; + + onInputCategoryName = (e: any) => { + this.setState({ + categoryName: e.target.value.trim() + }); + }; + + submitCategoryName = () => { + const { categoryName } = this.state; + if (!categoryName) { + this.setState({ + error: "Please input category name" + }); + return; + } + this.setState({ + submitting: true + }); + + const mainStore = this.props.store!.main; + setTimeout(() => { + mainStore + .addNewCategory(categoryName) + .then(() => { + this.setState({ + submitting: false, + categoryName: "" + }); + }) + .catch(error => { + this.setState({ + submitting: false, + error + }); + }); + }, 2000); + }; + + clearError = () => { + this.setState({ + error: null + }); + }; + + openSettingWindow = () => { + ipcRenderer.send(EVENTS.OPEN_SETTING_WIN, ""); + }; + + render() { + return ( +
+ + + + {this.state.error && ( + + )} + + +
+ ); + } +} diff --git a/src/renderer/components/MainGroupFooter/styles/index.less b/src/renderer/components/MainGroupFooter/styles/index.less new file mode 100644 index 0000000..886538f --- /dev/null +++ b/src/renderer/components/MainGroupFooter/styles/index.less @@ -0,0 +1,35 @@ +.groupFooter { + position: absolute; + width: 100%; + height: 36px; + left: 0; + bottom: 0; +} + +.settingBtn { + width: 16px; + height: 16px; + font-size: 15px; + position: absolute; + top: 5px; + left: 16px; + cursor: pointer; + &:hover { + color: #eee; + } +} + +.addCatBtn { + width: 16px; + height: 16px; + font-size: 16px; + position: absolute; + top: 5px; + right: 16px; + transition: all 0.3s ease; + cursor: pointer; + &:hover { + color: #eee; + transform: rotate(90deg); + } +} diff --git a/src/renderer/components/MainGroupNavs/index.tsx b/src/renderer/components/MainGroupNavs/index.tsx new file mode 100644 index 0000000..6131e8d --- /dev/null +++ b/src/renderer/components/MainGroupNavs/index.tsx @@ -0,0 +1,96 @@ +import * as React from "react"; +import { observer, inject } from "mobx-react"; +import { toJS } from "mobx"; +import ClassNames from "classnames"; +import { Menu, Icon } from "antd"; +import IStore from "../../interface/IStore"; +import GroupType from "../../enum/GroupType"; + +const SubMenu = Menu.SubMenu; + +const styles = require("./styles/index.less"); + +interface MainGroupNavsProps { + store?: IStore; +} + +interface MainGroupNavsState {} + +@inject("store") +@observer +export default class MainGroupNavs extends React.Component { + constructor(props) { + super(props); + } + + deleteCategory = (id: number, e) => { + e.stopPropagation(); + // TODO + console.log(id); + }; + + render() { + const mainStore = this.props.store!.main; + const { languages, categories, openNavMenus } = mainStore; + const currentItem = mainStore.group.id; + + return ( +
+ + + + ALL + + + + LANGUAGES + + } + > + {languages.map(language => ( + + {language.name} + {language.reposCount} + + ))} + + + + CATEGORIES + + } + > + {categories.map(category => ( + + + {category.name} + {category.reposCount} + + ))} + + + + UNCATEGORIZED + + +
+ ); + } +} diff --git a/src/renderer/components/MainGroupNavs/styles/index.less b/src/renderer/components/MainGroupNavs/styles/index.less new file mode 100644 index 0000000..bf67346 --- /dev/null +++ b/src/renderer/components/MainGroupNavs/styles/index.less @@ -0,0 +1,39 @@ +.groupNav { + position: relative; +} + +.langItem { + padding-right: 32px !important; +} + +.navDel { + position: absolute; + top: 0; + left: 25px; + text-align: left; + padding: 0; + font-size: 12px; + line-height: 42px; + opacity: 0; +} + +.catItem { + padding-right: 32px !important; + + &:hover { + .navDel { + opacity: 1; + } + } +} + +.navBadge { + position: absolute; + top: 0; + right: 10px; + text-align: right; + padding: 0 6px; + font-size: 14px; + line-height: 42px; + color: #fafafa; +} diff --git a/src/renderer/components/MainGroupPane/index.tsx b/src/renderer/components/MainGroupPane/index.tsx new file mode 100644 index 0000000..e812690 --- /dev/null +++ b/src/renderer/components/MainGroupPane/index.tsx @@ -0,0 +1,31 @@ +import * as React from "react"; +import ClassNames from "classnames"; +import RefreshIndicator from "../RefreshIndicator"; +import MainGroupAvatar from "../MainGroupAvatar"; +import MainGroupNavs from "../MainGroupNavs"; +import MainGroupFooter from "../MainGroupFooter"; + +const styles = require("./styles/index.less"); + +interface MainGroupPaneProps {} + +interface MainGroupPaneState {} + +export default class MainGroupPane extends React.Component { + constructor(props) { + super(props); + } + + render() { + return ( +
+
+ +
+ + + +
+ ); + } +} diff --git a/src/renderer/components/MainGroupPane/styles/index.less b/src/renderer/components/MainGroupPane/styles/index.less new file mode 100644 index 0000000..b3ae91c --- /dev/null +++ b/src/renderer/components/MainGroupPane/styles/index.less @@ -0,0 +1,8 @@ +.left { + position: relative; + width: 200px; + height: 100%; + background-color: rgba(39, 49, 67, 1); + // border-right: 1px solid rgba(186,208,223,0.72); + color: rgba(204, 204, 204, 1); +} diff --git a/src/renderer/components/MainListPane/index.tsx b/src/renderer/components/MainListPane/index.tsx new file mode 100644 index 0000000..8ebf8f6 --- /dev/null +++ b/src/renderer/components/MainListPane/index.tsx @@ -0,0 +1,29 @@ +import * as React from "react"; +import ClassNames from "classnames"; +import SearchBox from "../SearchBox"; +import SortBar from "../SortBar"; +import ReposList from "../ReposList"; +import FilterBar from "../FilterBar"; + +const styles = require("./styles/index.less"); + +interface MainListPaneProps {} + +interface MainListPaneState {} + +export default class MainListPane extends React.Component { + constructor(props) { + super(props); + } + + render() { + return ( +
+ + + + +
+ ); + } +} diff --git a/src/renderer/components/MainListPane/styles/index.less b/src/renderer/components/MainListPane/styles/index.less new file mode 100644 index 0000000..940f23f --- /dev/null +++ b/src/renderer/components/MainListPane/styles/index.less @@ -0,0 +1,9 @@ +.mid { + position: relative; + width: 300px; + height: 100%; + background-color: #fbfbfb; + border-right: 1px solid rgba(229, 229, 229, 1); + display: flex; + flex-direction: column; +} diff --git a/src/renderer/components/RefreshIndicator/index.tsx b/src/renderer/components/RefreshIndicator/index.tsx new file mode 100644 index 0000000..48ee8d5 --- /dev/null +++ b/src/renderer/components/RefreshIndicator/index.tsx @@ -0,0 +1,86 @@ +import * as React from "react"; +import { observer, inject } from "mobx-react"; +import ClassNames from "classnames"; +import { Icon, Tooltip, notification } from "antd"; +import IStore from "../../interface/IStore"; + +const styles = require("./styles/index.less"); + +interface RefreshIndicatorProps { + store?: IStore; +} + +interface RefreshIndicatorState {} + +@inject("store") +@observer +export default class RefreshIndicator extends React.Component< + RefreshIndicatorProps, + RefreshIndicatorState +> { + constructor(props) { + super(props); + } + + refresh = () => { + const mainStore = this.props.store!.main; + mainStore + .fetchRemoteRepos() + .then(increase => { + this.showIncreaseMessage(increase); + }) + .catch(() => {}); + }; + + componentDidMount() { + const mainStore = this.props.store!.main; + mainStore + .startup() + .then(increase => { + this.showIncreaseMessage(increase); + }) + .catch(() => {}); + } + + showIncreaseMessage = (increase: number) => { + notification.success({ + message: "Starred Repos Fetched", + description: + increase < 0 + ? `Decreased ${Math.abs(increase)} starred repositories.` + : `${increase} starred repositories were added.`, + duration: 10 + }); + }; + + render() { + const globalStore = this.props.store!.global; + const mainStore = this.props.store!.main; + const { offline } = globalStore; + const { fetching } = mainStore; + + let indicator; + if (offline) { + indicator = ( + + + + ); + } else { + indicator = ( + + ); + } + return
{indicator}
; + } +} diff --git a/src/renderer/components/RefreshIndicator/styles/index.less b/src/renderer/components/RefreshIndicator/styles/index.less new file mode 100644 index 0000000..58a0c51 --- /dev/null +++ b/src/renderer/components/RefreshIndicator/styles/index.less @@ -0,0 +1,16 @@ +.indicatorWrap { + position: relative; + width: 100%; + height: 36px; +} + +.indicator { + position: absolute; + top: 12px; + right: 12px; + display: inline-block; + width: 14px; + height: 14px; + font-size: 14px; + cursor: pointer; +} diff --git a/src/renderer/components/RepoDetail/index.tsx b/src/renderer/components/RepoDetail/index.tsx new file mode 100644 index 0000000..53923af --- /dev/null +++ b/src/renderer/components/RepoDetail/index.tsx @@ -0,0 +1,17 @@ +import * as React from "react"; + +// const styles = require("./index.less"); + +interface RepoDetailProps {} + +interface RepoDetailState {} + +export default class RepoDetail extends React.Component { + constructor(props) { + super(props); + } + + render() { + return
RepoDetail
; + } +} diff --git a/src/renderer/components/RepoDetailToolbar/index.tsx b/src/renderer/components/RepoDetailToolbar/index.tsx new file mode 100644 index 0000000..d707a2b --- /dev/null +++ b/src/renderer/components/RepoDetailToolbar/index.tsx @@ -0,0 +1,20 @@ +import * as React from "react"; + +// const styles = require("./index.less"); + +interface RepoDetailToolbarProps {} + +interface RepoDetailToolbarState {} + +export default class RepoDetailToolbar extends React.Component< + RepoDetailToolbarProps, + RepoDetailToolbarState +> { + constructor(props) { + super(props); + } + + render() { + return
RepoDetailToolbar
; + } +} diff --git a/src/renderer/components/ReposList/index.tsx b/src/renderer/components/ReposList/index.tsx new file mode 100644 index 0000000..b9d82be --- /dev/null +++ b/src/renderer/components/ReposList/index.tsx @@ -0,0 +1,17 @@ +import * as React from "react"; + +// const styles = require("./index.less"); + +interface ReposListProps {} + +interface ReposListState {} + +export default class ReposList extends React.Component { + constructor(props) { + super(props); + } + + render() { + return
ReposList
; + } +} diff --git a/src/renderer/components/SearchBox/index.tsx b/src/renderer/components/SearchBox/index.tsx new file mode 100644 index 0000000..2d88dfa --- /dev/null +++ b/src/renderer/components/SearchBox/index.tsx @@ -0,0 +1,17 @@ +import * as React from "react"; + +// const styles = require("./index.less"); + +interface SearchBoxProps {} + +interface SearchBoxState {} + +export default class SearchBox extends React.Component { + constructor(props) { + super(props); + } + + render() { + return
SearchBox
; + } +} diff --git a/src/renderer/components/SortBar/index.tsx b/src/renderer/components/SortBar/index.tsx new file mode 100644 index 0000000..41a0c41 --- /dev/null +++ b/src/renderer/components/SortBar/index.tsx @@ -0,0 +1,17 @@ +import * as React from "react"; + +// const styles = require("./index.less"); + +interface SortBarProps {} + +interface SortBarState {} + +export default class SortBar extends React.Component { + constructor(props) { + super(props); + } + + render() { + return
SortBar
; + } +} diff --git a/src/renderer/constants/index.ts b/src/renderer/constants/index.ts index 362689d..d5ed981 100644 --- a/src/renderer/constants/index.ts +++ b/src/renderer/constants/index.ts @@ -82,13 +82,6 @@ export const QUERY_REPOS_LIST_FAIL = "QUERY_REPOS_LIST_FAIL"; export const REPLACE_REPOS_LIST_ITEM = "REPLACE_REPOS_LIST_ITEM"; -// search field -export const SEARCH_FIELD_ALL = "SEARCH_FIELD_ALL"; -export const SEARCH_FIELD_REPO_NAME = "SEARCH_FIELD_REPO_NAME"; -export const SEARCH_FIELD_REPO_DESCRIPTION = "SEARCH_FIELD_REPO_DESCRIPTION"; -export const SEARCH_FIELD_REPO_NOTE = "SEARCH_FIELD_REPO_NOTE"; -export const SEARCH_FIELD_REPO_TAGS = "SEARCH_FIELD_REPO_TAGS"; - // filter types export const FILTER_OPTION_NONE = "FILTER_OPTION_NONE"; export const FILTER_OPTION_HAS_FLAG = "FILTER_OPTION_HAS_FLAG"; @@ -96,26 +89,10 @@ export const FILTER_OPTION_HAS_NOTE = "FILTER_OPTION_HAS_NOTE"; export const FILTER_OPTION_UNREAD = "FILTER_OPTION_UNREAD"; // order types -export const ORDER_BY_DEFAULT = "defaultOrder"; // TODO change to starred time, need change github api npm package -export const ORDER_BY_STARS_COUNT = "stars"; -export const ORDER_BY_FORKS_COUNT = "forks"; -export const ORDER_BY_WATCHERS_COUNT = "watchers"; -export const ORDER_BY_OPEN_ISSUES_COUNT = "openIssues"; -export const ORDER_BY_SIZE = "size"; -export const ORDER_BY_CREATE_TIME = "createdTime"; -export const ORDER_BY_UPDATE_TIME = "updatedTime"; -export const ORDER_BY_PUSH_TIME = "pushedTime"; -export const ORDER_BY_SCORE = "score"; export const ORDER_DESC = "ORDER_DESC"; export const ORDER_ASC = "ORDER_ASC"; -// group types -export const GROUP_TYPE_CATEGORY = "GROUP_TYPE_CATEGORY"; -export const GROUP_TYPE_LANGUAGE = "GROUP_TYPE_LANGUAGE"; -export const GROUP_TYPE_UNKNOWN = "GROUP_TYPE_UNKNOWN"; // repos who do not have a custom category -export const GROUP_TYPE_ALL = "GROUP_TYPE_ALL"; // means removing category filter - // query profile export const QUERY_MY_PROFILE = "QUERY_MY_PROFILE"; export const QUERY_MY_PROFILE_SUCCESS = "QUERY_MY_PROFILE_SUCCESS"; diff --git a/src/renderer/enum/GroupType.ts b/src/renderer/enum/GroupType.ts new file mode 100644 index 0000000..5de004e --- /dev/null +++ b/src/renderer/enum/GroupType.ts @@ -0,0 +1,9 @@ +// nav group types +enum GroupType { + GROUP_TYPE_CATEGORY = "GROUP_TYPE_CATEGORY", + GROUP_TYPE_LANGUAGE = "GROUP_TYPE_LANGUAGE", + GROUP_TYPE_UNKNOWN = "GROUP_TYPE_UNKNOWN", // repos who do not have a custom category + GROUP_TYPE_ALL = "GROUP_TYPE_ALL" // means removing category filter +} + +export default GroupType; diff --git a/src/renderer/enum/OrderBy.ts b/src/renderer/enum/OrderBy.ts new file mode 100644 index 0000000..db3ee5f --- /dev/null +++ b/src/renderer/enum/OrderBy.ts @@ -0,0 +1,15 @@ +// order by +enum OrderBy { + ORDER_BY_DEFAULT = "defaultOrder", // TODO change to starred time, need change github api npm package + ORDER_BY_STARS_COUNT = "stars", + ORDER_BY_FORKS_COUNT = "forks", + ORDER_BY_WATCHERS_COUNT = "watchers", + ORDER_BY_OPEN_ISSUES_COUNT = "openIssues", + ORDER_BY_SIZE = "size", + ORDER_BY_CREATE_TIME = "createdTime", + ORDER_BY_UPDATE_TIME = "updatedTime", + ORDER_BY_PUSH_TIME = "pushedTime", + ORDER_BY_SCORE = "score" +} + +export default OrderBy; diff --git a/src/renderer/enum/SearchType.ts b/src/renderer/enum/SearchType.ts new file mode 100644 index 0000000..34eb8e4 --- /dev/null +++ b/src/renderer/enum/SearchType.ts @@ -0,0 +1,11 @@ +// search field + +enum SearchType { + SEARCH_FIELD_ALL = "SEARCH_FIELD_ALL", + SEARCH_FIELD_REPO_NAME = "SEARCH_FIELD_REPO_NAME", + SEARCH_FIELD_REPO_DESCRIPTION = "SEARCH_FIELD_REPO_DESCRIPTION", + SEARCH_FIELD_REPO_NOTE = "SEARCH_FIELD_REPO_NOTE", + SEARCH_FIELD_REPO_TAGS = "SEARCH_FIELD_REPO_TAGS" +} + +export default SearchType; diff --git a/src/renderer/interface/IStore.ts b/src/renderer/interface/IStore.ts index 080e7c5..24c9030 100644 --- a/src/renderer/interface/IStore.ts +++ b/src/renderer/interface/IStore.ts @@ -1,5 +1,7 @@ import GlobalStore from "../store/GlobalStore"; +import MainStore from "../store/MainStore"; export default interface IStore { global: GlobalStore; -}; + main: MainStore; +} diff --git a/src/renderer/rxdb/database.ts b/src/renderer/rxdb/database.ts index 537afe4..88599a7 100644 --- a/src/renderer/rxdb/database.ts +++ b/src/renderer/rxdb/database.ts @@ -67,7 +67,7 @@ const collections: RxCollectionCreator[] = [ let dbPromise: Promise; -const _create = async function(dbName, _dispatch) { +const _create = async function(dbName) { logger.log(`DatabaseService: creating database ${dbName}..`); const db = await RxDB.create({ @@ -116,9 +116,9 @@ const _create = async function(dbName, _dispatch) { return db; }; -export function get(dbName, dispatch = null) { +export function get(dbName) { if (!dbPromise) { - dbPromise = _create(dbName, dispatch); + dbPromise = _create(dbName); } return dbPromise; } diff --git a/src/renderer/rxdb/dbHandler.ts b/src/renderer/rxdb/dbHandler.ts index e319c20..8859fe3 100644 --- a/src/renderer/rxdb/dbHandler.ts +++ b/src/renderer/rxdb/dbHandler.ts @@ -1,7 +1,8 @@ import moment from "moment"; import * as Database from "./database"; -import * as CONSTANTS from "../constants"; import IRepo from "../interface/IRepo"; +import GroupType from "../enum/GroupType"; +import SearchType from "../enum/SearchType"; export default class DBHandler { private dbName: string; @@ -23,7 +24,7 @@ export default class DBHandler { initDB = async () => { if (!this.RxDB) { - this.RxDB = await Database.get(this.dbName, null); + this.RxDB = await Database.get(this.dbName); } return this; @@ -213,11 +214,11 @@ export default class DBHandler { if (conditions.group) { const id = conditions.group.id; // string switch (conditions.group.type) { - case CONSTANTS.GROUP_TYPE_LANGUAGE: + case GroupType.GROUP_TYPE_LANGUAGE: args = { lang: { $eq: id } }; // query = reposCollection.find(args) break; - case CONSTANTS.GROUP_TYPE_CATEGORY: + case GroupType.GROUP_TYPE_CATEGORY: // we should go to category table to find the repos list const catsCollection = this.RxDB.categories; const category = await catsCollection.findOne({ key: { $eq: id } }).exec(); @@ -225,7 +226,7 @@ export default class DBHandler { args = { id: { $in: repoIds } }; // query = reposCollection.find(args) break; - case CONSTANTS.GROUP_TYPE_UNKNOWN: + case GroupType.GROUP_TYPE_UNKNOWN: const catsCollection2 = this.RxDB.categories; const categories = await catsCollection2.find().exec(); let nrepoIds = []; @@ -256,15 +257,15 @@ export default class DBHandler { if (conditions.search && conditions.search.key) { const key = conditions.search.key; switch (conditions.search.field) { - case CONSTANTS.SEARCH_FIELD_REPO_NAME: + case SearchType.SEARCH_FIELD_REPO_NAME: args.name = { $regex: new RegExp(key, "i") }; // query = query.find(searchArgs) break; - case CONSTANTS.SEARCH_FIELD_REPO_DESCRIPTION: + case SearchType.SEARCH_FIELD_REPO_DESCRIPTION: args.description = { $regex: new RegExp(key, "i") }; // query = query.find(searchArgs) break; - case CONSTANTS.SEARCH_FIELD_REPO_NOTE: + case SearchType.SEARCH_FIELD_REPO_NOTE: if (!args.note) { args.note = { $regex: new RegExp(key, "i") }; } else { @@ -274,7 +275,7 @@ export default class DBHandler { } // query = query.find(searchArgs) break; - case CONSTANTS.SEARCH_FIELD_REPO_TAGS: + case SearchType.SEARCH_FIELD_REPO_TAGS: const tag = await this.RxDB.tags .findOne({ name: { $regex: new RegExp("^" + key + "$", "i") } @@ -291,7 +292,7 @@ export default class DBHandler { args.id = { $in: tagRepoIds }; } break; - case CONSTANTS.SEARCH_FIELD_ALL: // currently not include tags + case SearchType.SEARCH_FIELD_ALL: // currently not include tags default: // query = query.find({$or: [{name: {$regex: new RegExp(key, 'i')}}, {description: {$regex: new RegExp(key, 'i')}}, {note: {$regex: new RegExp(key, 'i')}}]}) // TODO this does not work but no error diff --git a/src/renderer/store/GlobalStore.ts b/src/renderer/store/GlobalStore.ts index ed05b7e..bfd1a45 100644 --- a/src/renderer/store/GlobalStore.ts +++ b/src/renderer/store/GlobalStore.ts @@ -4,8 +4,47 @@ import Authentication from "../utils/authentication"; import { ICredentialsState } from "../interface/IAccount"; import IProfile from "../interface/IProfile"; import logger from "../utils/logger"; +import { RxDatabase } from "rxdb"; +import DBHandler from "../rxdb/dbHandler"; +import dbName from "../utils/dbName"; +import * as Database from "../rxdb/database"; +import * as CONSTANTS from "../constants"; export default class GlobalStore { + /** + * Local database + */ + private _db: RxDatabase; + + public getDb() { + if (this._db) { + return Promise.resolve(this._db); + } + const username = localStorage.getItem(CONSTANTS.LOCAL_STORAGE_USERNAME_KEY); + if (username) { + return Database.get(dbName(username)).then(db => { + this._db = db; + return db; + }); + } else { + return Promise.reject("No db instance and credentials"); + } + } + + /** + * Restore data from rxdb + */ + public restore() { + if (this.profile) { + return Promise.resolve(true); + } + return this.getDb().then(() => { + return Promise.all([this.getLocalCredentials(), this.getLocalProfile()]).then( + () => true + ); + }); + } + /** * Network status */ @@ -82,10 +121,35 @@ export default class GlobalStore { return Authentication.signInApp(credentials) .then(profile => { this.profile = profile; + if (!this._db) { + return Database.get(dbName(credentials.username)).then(db => { + this._db = db; + return profile; + }); + } return profile; }) .finally(() => { this.isRequestingSignin = false; }); }; + + /** + * Get local profile + */ + @action + getLocalProfile = () => { + const username = localStorage.getItem(CONSTANTS.LOCAL_STORAGE_USERNAME_KEY); + + return new DBHandler(this._db) + .initDB() + .then(dbHandler => dbHandler.getProfile(username!)) + .then(profile => { + this.profile = profile; + return profile; + }) + .catch(error => { + logger.log(error.message || error.toString()); + }); + }; } diff --git a/src/renderer/store/MainStore.ts b/src/renderer/store/MainStore.ts new file mode 100644 index 0000000..85cc6df --- /dev/null +++ b/src/renderer/store/MainStore.ts @@ -0,0 +1,246 @@ +import { observable, action } from "mobx"; +import ILanguage from "../interface/ILanguage"; +import ICategory from "../interface/ICategory"; +import GroupType from "../enum/GroupType"; +import SearchType from "../enum/SearchType"; +import OrderBy from "../enum/OrderBy"; +import { + IGroupConditionState, + ISearchConditionState, + IOrderConditionState, + IFilterConditionState +} from "../interface/IConditional"; +import GlobalStore from "../store/GlobalStore"; +import DBHandler from "../rxdb/dbHandler"; +import logger from "../utils/logger"; +import IRepo from "../interface/IRepo"; +import GithubClient from "../utils/githubClient"; + +export default class MainStore { + private globalStore: GlobalStore; + + constructor(globalStore: GlobalStore) { + this.globalStore = globalStore; + } + + private getDbHandler = () => { + return this.globalStore.getDb().then(db => { + return new DBHandler(db); + }); + }; + + public startup = () => { + return this.globalStore.restore().then(() => { + this.updateCategoryList(); + this.updateLanguageList(); + return this.fetchRemoteRepos(); + }); + }; + + /** + * Fetch status + */ + @observable fetching: boolean = false; + + /** + * Languages + */ + @observable languages: ILanguage[] = []; + + @action + updateLanguageList = () => { + return this.getDbHandler() + .then(dbHandler => dbHandler.initDB()) + .then(dbHandler => dbHandler.getLanguages()) + .then(languages => { + this.languages = languages; + return languages; + }) + .catch(error => { + logger.log(error.message || error.toString()); + }); + }; + + /** + * Categories + */ + @observable categories: ICategory[] = []; + + @action + updateCategoryList = () => { + return this.getDbHandler() + .then(dbHandler => dbHandler.initDB()) + .then(dbHandler => dbHandler.getCategories()) + .then(categories => { + this.categories = categories; + return categories; + }) + .catch(error => { + logger.log(error.message || error.toString()); + }); + }; + + @action + addNewCategory = (name: string) => { + const { categories } = this; + return this.getDbHandler() + .then(dbHandler => dbHandler.initDB()) + .then(dbHandler => dbHandler.upsertCategory(name)) + .then(categoryDoc => { + this.categories = new Array().concat(categories).concat(categoryDoc.toJSON()); + + return categoryDoc; + }) + .catch(error => { + logger.log(error.message || error.toString()); + throw error; + }); + }; + + @action + delCategory = (id: number) => { + return this.getDbHandler() + .then(dbHandler => dbHandler.initDB()) + .then(dbHandler => dbHandler.deleteCategory(id)) + .then(() => { + this.updateCategoryList(); + return true; + }) + .catch(error => { + logger.log(error.message || error.toString()); + }); + }; + + /** + * Search condition + */ + @observable search: ISearchConditionState = { key: "", field: SearchType.SEARCH_FIELD_ALL }; + + /** + * Order condition + */ + @observable order: IOrderConditionState = { by: OrderBy.ORDER_BY_DEFAULT, desc: true }; + + /** + * filter condition + */ + @observable filter: IFilterConditionState = { hasFlag: false, hasNote: false, unread: false }; + + /** + * Group condition + */ + @observable + group: IGroupConditionState = { + id: GroupType.GROUP_TYPE_ALL, + type: GroupType.GROUP_TYPE_ALL + }; + + @observable openNavMenus: GroupType[] = [GroupType.GROUP_TYPE_ALL]; + + @action + onClickNavMenuItem = ({ key, keyPath }) => { + if (this.fetching) { + return; // not available when fetching data + } + let group; + if (keyPath.length === 1) { + group = { + id: key, + type: key + }; + } else { + group = { + id: key, + type: keyPath[1] + }; + } + if (group.id === this.group.id) { + return; + } + this.group = group; + }; + + @action + onToggleNavMenus = (openKeys: GroupType[]) => { + const { openNavMenus } = this; + const latestOpenKey = openKeys.find(key => !(openNavMenus.indexOf(key) > -1)); + + let nextOpenKeys: GroupType[] = []; + if (latestOpenKey) { + nextOpenKeys = new Array().concat(latestOpenKey); + } + this.openNavMenus = nextOpenKeys; + }; + + /** + * Repos + */ + @observable repos: { [key: string]: IRepo } = {}; + + @action + updateRepoList = () => { + const { group, search, order, filter } = this; + const conditions = { + group, + search, + order, + filter + }; + + return this.getDbHandler() + .then(dbHandler => dbHandler.getRepos(conditions)) + .then(repos => { + // for easily replace one specified item of list + // we need convert the array to key-value pairs + let keyedRepos: { [key: string]: IRepo } = {}; + repos.forEach(repo => { + keyedRepos["_" + repo.id] = repo; + }); + + this.repos = keyedRepos; + return repos; + }) + .catch(error => { + logger.log(error.message || error.toString()); + // throw error; + }); + }; + + @action + fetchRemoteRepos = () => { + if (this.fetching) { + return Promise.reject(false); + } + const client = new GithubClient(this.globalStore.credentials); + this.fetching = true; + return client + .getStarredRepos() + .then(ret => ret.data) + .then(repos => { + return this.getDbHandler() + .then(dbHandler => { + return Promise.all([ + dbHandler.upsertRepos(repos), + dbHandler.upsertOwners(repos), + dbHandler.upsertLanguages(repos), + dbHandler.recordReposCount(repos.length) + ]); + }) + .then(ret => { + this.updateLanguageList(); + this.updateRepoList(); + + // return repo count change + return ret[3]; + }); + }) + .catch(error => { + logger.log(error.message || error.toString()); + this.updateRepoList(); + throw error; + }) + .finally(() => { + this.fetching = false; + }); + }; +} diff --git a/src/renderer/store/index.ts b/src/renderer/store/index.ts index 4740e69..fbb602e 100644 --- a/src/renderer/store/index.ts +++ b/src/renderer/store/index.ts @@ -1,8 +1,11 @@ import GlobalStore from "./GlobalStore"; +import MainStore from "./MainStore"; export default function getStore() { + const globalStore = new GlobalStore(); const store = { - global: new GlobalStore() + global: globalStore, + main: new MainStore(globalStore) }; return store; diff --git a/src/renderer/utils/authentication.ts b/src/renderer/utils/authentication.ts index 93c9697..f861350 100644 --- a/src/renderer/utils/authentication.ts +++ b/src/renderer/utils/authentication.ts @@ -12,18 +12,18 @@ export default class Authentication { return new Promise((resolve, reject) => { let username = localStorage.getItem(CONSTANTS.LOCAL_STORAGE_USERNAME_KEY); if (!username) { - reject(new Error("no local login record")); + reject(new Error("No local login record found")); } else { ipcRenderer.send(EVENTS.GET_LOCAL_CREDENTIALS, username); ipcRenderer.once(EVENTS.GET_LOCAL_CREDENTIALS_REPLY, (_event, arg) => { if (!arg) { - reject(new Error("retrieve password from keychain failed")); + reject(new Error("Retrieve password from keychain failed")); } let credentials = JSON.parse(arg); if (credentials.username && credentials.password) { resolve(credentials); } else { - reject(new Error("retrieve password from keychain failed")); + reject(new Error("Retrieve password from keychain failed")); } }); } @@ -38,7 +38,7 @@ export default class Authentication { if (result) { resolve(credentials); } else { - reject(new Error("save credentials to keychain failed")); + reject(new Error("Save credentials to keychain failed")); } }); }); @@ -61,7 +61,7 @@ export default class Authentication { ipcRenderer.once(EVENTS.DELETE_LOCAL_CREDENTIALS_REPLY, (_event, result) => { result ? resolve(username || "") - : reject(new Error("delete credentials from keychain failed")); + : reject(new Error("Delete credentials from keychain failed")); }); } }); diff --git a/src/renderer/utils/githubClient.ts b/src/renderer/utils/githubClient.ts index cad9221..99cd831 100644 --- a/src/renderer/utils/githubClient.ts +++ b/src/renderer/utils/githubClient.ts @@ -21,7 +21,7 @@ export default class GithubClient { return this.me.getProfile().then(ret => ret.data); }; - getStarredRepos = () => { + getStarredRepos = (): Promise => { // return this.me.listStarredRepos() // this method only fetch repos sorted by 'updated', but we need the order of starred time desc // ugly hack diff --git a/src/renderer/views/Main/index.tsx b/src/renderer/views/Main/index.tsx index 59a599a..17a68de 100644 --- a/src/renderer/views/Main/index.tsx +++ b/src/renderer/views/Main/index.tsx @@ -1,4 +1,8 @@ import * as React from "react"; +import ClassNames from "classnames"; +import MainGroupPane from "../../components/MainGroupPane"; +import MainListPane from "../../components/MainListPane"; +import MainDetailPane from "../../components/MainDetailPane"; const styles = require("./styles/index.less"); @@ -12,6 +16,15 @@ export default class MainView extends React.ComponentMainView
; + return ( +
+ {/*
*/} +
+ + + +
+
+ ); } } diff --git a/src/renderer/views/Main/styles/index.less b/src/renderer/views/Main/styles/index.less index e69de29..8af8343 100644 --- a/src/renderer/views/Main/styles/index.less +++ b/src/renderer/views/Main/styles/index.less @@ -0,0 +1,21 @@ +.main { + height: 100%; + overflow: hidden; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, + Arial, sans-serif; + font-size: 14px; + line-height: 1.5; +} + +.container { + display: flex; + position: relative; + width: 100%; + height: 100%; + //border-top: 1px solid rgba(186, 208, 223, 0.36); +} From fa338117769abbd36e211b67d534d1edfaa876c5 Mon Sep 17 00:00:00 2001 From: wuxueqian Date: Sun, 28 Jan 2018 18:23:05 +0800 Subject: [PATCH 17/25] fix pouchdb warning --- package.json | 38 +-- src/renderer/rxdb/database.ts | 24 +- yarn.lock | 508 ++++++++++++++++++++-------------- 3 files changed, 324 insertions(+), 246 deletions(-) diff --git a/package.json b/package.json index 2bb0c7c..464f11b 100644 --- a/package.json +++ b/package.json @@ -14,10 +14,7 @@ "target": "nsis" }, "linux": { - "target": [ - "AppImage", - "deb" - ] + "target": ["AppImage", "deb"] }, "directories": { "app": "app", @@ -30,16 +27,7 @@ "type": "git", "url": "git+https://github.com/thundernet8/StarCabinet.git" }, - "keywords": [ - "Github", - "Star", - "Electron", - "React", - "Mobx", - "React-Router", - "Webpack", - "rxdb" - ], + "keywords": ["Github", "Star", "Electron", "React", "Mobx", "React-Router", "Webpack", "rxdb"], "author": { "name": "WuXueqian", "email": "chinash2010@gmail.com" @@ -51,10 +39,14 @@ "homepage": "https://github.com/thundernet8/StarCabinet#readme", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "dll": "cross-env NODE_ENV=production webpack -p --hide-modules --config webpack/dll.conf.babel.js", - "dll:dev": "cross-env NODE_ENV=development webpack --hide-modules --config webpack/dll.conf.babel.js", - "build": "rimraf app/dist && mkdirp app/dist && cross-env NODE_ENV=production npm run dll && cross-env NODE_ENV=production webpack --progress --hide-modules --config webpack/prod.conf.babel.js", - "build:dev": "rimraf app/dist && mkdirp app/dist && cross-env NODE_ENV=development npm run dll:dev && cross-env NODE_ENV=development webpack --progress --hide-modules --config webpack/main.conf.babel.js && cross-env NODE_ENV=development webpack --progress --hide-modules --config webpack/dev.conf.babel.js", + "dll": + "cross-env NODE_ENV=production webpack -p --hide-modules --config webpack/dll.conf.babel.js", + "dll:dev": + "cross-env NODE_ENV=development webpack --hide-modules --config webpack/dll.conf.babel.js", + "build": + "rimraf app/dist && mkdirp app/dist && cross-env NODE_ENV=production npm run dll && cross-env NODE_ENV=production webpack --progress --hide-modules --config webpack/prod.conf.babel.js", + "build:dev": + "rimraf app/dist && mkdirp app/dist && cross-env NODE_ENV=development npm run dll:dev && cross-env NODE_ENV=development webpack --progress --hide-modules --config webpack/main.conf.babel.js && cross-env NODE_ENV=development webpack --progress --hide-modules --config webpack/dev.conf.babel.js", "dev": "npm run build:dev && webpack-dev-server --config webpack/dev.conf.babel.js", "analyze": "cross-env ANALYZE_ENV=true npm run build", "start": "cross-env NODE_ENV=development electron ./app", @@ -69,12 +61,8 @@ "lint-staged:style": "stylelint --syntax less" }, "lint-staged": { - "src/**/*.{ts,tsx}": [ - "lint-staged:ts" - ], - "src/**/*.less": [ - "lint-staged:style" - ] + "src/**/*.{ts,tsx}": ["lint-staged:ts"], + "src/**/*.less": ["lint-staged:style"] }, "pre-commit": "lint-staged", "devDependencies": { @@ -142,6 +130,6 @@ "react-dom": "^16.2.0", "react-markdown": "^3.1.4", "react-router-dom": "^4.2.2", - "rxdb": "^6.0.1" + "rxdb": "^3.0.0" } } diff --git a/src/renderer/rxdb/database.ts b/src/renderer/rxdb/database.ts index 88599a7..5f0890e 100644 --- a/src/renderer/rxdb/database.ts +++ b/src/renderer/rxdb/database.ts @@ -1,5 +1,5 @@ import * as RxDB from "rxdb"; -import { RxDatabase, RxCollectionCreator } from "rxdb"; +import { RxDatabase } from "rxdb"; import logger from "../utils/logger"; import { extendRxDB } from "./dbExtension"; import repoSchema from "./schemas/repoSchema"; @@ -14,20 +14,20 @@ declare var window; RxDB.plugin(require("pouchdb-adapter-idb")); -const collections: RxCollectionCreator[] = [ +const collections: any[] = [ { name: "repos", schema: repoSchema as any }, { name: "authors", - schema: authorSchema - // sync: false + schema: authorSchema, + sync: false }, { name: "me", - schema: meSchema - // sync: false + schema: meSchema, + sync: false }, { name: "tags", @@ -36,8 +36,8 @@ const collections: RxCollectionCreator[] = [ countRepos() { return this.repos.length; } - } - // sync: false + }, + sync: false }, { name: "categories", @@ -46,8 +46,8 @@ const collections: RxCollectionCreator[] = [ countRepos() { return this.repos.length; } - } - // sync: false + }, + sync: false }, { name: "languages", @@ -60,8 +60,8 @@ const collections: RxCollectionCreator[] = [ }, { name: "settings", - schema: settingSchema - // sync: false + schema: settingSchema, + sync: false } ]; diff --git a/yarn.lock b/yarn.lock index 9358020..929463e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -17,9 +17,9 @@ lodash "^4.2.0" to-fast-properties "^2.0.0" -"@types/core-js@0.9.43": - version "0.9.43" - resolved "https://registry.yarnpkg.com/@types/core-js/-/core-js-0.9.43.tgz#65d646c5e8c0cd1bdee37065799f9d3d48748253" +"@types/core-js@^0.9.35": + version "0.9.46" + resolved "https://registry.yarnpkg.com/@types/core-js/-/core-js-0.9.46.tgz#ea701ee34cbb6dfe6d100f1530319547c93c8d79" "@types/history@*": version "4.6.2" @@ -81,11 +81,15 @@ acorn-dynamic-import@^2.0.0: dependencies: acorn "^4.0.3" +acorn@^1.0.3: + version "1.2.2" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-1.2.2.tgz#c8ce27de0acc76d896d2b1fad3df588d9e82f014" + acorn@^4.0.3: version "4.0.13" resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787" -acorn@^5.0.0: +acorn@^5.0.0, acorn@^5.2.1: version "5.3.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.3.0.tgz#7446d39459c54fb49a80e6ee6478149b940ec822" @@ -131,6 +135,10 @@ alphanum-sort@^1.0.1, alphanum-sort@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" +amdefine@>=0.0.4: + version "1.0.1" + resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" + ansi-escapes@^1.0.0: version "1.4.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" @@ -359,6 +367,14 @@ assign-symbols@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" +ast-types@0.8.15: + version "0.8.15" + resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.8.15.tgz#8eef0827f04dff0ec8857ba925abe3fea6194e52" + +ast-types@0.9.6: + version "0.9.6" + resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.6.tgz#102c9e9e9005d3e7e3829bf0c4fa24ee862ee9b9" + async-each@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" @@ -655,7 +671,7 @@ babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: dependencies: babel-runtime "^6.22.0" -babel-plugin-transform-es2015-block-scoping@^6.23.0: +babel-plugin-transform-es2015-block-scoping@^6.23.0, babel-plugin-transform-es2015-block-scoping@^6.24.1: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f" dependencies: @@ -665,7 +681,7 @@ babel-plugin-transform-es2015-block-scoping@^6.23.0: babel-types "^6.26.0" lodash "^4.17.4" -babel-plugin-transform-es2015-classes@^6.23.0: +babel-plugin-transform-es2015-classes@^6.23.0, babel-plugin-transform-es2015-classes@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" dependencies: @@ -679,33 +695,33 @@ babel-plugin-transform-es2015-classes@^6.23.0: babel-traverse "^6.24.1" babel-types "^6.24.1" -babel-plugin-transform-es2015-computed-properties@^6.22.0: +babel-plugin-transform-es2015-computed-properties@^6.22.0, babel-plugin-transform-es2015-computed-properties@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" dependencies: babel-runtime "^6.22.0" babel-template "^6.24.1" -babel-plugin-transform-es2015-destructuring@^6.23.0: +babel-plugin-transform-es2015-destructuring@^6.22.0, babel-plugin-transform-es2015-destructuring@^6.23.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" dependencies: babel-runtime "^6.22.0" -babel-plugin-transform-es2015-duplicate-keys@^6.22.0: +babel-plugin-transform-es2015-duplicate-keys@^6.22.0, babel-plugin-transform-es2015-duplicate-keys@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" -babel-plugin-transform-es2015-for-of@^6.23.0: +babel-plugin-transform-es2015-for-of@^6.22.0, babel-plugin-transform-es2015-for-of@^6.23.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" dependencies: babel-runtime "^6.22.0" -babel-plugin-transform-es2015-function-name@^6.22.0: +babel-plugin-transform-es2015-function-name@^6.22.0, babel-plugin-transform-es2015-function-name@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" dependencies: @@ -736,7 +752,7 @@ babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-e babel-template "^6.26.0" babel-types "^6.26.0" -babel-plugin-transform-es2015-modules-systemjs@^6.23.0: +babel-plugin-transform-es2015-modules-systemjs@^6.23.0, babel-plugin-transform-es2015-modules-systemjs@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" dependencies: @@ -744,7 +760,7 @@ babel-plugin-transform-es2015-modules-systemjs@^6.23.0: babel-runtime "^6.22.0" babel-template "^6.24.1" -babel-plugin-transform-es2015-modules-umd@^6.23.0: +babel-plugin-transform-es2015-modules-umd@^6.23.0, babel-plugin-transform-es2015-modules-umd@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" dependencies: @@ -752,14 +768,14 @@ babel-plugin-transform-es2015-modules-umd@^6.23.0: babel-runtime "^6.22.0" babel-template "^6.24.1" -babel-plugin-transform-es2015-object-super@^6.22.0: +babel-plugin-transform-es2015-object-super@^6.22.0, babel-plugin-transform-es2015-object-super@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" dependencies: babel-helper-replace-supers "^6.24.1" babel-runtime "^6.22.0" -babel-plugin-transform-es2015-parameters@^6.23.0: +babel-plugin-transform-es2015-parameters@^6.23.0, babel-plugin-transform-es2015-parameters@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" dependencies: @@ -770,7 +786,7 @@ babel-plugin-transform-es2015-parameters@^6.23.0: babel-traverse "^6.24.1" babel-types "^6.24.1" -babel-plugin-transform-es2015-shorthand-properties@^6.22.0: +babel-plugin-transform-es2015-shorthand-properties@^6.22.0, babel-plugin-transform-es2015-shorthand-properties@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" dependencies: @@ -783,7 +799,7 @@ babel-plugin-transform-es2015-spread@^6.22.0: dependencies: babel-runtime "^6.22.0" -babel-plugin-transform-es2015-sticky-regex@^6.22.0: +babel-plugin-transform-es2015-sticky-regex@^6.22.0, babel-plugin-transform-es2015-sticky-regex@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" dependencies: @@ -797,13 +813,13 @@ babel-plugin-transform-es2015-template-literals@^6.22.0: dependencies: babel-runtime "^6.22.0" -babel-plugin-transform-es2015-typeof-symbol@^6.23.0: +babel-plugin-transform-es2015-typeof-symbol@^6.22.0, babel-plugin-transform-es2015-typeof-symbol@^6.23.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" dependencies: babel-runtime "^6.22.0" -babel-plugin-transform-es2015-unicode-regex@^6.22.0: +babel-plugin-transform-es2015-unicode-regex@^6.22.0, babel-plugin-transform-es2015-unicode-regex@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" dependencies: @@ -854,7 +870,7 @@ babel-plugin-transform-react-jsx@^6.24.1: babel-plugin-syntax-jsx "^6.8.0" babel-runtime "^6.22.0" -babel-plugin-transform-regenerator@^6.22.0: +babel-plugin-transform-regenerator@^6.22.0, babel-plugin-transform-regenerator@^6.24.1: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f" dependencies: @@ -910,6 +926,41 @@ babel-preset-env@^1.6.1: invariant "^2.2.2" semver "^5.3.0" +babel-preset-es2015-native-modules@6.9.4: + version "6.9.4" + resolved "https://registry.yarnpkg.com/babel-preset-es2015-native-modules/-/babel-preset-es2015-native-modules-6.9.4.tgz#ad2e0ff3a2cd879c1d8fc994ab33b4b80d2b5057" + dependencies: + babel-preset-es2015 latest + +babel-preset-es2015@latest: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz#d44050d6bc2c9feea702aaf38d727a0210538939" + dependencies: + babel-plugin-check-es2015-constants "^6.22.0" + babel-plugin-transform-es2015-arrow-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoped-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoping "^6.24.1" + babel-plugin-transform-es2015-classes "^6.24.1" + babel-plugin-transform-es2015-computed-properties "^6.24.1" + babel-plugin-transform-es2015-destructuring "^6.22.0" + babel-plugin-transform-es2015-duplicate-keys "^6.24.1" + babel-plugin-transform-es2015-for-of "^6.22.0" + babel-plugin-transform-es2015-function-name "^6.24.1" + babel-plugin-transform-es2015-literals "^6.22.0" + babel-plugin-transform-es2015-modules-amd "^6.24.1" + babel-plugin-transform-es2015-modules-commonjs "^6.24.1" + babel-plugin-transform-es2015-modules-systemjs "^6.24.1" + babel-plugin-transform-es2015-modules-umd "^6.24.1" + babel-plugin-transform-es2015-object-super "^6.24.1" + babel-plugin-transform-es2015-parameters "^6.24.1" + babel-plugin-transform-es2015-shorthand-properties "^6.24.1" + babel-plugin-transform-es2015-spread "^6.22.0" + babel-plugin-transform-es2015-sticky-regex "^6.24.1" + babel-plugin-transform-es2015-template-literals "^6.22.0" + babel-plugin-transform-es2015-typeof-symbol "^6.22.0" + babel-plugin-transform-es2015-unicode-regex "^6.24.1" + babel-plugin-transform-regenerator "^6.24.1" + babel-preset-flow@^6.23.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-preset-flow/-/babel-preset-flow-6.23.0.tgz#e71218887085ae9a24b5be4169affb599816c49d" @@ -939,7 +990,7 @@ babel-register@^6.26.0: mkdirp "^0.5.1" source-map-support "^0.4.15" -babel-runtime@6.x, babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.23.0, babel-runtime@^6.25.0, babel-runtime@^6.26.0: +babel-runtime@6.x, babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.23.0, babel-runtime@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" dependencies: @@ -995,6 +1046,10 @@ balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" +base62@^1.1.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/base62/-/base62-1.2.1.tgz#95a5a22350b0a557f3f081247fc2c398803ecb0c" + base64-js@^1.0.2: version "1.2.1" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.1.tgz#a91947da1f4a516ea38e5b4ec0ec3773675e0886" @@ -1551,7 +1606,7 @@ commander@2.12.x, commander@^2.11.0, commander@~2.12.1: version "2.12.2" resolved "https://registry.yarnpkg.com/commander/-/commander-2.12.2.tgz#0f5946c427ed9ec0d91a46bb9def53e54650e555" -commander@^2.12.1: +commander@^2.12.1, commander@^2.5.0: version "2.13.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c" @@ -1563,6 +1618,20 @@ commondir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" +commoner@^0.10.1: + version "0.10.8" + resolved "https://registry.yarnpkg.com/commoner/-/commoner-0.10.8.tgz#34fc3672cd24393e8bb47e70caa0293811f4f2c5" + dependencies: + commander "^2.5.0" + detective "^4.3.1" + glob "^5.0.15" + graceful-fs "^4.1.2" + iconv-lite "^0.4.5" + mkdirp "^0.5.0" + private "^0.1.6" + q "^1.1.2" + recast "^0.11.17" + component-classes@1.x, component-classes@^1.2.5, component-classes@^1.2.6: version "1.2.6" resolved "https://registry.yarnpkg.com/component-classes/-/component-classes-1.2.6.tgz#c642394c3618a4d8b0b8919efccbbd930e5cd691" @@ -1758,7 +1827,7 @@ crypto-browserify@^3.11.0: randombytes "^2.0.0" randomfill "^1.0.3" -crypto-js@^3.1.8: +crypto-js@3.1.8: version "3.1.8" resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-3.1.8.tgz#715f070bf6014f2ae992a98b3929258b713f08d5" @@ -1908,13 +1977,7 @@ debug@2.6.0: dependencies: ms "0.7.2" -debug@2.6.4: - version "2.6.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.4.tgz#7586a9b3c39741c0282ae33445c4e8ac74734fe0" - dependencies: - ms "0.7.3" - -debug@2.6.9, debug@^2.1.3, debug@^2.2.0, debug@^2.3.3, debug@^2.5.1, debug@^2.6.3, debug@^2.6.6, debug@^2.6.8: +debug@2.6.9, debug@^2.1.0, debug@^2.1.3, debug@^2.2.0, debug@^2.3.3, debug@^2.5.1, debug@^2.6.3, debug@^2.6.6, debug@^2.6.8: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" dependencies: @@ -2036,6 +2099,13 @@ detect-node@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.3.tgz#a2033c09cc8e158d37748fbde7507832bd6ce127" +detective@^4.3.1: + version "4.7.1" + resolved "https://registry.yarnpkg.com/detective/-/detective-4.7.1.tgz#0eca7314338442febb6d65da54c10bb1c82b246e" + dependencies: + acorn "^5.2.1" + defined "^1.0.0" + diff@^3.2.0: version "3.4.0" resolved "https://registry.yarnpkg.com/diff/-/diff-3.4.0.tgz#b1d85507daf3964828de54b37d0d73ba67dda56c" @@ -2314,6 +2384,14 @@ es-to-primitive@^1.1.1: is-date-object "^1.0.1" is-symbol "^1.0.1" +es3ify@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/es3ify/-/es3ify-0.2.2.tgz#5dae3e650e5be3684b88066513d528d092629862" + dependencies: + esprima "^2.7.1" + jstransform "~11.0.0" + through "~2.3.4" + es5-ext@^0.10.14, es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14: version "0.10.38" resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.38.tgz#fa7d40d65bbc9bb8a67e1d3f9cc656a00530eed3" @@ -2387,7 +2465,19 @@ escope@^3.6.0: esrecurse "^4.1.0" estraverse "^4.1.1" -esprima@^2.6.0: +esmangle-evaluator@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/esmangle-evaluator/-/esmangle-evaluator-1.0.1.tgz#620d866ef4861b3311f75766d52a8572bb3c6336" + +esprima-fb@^15001.1.0-dev-harmony-fb: + version "15001.1.0-dev-harmony-fb" + resolved "https://registry.yarnpkg.com/esprima-fb/-/esprima-fb-15001.1.0-dev-harmony-fb.tgz#30a947303c6b8d5e955bee2b99b1d233206a6901" + +esprima-fb@~15001.1001.0-dev-harmony-fb: + version "15001.1001.0-dev-harmony-fb" + resolved "https://registry.yarnpkg.com/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz#43beb57ec26e8cf237d3dd8b33e42533577f2659" + +esprima@^2.6.0, esprima@^2.7.1: version "2.7.3" resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" @@ -2395,6 +2485,10 @@ esprima@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" +esprima@~3.1.0: + version "3.1.3" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" + esrecurse@^4.1.0: version "4.2.0" resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.0.tgz#fa9568d98d3823f9a41d91e902dcab9ea6e5b163" @@ -2609,6 +2703,15 @@ extsprintf@^1.2.0: version "1.4.0" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" +falafel@^1.0.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/falafel/-/falafel-1.2.0.tgz#c18d24ef5091174a497f318cd24b026a25cddab4" + dependencies: + acorn "^1.0.3" + foreach "^2.0.5" + isarray "0.0.1" + object-keys "^1.0.6" + fast-deep-equal@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff" @@ -2938,6 +3041,16 @@ glob-parent@^2.0.0: dependencies: is-glob "^2.0.0" +glob@^5.0.15: + version "5.0.15" + resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" + dependencies: + inflight "^1.0.4" + inherits "2" + minimatch "2 || 3" + once "^1.3.0" + path-is-absolute "^1.0.0" + glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2: version "7.1.2" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" @@ -3309,7 +3422,7 @@ https-browserify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" -iconv-lite@0.4.19, iconv-lite@~0.4.13: +iconv-lite@0.4.19, iconv-lite@^0.4.5, iconv-lite@~0.4.13: version "0.4.19" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" @@ -3399,6 +3512,13 @@ ini@~1.3.0: version "1.3.5" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" +inline-process-browser@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/inline-process-browser/-/inline-process-browser-1.0.0.tgz#46a61b153dd3c9b1624b1a00626edb4f7f414f22" + dependencies: + falafel "^1.0.1" + through2 "^0.6.5" + internal-ip@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-1.2.0.tgz#ae9fbf93b984878785d50a8de1b356956058cf5c" @@ -3468,6 +3588,10 @@ is-array-buffer-x@^1.0.13: object-get-own-property-descriptor-x "^3.2.0" to-string-tag-x "^1.4.1" +is-array@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-array/-/is-array-1.0.1.tgz#e9850cc2cc860c3bc0977e84ccf0dd464584279a" + is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" @@ -3634,9 +3758,9 @@ is-index-x@^1.0.0: to-number-x "^2.0.0" to-string-symbols-supported-x "^1.0.0" -is-my-json-valid@2.16.1: - version "2.16.1" - resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.16.1.tgz#5a846777e2c2620d1e69104e5d3a03b1f6088f11" +is-my-json-valid@^2.16.0: + version "2.17.1" + resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.17.1.tgz#3da98914a70a22f0a8563ef1511a246c6fc55471" dependencies: generate-function "^2.0.0" generate-object-property "^1.1.0" @@ -3936,6 +4060,16 @@ jsprim@^1.2.2: json-schema "0.2.3" verror "1.10.0" +jstransform@~11.0.0: + version "11.0.3" + resolved "https://registry.yarnpkg.com/jstransform/-/jstransform-11.0.3.tgz#09a78993e0ae4d4ef4487f6155a91f6190cb4223" + dependencies: + base62 "^1.1.0" + commoner "^0.10.1" + esprima-fb "^15001.1.0-dev-harmony-fb" + object-assign "^2.0.0" + source-map "^0.4.2" + keytar@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/keytar/-/keytar-4.1.0.tgz#9e3933e489d656de1a868e1293709313044989d7" @@ -4024,15 +4158,18 @@ leven@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580" -lie@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/lie/-/lie-3.1.0.tgz#65e0139eaef9ae791a1f5c8c53692c8d3b4718f4" +lie@3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/lie/-/lie-3.0.4.tgz#bc7ae1ebe7f1c8de39afdcd4f789076b47b0f634" dependencies: + es3ify "^0.2.2" immediate "~3.0.5" + inline-process-browser "^1.0.0" + unreachable-branch-transform "^0.3.0" -lie@3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/lie/-/lie-3.1.1.tgz#9a436b2cc7746ca59de7a41fa469b3efb76bd87e" +lie@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lie/-/lie-3.1.0.tgz#65e0139eaef9ae791a1f5c8c53692c8d3b4718f4" dependencies: immediate "~3.0.5" @@ -4595,7 +4732,7 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" -minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.4: +"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" dependencies: @@ -4649,13 +4786,6 @@ mobx@^3.4.1: version "3.4.1" resolved "https://registry.yarnpkg.com/mobx/-/mobx-3.4.1.tgz#37abe5ee882d401828d9f26c6c1a2f47614bbbef" -modifyjs@0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/modifyjs/-/modifyjs-0.3.1.tgz#72469477fb4c470971d617a63ba1bbde9aaac7cf" - dependencies: - clone "^2.1.1" - deep-equal "^1.0.1" - moment@2.x, moment@^2.19.3, moment@^2.20.1: version "2.20.1" resolved "https://registry.yarnpkg.com/moment/-/moment-2.20.1.tgz#d6eb1a46cbcc14a2b2f9434112c1ff8907f313fd" @@ -4664,10 +4794,6 @@ ms@0.7.2: version "0.7.2" resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" -ms@0.7.3: - version "0.7.3" - resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.3.tgz#708155a5e44e33f5fd0fc53e81d0d40a91be1fff" - ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -4922,6 +5048,10 @@ object-assign@4.x, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4. version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" +object-assign@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-2.1.1.tgz#43c36e5d569ff8e4816c4efa8be02d26967c18aa" + object-copy@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" @@ -4945,7 +5075,7 @@ object-get-own-property-descriptor-x@^3.2.0: to-object-x "^1.4.1" to-property-key-x "^2.0.1" -object-keys@^1.0.8: +object-keys@^1.0.6, object-keys@^1.0.8: version "1.0.11" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d" @@ -4953,7 +5083,7 @@ object-keys@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-0.4.0.tgz#28a6aae7428dd2c3a92f3d95f21335dd204e0336" -object-path@0.11.4: +object-path@^0.11.4: version "0.11.4" resolved "https://registry.yarnpkg.com/object-path/-/object-path-0.11.4.tgz#370ae752fbf37de3ea70a861c23bba8915691949" @@ -5606,18 +5736,6 @@ postcss@^6.0.1, postcss@^6.0.14, postcss@^6.0.3, postcss@^6.0.6, postcss@^6.0.8: source-map "^0.6.1" supports-color "^4.4.0" -pouchdb-abstract-mapreduce@6.3.4: - version "6.3.4" - resolved "https://registry.yarnpkg.com/pouchdb-abstract-mapreduce/-/pouchdb-abstract-mapreduce-6.3.4.tgz#0d8a11ec300e3affcacbf6e9618d3eccd3f2e9ce" - dependencies: - pouchdb-binary-utils "6.3.4" - pouchdb-collate "6.3.4" - pouchdb-collections "6.3.4" - pouchdb-mapreduce-utils "6.3.4" - pouchdb-md5 "6.3.4" - pouchdb-promise "6.3.4" - pouchdb-utils "6.3.4" - pouchdb-adapter-idb@6.1.2: version "6.1.2" resolved "https://registry.yarnpkg.com/pouchdb-adapter-idb/-/pouchdb-adapter-idb-6.1.2.tgz#06f0f432705f6e9ae89c2aba6f08f0b7a0d83eff" @@ -5648,59 +5766,27 @@ pouchdb-binary-utils@6.1.2: dependencies: buffer-from "0.1.1" -pouchdb-binary-utils@6.3.4: - version "6.3.4" - resolved "https://registry.yarnpkg.com/pouchdb-binary-utils/-/pouchdb-binary-utils-6.3.4.tgz#9bfd1b4b3d8caccfd2b6046b1316b4f70afea9f6" - dependencies: - buffer-from "0.1.1" - -pouchdb-changes-filter@6.3.4: - version "6.3.4" - resolved "https://registry.yarnpkg.com/pouchdb-changes-filter/-/pouchdb-changes-filter-6.3.4.tgz#00947871a18a365a7a730a92ed29471ee5b44442" - dependencies: - pouchdb-errors "6.3.4" - pouchdb-selector-core "6.3.4" - pouchdb-utils "6.3.4" - -pouchdb-checkpointer@6.3.4: - version "6.3.4" - resolved "https://registry.yarnpkg.com/pouchdb-checkpointer/-/pouchdb-checkpointer-6.3.4.tgz#9e2368fd043fd45a79813ce4f8b45e186cb189b0" - dependencies: - pouchdb-collate "6.3.4" - pouchdb-promise "6.3.4" - pouchdb-utils "6.3.4" - -pouchdb-collate@6.3.4: - version "6.3.4" - resolved "https://registry.yarnpkg.com/pouchdb-collate/-/pouchdb-collate-6.3.4.tgz#4f03245b3309fdd5f937caffc9efa0e8ee591b4d" +pouchdb-collate@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/pouchdb-collate/-/pouchdb-collate-1.2.0.tgz#cae3b830fca124b7f97d23046e4faa311ec3828c" pouchdb-collections@6.1.2: version "6.1.2" resolved "https://registry.yarnpkg.com/pouchdb-collections/-/pouchdb-collections-6.1.2.tgz#070161cdf485d87ddd29d977e4e8392dabf9313d" -pouchdb-collections@6.3.4: - version "6.3.4" - resolved "https://registry.yarnpkg.com/pouchdb-collections/-/pouchdb-collections-6.3.4.tgz#24f4dd3d7aabd630b2f5f26353fe09ddd4ef7afa" - -pouchdb-core@6.3.4: - version "6.3.4" - resolved "https://registry.yarnpkg.com/pouchdb-core/-/pouchdb-core-6.3.4.tgz#843f1c63b4da3be7dffb2d0bdf1663a250ab092c" +pouchdb-core@6.1.2: + version "6.1.2" + resolved "https://registry.yarnpkg.com/pouchdb-core/-/pouchdb-core-6.1.2.tgz#57fc869ff99087e4af60d8b941a3681d5f915b1c" dependencies: argsarray "0.0.1" + debug "2.6.0" inherits "2.0.3" - pouchdb-changes-filter "6.3.4" - pouchdb-collections "6.3.4" - pouchdb-debug "6.3.4" - pouchdb-errors "6.3.4" - pouchdb-merge "6.3.4" - pouchdb-promise "6.3.4" - pouchdb-utils "6.3.4" - -pouchdb-debug@6.3.4: - version "6.3.4" - resolved "https://registry.yarnpkg.com/pouchdb-debug/-/pouchdb-debug-6.3.4.tgz#cea3e707307ec95911441f31f086a07a95aea806" - dependencies: - debug "2.6.4" + pouchdb-collections "6.1.2" + pouchdb-errors "6.1.2" + pouchdb-merge "6.1.2" + pouchdb-promise "6.1.2" + pouchdb-utils "6.1.2" + scope-eval "0.0.3" pouchdb-errors@6.1.2: version "6.1.2" @@ -5708,30 +5794,23 @@ pouchdb-errors@6.1.2: dependencies: inherits "2.0.3" -pouchdb-errors@6.3.4: - version "6.3.4" - resolved "https://registry.yarnpkg.com/pouchdb-errors/-/pouchdb-errors-6.3.4.tgz#abc1a84242e9276a1102e5cba1802aa08e5be45a" - dependencies: - inherits "2.0.3" - -pouchdb-find@6.3.4: - version "6.3.4" - resolved "https://registry.yarnpkg.com/pouchdb-find/-/pouchdb-find-6.3.4.tgz#27163e3d9a82bab2cc6db1deb73447762e8bd705" - dependencies: - pouchdb-abstract-mapreduce "6.3.4" - pouchdb-collate "6.3.4" - pouchdb-md5 "6.3.4" - pouchdb-promise "6.3.4" - pouchdb-selector-core "6.3.4" - pouchdb-utils "6.3.4" +pouchdb-extend@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/pouchdb-extend/-/pouchdb-extend-0.1.2.tgz#d1ce511bf704ed2e29f7bf428a416acfffa124b8" -pouchdb-generate-replication-id@6.3.4: - version "6.3.4" - resolved "https://registry.yarnpkg.com/pouchdb-generate-replication-id/-/pouchdb-generate-replication-id-6.3.4.tgz#d59012f196e0119ad00d53e616ac1dd0160a22a1" +pouchdb-find@^0.10.5: + version "0.10.5" + resolved "https://registry.yarnpkg.com/pouchdb-find/-/pouchdb-find-0.10.5.tgz#34f285b8a56496a98f9cef2e1a1f6a0aac4eae8b" dependencies: - pouchdb-collate "6.3.4" - pouchdb-md5 "6.3.4" - pouchdb-promise "6.3.4" + argsarray "0.0.1" + debug "^2.1.0" + inherits "^2.0.1" + is-array "^1.0.1" + pouchdb-collate "^1.2.0" + pouchdb-extend "^0.1.2" + pouchdb-promise "5.4.0" + pouchdb-upsert "~2.0.1" + spark-md5 "2.0.2" pouchdb-json@6.1.2: version "6.1.2" @@ -5739,15 +5818,6 @@ pouchdb-json@6.1.2: dependencies: vuvuzela "1.0.3" -pouchdb-mapreduce-utils@6.3.4: - version "6.3.4" - resolved "https://registry.yarnpkg.com/pouchdb-mapreduce-utils/-/pouchdb-mapreduce-utils-6.3.4.tgz#0d85fb7cc1faf078afc638fdf07d9db3ce8fdaa6" - dependencies: - argsarray "0.0.1" - inherits "2.0.3" - pouchdb-collections "6.3.4" - pouchdb-utils "6.3.4" - pouchdb-md5@6.1.2: version "6.1.2" resolved "https://registry.yarnpkg.com/pouchdb-md5/-/pouchdb-md5-6.1.2.tgz#27ab60957326dcc5b1e9dd56ba3f72eb2b53240d" @@ -5755,20 +5825,15 @@ pouchdb-md5@6.1.2: pouchdb-binary-utils "6.1.2" spark-md5 "3.0.0" -pouchdb-md5@6.3.4: - version "6.3.4" - resolved "https://registry.yarnpkg.com/pouchdb-md5/-/pouchdb-md5-6.3.4.tgz#364987fa184a33a48cfc7eb175a279fca113a4e8" - dependencies: - pouchdb-binary-utils "6.3.4" - spark-md5 "3.0.0" - pouchdb-merge@6.1.2: version "6.1.2" resolved "https://registry.yarnpkg.com/pouchdb-merge/-/pouchdb-merge-6.1.2.tgz#406c2a95b84bdb16fe973ab4b7d8f26153cc42aa" -pouchdb-merge@6.3.4: - version "6.3.4" - resolved "https://registry.yarnpkg.com/pouchdb-merge/-/pouchdb-merge-6.3.4.tgz#6c843304affafe2f66225586ee5d44f1079a7678" +pouchdb-promise@5.4.0: + version "5.4.0" + resolved "https://registry.yarnpkg.com/pouchdb-promise/-/pouchdb-promise-5.4.0.tgz#e277ac6bda1ac8504597abb5c43a7c3a9e56866f" + dependencies: + lie "3.0.4" pouchdb-promise@6.1.2: version "6.1.2" @@ -5776,29 +5841,17 @@ pouchdb-promise@6.1.2: dependencies: lie "3.1.0" -pouchdb-promise@6.3.4: - version "6.3.4" - resolved "https://registry.yarnpkg.com/pouchdb-promise/-/pouchdb-promise-6.3.4.tgz#817052fa2320293dd2dbc4be2f1cc81b02be30c2" +pouchdb-promise@^5.4.3: + version "5.4.5" + resolved "https://registry.yarnpkg.com/pouchdb-promise/-/pouchdb-promise-5.4.5.tgz#5c2a69759141eb73be1e172e522fd84da2e0752e" dependencies: - lie "3.1.1" - -pouchdb-replication@6.3.4: - version "6.3.4" - resolved "https://registry.yarnpkg.com/pouchdb-replication/-/pouchdb-replication-6.3.4.tgz#a1d22ace6f18e0bb459dc152ed0eed71d56534b0" - dependencies: - inherits "2.0.3" - pouchdb-checkpointer "6.3.4" - pouchdb-errors "6.3.4" - pouchdb-generate-replication-id "6.3.4" - pouchdb-promise "6.3.4" - pouchdb-utils "6.3.4" + lie "3.0.4" -pouchdb-selector-core@6.3.4: - version "6.3.4" - resolved "https://registry.yarnpkg.com/pouchdb-selector-core/-/pouchdb-selector-core-6.3.4.tgz#116958b1af9d7147143da5a5e6ee74de128a9fbc" +pouchdb-upsert@~2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/pouchdb-upsert/-/pouchdb-upsert-2.0.2.tgz#c746cc9945e52d8c78e42f63ade0666777996712" dependencies: - pouchdb-collate "6.3.4" - pouchdb-utils "6.3.4" + pouchdb-promise "^5.4.3" pouchdb-utils@6.1.2: version "6.1.2" @@ -5813,19 +5866,6 @@ pouchdb-utils@6.1.2: pouchdb-errors "6.1.2" pouchdb-promise "6.1.2" -pouchdb-utils@6.3.4: - version "6.3.4" - resolved "https://registry.yarnpkg.com/pouchdb-utils/-/pouchdb-utils-6.3.4.tgz#3926541ae439c019d9738d5e5c3aa9bb110e6a25" - dependencies: - argsarray "0.0.1" - clone-buffer "1.0.0" - immediate "3.0.6" - inherits "2.0.3" - pouchdb-collections "6.3.4" - pouchdb-errors "6.3.4" - pouchdb-promise "6.3.4" - uuid "^3.1.0" - pre-commit@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/pre-commit/-/pre-commit-1.2.2.tgz#dbcee0ee9de7235e57f79c56d7ce94641a69eec6" @@ -5867,7 +5907,7 @@ pretty-format@^21.2.1: ansi-regex "^3.0.0" ansi-styles "^3.2.0" -private@^0.1.6, private@^0.1.7: +private@^0.1.6, private@^0.1.7, private@~0.1.5: version "0.1.8" resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" @@ -6487,7 +6527,7 @@ read-pkg@^3.0.0: normalize-package-data "^2.3.2" path-type "^3.0.0" -readable-stream@1.0: +readable-stream@1.0, "readable-stream@>=1.0.33-1 <1.1.0-0": version "1.0.34" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" dependencies: @@ -6526,6 +6566,24 @@ readdirp@^2.0.0: readable-stream "^2.0.2" set-immediate-shim "^1.0.1" +recast@^0.10.1: + version "0.10.43" + resolved "https://registry.yarnpkg.com/recast/-/recast-0.10.43.tgz#b95d50f6d60761a5f6252e15d80678168491ce7f" + dependencies: + ast-types "0.8.15" + esprima-fb "~15001.1001.0-dev-harmony-fb" + private "~0.1.5" + source-map "~0.5.0" + +recast@^0.11.17: + version "0.11.23" + resolved "https://registry.yarnpkg.com/recast/-/recast-0.11.23.tgz#451fd3004ab1e4df9b4e4b66376b2a21912462d3" + dependencies: + ast-types "0.9.6" + esprima "~3.1.0" + private "~0.1.5" + source-map "~0.5.0" + redent@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" @@ -6853,26 +6911,25 @@ rmc-feedback@^1.0.0: babel-runtime "6.x" classnames "^2.2.5" -rxdb@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/rxdb/-/rxdb-6.0.1.tgz#7a6a7c8326ec170f04a6861a949fbfc17926a305" +rxdb@^3.0.0: + version "3.0.8" + resolved "https://registry.yarnpkg.com/rxdb/-/rxdb-3.0.8.tgz#ac232109d03d4db3f94a11acd048a0c510652223" dependencies: - "@types/core-js" "0.9.43" - babel-runtime "^6.25.0" + "@types/core-js" "^0.9.35" + babel-preset-es2015-native-modules "6.9.4" + babel-runtime "^6.23.0" clone "^2.1.1" - crypto-js "^3.1.8" + crypto-js "3.1.8" deep-equal "^1.0.1" - is-my-json-valid "2.16.1" - modifyjs "0.3.1" - object-path "0.11.4" - pouchdb-core "6.3.4" - pouchdb-find "6.3.4" - pouchdb-replication "6.3.4" - pouchdb-selector-core "6.3.4" + es6-promise "^4.0.5" + is-my-json-valid "^2.16.0" + object-path "^0.11.4" + pouchdb-core "6.1.2" + pouchdb-find "^0.10.5" random-token "0.0.8" - spark-md5 "^3.0.0" + spark-md5 "3.0.0" unload "^1.3.5" - url "^0.11.0" + url "0.11.0" rxjs@^5.1.1, rxjs@^5.4.2: version "5.5.6" @@ -6894,6 +6951,10 @@ schema-utils@^0.3.0: dependencies: ajv "^5.0.0" +scope-eval@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/scope-eval/-/scope-eval-0.0.3.tgz#166f2ccd1f3754429dec511805501f9d6923b5ec" + select-hose@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" @@ -7145,15 +7206,25 @@ source-map-url@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" -source-map@0.5.x, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1: +source-map@0.5.x, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.0, source-map@~0.5.1: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" +source-map@^0.4.2: + version "0.4.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" + dependencies: + amdefine ">=0.0.4" + source-map@^0.6.1, source-map@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" -spark-md5@3.0.0, spark-md5@^3.0.0: +spark-md5@2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/spark-md5/-/spark-md5-2.0.2.tgz#37b763847763ae7e7acef2ca5233d01e649a78b7" + +spark-md5@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/spark-md5/-/spark-md5-3.0.0.tgz#3722227c54e2faf24b1dc6d933cc144e6f71bfef" @@ -7539,6 +7610,13 @@ throttleit@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-0.0.2.tgz#cfedf88e60c00dd9697b61fdd2a8343a9b680eaf" +through2@^0.6.2, through2@^0.6.5: + version "0.6.5" + resolved "https://registry.yarnpkg.com/through2/-/through2-0.6.5.tgz#41ab9c67b29d57209071410e1d7a7a968cd3ad48" + dependencies: + readable-stream ">=1.0.33-1 <1.1.0-0" + xtend ">=4.0.0 <4.1.0-0" + through2@~0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/through2/-/through2-0.2.3.tgz#eb3284da4ea311b6cc8ace3653748a52abf25a3f" @@ -7546,6 +7624,10 @@ through2@~0.2.3: readable-stream "~1.1.9" xtend "~2.1.1" +through@~2.3.4: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + thunky@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/thunky/-/thunky-0.1.0.tgz#bf30146824e2b6e67b0f2d7a4ac8beb26908684e" @@ -7945,13 +8027,21 @@ universalify@^0.1.0: resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.1.tgz#fa71badd4437af4c148841e3b3b165f9e9e590b7" unload@^1.3.5: - version "1.3.5" - resolved "https://registry.yarnpkg.com/unload/-/unload-1.3.5.tgz#028b8a61dd5ef9b576a983c06e02776676523c4d" + version "1.3.6" + resolved "https://registry.yarnpkg.com/unload/-/unload-1.3.6.tgz#b68685007d7ac0444729747901717c6275131f6d" unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" +unreachable-branch-transform@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/unreachable-branch-transform/-/unreachable-branch-transform-0.3.0.tgz#d99cc4c6e746d264928845b611db54b0f3474caa" + dependencies: + esmangle-evaluator "^1.0.0" + recast "^0.10.1" + through2 "^0.6.2" + unset-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" @@ -7989,7 +8079,7 @@ url-parse@^1.1.8: querystringify "~1.0.0" requires-port "~1.0.0" -url@^0.11.0: +url@0.11.0, url@^0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" dependencies: @@ -8317,7 +8407,7 @@ xml-char-classes@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/xml-char-classes/-/xml-char-classes-1.0.0.tgz#64657848a20ffc5df583a42ad8a277b4512bbc4d" -xtend@^4.0.0, xtend@^4.0.1: +"xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0, xtend@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" From 6caba7d82f24931e0bbe7550b24c0d1f12489aa1 Mon Sep 17 00:00:00 2001 From: wuxueqian Date: Sun, 28 Jan 2018 19:14:32 +0800 Subject: [PATCH 18/25] restore searchbox --- src/renderer/assets/styles/main.less | 43 ------ src/renderer/components/SearchBox/index.tsx | 126 +++++++++++++++++- .../components/SearchBox/styles/index.less | 42 ++++++ src/renderer/store/MainStore.ts | 9 ++ 4 files changed, 173 insertions(+), 47 deletions(-) create mode 100644 src/renderer/components/SearchBox/styles/index.less diff --git a/src/renderer/assets/styles/main.less b/src/renderer/assets/styles/main.less index 8b31b50..54c3c2d 100644 --- a/src/renderer/assets/styles/main.less +++ b/src/renderer/assets/styles/main.less @@ -7,49 +7,6 @@ padding-bottom: 40px; } -.searchBox { - padding: 12px 10px; - > span { - border: 0; - z-index: 999; - &:hover { - input { - border-color: #d9d9d9 !important; - } - } - } - input { - background: rgb(225, 225, 225); - text-align: center; - &:focus { - box-shadow: none; - border-color: #d9d9d9; - background: #fff; - } - &:hover { - border-color: #d9d9d9; - background: #fff; - } - } - &:focus { - outline: 0; - } -} - -.searchBoxFocused { - > .searchFields { - margin-top: 0px; - } -} - -.searchFields { - position: relative; - padding: 10px 0; - transition: all 0.3s ease; - margin-top: -36px; - text-align: center; -} - .reposListWrapper { position: relative; flex: 1; diff --git a/src/renderer/components/SearchBox/index.tsx b/src/renderer/components/SearchBox/index.tsx index 2d88dfa..6cd0bad 100644 --- a/src/renderer/components/SearchBox/index.tsx +++ b/src/renderer/components/SearchBox/index.tsx @@ -1,17 +1,135 @@ import * as React from "react"; +import { observer, inject } from "mobx-react"; +import ClassNames from "classnames"; +import { Input, Radio, message } from "antd"; +import IStore from "../../interface/IStore"; +import SearchType from "../../enum/SearchType"; -// const styles = require("./index.less"); +const Search = Input.Search; +const RadioButton = Radio.Button; +const RadioGroup = Radio.Group; -interface SearchBoxProps {} +const styles = require("./styles/index.less"); -interface SearchBoxState {} +interface SearchBoxProps { + store?: IStore; +} + +interface SearchBoxState { + focus: boolean; + focusLock: boolean; + searchField: SearchType; + words: string; + searching: boolean; +} +@inject("store") +@observer export default class SearchBox extends React.Component { constructor(props) { super(props); + this.state = { + focus: false, + focusLock: false, + searchField: SearchType.SEARCH_FIELD_ALL, + words: "", + searching: false + }; } + onFocus = () => { + this.setState({ + focus: true + }); + }; + + onBlur = () => { + if (this.state.focusLock) { + return; + } + this.setState({ + focus: false + }); + }; + + onSearch = value => { + const mainStore = this.props.store!.main; + const { fetching } = mainStore; + const { searching, words, searchField } = this.state; + if (searching || words === value || fetching) { + return; + } + this.setState({ + searching: true, + words: value + }); + + mainStore + .onUpdateSearchCondition(value, searchField) + .then(repos => { + if (value && repos) { + message.success(`Searched ${repos.length} results`); + } + }) + .finally(() => { + this.setState({ + searching: false + }); + }); + }; + + onMouseEnter = () => { + this.setState({ + focusLock: true + }); + }; + + onMouseLeave = () => { + this.setState({ + focusLock: false + }); + }; + + onRadioChange = e => { + const field = e.target.value; + this.setState({ + searchField: field + }); + }; + render() { - return
SearchBox
; + return ( +
+ +
+ + All + Name + + Intro + + Note + Tags + +
+
+ ); } } diff --git a/src/renderer/components/SearchBox/styles/index.less b/src/renderer/components/SearchBox/styles/index.less new file mode 100644 index 0000000..789ed08 --- /dev/null +++ b/src/renderer/components/SearchBox/styles/index.less @@ -0,0 +1,42 @@ +.searchBox { + padding: 12px 10px; + > span { + border: 0; + z-index: 999; + &:hover { + input { + border-color: #d9d9d9 !important; + } + } + } + input { + background: rgb(225, 225, 225); + text-align: center; + &:focus { + box-shadow: none; + border-color: #d9d9d9; + background: #fff; + } + &:hover { + border-color: #d9d9d9; + background: #fff; + } + } + &:focus { + outline: 0; + } +} + +.searchBoxFocused { + > .searchFields { + margin-top: 0px; + } +} + +.searchFields { + position: relative; + padding: 10px 0; + transition: all 0.3s ease; + margin-top: -36px; + text-align: center; +} diff --git a/src/renderer/store/MainStore.ts b/src/renderer/store/MainStore.ts index 85cc6df..b65d1d5 100644 --- a/src/renderer/store/MainStore.ts +++ b/src/renderer/store/MainStore.ts @@ -116,6 +116,15 @@ export default class MainStore { */ @observable search: ISearchConditionState = { key: "", field: SearchType.SEARCH_FIELD_ALL }; + @action + onUpdateSearchCondition = (key: string, field: SearchType) => { + this.search = { + key, + field + }; + return this.updateRepoList(); + }; + /** * Order condition */ From 19edfca46174e8a2a193676f56cfa6a9a6fe4a76 Mon Sep 17 00:00:00 2001 From: wuxueqian Date: Sun, 28 Jan 2018 19:42:28 +0800 Subject: [PATCH 19/25] restore repo list --- src/renderer/assets/styles/main.less | 95 ------------------- src/renderer/components/ReposList/index.tsx | 31 +++++- src/renderer/components/ReposList/item.tsx | 89 +++++++++++++++++ .../components/ReposList/styles/index.less | 7 ++ .../components/ReposList/styles/item.less | 86 +++++++++++++++++ src/renderer/store/MainStore.ts | 36 ++++++- 6 files changed, 245 insertions(+), 99 deletions(-) create mode 100644 src/renderer/components/ReposList/item.tsx create mode 100644 src/renderer/components/ReposList/styles/index.less create mode 100644 src/renderer/components/ReposList/styles/item.less diff --git a/src/renderer/assets/styles/main.less b/src/renderer/assets/styles/main.less index 54c3c2d..75a0571 100644 --- a/src/renderer/assets/styles/main.less +++ b/src/renderer/assets/styles/main.less @@ -7,101 +7,6 @@ padding-bottom: 40px; } -.reposListWrapper { - position: relative; - flex: 1; - overflow-y: auto; - padding: 0; - // margin-bottom: 10px; -} - -.repoListItem { - position: relative; - padding: 0; - border-bottom: 1px solid rgb(230, 235, 239); // 1px solid #f5f5f5; - // background-color: #fff; - &.repoSelected { - background-color: #e5e5e5; - header { - > span { - > ul { - > li { - color: #fff; - transition: none; - } - } - } - } - } - &:hover { - background: #eaeaea; - header { - > span { - > ul { - > li { - color: #fff; - transition: none; - } - } - } - } - } - &:last-child { - border-bottom: 0; - } - > .repoItemInner { - padding: 10px; - > header { - position: relative; - > h2 { - // white-space: nowrap; - word-break: break-all; - text-overflow: ellipsis; - padding-right: 88px; - font-size: 18px; - font-weight: 500; - line-height: 20px; - overflow: hidden; - color: #3498db; // #56a07b; - } - > span { - position: absolute; - top: 0; - right: 0; - > ul { - text-align: right; - font-size: 12px; - line-height: 20px; - > li { - margin-right: 3px; - &:last-child { - margin-right: 0; - } - } - } - } - } - > div { - > p { - font-size: 13px; - line-height: 1.5; - padding: 8px 0; - color: #28353d; - word-wrap: break-word; - word-break: break-all; - margin-bottom: 10px; - } - } - > footer { - font-size: 13px; - color: #658399; - i { - margin-right: 5px; - } - } - } -} - .sortBarWrap { position: relative; height: 24px; diff --git a/src/renderer/components/ReposList/index.tsx b/src/renderer/components/ReposList/index.tsx index b9d82be..88250ce 100644 --- a/src/renderer/components/ReposList/index.tsx +++ b/src/renderer/components/ReposList/index.tsx @@ -1,17 +1,42 @@ import * as React from "react"; +import { observer, inject } from "mobx-react"; +import ClassNames from "classnames"; +import IStore from "../../interface/IStore"; +import RepoListItem from "./item"; -// const styles = require("./index.less"); +const styles = require("./styles/index.less"); -interface ReposListProps {} +interface ReposListProps { + store?: IStore; +} interface ReposListState {} +@inject("store") +@observer export default class ReposList extends React.Component { constructor(props) { super(props); } render() { - return
ReposList
; + const mainStore = this.props.store!.main; + const { repos, selectedRepo } = mainStore; + + return ( +
+ {Object.keys(repos) + .map(key => repos[key]) + .map(repo => ( + + ))} +
+ ); } } diff --git a/src/renderer/components/ReposList/item.tsx b/src/renderer/components/ReposList/item.tsx new file mode 100644 index 0000000..1faafe4 --- /dev/null +++ b/src/renderer/components/ReposList/item.tsx @@ -0,0 +1,89 @@ +import * as React from "react"; +import ClassNames from "classnames"; +import { Rate, Icon, Row, Col } from "antd"; +import IRepo from "../../interface/IRepo"; + +const styles = require("./styles/item.less"); + +interface RepoListItemProps { + repo: IRepo; + selectedRepo: IRepo; + onSelectRepo: (id: number) => void; + onRateRepo: (id: number, score: number) => void; +} + +interface RepoListItemState {} + +export default class RepoListItem extends React.Component { + constructor(props) { + super(props); + } + + clickStar = e => { + e.stopPropagation(); + }; + + onRateStar = value => { + this.props.onRateRepo(this.props.repo.id, value); + }; + + shouldComponentUpdate(nextProps) { + if ( + nextProps.selectedRepo.id !== this.props.selectedRepo.id || + nextProps.repo.id !== this.props.repo.id || + nextProps.repo.score !== this.props.repo.score + ) { + return true; + } + return false; + } + + render() { + const { repo, selectedRepo } = this.props; + const klass = ClassNames("repoListItem animated fadeIn", styles.repoListItem, { + [styles.repoSelected]: selectedRepo && repo.id === selectedRepo.id + }); + return ( +
+
+
+

{this.props.repo.name}

+ + } + defaultValue={0} + value={repo.score} + onChange={this.onRateStar} + /> + +
+
+

{this.props.repo.description}

+
+
+ + +
+ + {this.props.repo.lang} +
+ + +
+ + {this.props.repo.stars.toString()} +
+ + +
+ + {this.props.repo.forks.toString()} +
+ +
+
+
+
+ ); + } +} diff --git a/src/renderer/components/ReposList/styles/index.less b/src/renderer/components/ReposList/styles/index.less new file mode 100644 index 0000000..2321f3d --- /dev/null +++ b/src/renderer/components/ReposList/styles/index.less @@ -0,0 +1,7 @@ +.reposListWrapper { + position: relative; + flex: 1; + overflow-y: auto; + padding: 0; + // margin-bottom: 10px; +} diff --git a/src/renderer/components/ReposList/styles/item.less b/src/renderer/components/ReposList/styles/item.less new file mode 100644 index 0000000..8dc4d7a --- /dev/null +++ b/src/renderer/components/ReposList/styles/item.less @@ -0,0 +1,86 @@ +.repoListItem { + position: relative; + padding: 0; + border-bottom: 1px solid rgb(230, 235, 239); // 1px solid #f5f5f5; + // background-color: #fff; + &.repoSelected { + background-color: #e5e5e5; + header { + > span { + > ul { + > li { + color: #fff; + transition: none; + } + } + } + } + } + &:hover { + background: #eaeaea; + header { + > span { + > ul { + > li { + color: #fff; + transition: none; + } + } + } + } + } + &:last-child { + border-bottom: 0; + } + > .repoItemInner { + padding: 10px; + > header { + position: relative; + > h2 { + // white-space: nowrap; + word-break: break-all; + text-overflow: ellipsis; + padding-right: 88px; + font-size: 18px; + font-weight: 500; + line-height: 20px; + overflow: hidden; + color: #3498db; // #56a07b; + } + > span { + position: absolute; + top: 0; + right: 0; + > ul { + text-align: right; + font-size: 12px; + line-height: 20px; + > li { + margin-right: 3px; + &:last-child { + margin-right: 0; + } + } + } + } + } + > div { + > p { + font-size: 13px; + line-height: 1.5; + padding: 8px 0; + color: #28353d; + word-wrap: break-word; + word-break: break-all; + margin-bottom: 10px; + } + } + > footer { + font-size: 13px; + color: #658399; + i { + margin-right: 5px; + } + } + } +} diff --git a/src/renderer/store/MainStore.ts b/src/renderer/store/MainStore.ts index b65d1d5..4705a9c 100644 --- a/src/renderer/store/MainStore.ts +++ b/src/renderer/store/MainStore.ts @@ -203,7 +203,7 @@ export default class MainStore { // we need convert the array to key-value pairs let keyedRepos: { [key: string]: IRepo } = {}; repos.forEach(repo => { - keyedRepos["_" + repo.id] = repo; + keyedRepos[repo.id] = repo; }); this.repos = keyedRepos; @@ -252,4 +252,38 @@ export default class MainStore { this.fetching = false; }); }; + + /** + * Selected repo + */ + @observable selectedRepo: IRepo; + + @action + onSelectRepo = (id: number) => { + const { repos } = this; + this.selectedRepo = repos[id]; + }; + + @action + onRateRepo = (id: number, score: number) => { + const { repos } = this; + const updateObj = { + id, + score + }; + + return this.getDbHandler() + .then(dbHandler => dbHandler.updateRepo(updateObj)) + .then(repo => { + // also replace new repo into repos list + repos[repo.id] = repo; + this.repos = Object.assign({}, repos); + + return repo; + }) + .catch(error => { + logger.log(error.message || error.toString()); + // throw error; + }); + }; } From c549d552bdf717ec882bde998ccb55fed8071cab Mon Sep 17 00:00:00 2001 From: wuxueqian Date: Sun, 28 Jan 2018 22:40:50 +0800 Subject: [PATCH 20/25] restore repo list filter and sorter --- src/renderer/assets/styles/main.less | 60 ---------- src/renderer/components/FilterBar/index.tsx | 103 +++++++++++++++++- .../components/FilterBar/styles/index.less | 32 ++++++ .../MainGroupNavs/styles/index.less | 6 + .../MainGroupPane/styles/index.less | 1 + .../components/RefreshIndicator/index.tsx | 2 +- src/renderer/components/ReposList/index.tsx | 20 ++-- src/renderer/components/ReposList/item.tsx | 4 +- src/renderer/components/SortBar/index.tsx | 95 +++++++++++++++- .../components/SortBar/styles/index.less | 26 +++++ src/renderer/constants/index.ts | 9 -- src/renderer/enum/FilterType.ts | 9 ++ src/renderer/enum/Order.ts | 6 + src/renderer/interface/IConditional.ts | 10 +- src/renderer/store/MainStore.ts | 54 +++++++-- 15 files changed, 338 insertions(+), 99 deletions(-) create mode 100644 src/renderer/components/FilterBar/styles/index.less create mode 100644 src/renderer/components/SortBar/styles/index.less create mode 100644 src/renderer/enum/FilterType.ts create mode 100644 src/renderer/enum/Order.ts diff --git a/src/renderer/assets/styles/main.less b/src/renderer/assets/styles/main.less index 75a0571..63598db 100644 --- a/src/renderer/assets/styles/main.less +++ b/src/renderer/assets/styles/main.less @@ -7,66 +7,6 @@ padding-bottom: 40px; } -.sortBarWrap { - position: relative; - height: 24px; - font-size: 12px; - line-height: 20px; - margin-top: -16px; - text-align: right; - padding-right: 10px; - margin-bottom: 5px; - border-bottom: 1px solid #eaeaea; - > .reposCount { - float: left; - padding-left: 10px; - color: #9b9ea6; - font-size: 12px; - line-height: 20px; - } - > a { - color: #9b9ea6; - } -} - -.sortDropdown { - position: relative; - padding: 5px 0 !important; -} - -.filterDropdown { - position: relative; - padding: 5px 0 !important; -} - -.filterBarWrap { - position: relative; - height: 40px; - font-size: 12px; - line-height: 20px; - margin-top: 0; - text-align: center; - padding: 5px 10px 0; - border-top: 1px solid #eaeaea; - > i { - position: absolute; - left: 10px; - top: 0; - font-size: 20px; - line-height: 40px; - } - > a { - padding-top: 3px; - color: #9b9ea6; - } - > p { - padding-right: 5px; - font-size: 10px; - line-height: 12px; - color: #343536; - } -} - .detailHeader { -webkit-app-region: drag; .detailToolbar { diff --git a/src/renderer/components/FilterBar/index.tsx b/src/renderer/components/FilterBar/index.tsx index 096955f..95b7546 100644 --- a/src/renderer/components/FilterBar/index.tsx +++ b/src/renderer/components/FilterBar/index.tsx @@ -1,17 +1,114 @@ import * as React from "react"; +import { observer, inject } from "mobx-react"; +import ClassNames from "classnames"; +import { Icon, Menu, Dropdown, Checkbox } from "antd"; +import FilterType from "../../enum/FilterType"; +import IStore from "../../interface/IStore"; +import { IFilterConditionState } from "../../interface/IConditional"; -// const styles = require("./index.less"); +const styles = require("./styles/index.less"); -interface FilterBarProps {} +interface FilterBarProps { + store?: IStore; +} interface FilterBarState {} +@inject("store") +@observer export default class FilterBar extends React.Component { constructor(props) { super(props); } + get filters() { + const mainStore = this.props.store!.main; + const { filter } = mainStore; + const filters: FilterType[] = []; + if (filter.hasFlag) { + filters.push(FilterType.FILTER_OPTION_HAS_FLAG); + } + if (filter.hasNote) { + filters.push(FilterType.FILTER_OPTION_HAS_NOTE); + } + if (filter.unread) { + filters.push(FilterType.FILTER_OPTION_UNREAD); + } + + return filters; + } + + onMenuSelect = ({ key }) => { + const mainStore = this.props.store!.main; + const { fetching } = mainStore; + if (fetching) { + return; + } + + const index = this.filters.indexOf(key); + let filters = this.filters; + + if (key === FilterType.FILTER_OPTION_NONE) { + filters = []; + } else { + if (index > -1) { + filters.splice(index, 1); + } else { + filters.push(key); + } + } + + const filterCondition: IFilterConditionState = { + hasFlag: filters.includes(FilterType.FILTER_OPTION_HAS_FLAG), + hasNote: filters.includes(FilterType.FILTER_OPTION_HAS_NOTE), + unread: filters.includes(FilterType.FILTER_OPTION_UNREAD) + }; + + mainStore.onUpdateFilterCondition(filterCondition); + }; + render() { - return
FilterBar
; + const filterDict = { + [FilterType.FILTER_OPTION_UNREAD]: "UNREAD", + [FilterType.FILTER_OPTION_HAS_FLAG]: "HAS FLAG", + [FilterType.FILTER_OPTION_HAS_NOTE]: "HAS NOTE" + }; + + const upMenuItems = Object.keys(filterDict).map(key => { + return ( + + + {filterDict[key]} + + + ); + }); + + const menu = ( + + {upMenuItems} + + + + NONE + + + + ); + + return ( +
+ + + + FILTERS + + +

{this.filters.map(filter => filterDict[filter]).join(",")}

+
+ ); } } diff --git a/src/renderer/components/FilterBar/styles/index.less b/src/renderer/components/FilterBar/styles/index.less new file mode 100644 index 0000000..50748f7 --- /dev/null +++ b/src/renderer/components/FilterBar/styles/index.less @@ -0,0 +1,32 @@ +.filterDropdown { + position: relative; + padding: 5px 0 !important; +} + +.filterBarWrap { + position: relative; + height: 40px; + font-size: 12px; + line-height: 20px; + margin-top: 0; + text-align: center; + padding: 5px 10px 0; + border-top: 1px solid #eaeaea; + > i { + position: absolute; + left: 10px; + top: 0; + font-size: 20px; + line-height: 40px; + } + > a { + padding-top: 3px; + color: #9b9ea6; + } + > p { + padding-right: 5px; + font-size: 10px; + line-height: 12px; + color: #343536; + } +} diff --git a/src/renderer/components/MainGroupNavs/styles/index.less b/src/renderer/components/MainGroupNavs/styles/index.less index bf67346..bad48a8 100644 --- a/src/renderer/components/MainGroupNavs/styles/index.less +++ b/src/renderer/components/MainGroupNavs/styles/index.less @@ -1,5 +1,11 @@ .groupNav { position: relative; + & > ul { + font-family: inherit; + } + li + span { + font-weight: 300; + } } .langItem { diff --git a/src/renderer/components/MainGroupPane/styles/index.less b/src/renderer/components/MainGroupPane/styles/index.less index b3ae91c..e8f5b3e 100644 --- a/src/renderer/components/MainGroupPane/styles/index.less +++ b/src/renderer/components/MainGroupPane/styles/index.less @@ -5,4 +5,5 @@ background-color: rgba(39, 49, 67, 1); // border-right: 1px solid rgba(186,208,223,0.72); color: rgba(204, 204, 204, 1); + font-weight: 300; } diff --git a/src/renderer/components/RefreshIndicator/index.tsx b/src/renderer/components/RefreshIndicator/index.tsx index 48ee8d5..8e330ce 100644 --- a/src/renderer/components/RefreshIndicator/index.tsx +++ b/src/renderer/components/RefreshIndicator/index.tsx @@ -48,7 +48,7 @@ export default class RefreshIndicator extends React.Component< description: increase < 0 ? `Decreased ${Math.abs(increase)} starred repositories.` - : `${increase} starred repositories were added.`, + : `${increase} new starred repositories.`, duration: 10 }); }; diff --git a/src/renderer/components/ReposList/index.tsx b/src/renderer/components/ReposList/index.tsx index 88250ce..d5c8a8e 100644 --- a/src/renderer/components/ReposList/index.tsx +++ b/src/renderer/components/ReposList/index.tsx @@ -25,17 +25,15 @@ export default class ReposList extends React.Component - {Object.keys(repos) - .map(key => repos[key]) - .map(repo => ( - - ))} + {repos.map(repo => ( + + ))}
); } diff --git a/src/renderer/components/ReposList/item.tsx b/src/renderer/components/ReposList/item.tsx index 1faafe4..d49cc47 100644 --- a/src/renderer/components/ReposList/item.tsx +++ b/src/renderer/components/ReposList/item.tsx @@ -28,8 +28,10 @@ export default class RepoListItem extends React.Component { constructor(props) { super(props); } + onMenuSelect = ({ key }) => { + const mainStore = this.props.store!.main; + const { fetching, order } = mainStore; + const newOrder = Object.assign({}, toJS(order)); + + if (fetching) { + return; + } + + if (key === Order.ORDER_ASC) { + newOrder.desc = false; + } else if (key === Order.ORDER_DESC) { + newOrder.desc = true; + } else { + newOrder.by = key; + } + + mainStore.onUpdateOrderCondition(newOrder.desc, newOrder.by); + }; + render() { - return
SortBar
; + const mainStore = this.props.store!.main; + const { repos, order } = mainStore; + + const orderBys = { + [OrderBy.ORDER_BY_DEFAULT]: "DEFAULT", + [OrderBy.ORDER_BY_STARS_COUNT]: "STARS", + [OrderBy.ORDER_BY_FORKS_COUNT]: "FORKS", + [OrderBy.ORDER_BY_WATCHERS_COUNT]: "WATCHERS", + [OrderBy.ORDER_BY_CREATE_TIME]: "CREATE TIME", + [OrderBy.ORDER_BY_UPDATE_TIME]: "UPDATE TIME", + [OrderBy.ORDER_BY_PUSH_TIME]: "PUSH TIME", + [OrderBy.ORDER_BY_SCORE]: "SCORE", + [OrderBy.ORDER_BY_SIZE]: "SIZE", + [OrderBy.ORDER_BY_OPEN_ISSUES_COUNT]: "OPEN ISSUES" + }; + + const upMenuItems = Object.keys(orderBys).map(key => { + return ( + + + {orderBys[key]} + + + ); + }); + + const menu = ( + + {upMenuItems} + + + + ASC + + + + + DESC + + + + ); + + return ( +
+
+ {`${repos.length} Records`} +
+ + + {`SORT BY ${orderBys[order.by]}`} + + + +
+ ); } } diff --git a/src/renderer/components/SortBar/styles/index.less b/src/renderer/components/SortBar/styles/index.less new file mode 100644 index 0000000..789adb3 --- /dev/null +++ b/src/renderer/components/SortBar/styles/index.less @@ -0,0 +1,26 @@ +.sortBarWrap { + position: relative; + height: 24px; + font-size: 12px; + line-height: 20px; + margin-top: -16px; + text-align: right; + padding-right: 10px; + margin-bottom: 5px; + border-bottom: 1px solid #eaeaea; + > .reposCount { + float: left; + padding-left: 10px; + color: #9b9ea6; + font-size: 12px; + line-height: 20px; + } + > a { + color: #9b9ea6; + } +} + +.sortDropdown { + position: relative; + padding: 5px 0 !important; +} diff --git a/src/renderer/constants/index.ts b/src/renderer/constants/index.ts index d5ed981..672ef35 100644 --- a/src/renderer/constants/index.ts +++ b/src/renderer/constants/index.ts @@ -82,17 +82,8 @@ export const QUERY_REPOS_LIST_FAIL = "QUERY_REPOS_LIST_FAIL"; export const REPLACE_REPOS_LIST_ITEM = "REPLACE_REPOS_LIST_ITEM"; -// filter types -export const FILTER_OPTION_NONE = "FILTER_OPTION_NONE"; -export const FILTER_OPTION_HAS_FLAG = "FILTER_OPTION_HAS_FLAG"; -export const FILTER_OPTION_HAS_NOTE = "FILTER_OPTION_HAS_NOTE"; -export const FILTER_OPTION_UNREAD = "FILTER_OPTION_UNREAD"; - // order types -export const ORDER_DESC = "ORDER_DESC"; -export const ORDER_ASC = "ORDER_ASC"; - // query profile export const QUERY_MY_PROFILE = "QUERY_MY_PROFILE"; export const QUERY_MY_PROFILE_SUCCESS = "QUERY_MY_PROFILE_SUCCESS"; diff --git a/src/renderer/enum/FilterType.ts b/src/renderer/enum/FilterType.ts new file mode 100644 index 0000000..5d221fe --- /dev/null +++ b/src/renderer/enum/FilterType.ts @@ -0,0 +1,9 @@ +// filter types +enum FilterType { + FILTER_OPTION_NONE = "FILTER_OPTION_NONE", + FILTER_OPTION_HAS_FLAG = "FILTER_OPTION_HAS_FLAG", + FILTER_OPTION_HAS_NOTE = "FILTER_OPTION_HAS_NOTE", + FILTER_OPTION_UNREAD = "FILTER_OPTION_UNREAD" +} + +export default FilterType; diff --git a/src/renderer/enum/Order.ts b/src/renderer/enum/Order.ts new file mode 100644 index 0000000..eda1c67 --- /dev/null +++ b/src/renderer/enum/Order.ts @@ -0,0 +1,6 @@ +enum Order { + ORDER_DESC = "ORDER_DESC", + ORDER_ASC = "ORDER_ASC" +} + +export default Order; diff --git a/src/renderer/interface/IConditional.ts b/src/renderer/interface/IConditional.ts index 3b41fc1..55291ff 100644 --- a/src/renderer/interface/IConditional.ts +++ b/src/renderer/interface/IConditional.ts @@ -1,6 +1,10 @@ +import OrderBy from "../enum/OrderBy"; +import SearchType from "../enum/SearchType"; +import GroupType from "../enum/GroupType"; + export interface ISearchConditionState { key: string; - field: string; + field: SearchType; } export interface IFilterConditionState { @@ -10,11 +14,11 @@ export interface IFilterConditionState { } export interface IOrderConditionState { - by: string; + by: OrderBy; desc: boolean; } export interface IGroupConditionState { - type: string; + type: GroupType; id: string; } diff --git a/src/renderer/store/MainStore.ts b/src/renderer/store/MainStore.ts index 4705a9c..ce96a1d 100644 --- a/src/renderer/store/MainStore.ts +++ b/src/renderer/store/MainStore.ts @@ -1,4 +1,4 @@ -import { observable, action } from "mobx"; +import { observable, action, toJS } from "mobx"; import ILanguage from "../interface/ILanguage"; import ICategory from "../interface/ICategory"; import GroupType from "../enum/GroupType"; @@ -118,11 +118,15 @@ export default class MainStore { @action onUpdateSearchCondition = (key: string, field: SearchType) => { - this.search = { - key, - field - }; - return this.updateRepoList(); + const { search, repos } = this; + if (key !== search.key || field !== search.field) { + this.search = { + key, + field + }; + return this.updateRepoList(); + } + return Promise.resolve(toJS(repos)); }; /** @@ -130,11 +134,40 @@ export default class MainStore { */ @observable order: IOrderConditionState = { by: OrderBy.ORDER_BY_DEFAULT, desc: true }; + @action + onUpdateOrderCondition = (desc: boolean, by: OrderBy) => { + logger.log(`Sort: ${by} ${desc ? "DESC" : "ASC"}`); + const { order, repos } = this; + if (order.desc !== desc || order.by !== by) { + this.order = { + desc, + by + }; + return this.updateRepoList(); + } + return Promise.resolve(toJS(repos)); + }; + /** * filter condition */ @observable filter: IFilterConditionState = { hasFlag: false, hasNote: false, unread: false }; + @action + onUpdateFilterCondition = (newFilter: IFilterConditionState) => { + logger.log(`Filter: ${newFilter}`); + const { filter, repos } = this; + if ( + filter.hasFlag !== newFilter.hasFlag || + filter.hasNote !== newFilter.hasNote || + filter.unread !== newFilter.unread + ) { + this.filter = newFilter; + return this.updateRepoList(); + } + return Promise.resolve(toJS(repos)); + }; + /** * Group condition */ @@ -167,6 +200,7 @@ export default class MainStore { return; } this.group = group; + this.updateRepoList(); }; @action @@ -184,10 +218,13 @@ export default class MainStore { /** * Repos */ - @observable repos: { [key: string]: IRepo } = {}; + @observable repos: IRepo[] = []; + + @observable reposMap: { [key: string]: IRepo } = {}; @action updateRepoList = () => { + logger.log("Update repo list"); const { group, search, order, filter } = this; const conditions = { group, @@ -206,7 +243,8 @@ export default class MainStore { keyedRepos[repo.id] = repo; }); - this.repos = keyedRepos; + this.repos = repos; + this.reposMap = keyedRepos; return repos; }) .catch(error => { From c2b597577c8ac9bcf47b3b467d68585187362ec5 Mon Sep 17 00:00:00 2001 From: wuxueqian Date: Sun, 28 Jan 2018 23:51:22 +0800 Subject: [PATCH 21/25] working on details pane --- src/renderer/assets/styles/main.less | 63 --------- .../MainDetailPane/styles/index.less | 13 ++ .../components/RepoDetail/contributors.tsx | 52 +++++++ src/renderer/components/RepoDetail/index.tsx | 47 ++++++- src/renderer/components/RepoDetail/readme.tsx | 115 +++++++++++++++ .../components/RepoDetail/styles/index.less | 0 src/renderer/components/RepoDetail/tags.tsx | 132 ++++++++++++++++++ .../components/RepoDetailToolbar/group.tsx | 115 +++++++++++++++ .../components/RepoDetailToolbar/index.tsx | 114 ++++++++++++++- .../components/RepoDetailToolbar/links.tsx | 96 +++++++++++++ .../components/RepoDetailToolbar/note.tsx | 78 +++++++++++ .../RepoDetailToolbar/styles/index.less | 50 +++++++ src/renderer/store/MainStore.ts | 42 ++++++ 13 files changed, 848 insertions(+), 69 deletions(-) create mode 100644 src/renderer/components/RepoDetail/contributors.tsx create mode 100644 src/renderer/components/RepoDetail/readme.tsx create mode 100644 src/renderer/components/RepoDetail/styles/index.less create mode 100644 src/renderer/components/RepoDetail/tags.tsx create mode 100644 src/renderer/components/RepoDetailToolbar/group.tsx create mode 100644 src/renderer/components/RepoDetailToolbar/links.tsx create mode 100644 src/renderer/components/RepoDetailToolbar/note.tsx create mode 100644 src/renderer/components/RepoDetailToolbar/styles/index.less diff --git a/src/renderer/assets/styles/main.less b/src/renderer/assets/styles/main.less index 63598db..573be2a 100644 --- a/src/renderer/assets/styles/main.less +++ b/src/renderer/assets/styles/main.less @@ -1,66 +1,3 @@ -.detailContent { - height: 100%; - background-repeat: no-repeat; - background-position: 50% 40%; - flex: 1; - overflow: auto; - padding-bottom: 40px; -} - -.detailHeader { - -webkit-app-region: drag; - .detailToolbar { - position: relative; - height: 40px; - background-color: #fbfbfb; - border-bottom: 1px solid #e5e5e5; - > i { - font-size: 20px; - width: 20px; - height: 20px; - line-height: 20px; - display: inline-block; - margin: 10px; - cursor: pointer; - color: #3498db; // #007aff; - &:last-child { - float: right; - } - } - > i[data-flag="true"] { - color: rgb(255, 150, 0); - } - &.disabled { - > i { - display: none; - &:last-child { - display: inline-block; - } - } - } - } -} - -// .repoLinksToolInputWrap { - -// } - -.linksPaneTitle, -.notePaneTitle, -.classifyPaneTitle { - > span { - font-weight: 500; - } - > a { - float: right; - } -} - -.repoNoteToolInputWrap, -.repoClassifyToolInputWrap { - width: 240px; -} - .contributorsBar { margin-top: 10px; line-height: 100%; diff --git a/src/renderer/components/MainDetailPane/styles/index.less b/src/renderer/components/MainDetailPane/styles/index.less index b0f69db..ed764c2 100644 --- a/src/renderer/components/MainDetailPane/styles/index.less +++ b/src/renderer/components/MainDetailPane/styles/index.less @@ -4,3 +4,16 @@ height: 100%; background-color: #fff; // rgba(246, 246, 247, 1); } + +.detailHeader { + -webkit-app-region: drag; +} + +.detailContent { + height: 100%; + background-repeat: no-repeat; + background-position: 50% 40%; + flex: 1; + overflow: auto; + padding-bottom: 40px; +} diff --git a/src/renderer/components/RepoDetail/contributors.tsx b/src/renderer/components/RepoDetail/contributors.tsx new file mode 100644 index 0000000..435fa41 --- /dev/null +++ b/src/renderer/components/RepoDetail/contributors.tsx @@ -0,0 +1,52 @@ +import * as React from "react"; +import ClassNames from "classnames"; +import { Tooltip } from "antd"; + +const styles = require("./styles/index.less"); + +interface RepoContributorsBarProps {} + +interface RepoContributorsBarState {} + +export default class RepoContributorsBar extends React.Component< + RepoContributorsBarProps, + RepoContributorsBarState +> { + constructor(props) { + super(props); + } + + componentWillReceiveProps(nextProps) { + if (nextProps.selectedRepo && !nextProps.selectedRepo._contributors) { + this.props.onFetchRepoContributors(nextProps.selectedRepo); + this.props.onGetRepoContributors(nextProps.selectedRepo.id); + } + } + + componentWillMount() { + if (this.props.selectedRepo) { + this.props.onFetchRepoContributors(this.props.selectedRepo); + this.props.onGetRepoContributors(this.props.selectedRepo.id); + } + } + + render() { + if (!this.props.selectedRepo || !this.props.selectedRepo._contributors) { + return null; + } + + const avatars = this.props.selectedRepo._contributors.map(contributor => { + return ( + + + + + + ); + }); + + return ( +
{avatars}
+ ); + } +} diff --git a/src/renderer/components/RepoDetail/index.tsx b/src/renderer/components/RepoDetail/index.tsx index 53923af..6287b6e 100644 --- a/src/renderer/components/RepoDetail/index.tsx +++ b/src/renderer/components/RepoDetail/index.tsx @@ -1,17 +1,58 @@ import * as React from "react"; +import { observer, inject } from "mobx-react"; +import ClassNames from "classnames"; +import { Icon } from "antd"; +import moment from "moment"; +import IStore from "../../interface/IStore"; +import RepoContributorsBar from "./contributors"; +import RepoTagsBar from "./tags"; +import RepoReadme from "./readme"; -// const styles = require("./index.less"); +const styles = require("./styles/index.less"); -interface RepoDetailProps {} +interface RepoDetailProps { + store?: IStore; +} interface RepoDetailState {} +@inject("store") +@observer export default class RepoDetail extends React.Component { constructor(props) { super(props); } render() { - return
RepoDetail
; + const mainStore = this.props.store!.main; + const { selectedRepo } = mainStore; + if (!selectedRepo) { + return null; + } + + const { fullName, pushedAt, htmlUrl } = selectedRepo; + const namePieces = fullName.split("/"); + const pushTime = moment(pushedAt).format("YYYY-MM-DD HH:mm"); + + return ( +
+
+ +
Latest Push: {pushTime}
+ + +
+ +
+ ); } } diff --git a/src/renderer/components/RepoDetail/readme.tsx b/src/renderer/components/RepoDetail/readme.tsx new file mode 100644 index 0000000..64f81b5 --- /dev/null +++ b/src/renderer/components/RepoDetail/readme.tsx @@ -0,0 +1,115 @@ +import * as React from "react"; +import { observer, inject } from "mobx-react"; +import ClassNames from "classnames"; +import { Spin } from "antd"; +import ReactMarkdown from "react-markdown"; +import IStore from "../../interface/IStore"; + +require("github-markdown-css"); + +const styles = require("./styles/index.less"); + +interface RepoReadmeProps { + store?: IStore; +} + +interface RepoReadmeState {} + +@inject("store") +@observer +export default class RepoReadme extends React.Component { + constructor(props) { + super(props); + } + + transformImageUri = url => { + const mainStore = this.props.store!.main; + const { selectedRepo } = mainStore; + + const regex = /http(s?):\/\//i; + if (!regex.test(url)) { + if (selectedRepo) { + let prefix = + "https://raw.githubusercontent.com/" + + selectedRepo.fullName + + "/" + + selectedRepo.defaultBranch; + if (url.indexOf(".") !== 0) { + prefix += "/"; + } + return prefix + url; + } + } + return url; + }; + + // some readme markdown files includes html img tags + // and also for relative src should be replaced + replaceImageSrc = content => { + const mainStore = this.props.store!.main; + const { selectedRepo } = mainStore; + + if (selectedRepo) { + let prefix = + "https://raw.githubusercontent.com/" + + selectedRepo.fullName + + "/" + + selectedRepo.defaultBranch + + "/"; + return content.replace(/( +
+ +
+
+ ); + } + return ( +
+
+ +
+
+ ); + } +} diff --git a/src/renderer/components/RepoDetail/styles/index.less b/src/renderer/components/RepoDetail/styles/index.less new file mode 100644 index 0000000..e69de29 diff --git a/src/renderer/components/RepoDetail/tags.tsx b/src/renderer/components/RepoDetail/tags.tsx new file mode 100644 index 0000000..40f1c6c --- /dev/null +++ b/src/renderer/components/RepoDetail/tags.tsx @@ -0,0 +1,132 @@ +import * as React from "react"; +import { Tooltip, Tag, Input, Button } from "antd"; + +const styles = require("./styles/index.less"); + +interface RepoTagsBarProps {} + +interface RepoTagsBarState { + tags: string[]; + inputVisible: boolean; + inputValue: string; +} + +export default class RepoTagsBar extends React.Component { + private input: HTMLInputElement; + + constructor(props) { + super(props); + this.state = { + tags: [], + inputVisible: false, + inputValue: "" + }; + } + + handleClose = removedTag => { + const tags = this.state.tags.filter(tag => tag !== removedTag); + this.setState({ tags }); + + const { selectedRepo } = this.props; + if (selectedRepo) { + // remove tag in db + this.props.onRemoveTagForRepo(selectedRepo.id, removedTag); + } + }; + + showInput = () => { + this.setState({ inputVisible: true }, () => this.input.focus()); + }; + + handleInputChange = e => { + this.setState({ inputValue: e.target.value.trim() }); + }; + + handleInputConfirm = () => { + const { inputValue } = this.state; + const { selectedRepo } = this.props; + let tags: string[] = this.state.tags; + if (inputValue && tags.indexOf(inputValue) === -1) { + tags = [...tags, inputValue]; + // save new tag in db + if (selectedRepo) { + this.props.onAddTagForRepo(selectedRepo.id, inputValue); + } + } + this.setState({ + tags, + inputVisible: false, + inputValue: "" + }); + }; + + saveInputRef = input => { + this.input = input; + }; + + queryTags = repoId => { + this.props.onGetTagsForRepo(repoId).then(tags => { + this.setState({ + tags: tags.map(tag => tag.name) + }); + }); + }; + + componentWillReceiveProps(nextProps) { + if (nextProps.selectedRepo && (!this.props.selectedRepo || !nextProps.selectedRepo._tags)) { + this.queryTags(nextProps.selectedRepo.id); + } + if (nextProps.selectedRepo._tags) { + this.setState({ + tags: nextProps.selectedRepo._tags.map(tag => tag.name) + }); + } + } + + componentWillMount() { + const repo = this.props.selectedRepo; + if (repo && !repo._tags) { + this.queryTags(repo.id); + } + } + + render() { + const { tags, inputVisible, inputValue } = this.state; + return ( +
+ {/* */} + {tags.map(tag => { + const isLongTag = tag.length > 20; + const tagElem = ( + this.handleClose(tag)} + > + {isLongTag ? `${tag.slice(0, 20)}...` : tag} + + ); + return isLongTag ? {tagElem} : tagElem; + })} + {inputVisible && ( + + )} + {!inputVisible && ( + + )} +
+ ); + } +} diff --git a/src/renderer/components/RepoDetailToolbar/group.tsx b/src/renderer/components/RepoDetailToolbar/group.tsx new file mode 100644 index 0000000..ed3a624 --- /dev/null +++ b/src/renderer/components/RepoDetailToolbar/group.tsx @@ -0,0 +1,115 @@ +import * as React from "react"; +import ClassNames from "classnames"; +import { Icon, Tooltip, Popover } from "antd"; +import IRepo from "../../interface/IRepo"; + +// const CheckboxGroup = Checkbox.Group; + +const styles = require("./styles/index.less"); + +interface RepoGroupToolProps { + repo: IRepo; +} + +interface RepoGroupToolState { + visible: boolean; + categorySelection: { label: string; value: string }[]; +} + +export default class RepoGroupTool extends React.Component { + constructor(props) { + super(props); + this.state = { + visible: false, + categorySelection: [] + }; + } + + submit = () => { + this.setState({ + visible: false + }); + // this.props.onUpdateRepoCategories( + // this.props.repo.id, + // this.state.categorySelection.map(item => parseInt(item, 10)) + // ); + }; + + handleVisibleChange = visible => { + this.setState({ visible }); + }; + + onSelectionChange = checkValues => { + this.setState({ + categorySelection: checkValues + }); + }; + + queryCategories = _repoId => { + // this.props.onGetCategoriesForRepo(repoId).then(categories => { + // this.setState({ + // categorySelection: categories.map(category => category.id.toString()) + // }); + // }); + }; + + componentWillMount() { + const repo = this.props.repo; + if (repo && !repo._categories) { + this.queryCategories(repo.id); + } + } + + render() { + if (!this.props.repo) { + return null; + } + + const titleNode = ( +
+ Choose Repo Categoires + {/* {this.props.categories && + this.props.categories.length > 0 && SAVE} */} +
+ ); + + // const catsSelectionOptions = this.props.categories.map(category => { + // return { label: category.name, value: category.id.toString() }; + // }); + + // const catsSelectionOptions = []; + + const content = ( +
+ {/* {!this.props.categories || this.props.categories.length === 0 ? ( +
Please add some categories before choosing ones
+ ) : ( + + )} */} +
+ ); + + return ( + + + + + + ); + } +} diff --git a/src/renderer/components/RepoDetailToolbar/index.tsx b/src/renderer/components/RepoDetailToolbar/index.tsx index d707a2b..652320d 100644 --- a/src/renderer/components/RepoDetailToolbar/index.tsx +++ b/src/renderer/components/RepoDetailToolbar/index.tsx @@ -1,11 +1,22 @@ import * as React from "react"; +import { observer, inject } from "mobx-react"; +import ClassNames from "classnames"; +import { Icon, Tooltip, message } from "antd"; +import IStore from "../../interface/IStore"; +import RepoGroupTool from "./group"; +import RepoNoteTool from "./note"; +import RepoLinksTool from "./links"; -// const styles = require("./index.less"); +const styles = require("./styles/index.less"); -interface RepoDetailToolbarProps {} +interface RepoDetailToolbarProps { + store?: IStore; +} interface RepoDetailToolbarState {} +@inject("store") +@observer export default class RepoDetailToolbar extends React.Component< RepoDetailToolbarProps, RepoDetailToolbarState @@ -14,7 +25,104 @@ export default class RepoDetailToolbar extends React.Component< super(props); } + viewInGithub = () => { + const mainStore = this.props.store!.main; + const { selectedRepo } = mainStore; + + if (selectedRepo) { + const url = selectedRepo.htmlUrl; + window.open(url, "_blank"); + } + }; + + starStarCabinet = () => { + const mainStore = this.props.store!.main; + + mainStore + .onStarStarCabinet() + .then(() => { + message.success("Thank you for starring me"); + }) + .catch(() => { + message.info("Failed but thank you, maybe you have starred already"); + window.open("https://github.com/thundernet8/StarCabinet", "_blank"); + }); + }; + + changeReadStatus = () => { + const mainStore = this.props.store!.main; + const { selectedRepo } = mainStore; + + if (selectedRepo) { + mainStore.onUpdateSelectedRepo(selectedRepo.id, { read: !selectedRepo.read }); + } + }; + + changeRepoFlag = () => { + const mainStore = this.props.store!.main; + const { selectedRepo } = mainStore; + + if (selectedRepo) { + mainStore.onUpdateSelectedRepo(selectedRepo.id, { flag: !selectedRepo.flag }); + } + }; + + changeRepoNote = (note: string) => { + const mainStore = this.props.store!.main; + const { selectedRepo } = mainStore; + + if (selectedRepo) { + mainStore.onUpdateSelectedRepo(selectedRepo.id, { note }); + } + }; + render() { - return
RepoDetailToolbar
; + let readIcon; + let flagIcon; + + const mainStore = this.props.store!.main; + const { selectedRepo } = mainStore; + + if (selectedRepo) { + readIcon = ( + + + + ); + flagIcon = ( + + + + ); + } else { + readIcon = null; + flagIcon = null; + } + return ( +
+ + + + {readIcon} + {flagIcon} + + + + + + +
+ ); } } diff --git a/src/renderer/components/RepoDetailToolbar/links.tsx b/src/renderer/components/RepoDetailToolbar/links.tsx new file mode 100644 index 0000000..0eff227 --- /dev/null +++ b/src/renderer/components/RepoDetailToolbar/links.tsx @@ -0,0 +1,96 @@ +import * as React from "react"; +import ClassNames from "classnames"; +import { Icon, Tooltip, Popover, Input } from "antd"; +import CopyToClipboard from "react-copy-to-clipboard"; +import IRepo from "../../interface/IRepo"; + +const styles = require("./styles/index.less"); + +interface RepoLinksToolProps { + repo: IRepo; +} + +interface RepoLinksToolState { + visible: boolean; + copied: boolean; +} + +export default class RepoLinksTool extends React.Component { + constructor(props) { + super(props); + this.state = { + visible: false, + copied: false + }; + } + + handleVisibleChange = visible => { + this.setState({ visible }); + }; + + notifyCopied = () => { + this.setState({ + copied: true + }); + + setTimeout(() => { + this.setState({ + copied: false + }); + }, 1500); + }; + + render() { + if (!this.props.repo) { + return null; + } + const clipboard = value => ( + + + + ); + + const titleNode = ( +
+ Repo Clone Links + {this.state.copied && Copied !} +
+ ); + + const content = ( +
+ + + +
+ ); + return ( + + + + + + ); + } +} diff --git a/src/renderer/components/RepoDetailToolbar/note.tsx b/src/renderer/components/RepoDetailToolbar/note.tsx new file mode 100644 index 0000000..b998327 --- /dev/null +++ b/src/renderer/components/RepoDetailToolbar/note.tsx @@ -0,0 +1,78 @@ +import * as React from "react"; +import ClassNames from "classnames"; +import { Icon, Tooltip, Popover, Input } from "antd"; +import IRepo from "../../interface/IRepo"; + +const styles = require("./styles/index.less"); + +interface RepoNoteToolProps { + repo: IRepo; + updateNote: (note: string) => void; +} + +interface RepoNoteToolState { + visible: boolean; + note: string; +} + +export default class RepoNoteTool extends React.Component { + constructor(props) { + super(props); + this.state = { + visible: false, + note: "" + }; + } + + submit = () => { + this.setState({ + visible: false + }); + const { repo } = this.props; + if (repo) { + this.props.updateNote(this.state.note); + } + }; + + handleVisibleChange = visible => { + this.setState({ visible }); + }; + + inputValueChange = e => { + this.setState({ + note: e.target.value + }); + }; + + render() { + if (!this.props.repo) { + return null; + } + + const titleNode = ( +
+ Add Your Notes + SAVE +
+ ); + const content = ( +
+ +
+ ); + + return ( + + + + + + ); + } +} diff --git a/src/renderer/components/RepoDetailToolbar/styles/index.less b/src/renderer/components/RepoDetailToolbar/styles/index.less new file mode 100644 index 0000000..6dc930e --- /dev/null +++ b/src/renderer/components/RepoDetailToolbar/styles/index.less @@ -0,0 +1,50 @@ +.detailToolbar { + position: relative; + height: 40px; + background-color: #fbfbfb; + border-bottom: 1px solid #e5e5e5; + > i { + font-size: 20px; + width: 20px; + height: 20px; + line-height: 20px; + display: inline-block; + margin: 10px; + cursor: pointer; + color: #3498db; // #007aff; + &:last-child { + float: right; + } + } + > i[data-flag="true"] { + color: rgb(255, 150, 0); + } + &.disabled { + > i { + display: none; + &:last-child { + display: inline-block; + } + } + } +} + +// .repoLinksToolInputWrap { + +// } + +.linksPaneTitle, +.notePaneTitle, +.classifyPaneTitle { + > span { + font-weight: 500; + } + > a { + float: right; + } +} + +.repoNoteToolInputWrap, +.repoClassifyToolInputWrap { + width: 240px; +} diff --git a/src/renderer/store/MainStore.ts b/src/renderer/store/MainStore.ts index ce96a1d..ec74afa 100644 --- a/src/renderer/store/MainStore.ts +++ b/src/renderer/store/MainStore.ts @@ -324,4 +324,46 @@ export default class MainStore { // throw error; }); }; + + /** + * Star StarCabinet + */ + onStarStarCabinet = () => { + const client = new GithubClient(this.globalStore.credentials); + return client + .starStarCabinet() + .then(ret => { + return ret; + }) + .catch(error => { + logger.log(error.message || error.toString()); + throw new Error(error); + }); + }; + + /** + * Update select repo(flag, read status, note...) + */ + onUpdateSelectedRepo = (id: number, properties: { [key: string]: any }) => { + properties.id = id; + return this.getDbHandler() + .then(dbHandler => dbHandler.updateRepo(properties)) + .then(repo => { + // also replace the repo in repos list + repo._hotChange = Object.keys(properties); // mark the repo that its readme etc.. has fetched, do not fetch again + let { repos, reposMap } = this; + reposMap[id] = repo; + repos = repos.map(repo => reposMap[repo.id]); + + this.repos = Array.from(repos); + this.reposMap = Object.assign({}, reposMap); + this.selectedRepo = repo; + + return repo; + }) + .catch(error => { + logger.log(error.message || error.toString()); + throw error; + }); + }; } From f634c01888ecb04de0b46432d201c005490b3a59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=90=B4=E5=AD=A6=E8=B0=A6?= Date: Mon, 29 Jan 2018 13:55:15 +0800 Subject: [PATCH 22/25] migrate all components --- README.md | 51 ++-- package.json | 36 ++- src/renderer/assets/styles/main.less | 85 ------ src/renderer/assets/styles/setting.less | 57 ---- .../components/MainGroupNavs/index.tsx | 4 +- .../components/RepoDetail/contributors.tsx | 31 ++- src/renderer/components/RepoDetail/readme.tsx | 14 +- .../components/RepoDetail/styles/index.less | 85 ++++++ src/renderer/components/RepoDetail/tags.tsx | 63 ++--- .../components/RepoDetailToolbar/group.tsx | 49 ++-- .../components/RepoDetailToolbar/index.tsx | 14 +- src/renderer/interface/IRepo.ts | 1 + src/renderer/store/MainStore.ts | 252 +++++++++++++++++- src/renderer/views/Setting/index.tsx | 194 +++++++++++++- src/renderer/views/Setting/styles/index.less | 57 ++++ 15 files changed, 726 insertions(+), 267 deletions(-) delete mode 100644 src/renderer/assets/styles/main.less delete mode 100644 src/renderer/assets/styles/setting.less diff --git a/README.md b/README.md index fa4d078..8cff4e8 100644 --- a/README.md +++ b/README.md @@ -6,37 +6,41 @@ ## StarCabinet -基于React/Electron/Ant Design打造的开源Github Stars管理的跨平台工具 +基于 React/Electron/Ant Design 打造的开源 Github Stars 管理的跨平台工具 ## Features * 归类 - * 按自带的语言分类📚 - * 自定义添加分类💼 + + * 按自带的语言分类 📚 + * 自定义添加分类 💼 * 标记 - * 添加仓库的标签🏷 - * 添加仓库的旗标🏁 - * 添加仓库的阅读状态👀 - * 添加仓库的备注✍️ - * 添加仓库的评分💯 + + * 添加仓库的标签 🏷 + * 添加仓库的旗标 🏁 + * 添加仓库的阅读状态 👀 + * 添加仓库的备注 ✍️ + * 添加仓库的评分 💯 * 筛选 - * 归类🎏->选择语言或者分类 - * 搜索词🔍->全部字段|仓库名|仓库原始描述|仓库备注|仓库标签 - * 排序〽️->默认(即star添加时间)|stars数量|forks数量|watchers数量|创建时间|更新时间|推送时间|评分|大小|open issues数量,均支持增序和降序 - * 过滤器⏳->未读|有旗标|有备注 三种可多选 + + * 归类 🎏->选择语言或者分类 + * 搜索词 🔍->全部字段|仓库名|仓库原始描述|仓库备注|仓库标签 + * 排序〽️->默认(即 star 添加时间)|stars 数量|forks 数量|watchers 数量|创建时间|更新时间|推送时间|评分|大小|open issues 数量,均支持增序和降序 + * 过滤器 ⏳->未读|有旗标|有备注 三种可多选 * 离线支持 - 💾利用rxdb库和浏览器的indexed db存储仓库的数据 + 💾 利用 rxdb 库和浏览器的 indexed db 存储仓库的数据 - * 支持离线查看仓库并支持上述所有功能操作,包括readme文件的查看 + * 支持离线查看仓库并支持上述所有功能操作,包括 readme 文件的查看 * 高效的数据条件化呈现(不用频繁请求服务器) * 数据 - 支持Stars和自定义数据的导出备份和导入恢复 + 支持 Stars 和自定义数据的导出备份和导入恢复 ## Screenshots + ![Login](screenshots/StarCabinet-login.png) ![Main](screenshots/StarCabinet-main.png) @@ -44,9 +48,11 @@ ![Setting](screenshots/StarCabinet-setting.png) ## Demo + [StarCabinet Demo](http://7xrp00.com1.z0.glb.clouddn.com/starcabinet/StarCabinet.mp4) ## Debug + 直接使用源码的用户,按如下操作: ``` @@ -55,7 +61,20 @@ npm run dev npm start ``` -如果在install packages出错,提示keytar错误等信息,特别是windows用户,你可能需要安装windows-build-tools的package之后在进行上述步骤 +如果在 install packages 出错,提示 keytar 错误等信息,特别是 windows 用户,你可能需要安装 windows-build-tools 的 package 之后在进行上述步骤 + +或者尝试如下操作: + +``` +npm run rebuild +``` + +或者调试 + +``` +npm install -g --verbose electron +``` ## LICENSE + ### MIT diff --git a/package.json b/package.json index 464f11b..60a884b 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,10 @@ "target": "nsis" }, "linux": { - "target": ["AppImage", "deb"] + "target": [ + "AppImage", + "deb" + ] }, "directories": { "app": "app", @@ -27,7 +30,16 @@ "type": "git", "url": "git+https://github.com/thundernet8/StarCabinet.git" }, - "keywords": ["Github", "Star", "Electron", "React", "Mobx", "React-Router", "Webpack", "rxdb"], + "keywords": [ + "Github", + "Star", + "Electron", + "React", + "Mobx", + "React-Router", + "Webpack", + "rxdb" + ], "author": { "name": "WuXueqian", "email": "chinash2010@gmail.com" @@ -39,14 +51,10 @@ "homepage": "https://github.com/thundernet8/StarCabinet#readme", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "dll": - "cross-env NODE_ENV=production webpack -p --hide-modules --config webpack/dll.conf.babel.js", - "dll:dev": - "cross-env NODE_ENV=development webpack --hide-modules --config webpack/dll.conf.babel.js", - "build": - "rimraf app/dist && mkdirp app/dist && cross-env NODE_ENV=production npm run dll && cross-env NODE_ENV=production webpack --progress --hide-modules --config webpack/prod.conf.babel.js", - "build:dev": - "rimraf app/dist && mkdirp app/dist && cross-env NODE_ENV=development npm run dll:dev && cross-env NODE_ENV=development webpack --progress --hide-modules --config webpack/main.conf.babel.js && cross-env NODE_ENV=development webpack --progress --hide-modules --config webpack/dev.conf.babel.js", + "dll": "cross-env NODE_ENV=production webpack -p --hide-modules --config webpack/dll.conf.babel.js", + "dll:dev": "cross-env NODE_ENV=development webpack --hide-modules --config webpack/dll.conf.babel.js", + "build": "rimraf app/dist && mkdirp app/dist && cross-env NODE_ENV=production npm run dll && cross-env NODE_ENV=production webpack --progress --hide-modules --config webpack/prod.conf.babel.js", + "build:dev": "rimraf app/dist && mkdirp app/dist && cross-env NODE_ENV=development npm run dll:dev && cross-env NODE_ENV=development webpack --progress --hide-modules --config webpack/main.conf.babel.js && cross-env NODE_ENV=development webpack --progress --hide-modules --config webpack/dev.conf.babel.js", "dev": "npm run build:dev && webpack-dev-server --config webpack/dev.conf.babel.js", "analyze": "cross-env ANALYZE_ENV=true npm run build", "start": "cross-env NODE_ENV=development electron ./app", @@ -61,8 +69,12 @@ "lint-staged:style": "stylelint --syntax less" }, "lint-staged": { - "src/**/*.{ts,tsx}": ["lint-staged:ts"], - "src/**/*.less": ["lint-staged:style"] + "src/**/*.{ts,tsx}": [ + "lint-staged:ts" + ], + "src/**/*.less": [ + "lint-staged:style" + ] }, "pre-commit": "lint-staged", "devDependencies": { diff --git a/src/renderer/assets/styles/main.less b/src/renderer/assets/styles/main.less deleted file mode 100644 index 573be2a..0000000 --- a/src/renderer/assets/styles/main.less +++ /dev/null @@ -1,85 +0,0 @@ -.contributorsBar { - margin-top: 10px; - line-height: 100%; - > a { - display: inline-block; - img { - display: block; - width: 24px; - height: 24px; - margin: 2px; - border-radius: 3px; - } - } -} - -.repoDetailInner { - display: flex; - flex-direction: column; - position: relative; - height: 100%; - background-color: #fff; - overflow-y: auto; - > header { - padding: 5px 10px; - > .headtitle { - font-size: 20px; - line-height: 36px; - color: #28353d; - > i { - margin-right: 5px; - font-size: 20px; - line-height: 36px; - } - > span { - padding: 0 3px; - } - > a { - color: #28353d; - &:hover { - text-decoration: underline; - } - } - } - > .repoMeta { - font-size: 12px; - color: #666; - } - > .repoTags { - position: relative; - padding: 10px 0 0; - line-height: 30px; - > i { - font-size: 20px; - margin-right: 5px; - vertical-align: -4px; - } - } - } - > .repoReadMeWrap { - flex: 1; - position: relative; - padding: 10px; - > .repoReadmeLoading { - position: absolute; - width: 30px; - height: 30px; - top: 40%; - left: 50%; - margin-top: -15px; - margin-left: -15px; - > i { - font-size: 30px; - } - > div { - transform: scale(1.5); - } - } - > .repoReadme { - position: relative; - font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", - Helvetica, Arial, sans-serif !important; - font-size: 100%; - } - } -} diff --git a/src/renderer/assets/styles/setting.less b/src/renderer/assets/styles/setting.less deleted file mode 100644 index 6f14685..0000000 --- a/src/renderer/assets/styles/setting.less +++ /dev/null @@ -1,57 +0,0 @@ -.settingWrapper { - position: absolute; - width: 100%; - height: 100%; - > header { - line-height: 36px; - text-align: center; - font-size: 16px; - -webkit-app-region: drag; - background-color: #fafafa; - } - > .settingBody { - position: relative; - padding: 10px 20px; - } - .settingRow { - position: relative; - padding: 10px 0 15px; - border-bottom: 1px solid #fafafa; - &:first-child, - &:last-child { - border-bottom: 0; - } - > span:first-of-type { - font-size: 14px; - } - > button { - float: right; - } - } - .accountSetting { - margin-top: 20px; - height: 65px; - line-height: 45px; - .accountAvatar { - width: 45px; - height: 45px; - border-radius: 5px; - float: left; - } - .accountName { - font-weight: 500; - font-size: 16px; - margin-left: 10px; - } - button { - float: right; - margin-top: 8px; - } - } - > footer { - position: absolute; - width: 100%; - bottom: 20px; - text-align: center; - } -} diff --git a/src/renderer/components/MainGroupNavs/index.tsx b/src/renderer/components/MainGroupNavs/index.tsx index 6131e8d..f3e1179 100644 --- a/src/renderer/components/MainGroupNavs/index.tsx +++ b/src/renderer/components/MainGroupNavs/index.tsx @@ -25,8 +25,8 @@ export default class MainGroupNavs extends React.Component { e.stopPropagation(); - // TODO - console.log(id); + const mainStore = this.props.store!.main; + mainStore.delCategory(id); }; render() { diff --git a/src/renderer/components/RepoDetail/contributors.tsx b/src/renderer/components/RepoDetail/contributors.tsx index 435fa41..7b1c29c 100644 --- a/src/renderer/components/RepoDetail/contributors.tsx +++ b/src/renderer/components/RepoDetail/contributors.tsx @@ -1,13 +1,19 @@ import * as React from "react"; +import { observer, inject } from "mobx-react"; import ClassNames from "classnames"; import { Tooltip } from "antd"; +import IStore from "../../interface/IStore"; const styles = require("./styles/index.less"); -interface RepoContributorsBarProps {} +interface RepoContributorsBarProps { + store?: IStore; +} interface RepoContributorsBarState {} +@inject("store") +@observer export default class RepoContributorsBar extends React.Component< RepoContributorsBarProps, RepoContributorsBarState @@ -16,26 +22,25 @@ export default class RepoContributorsBar extends React.Component< super(props); } - componentWillReceiveProps(nextProps) { - if (nextProps.selectedRepo && !nextProps.selectedRepo._contributors) { - this.props.onFetchRepoContributors(nextProps.selectedRepo); - this.props.onGetRepoContributors(nextProps.selectedRepo.id); - } - } - componentWillMount() { - if (this.props.selectedRepo) { - this.props.onFetchRepoContributors(this.props.selectedRepo); - this.props.onGetRepoContributors(this.props.selectedRepo.id); + const mainStore = this.props.store!.main; + const { selectedRepo } = mainStore; + + if (selectedRepo) { + mainStore.onFetchRepoContributors(selectedRepo); + mainStore.onGetSelectRepoContributors(selectedRepo.id); } } render() { - if (!this.props.selectedRepo || !this.props.selectedRepo._contributors) { + const mainStore = this.props.store!.main; + const { selectedRepo } = mainStore; + + if (!selectedRepo || !selectedRepo._contributors) { return null; } - const avatars = this.props.selectedRepo._contributors.map(contributor => { + const avatars = selectedRepo._contributors.map(contributor => { return ( diff --git a/src/renderer/components/RepoDetail/readme.tsx b/src/renderer/components/RepoDetail/readme.tsx index 64f81b5..319756e 100644 --- a/src/renderer/components/RepoDetail/readme.tsx +++ b/src/renderer/components/RepoDetail/readme.tsx @@ -65,22 +65,10 @@ export default class RepoReadme extends React.Component a { + display: inline-block; + img { + display: block; + width: 24px; + height: 24px; + margin: 2px; + border-radius: 3px; + } + } +} + +.repoDetailInner { + display: flex; + flex-direction: column; + position: relative; + height: 100%; + background-color: #fff; + overflow-y: auto; + > header { + padding: 5px 10px; + > .headtitle { + font-size: 20px; + line-height: 36px; + color: #28353d; + > i { + margin-right: 5px; + font-size: 20px; + line-height: 36px; + } + > span { + padding: 0 3px; + } + > a { + color: #28353d; + &:hover { + text-decoration: underline; + } + } + } + > .repoMeta { + font-size: 12px; + color: #666; + } + > .repoTags { + position: relative; + padding: 10px 0 0; + line-height: 30px; + > i { + font-size: 20px; + margin-right: 5px; + vertical-align: -4px; + } + } + } + > .repoReadMeWrap { + flex: 1; + position: relative; + padding: 10px; + > .repoReadmeLoading { + position: absolute; + width: 30px; + height: 30px; + top: 40%; + left: 50%; + margin-top: -15px; + margin-left: -15px; + > i { + font-size: 30px; + } + > div { + transform: scale(1.5); + } + } + > .repoReadme { + position: relative; + font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", + Helvetica, Arial, sans-serif !important; + font-size: 100%; + } + } +} diff --git a/src/renderer/components/RepoDetail/tags.tsx b/src/renderer/components/RepoDetail/tags.tsx index 40f1c6c..442adec 100644 --- a/src/renderer/components/RepoDetail/tags.tsx +++ b/src/renderer/components/RepoDetail/tags.tsx @@ -1,36 +1,38 @@ import * as React from "react"; +import { observer, inject } from "mobx-react"; import { Tooltip, Tag, Input, Button } from "antd"; +import IStore from "../../interface/IStore"; const styles = require("./styles/index.less"); -interface RepoTagsBarProps {} +interface RepoTagsBarProps { + store?: IStore; +} interface RepoTagsBarState { - tags: string[]; inputVisible: boolean; inputValue: string; } +@inject("store") +@observer export default class RepoTagsBar extends React.Component { private input: HTMLInputElement; constructor(props) { super(props); this.state = { - tags: [], inputVisible: false, inputValue: "" }; } handleClose = removedTag => { - const tags = this.state.tags.filter(tag => tag !== removedTag); - this.setState({ tags }); - - const { selectedRepo } = this.props; + const mainStore = this.props.store!.main; + const { selectedRepo } = mainStore; if (selectedRepo) { // remove tag in db - this.props.onRemoveTagForRepo(selectedRepo.id, removedTag); + mainStore.onRemoveTagForRepo(selectedRepo.id, removedTag); } }; @@ -44,17 +46,18 @@ export default class RepoTagsBar extends React.Component { const { inputValue } = this.state; - const { selectedRepo } = this.props; - let tags: string[] = this.state.tags; - if (inputValue && tags.indexOf(inputValue) === -1) { + const mainStore = this.props.store!.main; + const { selectedRepo } = mainStore; + let tags = + selectedRepo && selectedRepo._tags ? selectedRepo._tags.map(tag => tag.name) : []; + if (inputValue && !tags.includes(inputValue)) { tags = [...tags, inputValue]; // save new tag in db if (selectedRepo) { - this.props.onAddTagForRepo(selectedRepo.id, inputValue); + mainStore.onAddTagForRepo(selectedRepo.id, inputValue); } } this.setState({ - tags, inputVisible: false, inputValue: "" }); @@ -65,33 +68,25 @@ export default class RepoTagsBar extends React.Component { - this.props.onGetTagsForRepo(repoId).then(tags => { - this.setState({ - tags: tags.map(tag => tag.name) - }); - }); + const mainStore = this.props.store!.main; + mainStore.onGetTagsForRepo(repoId); }; - componentWillReceiveProps(nextProps) { - if (nextProps.selectedRepo && (!this.props.selectedRepo || !nextProps.selectedRepo._tags)) { - this.queryTags(nextProps.selectedRepo.id); - } - if (nextProps.selectedRepo._tags) { - this.setState({ - tags: nextProps.selectedRepo._tags.map(tag => tag.name) - }); - } - } - componentWillMount() { - const repo = this.props.selectedRepo; - if (repo && !repo._tags) { - this.queryTags(repo.id); + const mainStore = this.props.store!.main; + const { selectedRepo } = mainStore; + if (selectedRepo && !selectedRepo._tags) { + this.queryTags(selectedRepo.id); } } render() { - const { tags, inputVisible, inputValue } = this.state; + const mainStore = this.props.store!.main; + const { selectedRepo } = mainStore; + const tags = + selectedRepo && selectedRepo._tags ? selectedRepo._tags.map(tag => tag.name) : []; + + const { inputVisible, inputValue } = this.state; return (
{/* */} @@ -102,7 +97,7 @@ export default class RepoTagsBar extends React.Component this.handleClose(tag)} + afterClose={this.handleClose.bind(this, tag)} > {isLongTag ? `${tag.slice(0, 20)}...` : tag} diff --git a/src/renderer/components/RepoDetailToolbar/group.tsx b/src/renderer/components/RepoDetailToolbar/group.tsx index ed3a624..eadf0e1 100644 --- a/src/renderer/components/RepoDetailToolbar/group.tsx +++ b/src/renderer/components/RepoDetailToolbar/group.tsx @@ -1,19 +1,23 @@ import * as React from "react"; import ClassNames from "classnames"; -import { Icon, Tooltip, Popover } from "antd"; +import { Icon, Tooltip, Popover, Checkbox } from "antd"; import IRepo from "../../interface/IRepo"; +import ICategory from "../../interface/ICategory"; -// const CheckboxGroup = Checkbox.Group; +const CheckboxGroup = Checkbox.Group; const styles = require("./styles/index.less"); interface RepoGroupToolProps { repo: IRepo; + categories: ICategory[]; + getCategories: (id: number) => void; + updateRepoCategories: (id: number, categoryIds: number[]) => void; } interface RepoGroupToolState { visible: boolean; - categorySelection: { label: string; value: string }[]; + categorySelection: string[]; } export default class RepoGroupTool extends React.Component { @@ -29,10 +33,10 @@ export default class RepoGroupTool extends React.Component parseInt(item, 10)) - // ); + this.props.updateRepoCategories( + this.props.repo.id, + this.state.categorySelection.map(item => parseInt(item, 10)) + ); }; handleVisibleChange = visible => { @@ -45,12 +49,8 @@ export default class RepoGroupTool extends React.Component { - // this.props.onGetCategoriesForRepo(repoId).then(categories => { - // this.setState({ - // categorySelection: categories.map(category => category.id.toString()) - // }); - // }); + queryCategories = (id: number) => { + this.props.getCategories(id); }; componentWillMount() { @@ -61,23 +61,24 @@ export default class RepoGroupTool extends React.Component category.id.toString()); + const titleNode = ( ); - // const catsSelectionOptions = this.props.categories.map(category => { - // return { label: category.name, value: category.id.toString() }; - // }); - - // const catsSelectionOptions = []; + const catsSelectionOptions = categories.map(category => { + return { label: category.name, value: category.id.toString() }; + }); const content = (
- {/* {!this.props.categories || this.props.categories.length === 0 ? ( + {categories.length === 0 ? (
Please add some categories before choosing ones
) : ( - )} */} + )}
); diff --git a/src/renderer/components/RepoDetailToolbar/index.tsx b/src/renderer/components/RepoDetailToolbar/index.tsx index 652320d..5b9b133 100644 --- a/src/renderer/components/RepoDetailToolbar/index.tsx +++ b/src/renderer/components/RepoDetailToolbar/index.tsx @@ -76,12 +76,17 @@ export default class RepoDetailToolbar extends React.Component< } }; + getRepoCategories = (id: number) => { + const mainStore = this.props.store!.main; + mainStore.onGetSelectRepoCategories(id); + }; + render() { let readIcon; let flagIcon; const mainStore = this.props.store!.main; - const { selectedRepo } = mainStore; + const { selectedRepo, categories } = mainStore; if (selectedRepo) { readIcon = ( @@ -116,7 +121,12 @@ export default class RepoDetailToolbar extends React.Component< {readIcon} {flagIcon} - + diff --git a/src/renderer/interface/IRepo.ts b/src/renderer/interface/IRepo.ts index dc776d0..8d16baa 100644 --- a/src/renderer/interface/IRepo.ts +++ b/src/renderer/interface/IRepo.ts @@ -84,6 +84,7 @@ export default interface IRepo { _categories: ICategory[]; _contributors: IAuthor[]; _tags: ITag[]; + _hotChange: string[]; } export interface IRepoFetchingStatus { diff --git a/src/renderer/store/MainStore.ts b/src/renderer/store/MainStore.ts index ec74afa..d531869 100644 --- a/src/renderer/store/MainStore.ts +++ b/src/renderer/store/MainStore.ts @@ -1,4 +1,5 @@ -import { observable, action, toJS } from "mobx"; +import { observable, action, toJS, autorun } from "mobx"; +import moment from "moment"; import ILanguage from "../interface/ILanguage"; import ICategory from "../interface/ICategory"; import GroupType from "../enum/GroupType"; @@ -21,6 +22,16 @@ export default class MainStore { constructor(globalStore: GlobalStore) { this.globalStore = globalStore; + + autorun(() => { + logger.log("Mobx autorun"); + const { selectedRepo } = this; + if (selectedRepo && !selectedRepo._contributors) { + logger.log("Mobx autorun: Fetch and get repo contributors"); + this.onFetchRepoContributors(selectedRepo); + this.onGetSelectRepoContributors(selectedRepo.id); + } + }); } private getDbHandler = () => { @@ -341,22 +352,38 @@ export default class MainStore { }); }; + /** + * Replace one repo in list + */ + @action + replaceOneRepoInList = (repo: IRepo) => { + let { repos, reposMap } = this; + reposMap[repo.id] = repo; + repos = repos.map(item => reposMap[item.id]); + + this.repos = Array.from(repos); + this.reposMap = Object.assign({}, reposMap); + }; + /** * Update select repo(flag, read status, note...) */ + @action onUpdateSelectedRepo = (id: number, properties: { [key: string]: any }) => { + const { selectedRepo } = this; + if (!selectedRepo || id !== selectedRepo.id) { + return Promise.reject(false); + } + properties.id = id; + return this.getDbHandler() .then(dbHandler => dbHandler.updateRepo(properties)) .then(repo => { // also replace the repo in repos list repo._hotChange = Object.keys(properties); // mark the repo that its readme etc.. has fetched, do not fetch again - let { repos, reposMap } = this; - reposMap[id] = repo; - repos = repos.map(repo => reposMap[repo.id]); + this.replaceOneRepoInList(repo); - this.repos = Array.from(repos); - this.reposMap = Object.assign({}, reposMap); this.selectedRepo = repo; return repo; @@ -366,4 +393,217 @@ export default class MainStore { throw error; }); }; + + /** + * Update repo categories + */ + @action + onUpdateRepoCategories = (id: number, catIds: number[]) => { + return this.getDbHandler() + .then(dbHandler => dbHandler.updateRepoCategories(id, catIds)) + .then(repo => { + // also replace the repo in repos list + this.replaceOneRepoInList(repo); + + // if it has same id with selectedRepo, also replace selectedRepo + this.onUpdateSelectedRepo(id, { + rxChange: Math.floor(moment.now().valueOf() / 1000) + }); + + // update all categories list, for updating the nav category node + this.updateCategoryList(); + + return repo; + }) + .catch(error => { + logger.log(error.message || error.toString()); + throw error; + }); + }; + + /** + * Update repo contributors + */ + @action + onUpdateRepoContributors = (id: number, contributors) => { + return this.getDbHandler() + .then(dbHandler => dbHandler.upsertContributors(id, contributors)) + .then(_contributors => { + // also replace the repo in repos list + let repo = this.reposMap[id]; + if (repo) { + repo._contributors = _contributors; + repo._hotChange = ["contributors"]; + this.replaceOneRepoInList(repo); + } + + // if it has same id with selectedRepo, also replace selectedRepo + this.onUpdateSelectedRepo(id, { + rxChange: Math.floor(moment.now().valueOf() / 1000) + }); + + return repo; + }) + .catch(error => { + logger.log(error.message || error.toString()); + throw error; + }); + }; + + @action + onAddTagForRepo = (id: number, tagName: string) => { + return this.getDbHandler() + .then(dbHandler => dbHandler.addRepoTag(id, tagName)) + .then(repo => { + // also replace the repo in repos list + this.replaceOneRepoInList(repo); + + // if it has same id with selectedRepo, also replace selectedRepo + this.onUpdateSelectedRepo(id, { + rxChange: Math.floor(moment.now().valueOf() / 1000) + }); + + return repo; + }) + .catch(error => { + logger.log(error.message || error.toString()); + throw error; + }); + }; + + @action + onRemoveTagForRepo = (id: number, tagName: string) => { + return this.getDbHandler() + .then(dbHandler => dbHandler.removeRepoTag(id, tagName)) + .then(repo => { + // also replace the repo in repos list + this.replaceOneRepoInList(repo); + + // if it has same id with selectedRepo, also replace selectedRepo + this.onUpdateSelectedRepo(id, { + rxChange: Math.floor(moment.now().valueOf() / 1000) + }); + + return repo; + }) + .catch(error => { + logger.log(error.message || error.toString()); + throw error; + }); + }; + + @action + onGetTagsForRepo = (id: number) => { + return this.getDbHandler() + .then(dbHandler => dbHandler.getRepoTags(id)) + .then(tags => { + // also add tags to the repo and replace the repo in repos list + let repo = this.reposMap[id]; + if (repo) { + repo._tags = tags; + this.replaceOneRepoInList(repo); + } + + return tags; + }) + .catch(error => { + logger.log(error.message || error.toString()); + throw error; + }); + }; + + @action + onFetchRepoReadMe = (repo: IRepo) => { + const client = new GithubClient(this.globalStore.credentials); + return client + .getRepoReadMe(repo.fullName, repo.defaultBranch) + .then(readme => { + if (repo.readme !== readme) { + this.onUpdateSelectedRepo(repo.id, { readme }); + } + + return readme; + }) + .catch(error => { + logger.log(error.message || error.toString()); + throw error; + }); + }; + + @action + onFetchRepoContributors = (repo: IRepo) => { + const client = new GithubClient(this.globalStore.credentials); + return client + .getRepoContributors(repo.fullName) + .then(contributors => { + // save contributors to db + this.onUpdateRepoContributors(repo.id, contributors); + + return contributors; + }) + .catch(error => { + logger.log(error.message || error.toString()); + throw error; + }); + }; + + /** + * Get contributors for selected repo + */ + @action + onGetSelectRepoContributors = (id: number) => { + const { selectedRepo } = this; + if (!selectedRepo || selectedRepo.id !== id) { + return Promise.reject(false); + } + return this.getDbHandler() + .then(dbHandler => dbHandler.getRepoContributors(id)) + .then(contributors => { + // also add contributors to the repo and replace the repo in repos list + let repo = this.reposMap[id]; + if (repo) { + repo._contributors = contributors; + repo._hotChange = ["contributors"]; + this.replaceOneRepoInList(repo); + } + + // if it has same id with selectedRepo, also replace selectedRepo + this.onUpdateSelectedRepo(id, { + rxChange: Math.floor(moment.now().valueOf() / 1000) + }); + + return contributors; + }) + .catch(error => { + logger.log(error.message || error.toString()); + throw error; + }); + }; + + /** + * Get categories for selected repo + */ + @action + onGetSelectRepoCategories = (id: number) => { + const { selectedRepo } = this; + if (!selectedRepo || selectedRepo.id !== id) { + return Promise.reject(false); + } + return this.getDbHandler() + .then(dbHandler => dbHandler.getRepoCategories(id)) + .then(categories => { + // also add categories to the repo and replace the repo in repos list + let repo = this.reposMap[id]; + if (repo) { + repo._categories = categories; + this.replaceOneRepoInList(repo); + } + + return categories; + }) + .catch(error => { + logger.log(error.message || error.toString()); + throw error; + }); + }; } diff --git a/src/renderer/views/Setting/index.tsx b/src/renderer/views/Setting/index.tsx index a0ffc79..ac42517 100644 --- a/src/renderer/views/Setting/index.tsx +++ b/src/renderer/views/Setting/index.tsx @@ -1,17 +1,205 @@ import * as React from "react"; +import { observer, inject } from "mobx-react"; +import { Icon, Button, message, Modal } from "antd"; +import ClassNames from "classnames"; +import { starsDataExportHandler, starsDataImportHandler } from "../../utils/data"; +import Authentication from "../../utils/authentication"; +import { quitElectronApp, restartElectronApp } from "../../utils/electronApp"; +import IStore from "../../interface/IStore"; + +const defaultAvatar = require("../../assets/images/avatar-default.png"); const styles = require("./styles/index.less"); -interface SettingViewProps {} +interface SettingViewProps { + store?: IStore; +} -interface SettingViewState {} +interface SettingViewState { + importing: boolean; + exporting: boolean; + restarModalVisible: boolean; + quitModalVisible: boolean; +} +@inject("store") +@observer export default class SettingView extends React.Component { constructor(props) { super(props); + this.state = { + importing: false, + exporting: false, + restarModalVisible: false, + quitModalVisible: false + }; + } + + cancelModal = () => { + this.setState({ + restarModalVisible: false, + quitModalVisible: false + }); + }; + + getAvatarUrl = () => { + const globalStore = this.props.store!.global; + const { profile } = globalStore; + + if (!profile || !profile.avatarUrl) { + return defaultAvatar; + } + return profile.avatarUrl; + }; + + showQuitWarning = () => { + this.setState({ + quitModalVisible: true + }); + }; + + signout = () => { + Authentication.signOutApp(); + setTimeout(() => { + quitElectronApp(); + }, 1000); + }; + + restart = () => { + restartElectronApp(); + }; + + importData = () => { + if (this.state.importing) { + return false; + } + + const globalStore = this.props.store!.global; + + globalStore + .getDb() + .then(db => starsDataImportHandler(db)) + .then(() => { + message.success("Data import successfully"); + this.setState({ + importing: false + }); + setTimeout(() => { + this.setState({ + restarModalVisible: true + }); + }, 2000); + }) + .catch(err => { + message.error(err.message); + console.log(err); + this.setState({ + importing: false + }); + }); + }; + + exportData = () => { + if (this.state.exporting) { + return false; + } + + const globalStore = this.props.store!.global; + + globalStore + .getDb() + .then(db => starsDataExportHandler(db)) + .then(() => { + message.success("Data export successfully"); + this.setState({ + exporting: false + }); + }) + .catch(err => { + message.error(err.message); + this.setState({ + exporting: false + }); + }); + }; + + openFeedback = () => { + window.open("https://github.com/thundernet8/StarCabinet/issues", "_blank"); + }; + + componentDidMount() { + const globalStore = this.props.store!.global; + globalStore.restore(); } render() { - return
SettingView
; + const globalStore = this.props.store!.global; + const { profile } = globalStore; + + return ( +
+
+
SETTING
+
+
+
+ + {profile && {profile.name}} + +
+
+ Backup: + +
+
+ Restore: + +
+
+ Feedback: + +
+
+
© 2017-{`${new Date().getFullYear()} StarCabinet`}
+ + App will exit after signing out + + + App need restart to apply the new data + +
+ ); } } diff --git a/src/renderer/views/Setting/styles/index.less b/src/renderer/views/Setting/styles/index.less index e69de29..6f14685 100644 --- a/src/renderer/views/Setting/styles/index.less +++ b/src/renderer/views/Setting/styles/index.less @@ -0,0 +1,57 @@ +.settingWrapper { + position: absolute; + width: 100%; + height: 100%; + > header { + line-height: 36px; + text-align: center; + font-size: 16px; + -webkit-app-region: drag; + background-color: #fafafa; + } + > .settingBody { + position: relative; + padding: 10px 20px; + } + .settingRow { + position: relative; + padding: 10px 0 15px; + border-bottom: 1px solid #fafafa; + &:first-child, + &:last-child { + border-bottom: 0; + } + > span:first-of-type { + font-size: 14px; + } + > button { + float: right; + } + } + .accountSetting { + margin-top: 20px; + height: 65px; + line-height: 45px; + .accountAvatar { + width: 45px; + height: 45px; + border-radius: 5px; + float: left; + } + .accountName { + font-weight: 500; + font-size: 16px; + margin-left: 10px; + } + button { + float: right; + margin-top: 8px; + } + } + > footer { + position: absolute; + width: 100%; + bottom: 20px; + text-align: center; + } +} From b508a7573498ff9ab2c5f68dde81c8348323a9b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=90=B4=E5=AD=A6=E8=B0=A6?= Date: Mon, 29 Jan 2018 17:40:37 +0800 Subject: [PATCH 23/25] fix queries --- .stylelintrc | 3 +- src/main/services/data.js | 20 +++-- .../assets/styles/global/antd-theme.less | 31 ++++---- src/renderer/assets/styles/global/system.less | 42 +++++----- .../MainDetailPane/styles/index.less | 1 + .../components/MainGroupFooter/index.tsx | 4 + .../MainGroupPane/styles/index.less | 1 + .../components/MainListPane/styles/index.less | 1 + .../components/RefreshIndicator/index.tsx | 2 +- .../components/RepoDetail/contributors.tsx | 7 +- src/renderer/components/RepoDetail/index.tsx | 2 +- src/renderer/components/RepoDetail/readme.tsx | 60 ++++++++------- src/renderer/components/RepoDetail/tags.tsx | 32 ++++---- .../components/RepoDetailToolbar/group.tsx | 26 ++++--- .../components/RepoDetailToolbar/index.tsx | 9 +-- .../components/RepoDetailToolbar/note.tsx | 10 +++ src/renderer/components/ReposList/item.tsx | 8 +- .../components/ReposList/styles/item.less | 1 + .../components/SearchBox/styles/index.less | 37 +++++---- src/renderer/interface/IContributor.ts | 6 ++ src/renderer/store/GlobalStore.ts | 2 +- src/renderer/store/MainStore.ts | 76 ++++++++++++++----- src/renderer/views/Login/index.tsx | 2 +- 23 files changed, 232 insertions(+), 151 deletions(-) create mode 100644 src/renderer/interface/IContributor.ts diff --git a/.stylelintrc b/.stylelintrc index 24d296e..8a79861 100644 --- a/.stylelintrc +++ b/.stylelintrc @@ -24,6 +24,7 @@ "value-list-max-empty-lines": null, "no-empty-source": null, "selector-combinator-space-before": null, - "selector-pseudo-class-no-unknown": null + "selector-pseudo-class-no-unknown": null, + "no-descending-specificity": null } } \ No newline at end of file diff --git a/src/main/services/data.js b/src/main/services/data.js index d8b4cd6..e34078a 100644 --- a/src/main/services/data.js +++ b/src/main/services/data.js @@ -11,10 +11,7 @@ export const exportDataHandle = () => { properties: ["openDirectory"] }; dialog.showOpenDialog(currentWin, dialogOptions, paths => { - event.sender.send( - EVENTS.SHOW_CHOOSE_DIRECTORY_DIALOG_REPLG, - paths[0] - ); + event.sender.send(EVENTS.SHOW_CHOOSE_DIRECTORY_DIALOG_REPLG, paths[0]); }); }); @@ -42,13 +39,14 @@ export const importDataHandle = () => { ] }; dialog.showOpenDialog(currentWin, dialogOptions, paths => { - fs.readFile(paths[0], "utf8", (err, data) => { - if (err) { - event.sender.send(EVENTS.READ_FILE_FAILED); - } else { - event.sender.send(EVENTS.SENT_IMPORT_STARS_DATA, data); - } - }); + paths && + fs.readFile(paths[0], "utf8", (err, data) => { + if (err) { + event.sender.send(EVENTS.READ_FILE_FAILED); + } else { + event.sender.send(EVENTS.SENT_IMPORT_STARS_DATA, data); + } + }); }); }); diff --git a/src/renderer/assets/styles/global/antd-theme.less b/src/renderer/assets/styles/global/antd-theme.less index e45cfb6..f09fcf0 100644 --- a/src/renderer/assets/styles/global/antd-theme.less +++ b/src/renderer/assets/styles/global/antd-theme.less @@ -21,9 +21,7 @@ input { } } } - &.ant-menu-item-selected { - background-color: rgb(71, 79, 95); - } + > .ant-menu-sub { background-color: transparent; max-height: 210px; @@ -36,6 +34,10 @@ input { } } } + + &.ant-menu-item-selected { + background-color: rgb(71, 79, 95); + } } &.ant-menu-inline { .ant-menu-item-selected { @@ -62,6 +64,15 @@ input { a { color: #343536; } + &:last-child { + .ant-checkbox-checked { + .ant-checkbox-inner { + &:after { + visibility: hidden; + } + } + } + } } > .ant-dropdown-menu-item-divider { margin: 4px 0; @@ -90,20 +101,6 @@ input { } } -.filterDropdown { - > .ant-dropdown-menu-item { - &:last-child { - .ant-checkbox-checked { - .ant-checkbox-inner { - &:after { - visibility: hidden; - } - } - } - } - } -} - .ant-rate-star-half .ant-rate-star-first, .ant-rate-star-full .ant-rate-star-second { color: #f96358 !important; diff --git a/src/renderer/assets/styles/global/system.less b/src/renderer/assets/styles/global/system.less index 25a4364..bb96aa4 100644 --- a/src/renderer/assets/styles/global/system.less +++ b/src/renderer/assets/styles/global/system.less @@ -17,8 +17,8 @@ ::-webkit-scrollbar-track-piece { background-color: transparent; } - ::-webkit-scrollbar-thumb:window-inactive, - ::-webkit-scrollbar-thumb { + ::-webkit-scrollbar-thumb, + ::-webkit-scrollbar-thumb:window-inactive { background-color: rgba(0, 0, 0, 0.8); border-radius: 5px; } @@ -52,27 +52,27 @@ } } - // ::-webkit-scrollbar { - // width:6px; - // } + ::-webkit-scrollbar { + width: 6px; + } - // ::-webkit-scrollbar-track { - // -webkit-border-radius:5px; - // border-radius:5px; - // background:transparent; // rgba(0,0,0,0.1); - // } + ::-webkit-scrollbar-track { + -webkit-border-radius: 5px; + border-radius: 5px; + background: transparent; // rgba(0,0,0,0.1); + } - // ::-webkit-scrollbar-thumb { - // -webkit-border-radius:5px; - // border-radius:5px; - // background:rgba(0,0,0,0.2); - // } + ::-webkit-scrollbar-thumb { + -webkit-border-radius: 5px; + border-radius: 5px; + background: rgba(0, 0, 0, 0.2); + } - // ::-webkit-scrollbar-thumb:hover { - // background:rgba(0,0,0,0.4); - // } + ::-webkit-scrollbar-thumb:window-inactive { + background: rgba(0, 0, 0, 0.05); + } - // ::-webkit-scrollbar-thumb:window-inactive { - // background:rgba(0,0,0,0.05); - // } + ::-webkit-scrollbar-thumb:hover { + background: rgba(0, 0, 0, 0.4); + } } diff --git a/src/renderer/components/MainDetailPane/styles/index.less b/src/renderer/components/MainDetailPane/styles/index.less index ed764c2..04b0aca 100644 --- a/src/renderer/components/MainDetailPane/styles/index.less +++ b/src/renderer/components/MainDetailPane/styles/index.less @@ -3,6 +3,7 @@ flex: 1; height: 100%; background-color: #fff; // rgba(246, 246, 247, 1); + width: ~"calc(100% - 500px)"; } .detailHeader { diff --git a/src/renderer/components/MainGroupFooter/index.tsx b/src/renderer/components/MainGroupFooter/index.tsx index 6ebd80e..99545cb 100644 --- a/src/renderer/components/MainGroupFooter/index.tsx +++ b/src/renderer/components/MainGroupFooter/index.tsx @@ -77,6 +77,7 @@ export default class MainGroupFooter extends React.Component< .then(() => { this.setState({ submitting: false, + modalVisible: false, categoryName: "" }); }) @@ -100,6 +101,8 @@ export default class MainGroupFooter extends React.Component< }; render() { + const { categoryName } = this.state; + return (
diff --git a/src/renderer/components/MainGroupPane/styles/index.less b/src/renderer/components/MainGroupPane/styles/index.less index e8f5b3e..0c6f361 100644 --- a/src/renderer/components/MainGroupPane/styles/index.less +++ b/src/renderer/components/MainGroupPane/styles/index.less @@ -1,6 +1,7 @@ .left { position: relative; width: 200px; + min-width: 200px; height: 100%; background-color: rgba(39, 49, 67, 1); // border-right: 1px solid rgba(186,208,223,0.72); diff --git a/src/renderer/components/MainListPane/styles/index.less b/src/renderer/components/MainListPane/styles/index.less index 940f23f..b1c7a1d 100644 --- a/src/renderer/components/MainListPane/styles/index.less +++ b/src/renderer/components/MainListPane/styles/index.less @@ -1,6 +1,7 @@ .mid { position: relative; width: 300px; + min-width: 300px; height: 100%; background-color: #fbfbfb; border-right: 1px solid rgba(229, 229, 229, 1); diff --git a/src/renderer/components/RefreshIndicator/index.tsx b/src/renderer/components/RefreshIndicator/index.tsx index 8e330ce..f959c7d 100644 --- a/src/renderer/components/RefreshIndicator/index.tsx +++ b/src/renderer/components/RefreshIndicator/index.tsx @@ -49,7 +49,7 @@ export default class RefreshIndicator extends React.Component< increase < 0 ? `Decreased ${Math.abs(increase)} starred repositories.` : `${increase} new starred repositories.`, - duration: 10 + duration: 5 }); }; diff --git a/src/renderer/components/RepoDetail/contributors.tsx b/src/renderer/components/RepoDetail/contributors.tsx index 7b1c29c..be5f40c 100644 --- a/src/renderer/components/RepoDetail/contributors.tsx +++ b/src/renderer/components/RepoDetail/contributors.tsx @@ -34,13 +34,14 @@ export default class RepoContributorsBar extends React.Component< render() { const mainStore = this.props.store!.main; - const { selectedRepo } = mainStore; + const { selectedRepo, selectRepoContributors } = mainStore; + console.log("Contributors component repo: ", selectedRepo); - if (!selectedRepo || !selectedRepo._contributors) { + if (!selectedRepo || !selectRepoContributors || selectRepoContributors.length === 0) { return null; } - const avatars = selectedRepo._contributors.map(contributor => { + const avatars = selectRepoContributors.map(contributor => { return ( diff --git a/src/renderer/components/RepoDetail/index.tsx b/src/renderer/components/RepoDetail/index.tsx index 6287b6e..fdc9231 100644 --- a/src/renderer/components/RepoDetail/index.tsx +++ b/src/renderer/components/RepoDetail/index.tsx @@ -51,7 +51,7 @@ export default class RepoDetail extends React.Component - +
); } diff --git a/src/renderer/components/RepoDetail/readme.tsx b/src/renderer/components/RepoDetail/readme.tsx index 319756e..710c556 100644 --- a/src/renderer/components/RepoDetail/readme.tsx +++ b/src/renderer/components/RepoDetail/readme.tsx @@ -1,39 +1,33 @@ import * as React from "react"; -import { observer, inject } from "mobx-react"; import ClassNames from "classnames"; import { Spin } from "antd"; import ReactMarkdown from "react-markdown"; -import IStore from "../../interface/IStore"; +import IRepo from "../../interface/IRepo"; require("github-markdown-css"); const styles = require("./styles/index.less"); interface RepoReadmeProps { - store?: IStore; + repo: IRepo; + onFetchRepoReadMe: (repo: IRepo) => void; } interface RepoReadmeState {} -@inject("store") -@observer export default class RepoReadme extends React.Component { constructor(props) { super(props); } transformImageUri = url => { - const mainStore = this.props.store!.main; - const { selectedRepo } = mainStore; + const { repo } = this.props; const regex = /http(s?):\/\//i; if (!regex.test(url)) { - if (selectedRepo) { + if (repo) { let prefix = - "https://raw.githubusercontent.com/" + - selectedRepo.fullName + - "/" + - selectedRepo.defaultBranch; + "https://raw.githubusercontent.com/" + repo.fullName + "/" + repo.defaultBranch; if (url.indexOf(".") !== 0) { prefix += "/"; } @@ -46,36 +40,50 @@ export default class RepoReadme extends React.Component { - const mainStore = this.props.store!.main; - const { selectedRepo } = mainStore; + const { repo } = this.props; - if (selectedRepo) { + if (repo) { let prefix = "https://raw.githubusercontent.com/" + - selectedRepo.fullName + + repo.fullName + "/" + - selectedRepo.defaultBranch + + repo.defaultBranch + "/"; return content.replace(/(
@@ -93,7 +101,7 @@ export default class RepoReadme extends React.Component
diff --git a/src/renderer/components/RepoDetail/tags.tsx b/src/renderer/components/RepoDetail/tags.tsx index 442adec..bf06de6 100644 --- a/src/renderer/components/RepoDetail/tags.tsx +++ b/src/renderer/components/RepoDetail/tags.tsx @@ -47,9 +47,8 @@ export default class RepoTagsBar extends React.Component { const { inputValue } = this.state; const mainStore = this.props.store!.main; - const { selectedRepo } = mainStore; - let tags = - selectedRepo && selectedRepo._tags ? selectedRepo._tags.map(tag => tag.name) : []; + const { selectedRepo, selectRepoTags } = mainStore; + let tags = selectedRepo && selectRepoTags ? selectRepoTags.map(tag => tag.name) : []; if (inputValue && !tags.includes(inputValue)) { tags = [...tags, inputValue]; // save new tag in db @@ -67,24 +66,23 @@ export default class RepoTagsBar extends React.Component { - const mainStore = this.props.store!.main; - mainStore.onGetTagsForRepo(repoId); - }; + // queryTags = repoId => { + // const mainStore = this.props.store!.main; + // mainStore.onGetTagsForRepo(repoId); + // }; - componentWillMount() { - const mainStore = this.props.store!.main; - const { selectedRepo } = mainStore; - if (selectedRepo && !selectedRepo._tags) { - this.queryTags(selectedRepo.id); - } - } + // componentWillMount() { + // const mainStore = this.props.store!.main; + // const { selectedRepo, selectRepoTags } = mainStore; + // if (selectedRepo && (!selectRepoTags || selectRepoTags.length === 0)) { + // this.queryTags(selectedRepo.id); + // } + // } render() { const mainStore = this.props.store!.main; - const { selectedRepo } = mainStore; - const tags = - selectedRepo && selectedRepo._tags ? selectedRepo._tags.map(tag => tag.name) : []; + const { selectedRepo, selectRepoTags } = mainStore; + const tags = selectedRepo && selectRepoTags ? selectRepoTags.map(tag => tag.name) : []; const { inputVisible, inputValue } = this.state; return ( diff --git a/src/renderer/components/RepoDetailToolbar/group.tsx b/src/renderer/components/RepoDetailToolbar/group.tsx index eadf0e1..cd1d20c 100644 --- a/src/renderer/components/RepoDetailToolbar/group.tsx +++ b/src/renderer/components/RepoDetailToolbar/group.tsx @@ -11,7 +11,7 @@ const styles = require("./styles/index.less"); interface RepoGroupToolProps { repo: IRepo; categories: ICategory[]; - getCategories: (id: number) => void; + repoCategories: ICategory[]; updateRepoCategories: (id: number, categoryIds: number[]) => void; } @@ -49,25 +49,31 @@ export default class RepoGroupTool extends React.Component { - this.props.getCategories(id); - }; - componentWillMount() { - const repo = this.props.repo; - if (repo && !repo._categories) { - this.queryCategories(repo.id); + const { repo, repoCategories } = this.props; + if (repo) { + this.setState({ + categorySelection: repoCategories.map(item => item.id.toString()) + }); } } + componentWillReceiveProps(nextProps) { + const { repoCategories } = nextProps; + + const categorySelection = repoCategories.map(category => category.id.toString()); + this.setState({ + categorySelection + }); + } + render() { const { repo, categories } = this.props; if (!repo) { return null; } - const repoCategories = repo._categories || []; - const categorySelection = repoCategories.map(category => category.id.toString()); + const { categorySelection } = this.state; const titleNode = (
diff --git a/src/renderer/components/RepoDetailToolbar/index.tsx b/src/renderer/components/RepoDetailToolbar/index.tsx index 5b9b133..a77e9d8 100644 --- a/src/renderer/components/RepoDetailToolbar/index.tsx +++ b/src/renderer/components/RepoDetailToolbar/index.tsx @@ -76,17 +76,12 @@ export default class RepoDetailToolbar extends React.Component< } }; - getRepoCategories = (id: number) => { - const mainStore = this.props.store!.main; - mainStore.onGetSelectRepoCategories(id); - }; - render() { let readIcon; let flagIcon; const mainStore = this.props.store!.main; - const { selectedRepo, categories } = mainStore; + const { selectedRepo, categories, selectRepoCategories } = mainStore; if (selectedRepo) { readIcon = ( @@ -124,7 +119,7 @@ export default class RepoDetailToolbar extends React.Component< diff --git a/src/renderer/components/RepoDetailToolbar/note.tsx b/src/renderer/components/RepoDetailToolbar/note.tsx index b998327..21a3995 100644 --- a/src/renderer/components/RepoDetailToolbar/note.tsx +++ b/src/renderer/components/RepoDetailToolbar/note.tsx @@ -44,11 +44,21 @@ export default class RepoNoteTool extends React.Component Add Your Notes diff --git a/src/renderer/components/ReposList/item.tsx b/src/renderer/components/ReposList/item.tsx index d49cc47..a99ca36 100644 --- a/src/renderer/components/ReposList/item.tsx +++ b/src/renderer/components/ReposList/item.tsx @@ -2,6 +2,7 @@ import * as React from "react"; import ClassNames from "classnames"; import { Rate, Icon, Row, Col } from "antd"; import IRepo from "../../interface/IRepo"; +import logger from "../../utils/logger"; const styles = require("./styles/item.less"); @@ -31,7 +32,9 @@ export default class RepoListItem extends React.Component span { - border: 0; - z-index: 999; - &:hover { - input { - border-color: #d9d9d9 !important; - } - } - } input { background: rgb(225, 225, 225); text-align: center; @@ -22,14 +13,19 @@ background: #fff; } } - &:focus { - outline: 0; + + > span { + border: 0; + z-index: 999; + &:hover { + input { + border-color: #d9d9d9 !important; + } + } } -} -.searchBoxFocused { - > .searchFields { - margin-top: 0px; + &:focus { + outline: 0; } } @@ -39,4 +35,15 @@ transition: all 0.3s ease; margin-top: -36px; text-align: center; + :global { + .ant-radio-group { + font-size: 12px; + } + } +} + +.searchBoxFocused { + > .searchFields { + margin-top: 0; + } } diff --git a/src/renderer/interface/IContributor.ts b/src/renderer/interface/IContributor.ts new file mode 100644 index 0000000..864ece7 --- /dev/null +++ b/src/renderer/interface/IContributor.ts @@ -0,0 +1,6 @@ +export default interface IContributor { + id: number; + htmlUrl: string; + login: string; + avatarUrl: string; +}; diff --git a/src/renderer/store/GlobalStore.ts b/src/renderer/store/GlobalStore.ts index bfd1a45..d672f84 100644 --- a/src/renderer/store/GlobalStore.ts +++ b/src/renderer/store/GlobalStore.ts @@ -108,7 +108,7 @@ export default class GlobalStore { }) .catch(error => { logger.log(error.message || error.toString()); - throw error; + return null; }); }; diff --git a/src/renderer/store/MainStore.ts b/src/renderer/store/MainStore.ts index d531869..a609e39 100644 --- a/src/renderer/store/MainStore.ts +++ b/src/renderer/store/MainStore.ts @@ -1,4 +1,4 @@ -import { observable, action, toJS, autorun } from "mobx"; +import { observable, action, toJS } from "mobx"; import moment from "moment"; import ILanguage from "../interface/ILanguage"; import ICategory from "../interface/ICategory"; @@ -16,22 +16,14 @@ import DBHandler from "../rxdb/dbHandler"; import logger from "../utils/logger"; import IRepo from "../interface/IRepo"; import GithubClient from "../utils/githubClient"; +import ITag from "renderer/interface/ITag"; +import IContributor from "renderer/interface/IContributor"; export default class MainStore { private globalStore: GlobalStore; constructor(globalStore: GlobalStore) { this.globalStore = globalStore; - - autorun(() => { - logger.log("Mobx autorun"); - const { selectedRepo } = this; - if (selectedRepo && !selectedRepo._contributors) { - logger.log("Mobx autorun: Fetch and get repo contributors"); - this.onFetchRepoContributors(selectedRepo); - this.onGetSelectRepoContributors(selectedRepo.id); - } - }); } private getDbHandler = () => { @@ -44,6 +36,7 @@ export default class MainStore { return this.globalStore.restore().then(() => { this.updateCategoryList(); this.updateLanguageList(); + this.updateRepoList(); return this.fetchRemoteRepos(); }); }; @@ -309,13 +302,29 @@ export default class MainStore { @action onSelectRepo = (id: number) => { - const { repos } = this; - this.selectedRepo = repos[id]; + logger.log(`Select repo: ${id}`); + const { reposMap, selectedRepo } = this; + if (selectedRepo && selectedRepo.id === id) { + return; + } + const newRepo = reposMap[id]; + this.selectedRepo = newRepo; + this.selectRepoTags = []; + this.selectRepoCategories = []; + this.selectRepoContributors = []; + + if (newRepo && !newRepo._contributors) { + logger.log(`Fetch and get repo contributors for selected repo ${newRepo.id}`); + this.onFetchRepoContributors(newRepo); + this.onGetSelectRepoContributors(newRepo.id); + this.onGetTagsForRepo(newRepo.id); + this.onGetSelectRepoCategories(newRepo.id); + } }; @action onRateRepo = (id: number, score: number) => { - const { repos } = this; + logger.log(`Rate repo: ${id}`); const updateObj = { id, score @@ -325,8 +334,7 @@ export default class MainStore { .then(dbHandler => dbHandler.updateRepo(updateObj)) .then(repo => { // also replace new repo into repos list - repos[repo.id] = repo; - this.repos = Object.assign({}, repos); + this.replaceOneRepoInList(repo); return repo; }) @@ -384,7 +392,7 @@ export default class MainStore { repo._hotChange = Object.keys(properties); // mark the repo that its readme etc.. has fetched, do not fetch again this.replaceOneRepoInList(repo); - this.selectedRepo = repo; + this.selectedRepo = Object.assign({}, selectedRepo, repo); return repo; }) @@ -410,6 +418,10 @@ export default class MainStore { rxChange: Math.floor(moment.now().valueOf() / 1000) }); + if (this.selectedRepo.id === id) { + this.selectRepoCategories = repo._categories; + } + // update all categories list, for updating the nav category node this.updateCategoryList(); @@ -435,6 +447,9 @@ export default class MainStore { repo._contributors = _contributors; repo._hotChange = ["contributors"]; this.replaceOneRepoInList(repo); + if (repo.id === this.selectedRepo.id) { + this.selectRepoContributors = _contributors; + } } // if it has same id with selectedRepo, also replace selectedRepo @@ -452,12 +467,17 @@ export default class MainStore { @action onAddTagForRepo = (id: number, tagName: string) => { + logger.log(`Adding tag: ${tagName} for repo: ${id}`); return this.getDbHandler() .then(dbHandler => dbHandler.addRepoTag(id, tagName)) .then(repo => { // also replace the repo in repos list this.replaceOneRepoInList(repo); + if (this.selectedRepo.id === id) { + this.selectRepoTags = repo._tags; + } + // if it has same id with selectedRepo, also replace selectedRepo this.onUpdateSelectedRepo(id, { rxChange: Math.floor(moment.now().valueOf() / 1000) @@ -479,6 +499,10 @@ export default class MainStore { // also replace the repo in repos list this.replaceOneRepoInList(repo); + if (this.selectedRepo.id === id) { + this.selectRepoTags = repo._tags; + } + // if it has same id with selectedRepo, also replace selectedRepo this.onUpdateSelectedRepo(id, { rxChange: Math.floor(moment.now().valueOf() / 1000) @@ -502,6 +526,9 @@ export default class MainStore { if (repo) { repo._tags = tags; this.replaceOneRepoInList(repo); + if (this.selectedRepo.id === repo.id) { + this.selectRepoTags = tags; + } } return tags; @@ -565,6 +592,10 @@ export default class MainStore { repo._contributors = contributors; repo._hotChange = ["contributors"]; this.replaceOneRepoInList(repo); + + if (repo.id === this.selectedRepo.id) { + this.selectRepoContributors = contributors; + } } // if it has same id with selectedRepo, also replace selectedRepo @@ -597,6 +628,10 @@ export default class MainStore { if (repo) { repo._categories = categories; this.replaceOneRepoInList(repo); + + if (this.selectedRepo.id === repo.id) { + this.selectRepoCategories = categories; + } } return categories; @@ -606,4 +641,11 @@ export default class MainStore { throw error; }); }; + + /** + * Ext properties for selected repo + */ + @observable selectRepoTags: ITag[] = []; + @observable selectRepoContributors: IContributor[] = []; + @observable selectRepoCategories: ICategory[] = []; } diff --git a/src/renderer/views/Login/index.tsx b/src/renderer/views/Login/index.tsx index 739b29d..e500659 100644 --- a/src/renderer/views/Login/index.tsx +++ b/src/renderer/views/Login/index.tsx @@ -88,7 +88,7 @@ export default class LoginView extends React.Component Date: Mon, 29 Jan 2018 18:10:58 +0800 Subject: [PATCH 24/25] add pagination --- .travis.yml | 2 +- .../components/MainListPane/index.tsx | 2 + src/renderer/components/ReposList/index.tsx | 4 +- .../components/ReposListPagination/index.tsx | 45 +++++++++++++++++++ .../ReposListPagination/styles/index.less | 5 +++ src/renderer/interface/IContributor.ts | 2 +- src/renderer/store/MainStore.ts | 36 ++++++++++++++- 7 files changed, 91 insertions(+), 5 deletions(-) create mode 100644 src/renderer/components/ReposListPagination/index.tsx create mode 100644 src/renderer/components/ReposListPagination/styles/index.less diff --git a/.travis.yml b/.travis.yml index 17bb7b6..d708fb8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,7 +25,7 @@ before_install: | tar -xz -C /tmp/git-lfs --strip-components 1 && /tmp/git-lfs/git-lfs pull - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install --no-install-recommends -y icnsutils graphicsmagick xz-utils; fi install: -- nvm install 6 +- nvm install 7 - npm install electron-builder@next - npm install - npm prune diff --git a/src/renderer/components/MainListPane/index.tsx b/src/renderer/components/MainListPane/index.tsx index 8ebf8f6..15d4e37 100644 --- a/src/renderer/components/MainListPane/index.tsx +++ b/src/renderer/components/MainListPane/index.tsx @@ -3,6 +3,7 @@ import ClassNames from "classnames"; import SearchBox from "../SearchBox"; import SortBar from "../SortBar"; import ReposList from "../ReposList"; +import ReposListPagination from "../ReposListPagination"; import FilterBar from "../FilterBar"; const styles = require("./styles/index.less"); @@ -22,6 +23,7 @@ export default class MainListPane extends React.Component +
); diff --git a/src/renderer/components/ReposList/index.tsx b/src/renderer/components/ReposList/index.tsx index d5c8a8e..da863e3 100644 --- a/src/renderer/components/ReposList/index.tsx +++ b/src/renderer/components/ReposList/index.tsx @@ -21,11 +21,11 @@ export default class ReposList extends React.Component - {repos.map(repo => ( + {pageRepos.map(repo => ( { + constructor(props) { + super(props); + } + + render() { + const mainStore = this.props.store!.main; + const { page, pageSize, total } = mainStore; + + if (total === 0) { + return null; + } + + return ( +
+ +
+ ); + } +} diff --git a/src/renderer/components/ReposListPagination/styles/index.less b/src/renderer/components/ReposListPagination/styles/index.less new file mode 100644 index 0000000..4495497 --- /dev/null +++ b/src/renderer/components/ReposListPagination/styles/index.less @@ -0,0 +1,5 @@ +.repoListPagination { + position: relative; + text-align: center; + padding: 10px; +} diff --git a/src/renderer/interface/IContributor.ts b/src/renderer/interface/IContributor.ts index 864ece7..de857e0 100644 --- a/src/renderer/interface/IContributor.ts +++ b/src/renderer/interface/IContributor.ts @@ -3,4 +3,4 @@ export default interface IContributor { htmlUrl: string; login: string; avatarUrl: string; -}; +} diff --git a/src/renderer/store/MainStore.ts b/src/renderer/store/MainStore.ts index a609e39..4c35f00 100644 --- a/src/renderer/store/MainStore.ts +++ b/src/renderer/store/MainStore.ts @@ -1,4 +1,4 @@ -import { observable, action, toJS } from "mobx"; +import { observable, action, toJS, computed } from "mobx"; import moment from "moment"; import ILanguage from "../interface/ILanguage"; import ICategory from "../interface/ICategory"; @@ -249,6 +249,14 @@ export default class MainStore { this.repos = repos; this.reposMap = keyedRepos; + + const total = repos.length; + const maxPage = Math.ceil(total / this.pageSize); + this.total = total; + if (this.page > maxPage) { + this.page = 1; + } + return repos; }) .catch(error => { @@ -648,4 +656,30 @@ export default class MainStore { @observable selectRepoTags: ITag[] = []; @observable selectRepoContributors: IContributor[] = []; @observable selectRepoCategories: ICategory[] = []; + + /** + * Pagination + */ + @observable page: number = 1; + @observable pageSize: number = 20; + @observable total: number = 0; + + @computed + get pageRepos() { + const { page, pageSize, repos } = this; + const list = repos.slice((page - 1) * pageSize, page * pageSize); + return list; + } + + @action + onPageChange = (page: number) => { + logger.log(`Change page to: ${page}`); + this.page = page; + }; + + @action + resetPagination = () => { + this.page = 1; + this.pageSize = 20; + }; } From ac80109b2201d9507a6b2fd8ec84ba0c1b6b6d2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=90=B4=E5=AD=A6=E8=B0=A6?= Date: Mon, 29 Jan 2018 18:14:21 +0800 Subject: [PATCH 25/25] update README --- README.md | 9 ++++++--- package.json | 39 ++++++++++++++------------------------- 2 files changed, 20 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 8cff4e8..0785f08 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,10 @@ 基于 React/Electron/Ant Design 打造的开源 Github Stars 管理的跨平台工具 +## Update 2018.1 + +已经基于 TypeScript 重写了整个代码,使用 Mobx 替代 Redux 作为状态管理工具,并优化了开发编译 Webpack 脚本配置。 + ## Features * 归类 @@ -36,8 +40,7 @@ * 支持离线查看仓库并支持上述所有功能操作,包括 readme 文件的查看 * 高效的数据条件化呈现(不用频繁请求服务器) -* 数据 - 支持 Stars 和自定义数据的导出备份和导入恢复 +* 数据支持 Stars 和自定义数据的导出备份和导入恢复 ## Screenshots @@ -58,7 +61,7 @@ ``` npm install npm run dev -npm start +npm run start:dev ``` 如果在 install packages 出错,提示 keytar 错误等信息,特别是 windows 用户,你可能需要安装 windows-build-tools 的 package 之后在进行上述步骤 diff --git a/package.json b/package.json index 60a884b..331f240 100644 --- a/package.json +++ b/package.json @@ -14,10 +14,7 @@ "target": "nsis" }, "linux": { - "target": [ - "AppImage", - "deb" - ] + "target": ["AppImage", "deb"] }, "directories": { "app": "app", @@ -30,16 +27,7 @@ "type": "git", "url": "git+https://github.com/thundernet8/StarCabinet.git" }, - "keywords": [ - "Github", - "Star", - "Electron", - "React", - "Mobx", - "React-Router", - "Webpack", - "rxdb" - ], + "keywords": ["Github", "Star", "Electron", "React", "Mobx", "React-Router", "Webpack", "rxdb"], "author": { "name": "WuXueqian", "email": "chinash2010@gmail.com" @@ -51,13 +39,18 @@ "homepage": "https://github.com/thundernet8/StarCabinet#readme", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "dll": "cross-env NODE_ENV=production webpack -p --hide-modules --config webpack/dll.conf.babel.js", - "dll:dev": "cross-env NODE_ENV=development webpack --hide-modules --config webpack/dll.conf.babel.js", - "build": "rimraf app/dist && mkdirp app/dist && cross-env NODE_ENV=production npm run dll && cross-env NODE_ENV=production webpack --progress --hide-modules --config webpack/prod.conf.babel.js", - "build:dev": "rimraf app/dist && mkdirp app/dist && cross-env NODE_ENV=development npm run dll:dev && cross-env NODE_ENV=development webpack --progress --hide-modules --config webpack/main.conf.babel.js && cross-env NODE_ENV=development webpack --progress --hide-modules --config webpack/dev.conf.babel.js", + "dll": + "cross-env NODE_ENV=production webpack -p --hide-modules --config webpack/dll.conf.babel.js", + "dll:dev": + "cross-env NODE_ENV=development webpack --hide-modules --config webpack/dll.conf.babel.js", + "build": + "rimraf app/dist && mkdirp app/dist && cross-env NODE_ENV=production npm run dll && cross-env NODE_ENV=production webpack --progress --hide-modules --config webpack/prod.conf.babel.js", + "build:dev": + "rimraf app/dist && mkdirp app/dist && cross-env NODE_ENV=development npm run dll:dev && cross-env NODE_ENV=development webpack --progress --hide-modules --config webpack/main.conf.babel.js && cross-env NODE_ENV=development webpack --progress --hide-modules --config webpack/dev.conf.babel.js", "dev": "npm run build:dev && webpack-dev-server --config webpack/dev.conf.babel.js", "analyze": "cross-env ANALYZE_ENV=true npm run build", - "start": "cross-env NODE_ENV=development electron ./app", + "start": "cross-env NODE_ENV=production electron ./app", + "start:dev": "cross-env NODE_ENV=development electron ./app", "pack": "npm run build && build --dir", "dist": "npm run build && build", "rebuild": "electron-rebuild", @@ -69,12 +62,8 @@ "lint-staged:style": "stylelint --syntax less" }, "lint-staged": { - "src/**/*.{ts,tsx}": [ - "lint-staged:ts" - ], - "src/**/*.less": [ - "lint-staged:style" - ] + "src/**/*.{ts,tsx}": ["lint-staged:ts"], + "src/**/*.less": ["lint-staged:style"] }, "pre-commit": "lint-staged", "devDependencies": {