chore: prettier files

This commit is contained in:
Mo
2022-05-03 10:51:40 -05:00
parent f5a90060ea
commit 43d94fbcbf
127 changed files with 1365 additions and 2428 deletions

View File

@@ -1,8 +1,5 @@
import { FunctionalComponent } from 'preact'
import {
PreferencesGroup,
PreferencesSegment,
} from '@/Components/Preferences/PreferencesComponents'
import { PreferencesGroup, PreferencesSegment } from '@/Components/Preferences/PreferencesComponents'
import { OfflineSubscription } from '@/Components/Preferences/Panes/Account/OfflineSubscription'
import { WebApplication } from '@/UIModels/Application'
import { observer } from 'mobx-react-lite'
@@ -17,25 +14,23 @@ interface IProps {
extensionsLatestVersions: ExtensionsLatestVersions
}
export const Advanced: FunctionalComponent<IProps> = observer(
({ application, appState, extensionsLatestVersions }) => {
return (
<PreferencesGroup>
<PreferencesSegment>
<AccordionItem title={'Advanced Settings'}>
<div className="flex flex-row items-center">
<div className="flex-grow flex flex-col">
<OfflineSubscription application={application} appState={appState} />
<Extensions
className={'mt-3'}
application={application}
extensionsLatestVersions={extensionsLatestVersions}
/>
</div>
export const Advanced: FunctionalComponent<IProps> = observer(({ application, appState, extensionsLatestVersions }) => {
return (
<PreferencesGroup>
<PreferencesSegment>
<AccordionItem title={'Advanced Settings'}>
<div className="flex flex-row items-center">
<div className="flex-grow flex flex-col">
<OfflineSubscription application={application} appState={appState} />
<Extensions
className={'mt-3'}
application={application}
extensionsLatestVersions={extensionsLatestVersions}
/>
</div>
</AccordionItem>
</PreferencesSegment>
</PreferencesGroup>
)
},
)
</div>
</AccordionItem>
</PreferencesSegment>
</PreferencesGroup>
)
})

View File

@@ -1,11 +1,6 @@
import { AccountMenuPane } from '@/Components/AccountMenu'
import { Button } from '@/Components/Button/Button'
import {
PreferencesGroup,
PreferencesSegment,
Text,
Title,
} from '@/Components/Preferences/PreferencesComponents'
import { PreferencesGroup, PreferencesSegment, Text, Title } from '@/Components/Preferences/PreferencesComponents'
import { WebApplication } from '@/UIModels/Application'
import { AppState } from '@/UIModels/AppState'
import { observer } from 'mobx-react-lite'
@@ -35,21 +30,12 @@ export const Authentication: FunctionComponent<{
<AccountIllustration className="mb-3" />
<Title>You're not signed in</Title>
<Text className="text-center mb-3">
Sign in to sync your notes and preferences across all your devices and enable end-to-end
encryption.
Sign in to sync your notes and preferences across all your devices and enable end-to-end encryption.
</Text>
<Button
variant="primary"
label="Create free account"
onClick={clickRegister}
className="mb-3"
/>
<Button variant="primary" label="Create free account" onClick={clickRegister} className="mb-3" />
<div className="text-input">
Already have an account?{' '}
<button
className="border-0 p-0 bg-default color-info underline cursor-pointer"
onClick={clickSignIn}
>
<button className="border-0 p-0 bg-default color-info underline cursor-pointer" onClick={clickSignIn}>
Sign in
</button>
</div>

View File

@@ -10,10 +10,7 @@ const labelClassName = 'block mb-1'
const inputClassName = 'sk-input contrast'
export const ChangeEmailForm: FunctionalComponent<Props> = ({
setNewEmail,
setCurrentPassword,
}) => {
export const ChangeEmailForm: FunctionalComponent<Props> = ({ setNewEmail, setCurrentPassword }) => {
return (
<div className="w-full flex flex-col">
<div className="mt-2 mb-3">

View File

@@ -5,8 +5,8 @@ export const ChangeEmailSuccess: FunctionalComponent = () => {
<div>
<div className={'sk-label sk-bold info mt-2'}>Your email has been successfully changed.</div>
<p className={'sk-p'}>
Please ensure you are running the latest version of Standard Notes on all platforms to
ensure maximum compatibility.
Please ensure you are running the latest version of Standard Notes on all platforms to ensure maximum
compatibility.
</p>
</div>
)

View File

@@ -63,9 +63,7 @@ export const ChangeEmail: FunctionalComponent<Props> = ({ onCloseDialog, applica
const validateNewEmail = async () => {
if (!isEmailValid(newEmail)) {
applicationAlertService
.alert(
'The email you entered has an invalid format. Please review your input and try again.',
)
.alert('The email you entered has an invalid format. Please review your input and try again.')
.catch(console.error)
return false
@@ -95,9 +93,7 @@ export const ChangeEmail: FunctionalComponent<Props> = ({ onCloseDialog, applica
const dismiss = () => {
if (lockContinue) {
applicationAlertService
.alert('Cannot close window until pending tasks are complete.')
.catch(console.error)
applicationAlertService.alert('Cannot close window until pending tasks are complete.').catch(console.error)
} else {
onCloseDialog()
}
@@ -139,9 +135,7 @@ export const ChangeEmail: FunctionalComponent<Props> = ({ onCloseDialog, applica
const handleDialogClose = () => {
if (lockContinue) {
applicationAlertService
.alert('Cannot close window until pending tasks are complete.')
.catch(console.error)
applicationAlertService.alert('Cannot close window until pending tasks are complete.').catch(console.error)
} else {
onCloseDialog()
}
@@ -158,12 +152,7 @@ export const ChangeEmail: FunctionalComponent<Props> = ({ onCloseDialog, applica
{currentStep === Steps.FinishStep && <ChangeEmailSuccess />}
</ModalDialogDescription>
<ModalDialogButtons className="px-4.5">
<Button
className="min-w-20"
variant="primary"
label={submitButtonTitle}
onClick={handleSubmit}
/>
<Button className="min-w-20" variant="primary" label={submitButtonTitle} onClick={handleSubmit} />
</ModalDialogButtons>
</ModalDialog>
</div>

View File

@@ -30,10 +30,7 @@ export const Credentials: FunctionComponent<Props> = observer(({ application }:
const passwordCreatedOn = dateToLocalizedString(passwordCreatedAtTimestamp)
const presentPasswordWizard = useCallback(() => {
render(
<PasswordWizard application={application} />,
document.body.appendChild(document.createElement('div')),
)
render(<PasswordWizard application={application} />, document.body.appendChild(document.createElement('div')))
}, [application])
return (
@@ -57,17 +54,9 @@ export const Credentials: FunctionComponent<Props> = observer(({ application }:
<Text>
Current password was set on <span className="font-bold">{passwordCreatedOn}</span>
</Text>
<Button
className="min-w-20 mt-3"
variant="normal"
label="Change password"
onClick={presentPasswordWizard}
/>
<Button className="min-w-20 mt-3" variant="normal" label="Change password" onClick={presentPasswordWizard} />
{isChangeEmailDialogOpen && (
<ChangeEmail
onCloseDialog={() => setIsChangeEmailDialogOpen(false)}
application={application}
/>
<ChangeEmail onCloseDialog={() => setIsChangeEmailDialogOpen(false)} application={application} />
)}
</PreferencesSegment>
</PreferencesGroup>

View File

@@ -28,9 +28,7 @@ export const OfflineSubscription: FunctionalComponent<IProps> = observer(({ appl
}, [application])
const shouldShowOfflineSubscription = () => {
return (
!application.hasAccount() || application.isThirdPartyHostUsed() || hasUserPreviouslyStoredCode
)
return !application.hasAccount() || application.isThirdPartyHostUsed() || hasUserPreviouslyStoredCode
}
const handleSubscriptionCodeSubmit = async (event: Event) => {
@@ -98,8 +96,8 @@ export const OfflineSubscription: FunctionalComponent<IProps> = observer(({ appl
</div>
{(isSuccessfullyActivated || isSuccessfullyRemoved) && (
<div className={'mt-3 mb-3 info'}>
Your offline subscription code has been successfully{' '}
{isSuccessfullyActivated ? 'activated' : 'removed'}.
Your offline subscription code has been successfully {isSuccessfullyActivated ? 'activated' : 'removed'}
.
</div>
)}
{hasUserPreviouslyStoredCode && (

View File

@@ -33,11 +33,7 @@ const SignOutView: FunctionComponent<{
appState.accountMenu.setOtherSessionsSignOut(true)
}}
/>
<Button
variant="normal"
label="Manage sessions"
onClick={() => appState.openSessionsModal()}
/>
<Button variant="normal" label="Manage sessions" onClick={() => appState.openSessionsModal()} />
</div>
</PreferencesSegment>
<PreferencesSegment>

View File

@@ -12,8 +12,7 @@ export const NoSubscription: FunctionalComponent<{
const [purchaseFlowError, setPurchaseFlowError] = useState<string | undefined>(undefined)
const onPurchaseClick = async () => {
const errorMessage =
'There was an error when attempting to redirect you to the subscription page.'
const errorMessage = 'There was an error when attempting to redirect you to the subscription page.'
setIsLoadingPurchaseFlow(true)
try {
if (!(await loadPurchaseFlowUrl(application))) {
@@ -32,18 +31,9 @@ export const NoSubscription: FunctionalComponent<{
{isLoadingPurchaseFlow && <Text>Redirecting you to the subscription page...</Text>}
{purchaseFlowError && <Text className="color-danger">{purchaseFlowError}</Text>}
<div className="flex">
<LinkButton
className="min-w-20 mt-3 mr-3"
label="Learn More"
link={window.plansUrl as string}
/>
<LinkButton className="min-w-20 mt-3 mr-3" label="Learn More" link={window.plansUrl as string} />
{application.hasAccount() && (
<Button
className="min-w-20 mt-3"
variant="primary"
label="Subscribe"
onClick={onPurchaseClick}
/>
<Button className="min-w-20 mt-3" variant="primary" label="Subscribe" onClick={onPurchaseClick} />
)}
</div>
</>

View File

@@ -1,8 +1,4 @@
import {
PreferencesGroup,
PreferencesSegment,
Title,
} from '@/Components/Preferences/PreferencesComponents'
import { PreferencesGroup, PreferencesSegment, Title } from '@/Components/Preferences/PreferencesComponents'
import { WebApplication } from '@/UIModels/Application'
import { SubscriptionInformation } from './SubscriptionInformation'
import { NoSubscription } from './NoSubscription'
@@ -15,31 +11,26 @@ type Props = {
appState: AppState
}
export const Subscription: FunctionComponent<Props> = observer(
({ application, appState }: Props) => {
const subscriptionState = appState.subscription
const { userSubscription } = subscriptionState
export const Subscription: FunctionComponent<Props> = observer(({ application, appState }: Props) => {
const subscriptionState = appState.subscription
const { userSubscription } = subscriptionState
const now = new Date().getTime()
const now = new Date().getTime()
return (
<PreferencesGroup>
<PreferencesSegment>
<div className="flex flex-row items-center">
<div className="flex-grow flex flex-col">
<Title>Subscription</Title>
{userSubscription && userSubscription.endsAt > now ? (
<SubscriptionInformation
subscriptionState={subscriptionState}
application={application}
/>
) : (
<NoSubscription application={application} />
)}
</div>
return (
<PreferencesGroup>
<PreferencesSegment>
<div className="flex flex-row items-center">
<div className="flex-grow flex flex-col">
<Title>Subscription</Title>
{userSubscription && userSubscription.endsAt > now ? (
<SubscriptionInformation subscriptionState={subscriptionState} application={application} />
) : (
<NoSubscription application={application} />
)}
</div>
</PreferencesSegment>
</PreferencesGroup>
)
},
)
</div>
</PreferencesSegment>
</PreferencesGroup>
)
})

View File

@@ -10,49 +10,16 @@ type Props = {
application: WebApplication
}
const StatusText = observer(
({ subscriptionState }: { subscriptionState: Props['subscriptionState'] }) => {
const {
userSubscriptionName,
userSubscriptionExpirationDate,
isUserSubscriptionExpired,
isUserSubscriptionCanceled,
} = subscriptionState
const expirationDateString = userSubscriptionExpirationDate?.toLocaleString()
if (isUserSubscriptionCanceled) {
return (
<Text className="mt-1">
Your{' '}
<span className="font-bold">
Standard Notes{userSubscriptionName ? ' ' : ''}
{userSubscriptionName}
</span>{' '}
subscription has been canceled{' '}
{isUserSubscriptionExpired ? (
<span className="font-bold">and expired on {expirationDateString}</span>
) : (
<span className="font-bold">but will remain valid until {expirationDateString}</span>
)}
. You may resubscribe below if you wish.
</Text>
)
}
if (isUserSubscriptionExpired) {
return (
<Text className="mt-1">
Your{' '}
<span className="font-bold">
Standard Notes{userSubscriptionName ? ' ' : ''}
{userSubscriptionName}
</span>{' '}
subscription <span className="font-bold">expired on {expirationDateString}</span>. You may
resubscribe below if you wish.
</Text>
)
}
const StatusText = observer(({ subscriptionState }: { subscriptionState: Props['subscriptionState'] }) => {
const {
userSubscriptionName,
userSubscriptionExpirationDate,
isUserSubscriptionExpired,
isUserSubscriptionCanceled,
} = subscriptionState
const expirationDateString = userSubscriptionExpirationDate?.toLocaleString()
if (isUserSubscriptionCanceled) {
return (
<Text className="mt-1">
Your{' '}
@@ -60,11 +27,42 @@ const StatusText = observer(
Standard Notes{userSubscriptionName ? ' ' : ''}
{userSubscriptionName}
</span>{' '}
subscription will be <span className="font-bold">renewed on {expirationDateString}</span>.
subscription has been canceled{' '}
{isUserSubscriptionExpired ? (
<span className="font-bold">and expired on {expirationDateString}</span>
) : (
<span className="font-bold">but will remain valid until {expirationDateString}</span>
)}
. You may resubscribe below if you wish.
</Text>
)
},
)
}
if (isUserSubscriptionExpired) {
return (
<Text className="mt-1">
Your{' '}
<span className="font-bold">
Standard Notes{userSubscriptionName ? ' ' : ''}
{userSubscriptionName}
</span>{' '}
subscription <span className="font-bold">expired on {expirationDateString}</span>. You may resubscribe below if
you wish.
</Text>
)
}
return (
<Text className="mt-1">
Your{' '}
<span className="font-bold">
Standard Notes{userSubscriptionName ? ' ' : ''}
{userSubscriptionName}
</span>{' '}
subscription will be <span className="font-bold">renewed on {expirationDateString}</span>.
</Text>
)
})
export const SubscriptionInformation = observer(({ subscriptionState, application }: Props) => {
const manageSubscription = async () => {

View File

@@ -1,9 +1,4 @@
import {
PreferencesGroup,
PreferencesSegment,
Text,
Title,
} from '@/Components/Preferences/PreferencesComponents'
import { PreferencesGroup, PreferencesSegment, Text, Title } from '@/Components/Preferences/PreferencesComponents'
import { Button } from '@/Components/Button/Button'
import { SyncQueueStrategy, dateToLocalizedString } from '@standardnotes/snjs'
import { STRING_GENERIC_SYNC_ERROR } from '@/Strings'
@@ -22,9 +17,7 @@ export const formatLastSyncDate = (lastUpdatedDate: Date) => {
export const Sync: FunctionComponent<Props> = observer(({ application }: Props) => {
const [isSyncingInProgress, setIsSyncingInProgress] = useState(false)
const [lastSyncDate, setLastSyncDate] = useState(
formatLastSyncDate(application.sync.getLastSyncDate() as Date),
)
const [lastSyncDate, setLastSyncDate] = useState(formatLastSyncDate(application.sync.getLastSyncDate() as Date))
const doSynchronization = async () => {
setIsSyncingInProgress(true)

View File

@@ -3,14 +3,7 @@ import { usePremiumModal } from '@/Hooks/usePremiumModal'
import { HorizontalSeparator } from '@/Components/Shared/HorizontalSeparator'
import { Switch } from '@/Components/Switch'
import { WebApplication } from '@/UIModels/Application'
import {
ContentType,
FeatureIdentifier,
FeatureStatus,
PrefKey,
GetFeatures,
SNTheme,
} from '@standardnotes/snjs'
import { ContentType, FeatureIdentifier, FeatureStatus, PrefKey, GetFeatures, SNTheme } from '@standardnotes/snjs'
import { observer } from 'mobx-react-lite'
import { FunctionComponent } from 'preact'
import { useEffect, useState } from 'preact/hooks'
@@ -31,8 +24,7 @@ type Props = {
export const Appearance: FunctionComponent<Props> = observer(({ application }) => {
const premiumModal = usePremiumModal()
const isEntitledToMidnightTheme =
application.features.getFeatureStatus(FeatureIdentifier.MidnightTheme) ===
FeatureStatus.Entitled
application.features.getFeatureStatus(FeatureIdentifier.MidnightTheme) === FeatureStatus.Entitled
const [themeItems, setThemeItems] = useState<DropdownItem[]>([])
const [autoLightTheme, setAutoLightTheme] = useState<string>(
@@ -100,9 +92,7 @@ export const Appearance: FunctionComponent<Props> = observer(({ application }) =
if (item.icon === 'premium-feature') {
premiumModal.activate(`${item.label} theme`)
} else {
application
.setPreference(PrefKey.AutoLightThemeIdentifier, value as FeatureIdentifier)
.catch(console.error)
application.setPreference(PrefKey.AutoLightThemeIdentifier, value as FeatureIdentifier).catch(console.error)
setAutoLightTheme(value)
}
}
@@ -111,9 +101,7 @@ export const Appearance: FunctionComponent<Props> = observer(({ application }) =
if (item.icon === 'premium-feature') {
premiumModal.activate(`${item.label} theme`)
} else {
application
.setPreference(PrefKey.AutoDarkThemeIdentifier, value as FeatureIdentifier)
.catch(console.error)
application.setPreference(PrefKey.AutoDarkThemeIdentifier, value as FeatureIdentifier).catch(console.error)
setAutoDarkTheme(value)
}
}

View File

@@ -66,18 +66,13 @@ export const CloudBackupProvider: FunctionComponent<Props> = ({
const performBackupNow = async () => {
// A backup is performed anytime the setting is updated with the integration token, so just update it here
try {
await application.settings.updateSetting(
backupFrequencySettingName,
backupFrequency as string,
)
await application.settings.updateSetting(backupFrequencySettingName, backupFrequency as string)
void application.alertService.alert(
'A backup has been triggered for this provider. Please allow a couple minutes for your backup to be processed.',
)
} catch (err) {
application.alertService
.alert(
'There was an error while trying to trigger a backup for this provider. Please try again.',
)
.alert('There was an error while trying to trigger a backup for this provider. Please try again.')
.catch(console.error)
}
}
@@ -184,8 +179,8 @@ export const CloudBackupProvider: FunctionComponent<Props> = ({
{authBegan && (
<div>
<p className="sk-panel-row">
Complete authentication from the newly opened window. Upon completion, a confirmation
code will be displayed. Enter this code below:
Complete authentication from the newly opened window. Upon completion, a confirmation code will be
displayed. Enter this code below:
</p>
<div className={'mt-1'}>
<input

View File

@@ -22,11 +22,7 @@ import { Switch } from '@/Components/Switch'
import { convertStringifiedBooleanToBoolean } from '@/Utils'
import { STRING_FAILED_TO_UPDATE_USER_SETTING } from '@/Strings'
const providerData = [
{ name: CloudProvider.Dropbox },
{ name: CloudProvider.Google },
{ name: CloudProvider.OneDrive },
]
const providerData = [{ name: CloudProvider.Dropbox }, { name: CloudProvider.Google }, { name: CloudProvider.OneDrive }]
type Props = {
application: WebApplication
@@ -62,20 +58,12 @@ export const CloudLink: FunctionComponent<Props> = ({ application }) => {
}, [application])
useEffect(() => {
const dailyDropboxBackupStatus = application.features.getFeatureStatus(
FeatureIdentifier.DailyDropboxBackup,
const dailyDropboxBackupStatus = application.features.getFeatureStatus(FeatureIdentifier.DailyDropboxBackup)
const dailyGdriveBackupStatus = application.features.getFeatureStatus(FeatureIdentifier.DailyGDriveBackup)
const dailyOneDriveBackupStatus = application.features.getFeatureStatus(FeatureIdentifier.DailyOneDriveBackup)
const isCloudBackupsAllowed = [dailyDropboxBackupStatus, dailyGdriveBackupStatus, dailyOneDriveBackupStatus].every(
(status) => status === FeatureStatus.Entitled,
)
const dailyGdriveBackupStatus = application.features.getFeatureStatus(
FeatureIdentifier.DailyGDriveBackup,
)
const dailyOneDriveBackupStatus = application.features.getFeatureStatus(
FeatureIdentifier.DailyOneDriveBackup,
)
const isCloudBackupsAllowed = [
dailyDropboxBackupStatus,
dailyGdriveBackupStatus,
dailyOneDriveBackupStatus,
].every((status) => status === FeatureStatus.Entitled)
setIsEntitledToCloudBackups(isCloudBackupsAllowed)
loadIsFailedCloudBackupEmailMutedSetting().catch(console.error)
@@ -114,9 +102,8 @@ export const CloudLink: FunctionComponent<Props> = ({ application }) => {
{!isEntitledToCloudBackups && (
<>
<Text>
A <span className={'font-bold'}>Plus</span> or{' '}
<span className={'font-bold'}>Pro</span> subscription plan is required to enable Cloud
Backups.{' '}
A <span className={'font-bold'}>Plus</span> or <span className={'font-bold'}>Pro</span> subscription plan
is required to enable Cloud Backups.{' '}
<a target="_blank" href="https://standardnotes.com/features">
Learn more
</a>
@@ -127,8 +114,8 @@ export const CloudLink: FunctionComponent<Props> = ({ application }) => {
)}
<div>
<Text className={additionalClass}>
Configure the integrations below to enable automatic daily backups of your encrypted
data set to your third-party cloud provider.
Configure the integrations below to enable automatic daily backups of your encrypted data set to your
third-party cloud provider.
</Text>
<div>
<HorizontalSeparator classes={`mt-3 mb-3 ${additionalClass}`} />

View File

@@ -160,8 +160,7 @@ export const DataBackups = observer(({ application, appState }: Props) => {
{!isDesktopApplication() && (
<Text className="mb-3">
Backups are automatically created on desktop and can be managed via the "Backups"
top-level menu.
Backups are automatically created on desktop and can be managed via the "Backups" top-level menu.
</Text>
)}
@@ -171,43 +170,25 @@ export const DataBackups = observer(({ application, appState }: Props) => {
<form className="sk-panel-form sk-panel-row">
<div className="sk-input-group">
<label className="sk-horizontal-group tight">
<input
type="radio"
onChange={() => setIsBackupEncrypted(true)}
checked={isBackupEncrypted}
/>
<input type="radio" onChange={() => setIsBackupEncrypted(true)} checked={isBackupEncrypted} />
<Subtitle>Encrypted</Subtitle>
</label>
<label className="sk-horizontal-group tight">
<input
type="radio"
onChange={() => setIsBackupEncrypted(false)}
checked={!isBackupEncrypted}
/>
<input type="radio" onChange={() => setIsBackupEncrypted(false)} checked={!isBackupEncrypted} />
<Subtitle>Decrypted</Subtitle>
</label>
</div>
</form>
)}
<Button
variant="normal"
onClick={downloadDataArchive}
label="Download backup"
className="mt-2"
/>
<Button variant="normal" onClick={downloadDataArchive} label="Download backup" className="mt-2" />
</PreferencesSegment>
<PreferencesSegment>
<Subtitle>Import a previously saved backup file</Subtitle>
<div class="flex flex-row items-center mt-3">
<Button variant="normal" label="Import backup" onClick={handleImportFile} />
<input
type="file"
ref={fileInputRef}
onChange={importFileSelected}
className="hidden"
/>
<input type="file" ref={fileInputRef} onChange={importFileSelected} className="hidden" />
{isImportDataLoading && <div className="sk-spinner normal info ml-4" />}
</div>
</PreferencesSegment>

View File

@@ -27,9 +27,7 @@ type Props = {
export const EmailBackups = observer(({ application }: Props) => {
const [isLoading, setIsLoading] = useState(false)
const [emailFrequency, setEmailFrequency] = useState<EmailBackupFrequency>(
EmailBackupFrequency.Disabled,
)
const [emailFrequency, setEmailFrequency] = useState<EmailBackupFrequency>(EmailBackupFrequency.Disabled)
const [emailFrequencyOptions, setEmailFrequencyOptions] = useState<DropdownItem[]>([])
const [isFailedBackupEmailMuted, setIsFailedBackupEmailMuted] = useState(true)
const [isEntitledToEmailBackups, setIsEntitledToEmailBackups] = useState(false)
@@ -64,9 +62,7 @@ export const EmailBackups = observer(({ application }: Props) => {
}, [application])
useEffect(() => {
const emailBackupsFeatureStatus = application.features.getFeatureStatus(
FeatureIdentifier.DailyEmailBackup,
)
const emailBackupsFeatureStatus = application.features.getFeatureStatus(FeatureIdentifier.DailyEmailBackup)
setIsEntitledToEmailBackups(emailBackupsFeatureStatus === FeatureStatus.Entitled)
const frequencyOptions = []
@@ -109,10 +105,7 @@ export const EmailBackups = observer(({ application }: Props) => {
const previousValue = isFailedBackupEmailMuted
setIsFailedBackupEmailMuted(!isFailedBackupEmailMuted)
const updateResult = await updateSetting(
SettingName.MuteFailedBackupsEmails,
`${!isFailedBackupEmailMuted}`,
)
const updateResult = await updateSetting(SettingName.MuteFailedBackupsEmails, `${!isFailedBackupEmailMuted}`)
if (!updateResult) {
setIsFailedBackupEmailMuted(previousValue)
}
@@ -132,9 +125,8 @@ export const EmailBackups = observer(({ application }: Props) => {
{!isEntitledToEmailBackups && (
<>
<Text>
A <span className={'font-bold'}>Plus</span> or{' '}
<span className={'font-bold'}>Pro</span> subscription plan is required to enable Email
Backups.{' '}
A <span className={'font-bold'}>Plus</span> or <span className={'font-bold'}>Pro</span> subscription plan
is required to enable Email Backups.{' '}
<a target="_blank" href="https://standardnotes.com/features">
Learn more
</a>
@@ -146,8 +138,7 @@ export const EmailBackups = observer(({ application }: Props) => {
<div className={isEntitledToEmailBackups ? '' : 'faded cursor-default pointer-events-none'}>
{!isDesktopApplication() && (
<Text className="mb-3">
Daily encrypted email backups of your entire data set delivered directly to your
inbox.
Daily encrypted email backups of your entire data set delivered directly to your inbox.
</Text>
)}
<Subtitle>Email frequency</Subtitle>

View File

@@ -17,10 +17,10 @@ export const CloudLink: FunctionComponent = () => (
<div className="h-2 w-full" />
<Subtitle>Who can read my private notes?</Subtitle>
<Text>
Quite simply: no one but you. Not us, not your ISP, not a hacker, and not a government
agency. As long as you keep your password safe, and your password is reasonably strong,
then you are the only person in the world with the ability to decrypt your notes. For more
on how we handle your privacy and security, check out our easy to read{' '}
Quite simply: no one but you. Not us, not your ISP, not a hacker, and not a government agency. As long as you
keep your password safe, and your password is reasonably strong, then you are the only person in the world
with the ability to decrypt your notes. For more on how we handle your privacy and security, check out our
easy to read{' '}
<a target="_blank" href="https://standardnotes.com/privacy">
Privacy Manifesto.
</a>
@@ -29,21 +29,17 @@ export const CloudLink: FunctionComponent = () => (
<PreferencesSegment>
<Subtitle>Can I collaborate with others on a note?</Subtitle>
<Text>
Because of our encrypted architecture, Standard Notes does not currently provide a
real-time collaboration solution. Multiple users can share the same account however, but
editing at the same time may result in sync conflicts, which may result in the duplication
of notes.
Because of our encrypted architecture, Standard Notes does not currently provide a real-time collaboration
solution. Multiple users can share the same account however, but editing at the same time may result in sync
conflicts, which may result in the duplication of notes.
</Text>
</PreferencesSegment>
<PreferencesSegment>
<Subtitle>Can I use Standard Notes totally offline?</Subtitle>
<Text>
Standard Notes can be used totally offline without an account, and without an internet
connection. You can find{' '}
<a
target="_blank"
href="https://standardnotes.com/help/59/can-i-use-standard-notes-totally-offline"
>
Standard Notes can be used totally offline without an account, and without an internet connection. You can
find{' '}
<a target="_blank" href="https://standardnotes.com/help/59/can-i-use-standard-notes-totally-offline">
more details here.
</a>
</Text>
@@ -57,38 +53,25 @@ export const CloudLink: FunctionComponent = () => (
<PreferencesSegment>
<Title>Community forum</Title>
<Text>
If you have an issue, found a bug or want to suggest a feature, you can browse or post to
the forum. Its recommended for non-account related issues. Please read our{' '}
If you have an issue, found a bug or want to suggest a feature, you can browse or post to the forum. Its
recommended for non-account related issues. Please read our{' '}
<a target="_blank" href="https://standardnotes.com/longevity/">
Longevity statement
</a>{' '}
before advocating for a feature request.
</Text>
<LinkButton
className="mt-3"
label="Go to the forum"
link="https://forum.standardnotes.org/"
/>
<LinkButton className="mt-3" label="Go to the forum" link="https://forum.standardnotes.org/" />
</PreferencesSegment>
</PreferencesGroup>
<PreferencesGroup>
<PreferencesSegment>
<Title>Community groups</Title>
<Text>
Want to meet other passionate note-takers and privacy enthusiasts? Want to share your
feedback with us? Join the Standard Notes community groups for discussions on security,
themes, editors and more.
Want to meet other passionate note-takers and privacy enthusiasts? Want to share your feedback with us? Join
the Standard Notes community groups for discussions on security, themes, editors and more.
</Text>
<LinkButton
className="mt-3"
link="https://standardnotes.com/slack"
label="Join our Slack"
/>
<LinkButton
className="mt-3"
link="https://standardnotes.com/discord"
label="Join our Discord"
/>
<LinkButton className="mt-3" link="https://standardnotes.com/slack" label="Join our Slack" />
<LinkButton className="mt-3" link="https://standardnotes.com/discord" label="Join our Discord" />
</PreferencesSegment>
</PreferencesGroup>
<PreferencesGroup>

View File

@@ -1,12 +1,7 @@
import { DisplayStringForContentType, SNComponent } from '@standardnotes/snjs'
import { Button } from '@/Components/Button/Button'
import { FunctionComponent } from 'preact'
import {
Title,
Text,
Subtitle,
PreferencesSegment,
} from '@/Components/Preferences/PreferencesComponents'
import { Title, Text, Subtitle, PreferencesSegment } from '@/Components/Preferences/PreferencesComponents'
export const ConfirmCustomExtension: FunctionComponent<{
component: SNComponent
@@ -59,21 +54,11 @@ export const ConfirmCustomExtension: FunctionComponent<{
<div className="min-h-3" />
<div className="flex flex-row">
<Button
className="min-w-20"
variant="normal"
label="Cancel"
onClick={() => callback(false)}
/>
<Button className="min-w-20" variant="normal" label="Cancel" onClick={() => callback(false)} />
<div className="min-w-3" />
<Button
className="min-w-20"
variant="normal"
label="Install"
onClick={() => callback(true)}
/>
<Button className="min-w-20" variant="normal" label="Install" onClick={() => callback(true)} />
</div>
</PreferencesSegment>
)

View File

@@ -1,10 +1,6 @@
import { FunctionComponent } from 'preact'
import { SNComponent } from '@standardnotes/snjs'
import {
PreferencesSegment,
SubtitleLight,
Title,
} from '@/Components/Preferences/PreferencesComponents'
import { PreferencesSegment, SubtitleLight, Title } from '@/Components/Preferences/PreferencesComponents'
import { Switch } from '@/Components/Switch'
import { WebApplication } from '@/UIModels/Application'
import { useState } from 'preact/hooks'
@@ -30,12 +26,7 @@ export interface ExtensionItemProps {
toggleActivate?: (extension: SNComponent) => void
}
export const ExtensionItem: FunctionComponent<ExtensionItemProps> = ({
application,
extension,
first,
uninstall,
}) => {
export const ExtensionItem: FunctionComponent<ExtensionItemProps> = ({ application, extension, first, uninstall }) => {
const [offlineOnly, setOfflineOnly] = useState(extension.offlineOnly ?? false)
const [extensionName, setExtensionName] = useState(extension.name)
@@ -95,12 +86,7 @@ export const ExtensionItem: FunctionComponent<ExtensionItemProps> = ({
<>
<div className="min-h-2" />
<div className="flex flex-row">
<Button
className="min-w-20"
variant="normal"
label="Uninstall"
onClick={() => uninstall(extension)}
/>
<Button className="min-w-20" variant="normal" label="Uninstall" onClick={() => uninstall(extension)} />
</div>
</>
</PreferencesSegment>

View File

@@ -29,10 +29,7 @@ export class ExtensionsLatestVersions {
}
}
function collectFeatures(
features: FeatureDescription[] | undefined,
versionMap: Map<string, string>,
) {
function collectFeatures(features: FeatureDescription[] | undefined, versionMap: Map<string, string>) {
if (features == undefined) {
return
}

View File

@@ -11,11 +11,7 @@ import { ExtensionItem } from './ExtensionItem'
import { ConfirmCustomExtension } from './ConfirmCustomExtension'
const loadExtensions = (application: WebApplication) =>
application.items.getItems([
ContentType.ActionsExtension,
ContentType.Component,
ContentType.Theme,
]) as SNComponent[]
application.items.getItems([ContentType.ActionsExtension, ContentType.Component, ContentType.Theme]) as SNComponent[]
export const Extensions: FunctionComponent<{
application: WebApplication
@@ -23,9 +19,7 @@ export const Extensions: FunctionComponent<{
className?: string
}> = observer(({ application, extensionsLatestVersions, className = '' }) => {
const [customUrl, setCustomUrl] = useState('')
const [confirmableExtension, setConfirmableExtension] = useState<SNComponent | undefined>(
undefined,
)
const [confirmableExtension, setConfirmableExtension] = useState<SNComponent | undefined>(undefined)
const [extensions, setExtensions] = useState(loadExtensions(application))
const confirmableEnd = useRef<HTMLDivElement>(null)
@@ -122,10 +116,7 @@ export const Extensions: FunctionComponent<{
)}
{confirmableExtension && (
<PreferencesSegment>
<ConfirmCustomExtension
component={confirmableExtension}
callback={handleConfirmExtensionSubmit}
/>
<ConfirmCustomExtension component={confirmableExtension} callback={handleConfirmExtensionSubmit} />
<div ref={confirmableEnd} />
</PreferencesSegment>
)}

View File

@@ -29,19 +29,16 @@ export const LabsPane: FunctionComponent<Props> = ({ application }) => {
const [experimentalFeatures, setExperimentalFeatures] = useState<ExperimentalFeatureItem[]>([])
const reloadExperimentalFeatures = useCallback(() => {
const experimentalFeatures = application.features
.getExperimentalFeatures()
.map((featureIdentifier) => {
const feature = FindNativeFeature(featureIdentifier)
return {
identifier: featureIdentifier,
name: feature?.name ?? featureIdentifier,
description: feature?.description ?? '',
isEnabled: application.features.isExperimentalFeatureEnabled(featureIdentifier),
isEntitled:
application.features.getFeatureStatus(featureIdentifier) === FeatureStatus.Entitled,
}
})
const experimentalFeatures = application.features.getExperimentalFeatures().map((featureIdentifier) => {
const feature = FindNativeFeature(featureIdentifier)
return {
identifier: featureIdentifier,
name: feature?.name ?? featureIdentifier,
description: feature?.description ?? '',
isEnabled: application.features.isExperimentalFeatureEnabled(featureIdentifier),
isEntitled: application.features.getFeatureStatus(featureIdentifier) === FeatureStatus.Entitled,
}
})
setExperimentalFeatures(experimentalFeatures)
}, [application.features])
@@ -56,35 +53,32 @@ export const LabsPane: FunctionComponent<Props> = ({ application }) => {
<PreferencesSegment>
<Title>Labs</Title>
<div>
{experimentalFeatures.map(
({ identifier, name, description, isEnabled, isEntitled }, index: number) => {
const toggleFeature = () => {
if (!isEntitled) {
premiumModal.activate(name)
return
}
application.features.toggleExperimentalFeature(identifier)
reloadExperimentalFeatures()
{experimentalFeatures.map(({ identifier, name, description, isEnabled, isEntitled }, index: number) => {
const toggleFeature = () => {
if (!isEntitled) {
premiumModal.activate(name)
return
}
const showHorizontalSeparator =
experimentalFeatures.length > 1 && index !== experimentalFeatures.length - 1
application.features.toggleExperimentalFeature(identifier)
reloadExperimentalFeatures()
}
return (
<>
<div className="flex items-center justify-between">
<div className="flex flex-col">
<Subtitle>{name}</Subtitle>
<Text>{description}</Text>
</div>
<Switch onChange={toggleFeature} checked={isEnabled} />
const showHorizontalSeparator = experimentalFeatures.length > 1 && index !== experimentalFeatures.length - 1
return (
<>
<div className="flex items-center justify-between">
<div className="flex flex-col">
<Subtitle>{name}</Subtitle>
<Text>{description}</Text>
</div>
{showHorizontalSeparator && <HorizontalSeparator classes="mt-5 mb-3" />}
</>
)
},
)}
<Switch onChange={toggleFeature} checked={isEnabled} />
</div>
{showHorizontalSeparator && <HorizontalSeparator classes="mt-5 mb-3" />}
</>
)
})}
{experimentalFeatures.length === 0 && (
<div className="flex items-center justify-between">
<div className="flex flex-col">

View File

@@ -21,11 +21,7 @@ export const General: FunctionComponent<GeneralProps> = observer(
<Tools application={application} />
<Defaults application={application} />
<LabsPane application={application} />
<Advanced
application={application}
appState={appState}
extensionsLatestVersions={extensionsLatestVersions}
/>
<Advanced application={application} appState={appState} extensionsLatestVersions={extensionsLatestVersions} />
</PreferencesPane>
),
)

View File

@@ -17,10 +17,10 @@ export const HelpAndFeedback: FunctionComponent = () => (
<div className="h-2 w-full" />
<Subtitle>Who can read my private notes?</Subtitle>
<Text>
Quite simply: no one but you. Not us, not your ISP, not a hacker, and not a government
agency. As long as you keep your password safe, and your password is reasonably strong,
then you are the only person in the world with the ability to decrypt your notes. For more
on how we handle your privacy and security, check out our easy to read{' '}
Quite simply: no one but you. Not us, not your ISP, not a hacker, and not a government agency. As long as you
keep your password safe, and your password is reasonably strong, then you are the only person in the world
with the ability to decrypt your notes. For more on how we handle your privacy and security, check out our
easy to read{' '}
<a target="_blank" href="https://standardnotes.com/privacy">
Privacy Manifesto.
</a>
@@ -29,21 +29,17 @@ export const HelpAndFeedback: FunctionComponent = () => (
<PreferencesSegment>
<Subtitle>Can I collaborate with others on a note?</Subtitle>
<Text>
Because of our encrypted architecture, Standard Notes does not currently provide a
real-time collaboration solution. Multiple users can share the same account however, but
editing at the same time may result in sync conflicts, which may result in the duplication
of notes.
Because of our encrypted architecture, Standard Notes does not currently provide a real-time collaboration
solution. Multiple users can share the same account however, but editing at the same time may result in sync
conflicts, which may result in the duplication of notes.
</Text>
</PreferencesSegment>
<PreferencesSegment>
<Subtitle>Can I use Standard Notes totally offline?</Subtitle>
<Text>
Standard Notes can be used totally offline without an account, and without an internet
connection. You can find{' '}
<a
target="_blank"
href="https://standardnotes.com/help/59/can-i-use-standard-notes-totally-offline"
>
Standard Notes can be used totally offline without an account, and without an internet connection. You can
find{' '}
<a target="_blank" href="https://standardnotes.com/help/59/can-i-use-standard-notes-totally-offline">
more details here.
</a>
</Text>
@@ -57,38 +53,25 @@ export const HelpAndFeedback: FunctionComponent = () => (
<PreferencesSegment>
<Title>Community forum</Title>
<Text>
If you have an issue, found a bug or want to suggest a feature, you can browse or post to
the forum. Its recommended for non-account related issues. Please read our{' '}
If you have an issue, found a bug or want to suggest a feature, you can browse or post to the forum. Its
recommended for non-account related issues. Please read our{' '}
<a target="_blank" href="https://standardnotes.com/longevity/">
Longevity statement
</a>{' '}
before advocating for a feature request.
</Text>
<LinkButton
className="mt-3"
label="Go to the forum"
link="https://forum.standardnotes.org/"
/>
<LinkButton className="mt-3" label="Go to the forum" link="https://forum.standardnotes.org/" />
</PreferencesSegment>
</PreferencesGroup>
<PreferencesGroup>
<PreferencesSegment>
<Title>Community groups</Title>
<Text>
Want to meet other passionate note-takers and privacy enthusiasts? Want to share your
feedback with us? Join the Standard Notes community groups for discussions on security,
themes, editors and more.
Want to meet other passionate note-takers and privacy enthusiasts? Want to share your feedback with us? Join
the Standard Notes community groups for discussions on security, themes, editors and more.
</Text>
<LinkButton
className="mt-3"
link="https://standardnotes.com/slack"
label="Join our Slack"
/>
<LinkButton
className="mt-3"
link="https://standardnotes.com/discord"
label="Join our Discord"
/>
<LinkButton className="mt-3" link="https://standardnotes.com/slack" label="Join our Slack" />
<LinkButton className="mt-3" link="https://standardnotes.com/discord" label="Join our Discord" />
</PreferencesSegment>
</PreferencesGroup>
<PreferencesGroup>

View File

@@ -11,11 +11,7 @@ type Props = {
application: WebApplication
}
export const ListedAccountItem: FunctionalComponent<Props> = ({
account,
showSeparator,
application,
}) => {
export const ListedAccountItem: FunctionalComponent<Props> = ({ account, showSeparator, application }) => {
const [isLoading, setIsLoading] = useState(false)
const [accountInfo, setAccountInfo] = useState<ListedAccountInfo>()

View File

@@ -84,8 +84,8 @@ export const Listed = observer(({ application }: Props) => {
<div className="h-2 w-full" />
<Subtitle>What is Listed?</Subtitle>
<Text>
Listed is a free blogging platform that allows you to create a public journal published
directly from your notes.{' '}
Listed is a free blogging platform that allows you to create a public journal published directly from your
notes.{' '}
<a target="_blank" href="https://listed.to" rel="noreferrer noopener">
Learn more
</a>

View File

@@ -3,12 +3,7 @@ import { STRING_E2E_ENABLED, STRING_ENC_NOT_ENABLED, STRING_LOCAL_ENC_ENABLED }
import { AppState } from '@/UIModels/AppState'
import { observer } from 'mobx-react-lite'
import { ComponentChild, FunctionComponent } from 'preact'
import {
PreferencesGroup,
PreferencesSegment,
Text,
Title,
} from '@/Components/Preferences/PreferencesComponents'
import { PreferencesGroup, PreferencesSegment, Text, Title } from '@/Components/Preferences/PreferencesComponents'
const formatCount = (count: number, itemType: string) => `${count} / ${count} ${itemType}`

View File

@@ -18,12 +18,7 @@ import { useCallback, useEffect, useRef, useState } from 'preact/hooks'
import { ApplicationEvent } from '@standardnotes/snjs'
import { observer } from 'mobx-react-lite'
import { AppState } from '@/UIModels/AppState'
import {
PreferencesSegment,
Title,
Text,
PreferencesGroup,
} from '@/Components/Preferences/PreferencesComponents'
import { PreferencesSegment, Title, Text, PreferencesGroup } from '@/Components/Preferences/PreferencesComponents'
import { Button } from '@/Components/Button/Button'
type Props = {
@@ -35,8 +30,7 @@ export const PasscodeLock = observer(({ application, appState }: Props) => {
const keyStorageInfo = StringUtils.keyStorageInfo(application)
const passcodeAutoLockOptions = application.getAutolockService().getAutoLockIntervalOptions()
const { setIsEncryptionEnabled, setIsBackupEncrypted, setEncryptionStatusString } =
appState.accountMenu
const { setIsEncryptionEnabled, setIsBackupEncrypted, setEncryptionStatusString } = appState.accountMenu
const passcodeInputRef = useRef<HTMLInputElement>(null)
@@ -109,9 +103,7 @@ export const PasscodeLock = observer(({ application, appState }: Props) => {
setPasscodeConfirmation(value)
}
const submitPasscodeForm = async (
event: TargetedEvent<HTMLFormElement> | TargetedMouseEvent<HTMLButtonElement>,
) => {
const submitPasscodeForm = async (event: TargetedEvent<HTMLFormElement> | TargetedMouseEvent<HTMLButtonElement>) => {
event.preventDefault()
if (!passcode || passcode.length === 0) {
@@ -183,22 +175,18 @@ export const PasscodeLock = observer(({ application, appState }: Props) => {
{!hasPasscode && canAddPasscode && (
<>
<Text className="mb-3">
Add a passcode to lock the application and encrypt on-device key storage.
</Text>
<Text className="mb-3">Add a passcode to lock the application and encrypt on-device key storage.</Text>
{keyStorageInfo && <Text className="mb-3">{keyStorageInfo}</Text>}
{!showPasscodeForm && (
<Button label="Add passcode" onClick={handleAddPassCode} variant="primary" />
)}
{!showPasscodeForm && <Button label="Add passcode" onClick={handleAddPassCode} variant="primary" />}
</>
)}
{!hasPasscode && !canAddPasscode && (
<Text>
Adding a passcode is not supported in temporary sessions. Please sign out, then sign
back in with the "Stay signed in" option checked.
Adding a passcode is not supported in temporary sessions. Please sign out, then sign back in with the
"Stay signed in" option checked.
</Text>
)}
@@ -221,12 +209,7 @@ export const PasscodeLock = observer(({ application, appState }: Props) => {
placeholder="Confirm Passcode"
/>
<div className="min-h-2" />
<Button
variant="primary"
onClick={submitPasscodeForm}
label="Set Passcode"
className="mr-3"
/>
<Button variant="primary" onClick={submitPasscodeForm} label="Set Passcode" className="mr-3" />
<Button variant="normal" onClick={() => setShowPasscodeForm(false)} label="Cancel" />
</form>
)}
@@ -235,17 +218,8 @@ export const PasscodeLock = observer(({ application, appState }: Props) => {
<>
<Text>Passcode lock is enabled.</Text>
<div className="flex flex-row mt-3">
<Button
variant="normal"
label="Change Passcode"
onClick={changePasscodePressed}
className="mr-3"
/>
<Button
dangerStyle={true}
label="Remove Passcode"
onClick={removePasscodePressed}
/>
<Button variant="normal" label="Change Passcode" onClick={changePasscodePressed} className="mr-3" />
<Button dangerStyle={true} label="Remove Passcode" onClick={removePasscodePressed} />
</div>
</>
)}
@@ -258,16 +232,12 @@ export const PasscodeLock = observer(({ application, appState }: Props) => {
<PreferencesGroup>
<PreferencesSegment>
<Title>Autolock</Title>
<Text className="mb-3">
The autolock timer begins when the window or tab loses focus.
</Text>
<Text className="mb-3">The autolock timer begins when the window or tab loses focus.</Text>
<div className="flex flex-row items-center">
{passcodeAutoLockOptions.map((option) => {
return (
<a
className={`sk-a info mr-3 ${
option.value === selectedAutoLockInterval ? 'boxed' : ''
}`}
className={`sk-a info mr-3 ${option.value === selectedAutoLockInterval ? 'boxed' : ''}`}
onClick={() => selectAutoLockInterval(option.value)}
>
{option.label}

View File

@@ -71,9 +71,7 @@ export const Privacy: FunctionalComponent<Props> = observer(({ application }: Pr
const toggleMuteSignInEmails = async () => {
const previousValue = signInEmailsMutedValue
const newValue =
previousValue === MuteSignInEmailsOption.Muted
? MuteSignInEmailsOption.NotMuted
: MuteSignInEmailsOption.Muted
previousValue === MuteSignInEmailsOption.Muted ? MuteSignInEmailsOption.NotMuted : MuteSignInEmailsOption.Muted
setSignInEmailsMutedValue(newValue)
const updateResult = await updateSetting(SettingName.MuteSignInEmails, newValue)
@@ -107,8 +105,8 @@ export const Privacy: FunctionalComponent<Props> = observer(({ application }: Pr
<div className="flex flex-col">
<Subtitle>Disable sign-in notification emails</Subtitle>
<Text>
Disables email notifications when a new sign-in occurs on your account. (Email
notifications are available to paid subscribers).
Disables email notifications when a new sign-in occurs on your account. (Email notifications are
available to paid subscribers).
</Text>
</div>
{isLoading ? (
@@ -125,9 +123,9 @@ export const Privacy: FunctionalComponent<Props> = observer(({ application }: Pr
<div className="flex flex-col">
<Subtitle>Session user agent logging</Subtitle>
<Text>
User agent logging allows you to identify the devices or browsers signed into your
account. For increased privacy, you can disable this feature, which will remove all
saved user agent values from our server, and disable future logging of this value.
User agent logging allows you to identify the devices or browsers signed into your account. For
increased privacy, you can disable this feature, which will remove all saved user agent values from our
server, and disable future logging of this value.
</Text>
</div>
{isLoading ? (

View File

@@ -3,12 +3,7 @@ import { FunctionalComponent } from 'preact'
import { useCallback, useState, useEffect } from 'preact/hooks'
import { ApplicationEvent } from '@standardnotes/snjs'
import { isSameDay } from '@/Utils'
import {
PreferencesGroup,
PreferencesSegment,
Title,
Text,
} from '@/Components/Preferences/PreferencesComponents'
import { PreferencesGroup, PreferencesSegment, Title, Text } from '@/Components/Preferences/PreferencesComponents'
import { Button } from '@/Components/Button/Button'
type Props = {
@@ -47,9 +42,7 @@ export const Protections: FunctionalComponent<Props> = ({ application }) => {
return null
}, [application])
const [protectionsDisabledUntil, setProtectionsDisabledUntil] = useState(
getProtectionsDisabledUntil(),
)
const [protectionsDisabledUntil, setProtectionsDisabledUntil] = useState(getProtectionsDisabledUntil())
useEffect(() => {
const removeUnprotectedSessionBeginObserver = application.addEventObserver(async () => {
@@ -85,17 +78,11 @@ export const Protections: FunctionalComponent<Props> = ({ application }) => {
<Text className="info">Protections are enabled.</Text>
)}
<Text className="mt-2">
Actions like viewing or searching protected notes, exporting decrypted backups, or
revoking an active session require additional authentication such as entering your account
password or application passcode.
Actions like viewing or searching protected notes, exporting decrypted backups, or revoking an active session
require additional authentication such as entering your account password or application passcode.
</Text>
{protectionsDisabledUntil && (
<Button
className="mt-3"
variant="primary"
label="End Unprotected Access"
onClick={enableProtections}
/>
<Button className="mt-3" variant="primary" label="End Unprotected Access" onClick={enableProtections} />
)}
</PreferencesSegment>
</PreferencesGroup>

View File

@@ -14,9 +14,7 @@ const DisclosureIconButton: FunctionComponent<{
<DisclosureButton
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
className={`no-border cursor-pointer bg-transparent hover:brightness-130 p-0 ${
className ?? ''
}`}
className={`no-border cursor-pointer bg-transparent hover:brightness-130 p-0 ${className ?? ''}`}
>
<Icon type={icon} />
</DisclosureButton>
@@ -56,8 +54,8 @@ export const AuthAppInfoTooltip: FunctionComponent = () => {
className={`bg-inverted-default color-inverted-default text-center rounded shadow-overlay
py-1.5 px-2 absolute w-103 -top-10 -left-51`}
>
Some apps, like Google Authenticator, do not back up and restore your secret keys if you
lose your device or get a new one.
Some apps, like Google Authenticator, do not back up and restore your secret keys if you lose your device or
get a new one.
</div>
</DisclosurePanel>
</div>

View File

@@ -76,18 +76,8 @@ export const SaveSecretKey: FunctionComponent<{
</div>
</ModalDialogDescription>
<ModalDialogButtons>
<Button
className="min-w-20"
variant="normal"
label="Back"
onClick={() => act.openScanQRCode()}
/>
<Button
className="min-w-20"
variant="primary"
label="Next"
onClick={() => act.openVerification()}
/>
<Button className="min-w-20" variant="normal" label="Back" onClick={() => act.openScanQRCode()} />
<Button className="min-w-20" variant="primary" label="Next" onClick={() => act.openVerification()} />
</ModalDialogButtons>
</ModalDialog>
)

View File

@@ -19,16 +19,10 @@ export const ScanQRCode: FunctionComponent<{
}> = observer(({ activation: act }) => {
return (
<ModalDialog>
<ModalDialogLabel closeDialog={act.cancelActivation}>
Step 1 of 3 - Scan QR code
</ModalDialogLabel>
<ModalDialogLabel closeDialog={act.cancelActivation}>Step 1 of 3 - Scan QR code</ModalDialogLabel>
<ModalDialogDescription className="h-33">
<div className="w-25 h-25 flex items-center justify-center bg-info">
<QRCode
className="border-neutral-contrast-bg border-solid border-2"
value={act.qrCode}
size={100}
/>
<QRCode className="border-neutral-contrast-bg border-solid border-2" value={act.qrCode} size={100} />
</div>
<div className="min-w-5" />
<div className="flex-grow flex flex-col">
@@ -59,18 +53,8 @@ export const ScanQRCode: FunctionComponent<{
</div>
</ModalDialogDescription>
<ModalDialogButtons>
<Button
className="min-w-20"
variant="normal"
label="Cancel"
onClick={() => act.cancelActivation()}
/>
<Button
className="min-w-20"
variant="primary"
label="Next"
onClick={() => act.openSaveSecretKey()}
/>
<Button className="min-w-20" variant="normal" label="Cancel" onClick={() => act.cancelActivation()} />
<Button className="min-w-20" variant="primary" label="Next" onClick={() => act.openSaveSecretKey()} />
</ModalDialogButtons>
</ModalDialog>
)

View File

@@ -25,12 +25,7 @@ export class TwoFactorActivation {
makeAutoObservable<
TwoFactorActivation,
| '_secretKey'
| '_authCode'
| '_step'
| '_enable2FAVerification'
| 'inputOtpToken'
| 'inputSecretKey'
'_secretKey' | '_authCode' | '_step' | '_enable2FAVerification' | 'inputOtpToken' | 'inputSecretKey'
>(
this,
{

View File

@@ -10,23 +10,16 @@ export const is2FADisabled = (status: TwoFactorStatus): status is 'two-factor-di
export const is2FAActivation = (status: TwoFactorStatus): status is TwoFactorActivation =>
(status as TwoFactorActivation)?.type === 'two-factor-activation'
export const is2FAEnabled = (status: TwoFactorStatus): status is 'two-factor-enabled' =>
status === 'two-factor-enabled'
export const is2FAEnabled = (status: TwoFactorStatus): status is 'two-factor-enabled' => status === 'two-factor-enabled'
export class TwoFactorAuth {
private _status: TwoFactorStatus | 'fetching' = 'fetching'
private _errorMessage: string | null
constructor(
private readonly mfaProvider: MfaProvider,
private readonly userProvider: UserProvider,
) {
constructor(private readonly mfaProvider: MfaProvider, private readonly userProvider: UserProvider) {
this._errorMessage = null
makeAutoObservable<
TwoFactorAuth,
'_status' | '_errorMessage' | 'deactivateMfa' | 'startActivation'
>(
makeAutoObservable<TwoFactorAuth, '_status' | '_errorMessage' | 'deactivateMfa' | 'startActivation'>(
this,
{
_status: observable,

View File

@@ -1,10 +1,5 @@
import { FunctionComponent } from 'preact'
import {
Title,
Text,
PreferencesGroup,
PreferencesSegment,
} from '@/Components/Preferences/PreferencesComponents'
import { Title, Text, PreferencesGroup, PreferencesSegment } from '@/Components/Preferences/PreferencesComponents'
import { Switch } from '@/Components/Switch'
import { observer } from 'mobx-react-lite'
import { is2FAActivation, is2FADisabled, TwoFactorAuth } from './TwoFactorAuth'

View File

@@ -16,18 +16,11 @@ export const TwoFactorSuccess: FunctionComponent<{
<ModalDialogLabel closeDialog={act.finishActivation}>Successfully Enabled</ModalDialogLabel>
<ModalDialogDescription>
<div className="flex flex-row items-center justify-center pt-2">
<Subtitle>
Two-factor authentication has been successfully enabled for your account.
</Subtitle>
<Subtitle>Two-factor authentication has been successfully enabled for your account.</Subtitle>
</div>
</ModalDialogDescription>
<ModalDialogButtons>
<Button
className="min-w-20"
variant="primary"
label="Finish"
onClick={act.finishActivation}
/>
<Button className="min-w-20" variant="primary" label="Finish" onClick={act.finishActivation} />
</ModalDialogButtons>
</ModalDialog>
))

View File

@@ -18,9 +18,7 @@ export const Verification: FunctionComponent<{
const authTokenClass = act.verificationStatus === 'invalid-auth-code' ? 'border-danger' : ''
return (
<ModalDialog>
<ModalDialogLabel closeDialog={act.cancelActivation}>
Step 3 of 3 - Verification
</ModalDialogLabel>
<ModalDialogLabel closeDialog={act.cancelActivation}>Step 3 of 3 - Verification</ModalDialogLabel>
<ModalDialogDescription className="h-33">
<div className="flex-grow flex flex-col">
<div className="flex flex-row items-center mb-4">
@@ -45,21 +43,12 @@ export const Verification: FunctionComponent<{
</ModalDialogDescription>
<ModalDialogButtons>
{act.verificationStatus === 'invalid-auth-code' && (
<div className="text-sm color-danger flex-grow">
Incorrect authentication code, please try again.
</div>
<div className="text-sm color-danger flex-grow">Incorrect authentication code, please try again.</div>
)}
{act.verificationStatus === 'invalid-secret' && (
<div className="text-sm color-danger flex-grow">
Incorrect secret key, please try again.
</div>
<div className="text-sm color-danger flex-grow">Incorrect secret key, please try again.</div>
)}
<Button
className="min-w-20"
variant="normal"
label="Back"
onClick={act.openSaveSecretKey}
/>
<Button className="min-w-20" variant="normal" label="Back" onClick={act.openSaveSecretKey} />
<Button className="min-w-20" variant="primary" label="Next" onClick={act.enable2FA} />
</ModalDialogButtons>
</ModalDialog>

View File

@@ -7,15 +7,13 @@ export const Title: FunctionComponent = ({ children }) => (
</>
)
export const Subtitle: FunctionComponent<{ className?: string }> = ({
children,
className = '',
}) => <h4 className={`font-medium text-sm m-0 mb-1 ${className}`}>{children}</h4>
export const Subtitle: FunctionComponent<{ className?: string }> = ({ children, className = '' }) => (
<h4 className={`font-medium text-sm m-0 mb-1 ${className}`}>{children}</h4>
)
export const SubtitleLight: FunctionComponent<{ className?: string }> = ({
children,
className = '',
}) => <h4 className={`font-normal text-sm m-0 mb-1 ${className}`}>{children}</h4>
export const SubtitleLight: FunctionComponent<{ className?: string }> = ({ children, className = '' }) => (
<h4 className={`font-normal text-sm m-0 mb-1 ${className}`}>{children}</h4>
)
export const Text: FunctionComponent<{ className?: string }> = ({ children, className = '' }) => (
<p className={`${className} text-xs`}>{children}</p>

View File

@@ -10,13 +10,7 @@ interface Props {
onClick: () => void
}
export const MenuItem: FunctionComponent<Props> = ({
iconType,
label,
selected,
onClick,
hasBubble,
}) => (
export const MenuItem: FunctionComponent<Props> = ({ iconType, label, selected, onClick, hasBubble }) => (
<div
className={`preferences-menu-item select-none ${selected ? 'selected' : ''}`}
onClick={(e) => {

View File

@@ -4,9 +4,7 @@ export const PreferencesPane: FunctionComponent = ({ children }) => (
<div className="color-foreground 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.filter((child) => child != undefined)
: children}
{children != undefined && Array.isArray(children) ? children.filter((child) => child != undefined) : children}
</div>
</div>
<div className="flex-basis-55 flex-shrink" />

View File

@@ -59,27 +59,16 @@ const READY_PREFERENCES_MENU_ITEMS: PreferencesMenuItem[] = [
export class PreferencesMenu {
private _selectedPane: PreferenceId = 'account'
private _menu: PreferencesMenuItem[]
private _extensionLatestVersions: ExtensionsLatestVersions = new ExtensionsLatestVersions(
new Map(),
)
private _extensionLatestVersions: ExtensionsLatestVersions = new ExtensionsLatestVersions(new Map())
constructor(
private application: WebApplication,
private readonly _enableUnfinishedFeatures: boolean,
) {
this._menu = this._enableUnfinishedFeatures
? PREFERENCES_MENU_ITEMS
: READY_PREFERENCES_MENU_ITEMS
constructor(private application: WebApplication, private readonly _enableUnfinishedFeatures: boolean) {
this._menu = this._enableUnfinishedFeatures ? PREFERENCES_MENU_ITEMS : READY_PREFERENCES_MENU_ITEMS
this.loadLatestVersions()
makeAutoObservable<
PreferencesMenu,
| '_selectedPane'
| '_twoFactorAuth'
| '_extensionPanes'
| '_extensionLatestVersions'
| 'loadLatestVersions'
'_selectedPane' | '_twoFactorAuth' | '_extensionPanes' | '_extensionLatestVersions' | 'loadLatestVersions'
>(this, {
_twoFactorAuth: observable,
_selectedPane: observable,

View File

@@ -67,14 +67,12 @@ const PaneSelector: FunctionComponent<PreferencesProps & { menu: PreferencesMenu
},
)
const PreferencesCanvas: FunctionComponent<PreferencesProps & { menu: PreferencesMenu }> = observer(
(props) => (
<div className="flex flex-row flex-grow min-h-0 justify-between">
<PreferencesMenuView menu={props.menu} />
<PaneSelector {...props} />
</div>
),
)
const PreferencesCanvas: FunctionComponent<PreferencesProps & { menu: PreferencesMenu }> = observer((props) => (
<div className="flex flex-row flex-grow min-h-0 justify-between">
<PreferencesMenuView menu={props.menu} />
<PaneSelector {...props} />
</div>
))
export const PreferencesView: FunctionComponent<PreferencesProps> = observer((props) => {
const menu = useMemo(