mirror of
https://github.com/XFox111/TabsAsideExtension.git
synced 2026-04-22 07:58:01 +03:00
feat: ability to disable cloud collection storage
This commit is contained in:
@@ -1,4 +1,6 @@
|
|||||||
import { useDialog } from "@/contexts/DialogProvider";
|
import { useDialog } from "@/contexts/DialogProvider";
|
||||||
|
import { cloudDisabled, setCloudStorage } from "@/features/collectionStorage";
|
||||||
|
import { useDangerStyles } from "@/hooks/useDangerStyles";
|
||||||
import useStorageInfo from "@/hooks/useStorageInfo";
|
import useStorageInfo from "@/hooks/useStorageInfo";
|
||||||
import { Button, Field, MessageBar, MessageBarBody, MessageBarTitle, ProgressBar } from "@fluentui/react-components";
|
import { Button, Field, MessageBar, MessageBarBody, MessageBarTitle, ProgressBar } from "@fluentui/react-components";
|
||||||
import { ArrowDownload20Regular, ArrowUpload20Regular } from "@fluentui/react-icons";
|
import { ArrowDownload20Regular, ArrowUpload20Regular } from "@fluentui/react-icons";
|
||||||
@@ -10,9 +12,17 @@ export default function StorageSection(): React.ReactElement
|
|||||||
{
|
{
|
||||||
const { bytesInUse, storageQuota, usedStorageRatio } = useStorageInfo();
|
const { bytesInUse, storageQuota, usedStorageRatio } = useStorageInfo();
|
||||||
const [importResult, setImportResult] = useState<boolean | null>(null);
|
const [importResult, setImportResult] = useState<boolean | null>(null);
|
||||||
|
const [isCloudDisabled, setCloudDisabled] = useState<boolean>(null!);
|
||||||
|
|
||||||
const dialog = useDialog();
|
const dialog = useDialog();
|
||||||
const cls = useOptionsStyles();
|
const cls = useOptionsStyles();
|
||||||
|
const dangerCls = useDangerStyles();
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
cloudDisabled.getValue().then(setCloudDisabled);
|
||||||
|
return cloudDisabled.watch(setCloudDisabled);
|
||||||
|
}, []);
|
||||||
|
|
||||||
const handleImport = (): void =>
|
const handleImport = (): void =>
|
||||||
dialog.pushPrompt({
|
dialog.pushPrompt({
|
||||||
@@ -30,15 +40,32 @@ export default function StorageSection(): React.ReactElement
|
|||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const handleDisableCloud = (): void =>
|
||||||
|
dialog.pushPrompt({
|
||||||
|
title: i18n.t("options_page.storage.disable"),
|
||||||
|
content: i18n.t("options_page.storage.disable_prompt.text"),
|
||||||
|
confirmText: i18n.t("options_page.storage.disable_prompt.action"),
|
||||||
|
destructive: true,
|
||||||
|
onConfirm: () => setCloudStorage(false)
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Field
|
{ isCloudDisabled === false &&
|
||||||
label={ i18n.t("options_page.storage.capacity.title") }
|
<Field
|
||||||
hint={ i18n.t("options_page.storage.capacity.description", [(bytesInUse / 1024).toFixed(1), storageQuota / 1024]) }
|
label={ i18n.t("options_page.storage.capacity.title") }
|
||||||
validationState={ usedStorageRatio >= 0.8 ? "error" : undefined }
|
hint={ i18n.t("options_page.storage.capacity.description", [(bytesInUse / 1024).toFixed(1), storageQuota / 1024]) }
|
||||||
>
|
validationState={ usedStorageRatio >= 0.8 ? "error" : undefined }
|
||||||
<ProgressBar value={ usedStorageRatio } thickness="large" />
|
>
|
||||||
</Field>
|
<ProgressBar value={ usedStorageRatio } thickness="large" />
|
||||||
|
</Field>
|
||||||
|
}
|
||||||
|
|
||||||
|
{ isCloudDisabled === true &&
|
||||||
|
<Button appearance="primary" onClick={ () => setCloudStorage(true) }>
|
||||||
|
{ i18n.t("options_page.storage.enable") }
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
|
|
||||||
<div className={ cls.horizontalButtons }>
|
<div className={ cls.horizontalButtons }>
|
||||||
<Button icon={ <ArrowDownload20Regular /> } onClick={ exportData }>
|
<Button icon={ <ArrowDownload20Regular /> } onClick={ exportData }>
|
||||||
@@ -59,6 +86,17 @@ export default function StorageSection(): React.ReactElement
|
|||||||
</MessageBarBody>
|
</MessageBarBody>
|
||||||
</MessageBar>
|
</MessageBar>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{ isCloudDisabled === false &&
|
||||||
|
<div className={ cls.horizontalButtons }>
|
||||||
|
<Button
|
||||||
|
appearance="subtle" className={ dangerCls.buttonSubtle }
|
||||||
|
onClick={ handleDisableCloud }
|
||||||
|
>
|
||||||
|
{ i18n.t("options_page.storage.disable") }
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ export * from "./utils/getCollections";
|
|||||||
export { default as getCollections } from "./utils/getCollections";
|
export { default as getCollections } from "./utils/getCollections";
|
||||||
export { default as resoveConflict } from "./utils/resolveConflict";
|
export { default as resoveConflict } from "./utils/resolveConflict";
|
||||||
export { default as saveCollections } from "./utils/saveCollections";
|
export { default as saveCollections } from "./utils/saveCollections";
|
||||||
|
export { default as setCloudStorage } from "./utils/setCloudStorage";
|
||||||
|
|
||||||
export const collectionCount = collectionStorage.count;
|
export const collectionCount = collectionStorage.count;
|
||||||
export const graphics = collectionStorage.graphics;
|
export const graphics = collectionStorage.graphics;
|
||||||
|
|
||||||
|
export const cloudDisabled = collectionStorage.disableCloud;
|
||||||
|
|||||||
@@ -8,5 +8,6 @@ export const collectionStorage =
|
|||||||
localCollections: storage.defineItem<CollectionItem[]>("local:collections", { fallback: [] }),
|
localCollections: storage.defineItem<CollectionItem[]>("local:collections", { fallback: [] }),
|
||||||
count: storage.defineItem<number>("local:count", { fallback: 0 }),
|
count: storage.defineItem<number>("local:count", { fallback: 0 }),
|
||||||
graphics: storage.defineItem<GraphicsStorage>("local:graphics", { fallback: {} }),
|
graphics: storage.defineItem<GraphicsStorage>("local:graphics", { fallback: {} }),
|
||||||
|
disableCloud: storage.defineItem<boolean>("sync:disableCloud", { fallback: false }),
|
||||||
maxChunkCount: 12
|
maxChunkCount: 12
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,14 +1,17 @@
|
|||||||
import { CollectionItem } from "@/models/CollectionModels";
|
import { CollectionItem } from "@/models/CollectionModels";
|
||||||
|
import getLogger from "@/utils/getLogger";
|
||||||
import { collectionStorage } from "./collectionStorage";
|
import { collectionStorage } from "./collectionStorage";
|
||||||
import getCollectionsFromCloud from "./getCollectionsFromCloud";
|
import getCollectionsFromCloud from "./getCollectionsFromCloud";
|
||||||
import getCollectionsFromLocal from "./getCollectionsFromLocal";
|
import getCollectionsFromLocal from "./getCollectionsFromLocal";
|
||||||
import saveCollectionsToLocal from "./saveCollectionsToLocal";
|
import saveCollectionsToLocal from "./saveCollectionsToLocal";
|
||||||
import getLogger from "@/utils/getLogger";
|
|
||||||
|
|
||||||
const logger = getLogger("getCollections");
|
const logger = getLogger("getCollections");
|
||||||
|
|
||||||
export default async function getCollections(): Promise<[CollectionItem[], CloudStorageIssueType | null]>
|
export default async function getCollections(): Promise<[CollectionItem[], CloudStorageIssueType | null]>
|
||||||
{
|
{
|
||||||
|
if (await collectionStorage.disableCloud.getValue() === true)
|
||||||
|
return [await getCollectionsFromLocal(), null];
|
||||||
|
|
||||||
const lastUpdatedLocal: number = await collectionStorage.localLastUpdated.getValue();
|
const lastUpdatedLocal: number = await collectionStorage.localLastUpdated.getValue();
|
||||||
const lastUpdatedSync: number = await collectionStorage.syncLastUpdated.getValue();
|
const lastUpdatedSync: number = await collectionStorage.syncLastUpdated.getValue();
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { CollectionItem, GraphicsStorage } from "@/models/CollectionModels";
|
import { CollectionItem, GraphicsStorage } from "@/models/CollectionModels";
|
||||||
import getLogger from "@/utils/getLogger";
|
import getLogger from "@/utils/getLogger";
|
||||||
import sendNotification from "@/utils/sendNotification";
|
import sendNotification from "@/utils/sendNotification";
|
||||||
|
import { collectionStorage } from "./collectionStorage";
|
||||||
import saveCollectionsToCloud from "./saveCollectionsToCloud";
|
import saveCollectionsToCloud from "./saveCollectionsToCloud";
|
||||||
import saveCollectionsToLocal from "./saveCollectionsToLocal";
|
import saveCollectionsToLocal from "./saveCollectionsToLocal";
|
||||||
import updateGraphics from "./updateGraphics";
|
import updateGraphics from "./updateGraphics";
|
||||||
@@ -16,7 +17,7 @@ export default async function saveCollections(
|
|||||||
const timestamp: number = Date.now();
|
const timestamp: number = Date.now();
|
||||||
await saveCollectionsToLocal(collections, timestamp);
|
await saveCollectionsToLocal(collections, timestamp);
|
||||||
|
|
||||||
if (updateCloud)
|
if (updateCloud && await collectionStorage.disableCloud.getValue() !== true)
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await saveCollectionsToCloud(collections, timestamp);
|
await saveCollectionsToCloud(collections, timestamp);
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import { collectionStorage } from "./collectionStorage";
|
||||||
|
import saveCollectionsToCloud from "./saveCollectionsToCloud";
|
||||||
|
|
||||||
|
export default async function setCloudStorage(enable: boolean): Promise<void>
|
||||||
|
{
|
||||||
|
if (enable)
|
||||||
|
{
|
||||||
|
await collectionStorage.disableCloud.setValue(false);
|
||||||
|
const collections = await collectionStorage.localCollections.getValue();
|
||||||
|
const lastUpdated = await collectionStorage.localLastUpdated.getValue();
|
||||||
|
await saveCollectionsToCloud(collections, lastUpdated);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await collectionStorage.disableCloud.setValue(true);
|
||||||
|
await saveCollectionsToCloud([], 0);
|
||||||
|
browser.runtime.reload();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,5 +24,19 @@ export const useDangerStyles = makeStyles({
|
|||||||
backgroundColor: tokens.colorStatusDangerBackground3Pressed
|
backgroundColor: tokens.colorStatusDangerBackground3Pressed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
buttonSubtle:
|
||||||
|
{
|
||||||
|
color: tokens.colorStatusDangerForeground1,
|
||||||
|
|
||||||
|
"&:hover":
|
||||||
|
{
|
||||||
|
color: tokens.colorStatusDangerForeground2,
|
||||||
|
|
||||||
|
"&:active":
|
||||||
|
{
|
||||||
|
color: tokens.colorStatusDangerForeground3
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -116,6 +116,11 @@ options_page:
|
|||||||
warning_title: "This is an irreversible action"
|
warning_title: "This is an irreversible action"
|
||||||
warning_text: "This will overwrite all your data. Make sure you picked a correct file, otherwise data corruption or loss may occur. It is recommended to export data first."
|
warning_text: "This will overwrite all your data. Make sure you picked a correct file, otherwise data corruption or loss may occur. It is recommended to export data first."
|
||||||
proceed: "Pick a file"
|
proceed: "Pick a file"
|
||||||
|
enable: "Enable cloud storage"
|
||||||
|
disable: "Disable cloud storage"
|
||||||
|
disable_prompt:
|
||||||
|
text: "This action will disable collection synchronization between your devices. Extension's settings will still be synchronized."
|
||||||
|
action: "Disable and reload the extension"
|
||||||
about:
|
about:
|
||||||
title: "About"
|
title: "About"
|
||||||
developed_by: "Developed by Eugene Fox"
|
developed_by: "Developed by Eugene Fox"
|
||||||
|
|||||||
@@ -116,6 +116,11 @@ options_page:
|
|||||||
warning_title: "Это необратимое действие!"
|
warning_title: "Это необратимое действие!"
|
||||||
warning_text: "Оно перезапишет все ваши данные. Убедитесь, что вы выбрали правильный файл, иначе это может привести к повреждению или потере данных. Рекомендуется сначала экспортировать данные."
|
warning_text: "Оно перезапишет все ваши данные. Убедитесь, что вы выбрали правильный файл, иначе это может привести к повреждению или потере данных. Рекомендуется сначала экспортировать данные."
|
||||||
proceed: "Выбрать файл"
|
proceed: "Выбрать файл"
|
||||||
|
enable: "Включить облачное хранилище"
|
||||||
|
disable: "Отключить облачное хранилище"
|
||||||
|
disable_prompt:
|
||||||
|
text: "Это действие отключит синхронизацию коллекций между вашими устройствами. Настройки расширения продолжат храниться в облаке."
|
||||||
|
action: "Отключить и перезагрузить расширение"
|
||||||
about:
|
about:
|
||||||
title: "О расширении"
|
title: "О расширении"
|
||||||
developed_by: "Разработчик: Евгений Лис"
|
developed_by: "Разработчик: Евгений Лис"
|
||||||
|
|||||||
@@ -116,6 +116,11 @@ options_page:
|
|||||||
warning_title: "Це незворотна дія!"
|
warning_title: "Це незворотна дія!"
|
||||||
warning_text: "Вона перезапише всі ваші дані. Переконайтеся, що ви вибрали правильний файл, інакше це може призвести до пошкодження або втрати даних. Рекомендується спочатку експортувати дані."
|
warning_text: "Вона перезапише всі ваші дані. Переконайтеся, що ви вибрали правильний файл, інакше це може призвести до пошкодження або втрати даних. Рекомендується спочатку експортувати дані."
|
||||||
proceed: "Вибрати файл"
|
proceed: "Вибрати файл"
|
||||||
|
disable: "Вимкнути хмарне сховище"
|
||||||
|
enable: "Увімкнути хмарне сховище"
|
||||||
|
disable_prompt:
|
||||||
|
text: "Ця дія вимкне синхронізацію колекцій між вашими пристроями. Налаштування продовжать зберігатися у хмарі."
|
||||||
|
action: "Вимкнути та перезавантажити розширення"
|
||||||
about:
|
about:
|
||||||
title: "О розширенні"
|
title: "О розширенні"
|
||||||
developed_by: "Розробник: Євген Лис"
|
developed_by: "Розробник: Євген Лис"
|
||||||
|
|||||||
Reference in New Issue
Block a user