chore: improve preferences folder hierarchies (#1186)
This commit is contained in:
@@ -15,6 +15,7 @@
|
||||
"prebuild": "yarn clean",
|
||||
"build": "webpack --config web.webpack.prod.js && yarn tsc",
|
||||
"lint": "eslint src/javascripts",
|
||||
"format": "prettier --write src/javascripts",
|
||||
"tsc": "tsc --project tsconfig.json",
|
||||
"test": "jest --config jest.config.js --coverage",
|
||||
"upgrade:snjs": "ncu -u '@standardnotes/*'"
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
import { WebApplication } from '@/Application/Application'
|
||||
import { AnyExtension } from './AnyExtension'
|
||||
|
||||
export interface ExtensionItemProps {
|
||||
application: WebApplication
|
||||
extension: AnyExtension
|
||||
first: boolean
|
||||
latestVersion: string | undefined
|
||||
uninstall: (extension: AnyExtension) => void
|
||||
toggleActivate?: (extension: AnyExtension) => void
|
||||
}
|
||||
@@ -1,29 +1,29 @@
|
||||
import { FunctionComponent } from 'react'
|
||||
import OfflineSubscription from '@/Components/Preferences/Panes/Account/OfflineSubscription'
|
||||
import OfflineSubscription from '@/Components/Preferences/Panes/General/Advanced/OfflineSubscription'
|
||||
import { WebApplication } from '@/Application/Application'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { ViewControllerManager } from '@/Services/ViewControllerManager'
|
||||
import Extensions from '@/Components/Preferences/Panes/Extensions/Extensions'
|
||||
import { ExtensionsLatestVersions } from '@/Components/Preferences/Panes/Extensions/ExtensionsLatestVersions'
|
||||
import PackagesPreferencesSection from '@/Components/Preferences/Panes/General/Advanced/Packages/Section'
|
||||
import { PackageProvider } from '@/Components/Preferences/Panes/General/Advanced/Packages/Provider/PackageProvider'
|
||||
import AccordionItem from '@/Components/Shared/AccordionItem'
|
||||
import PreferencesGroup from '../../PreferencesComponents/PreferencesGroup'
|
||||
import PreferencesSegment from '../../PreferencesComponents/PreferencesSegment'
|
||||
import PreferencesGroup from '../../../PreferencesComponents/PreferencesGroup'
|
||||
import PreferencesSegment from '../../../PreferencesComponents/PreferencesSegment'
|
||||
|
||||
type Props = {
|
||||
application: WebApplication
|
||||
viewControllerManager: ViewControllerManager
|
||||
extensionsLatestVersions: ExtensionsLatestVersions
|
||||
extensionsLatestVersions: PackageProvider
|
||||
}
|
||||
|
||||
const Advanced: FunctionComponent<Props> = ({ application, viewControllerManager, extensionsLatestVersions }) => {
|
||||
return (
|
||||
<PreferencesGroup>
|
||||
<PreferencesSegment>
|
||||
<AccordionItem title={'Advanced Settings'}>
|
||||
<AccordionItem title={'Advanced Options'}>
|
||||
<div className="flex flex-row items-center">
|
||||
<div className="flex flex-grow flex-col">
|
||||
<OfflineSubscription application={application} viewControllerManager={viewControllerManager} />
|
||||
<Extensions
|
||||
<PackagesPreferencesSection
|
||||
className={'mt-3'}
|
||||
application={application}
|
||||
extensionsLatestVersions={extensionsLatestVersions}
|
||||
@@ -2,11 +2,11 @@ import { DisplayStringForContentType } from '@standardnotes/snjs'
|
||||
import Button from '@/Components/Button/Button'
|
||||
import { Fragment, FunctionComponent } from 'react'
|
||||
import { Title, Text, Subtitle } from '@/Components/Preferences/PreferencesComponents/Content'
|
||||
import { AnyExtension } from './AnyExtension'
|
||||
import PreferencesSegment from '../../PreferencesComponents/PreferencesSegment'
|
||||
import { AnyPackageType } from './Types/AnyPackageType'
|
||||
import PreferencesSegment from '../../../../PreferencesComponents/PreferencesSegment'
|
||||
|
||||
const ConfirmCustomExtension: FunctionComponent<{
|
||||
component: AnyExtension
|
||||
const ConfirmCustomPackage: FunctionComponent<{
|
||||
component: AnyPackageType
|
||||
callback: (confirmed: boolean) => void
|
||||
}> = ({ component, callback }) => {
|
||||
const fields = [
|
||||
@@ -66,4 +66,4 @@ const ConfirmCustomExtension: FunctionComponent<{
|
||||
)
|
||||
}
|
||||
|
||||
export default ConfirmCustomExtension
|
||||
export default ConfirmCustomPackage
|
||||
@@ -3,9 +3,10 @@ import { ComponentMutator, SNComponent } from '@standardnotes/snjs'
|
||||
import { SubtitleLight } from '@/Components/Preferences/PreferencesComponents/Content'
|
||||
import Switch from '@/Components/Switch/Switch'
|
||||
import Button from '@/Components/Button/Button'
|
||||
import ExtensionInfoCell from './ExtensionInfoCell'
|
||||
import { ExtensionItemProps } from './ExtensionItemProps'
|
||||
import PreferencesSegment from '../../PreferencesComponents/PreferencesSegment'
|
||||
import PackageEntrySubInfo from './PackageEntrySubInfo'
|
||||
import PreferencesSegment from '../../../../PreferencesComponents/PreferencesSegment'
|
||||
import { WebApplication } from '@/Application/Application'
|
||||
import { AnyPackageType } from './Types/AnyPackageType'
|
||||
|
||||
const UseHosted: FunctionComponent<{
|
||||
offlineOnly: boolean
|
||||
@@ -17,7 +18,16 @@ const UseHosted: FunctionComponent<{
|
||||
</div>
|
||||
)
|
||||
|
||||
const ExtensionItem: FunctionComponent<ExtensionItemProps> = ({ application, extension, uninstall }) => {
|
||||
interface PackageEntryProps {
|
||||
application: WebApplication
|
||||
extension: AnyPackageType
|
||||
first: boolean
|
||||
latestVersion: string | undefined
|
||||
uninstall: (extension: AnyPackageType) => void
|
||||
toggleActivate?: (extension: AnyPackageType) => void
|
||||
}
|
||||
|
||||
const PackageEntry: FunctionComponent<PackageEntryProps> = ({ application, extension, uninstall }) => {
|
||||
const [offlineOnly, setOfflineOnly] = useState(extension instanceof SNComponent ? extension.offlineOnly : false)
|
||||
const [extensionName, setExtensionName] = useState(extension.displayName)
|
||||
|
||||
@@ -56,7 +66,7 @@ const ExtensionItem: FunctionComponent<ExtensionItemProps> = ({ application, ext
|
||||
|
||||
return (
|
||||
<PreferencesSegment classes={'mb-5'}>
|
||||
<ExtensionInfoCell isThirdParty={isThirdParty} extensionName={extensionName} changeName={changeExtensionName} />
|
||||
<PackageEntrySubInfo isThirdParty={isThirdParty} extensionName={extensionName} changeName={changeExtensionName} />
|
||||
|
||||
<div className="my-1" />
|
||||
|
||||
@@ -71,4 +81,4 @@ const ExtensionItem: FunctionComponent<ExtensionItemProps> = ({ application, ext
|
||||
)
|
||||
}
|
||||
|
||||
export default ExtensionItem
|
||||
export default PackageEntry
|
||||
@@ -6,7 +6,7 @@ type Props = {
|
||||
isThirdParty: boolean
|
||||
}
|
||||
|
||||
const ExtensionInfoCell: FunctionComponent<Props> = ({ extensionName, changeName, isThirdParty }) => {
|
||||
const PackageEntrySubInfo: FunctionComponent<Props> = ({ extensionName, changeName, isThirdParty }) => {
|
||||
const [isRenaming, setIsRenaming] = useState(false)
|
||||
const [newExtensionName, setNewExtensionName] = useState<string>(extensionName)
|
||||
|
||||
@@ -73,4 +73,4 @@ const ExtensionInfoCell: FunctionComponent<Props> = ({ extensionName, changeName
|
||||
)
|
||||
}
|
||||
|
||||
export default ExtensionInfoCell
|
||||
export default PackageEntrySubInfo
|
||||
@@ -1,13 +1,13 @@
|
||||
import { WebApplication } from '@/Application/Application'
|
||||
import { ClientDisplayableError, FeatureDescription } from '@standardnotes/snjs'
|
||||
import { makeAutoObservable, observable } from 'mobx'
|
||||
import { AnyExtension } from './AnyExtension'
|
||||
import { AnyPackageType } from '../Types/AnyPackageType'
|
||||
import { ComponentChecksumsType } from '@standardnotes/components-meta'
|
||||
import RawComponentChecksumsFile from '@standardnotes/components-meta/dist/zips/checksums.json'
|
||||
const ComponentChecksums = RawComponentChecksumsFile as ComponentChecksumsType
|
||||
|
||||
export class ExtensionsLatestVersions {
|
||||
static async load(application: WebApplication): Promise<ExtensionsLatestVersions | undefined> {
|
||||
export class PackageProvider {
|
||||
static async load(application: WebApplication): Promise<PackageProvider | undefined> {
|
||||
const response = await application.getAvailableSubscriptions()
|
||||
|
||||
if (response instanceof ClientDisplayableError) {
|
||||
@@ -18,16 +18,16 @@ export class ExtensionsLatestVersions {
|
||||
collectFeatures(response.PLUS_PLAN?.features as FeatureDescription[], versionMap)
|
||||
collectFeatures(response.PRO_PLAN?.features as FeatureDescription[], versionMap)
|
||||
|
||||
return new ExtensionsLatestVersions(versionMap)
|
||||
return new PackageProvider(versionMap)
|
||||
}
|
||||
|
||||
constructor(private readonly latestVersionsMap: Map<string, string>) {
|
||||
makeAutoObservable<ExtensionsLatestVersions, 'latestVersionsMap'>(this, {
|
||||
makeAutoObservable<PackageProvider, 'latestVersionsMap'>(this, {
|
||||
latestVersionsMap: observable.ref,
|
||||
})
|
||||
}
|
||||
|
||||
getVersion(extension: AnyExtension): string | undefined {
|
||||
getVersion(extension: AnyPackageType): string | undefined {
|
||||
return this.latestVersionsMap.get(extension.package_info.identifier)
|
||||
}
|
||||
}
|
||||
@@ -3,26 +3,34 @@ import Button from '@/Components/Button/Button'
|
||||
import DecoratedInput from '@/Components/Input/DecoratedInput'
|
||||
import { WebApplication } from '@/Application/Application'
|
||||
import { FunctionComponent, useEffect, useRef, useState } from 'react'
|
||||
import { Title } from '@/Components/Preferences/PreferencesComponents/Content'
|
||||
import { Subtitle } from '@/Components/Preferences/PreferencesComponents/Content'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { ExtensionsLatestVersions } from './ExtensionsLatestVersions'
|
||||
import ExtensionItem from './ExtensionItem'
|
||||
import ConfirmCustomExtension from './ConfirmCustomExtension'
|
||||
import { AnyExtension } from './AnyExtension'
|
||||
import PreferencesSegment from '../../PreferencesComponents/PreferencesSegment'
|
||||
import { PackageProvider } from './Provider/PackageProvider'
|
||||
import PackageEntry from './PackageEntry'
|
||||
import ConfirmCustomPackage from './ConfirmCustomPackage'
|
||||
import { AnyPackageType } from './Types/AnyPackageType'
|
||||
import PreferencesSegment from '../../../../PreferencesComponents/PreferencesSegment'
|
||||
|
||||
const loadExtensions = (application: WebApplication) =>
|
||||
application.items.getItems([ContentType.ActionsExtension, ContentType.Component, ContentType.Theme]) as AnyExtension[]
|
||||
application.items.getItems([
|
||||
ContentType.ActionsExtension,
|
||||
ContentType.Component,
|
||||
ContentType.Theme,
|
||||
]) as AnyPackageType[]
|
||||
|
||||
type Props = {
|
||||
application: WebApplication
|
||||
extensionsLatestVersions: ExtensionsLatestVersions
|
||||
extensionsLatestVersions: PackageProvider
|
||||
className?: string
|
||||
}
|
||||
|
||||
const Extensions: FunctionComponent<Props> = ({ application, extensionsLatestVersions, className = '' }) => {
|
||||
const PackagesPreferencesSection: FunctionComponent<Props> = ({
|
||||
application,
|
||||
extensionsLatestVersions,
|
||||
className = '',
|
||||
}) => {
|
||||
const [customUrl, setCustomUrl] = useState('')
|
||||
const [confirmableExtension, setConfirmableExtension] = useState<AnyExtension | undefined>(undefined)
|
||||
const [confirmableExtension, setConfirmableExtension] = useState<AnyPackageType | undefined>(undefined)
|
||||
const [extensions, setExtensions] = useState(loadExtensions(application))
|
||||
|
||||
const confirmableEnd = useRef<HTMLDivElement>(null)
|
||||
@@ -33,7 +41,7 @@ const Extensions: FunctionComponent<Props> = ({ application, extensionsLatestVer
|
||||
}
|
||||
}, [confirmableExtension, confirmableEnd])
|
||||
|
||||
const uninstallExtension = async (extension: AnyExtension) => {
|
||||
const uninstallExtension = async (extension: AnyPackageType) => {
|
||||
application.alertService
|
||||
.confirm(
|
||||
'Are you sure you want to uninstall this extension? Note that extensions managed by your subscription will automatically be re-installed on application restart.',
|
||||
@@ -69,7 +77,7 @@ const Extensions: FunctionComponent<Props> = ({ application, extensionsLatestVer
|
||||
}
|
||||
|
||||
const confirmExtension = async () => {
|
||||
await application.mutator.insertItem(confirmableExtension as AnyExtension)
|
||||
await application.mutator.insertItem(confirmableExtension as AnyPackageType)
|
||||
application.sync.sync().catch(console.error)
|
||||
setExtensions(loadExtensions(application))
|
||||
}
|
||||
@@ -95,7 +103,7 @@ const Extensions: FunctionComponent<Props> = ({ application, extensionsLatestVer
|
||||
{visibleExtensions
|
||||
.sort((e1, e2) => e1.displayName?.toLowerCase().localeCompare(e2.displayName?.toLowerCase()))
|
||||
.map((extension, i) => (
|
||||
<ExtensionItem
|
||||
<PackageEntry
|
||||
key={extension.uuid}
|
||||
application={application}
|
||||
extension={extension}
|
||||
@@ -110,20 +118,28 @@ const Extensions: FunctionComponent<Props> = ({ application, extensionsLatestVer
|
||||
<div>
|
||||
{!confirmableExtension && (
|
||||
<PreferencesSegment>
|
||||
<Title>Install Custom Extension</Title>
|
||||
<DecoratedInput
|
||||
placeholder={'Enter Extension URL'}
|
||||
value={customUrl}
|
||||
onChange={(value) => {
|
||||
setCustomUrl(value)
|
||||
}}
|
||||
<Subtitle>Install External Package</Subtitle>
|
||||
<div className={'mt-2'}>
|
||||
<DecoratedInput
|
||||
placeholder={'Enter Package URL'}
|
||||
value={customUrl}
|
||||
onChange={(value) => {
|
||||
setCustomUrl(value)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
disabled={customUrl.length === 0}
|
||||
className="mt-3 min-w-20"
|
||||
primary
|
||||
label="Install"
|
||||
onClick={() => submitExtensionUrl(customUrl)}
|
||||
/>
|
||||
<Button className="mt-3 min-w-20" label="Install" onClick={() => submitExtensionUrl(customUrl)} />
|
||||
</PreferencesSegment>
|
||||
)}
|
||||
{confirmableExtension && (
|
||||
<PreferencesSegment>
|
||||
<ConfirmCustomExtension component={confirmableExtension} callback={handleConfirmExtensionSubmit} />
|
||||
<ConfirmCustomPackage component={confirmableExtension} callback={handleConfirmExtensionSubmit} />
|
||||
<div ref={confirmableEnd} />
|
||||
</PreferencesSegment>
|
||||
)}
|
||||
@@ -132,4 +148,4 @@ const Extensions: FunctionComponent<Props> = ({ application, extensionsLatestVer
|
||||
)
|
||||
}
|
||||
|
||||
export default observer(Extensions)
|
||||
export default observer(PackagesPreferencesSection)
|
||||
@@ -1,3 +1,3 @@
|
||||
import { SNActionsExtension, SNComponent, SNTheme } from '@standardnotes/snjs'
|
||||
|
||||
export type AnyExtension = SNComponent | SNTheme | SNActionsExtension
|
||||
export type AnyPackageType = SNComponent | SNTheme | SNActionsExtension
|
||||
@@ -1,18 +1,18 @@
|
||||
import { WebApplication } from '@/Application/Application'
|
||||
import { ViewControllerManager } from '@/Services/ViewControllerManager'
|
||||
import { FunctionComponent } from 'react'
|
||||
import { ExtensionsLatestVersions } from '@/Components/Preferences/Panes/Extensions/ExtensionsLatestVersions'
|
||||
import { PackageProvider } from '@/Components/Preferences/Panes/General/Advanced/Packages/Provider/PackageProvider'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import Tools from './Tools'
|
||||
import Defaults from './Defaults'
|
||||
import LabsPane from './Labs/Labs'
|
||||
import Advanced from '@/Components/Preferences/Panes/Account/Advanced'
|
||||
import Advanced from '@/Components/Preferences/Panes/General/Advanced/AdvancedSection'
|
||||
import PreferencesPane from '../../PreferencesComponents/PreferencesPane'
|
||||
|
||||
type Props = {
|
||||
viewControllerManager: ViewControllerManager
|
||||
application: WebApplication
|
||||
extensionsLatestVersions: ExtensionsLatestVersions
|
||||
extensionsLatestVersions: PackageProvider
|
||||
}
|
||||
|
||||
const General: FunctionComponent<Props> = ({ viewControllerManager, application, extensionsLatestVersions }) => (
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { WebApplication } from '@/Application/Application'
|
||||
import { ViewControllerManager } from '@/Services/ViewControllerManager'
|
||||
import { FunctionComponent } from 'react'
|
||||
import TwoFactorAuthWrapper from '../TwoFactorAuth/TwoFactorAuthWrapper'
|
||||
import { MfaProps } from '../TwoFactorAuth/MfaProps'
|
||||
import TwoFactorAuthWrapper from './TwoFactorAuth/TwoFactorAuthWrapper'
|
||||
import { MfaProps } from './TwoFactorAuth/MfaProps'
|
||||
import Encryption from './Encryption'
|
||||
import PasscodeLock from './PasscodeLock'
|
||||
import Privacy from './Privacy'
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { action, makeAutoObservable, observable } from 'mobx'
|
||||
import { IconType } from '@standardnotes/snjs'
|
||||
import { WebApplication } from '@/Application/Application'
|
||||
import { ExtensionsLatestVersions } from './Panes/Extensions/ExtensionsLatestVersions'
|
||||
import { PackageProvider } from './Panes/General/Advanced/Packages/Provider/PackageProvider'
|
||||
import { securityPrefsHasBubble } from './Panes/Security/securityPrefsHasBubble'
|
||||
|
||||
const PREFERENCE_IDS = [
|
||||
@@ -59,7 +59,7 @@ 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: PackageProvider = new PackageProvider(new Map())
|
||||
|
||||
constructor(private application: WebApplication, private readonly _enableUnfinishedFeatures: boolean) {
|
||||
this._menu = this._enableUnfinishedFeatures ? PREFERENCES_MENU_ITEMS : READY_PREFERENCES_MENU_ITEMS
|
||||
@@ -79,7 +79,7 @@ export class PreferencesMenu {
|
||||
}
|
||||
|
||||
private loadLatestVersions(): void {
|
||||
ExtensionsLatestVersions.load(this.application)
|
||||
PackageProvider.load(this.application)
|
||||
.then((versions) => {
|
||||
if (versions) {
|
||||
this._extensionLatestVersions = versions
|
||||
@@ -88,7 +88,7 @@ export class PreferencesMenu {
|
||||
.catch(console.error)
|
||||
}
|
||||
|
||||
get extensionsLatestVersions(): ExtensionsLatestVersions {
|
||||
get extensionsLatestVersions(): PackageProvider {
|
||||
return this._extensionLatestVersions
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { WebApplication } from '@/Application/Application'
|
||||
import { MfaProps } from './Panes/TwoFactorAuth/MfaProps'
|
||||
import { MfaProps } from './Panes/Security/TwoFactorAuth/MfaProps'
|
||||
import { ViewControllerManager } from '@/Services/ViewControllerManager'
|
||||
|
||||
export interface PreferencesProps extends MfaProps {
|
||||
|
||||
Reference in New Issue
Block a user