From 413af3042d863fc57d519165f820c64167160375 Mon Sep 17 00:00:00 2001 From: gdbroman <99gustaf@gmail.com> Date: Fri, 28 Jul 2023 12:01:58 +0200 Subject: [PATCH 1/2] Fix personal notes not saving to Bedrock --- app/src/os/realm.service.ts | 14 +-- app/src/os/services/ship/ship.service.ts | 97 ++++++++++--------- .../sections/AccountPassportSection.tsx | 1 + .../onboarding/components/PassportForm.tsx | 2 +- 4 files changed, 59 insertions(+), 55 deletions(-) diff --git a/app/src/os/realm.service.ts b/app/src/os/realm.service.ts index e68d5f455b..c61a5a73c7 100644 --- a/app/src/os/realm.service.ts +++ b/app/src/os/realm.service.ts @@ -206,24 +206,24 @@ export class RealmService extends AbstractService { // Used in onboarding before a session exists. async uploadFile( args: FileUploadParams - ): Promise<{ Location: string; key: string } | undefined> { - if (!this.services) return; + ): Promise<{ Location: string; key: string } | null> { + if (!this.services?.ship) return null; - const credentials = this.services.ship?.credentials; + const credentials = this.services.ship.credentials; if (!credentials) { log.error('realm.service.ts:', 'No credentials found'); - return; + return null; } - const patp = this.services.ship?.patp; + const patp = this.services.ship.patp; if (!patp) { log.error('realm.service.ts:', 'No patp found'); - return; + return null; } - return this.services.ship?.uploadFile(args); + return this.services.ship.uploadFile(args); } async updatePassword(patp: string, password: string) { diff --git a/app/src/os/services/ship/ship.service.ts b/app/src/os/services/ship/ship.service.ts index c4f8adfab4..be88f1a1c2 100644 --- a/app/src/os/services/ship/ship.service.ts +++ b/app/src/os/services/ship/ship.service.ts @@ -297,8 +297,8 @@ export class ShipService extends AbstractService { }); return { credentials, configuration }; - } catch (e) { - log.error('ship.service.ts, getS3Bucket(): error getting credentials', e); + } catch { + log.error('ship.service.ts: Failed to get S3 bucket.'); return null; } @@ -306,52 +306,55 @@ export class ShipService extends AbstractService { public async uploadFile( args: FileUploadParams - ): Promise<{ Location: string; key: string }> { - return await new Promise((resolve, reject) => { - this.getS3Bucket() - .then(async (response) => { - console.log('getS3Bucket response: ', response); - if (!response) return; - // a little shim to handle people who accidentally included their bucket at the front of the credentials.endpoint - let endp = response.credentials.endpoint; - if (endp.split('.')[0] === response.configuration.currentBucket) { - endp = endp.split('.').slice(1).join('.'); - } - const client = new S3Client({ - credentials: response.credentials, - endpoint: endp, - signatureVersion: 'v4', - }); - let fileContent, fileName, fileExtension; - if (args.source === 'file' && typeof args.content === 'string') { - fileContent = fs.readFileSync(args.content); - const fileParts = args.content.split('.'); - fileName = fileParts.slice(0, -1); - // only take the filename, not the path - fileName = fileName[0].split('/').pop(); - fileExtension = fileParts.pop(); - } else if (args.source === 'buffer') { - fileContent = Buffer.from(args.content, 'base64'); - fileName = 'clipboard'; - fileExtension = args.contentType.split('/')[1]; - } - if (!fileContent) log.warn('No file content found'); - const key = `${ - this.patp - }/${moment().unix()}-${fileName}.${fileExtension}`; - const params = { - Bucket: response.configuration.currentBucket, - Key: key, - Body: fileContent as Buffer, - ACL: StorageAcl.PublicRead, - ContentType: args.contentType, - }; - const { Location } = await client.upload(params).promise(); - resolve({ Location, key }); - }) - .catch(reject); - }); + ): Promise<{ Location: string; key: string } | null> { + try { + const response = await this.getS3Bucket(); + if (!response) return null; + + // a little shim to handle people who accidentally included their bucket at the front of the credentials.endpoint + let endp = response.credentials.endpoint; + if (endp.split('.')[0] === response.configuration.currentBucket) { + endp = endp.split('.').slice(1).join('.'); + } + const client = new S3Client({ + credentials: response.credentials, + endpoint: endp, + signatureVersion: 'v4', + }); + let fileContent, fileName, fileExtension; + if (args.source === 'file' && typeof args.content === 'string') { + fileContent = fs.readFileSync(args.content); + const fileParts = args.content.split('.'); + fileName = fileParts.slice(0, -1); + // only take the filename, not the path + fileName = fileName[0].split('/').pop(); + fileExtension = fileParts.pop(); + } else if (args.source === 'buffer') { + fileContent = Buffer.from(args.content, 'base64'); + fileName = 'clipboard'; + fileExtension = args.contentType.split('/')[1]; + } + if (!fileContent) log.warn('No file content found'); + const key = `${ + this.patp + }/${moment().unix()}-${fileName}.${fileExtension}`; + const params = { + Bucket: response.configuration.currentBucket, + Key: key, + Body: fileContent as Buffer, + ACL: StorageAcl.PublicRead, + ContentType: args.contentType, + }; + const { Location } = await client.upload(params).promise(); + + return { Location, key }; + } catch { + log.error('ship.service.ts: Failed to upload file.'); + + return null; + } } + public async deleteFile(args: { key: string }): Promise { return await new Promise((resolve, reject) => { this.getS3Bucket() diff --git a/app/src/renderer/apps/System/panels/sections/AccountPassportSection.tsx b/app/src/renderer/apps/System/panels/sections/AccountPassportSection.tsx index 4a681d8bbf..f276853aeb 100644 --- a/app/src/renderer/apps/System/panels/sections/AccountPassportSection.tsx +++ b/app/src/renderer/apps/System/panels/sections/AccountPassportSection.tsx @@ -29,6 +29,7 @@ export const AccountPassportSection = ({ account }: Props) => { content: file.path, contentType: file.type, }); + if (!result) return null; return result.Location; }; diff --git a/shared/src/onboarding/components/PassportForm.tsx b/shared/src/onboarding/components/PassportForm.tsx index eb932e0128..1077e4435b 100644 --- a/shared/src/onboarding/components/PassportForm.tsx +++ b/shared/src/onboarding/components/PassportForm.tsx @@ -50,7 +50,7 @@ type Props = { setNickname: (nickname: string) => void; setDescription: (description: string) => void; setAvatarSrc: (src?: string) => void; - onUploadFile: (file: File) => Promise; + onUploadFile: (file: File) => Promise; }; export const PassportForm = ({ From 59c30a88d958b1dc4dd1fc4274e720f94757604b Mon Sep 17 00:00:00 2001 From: gdbroman <99gustaf@gmail.com> Date: Fri, 28 Jul 2023 12:15:32 +0200 Subject: [PATCH 2/2] Disable next button on Passport step if loading --- .../apps/Courier/components/ChatInputBox.tsx | 23 ++++++++++--------- .../onboarding/steps/PassportStep.tsx | 15 +++++++----- .../components/PassportCardAvatar.tsx | 2 +- .../dialogs/Passport/PassportDialog.tsx | 4 ++-- 4 files changed, 24 insertions(+), 20 deletions(-) diff --git a/app/src/renderer/apps/Courier/components/ChatInputBox.tsx b/app/src/renderer/apps/Courier/components/ChatInputBox.tsx index 2332387a34..2142762f8e 100644 --- a/app/src/renderer/apps/Courier/components/ChatInputBox.tsx +++ b/app/src/renderer/apps/Courier/components/ChatInputBox.tsx @@ -60,19 +60,20 @@ export const ChatInputBox = ({ }, [attachments]); const uploadFile = useCallback( - (params: FileUploadParams) => { + async (params: FileUploadParams) => { setIsUploading(true); setUploadError(''); - (ShipIPC.uploadFile(params) as Promise) - .then((data: { Location: string; key: string }) => { - console.log(data); - const url = data.Location; - setAttachment([...attachments, url]); - }) - .catch(() => { - setUploadError('Failed upload, please try again.'); - }) - .finally(() => setIsUploading(false)); + + try { + const data = await ShipIPC.uploadFile(params); + if (!data) throw new Error('Failed upload, please try again.'); + + setAttachment([...attachments, data.Location]); + } catch (e: string | any) { + setUploadError(e); + } finally { + setIsUploading(false); + } }, [attachments] ); diff --git a/app/src/renderer/onboarding/steps/PassportStep.tsx b/app/src/renderer/onboarding/steps/PassportStep.tsx index db0df7fcd3..7962692d15 100644 --- a/app/src/renderer/onboarding/steps/PassportStep.tsx +++ b/app/src/renderer/onboarding/steps/PassportStep.tsx @@ -1,6 +1,7 @@ import { useEffect, useState } from 'react'; import { track } from '@amplitude/analytics-browser'; +import { useToggle } from '@holium/design-system/util'; import { OnboardingStorage, PassportDialog } from '@holium/shared'; import { FileUploadParams } from '../../../os/services/ship/ship.service'; @@ -15,7 +16,7 @@ export const PassportStep = ({ setStep }: StepProps) => { const [nicknameSrc, setNickname] = useState(nickname); const [sigilColor, setSigilColor] = useState('#000000'); - const [isReady, setIsReady] = useState(false); + const loading = useToggle(true); const isHoliumHosted = serverType === 'hosted'; @@ -48,18 +49,18 @@ export const PassportStep = ({ setStep }: StepProps) => { OnboardingIPC.getPassport() .then((ourPassport) => { if (!ourPassport) { - setIsReady(true); + loading.toggleOff(); return; } setNickname(ourPassport?.nickname); setAvatarSrc(ourPassport?.avatar); setDescription(ourPassport?.bio); setSigilColor(ourPassport?.color); - setIsReady(true); + loading.toggleOff(); }) .catch((e) => { console.error(e); - setIsReady(true); + loading.toggleOff(); }); }, []); @@ -74,7 +75,9 @@ export const PassportStep = ({ setStep }: StepProps) => { contentType: file.type, }; const result = await RealmIPC.uploadFile(params); - return result?.Location; + if (!result) return null; + + return result.Location; }; const onBack = () => { @@ -117,7 +120,7 @@ export const PassportStep = ({ setStep }: StepProps) => { return ( void; - onUploadFile: (file: File) => Promise; + onUploadFile: (file: File) => Promise; }; export const PassportCardAvatar = ({ diff --git a/shared/src/onboarding/dialogs/Passport/PassportDialog.tsx b/shared/src/onboarding/dialogs/Passport/PassportDialog.tsx index 74626b0d6f..71c70c59e7 100644 --- a/shared/src/onboarding/dialogs/Passport/PassportDialog.tsx +++ b/shared/src/onboarding/dialogs/Passport/PassportDialog.tsx @@ -33,7 +33,7 @@ type Props = { prefilledNickname: string; prefilledDescription: string; prefilledAvatarSrc: string; - onUploadFile: (file: File) => Promise; + onUploadFile: (file: File) => Promise; onBack?: () => void; onNext: ( nickname: string, @@ -129,7 +129,7 @@ export const PassportDialog = ({ } onBack={onBack} - onNext={handleOnNext} + onNext={loading ? undefined : handleOnNext} /> ); };