feat: better decryption attempt; upgrade snjs with file size changes
This commit is contained in:
@@ -95,15 +95,12 @@ export const PopoverFileItem: FunctionComponent<PopoverFileItemProps> = ({
|
||||
<div className="text-sm mb-1 break-word">
|
||||
<span className="vertical-middle">{file.name}</span>
|
||||
{file.protected && (
|
||||
<Icon
|
||||
type="lock-filled"
|
||||
className="sn-icon--small ml-2 color-neutral vertical-middle"
|
||||
/>
|
||||
<Icon type="lock-filled" className="sn-icon--small ml-2 color-neutral vertical-middle" />
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div className="text-xs color-grey-0">
|
||||
{file.created_at.toLocaleString()} · {formatSizeToReadableString(file.size)}
|
||||
{file.created_at.toLocaleString()} · {formatSizeToReadableString(file.decryptedSize)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -18,14 +18,13 @@ export const FilePreviewInfoPanel: FunctionComponent<Props> = ({ file }) => {
|
||||
<span className="font-semibold">Type:</span> {file.mimeType}
|
||||
</div>
|
||||
<div className="mb-3">
|
||||
<span className="font-semibold">Size:</span> {formatSizeToReadableString(file.size)}
|
||||
<span className="font-semibold">Size:</span> {formatSizeToReadableString(file.decryptedSize)}
|
||||
</div>
|
||||
<div className="mb-3">
|
||||
<span className="font-semibold">Created:</span> {file.created_at.toLocaleString()}
|
||||
</div>
|
||||
<div className="mb-3">
|
||||
<span className="font-semibold">Last Modified:</span>{' '}
|
||||
{file.userModifiedDate.toLocaleString()}
|
||||
<span className="font-semibold">Last Modified:</span> {file.userModifiedDate.toLocaleString()}
|
||||
</div>
|
||||
<div>
|
||||
<span className="font-semibold">File ID:</span> {file.uuid}
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
} from '@/Components/Preferences/PreferencesComponents'
|
||||
import {
|
||||
ButtonType,
|
||||
ClientDisplayableError,
|
||||
DisplayStringForContentType,
|
||||
EncryptedItemInterface,
|
||||
} from '@standardnotes/snjs'
|
||||
@@ -17,7 +18,9 @@ import { Button } from '@/Components/Button/Button'
|
||||
import { HorizontalSeparator } from '@/Components/Shared/HorizontalSeparator'
|
||||
import { useState } from 'preact/hooks'
|
||||
|
||||
export const ErroredItems: FunctionComponent<{ appState: AppState }> = observer(({ appState }) => {
|
||||
type Props = { appState: AppState }
|
||||
|
||||
export const ErroredItems: FunctionComponent<Props> = observer(({ appState }: Props) => {
|
||||
const app = appState.application
|
||||
|
||||
const [erroredItems, setErroredItems] = useState(app.items.invalidItems)
|
||||
@@ -51,6 +54,18 @@ export const ErroredItems: FunctionComponent<{ appState: AppState }> = observer(
|
||||
setErroredItems(app.items.invalidItems)
|
||||
}
|
||||
|
||||
const attemptDecryption = (item: EncryptedItemInterface): void => {
|
||||
const errorOrTrue = app.canAttemptDecryptionOfItem(item)
|
||||
|
||||
if (errorOrTrue instanceof ClientDisplayableError) {
|
||||
void app.alertService.showErrorAlert(errorOrTrue)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
app.presentKeyRecoveryWizard()
|
||||
}
|
||||
|
||||
return (
|
||||
<PreferencesGroup>
|
||||
<PreferencesSegment>
|
||||
@@ -84,9 +99,7 @@ export const ErroredItems: FunctionComponent<{ appState: AppState }> = observer(
|
||||
<>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex flex-col">
|
||||
<Subtitle>{`${getContentTypeDisplay(item)} created on ${
|
||||
item.createdAtString
|
||||
}`}</Subtitle>
|
||||
<Subtitle>{`${getContentTypeDisplay(item)} created on ${item.createdAtString}`}</Subtitle>
|
||||
<Text>
|
||||
<div>Item ID: {item.uuid}</div>
|
||||
<div>Last Modified: {item.updatedAtString}</div>
|
||||
@@ -97,7 +110,7 @@ export const ErroredItems: FunctionComponent<{ appState: AppState }> = observer(
|
||||
variant="normal"
|
||||
label="Attempt decryption"
|
||||
onClick={() => {
|
||||
void app.presentKeyRecoveryWizard()
|
||||
attemptDecryption(item)
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/* eslint-disable prefer-promise-reject-errors */
|
||||
import { SNAlertService, ButtonType, sanitizeHtmlString } from '@standardnotes/snjs'
|
||||
import { SKAlert } from '@standardnotes/stylekit'
|
||||
|
||||
@@ -66,10 +65,7 @@ export function alertDialog({
|
||||
})
|
||||
}
|
||||
|
||||
export class AlertService implements SNAlertService {
|
||||
/**
|
||||
* @deprecated use the standalone `alertDialog` function instead
|
||||
*/
|
||||
export class AlertService extends SNAlertService {
|
||||
alert(text: string, title?: string, closeButtonText?: string) {
|
||||
return alertDialog({ text, title, closeButtonText })
|
||||
}
|
||||
|
||||
@@ -18,9 +18,7 @@ export class FilesState {
|
||||
let downloadingToastId = ''
|
||||
|
||||
try {
|
||||
const saver = StreamingFileSaver.available()
|
||||
? new StreamingFileSaver(file.name)
|
||||
: new ClassicFileSaver()
|
||||
const saver = StreamingFileSaver.available() ? new StreamingFileSaver(file.name) : new ClassicFileSaver()
|
||||
|
||||
const isUsingStreamingSaver = saver instanceof StreamingFileSaver
|
||||
|
||||
@@ -110,7 +108,7 @@ export class FilesState {
|
||||
message: `Uploading file "${file.name}"...`,
|
||||
})
|
||||
|
||||
const operation = await this.application.files.beginNewFileUpload()
|
||||
const operation = await this.application.files.beginNewFileUpload(file.size)
|
||||
|
||||
if (operation instanceof ClientDisplayableError) {
|
||||
addToast({
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import { confirmDialog } from '@/Services/AlertService'
|
||||
import { STRING_DELETE_TAG } from '@/Strings'
|
||||
import {
|
||||
MAX_MENU_SIZE_MULTIPLIER,
|
||||
MENU_MARGIN_FROM_APP_BORDER,
|
||||
SMART_TAGS_FEATURE_NAME,
|
||||
} from '@/Constants'
|
||||
import { MAX_MENU_SIZE_MULTIPLIER, MENU_MARGIN_FROM_APP_BORDER, SMART_TAGS_FEATURE_NAME } from '@/Constants'
|
||||
import {
|
||||
ComponentAction,
|
||||
ContentType,
|
||||
@@ -46,11 +42,7 @@ const tagSiblings = (application: SNApplication, tag: SNTag): SNTag[] => {
|
||||
return withoutCurrentTag(rootTags(application))
|
||||
}
|
||||
|
||||
const isValidFutureSiblings = (
|
||||
application: SNApplication,
|
||||
futureSiblings: SNTag[],
|
||||
tag: SNTag,
|
||||
): boolean => {
|
||||
const isValidFutureSiblings = (application: SNApplication, futureSiblings: SNTag[], tag: SNTag): boolean => {
|
||||
const siblingWithSameName = futureSiblings.find((otherTag) => otherTag.title === tag.title)
|
||||
|
||||
if (siblingWithSameName) {
|
||||
@@ -83,11 +75,7 @@ export class TagsState {
|
||||
|
||||
private readonly tagsCountsState: TagsCountsState
|
||||
|
||||
constructor(
|
||||
private application: WebApplication,
|
||||
appEventListeners: (() => void)[],
|
||||
private features: FeaturesState,
|
||||
) {
|
||||
constructor(private application: WebApplication, appEventListeners: (() => void)[], private features: FeaturesState) {
|
||||
this.tagsCountsState = new TagsCountsState(this.application)
|
||||
|
||||
this.selected_ = undefined
|
||||
@@ -138,31 +126,28 @@ export class TagsState {
|
||||
})
|
||||
|
||||
appEventListeners.push(
|
||||
this.application.streamItems(
|
||||
[ContentType.Tag, ContentType.SmartView],
|
||||
({ changed, removed }) => {
|
||||
runInAction(() => {
|
||||
this.tags = this.application.items.getDisplayableItems<SNTag>(ContentType.Tag)
|
||||
this.application.streamItems([ContentType.Tag, ContentType.SmartView], ({ changed, removed }) => {
|
||||
runInAction(() => {
|
||||
this.tags = this.application.items.getDisplayableItems<SNTag>(ContentType.Tag)
|
||||
|
||||
this.smartViews = this.application.items.getSmartViews()
|
||||
this.smartViews = this.application.items.getSmartViews()
|
||||
|
||||
const selectedTag = this.selected_
|
||||
const selectedTag = this.selected_
|
||||
|
||||
if (selectedTag && !isSystemView(selectedTag as SmartView)) {
|
||||
if (FindItem(removed, selectedTag.uuid)) {
|
||||
this.selected_ = this.smartViews[0]
|
||||
}
|
||||
|
||||
const updated = FindItem(changed, selectedTag.uuid)
|
||||
if (updated) {
|
||||
this.selected_ = updated as AnyTag
|
||||
}
|
||||
} else {
|
||||
if (selectedTag && !isSystemView(selectedTag as SmartView)) {
|
||||
if (FindItem(removed, selectedTag.uuid)) {
|
||||
this.selected_ = this.smartViews[0]
|
||||
}
|
||||
})
|
||||
},
|
||||
),
|
||||
|
||||
const updated = FindItem(changed, selectedTag.uuid)
|
||||
if (updated) {
|
||||
this.selected_ = updated as AnyTag
|
||||
}
|
||||
} else {
|
||||
this.selected_ = this.smartViews[0]
|
||||
}
|
||||
})
|
||||
}),
|
||||
)
|
||||
|
||||
appEventListeners.push(
|
||||
@@ -170,7 +155,10 @@ export class TagsState {
|
||||
if (!tagUuid) {
|
||||
this.setAllNotesCount(this.application.items.allCountableNotesCount())
|
||||
} else {
|
||||
this.tagsCountsState.update([this.application.items.findItem(tagUuid) as SNTag])
|
||||
const tag = this.application.items.findItem<SNTag>(tagUuid)
|
||||
if (tag) {
|
||||
this.tagsCountsState.update([tag])
|
||||
}
|
||||
}
|
||||
}),
|
||||
)
|
||||
@@ -314,8 +302,7 @@ export class TagsState {
|
||||
return
|
||||
}
|
||||
|
||||
const futureParent =
|
||||
futureParentUuid && (this.application.items.findItem(futureParentUuid) as SNTag)
|
||||
const futureParent = futureParentUuid && (this.application.items.findItem(futureParentUuid) as SNTag)
|
||||
|
||||
if (!futureParent) {
|
||||
const futureSiblings = rootTags(this.application)
|
||||
@@ -399,8 +386,7 @@ export class TagsState {
|
||||
}
|
||||
|
||||
public async createNewTemplate() {
|
||||
const isAlreadyEditingATemplate =
|
||||
this.editing_ && this.application.items.isTemplateItem(this.editing_)
|
||||
const isAlreadyEditingATemplate = this.editing_ && this.application.items.isTemplateItem(this.editing_)
|
||||
|
||||
if (isAlreadyEditingATemplate) {
|
||||
return
|
||||
@@ -439,9 +425,7 @@ export class TagsState {
|
||||
const isTemplateChange = this.application.items.isTemplateItem(tag)
|
||||
|
||||
const siblings = tag instanceof SNTag ? tagSiblings(this.application, tag) : []
|
||||
const hasDuplicatedTitle = siblings.some(
|
||||
(other) => other.title.toLowerCase() === newTitle.toLowerCase(),
|
||||
)
|
||||
const hasDuplicatedTitle = siblings.some((other) => other.title.toLowerCase() === newTitle.toLowerCase())
|
||||
|
||||
runInAction(() => {
|
||||
this.editing_ = undefined
|
||||
@@ -458,9 +442,7 @@ export class TagsState {
|
||||
if (isTemplateChange) {
|
||||
this.undoCreateNewTag()
|
||||
}
|
||||
this.application.alertService
|
||||
?.alert('A tag with this name already exists.')
|
||||
.catch(console.error)
|
||||
this.application.alertService?.alert('A tag with this name already exists.').catch(console.error)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
"@standardnotes/components": "1.7.15",
|
||||
"@standardnotes/filepicker": "1.13.3",
|
||||
"@standardnotes/sncrypto-web": "1.8.4",
|
||||
"@standardnotes/snjs": "2.100.0",
|
||||
"@standardnotes/snjs": "2.102.0",
|
||||
"@standardnotes/stylekit": "5.23.0",
|
||||
"@zip.js/zip.js": "^2.4.10",
|
||||
"mobx": "^6.5.0",
|
||||
|
||||
86
yarn.lock
86
yarn.lock
@@ -2450,27 +2450,27 @@
|
||||
"@typescript-eslint/eslint-plugin" "^5.12.1"
|
||||
"@typescript-eslint/parser" "^5.12.1"
|
||||
|
||||
"@standardnotes/domain-events@^2.27.11":
|
||||
version "2.27.11"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/domain-events/-/domain-events-2.27.11.tgz#0675304c19660b4907c3371e80bf2f7969761546"
|
||||
integrity sha512-fV4nEfayUHjEpTC+9rD5q7h5R318onA9HuqT8eR7HQId1ATGGDcIS0bUITPrlPyZ0pVKmMg8ox7Glya8WTyfwA==
|
||||
"@standardnotes/domain-events@^2.27.12":
|
||||
version "2.27.12"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/domain-events/-/domain-events-2.27.12.tgz#6eb8e484273e7e8b6bb1b40a791cfee24bd6d383"
|
||||
integrity sha512-Sr4KASWYITVpSnE9a8awGyjqeQ9U0e0kpl1jgGYdbkRIWvcxs8bnYWOuwffmD2SfV7PeCbtpUXEyvYDVIsZijA==
|
||||
dependencies:
|
||||
"@standardnotes/auth" "^3.18.11"
|
||||
"@standardnotes/features" "^1.38.0"
|
||||
"@standardnotes/features" "^1.38.1"
|
||||
|
||||
"@standardnotes/encryption@^1.4.10":
|
||||
version "1.4.10"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/encryption/-/encryption-1.4.10.tgz#ff5d5a884aae9a14fff7e3afe3772f41af1bb642"
|
||||
integrity sha512-BH5brDoevoGEyNXEIV/D6G28Bn1zHxKed01aofqgronOgbZdVGXtxKr7j/EOfzareg7vhhUO2oA73aTU73dAOA==
|
||||
"@standardnotes/encryption@^1.4.12":
|
||||
version "1.4.12"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/encryption/-/encryption-1.4.12.tgz#098c9320a7b19aba44e0c7baa1fcd243120c2fef"
|
||||
integrity sha512-DTW/CAlDDOimXwE8XN+V2R3sPXXQYzYnWZHs6WCD3NaLN41MAoG1j8cVuTKHHMP0hhaS2/refOllgt8Kf97mKQ==
|
||||
dependencies:
|
||||
"@standardnotes/models" "^1.4.9"
|
||||
"@standardnotes/responses" "^1.6.11"
|
||||
"@standardnotes/services" "^1.9.11"
|
||||
"@standardnotes/models" "^1.5.1"
|
||||
"@standardnotes/responses" "^1.6.12"
|
||||
"@standardnotes/services" "^1.9.13"
|
||||
|
||||
"@standardnotes/features@^1.38.0":
|
||||
version "1.38.0"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/features/-/features-1.38.0.tgz#ddd6817af1544374013fec0bb19f5dff4a11ae60"
|
||||
integrity sha512-6a56WZTgbB1/IefF8ADWuOI9FPthP30BpJT+Dmu4TEG8SdEC4QFCogAfRPwJ2z8Kh8xYeWuRZDr+CYsm20vqWg==
|
||||
"@standardnotes/features@^1.38.1":
|
||||
version "1.38.1"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/features/-/features-1.38.1.tgz#5ee52ab91f02be2d2762dcee49db17d1040a7bf8"
|
||||
integrity sha512-rSQ8ClG7os3w9AddP0VZbvkIpEHCKGzCLiHum0D90ogjFFXgr8+EvonOfFQEc3pa9hdyq1fofhedNQRJsdo14Q==
|
||||
dependencies:
|
||||
"@standardnotes/auth" "^3.18.11"
|
||||
"@standardnotes/common" "^1.19.6"
|
||||
@@ -2483,32 +2483,32 @@
|
||||
"@standardnotes/common" "^1.19.6"
|
||||
"@standardnotes/utils" "^1.6.2"
|
||||
|
||||
"@standardnotes/models@^1.4.9":
|
||||
version "1.4.9"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/models/-/models-1.4.9.tgz#50b0055a4e149b948068405c69beeda1859a378d"
|
||||
integrity sha512-34iv7Z+WiJIoOYcld8RPm4suexK0cuW2drtYdtl/10y/hJC+rXSlVIUVMj7ckPb9g4cuxyI+WVfZ1ebx8+1n0g==
|
||||
"@standardnotes/models@^1.5.1":
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/models/-/models-1.5.1.tgz#a522c715c74c63e58fc4182e69baad46548dbfba"
|
||||
integrity sha512-dOVnT5HCAjU3i4KqTeu05h5d+LDp8nteam6xb9V75XbA/UT9TMC3zwE+yEYpvWC4iKSbdPQvIuuvp8hXFyOnbA==
|
||||
dependencies:
|
||||
"@standardnotes/features" "^1.38.0"
|
||||
"@standardnotes/responses" "^1.6.11"
|
||||
"@standardnotes/features" "^1.38.1"
|
||||
"@standardnotes/responses" "^1.6.12"
|
||||
"@standardnotes/utils" "^1.6.2"
|
||||
|
||||
"@standardnotes/responses@^1.6.11":
|
||||
version "1.6.11"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/responses/-/responses-1.6.11.tgz#78adf45af580a0b5ecc6f2a6b5b80c286107c36c"
|
||||
integrity sha512-laQfkpTZMHKghyE2Vnc2lt9QEnEFpwEi2j0GezJ0QjbjKdxIyzGUMHMFCZREvQd9Z3PiVuwPXW49DGyGJZHAfQ==
|
||||
"@standardnotes/responses@^1.6.12":
|
||||
version "1.6.12"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/responses/-/responses-1.6.12.tgz#99090e407f10d430cf5bea548a9314472c00a1c7"
|
||||
integrity sha512-WqPcxI7BeuSwbemI5Hag6tK0Rzf/OxyX1aeRWGXWrQOQJjv4tpyUSjT0gdutsslqkIehI3oLG+B9DLUNe6Wddg==
|
||||
dependencies:
|
||||
"@standardnotes/auth" "^3.18.11"
|
||||
"@standardnotes/common" "^1.19.6"
|
||||
"@standardnotes/features" "^1.38.0"
|
||||
"@standardnotes/features" "^1.38.1"
|
||||
|
||||
"@standardnotes/services@^1.9.11":
|
||||
version "1.9.11"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/services/-/services-1.9.11.tgz#b35e60098a8196a58d0a0547a61fc742b2895efc"
|
||||
integrity sha512-UWGbwS7uvxKOpLFb+HfICe2oqY6oNoqfk4A5WzrLiUsfELvh8VtaahoE9KoGn/4QSzrrYBFG9jXk2CtA5IGEgg==
|
||||
"@standardnotes/services@^1.9.13":
|
||||
version "1.9.13"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/services/-/services-1.9.13.tgz#4af36863626cd70be976785f85dc76cb3fd8f3d8"
|
||||
integrity sha512-UWrg8ThBUl3JvLRFc3tEPXstJFQtnLAVHOfRppUL8MZZ+U6sYmKRpQp9+pX0Wdx0SQwQuuRyFKtSw9JFlLvrnA==
|
||||
dependencies:
|
||||
"@standardnotes/common" "^1.19.6"
|
||||
"@standardnotes/models" "^1.4.9"
|
||||
"@standardnotes/responses" "^1.6.11"
|
||||
"@standardnotes/models" "^1.5.1"
|
||||
"@standardnotes/responses" "^1.6.12"
|
||||
"@standardnotes/utils" "^1.6.2"
|
||||
|
||||
"@standardnotes/settings@^1.14.1":
|
||||
@@ -2530,20 +2530,20 @@
|
||||
buffer "^6.0.3"
|
||||
libsodium-wrappers "^0.7.9"
|
||||
|
||||
"@standardnotes/snjs@2.100.0":
|
||||
version "2.100.0"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/snjs/-/snjs-2.100.0.tgz#d62c7f0cd17a50b4f3d9e349c7c00a3f6de1192c"
|
||||
integrity sha512-4pnmAJJ3mDDmLWx8ChR3qEKHcsKB4M1+/o1Nxj8rYOdOnVzvBhzqSERKUyUabNvDOcmo0RkAIDeHgIIRjkJtiQ==
|
||||
"@standardnotes/snjs@2.102.0":
|
||||
version "2.102.0"
|
||||
resolved "https://registry.yarnpkg.com/@standardnotes/snjs/-/snjs-2.102.0.tgz#756ad160395c87d791399d0d2784ae9b2853d07e"
|
||||
integrity sha512-+cPyYW6MUex1D8MeX0hrDzKywnuGZj8le7varDbhs3zT++f7UWt6pmu7SEXx71A75rP5u5oDtdaOxqSyBNHOlg==
|
||||
dependencies:
|
||||
"@standardnotes/auth" "^3.18.11"
|
||||
"@standardnotes/common" "^1.19.6"
|
||||
"@standardnotes/domain-events" "^2.27.11"
|
||||
"@standardnotes/encryption" "^1.4.10"
|
||||
"@standardnotes/features" "^1.38.0"
|
||||
"@standardnotes/domain-events" "^2.27.12"
|
||||
"@standardnotes/encryption" "^1.4.12"
|
||||
"@standardnotes/features" "^1.38.1"
|
||||
"@standardnotes/filepicker" "^1.13.3"
|
||||
"@standardnotes/models" "^1.4.9"
|
||||
"@standardnotes/responses" "^1.6.11"
|
||||
"@standardnotes/services" "^1.9.11"
|
||||
"@standardnotes/models" "^1.5.1"
|
||||
"@standardnotes/responses" "^1.6.12"
|
||||
"@standardnotes/services" "^1.9.13"
|
||||
"@standardnotes/settings" "^1.14.1"
|
||||
"@standardnotes/sncrypto-common" "^1.7.7"
|
||||
"@standardnotes/utils" "^1.6.2"
|
||||
|
||||
Reference in New Issue
Block a user