feat: prep fopr v3.7.0 as well as minor tweaks

This commit is contained in:
2026-06-02 08:42:24 +09:30
parent 9e521722f1
commit 337f85c3cc
13 changed files with 176 additions and 31 deletions
@@ -16,6 +16,7 @@
TIME_RANGE_OPTIONS,
type TimeRange,
} from "./timeRange";
import { openAnalyticsPrivacyPopup } from "./openAnalyticsPrivacyPopup";
let analyticsData: Assessment[] | null = $state(null);
let loading = $state(true);
@@ -208,14 +209,23 @@
<p class="bsplus-analytics-meta">Last updated: {formattedTimestamp()}</p>
{/if}
</div>
<button
type="button"
class="bsplus-analytics-btn bsplus-analytics-btn-primary"
disabled={syncing}
onclick={() => runSync()}
>
{syncing ? "Syncing…" : "Refresh data"}
</button>
<div class="bsplus-analytics-header-actions">
<button
type="button"
class="bsplus-analytics-btn bsplus-analytics-btn-primary"
disabled={syncing}
onclick={() => runSync()}
>
{syncing ? "Syncing…" : "Refresh data"}
</button>
<button
type="button"
class="bsplus-analytics-btn bsplus-analytics-btn-ghost"
onclick={() => openAnalyticsPrivacyPopup()}
>
Privacy notice
</button>
</div>
</header>
{#if error}
@@ -1,9 +1,13 @@
import type { Plugin } from "@/plugins/core/types";
import MenuitemSVGKey from "@/seqta/content/MenuItemSVGKey.json";
import { waitForElm } from "@/seqta/utils/waitForElm";
import { isSeqtaEngageExperience } from "@/seqta/utils/isSeqtaEngage";
import { processMenuItemNode } from "@/seqta/utils/sidebarMenuIcons";
import { loadAnalyticsPage } from "../loadAnalyticsPage";
import styles from "../styles.css?inline";
const ANALYTICS_MENU_ICON = MenuitemSVGKey.analytics;
const ANALYTICS_MENU_CLASS = "betterseqta-grade-analytics-item";
const gradeAnalyticsPlugin: Plugin<{}> = {
@@ -30,7 +34,7 @@ const gradeAnalyticsPlugin: Plugin<{}> = {
analyticsItem.dataset.key = "analytics";
analyticsItem.dataset.path = "/analytics";
analyticsItem.dataset.betterseqta = "true";
analyticsItem.innerHTML = `<label><svg style="width:24px;height:24px" viewBox="0 0 24 24" aria-hidden="true"><path fill="currentColor" d="M3 13h2v-2H3v2zm0 4h2v-2H3v2zm0-8h2V7H3v2zm4 8h14v-2H7v2zm0 4h14v-2H7v2zM7 7v2h14V7H7z"/></svg><span>Analytics</span></label>`;
analyticsItem.innerHTML = `<label>${ANALYTICS_MENU_ICON}<span>Analytics</span></label>`;
const homeButton = document.getElementById("homebutton");
if (homeButton?.parentElement === menuList) {
@@ -39,6 +43,8 @@ const gradeAnalyticsPlugin: Plugin<{}> = {
menuList.insertBefore(analyticsItem, menuList.firstChild);
}
processMenuItemNode(analyticsItem);
const menuObserver = new MutationObserver(() => {
if (!menuList.contains(analyticsItem)) {
if (homeButton?.parentElement === menuList) {
@@ -46,6 +52,7 @@ const gradeAnalyticsPlugin: Plugin<{}> = {
} else {
menuList.insertBefore(analyticsItem, menuList.firstChild);
}
processMenuItemNode(analyticsItem);
}
});
menuObserver.observe(menuList, { childList: true });
@@ -0,0 +1,61 @@
import stringToHTML from "@/seqta/utils/stringToHTML";
import { openPopup } from "@/seqta/utils/Openers/PopupManager";
/** Grade Analytics privacy — uses the shared BetterSEQTA+ whatsnew popup shell. */
export function openAnalyticsPrivacyPopup() {
const header = stringToHTML(
/* html */
`<div class="whatsnewHeader">
<h1>Privacy notice</h1>
<p>Grade Analytics on this device</p>
</div>`,
).firstChild as HTMLElement;
const text = stringToHTML(/* html */ `
<div class="whatsnewTextContainer privacyStatement">
<p style="margin-top: 0;">
<strong>Your grade history and charts stay on this device.</strong>
BetterSEQTA+ does not collect or store your analytics on our servers.
</p>
<h3>What we store locally</h3>
<ul style="text-align: left; margin: 10px 0;">
<li>Assessment results and subjects used for trends, distribution, and the table</li>
<li>Chart preferences (for example, grade distribution grouping) for your school account</li>
<li>A cache timestamp so Refresh data knows when to fetch from SEQTA again</li>
</ul>
<h3>What we never do</h3>
<ul style="text-align: left; margin: 10px 0;">
<li>Upload analytics data to BetterSEQTA Cloud or any BetterSEQTA server</li>
<li>Include analytics in automatic cloud settings backup or restore</li>
<li>Send your grades to third-party analytics or tracking services</li>
</ul>
<h3>How refresh works</h3>
<p>
Refresh data loads released marks directly from SEQTA while you are logged in.
That traffic is between your browser and your schools SEQTA site — not to us.
</p>
<h3>Clearing your data</h3>
<p>
You can remove cached analytics any time by clearing this extensions storage in
your browser settings.
</p>
<p style="font-weight: 600;">
General plugin settings (such as cache duration in the Grade Analytics plugin
panel) may still sync if you use BetterSEQTA Cloud — but never your assessment
results or charts.
</p>
</div>
`).firstChild as HTMLElement;
openPopup({
header,
content: [text],
animateSelector: ".whatsnewTextContainer *",
containerClass: "whatsnewContainer--scrollBody",
});
}
@@ -103,6 +103,20 @@
gap: 1.25rem;
}
.bsplus-analytics-header-actions {
display: flex;
flex-direction: column;
align-items: stretch;
gap: 0.5rem;
flex-shrink: 0;
}
@media (min-width: 480px) {
.bsplus-analytics-header-actions {
min-width: 10.5rem;
}
}
.bsplus-analytics-header-text h1 {
margin: 0 0 0.35rem;
font-size: 1.875rem;