commit
063797df55
|
@ -32,12 +32,13 @@ export default function ExportFinished(props: Props) {
|
||||||
<Label width="60%">{constants.SUCCESSFULLY_EXPORTED_FILES}</Label>
|
<Label width="60%">{constants.SUCCESSFULLY_EXPORTED_FILES}</Label>
|
||||||
<Value width="35%"><ComfySpan>{props.exportStats.success} / {totalFiles}</ComfySpan></Value>
|
<Value width="35%"><ComfySpan>{props.exportStats.success} / {totalFiles}</ComfySpan></Value>
|
||||||
</Row>
|
</Row>
|
||||||
|
{props.exportStats.failed>0 &&
|
||||||
<Row>
|
<Row>
|
||||||
<Label width="60%">{constants.FAILED_EXPORTED_FILES}</Label>
|
<Label width="60%">{constants.FAILED_EXPORTED_FILES}</Label>
|
||||||
<Value width="35%">
|
<Value width="35%">
|
||||||
<ComfySpan>{props.exportStats.failed} / {totalFiles}</ComfySpan>
|
<ComfySpan>{props.exportStats.failed} / {totalFiles}</ComfySpan>
|
||||||
</Value>
|
</Value>
|
||||||
</Row>
|
</Row>}
|
||||||
</div>
|
</div>
|
||||||
<div style={{ width: '100%', display: 'flex', justifyContent: 'space-around' }}>
|
<div style={{ width: '100%', display: 'flex', justifyContent: 'space-around' }}>
|
||||||
<Button block variant={'outline-secondary'} onClick={props.onHide}>{constants.CLOSE}</Button>
|
<Button block variant={'outline-secondary'} onClick={props.onHide}>{constants.CLOSE}</Button>
|
||||||
|
|
|
@ -26,7 +26,18 @@ const FolderIconWrapper = styled.div`
|
||||||
&:hover{
|
&:hover{
|
||||||
background-color:#444;
|
background-color:#444;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const ExportFolderPathContainer =styled.span`
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
width: 200px;
|
||||||
|
|
||||||
|
/* Beginning of string */
|
||||||
|
direction: rtl;
|
||||||
|
text-align: left;
|
||||||
|
`;
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
show: boolean
|
show: boolean
|
||||||
|
@ -88,7 +99,6 @@ export default function ExportModal(props: Props) {
|
||||||
updateExportProgress({ current: exportedFileCnt + failedFilesCnt, total: syncedFilesCnt });
|
updateExportProgress({ current: exportedFileCnt + failedFilesCnt, total: syncedFilesCnt });
|
||||||
const exportFileUIDs = new Set([...exportRecord.exportedFiles, ...exportRecord.failedFiles]);
|
const exportFileUIDs = new Set([...exportRecord.exportedFiles, ...exportRecord.failedFiles]);
|
||||||
const unExportedFiles = localFiles.filter((file) => !exportFileUIDs.has(getFileUID(file)));
|
const unExportedFiles = localFiles.filter((file) => !exportFileUIDs.has(getFileUID(file)));
|
||||||
console.log(exportedFileCnt + failedFilesCnt + unExportedFiles.length, syncedFilesCnt);
|
|
||||||
exportService.addFilesQueuedRecord(exportFolder, unExportedFiles);
|
exportService.addFilesQueuedRecord(exportFolder, unExportedFiles);
|
||||||
updateExportStage(ExportStage.PAUSED);
|
updateExportStage(ExportStage.PAUSED);
|
||||||
}
|
}
|
||||||
|
@ -266,11 +276,13 @@ export default function ExportModal(props: Props) {
|
||||||
<Label width="40%">{constants.DESTINATION}</Label>
|
<Label width="40%">{constants.DESTINATION}</Label>
|
||||||
<Value width="60%">
|
<Value width="60%">
|
||||||
{!exportFolder ?
|
{!exportFolder ?
|
||||||
(<Button variant={'outline-success'} onClick={selectExportDirectory}>{constants.SELECT_FOLDER}</Button>) :
|
(<Button variant={'outline-success'} size={'sm'} onClick={selectExportDirectory}>{constants.SELECT_FOLDER}</Button>) :
|
||||||
(<>
|
(<>
|
||||||
<span style={{ overflow: 'hidden', direction: 'rtl', height: '1.5rem', width: '90%', whiteSpace: 'nowrap' }}>
|
{/* <span style={{ overflow: 'hidden', direction: 'rtl', height: '1.5rem', width: '90%', whiteSpace: 'nowrap' }}> */}
|
||||||
|
<ExportFolderPathContainer>
|
||||||
{exportFolder}
|
{exportFolder}
|
||||||
</span>
|
</ExportFolderPathContainer>
|
||||||
|
{/* </span> */}
|
||||||
{(exportStage === ExportStage.FINISHED || exportStage === ExportStage.INIT) && (
|
{(exportStage === ExportStage.FINISHED || exportStage === ExportStage.INIT) && (
|
||||||
<FolderIconWrapper onClick={selectExportDirectory} >
|
<FolderIconWrapper onClick={selectExportDirectory} >
|
||||||
<FolderIcon />
|
<FolderIcon />
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { getEndpoint } from 'utils/common/apiUtil';
|
||||||
import { getStripePublishableKey, getToken } from 'utils/common/key';
|
import { getStripePublishableKey, getToken } from 'utils/common/key';
|
||||||
import { checkConnectivity, runningInBrowser } from 'utils/common/';
|
import { checkConnectivity, runningInBrowser } from 'utils/common/';
|
||||||
import { setData, LS_KEYS } from 'utils/storage/localStorage';
|
import { setData, LS_KEYS } from 'utils/storage/localStorage';
|
||||||
import { convertBytesToGBs } from 'utils/billingUtil';
|
import { convertToHumanReadable } from 'utils/billingUtil';
|
||||||
import { loadStripe, Stripe } from '@stripe/stripe-js';
|
import { loadStripe, Stripe } from '@stripe/stripe-js';
|
||||||
import { SUBSCRIPTION_VERIFICATION_ERROR } from 'utils/common/errorUtil';
|
import { SUBSCRIPTION_VERIFICATION_ERROR } from 'utils/common/errorUtil';
|
||||||
import HTTPService from './HTTPService';
|
import HTTPService from './HTTPService';
|
||||||
|
@ -242,7 +242,7 @@ class billingService {
|
||||||
'X-Auth-Token': getToken(),
|
'X-Auth-Token': getToken(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
return convertBytesToGBs(response.data.usage);
|
return convertToHumanReadable(response.data.usage);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logError(e, 'error getting usage');
|
logError(e, 'error getting usage');
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,10 @@ export enum ExportType {
|
||||||
PENDING,
|
PENDING,
|
||||||
RETRY_FAILED
|
RETRY_FAILED
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ExportRecordFileName='export_status.json';
|
||||||
|
const MetadataFolderName='metadata';
|
||||||
|
|
||||||
class ExportService {
|
class ExportService {
|
||||||
ElectronAPIs: any;
|
ElectronAPIs: any;
|
||||||
|
|
||||||
|
@ -124,6 +128,9 @@ class ExportService {
|
||||||
await this.ElectronAPIs.checkExistsAndCreateCollectionDir(
|
await this.ElectronAPIs.checkExistsAndCreateCollectionDir(
|
||||||
collectionFolderPath,
|
collectionFolderPath,
|
||||||
);
|
);
|
||||||
|
await this.ElectronAPIs.checkExistsAndCreateCollectionDir(
|
||||||
|
`${collectionFolderPath}/${MetadataFolderName}`,
|
||||||
|
);
|
||||||
collectionIDMap.set(collection.id, collectionFolderPath);
|
collectionIDMap.set(collection.id, collectionFolderPath);
|
||||||
}
|
}
|
||||||
for (const [index, file] of files.entries()) {
|
for (const [index, file] of files.entries()) {
|
||||||
|
@ -137,12 +144,9 @@ class ExportService {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
const uid = `${file.id}_${this.sanitizeName(
|
const collectionPath = collectionIDMap.get(file.collectionID);
|
||||||
file.metadata.title,
|
|
||||||
)}`;
|
|
||||||
const filePath = `${collectionIDMap.get(file.collectionID)}/${uid}`;
|
|
||||||
try {
|
try {
|
||||||
await this.downloadAndSave(file, filePath);
|
await this.downloadAndSave(file, collectionPath);
|
||||||
await this.addFileExportRecord(dir, file, RecordType.SUCCESS);
|
await this.addFileExportRecord(dir, file, RecordType.SUCCESS);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
await this.addFileExportRecord(dir, file, RecordType.FAILED);
|
await this.addFileExportRecord(dir, file, RecordType.FAILED);
|
||||||
|
@ -222,7 +226,7 @@ class ExportService {
|
||||||
}
|
}
|
||||||
const exportRecord = await this.getExportRecord(folder);
|
const exportRecord = await this.getExportRecord(folder);
|
||||||
const newRecord = { ...exportRecord, ...newData };
|
const newRecord = { ...exportRecord, ...newData };
|
||||||
await this.ElectronAPIs.setExportRecord(folder, JSON.stringify(newRecord, null, 2));
|
await this.ElectronAPIs.setExportRecord(`${folder}/${ExportRecordFileName}`, JSON.stringify(newRecord, null, 2));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logError(e, 'error updating Export Record');
|
logError(e, 'error updating Export Record');
|
||||||
}
|
}
|
||||||
|
@ -235,7 +239,7 @@ class ExportService {
|
||||||
if (!folder) {
|
if (!folder) {
|
||||||
folder = getData(LS_KEYS.EXPORT)?.folder;
|
folder = getData(LS_KEYS.EXPORT)?.folder;
|
||||||
}
|
}
|
||||||
const recordFile = await this.ElectronAPIs.getExportRecord(folder);
|
const recordFile = await this.ElectronAPIs.getExportRecord(`${folder}/${ExportRecordFileName}`);
|
||||||
if (recordFile) {
|
if (recordFile) {
|
||||||
return JSON.parse(recordFile);
|
return JSON.parse(recordFile);
|
||||||
} else {
|
} else {
|
||||||
|
@ -246,11 +250,14 @@ class ExportService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async downloadAndSave(file: File, path) {
|
async downloadAndSave(file: File, collectionPath:string) {
|
||||||
|
const uid = `${file.id}_${this.sanitizeName(
|
||||||
|
file.metadata.title,
|
||||||
|
)}`;
|
||||||
const fileStream = await retryPromise(downloadManager.downloadFile(file));
|
const fileStream = await retryPromise(downloadManager.downloadFile(file));
|
||||||
this.ElectronAPIs.saveStreamToDisk(path, fileStream);
|
this.ElectronAPIs.saveStreamToDisk(`${collectionPath}/${uid}`, fileStream);
|
||||||
this.ElectronAPIs.saveFileToDisk(
|
this.ElectronAPIs.saveFileToDisk(
|
||||||
`${path}.json`,
|
`${collectionPath}/${MetadataFolderName}/${uid}.json`,
|
||||||
JSON.stringify(file.metadata, null, 2),
|
JSON.stringify(file.metadata, null, 2),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,14 @@ const STRIPE = 'stripe';
|
||||||
export function convertBytesToGBs(bytes, precision?): string {
|
export function convertBytesToGBs(bytes, precision?): string {
|
||||||
return (bytes / (1024 * 1024 * 1024)).toFixed(precision ?? 2);
|
return (bytes / (1024 * 1024 * 1024)).toFixed(precision ?? 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function convertToHumanReadable(bytes:number, precision=2): string {
|
||||||
|
const i = Math.floor(Math.log(bytes) / Math.log(1024));
|
||||||
|
const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
||||||
|
|
||||||
|
return (bytes / Math.pow(1024, i)).toFixed(precision)+ ' ' + sizes[i];
|
||||||
|
}
|
||||||
|
|
||||||
export function hasPaidSubscription(subscription?: Subscription) {
|
export function hasPaidSubscription(subscription?: Subscription) {
|
||||||
subscription = subscription ?? getUserSubscription();
|
subscription = subscription ?? getUserSubscription();
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { ExportRecord } from 'services/exportService';
|
||||||
import { File } from 'services/fileService';
|
import { File } from 'services/fileService';
|
||||||
|
|
||||||
|
|
||||||
export const getFileUID = (file: File) => `${file.id}_${file.collectionID}`;
|
export const getFileUID = (file: File) => `${file.id}_${file.collectionID}_${file.updationTime}`;
|
||||||
|
|
||||||
|
|
||||||
export const getExportPendingFiles = async (allFiles: File[], exportRecord: ExportRecord) => {
|
export const getExportPendingFiles = async (allFiles: File[], exportRecord: ExportRecord) => {
|
||||||
|
|
|
@ -260,7 +260,7 @@ const englishConstants = {
|
||||||
<p>
|
<p>
|
||||||
you have used {usage}
|
you have used {usage}
|
||||||
{' '}
|
{' '}
|
||||||
GB out of your {quota}
|
out of your {quota}
|
||||||
{' '}
|
{' '}
|
||||||
GB quota
|
GB quota
|
||||||
</p>
|
</p>
|
||||||
|
@ -439,10 +439,10 @@ const englishConstants = {
|
||||||
RESUME: 'resume',
|
RESUME: 'resume',
|
||||||
MINIMIZE: 'minimize',
|
MINIMIZE: 'minimize',
|
||||||
LAST_EXPORT_TIME: 'last export time',
|
LAST_EXPORT_TIME: 'last export time',
|
||||||
SUCCESSFULLY_EXPORTED_FILES: 'successfully exported files',
|
SUCCESSFULLY_EXPORTED_FILES: 'successful exports',
|
||||||
FAILED_EXPORTED_FILES: 'failed file export',
|
FAILED_EXPORTED_FILES: 'failed exports',
|
||||||
EXPORT_AGAIN: 'export new data ',
|
EXPORT_AGAIN: 'resync',
|
||||||
RETRY_EXPORT_: 'retry failed files ',
|
RETRY_EXPORT_: 'retry failed exports',
|
||||||
LOCAL_STORAGE_NOT_ACCESSIBLE: 'local storage not accessible',
|
LOCAL_STORAGE_NOT_ACCESSIBLE: 'local storage not accessible',
|
||||||
LOCAL_STORAGE_NOT_ACCESSIBLE_MESSAGE: 'your browser or an addon is blocking ente from saving data into local storage. please try loading this page after switching your browsing mode.',
|
LOCAL_STORAGE_NOT_ACCESSIBLE_MESSAGE: 'your browser or an addon is blocking ente from saving data into local storage. please try loading this page after switching your browsing mode.',
|
||||||
RETRY: 'retry',
|
RETRY: 'retry',
|
||||||
|
|
Loading…
Reference in a new issue