mirror of
https://github.com/standardnotes/app.git
synced 2026-01-16 23:01:30 +00:00
feat: implement UI for logging out (#638)
* feat: implement UI for logging out * feat: use old style dialogs for logout confirmation * feat: implement manage sessions * feat: implement session logout success dialog * feat: use snjs alert for revoking sessions confirmation * fix: make OtherSessionsLogout easier to read
This commit is contained in:
parent
a9610fdbc6
commit
77525a56cd
19 changed files with 342 additions and 70 deletions
|
|
@ -2,19 +2,22 @@ import { FunctionComponent } from 'preact';
|
|||
|
||||
const baseClass = `rounded px-4 py-1.75 font-bold text-sm fit-content`;
|
||||
|
||||
const normalClass = `${baseClass} bg-default color-text border-solid border-gray-300 border-1 \
|
||||
focus:bg-contrast hover:bg-contrast`;
|
||||
const primaryClass = `${baseClass} no-border bg-info color-info-contrast hover:brightness-130 \
|
||||
focus:brightness-130`;
|
||||
type ButtonType = 'normal' | 'primary' | 'danger';
|
||||
|
||||
const buttonClasses: { [type in ButtonType]: string } = {
|
||||
normal: `${baseClass} bg-default color-text border-solid border-gray-300 border-1 focus:bg-contrast hover:bg-contrast`,
|
||||
primary: `${baseClass} no-border bg-info color-info-contrast hover:brightness-130 focus:brightness-130`,
|
||||
danger: `${baseClass} bg-default color-danger border-solid border-gray-300 border-1 focus:bg-contrast hover:bg-contrast`,
|
||||
};
|
||||
|
||||
export const Button: FunctionComponent<{
|
||||
className?: string;
|
||||
type: 'normal' | 'primary';
|
||||
type: ButtonType;
|
||||
label: string;
|
||||
onClick: () => void;
|
||||
disabled?: boolean;
|
||||
}> = ({ type, label, className = '', onClick, disabled = false }) => {
|
||||
const buttonClass = type === 'primary' ? primaryClass : normalClass;
|
||||
const buttonClass = buttonClasses[type];
|
||||
const cursorClass = disabled ? 'cursor-default' : 'cursor-pointer';
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ const ConfirmSignoutModal = observer(({ application, appState }: Props) => {
|
|||
const [deleteLocalBackups, setDeleteLocalBackups] = useState(false);
|
||||
|
||||
const cancelRef = useRef<HTMLButtonElement>();
|
||||
function close() {
|
||||
function closeDialog() {
|
||||
appState.accountMenu.setSigningOut(false);
|
||||
}
|
||||
|
||||
|
|
@ -37,7 +37,7 @@ const ConfirmSignoutModal = observer(({ application, appState }: Props) => {
|
|||
}, [appState.accountMenu.signingOut, application.bridge]);
|
||||
|
||||
return (
|
||||
<AlertDialog onDismiss={close} leastDestructiveRef={cancelRef}>
|
||||
<AlertDialog onDismiss={closeDialog} leastDestructiveRef={cancelRef}>
|
||||
<div className="sk-modal-content">
|
||||
<div className="sn-component">
|
||||
<div className="sk-panel">
|
||||
|
|
@ -83,7 +83,7 @@ const ConfirmSignoutModal = observer(({ application, appState }: Props) => {
|
|||
<button
|
||||
className="sn-button small neutral"
|
||||
ref={cancelRef}
|
||||
onClick={close}
|
||||
onClick={closeDialog}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
|
|
@ -95,7 +95,7 @@ const ConfirmSignoutModal = observer(({ application, appState }: Props) => {
|
|||
} else {
|
||||
application.signOut();
|
||||
}
|
||||
close();
|
||||
closeDialog();
|
||||
}}
|
||||
>
|
||||
{application.hasAccount()
|
||||
|
|
|
|||
35
app/assets/javascripts/components/ConfirmationDialog.tsx
Normal file
35
app/assets/javascripts/components/ConfirmationDialog.tsx
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import { ComponentChildren, FunctionComponent } from 'preact';
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogDescription,
|
||||
AlertDialogLabel,
|
||||
} from '@reach/alert-dialog';
|
||||
import { useRef } from 'preact/hooks';
|
||||
|
||||
export const ConfirmationDialog: FunctionComponent<{
|
||||
title: string | ComponentChildren;
|
||||
}> = ({ title, children }) => {
|
||||
const ldRef = useRef<HTMLButtonElement>();
|
||||
|
||||
return (
|
||||
<AlertDialog leastDestructiveRef={ldRef}>
|
||||
{/* sn-component is focusable by default, but doesn't stretch to child width
|
||||
resulting in a badly focused dialog. Utility classes are not available
|
||||
at the sn-component level, only below it. tabIndex -1 disables focus
|
||||
and enables it on the child component */}
|
||||
<div tabIndex={-1} className="sn-component">
|
||||
<div
|
||||
tabIndex={0}
|
||||
className="max-w-89 bg-default rounded shadow-overlay focus:padded-ring-info px-9 py-9 flex flex-col items-center"
|
||||
>
|
||||
<AlertDialogLabel>{title}</AlertDialogLabel>
|
||||
<div className="min-h-2" />
|
||||
|
||||
<AlertDialogDescription className="flex flex-col items-center">
|
||||
{children}
|
||||
</AlertDialogDescription>
|
||||
</div>
|
||||
</div>
|
||||
</AlertDialog>
|
||||
);
|
||||
};
|
||||
80
app/assets/javascripts/components/OtherSessionsLogout.tsx
Normal file
80
app/assets/javascripts/components/OtherSessionsLogout.tsx
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
import { useRef, useState } from 'preact/hooks';
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogDescription,
|
||||
AlertDialogLabel,
|
||||
} from '@reach/alert-dialog';
|
||||
import { WebApplication } from '@/ui_models/application';
|
||||
import { AppState } from '@/ui_models/app_state';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { FunctionComponent } from 'preact';
|
||||
|
||||
type Props = {
|
||||
application: WebApplication;
|
||||
appState: AppState;
|
||||
};
|
||||
|
||||
export const OtherSessionsLogoutContainer = observer((props: Props) => {
|
||||
if (!props.appState.accountMenu.otherSessionsLogOut) {
|
||||
return null;
|
||||
}
|
||||
return <ConfirmOtherSessionsLogout {...props} />;
|
||||
});
|
||||
|
||||
const ConfirmOtherSessionsLogout = observer(
|
||||
({ application, appState }: Props) => {
|
||||
|
||||
const cancelRef = useRef<HTMLButtonElement>();
|
||||
function closeDialog() {
|
||||
appState.accountMenu.setOtherSessionsLogout(false);
|
||||
}
|
||||
|
||||
return (
|
||||
<AlertDialog onDismiss={closeDialog} leastDestructiveRef={cancelRef}>
|
||||
<div className="sk-modal-content">
|
||||
<div className="sn-component">
|
||||
<div className="sk-panel">
|
||||
<div className="sk-panel-content">
|
||||
<div className="sk-panel-section">
|
||||
<AlertDialogLabel className="sk-h3 sk-panel-section-title capitalize">
|
||||
End all other sessions?
|
||||
</AlertDialogLabel>
|
||||
<AlertDialogDescription className="sk-panel-row">
|
||||
<p className="color-foreground">
|
||||
This action will sign out all other devices signed into your account,
|
||||
and remove your data from those devices when they next regain connection
|
||||
to the internet. You may sign back in on those devices at any time.
|
||||
</p>
|
||||
</AlertDialogDescription>
|
||||
<div className="flex my-1 mt-4">
|
||||
<button
|
||||
className="sn-button small neutral"
|
||||
ref={cancelRef}
|
||||
onClick={closeDialog}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
className="sn-button small danger ml-2"
|
||||
onClick={() => {
|
||||
application.revokeAllOtherSessions();
|
||||
closeDialog();
|
||||
application.alertService.alert(
|
||||
"You have successfully revoked your sessions from other devices.",
|
||||
undefined,
|
||||
"Finish"
|
||||
);
|
||||
}}
|
||||
>
|
||||
End Sessions
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</AlertDialog>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
|
@ -26,12 +26,12 @@ type Session = RemoteSession & {
|
|||
function useSessions(
|
||||
application: SNApplication
|
||||
): [
|
||||
Session[],
|
||||
() => void,
|
||||
boolean,
|
||||
(uuid: UuidString) => Promise<void>,
|
||||
string
|
||||
] {
|
||||
Session[],
|
||||
() => void,
|
||||
boolean,
|
||||
(uuid: UuidString) => Promise<void>,
|
||||
string
|
||||
] {
|
||||
const [sessions, setSessions] = useState<Session[]>([]);
|
||||
const [lastRefreshDate, setLastRefreshDate] = useState(Date.now());
|
||||
const [refreshing, setRefreshing] = useState(true);
|
||||
|
|
@ -240,7 +240,7 @@ const SessionsModal: FunctionComponent<{
|
|||
);
|
||||
};
|
||||
|
||||
const Sessions: FunctionComponent<{
|
||||
export const Sessions: FunctionComponent<{
|
||||
appState: AppState;
|
||||
application: WebApplication;
|
||||
}> = observer(({ appState, application }) => {
|
||||
|
|
|
|||
|
|
@ -7,9 +7,11 @@ import { PreferencesMenu } from './PreferencesMenu';
|
|||
import { PreferencesMenuView } from './PreferencesMenuView';
|
||||
import { WebApplication } from '@/ui_models/application';
|
||||
import { MfaProps } from './panes/two-factor-auth/MfaProps';
|
||||
import { AppState } from '@/ui_models/app_state';
|
||||
|
||||
interface PreferencesProps extends MfaProps {
|
||||
application: WebApplication;
|
||||
appState: AppState;
|
||||
closePreferences: () => void;
|
||||
}
|
||||
|
||||
|
|
@ -20,7 +22,12 @@ const PaneSelector: FunctionComponent<
|
|||
case 'general':
|
||||
return null;
|
||||
case 'account':
|
||||
return <AccountPreferences application={props.application} />;
|
||||
return (
|
||||
<AccountPreferences
|
||||
application={props.application}
|
||||
appState={props.appState}
|
||||
/>
|
||||
);
|
||||
case 'appearance':
|
||||
return null;
|
||||
case 'security':
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@ import { FunctionComponent } from 'preact';
|
|||
import { observer } from 'mobx-react-lite';
|
||||
import { WebApplication } from '@/ui_models/application';
|
||||
import { PreferencesView } from './PreferencesView';
|
||||
import { AppState } from '@/ui_models/app_state';
|
||||
|
||||
export interface PreferencesViewWrapperProps {
|
||||
appState: { preferences: { isOpen: boolean; closePreferences: () => void } };
|
||||
appState: AppState;
|
||||
application: WebApplication;
|
||||
}
|
||||
|
||||
|
|
@ -18,6 +19,7 @@ export const PreferencesViewWrapper: FunctionComponent<PreferencesViewWrapperPro
|
|||
<PreferencesView
|
||||
closePreferences={() => appState.preferences.closePreferences()}
|
||||
application={application}
|
||||
appState={appState}
|
||||
mfaProvider={application}
|
||||
userProvider={application}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
import { FunctionComponent } from 'preact';
|
||||
import { HorizontalSeparator } from '@/components/shared/HorizontalSeparator';
|
||||
|
||||
const HorizontalLine: FunctionComponent<{ index: number; length: number }> = ({
|
||||
index,
|
||||
length,
|
||||
}) => (index < length - 1 ? <HorizontalSeparator classes="my-4" /> : null);
|
||||
|
||||
export const PreferencesGroup: FunctionComponent = ({ children }) => (
|
||||
<div className="bg-default border-1 border-solid rounded border-gray-300 px-6 py-6 flex flex-col">
|
||||
{Array.isArray(children)
|
||||
? children
|
||||
.filter(
|
||||
(child) => child != undefined && child !== '' && child !== false
|
||||
)
|
||||
.map((child, i, arr) => (
|
||||
<>
|
||||
{child}
|
||||
<HorizontalLine index={i} length={arr.length} />
|
||||
</>
|
||||
))
|
||||
: children}
|
||||
</div>
|
||||
);
|
||||
|
|
@ -1,43 +1,18 @@
|
|||
import { FunctionComponent } from 'preact';
|
||||
import { HorizontalSeparator } from '@/components/shared/HorizontalSeparator';
|
||||
|
||||
const HorizontalLine: FunctionComponent<{ index: number; length: number }> = ({
|
||||
index,
|
||||
length,
|
||||
}) => (index < length - 1 ? <HorizontalSeparator classes="my-4" /> : null);
|
||||
|
||||
export const PreferencesSegment: FunctionComponent = ({ children }) => (
|
||||
<div className="flex flex-col">{children}</div>
|
||||
);
|
||||
|
||||
export const PreferencesGroup: FunctionComponent = ({ children }) => (
|
||||
<div className="bg-default border-1 border-solid rounded border-gray-300 px-6 py-6 flex flex-col">
|
||||
{Array.isArray(children)
|
||||
? children
|
||||
.filter(
|
||||
(child) => child != undefined && child !== '' && child !== false
|
||||
)
|
||||
.map((child, i, arr) => (
|
||||
<>
|
||||
{child}
|
||||
<HorizontalLine index={i} length={arr.length} />
|
||||
</>
|
||||
))
|
||||
: children}
|
||||
</div>
|
||||
);
|
||||
|
||||
export const PreferencesPane: FunctionComponent = ({ children }) => (
|
||||
<div className="color-black flex-grow flex flex-row overflow-y-auto min-h-0">
|
||||
<div className="flex-grow flex flex-col py-6 items-center">
|
||||
<div className="w-125 max-w-125 flex flex-col">
|
||||
{children != undefined && Array.isArray(children)
|
||||
? children.map((child, idx, arr) => (
|
||||
<>
|
||||
{child}
|
||||
{idx < arr.length - 1 ? <div className="min-h-3" /> : undefined}
|
||||
</>
|
||||
))
|
||||
? children
|
||||
.filter((child) => child != undefined)
|
||||
.map((child) => (
|
||||
<>
|
||||
{child}
|
||||
<div className="min-h-3" />
|
||||
</>
|
||||
))
|
||||
: children}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
import { FunctionComponent } from 'preact';
|
||||
|
||||
export const PreferencesSegment: FunctionComponent = ({ children }) => (
|
||||
<div className="flex flex-col">{children}</div>
|
||||
);
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
export * from './Content';
|
||||
export * from './MenuItem';
|
||||
export * from './PreferencesPane';
|
||||
export * from './PreferencesGroup';
|
||||
export * from './PreferencesSegment';
|
||||
|
|
|
|||
|
|
@ -1,17 +1,28 @@
|
|||
import { Sync, SubscriptionWrapper, Credentials } from '@/preferences/panes/account';
|
||||
import {
|
||||
Sync,
|
||||
SubscriptionWrapper,
|
||||
Credentials,
|
||||
LogOutWrapper,
|
||||
} from '@/preferences/panes/account';
|
||||
import { PreferencesPane } from '@/preferences/components';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { WebApplication } from '@/ui_models/application';
|
||||
import { AppState } from '@/ui_models/app_state';
|
||||
|
||||
type Props = {
|
||||
application: WebApplication;
|
||||
}
|
||||
export const AccountPreferences = observer(({application}: Props) => {
|
||||
return (
|
||||
<PreferencesPane>
|
||||
<Credentials application={application} />
|
||||
<Sync application={application} />
|
||||
<SubscriptionWrapper application={application} />
|
||||
</PreferencesPane>
|
||||
);
|
||||
});
|
||||
appState: AppState;
|
||||
};
|
||||
|
||||
export const AccountPreferences = observer(
|
||||
({ application, appState }: Props) => {
|
||||
return (
|
||||
<PreferencesPane>
|
||||
<Credentials application={application} />
|
||||
<Sync application={application} />
|
||||
<SubscriptionWrapper application={application} />
|
||||
<LogOutWrapper application={application} appState={appState} />
|
||||
</PreferencesPane>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
|
|
|||
103
app/assets/javascripts/preferences/panes/account/LogOutView.tsx
Normal file
103
app/assets/javascripts/preferences/panes/account/LogOutView.tsx
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
import { Button } from '@/components/Button';
|
||||
import { ConfirmSignoutContainer } from '@/components/ConfirmSignoutModal';
|
||||
import { OtherSessionsLogoutContainer } from '@/components/OtherSessionsLogout';
|
||||
import {
|
||||
PreferencesGroup,
|
||||
PreferencesSegment,
|
||||
Subtitle,
|
||||
Text,
|
||||
Title,
|
||||
} from '@/preferences/components';
|
||||
import { WebApplication } from '@/ui_models/application';
|
||||
import { AppState } from '@/ui_models/app_state';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { FunctionComponent } from 'preact';
|
||||
|
||||
const LogOutView: FunctionComponent<{
|
||||
application: WebApplication;
|
||||
appState: AppState;
|
||||
}> = observer(({ application, appState }) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<PreferencesGroup>
|
||||
<PreferencesSegment>
|
||||
<Title>Log out</Title>
|
||||
<div className="min-h-2" />
|
||||
<Subtitle>Other devices</Subtitle>
|
||||
<Text>Want to log out on all devices except this one?</Text>
|
||||
<div className="min-h-3" />
|
||||
<div className="flex flex-row">
|
||||
<Button
|
||||
className="mr-3"
|
||||
type="normal"
|
||||
label="Log out other sessions"
|
||||
onClick={() => {
|
||||
appState.accountMenu.setOtherSessionsLogout(true);
|
||||
}}
|
||||
/>
|
||||
<Button type="normal" label="Manage sessions" onClick={() => appState.openSessionsModal()} />
|
||||
</div>
|
||||
</PreferencesSegment>
|
||||
<PreferencesSegment>
|
||||
<Subtitle>This device</Subtitle>
|
||||
<Text>This will delete all local items and preferences.</Text>
|
||||
<div className="min-h-3" />
|
||||
<Button
|
||||
type="danger"
|
||||
label="Log out and clear local data"
|
||||
onClick={() => {
|
||||
appState.accountMenu.setSigningOut(true);
|
||||
}}
|
||||
/>
|
||||
</PreferencesSegment>
|
||||
</PreferencesGroup>
|
||||
<OtherSessionsLogoutContainer appState={appState} application={application} />
|
||||
|
||||
<ConfirmSignoutContainer
|
||||
appState={appState}
|
||||
application={application}
|
||||
/>
|
||||
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
const ClearSessionDataView: FunctionComponent<{
|
||||
application: WebApplication;
|
||||
appState: AppState;
|
||||
}> = observer(({ application, appState }) => {
|
||||
return (
|
||||
<>
|
||||
<PreferencesGroup>
|
||||
<PreferencesSegment>
|
||||
<Title>Clear Session Data</Title>
|
||||
<div className="min-h-2" />
|
||||
<Text>This will delete all local items and preferences.</Text>
|
||||
<div className="min-h-3" />
|
||||
<Button
|
||||
type="danger"
|
||||
label="Clear Session Data"
|
||||
onClick={() => {
|
||||
appState.accountMenu.setSigningOut(true);
|
||||
}}
|
||||
/>
|
||||
</PreferencesSegment>
|
||||
</PreferencesGroup>
|
||||
|
||||
<ConfirmSignoutContainer
|
||||
appState={appState}
|
||||
application={application}
|
||||
/>
|
||||
|
||||
</>);
|
||||
});
|
||||
|
||||
export const LogOutWrapper: FunctionComponent<{
|
||||
application: WebApplication;
|
||||
appState: AppState;
|
||||
}> = observer(({ application, appState }) => {
|
||||
const isLoggedIn = application.getUser() != undefined;
|
||||
if (!isLoggedIn) return <ClearSessionDataView appState={appState} application={application} />;
|
||||
return <LogOutView appState={appState} application={application} />;
|
||||
});
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
export { SubscriptionWrapper } from './subscription/SubscriptionWrapper';
|
||||
export { Sync } from './Sync';
|
||||
export { Credentials } from './Credentials';
|
||||
export { LogOutWrapper } from './LogOutView';
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { SNItem } from '@standardnotes/snjs/dist/@types/models/core/item';
|
|||
export class AccountMenuState {
|
||||
show = false;
|
||||
signingOut = false;
|
||||
otherSessionsLogOut = false;
|
||||
server: string | undefined = undefined;
|
||||
notesAndTags: SNItem[] = [];
|
||||
isEncryptionEnabled = false;
|
||||
|
|
@ -21,6 +22,7 @@ export class AccountMenuState {
|
|||
makeObservable(this, {
|
||||
show: observable,
|
||||
signingOut: observable,
|
||||
otherSessionsLogOut: observable,
|
||||
server: observable,
|
||||
notesAndTags: observable,
|
||||
isEncryptionEnabled: observable,
|
||||
|
|
@ -35,6 +37,7 @@ export class AccountMenuState {
|
|||
setIsEncryptionEnabled: action,
|
||||
setEncryptionStatusString: action,
|
||||
setIsBackupEncrypted: action,
|
||||
setOtherSessionsLogout: action,
|
||||
|
||||
notesAndTagsCount: computed
|
||||
});
|
||||
|
|
@ -106,6 +109,10 @@ export class AccountMenuState {
|
|||
this.show = !this.show;
|
||||
};
|
||||
|
||||
setOtherSessionsLogout = (otherSessionsLogOut: boolean): void => {
|
||||
this.otherSessionsLogOut = otherSessionsLogOut;
|
||||
}
|
||||
|
||||
get notesAndTagsCount(): number {
|
||||
return this.notesAndTags.length;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -161,11 +161,11 @@ export class AppState {
|
|||
this.onVisibilityChange = undefined;
|
||||
}
|
||||
|
||||
openSessionsModal() {
|
||||
openSessionsModal(): void {
|
||||
this.isSessionsModalVisible = true;
|
||||
}
|
||||
|
||||
closeSessionsModal() {
|
||||
closeSessionsModal(): void {
|
||||
this.isSessionsModalVisible = false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -166,6 +166,10 @@
|
|||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.max-w-89 {
|
||||
max-width: 22.25rem;
|
||||
}
|
||||
|
||||
.w-92 {
|
||||
width: 23rem;
|
||||
}
|
||||
|
|
@ -206,6 +210,10 @@
|
|||
min-height: 0.75rem;
|
||||
}
|
||||
|
||||
.min-h-6 {
|
||||
min-height: 1.5rem;
|
||||
}
|
||||
|
||||
.border-danger {
|
||||
border-color: var(--sn-stylekit-danger-color);
|
||||
}
|
||||
|
|
@ -218,3 +226,12 @@
|
|||
padding-top: 0.5rem;
|
||||
}
|
||||
|
||||
.px-9 {
|
||||
padding-left: 2.25rem;
|
||||
padding-right: 2.25rem;
|
||||
}
|
||||
|
||||
.py-9 {
|
||||
padding-top: 2.25rem;
|
||||
padding-bottom: 2.25rem;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@
|
|||
"@reach/dialog": "^0.13.0",
|
||||
"@standardnotes/sncrypto-web": "1.5.2",
|
||||
"@standardnotes/features": "1.6.1",
|
||||
"@standardnotes/snjs": "2.14.5",
|
||||
"@standardnotes/snjs": "2.14.6",
|
||||
"mobx": "^6.3.2",
|
||||
"mobx-react-lite": "^3.2.0",
|
||||
"preact": "^10.5.12",
|
||||
|
|
|
|||
|
|
@ -2069,10 +2069,10 @@
|
|||
"@standardnotes/sncrypto-common" "^1.5.2"
|
||||
libsodium-wrappers "^0.7.8"
|
||||
|
||||
"@standardnotes/snjs@2.14.5":
|
||||
version "2.14.5"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/snjs/-/snjs-2.14.5.tgz#1a48b71a4ae5dbdc863cdbbb468e8ebf2113f918"
|
||||
integrity sha512-PAjv4VgWs//pzG4aYdnQC+4bY8MmwBgkdbwEfCmWRVXv7o/Mfa4t1ds+FbeiyqoEhwCcdWg3E7RRWPqRH93lQQ==
|
||||
"@standardnotes/snjs@2.14.6":
|
||||
version "2.14.6"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/snjs/-/snjs-2.14.6.tgz#fb3f625ec6f22bbee543ccb6fc69e177311c1a4b"
|
||||
integrity sha512-/PfuyOv2u4Km29yQi2JXYYUteFmHmLYnbQhk96wYHbCwBiNmIyVdSp0VaA4XgVIuZq32QyhhTayjkexq5Huw/Q==
|
||||
dependencies:
|
||||
"@standardnotes/auth" "3.7.2"
|
||||
"@standardnotes/common" "1.1.0"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue