1
0
mirror of https://github.com/XFox111/TabsAsideExtension.git synced 2026-04-22 07:58:01 +03:00

feat: Minor 3.1.0 (#150)

* Some features are now optional (#148)

* fix(dev): yarn.lock tree fix

* feat: bookmarks moved to optional permissions

* fix: analytics not working in firefox

* feat!: ability to turn off analytics (uses permissions on firefox)

* feat: analytics tracker for bookmark export

* feat: add privacy policy link in about section

* docs: privacy policy update

* feat: ability to chain multiple dialogs

* fix(loc): analytics option translation

* feat: settings review dialog

* fix: background script fails to load because of frontend code

* chore: use analytics permission as storage value

* fix: inverted analytics value

* feat!: option to disable thumbnail capture

* fix(ci): sed typo

* fix: minor fixes

* fix(firefox): web-ext lint error fix

* chore(ci): switch web-ext action

* chore(lint): fix eslint warnings

* chore(deps): monthly dependency bump (September 2025) (#149)

* chore: 3.1.0 version bump

* chore: minor cleanup

* fix: allow analytics checkbox stays inactive after denying permission on firefox

* fix(deps): yarn.lock rebuild

* fix: type assertion for userId

* fix: settings review dialog not showing if welcome dialog is not required

* fix: analytics and thumbnail capture toggles react incorrectly if permission is denied
This commit is contained in:
2025-09-09 12:24:01 +03:00
committed by GitHub
parent 735089eb59
commit e21022d985
46 changed files with 2510 additions and 2369 deletions
@@ -34,5 +34,12 @@ export const useOptionsStyles = makeStyles({
display: "flex",
flexWrap: "wrap",
gap: tokens.spacingHorizontalS
},
group:
{
display: "flex",
flexFlow: "column",
alignItems: "flex-start",
gap: tokens.spacingVerticalSNudge
}
});
+2 -1
View File
@@ -34,7 +34,8 @@ export default function AboutSection(): React.ReactElement
<Body1 as="p">
<Link { ...extLink(websiteLink) }>{ i18n.t("options_page.about.links.website") }</Link><br />
<Link { ...extLink(githubLinks.repo) }>{ i18n.t("options_page.about.links.source") }</Link><br />
<Link { ...extLink(githubLinks.release) }>{ i18n.t("options_page.about.links.changelog") }</Link>
<Link { ...extLink(githubLinks.release) }>{ i18n.t("options_page.about.links.changelog") }</Link><br />
<Link { ...extLink(githubLinks.privacy) }>{ i18n.t("options_page.about.links.privacy") }</Link>
</Body1>
<div className={ cls.horizontalButtons }>
@@ -2,6 +2,7 @@ import useSettings, { SettingsValue } from "@/hooks/useSettings";
import { Button, Checkbox, Dropdown, Field, Option, OptionOnSelectData } from "@fluentui/react-components";
import { KeyCommand20Regular } from "@fluentui/react-icons";
import { useOptionsStyles } from "../hooks/useOptionsStyles";
import { analyticsPermission } from "@/features/analytics";
export default function GeneralSection(): React.ReactElement
{
@@ -14,8 +15,23 @@ export default function GeneralSection(): React.ReactElement
const [listLocation, setListLocation] = useSettings("listLocation");
const [contextAction, setContextAction] = useSettings("contextAction");
const [allowAnalytics, setAllowAnalytics] = useState<boolean | null>(null);
const cls = useOptionsStyles();
useEffect(() =>
{
analyticsPermission.getValue().then(setAllowAnalytics);
return analyticsPermission.watch(setAllowAnalytics);
}, []);
const updateAnalytics = (enabled: boolean): void =>
{
setAllowAnalytics(null);
analyticsPermission.setValue(enabled)
.catch(() => setAllowAnalytics(!enabled));
};
const openShortcutsPage = (): Promise<any> =>
browser.tabs.create({
url: "chrome://extensions/shortcuts",
@@ -60,6 +76,12 @@ export default function GeneralSection(): React.ReactElement
label={ i18n.t("options_page.general.options.unload_tabs") }
checked={ dismissOnLoad ?? false }
onChange={ (_, e) => setDismissOnLoad(e.checked as boolean) } />
<Checkbox
label={ i18n.t("options_page.general.options.allow_analytics") }
checked={ allowAnalytics ?? true }
disabled={ allowAnalytics === null }
onChange={ (_, e) => updateAnalytics(e.checked as boolean) } />
</section>
<Field label={ i18n.t("options_page.general.options.list_locations.title") }>
+53 -3
View File
@@ -1,18 +1,20 @@
import { useDialog } from "@/contexts/DialogProvider";
import { cloudDisabled, setCloudStorage } from "@/features/collectionStorage";
import { clearGraphicsStorage, cloudDisabled, setCloudStorage, thumbnailCaptureEnabled } from "@/features/collectionStorage";
import { useDangerStyles } from "@/hooks/useDangerStyles";
import useStorageInfo from "@/hooks/useStorageInfo";
import { Button, Field, MessageBar, MessageBarBody, MessageBarTitle, ProgressBar } from "@fluentui/react-components";
import { Button, Field, InfoLabel, LabelProps, MessageBar, MessageBarBody, MessageBarTitle, ProgressBar, Switch } from "@fluentui/react-components";
import { ArrowDownload20Regular, ArrowUpload20Regular } from "@fluentui/react-icons";
import { useOptionsStyles } from "../hooks/useOptionsStyles";
import exportData from "../utils/exportData";
import importData from "../utils/importData";
import { Unwatch } from "wxt/storage";
export default function StorageSection(): React.ReactElement
{
const { bytesInUse, storageQuota, usedStorageRatio } = useStorageInfo();
const [importResult, setImportResult] = useState<boolean | null>(null);
const [isCloudDisabled, setCloudDisabled] = useState<boolean>(null!);
const [isThumbnailCaptureEnabled, setThumbnailCaptureEnabled] = useState<boolean | null>(null);
const dialog = useDialog();
const cls = useOptionsStyles();
@@ -20,10 +22,35 @@ export default function StorageSection(): React.ReactElement
useEffect(() =>
{
thumbnailCaptureEnabled.getValue().then(setThumbnailCaptureEnabled);
cloudDisabled.getValue().then(setCloudDisabled);
return cloudDisabled.watch(setCloudDisabled);
const unwatchCloud: Unwatch = cloudDisabled.watch(setCloudDisabled);
const unwatchThumbnails: Unwatch = thumbnailCaptureEnabled.watch(setThumbnailCaptureEnabled);
return () =>
{
unwatchCloud();
unwatchThumbnails();
};
}, []);
const handleSetThumbnailCapture = (enabled: boolean): void =>
{
setThumbnailCaptureEnabled(null);
thumbnailCaptureEnabled.setValue(enabled)
.catch(() => setThumbnailCaptureEnabled(!enabled));
};
const handleClearThumbnails = (): void =>
dialog.pushPrompt({
title: i18n.t("options_page.storage.clear_thumbnails.title"),
content: i18n.t("options_page.storage.clear_thumbnails.prompt"),
confirmText: i18n.t("common.actions.delete"),
destructive: true,
onConfirm: () => clearGraphicsStorage()
});
const handleImport = (): void =>
dialog.pushPrompt({
title: i18n.t("options_page.storage.import_prompt.title"),
@@ -51,6 +78,29 @@ export default function StorageSection(): React.ReactElement
return (
<>
<div className={ cls.group }>
<Switch
checked={ isThumbnailCaptureEnabled ?? true }
disabled={ isThumbnailCaptureEnabled === null }
onChange={ (_, e) => handleSetThumbnailCapture(e.checked as boolean) }
label={ {
children: (_: any, props: LabelProps) =>
<InfoLabel
{ ...props }
label={ i18n.t("options_page.storage.thumbnail_capture") }
info={
<p>
{ i18n.t("options_page.storage.thumbnail_capture_notice1") }<br /><br />
{ i18n.t("options_page.storage.thumbnail_capture_notice2") }
</p>
} />
} } />
<Button onClick={ handleClearThumbnails } className={ dangerCls.buttonSubtle } appearance="subtle">
{ i18n.t("options_page.storage.clear_thumbnails.action") }
</Button>
</div>
{ isCloudDisabled === false &&
<Field
label={ i18n.t("options_page.storage.capacity.title") }
+2 -1
View File
@@ -1,5 +1,6 @@
import App from "@/App.tsx";
import "@/assets/global.css";
import { trackPage } from "@/features/analytics";
import { Tab, TabList } from "@fluentui/react-components";
import ReactDOM from "react-dom/client";
import { useOptionsStyles } from "./hooks/useOptionsStyles.ts";
@@ -14,7 +15,7 @@ ReactDOM.createRoot(document.getElementById("root")!).render(
</App>
);
analytics.page("options_page");
trackPage("options_page");
function OptionsPage(): React.ReactElement
{