Skip to content

Commit

Permalink
Merge pull request #1040 from internxt/release/staging-manage-upload
Browse files Browse the repository at this point in the history
[PB-1285]: release/manage-upload
  • Loading branch information
CandelR authored Feb 29, 2024
2 parents a935781 + 964e93c commit 90ffc56
Show file tree
Hide file tree
Showing 57 changed files with 1,510 additions and 342 deletions.
3 changes: 3 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import { PreviewFileItem } from './app/share/types';
import { FolderPath } from 'app/drive/types';
import { manager } from './app/utils/dnd-utils';
import { AppView } from 'app/core/types';
import useBeforeUnload from './hooks/useBeforeUnload';

interface AppProps {
isAuthenticated: boolean;
Expand All @@ -56,6 +57,8 @@ const App = (props: AppProps): JSX.Element => {
const skipSignupIfLoggedIn = params.get('skipSignupIfLoggedIn') === 'true';
const queryParameters = navigationService.history.location.search;

useBeforeUnload();

useEffect(() => {
initialState();
}, []);
Expand Down
8 changes: 8 additions & 0 deletions src/WebWorker.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
export const createUploadWebWorker = (): Worker => {
return new Worker(new URL('./upload.worker', import.meta.url), { type: 'module' });
};

export const WORKER_MESSAGE_STATES = {
SUCCESS: 'success',
ERROR: 'error',
ABORT: 'abort',
CHECK_UPLOAD_STATUS: 'checkUploadStatus',
UPLOAD_STATUS: 'uploadStatus',
};
3 changes: 3 additions & 0 deletions src/app/analytics/TrackingPlan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ export namespace TrackingPlan {
FileUploadError = 'Upload Error',
FileUploadCompleted = 'Upload Completed',
FileUploadAborted = 'Upload Aborted',
FileUploadPause = 'Upload Paused',
FileUploadResume = 'Upload Resumed',
FileUploadRetry = 'Upload Retried',
FileDownloadCompleted = 'Download Completed',
FileDownloadError = 'Download Error',
FileDownloadStarted = 'Download Started',
Expand Down
15 changes: 15 additions & 0 deletions src/app/analytics/services/analytics.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,18 @@ export function trackFileUploadAborted(properties: TrackingPlan.UploadAbortedPro
analytics.track(TrackingPlan.EventNames.FileUploadAborted, properties);
}

function trackFileUploadPaused(properties: TrackingPlan.UploadProperties): void {
analytics.track(TrackingPlan.EventNames.FileUploadPause, properties);
}

function trackFileUploadResumed(properties: TrackingPlan.UploadProperties): void {
analytics.track(TrackingPlan.EventNames.FileUploadResume, properties);
}

function trackFileUploadRetried(properties: TrackingPlan.UploadProperties): void {
analytics.track(TrackingPlan.EventNames.FileUploadRetry, properties);
}

export function trackFileDownloadStarted(properties: TrackingPlan.DownloadProperties): void {
analytics.track(TrackingPlan.EventNames.FileDownloadStarted, properties);
}
Expand Down Expand Up @@ -506,6 +518,9 @@ const analyticsService = {
trackFileUploadCompleted,
trackFileUploadAborted,
trackFileUploadError,
trackFileUploadPaused,
trackFileUploadResumed,
trackFileUploadRetried,
trackMoveItem,
trackDeleteItem,
trackOpenWelcomeFile,
Expand Down
2 changes: 1 addition & 1 deletion src/app/banners/BannerWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { UserSettings } from '@internxt/sdk/dist/shared/types/userSettings';
import Banner from './Banner';

const SHOW_BANNER_COOKIE_NAME = 'show_lifetime_soft_banner';
const OFFER_OFF_DAY = new Date('2024-02-29');
const OFFER_OFF_DAY = new Date('2024-03-04');

const BannerWrapper = (): JSX.Element => {
const [showBanner, setShowBanner] = useState(false);
Expand Down
25 changes: 0 additions & 25 deletions src/app/core/components/Navbar/Navbar.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
import React from 'react';
import { connect } from 'react-redux';
import { AppDispatch, RootState } from '../../../store';
import { userThunks } from '../../../store/slices/user';
import { uiActions } from '../../../store/slices/ui';
import { storageActions, storageSelectors } from '../../../store/slices/storage';
import validationService from '../../services/validation.service';
import { StorageFilters } from '../../../store/slices/storage/storage.model';
import { sessionSelectors } from '../../../store/slices/session/session.selectors';
import sessionThunks from '../../../store/slices/session/session.thunks';
import storageThunks from '../../../store/slices/storage/storage.thunks';
import { Workspace } from '../../types';
import { UserSettings } from '@internxt/sdk/dist/shared/types/userSettings';
import { TeamsSettings } from '../../../teams/types';
Expand Down Expand Up @@ -37,27 +33,6 @@ const Navbar = (props: NavbarProps) => {
// TODO: do search
};

const onSupportButtonClicked = (): void => {
window.open('https://help.internxt.com/');
};

const onChangeWorkspaceButtonClicked = (): void => {
const { dispatch, currentFolderId } = props;

dispatch(sessionThunks.changeWorkspaceThunk());
dispatch(storageThunks.resetNamePathThunk());
dispatch(storageThunks.fetchFolderContentThunk(currentFolderId));
dispatch(storageThunks.fetchRecentsThunk());
};

const onLogoutButtonClicked = (): void => {
props.dispatch(userThunks.logoutThunk());
};

const onInviteMemberClick = (): void => {
props.dispatch(uiActions.setIsInviteMemberDialogOpen(true));
};

const onSearchInputChange = (e: React.ChangeEvent<HTMLInputElement>): void => {
if (validationService.validateSearchText(e.target.value)) {
props.dispatch(
Expand Down
2 changes: 1 addition & 1 deletion src/app/core/config/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@
],
"database": {
"name": "app-database",
"version": 4,
"version": 5,
"provider": "indexed-db"
}
}
4 changes: 4 additions & 0 deletions src/app/core/services/socket.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ export default class RealtimeService {
return true;
}

removeAllListeners() {
this.socket?.removeAllListeners();
}

stop(): void {
console.log('[REALTIME] STOPING...');

Expand Down
6 changes: 6 additions & 0 deletions src/app/database/services/database.service/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import configService from '../../../core/services/config.service';
import { DriveItemData } from '../../../drive/types';
import indexedDBService from './indexed-db.service';
import { LRUCacheStruture } from './LRUCache';
import { TaskStatus } from '../../../tasks/types';

export enum DatabaseProvider {
IndexedDB = 'indexed-db',
Expand All @@ -15,6 +16,7 @@ export enum DatabaseCollection {
LevelsBlobs = 'levels_blobs',
LRU_cache = 'lru_cache',
Account_settings = 'account_settings',
UploadItemStatus = 'upload_item_status',
}

export enum LRUCacheTypes {
Expand Down Expand Up @@ -72,6 +74,10 @@ export interface AppDatabase extends DBSchema {
key: string;
value: AvatarBlobData;
};
upload_item_status: {
key: string;
value: TaskStatus;
};
}

export interface DatabaseService {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ const open = (name: string, version?: number): Promise<idb.IDBPDatabase<AppDatab
}
if (oldVersion <= 3) {
db.createObjectStore('account_settings');
db.createObjectStore('move_levels');
}
if (oldVersion <= 4) {
db.createObjectStore('move_levels');
db.createObjectStore('upload_item_status');
}
},
blocked: () => undefined,
Expand All @@ -27,6 +28,7 @@ const open = (name: string, version?: number): Promise<idb.IDBPDatabase<AppDatab

const indexedDBIsAvailable = async () =>
!(await browserService.isBrowser({ browser: Browser.Firefox, incognito: true }));

const indexedDBService: DatabaseService = (databaseName, databaseVersion) => ({
isAvailable: indexedDBIsAvailable,
put: async (collectionName, key, value) => {
Expand Down
19 changes: 3 additions & 16 deletions src/app/drive/components/DriveExplorer/DriveExplorer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -166,12 +166,6 @@ const DriveExplorer = (props: DriveExplorerProps): JSX.Element => {
const [openedWithRightClick, setOpenedWithRightClick] = useState(false);
const [dimensions, setDimensions] = useState({ width: 0, height: 0 });

// LISTEN NOTIFICATION STATES
const [folderListenerList, setFolderListenerList] = useState<number[]>([]);
const inProcessNotifications = useTaskManagerGetNotifications({
status: [TaskStatus.InProcess, TaskStatus.Encrypting],
});

// ONBOARDING TUTORIAL STATES
const [currentTutorialStep, setCurrentTutorialStep] = useState(0);
const [showSecondTutorialStep, setShowSecondTutorialStep] = useState(false);
Expand Down Expand Up @@ -207,8 +201,7 @@ const DriveExplorer = (props: DriveExplorerProps): JSX.Element => {
const handleFileCreatedEvent = (data) => {
if (data.event === SOCKET_EVENTS.FILE_CREATED) {
const folderId = data.payload.folderId;

if (folderId === currentFolderId && inProcessNotifications.length === 0) {
if (folderId === currentFolderId) {
dispatch(
storageActions.pushItems({
updateRecents: true,
Expand All @@ -219,11 +212,6 @@ const DriveExplorer = (props: DriveExplorerProps): JSX.Element => {
}
}
};
const handleOnEventCreation = () => {
const isEventCreated = realtimeService.onEvent(handleFileCreatedEvent);
if (isEventCreated) setFolderListenerList([...folderListenerList, currentFolderId]);
else setTimeout(handleOnEventCreation, 10000);
};

useEffect(() => {
if (itemToRename) {
Expand All @@ -233,9 +221,8 @@ const DriveExplorer = (props: DriveExplorerProps): JSX.Element => {

useEffect(() => {
try {
if (!folderListenerList.includes(currentFolderId)) {
handleOnEventCreation();
}
realtimeService.removeAllListeners();
realtimeService.onEvent(handleFileCreatedEvent);
} catch (err) {
errorService.reportError(err);
}
Expand Down
33 changes: 26 additions & 7 deletions src/app/drive/services/file.service/uploadFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ export async function uploadFile(
file: FileToUpload,
updateProgressCallback: (progress: number) => void,
options: FileUploadOptions,
continueUploadOptions: {
taskId: string;
isPaused: boolean;
isRetriedUpload: boolean;
},
): Promise<DriveFileData> {
const { bridgeUser, bridgePass, encryptionKey, bucketId } =
options.ownerUserAuthenticationData ?? getEnvironmentConfig(options.isTeam);
Expand All @@ -60,6 +65,10 @@ export async function uploadFile(
try {
analyticsService.trackFileUploadStarted(trackingUploadProperties);

if (continueUploadOptions?.isRetriedUpload) {
analyticsService.trackFileUploadRetried(trackingUploadProperties);
}

if (!bucketId) {
analyticsService.trackFileUploadError({
...trackingUploadProperties,
Expand All @@ -75,13 +84,23 @@ export async function uploadFile(
throw new Error('Bucket not found!');
}

const [promise, abort] = new Network(bridgeUser, bridgePass, encryptionKey).uploadFile(bucketId, {
filecontent: file.content,
filesize: file.size,
progressCallback: (progress) => {
updateProgressCallback(progress);
const analyticsCallbacks = {
pauseUploadCallback: () => analyticsService.trackFileUploadPaused(trackingUploadProperties),
resumeUploadCallback: () => analyticsService.trackFileUploadResumed(trackingUploadProperties),
};

const [promise, abort] = new Network(bridgeUser, bridgePass, encryptionKey).uploadFile(
bucketId,
{
filecontent: file.content,
filesize: file.size,
progressCallback: (progress) => {
updateProgressCallback(progress);
},
},
});
continueUploadOptions,
analyticsCallbacks,
);

options.abortCallback?.(abort?.abort);

Expand Down Expand Up @@ -110,7 +129,7 @@ export async function uploadFile(
}

const generatedThumbnail = await generateThumbnailFromFile(file, response.id, userEmail, options.isTeam);
if (generatedThumbnail && generatedThumbnail.thumbnail) {
if (generatedThumbnail?.thumbnail) {
response.thumbnails.push(generatedThumbnail.thumbnail);
if (generatedThumbnail.thumbnailFile) {
generatedThumbnail.thumbnail.urlObject = URL.createObjectURL(generatedThumbnail.thumbnailFile);
Expand Down
55 changes: 24 additions & 31 deletions src/app/drive/services/network.service/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ import { UserSettings } from '@internxt/sdk/dist/shared/types/userSettings';
import { TeamsSettings } from '../../../teams/types';
import { Abortable } from 'app/network/Abortable';
import { createUploadWebWorker } from '../../../../WebWorker';
import { createWorkerMessageHandlerPromise } from '../worker.service/uploadWorkerUtils';

export const MAX_ALLOWED_UPLOAD_SIZE = 20 * 1024 * 1024 * 1024;

type ProgressCallback = (progress: number, uploadedBytes: number | null, totalBytes: number | null) => void;
interface IUploadParams {
export interface IUploadParams {
filesize: number;
filecontent: File;
progressCallback: ProgressCallback;
Expand Down Expand Up @@ -74,7 +75,17 @@ export class Network {
* @param params Required params for uploading a file
* @returns Id of the created file
*/
uploadFile(bucketId: string, params: IUploadParams): [Promise<string>, Abortable | undefined] {
uploadFile(
bucketId: string,
params: IUploadParams,
continueUploadOptions: {
taskId: string;
},
analyticsServiceCallbacks?: {
pauseUploadCallback: () => void;
resumeUploadCallback: () => void;
},
): [Promise<string>, Abortable | undefined] {
if (!bucketId) {
throw new Error('Bucket id not provided');
}
Expand All @@ -84,42 +95,24 @@ export class Network {
}

const worker: Worker = createUploadWebWorker();
const payload: Omit<IUploadParams, 'progressCallback'> & { creds: any; mnemonic: string } = {
const payload: Omit<IUploadParams, 'progressCallback'> & {
creds: any;
mnemonic: string;
continueUploadOptions: {
taskId: string;
isPaused?: boolean;
};
} = {
filecontent: params.filecontent,
filesize: params.filesize,
creds: this.creds,
mnemonic: this.mnemonic,
continueUploadOptions,
};

worker.postMessage({ bucketId, params: payload, type: 'upload' });

return [
new Promise((resolve, reject) => {
worker.addEventListener('error', reject);
worker.addEventListener('message', (msg) => {
console.log('[MAIN_THREAD]: Message received from worker', msg);
if (msg.data.progress) {
params.progressCallback(msg.data.progress, msg.data.uploadedBytes, msg.data.totalBytes);
} else if (msg.data.result === 'success') {
resolve(msg.data.fileId);
worker.terminate();
} else if (msg.data.result === 'error') {
reject(msg.data.error);
worker.terminate();
} else if (msg.data.result == 'abort') {
console.warn('[MAIN_THREAD]: ABORT SIGNAL', msg.data.fileId);
reject(msg.data.result);
worker.terminate();
} else {
console.warn('[MAIN_THREAD]: Received unknown message from worker');
}
});
}),
{
abort: () => {
worker.postMessage({ type: 'upload', abort: true });
},
},
];
return createWorkerMessageHandlerPromise(worker, params, continueUploadOptions);
}

/**
Expand Down
3 changes: 2 additions & 1 deletion src/app/drive/services/thumbnail.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { Downloadable } from 'app/network/download';
import { storageActions } from 'app/store/slices/storage';
import { AppDispatch } from 'app/store';
import { pdfjs } from 'react-pdf';
import errorService from '../../core/services/error.service';

export interface ThumbnailToUpload {
fileId: number;
Expand Down Expand Up @@ -199,7 +200,7 @@ export const generateThumbnailFromFile = async (
};
}
} catch (error) {
console.log(error);
errorService.reportError(error);
}
}
return null;
Expand Down
Loading

0 comments on commit 90ffc56

Please sign in to comment.