Skip to content

Commit

Permalink
Finish updater
Browse files Browse the repository at this point in the history
  • Loading branch information
abrenneke committed Oct 18, 2023
1 parent 1cf5d03 commit 4299338
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 11 deletions.
63 changes: 60 additions & 3 deletions packages/app/src/components/SettingsModal.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { type FC, useState } from 'react';
import { atom, useRecoilState } from 'recoil';
import { atom, useRecoilState, useRecoilValue } from 'recoil';
import {
defaultExecutorState,
executorOptions,
previousDataPerNodeToKeepState,
recordExecutionsState,
settingsState,
skippedMaxVersionState,
themeState,
themes,
} from '../state/settings.js';
Expand All @@ -23,6 +24,7 @@ import CrossIcon from '@atlaskit/icon/glyph/cross';
import { css } from '@emotion/react';
import Toggle from '@atlaskit/toggle';
import { KeyValuePairs } from './editors/KeyValuePairEditor';
import { useCheckForUpdate } from '../hooks/useCheckForUpdate';

interface SettingsModalProps {}

Expand All @@ -45,7 +47,7 @@ const modalBody = css`
}
`;

type Pages = 'general' | 'openai' | 'plugins';
type Pages = 'general' | 'openai' | 'plugins' | 'updates';

const buttonsContainer = css`
> button span {
Expand All @@ -63,7 +65,7 @@ export const SettingsModal: FC<SettingsModalProps> = () => {
return (
<ModalTransition>
{isOpen && (
<Modal onClose={closeModal} width="xlarge">
<Modal onClose={closeModal} width="80%">
<ModalHeader>
<ModalTitle>Settings</ModalTitle>
<Button appearance="link" onClick={() => setIsOpen(false)}>
Expand All @@ -85,6 +87,9 @@ export const SettingsModal: FC<SettingsModalProps> = () => {
<ButtonItem isSelected={page === 'plugins'} onClick={() => setPage('plugins')}>
Plugins
</ButtonItem>
<ButtonItem isSelected={page === 'updates'} onClick={() => setPage('updates')}>
Updates
</ButtonItem>
</div>
</NavigationContent>
</SideNavigation>
Expand All @@ -94,6 +99,7 @@ export const SettingsModal: FC<SettingsModalProps> = () => {
.with('general', () => <GeneralSettingsPage />)
.with('openai', () => <OpenAiSettingsPage />)
.with('plugins', () => <PluginsSettingsPage />)
.with('updates', () => <UpdatesSettingsPage />)
.exhaustive()}
</main>
</div>
Expand Down Expand Up @@ -383,3 +389,54 @@ export const PluginsSettingsPage: FC = () => {
</div>
);
};

export const UpdatesSettingsPage: FC = () => {
const checkForUpdates = useCheckForUpdate({ notifyNoUpdates: true, force: true });

const skippedMaxVersion = useRecoilValue(skippedMaxVersionState);

return (
<div css={fields}>
<Field name="check-for-updates">
{() => (
<>
<Label htmlFor="check-for-updates" testId="check-for-updates">
Check for updates on startup
</Label>
<div className="toggle-field">
<Toggle
id="check-for-updates"
isChecked={true}
onChange={(e) => {
// TODO
}}
/>
</div>
<HelperMessage>Automatically check for updates on startup</HelperMessage>
</>
)}
</Field>
<Field name="check-for-updates-now">
{() => (
<>
<Button appearance="primary" onClick={() => checkForUpdates()}>
Check for updates now
</Button>
</>
)}
</Field>
{skippedMaxVersion && (
<Field name="skipped-update-version">
{() => (
<>
<Label htmlFor="skipped-update-version" testId="skipped-update-version">
Skipped update version
</Label>
<div>You have skipped version {skippedMaxVersion}. You may update by clicking the button above.</div>
</>
)}
</Field>
)}
</div>
);
};
8 changes: 6 additions & 2 deletions packages/app/src/components/UpdateModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useState, type FC, useEffect } from 'react';

import Modal, { ModalTransition, ModalBody, ModalFooter, ModalHeader, ModalTitle } from '@atlaskit/modal-dialog';
import { useRecoilState, useSetRecoilState } from 'recoil';
import { updateModalOpenState, updateStatusState } from '../state/settings';
import { skippedMaxVersionState, updateModalOpenState, updateStatusState } from '../state/settings';
import Button from '@atlaskit/button';
import useAsyncEffect from 'use-async-effect';
import { checkUpdate, installUpdate, onUpdaterEvent } from '@tauri-apps/api/updater';
Expand All @@ -26,6 +26,7 @@ export const UpdateModal: FC = () => {
const setModalOpen = useSetRecoilState(updateModalOpenState);
const [isUpdating, setIsUpdating] = useState(false);
const [updateStatus, setUpdateStatus] = useRecoilState(updateStatusState);
const setSkippedMaxVersion = useSetRecoilState(skippedMaxVersionState);

const [currentVersion, setCurrentVersion] = useState('');
const [latestVersion, setLatestVersion] = useState('');
Expand Down Expand Up @@ -64,7 +65,10 @@ export const UpdateModal: FC = () => {
}
}, [updateStatus]);

const skipUpdate = () => {};
const skipUpdate = () => {
setSkippedMaxVersion(latestVersion);
handleModalClose();
};

const canRender = currentVersion && latestVersion && updateBody;

Expand Down
33 changes: 28 additions & 5 deletions packages/app/src/hooks/useCheckForUpdate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import useAsyncEffect from 'use-async-effect';
import { toast } from 'react-toastify';
import { css } from '@emotion/react';
import { isInTauri } from '../utils/tauri';
import { useSetRecoilState } from 'recoil';
import { updateModalOpenState } from '../state/settings';
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil';
import { checkForUpdatesState, skippedMaxVersionState, updateModalOpenState } from '../state/settings';
import { gt, lt, lte } from 'semver';
import { getVersion } from '@tauri-apps/api/app';

const toastStyle = css`
display: flex;
Expand Down Expand Up @@ -38,13 +40,32 @@ const toastStyle = css`
}
`;

export function useCheckForUpdate() {
export function useCheckForUpdate({
notifyNoUpdates = false,
force = false,
}: { notifyNoUpdates?: boolean; force?: boolean } = {}) {
const setUpdateModalOpen = useSetRecoilState(updateModalOpenState);
const checkForUpdates = useRecoilValue(checkForUpdatesState);
const [skippedMaxVersion, setSkippedMaxVersion] = useRecoilState(skippedMaxVersionState);

return async () => {
if (!checkForUpdates) {
return;
}

const { shouldUpdate, manifest } = await checkUpdate();

if (shouldUpdate) {
if (!manifest) {
return;
}

const shouldSkip = skippedMaxVersion == null ? false : lte(manifest.version, skippedMaxVersion);

if (force) {
setSkippedMaxVersion(undefined);
}

if (shouldUpdate && (force || !shouldSkip)) {
toast.success(
({ closeToast }) => (
<div css={toastStyle}>
Expand All @@ -53,7 +74,7 @@ export function useCheckForUpdate() {
<button className="primary" onClick={() => setUpdateModalOpen(true)}>
Install
</button>
<button onClick={() => installUpdate()}>Skip</button>
<button onClick={() => setSkippedMaxVersion(manifest?.version)}>Skip</button>
<button onClick={() => closeToast?.()}>Not Now</button>
</div>
</div>
Expand All @@ -63,6 +84,8 @@ export function useCheckForUpdate() {
closeButton: false,
},
);
} else if (notifyNoUpdates) {
toast.info('Rivet is up to date!');
}
};
}
8 changes: 7 additions & 1 deletion packages/app/src/state/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,13 @@ export const previousDataPerNodeToKeepState = atom<number>({
effects_UNSTABLE: [persistAtom],
});

export const skippedMaxVersion = atom<string | undefined>({
export const checkForUpdatesState = atom<boolean>({
key: 'checkForUpdates',
default: true,
effects_UNSTABLE: [persistAtom],
});

export const skippedMaxVersionState = atom<string | undefined>({
key: 'skippedMaxVersion',
default: undefined,
effects_UNSTABLE: [persistAtom],
Expand Down

0 comments on commit 4299338

Please sign in to comment.