feat: implement latest version updater for macos (#2214)

Co-authored-by: himself65 <himself65@outlook.com>
This commit is contained in:
Horus 2023-05-09 02:21:15 +08:00 committed by GitHub
parent d1457075b3
commit 41d4af1dc1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 263 additions and 12 deletions

View File

@ -0,0 +1,4 @@
owner: toeverything
repo: AFFiNE
provider: github
private: false

View File

@ -45,6 +45,7 @@ module.exports = {
teamId: process.env.APPLE_TEAM_ID,
}
: undefined,
extraResource: ['./resources/app-update.yml'],
},
makers: [
{

View File

@ -2,4 +2,5 @@
// It will guide preload and main process on the correct event types and payloads
export interface MainEventMap {
'main:on-db-update': (workspaceId: string) => void;
'main:client-update-available': (version: string) => void;
}

View File

@ -18,6 +18,7 @@ import { openWorkspaceDatabase } from './data/sqlite';
import { deleteWorkspace, listWorkspaces } from './data/workspace';
import { getExchangeTokenParams, oauthEndpoint } from './google-auth';
import { sendMainEvent } from './send-main-event';
import { updateClient } from './updater';
let currentWorkspaceId = '';
@ -144,6 +145,10 @@ function registerUIHandlers() {
ipcMain.handle('main:env-update', async (_, env, value) => {
process.env[env] = value;
});
ipcMain.handle('ui:client-update-install', async () => {
await updateClient();
});
}
function registerDBHandlers() {

View File

@ -7,6 +7,7 @@ import { logger } from '../../logger';
import { registerHandlers } from './handlers';
import { restoreOrCreateWindow } from './main-window';
import { registerProtocol } from './protocol';
import { registerUpdater } from './updater';
if (require('electron-squirrel-startup')) app.exit();
if (process.defaultApp) {
@ -58,6 +59,7 @@ app
.then(registerProtocol)
.then(registerHandlers)
.then(restoreOrCreateWindow)
.then(registerUpdater)
.catch(e => console.error('Failed create window:', e));
/**
* Check new app version in production mode only

View File

@ -0,0 +1,43 @@
import { autoUpdater } from 'electron-updater';
import { isMacOS } from '../../utils';
import { sendMainEvent } from './send-main-event';
const buildType = (process.env.BUILD_TYPE || 'canary').trim().toLowerCase();
const mode = process.env.NODE_ENV;
const isDev = mode === 'development';
autoUpdater.autoDownload = false;
autoUpdater.allowPrerelease = buildType !== 'stable';
autoUpdater.autoInstallOnAppQuit = false;
autoUpdater.autoRunAppAfterInstall = false;
autoUpdater.setFeedURL({
channel: buildType,
provider: 'github',
repo: 'AFFiNE',
owner: 'toeverything',
releaseType: buildType === 'stable' ? 'release' : 'prerelease',
});
export const updateClient = async () => {
autoUpdater.quitAndInstall();
};
export const registerUpdater = async () => {
if (isMacOS()) {
autoUpdater.on('update-available', () => {
autoUpdater.downloadUpdate();
});
autoUpdater.on('download-progress', e => {
console.log(e.percent);
});
autoUpdater.on('update-downloaded', e => {
sendMainEvent('main:client-update-available', e.version);
});
autoUpdater.on('error', e => {
console.log(e.message);
});
autoUpdater.forceDevUpdateConfig = isDev;
await autoUpdater.checkForUpdatesAndNotify();
}
};

View File

@ -72,6 +72,13 @@ const apis = {
updateEnv: (env: string, value: string) => {
ipcRenderer.invoke('main:env-update', env, value);
},
onClientUpdateInstall: () => {
ipcRenderer.invoke('ui:client-update-install');
},
onClientUpdateAvailable: (callback: (version: string) => void) => {
return onMainEvent('main:client-update-available', callback);
},
};
const appInfo = {

View File

@ -3,6 +3,10 @@
"private": true,
"version": "0.5.4-canary.26",
"author": "affine",
"repository": {
"url": "https://github.com/toeverything/AFFiNE",
"type": "git"
},
"description": "AFFiNE App",
"homepage": "https://github.com/toeverything/AFFiNE",
"scripts": {
@ -51,6 +55,7 @@
},
"dependencies": {
"better-sqlite3": "^8.3.0",
"electron-updater": "^5.3.0",
"yjs": "^13.6.1"
},
"build": {

View File

@ -0,0 +1,4 @@
owner: toeverything
repo: AFFiNE
provider: github
private: false

View File

@ -85,6 +85,7 @@ async function buildLayers() {
define: {
...common.main.define,
'process.env.NODE_ENV': `"production"`,
'process.env.BUILD_TYPE': `"${process.env.BUILD_TYPE || 'statble'}"`,
},
});
}

View File

@ -46,6 +46,7 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-is": "^18.2.0",
"rxjs": "^7.8.1",
"swr": "^2.1.5",
"y-protocols": "^1.0.5",
"yjs": "^13.6.1",

View File

@ -45,7 +45,8 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-error-boundary": "^4.0.4",
"react-is": "^18.2.0"
"react-is": "^18.2.0",
"rxjs": "^7.8.1"
},
"devDependencies": {
"@blocksuite/blocks": "0.0.0-20230508043859-34d0cc68-nightly",

View File

@ -105,3 +105,66 @@ export const sidebarFloatMaskStyle = style({
},
},
});
export const haloStyle = style({
overflow: 'hidden',
width: '100%',
height: '100%',
position: 'absolute',
top: 0,
left: 0,
':before': {
content: '""',
display: 'block',
width: '60%',
height: '40%',
position: 'absolute',
top: '80%',
left: '50%',
background:
'linear-gradient(180deg, rgba(50, 26, 206, 0.1) 10%, rgba(50, 26, 206, 0.35) 30%, rgba(84, 56, 255, 1) 50%)',
filter: 'blur(10px) saturate(1.2)',
transform: 'translateX(-50%) translateY(calc(0 * 1%)) scale(0)',
transition: '0.3s ease',
willChange: 'filter',
},
selectors: {
'&:hover:before': {
transform: 'translateX(-50%) translateY(calc(-70 * 1%)) scale(1)',
},
},
});
export const updaterButtonStyle = style({});
export const particlesStyle = style({
background: `var(--svg-animation), var(--svg-animation)`,
backgroundRepeat: 'no-repeat, repeat',
backgroundPosition: 'center, center top 100%',
backgroundSize: '100%, 130%',
WebkitMaskImage:
'linear-gradient(to top, transparent, black, black, transparent)',
width: '100%',
height: '100%',
position: 'absolute',
});
export const particlesBefore = style({
content: '""',
display: 'block',
position: 'absolute',
width: '100%',
height: '100%',
background: `var(--svg-animation), var(--svg-animation), var(--svg-animation)`,
backgroundRepeat: 'no-repeat, repeat, repeat',
backgroundPosition: 'center, center top 100%, center center',
backgroundSize: '100% 120%, 150%, 120%',
filter: 'blur(1px)',
willChange: 'filter',
});
export const installLabelStyle = style({
display: 'flex',
justifyContent: 'flex-start',
alignItems: 'center',
paddingLeft: '8px',
});

View File

@ -1,4 +1,6 @@
import { atomWithObservable } from 'jotai/utils';
import { atomWithStorage } from 'jotai/utils';
import { Observable } from 'rxjs';
export const APP_SIDEBAR_OPEN = 'app-sidebar-open';
export const appSidebarOpenAtom = atomWithStorage(
@ -9,3 +11,20 @@ export const appSidebarWidthAtom = atomWithStorage(
'app-sidebar-width',
256 /* px */
);
export const updateAvailableAtom = atomWithObservable<boolean>(() => {
return new Observable<boolean>(subscriber => {
if (typeof window !== 'undefined') {
const isMacosDesktop = environment.isDesktop && environment.isMacOs;
if (isMacosDesktop) {
const dispose = window.apis?.onClientUpdateAvailable(() => {
subscriber.next(true);
});
return () => {
dispose?.();
};
}
}
subscriber.next(false);
});
});

View File

@ -1,7 +1,10 @@
import { Button } from '@affine/component';
import { getEnvironment } from '@affine/env';
import { useAFFiNEI18N } from '@affine/i18n/hooks';
import {
ArrowLeftSmallIcon,
ArrowRightSmallIcon,
ResetIcon,
SidebarIcon,
} from '@blocksuite/icons';
import { assignInlineVars } from '@vanilla-extract/dynamic';
@ -13,18 +16,23 @@ import { forwardRef, useCallback, useEffect } from 'react';
import { IconButton } from '../../ui/button/IconButton';
import {
floatingMaxWidth,
haloStyle,
installLabelStyle,
navBodyStyle,
navFooterStyle,
navHeaderStyle,
navStyle,
navWidthVar,
particlesStyle,
sidebarButtonStyle,
sidebarFloatMaskStyle,
updaterButtonStyle,
} from './index.css';
import {
APP_SIDEBAR_OPEN,
appSidebarOpenAtom,
appSidebarWidthAtom,
updateAvailableAtom,
} from './index.jotai';
export { appSidebarOpenAtom };
@ -36,7 +44,8 @@ export type AppSidebarProps = PropsWithChildren<{
export const AppSidebar = forwardRef<HTMLElement, AppSidebarProps>(
function AppSidebar(props, forwardedRef): ReactElement {
const [open, setOpen] = useAtom(appSidebarOpenAtom);
const clientUpdateAvailable = useAtomValue(updateAvailableAtom);
const t = useAFFiNEI18N();
const appSidebarWidth = useAtomValue(appSidebarWidthAtom);
const initialRender = open === undefined;
@ -112,6 +121,23 @@ export const AppSidebar = forwardRef<HTMLElement, AppSidebarProps>(
</IconButton>
</div>
<div className={navBodyStyle}>{props.children}</div>
{clientUpdateAvailable && (
<Button
onClick={() => {
window.apis?.onClientUpdateInstall();
}}
noBorder
className={updaterButtonStyle}
type={'light'}
>
<div className={particlesStyle} aria-hidden="true"></div>
<span className={haloStyle} aria-hidden="true"></span>
<div className={installLabelStyle}>
<ResetIcon />
<span>{t['Restart Install Client Update']()}</span>
</div>
</Button>
)}
<div className={navFooterStyle}>{props.footer}</div>
</nav>
<div

View File

@ -102,6 +102,7 @@
"My Workspaces": "Meine Workspaces",
"New Keyword Page": "Neue '{{query}}' Seite",
"New Page": "Neue Seite",
"Restart Install Client Update": "Neustart zur Installation des Updates",
"New Workspace": "Neuer Workspace",
"No item": "Kein Inhalt",
"Non-Gmail": "Nur Gmail wird unterstützt",

View File

@ -20,6 +20,7 @@
"Import": "Import",
"Trash": "Trash",
"New Page": "New Page",
"Restart Install Client Update": "Restart to install update",
"New Keyword Page": "New '{{query}}' page",
"Find 0 result": "Find 0 result",
"Find results": "Find {{number}} results",

View File

@ -57,6 +57,7 @@
"Moved to Trash": "Déplacé à la corbeille ",
"New Keyword Page": "Nouvelle page '{{query}}'",
"New Page": "Nouvelle page",
"Restart Install Client Update": "Redémarrer pour installer la mise à jour",
"New Workspace": "Nouvel espace de travail ",
"No item": "Aucun objet ",
"Official Website": "Site officiel ",

View File

@ -89,6 +89,7 @@
"Ooops!": "Упс!",
"Official Website": "Официальный Сайт",
"New Page": "Новая страница",
"Restart Install Client Update": "Перезапустите для установки обновления",
"Moved to Trash": "Перемещено в корзину",
"Markdown Syntax": "Markdown Синтаксис",
"Access level": "Уровень доступа",

View File

@ -94,6 +94,7 @@
"Moved to Trash": "已移到垃圾箱",
"My Workspaces": "我的工作区",
"New Page": "新建页面",
"Restart Install Client Update": "重启安装更新",
"New Workspace": "新建工作区",
"No item": "无项目",
"Non-Gmail": "不支持非Gmail邮箱",

View File

@ -97,6 +97,7 @@ __metadata:
react-dom: ^18.2.0
react-error-boundary: ^4.0.4
react-is: ^18.2.0
rxjs: ^7.8.1
serve: ^14.2.0
storybook: ^7.0.9
storybook-dark-mode: ^3.0.0
@ -145,6 +146,7 @@ __metadata:
electron: 24.2.0
electron-log: ^5.0.0-beta.23
electron-squirrel-startup: 1.0.0
electron-updater: ^5.3.0
electron-window-state: ^5.0.3
esbuild: ^0.17.18
fs-extra: ^11.1.1
@ -340,6 +342,7 @@ __metadata:
react-dom: ^18.2.0
react-is: ^18.2.0
redux: ^4.2.1
rxjs: ^7.8.1
swc-plugin-coverage-instrument: ^0.0.18
swr: ^2.1.5
typescript: ^5.0.4
@ -8721,7 +8724,7 @@ __metadata:
languageName: node
linkType: hard
"@types/semver@npm:^7.3.12, @types/semver@npm:^7.3.4":
"@types/semver@npm:^7.3.12, @types/semver@npm:^7.3.4, @types/semver@npm:^7.3.6":
version: 7.3.13
resolution: "@types/semver@npm:7.3.13"
checksum: 00c0724d54757c2f4bc60b5032fe91cda6410e48689633d5f35ece8a0a66445e3e57fa1d6e07eb780f792e82ac542948ec4d0b76eb3484297b79bd18b8cf1cb0
@ -10718,6 +10721,16 @@ __metadata:
languageName: node
linkType: hard
"builder-util-runtime@npm:9.1.1":
version: 9.1.1
resolution: "builder-util-runtime@npm:9.1.1"
dependencies:
debug: ^4.3.4
sax: ^1.2.4
checksum: 3458f9c8accad6e934c841cffa93f5d4b342c22b10b9c1a2eb3fd44ca96ea2c662b1048f9a075da9b8a4fada17206887b7e92ebdca331b1071520916e013e245
languageName: node
linkType: hard
"bundle-name@npm:^3.0.0":
version: 3.0.0
resolution: "bundle-name@npm:3.0.0"
@ -12818,6 +12831,23 @@ __metadata:
languageName: node
linkType: hard
"electron-updater@npm:^5.3.0":
version: 5.3.0
resolution: "electron-updater@npm:5.3.0"
dependencies:
"@types/semver": ^7.3.6
builder-util-runtime: 9.1.1
fs-extra: ^10.0.0
js-yaml: ^4.1.0
lazy-val: ^1.0.5
lodash.escaperegexp: ^4.1.2
lodash.isequal: ^4.5.0
semver: ^7.3.5
typed-emitter: ^2.1.0
checksum: 975381ffb0d9e17686f7f0b90739320922ca52d06ee548e89ceeb3b56bfc23180c20e7049e5c33ef789b228eb4c960c9886986e1332577866dca2437c315ed4e
languageName: node
linkType: hard
"electron-window-state@npm:^5.0.3":
version: 5.0.3
resolution: "electron-window-state@npm:5.0.3"
@ -17859,6 +17889,13 @@ __metadata:
languageName: node
linkType: hard
"lazy-val@npm:^1.0.5":
version: 1.0.5
resolution: "lazy-val@npm:1.0.5"
checksum: 31e12e0b118826dfae74f8f3ff8ebcddfe4200ff88d0d448db175c7265ee537e0ba55488d411728246337f3ed3c9ec68416f10889f632a2ce28fb7a970909fb5
languageName: node
linkType: hard
"leven@npm:^3.1.0":
version: 3.1.0
resolution: "leven@npm:3.1.0"
@ -18136,6 +18173,13 @@ __metadata:
languageName: node
linkType: hard
"lodash.escaperegexp@npm:^4.1.2":
version: 4.1.2
resolution: "lodash.escaperegexp@npm:4.1.2"
checksum: 6d99452b1cfd6073175a9b741a9b09ece159eac463f86f02ea3bee2e2092923fce812c8d2bf446309cc52d1d61bf9af51c8118b0d7421388e6cead7bd3798f0f
languageName: node
linkType: hard
"lodash.flattendeep@npm:^4.4.0":
version: 4.4.0
resolution: "lodash.flattendeep@npm:4.4.0"
@ -22040,6 +22084,15 @@ __metadata:
languageName: node
linkType: hard
"rxjs@npm:*, rxjs@npm:^7.5.5, rxjs@npm:^7.8.0, rxjs@npm:^7.8.1":
version: 7.8.1
resolution: "rxjs@npm:7.8.1"
dependencies:
tslib: ^2.1.0
checksum: de4b53db1063e618ec2eca0f7965d9137cabe98cf6be9272efe6c86b47c17b987383df8574861bcced18ebd590764125a901d5506082be84a8b8e364bf05f119
languageName: node
linkType: hard
"rxjs@npm:^6.6.3":
version: 6.6.7
resolution: "rxjs@npm:6.6.7"
@ -22049,15 +22102,6 @@ __metadata:
languageName: node
linkType: hard
"rxjs@npm:^7.5.5, rxjs@npm:^7.8.0, rxjs@npm:^7.8.1":
version: 7.8.1
resolution: "rxjs@npm:7.8.1"
dependencies:
tslib: ^2.1.0
checksum: de4b53db1063e618ec2eca0f7965d9137cabe98cf6be9272efe6c86b47c17b987383df8574861bcced18ebd590764125a901d5506082be84a8b8e364bf05f119
languageName: node
linkType: hard
"safe-buffer@npm:5.1.1":
version: 5.1.1
resolution: "safe-buffer@npm:5.1.1"
@ -22097,6 +22141,13 @@ __metadata:
languageName: node
linkType: hard
"sax@npm:^1.2.4":
version: 1.2.4
resolution: "sax@npm:1.2.4"
checksum: d3df7d32b897a2c2f28e941f732c71ba90e27c24f62ee918bd4d9a8cfb3553f2f81e5493c7f0be94a11c1911b643a9108f231dd6f60df3fa9586b5d2e3e9e1fe
languageName: node
linkType: hard
"scheduler@npm:^0.23.0":
version: 0.23.0
resolution: "scheduler@npm:0.23.0"
@ -24011,6 +24062,18 @@ __metadata:
languageName: node
linkType: hard
"typed-emitter@npm:^2.1.0":
version: 2.1.0
resolution: "typed-emitter@npm:2.1.0"
dependencies:
rxjs: "*"
dependenciesMeta:
rxjs:
optional: true
checksum: 95821a9e05784b972cc9d152891fd12a56cb4b1a7c57e768c02bea6a8984da7aff8f19404a7b69eea11fae2a3b6c0c510a4c510f575f50162c759ae9059f2520
languageName: node
linkType: hard
"typedarray-to-buffer@npm:^3.1.5":
version: 3.1.5
resolution: "typedarray-to-buffer@npm:3.1.5"