diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml
index a1d16d13044d8..8238a471fc6fa 100644
--- a/.github/workflows/android.yml
+++ b/.github/workflows/android.yml
@@ -2,7 +2,7 @@ name: Build and Deploy Android
on:
push:
- branches: [ master ]
+ tags: ['**']
jobs:
build:
diff --git a/.github/workflows/desktop.yml b/.github/workflows/desktop.yml
index ac5f3d87bdb0f..ecbb24894832a 100644
--- a/.github/workflows/desktop.yml
+++ b/.github/workflows/desktop.yml
@@ -2,7 +2,7 @@ name: Build and Deploy Desktop
on:
push:
- branches: [ master ]
+ tags: ['**']
jobs:
build:
@@ -18,13 +18,6 @@ jobs:
- name: Install node packages
run: npm install
- - name: Configure AWS Credentials
- uses: aws-actions/configure-aws-credentials@v1
- with:
- aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
- aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
- aws-region: us-east-1
-
- name: Decrypt Developer ID Certificate
run: cd desktop && gpg --quiet --batch --yes --decrypt --passphrase="$DEVELOPER_ID_SECRET_PASSPHRASE" --output developer_id.p12 developer_id.p12.gpg
env:
@@ -37,9 +30,5 @@ jobs:
CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
-
- - name: Zip desktop build
- run: 7z a $GITHUB_WORKSPACE/dist/mac/Chat.app.zip $GITHUB_WORKSPACE/dist/mac/Chat.app
-
- - name: Deploy to S3
- run: aws s3 cp --acl public-read $GITHUB_WORKSPACE/dist/mac/Chat.app.zip s3://chat-test-expensify-com/Chat.app.zip
+ AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
+ AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 167217ae4a278..e66724314d511 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -1,6 +1,6 @@
name: eslint
-on: [push]
+on: push
jobs:
build:
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
deleted file mode 100644
index bb3f364bedaab..0000000000000
--- a/.github/workflows/main.yml
+++ /dev/null
@@ -1,60 +0,0 @@
-# This is a basic workflow to help you get started with Actions
-
-name: Build and Deploy Web
-
-# Controls when the action will run. Triggers the workflow on push or pull request
-# events but only for the master branch
-on:
- push:
- branches: [ master ]
-
-# A workflow run is made up of one or more jobs that can run sequentially or in parallel
-jobs:
- # This workflow contains a single job called "build"
- build:
- # The type of runner that the job will run on
- runs-on: ubuntu-16.04
-
- # Steps represent a sequence of tasks that will be executed as part of the job
- steps:
- # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- - uses: actions/checkout@v2
-
- # Installs node
- - name: Setup Node
- uses: actions/setup-node@v1
- with:
- node-version: '14.x'
-
- # Install python pre-reqs
- - name: Setup python
- run: sudo apt-get install python3-setuptools
-
- # Installs Cloudflare CLI, after installing/upgrading dependencies
- - name: Setup Cloudflare CLI
- run: |
- pip3 install --upgrade pip
- pip3 install wheel # need wheel before cloudflare, this is the only way to ensure order.
- pip3 install cloudflare
-
- - name: Configure AWS Credentials
- uses: aws-actions/configure-aws-credentials@v1
- with:
- aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
- aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
- aws-region: us-east-1
-
- # Install node modules
- - name: Install dependenices
- run: npm install
-
- - name: Build web
- run: npm run build
-
- - name: Deploy to S3
- run: aws s3 cp --recursive --acl public-read $GITHUB_WORKSPACE/dist s3://chat-test-expensify-com/
-
- - name: Purge Cloudflare cache
- run: /home/runner/.local/bin/cli4 --delete hosts=["chat.expensify.com"] /zones/:9ee042e6cfc7fd45e74aa7d2f78d617b/purge_cache
- env:
- CF_API_KEY: ${{ secrets.CLOUDFLARE_TOKEN }}
diff --git a/.github/workflows/version.yml b/.github/workflows/version.yml
new file mode 100644
index 0000000000000..7f5826026e533
--- /dev/null
+++ b/.github/workflows/version.yml
@@ -0,0 +1,29 @@
+name: Create a new version
+
+on:
+ push:
+ branches: [master]
+
+jobs:
+ build:
+ runs-on: ubuntu-16.04
+
+ steps:
+ - uses: actions/checkout@v2
+
+ - name: Setup Node
+ uses: actions/setup-node@v1
+ with:
+ node-version: '14.x'
+
+ - name: Install dependenices
+ run: npm install
+
+ - name: Set git user
+ run: git config user.name github-action
+
+ - name: Generate version
+ run: npm version prerelease -m "Update version to %s"
+
+ - name: Push new version
+ run: git push && git push --tags
diff --git a/.github/workflows/web.yml b/.github/workflows/web.yml
new file mode 100644
index 0000000000000..5696cd4b6744b
--- /dev/null
+++ b/.github/workflows/web.yml
@@ -0,0 +1,51 @@
+name: Build and Deploy Web
+
+on:
+ push:
+ tags: ['**']
+
+jobs:
+ build:
+ runs-on: ubuntu-16.04
+
+ steps:
+ - uses: actions/checkout@v2
+
+ # Installs node
+ - name: Setup Node
+ uses: actions/setup-node@v1
+ with:
+ node-version: '14.x'
+
+ # Install python pre-reqs
+ - name: Setup python
+ run: sudo apt-get install python3-setuptools
+
+ # Installs Cloudflare CLI, after installing/upgrading dependencies
+ - name: Setup Cloudflare CLI
+ run: |
+ pip3 install --upgrade pip
+ pip3 install wheel # need wheel before cloudflare, this is the only way to ensure order.
+ pip3 install cloudflare
+
+ - name: Configure AWS Credentials
+ uses: aws-actions/configure-aws-credentials@v1
+ with:
+ aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
+ aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
+ aws-region: us-east-1
+
+ # Install node modules
+ - name: Install dependenices
+ run: npm install
+
+ - name: Build web
+ run: npm run build
+
+ - name: Deploy to S3
+ run: aws s3 cp --recursive --acl public-read $GITHUB_WORKSPACE/dist s3://chat-test-expensify-com/
+
+ - name: Purge Cloudflare cache
+ run: /home/runner/.local/bin/cli4 --delete hosts=["chat.expensify.com"] /zones/:9ee042e6cfc7fd45e74aa7d2f78d617b/purge_cache
+ env:
+ CF_API_KEY: ${{ secrets.CLOUDFLARE_TOKEN }}
diff --git a/android/app/build.gradle b/android/app/build.gradle
index ba0b3890da916..777de1007303c 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -138,8 +138,8 @@ android {
applicationId "com.expensifyreactnative.chat"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
- versionCode 5
- versionName "1.0.1-4"
+ versionCode 18
+ versionName "1.0.1-17"
}
splits {
abi {
diff --git a/desktop/electron.config.js b/desktop/electron.config.js
index cf4ab39a9f846..846733d1fa592 100644
--- a/desktop/electron.config.js
+++ b/desktop/electron.config.js
@@ -10,6 +10,16 @@ module.exports = {
entitlementsInherit: 'desktop/entitlements.mac.plist',
type: 'distribution'
},
+ dmg: {
+ title: 'Chat',
+ artifactName: 'Chat.dmg',
+ internetEnabled: true
+ },
+ publish: [{
+ provider: 's3',
+ bucket: 'chat-test-expensify-com',
+ channel: 'latest'
+ }],
files: [
'./dist/**/*',
'./main.js'
diff --git a/ios/ReactNativeChat/Info.plist b/ios/ReactNativeChat/Info.plist
index 725edbf72f02b..2f0c281472fe6 100644
--- a/ios/ReactNativeChat/Info.plist
+++ b/ios/ReactNativeChat/Info.plist
@@ -21,7 +21,7 @@
CFBundleSignature
????
CFBundleVersion
- 5
+ 18
ITSAppUsesNonExemptEncryption
LSRequiresIPhoneOS
diff --git a/ios/ReactNativeChatTests/Info.plist b/ios/ReactNativeChatTests/Info.plist
index 2a1c32ed7c004..061521b8cc177 100644
--- a/ios/ReactNativeChatTests/Info.plist
+++ b/ios/ReactNativeChatTests/Info.plist
@@ -19,6 +19,6 @@
CFBundleSignature
????
CFBundleVersion
- 5
+ 18
diff --git a/main.js b/main.js
index 17e05f407ca95..ad1c5ebabee39 100644
--- a/main.js
+++ b/main.js
@@ -1,6 +1,8 @@
const {app, BrowserWindow, shell} = require('electron');
const serve = require('electron-serve');
const contextMenu = require('electron-context-menu');
+const {autoUpdater} = require('electron-updater');
+const log = require('electron-log');
/**
* Electron main process that handles wrapping the web application.
@@ -8,42 +10,64 @@ const contextMenu = require('electron-context-menu');
* @see: https://www.electronjs.org/docs/tutorial/application-architecture#main-and-renderer-processes
*/
-// TODO: Turn this off, use web-security after alpha launch, currently we recieve a CORS issue preventing
+// Interval that we check for new versions of the app
+const UPDATE_INTERVAL = 1000 * 60 * 60;
+
+// TODO: Turn this off, use web-security after alpha launch, currently we receive a CORS issue preventing
// the electron app from making any API requests.
app.commandLine.appendSwitch('disable-web-security');
-const mainWindow = (async () => {
+// Initialize the right click menu
+// See https://github.com/sindresorhus/electron-context-menu
+contextMenu();
+
+// Send all autoUpdater logs to a log file: ~/Library/Logs/react-native-chat/main.log
+// See https://www.npmjs.com/package/electron-log
+autoUpdater.logger = log;
+autoUpdater.logger.transports.file.level = 'info';
+
+// Send all Console logs to a log file: ~/Library/Logs/react-native-chat/main.log
+// See https://www.npmjs.com/package/electron-log
+Object.assign(console, log.functions);
+
+const mainWindow = (() => {
const loadURL = serve({directory: 'dist'});
- await app.whenReady();
-
- // Initialize the right click menu
- // See https://github.com/sindresorhus/electron-context-menu
- contextMenu();
-
- const browserWindow = new BrowserWindow({
- backgroundColor: '#FAFAFA',
- width: 1200,
- height: 900,
- webPreferences: {
- nodeIntegration: true,
- },
- });
-
- await loadURL(browserWindow);
-
- // When the user clicks a link that has target="_blank" (which is all external links)
- // open the default browser instead of a new electron window
- browserWindow.webContents.on('new-window', (e, url) => {
- // make sure local urls stay in electron perimeter
- if (url.substr(0, 'file://'.length) === 'file://') {
- return;
- }
-
- // and open every other protocol in the browser
- e.preventDefault();
- shell.openExternal(url);
- });
+ return app.whenReady()
+ .then(() => {
+ const browserWindow = new BrowserWindow({
+ backgroundColor: '#FAFAFA',
+ width: 1200,
+ height: 900,
+ webPreferences: {
+ nodeIntegration: true,
+ },
+ });
+
+ // When the user clicks a link that has target="_blank" (which is all external links)
+ // open the default browser instead of a new electron window
+ browserWindow.webContents.on('new-window', (e, url) => {
+ // make sure local urls stay in electron perimeter
+ if (url.substr(0, 'file://'.length) === 'file://') {
+ return;
+ }
+
+ // and open every other protocol in the browser
+ e.preventDefault();
+ return shell.openExternal(url);
+ });
+
+ return browserWindow;
+ })
+
+ // After initializing and configuring the browser window, load the compiled JavaScript
+ .then(browserWindow => loadURL(browserWindow))
+
+ // Check for a new version of the app on launch
+ .then(() => autoUpdater.checkForUpdatesAndNotify())
+
+ // Set a timer to check for new versions of the app
+ .then(() => setInterval(() => autoUpdater.checkForUpdatesAndNotify(), UPDATE_INTERVAL));
});
-mainWindow();
+mainWindow().then(window => window);
diff --git a/package-lock.json b/package-lock.json
index 1f24912cbfc1f..6813e8b4ffb38 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "react-native-chat",
- "version": "1.0.1-4",
+ "version": "1.0.1-17",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -1981,6 +1981,11 @@
"integrity": "sha512-IkVfat549ggtkZUthUzEX49562eGikhSYeVGX97SkMFn+sTZrgRewXjQ4tPKFPCykZHkX1Zfd9OoELGqKU2jJA==",
"dev": true
},
+ "@types/semver": {
+ "version": "7.3.3",
+ "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.3.tgz",
+ "integrity": "sha512-jQxClWFzv9IXdLdhSaTf16XI3NYe6zrEbckSpb5xhKfPbWgIyAY0AFyWWWfaiDcBuj3UHmMkCIwSRqpKMTZL2Q=="
+ },
"@types/source-list-map": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz",
@@ -3033,8 +3038,7 @@
"at-least-node": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
- "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==",
- "dev": true
+ "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg=="
},
"atob": {
"version": "2.1.2",
@@ -3972,7 +3976,6 @@
"version": "8.7.2",
"resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.7.2.tgz",
"integrity": "sha512-xBqv+8bg6cfnzAQK1k3OGpfaHg+QkPgIgpEkXNhouZ0WiUkyZCftuRc2LYzQrLucFywpa14Xbc6+hTbpq83yRA==",
- "dev": true,
"requires": {
"debug": "^4.1.1",
"sax": "^1.2.4"
@@ -3982,7 +3985,6 @@
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
- "dev": true,
"requires": {
"ms": "^2.1.1"
}
@@ -5928,6 +5930,11 @@
"resolved": "https://registry.npmjs.org/electron-is-dev/-/electron-is-dev-1.2.0.tgz",
"integrity": "sha512-R1oD5gMBPS7PVU8gJwH6CtT0e6VSoD0+SzSnYpNm+dBkcijgA+K7VAMHDfnRq/lkKPZArpzplTW6jfiMYosdzw=="
},
+ "electron-log": {
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/electron-log/-/electron-log-4.2.4.tgz",
+ "integrity": "sha512-CXbDU+Iwi+TjKzugKZmTRIORIPe3uQRqgChUl19fkW/reFUn5WP7dt+cNGT3bkLV8xfPilpkPFv33HgtmLLewQ=="
+ },
"electron-notarize": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/electron-notarize/-/electron-notarize-1.0.0.tgz",
@@ -6040,6 +6047,52 @@
"integrity": "sha512-HiroW5ZbGwgT8kCnoEO8qnGjoTPzJxduvV/Vv/wH63eo2N6Zj3xT5fmmaSPAPUM05iN9/5fIEkIg3owTtV6QZg==",
"dev": true
},
+ "electron-updater": {
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-4.3.4.tgz",
+ "integrity": "sha512-ekpgxDrYl+Wi24ktO4qfj2CtCABxrmK1C/oekp0tai6q4VR4ZdPkit4CX8+GenvKMme7uMmfPFnLp/vwhP/ThQ==",
+ "requires": {
+ "@types/semver": "^7.3.1",
+ "builder-util-runtime": "8.7.2",
+ "fs-extra": "^9.0.1",
+ "js-yaml": "^3.14.0",
+ "lazy-val": "^1.0.4",
+ "lodash.isequal": "^4.5.0",
+ "semver": "^7.3.2"
+ },
+ "dependencies": {
+ "fs-extra": {
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz",
+ "integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==",
+ "requires": {
+ "at-least-node": "^1.0.0",
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^6.0.1",
+ "universalify": "^1.0.0"
+ }
+ },
+ "jsonfile": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.0.1.tgz",
+ "integrity": "sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg==",
+ "requires": {
+ "graceful-fs": "^4.1.6",
+ "universalify": "^1.0.0"
+ }
+ },
+ "semver": {
+ "version": "7.3.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
+ "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ=="
+ },
+ "universalify": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz",
+ "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug=="
+ }
+ }
+ },
"electron-webpack": {
"version": "2.8.2",
"resolved": "https://registry.npmjs.org/electron-webpack/-/electron-webpack-2.8.2.tgz",
@@ -10785,8 +10838,7 @@
"lazy-val": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.4.tgz",
- "integrity": "sha512-u93kb2fPbIrfzBuLjZE+w+fJbUUMhNDXxNmMfaqNgpfQf1CO5ZSe2LfsnBqVAk7i/2NF48OSoRj+Xe2VT+lE8Q==",
- "dev": true
+ "integrity": "sha512-u93kb2fPbIrfzBuLjZE+w+fJbUUMhNDXxNmMfaqNgpfQf1CO5ZSe2LfsnBqVAk7i/2NF48OSoRj+Xe2VT+lE8Q=="
},
"lcid": {
"version": "1.0.0",
@@ -10922,6 +10974,11 @@
"resolved": "https://registry.npmjs.org/lodash.has/-/lodash.has-4.5.2.tgz",
"integrity": "sha1-0Z9NwQlQWMzL4rDN9O4P5Ko3yGI="
},
+ "lodash.isequal": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
+ "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA="
+ },
"lodash.sortby": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
diff --git a/package.json b/package.json
index 26bb299eece4f..e412a5c5dfd4d 100644
--- a/package.json
+++ b/package.json
@@ -1,8 +1,9 @@
{
"name": "react-native-chat",
- "version": "1.0.1-4",
+ "version": "1.0.1-17",
"author": "Expensify, Inc.",
"homepage": "https://expensify.com",
+ "description": "Expensify Chat",
"private": true,
"scripts": {
"android": "react-native run-android",
@@ -11,7 +12,7 @@
"start": "react-native start",
"web": "webpack-dev-server --open --config webpack.dev.js",
"build": "webpack --config webpack.prod.js",
- "desktop-build": "webpack --config webpack.prod.js && electron-builder --dir --config desktop/electron.config.js",
+ "desktop-build": "webpack --config webpack.prod.js && electron-builder --config desktop/electron.config.js --publish always",
"test": "jest",
"lint": "eslint .",
"deploy-ios": "npm version prerelease && git push && fastlane ios beta",
@@ -23,7 +24,9 @@
"babel-plugin-transform-remove-console": "^6.9.4",
"dotenv": "^8.2.0",
"electron-context-menu": "^2.3.0",
+ "electron-log": "^4.2.4",
"electron-serve": "^1.0.0",
+ "electron-updater": "^4.3.4",
"file-loader": "^6.0.0",
"html-entities": "^1.3.1",
"jquery": "^3.5.1",
diff --git a/src/page/home/sidebar/AppLinks.js b/src/page/home/sidebar/AppLinks.js
index dec89abad5427..421263a09045c 100644
--- a/src/page/home/sidebar/AppLinks.js
+++ b/src/page/home/sidebar/AppLinks.js
@@ -6,7 +6,7 @@ const AppLinks = () => (
<>
Desktop