Skip to content

Commit

Permalink
Merge pull request #1589 from IBMa/joho-changeRuleSet-duringMultiScan…
Browse files Browse the repository at this point in the history
…-954

Modal to warn user that if they have stored scans they will be lost if user changes ruleset
  • Loading branch information
ErickRenteria authored Aug 29, 2023
2 parents 69f4574 + 93355a3 commit 72ea29c
Show file tree
Hide file tree
Showing 4 changed files with 175 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*****************************************************************************/

import { getDevtoolsController } from "../devtools/devtoolsController";
import { IArchiveDefinition, IMessage, IReport, IRuleset, ISettings } from "../interfaces/interfaces";
import { IArchiveDefinition, IMessage, IReport, IRuleset, ISessionState, ISettings } from "../interfaces/interfaces";
import { CommonMessaging } from "../messaging/commonMessaging";
import { Controller, eControllerType, ListenerType } from "../messaging/controller";
import Config from "../util/config";
Expand Down Expand Up @@ -143,6 +143,56 @@ class BackgroundController extends Controller {
}

///// Settings related functions /////////////////////////////////////////
/**
* Global state for the extension
*/
public async getSessionState() : Promise<ISessionState> {
let retVal = (await this.hook("getSessionState", null, async () => {
let retVal = await new Promise<ISessionState>((resolve, _reject) => {
(chrome.storage as any).session.get("SESSION_STATE", async function (result: { SESSION_STATE?: ISessionState}) {
result.SESSION_STATE = result.SESSION_STATE || {
tabStoredCount: {}
}
result.SESSION_STATE.tabStoredCount = result.SESSION_STATE.tabStoredCount || {};
resolve(result.SESSION_STATE as ISessionState);
});
})
return retVal;
}))!;
return retVal;
}

/**
* Set settings for the extension
*/
public async setSessionState(sessionState: ISessionState) : Promise<ISessionState> {
return this.hook("setSessionState", sessionState, async () => {
await new Promise<ISessionState>((resolve, _reject) => {
(chrome.storage as any).session.set({ "SESSION_STATE": sessionState }, async function () {
resolve(sessionState!);
});
});
this.notifyEventListeners("BG_onSessionState", -1, sessionState);
return sessionState;
});
}


/**
* Set stored scan count
*/
public async setStoredScanCount(info: { tabId: number, count: number }) : Promise<ISessionState> {
return this.hook("setStoredScanCount", info, async () => {
let { tabId, count }: {tabId: number, count: number } = info;
let sessionState = await this.getSessionState();
if (count === 0) {
delete sessionState.tabStoredCount[tabId];
} else {
sessionState.tabStoredCount[tabId] = count;
}
return await this.setSessionState(sessionState);
});
}

/**
* Get settings for the extension
Expand Down Expand Up @@ -180,6 +230,9 @@ class BackgroundController extends Controller {
this.addEventListener(listener, `BG_onSettings`);
}

public async addSessionStateListener(listener: ListenerType<ISessionState>) {
this.addEventListener(listener, `BG_onSessionState`);
}
/**
* Get the archive definitions
*/
Expand Down Expand Up @@ -219,7 +272,6 @@ class BackgroundController extends Controller {
(async () => {
let settings = await this.getSettings();
getDevtoolsController(false, "remote", senderTabId).setScanningState("running");
console.info(`[INFO]: Scanning using archive ${settings.selected_archive.id} and guideline ${settings.selected_ruleset.id}`);
let report : IReport = await myExecuteScript2(senderTabId, (settings: ISettings) => {
let checker = new (<any>window).aceIBMa.Checker();
if (Object.keys(checker.engine.nlsMap).length === 0) {
Expand Down Expand Up @@ -342,6 +394,13 @@ class BackgroundController extends Controller {
const listenMsgs : {
[ msgId: string ] : (msgBody: IMessage<any>, senderTabId?: number) => Promise<any>
}= {
"BG_getSessionState": async () => self.getSessionState(),
"BG_setSessionState": async (msgBody) => {
return self.setSessionState(msgBody.content);
},
"BG_setStoredScanCount": async (msgBody) => {
return self.setStoredScanCount(msgBody.content);
},
"BG_getSettings": async () => self.getSettings(),
"BG_getArchives": async () => self.getArchives(),
"BG_getTabId": async (_a, senderTabId) => self.getTabId(senderTabId),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ export class DevtoolsController extends Controller {
return await this.hook("setStoredReportsMeta", updateMetaArr, async () => {
if (updateMetaArr.length === 0) {
devtoolsState!.storedReports = [];
getBGController().setStoredScanCount({ tabId: this.ctrlDest.tabId, count: 0});
this.notifyEventListeners("DT_onStoredReportsMeta", this.ctrlDest.tabId, await this.getStoredReportsMeta());
} else {
let misMatch = false;
Expand All @@ -113,6 +114,7 @@ export class DevtoolsController extends Controller {
if (!misMatch) {
devtoolsState!.storedReports = newReports;
let data = await this.getStoredReportsMeta();
getBGController().setStoredScanCount({ tabId: this.ctrlDest.tabId, count: data.length});
this.notifyEventListeners("DT_onStoredReportsMeta", this.ctrlDest.tabId, data);
}
}
Expand All @@ -139,6 +141,7 @@ export class DevtoolsController extends Controller {
public async clearStoredReports() : Promise<void> {
return this.hook("clearStoredReports", null, async () => {
devtoolsState!.storedReports = [];
getBGController().setStoredScanCount({ tabId: this.ctrlDest.tabId, count: 0});
this.notifyEventListeners("DT_onStoredReportsMeta", this.ctrlDest.tabId, await this.getStoredReportsMeta());
});
}
Expand Down Expand Up @@ -213,7 +216,9 @@ export class DevtoolsController extends Controller {
return new Promise((resolve, _reject) => {
setTimeout(async () => {
this.notifyEventListeners("DT_onReport", this.ctrlDest.tabId, report);
this.notifyEventListeners("DT_onStoredReportsMeta", this.ctrlDest.tabId, await this.getStoredReportsMeta());
let storedReportsMeta = await this.getStoredReportsMeta();
getBGController().setStoredScanCount({ tabId: this.ctrlDest.tabId, count: storedReportsMeta.length});
this.notifyEventListeners("DT_onStoredReportsMeta", this.ctrlDest.tabId, storedReportsMeta);
resolve();
}, 0)
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ export interface ISettings {
tabStopFirstTime: boolean
}

export interface ISessionState {
tabStoredCount: {
[tabId: number]: number
}
}

export type MsgDestType = {
type: "contentScript"
tabId: number
Expand Down
113 changes: 102 additions & 11 deletions accessibility-checker-extension/src/ts/options/OptionsApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,10 @@ limitations under the License.
*****************************************************************************/

import React from "react";

import ReactDOM from 'react-dom';
import { IArchiveDefinition, IPolicyDefinition, ISettings } from "../interfaces/interfaces";
import { getBGController } from "../background/backgroundController";
import { DocPage } from "../docs/components/DocPage";
// import { BrowserDetection } from "../util/browserDetection";

import {
Button,
Expand All @@ -43,6 +42,7 @@ import {
} from "@carbon/react/icons";

import "./option.scss";
import { getDevtoolsController } from "../devtools/devtoolsController";

interface OptionsAppState {
lastSettings?: ISettings
Expand All @@ -57,6 +57,10 @@ interface OptionsAppState {
tabStopOutlines: boolean;
tabStopAlerts: boolean;
tabStopFirstTime: boolean;
// Change Ruleset while there are stored scans
storedScansExist: boolean;
modalDeploymentWithScans: boolean;
modalGuidelinesWithScans: boolean;
savePending: number;
}

Expand All @@ -75,13 +79,16 @@ export class OptionsApp extends React.Component<{}, OptionsAppState> {
tabStopOutlines: false,
tabStopAlerts: true,
tabStopFirstTime: true,
// Change Ruleset while there are stored scans
storedScansExist: false,
modalDeploymentWithScans: false,
modalGuidelinesWithScans: false,
savePending: 0
};

async componentDidMount() {
let self = this;
let settings = await bgController.getSettings();
// console.log("***", settings);
let archives = await bgController.getArchives();
let selected_archive: IArchiveDefinition | null = null;
let rulesets: IPolicyDefinition[] | null = null;
Expand All @@ -92,6 +99,7 @@ export class OptionsApp extends React.Component<{}, OptionsAppState> {
let tabStopAlerts: boolean = true;
let tabStopFirstTime: boolean = true;

let storedScansExist = await this.existStoredScans();

selected_archive = settings.selected_archive;
rulesets = selected_archive.rulesets.default;
Expand Down Expand Up @@ -126,7 +134,11 @@ export class OptionsApp extends React.Component<{}, OptionsAppState> {
selected_ruleset: this.getGuideline(selected_archive, selectedRulesetId!),
tabStopLines: tabStopLines, tabStopOutlines: tabStopOutlines,
tabStopAlerts: tabStopAlerts, tabStopFirstTime: tabStopFirstTime,
storedScansExist: storedScansExist,
});



bgController.addSettingsListener(async (newSettings) => {
let newState : any = {
lastSettings: newSettings
Expand All @@ -141,6 +153,35 @@ export class OptionsApp extends React.Component<{}, OptionsAppState> {
});
}

setModalDeploymentWithScans() {
this.setState({modalDeploymentWithScans: true});
}

setModalGuidelinesWithScans() {
this.setState({modalGuidelinesWithScans: true});
}

async existStoredScans() {
let tabStoredScans = (await getBGController().getSessionState()).tabStoredCount;
let existScans = false;
for (const tabId in tabStoredScans) {
if (tabStoredScans[tabId] > 0) {
existScans = true;
}
}
return existScans;
}

async clearStoredScans() {
let tabStoredScans = (await getBGController().getSessionState()).tabStoredCount;
for (const tabId in tabStoredScans) {
if (tabStoredScans[tabId] > 0) {
getDevtoolsController(false, "remote", parseInt(tabId)).clearStoredReports();
}
}
this.setState({storedScansExist: false});
}

/**
* Return the archive definition corresponding to the 'latest' id
* @param archives
Expand Down Expand Up @@ -350,6 +391,10 @@ export class OptionsApp extends React.Component<{}, OptionsAppState> {
</Button>
</div>

{/* JCH - Need to check if there are scans, storedReportsCount > 0
but we need to make a state and set it in componentDidMount
*/}

{!this.state.selected_archive && <DropdownSkeleton />}
{this.state.selected_archive && <>
<Dropdown
Expand All @@ -364,11 +409,16 @@ export class OptionsApp extends React.Component<{}, OptionsAppState> {
titleText=""
type="default"
selectedItem={selected_archive}
onChange={this.onSelectArchive.bind(this)}
onChange={async (evt: any) => {
await this.onSelectArchive(evt);
if (this.state.storedScansExist) {
this.setModalDeploymentWithScans();
}
}}
/>
</>}

<Modal
{typeof document === 'undefined' ? null : ReactDOM.createPortal(<Modal
aria-label="Version information"
modalHeading="Selecting a rule set deployment date"
passiveModal={true}
Expand All @@ -383,7 +433,27 @@ export class OptionsApp extends React.Component<{}, OptionsAppState> {
<p style={{ maxWidth: "100%" }}><strong>Preview rules: </strong> Try an experimental preview of possible future rule set</p>

<p style={{ maxWidth: "100%" }}>For details on rule set changes between deployments, see <Link inline={true} size="md" className="link" href="https://www.ibm.com/able/requirements/release-notes" target="_blank" style={{ color: '#002D9C' }}>Release notes</Link></p>
</Modal>
</Modal>, document.body)}

{typeof document === 'undefined' ? null : ReactDOM.createPortal(<Modal
modalHeading="Stored scans"
size='sm'
primaryButtonText="Change deployment dates"
secondaryButtonText="Cancel"
open={this.state.modalDeploymentWithScans}
onRequestClose={(() => {
this.setState({ modalDeploymentWithScans: false });
this.setState({ selected_archive: this.state.lastSettings?.selected_archive! });
}).bind(this)}
onRequestSubmit={(() => {
this.clearStoredScans();
this.setState({ modalDeploymentWithScans: false });
}).bind(this)
}
>
<p>Changing the rule set deployment dates will delete any currently stored scans.</p>
</Modal>, document.body)}

</div>
{/**** Select ruleset / policy */}
<div>
Expand Down Expand Up @@ -417,11 +487,16 @@ export class OptionsApp extends React.Component<{}, OptionsAppState> {
titleText=""
type="default"
selectedItem={selected_ruleset}
onChange={this.onSelectGuideline.bind(this)}
onChange={async (evt: any) => {
await this.onSelectGuideline(evt);
if (this.state.storedScansExist) {
this.setModalGuidelinesWithScans();
}
}}
/>
</>}

<Modal
{typeof document === 'undefined' ? null : ReactDOM.createPortal(<Modal
aria-label="Guidelines information"
modalHeading="Selecting accessibility guidelines"
passiveModal={true}
Expand All @@ -433,9 +508,27 @@ export class OptionsApp extends React.Component<{}, OptionsAppState> {
<p style={{ maxWidth: "100%" }}><strong>IBM Accessibility: </strong> Rules for WCAG 2.1 AA plus additional IBM requirements</p>
<p style={{ maxWidth: "100%" }}><strong>WCAG 2.1 (A, AA): </strong> This is the current W3C recommendation. Content that conforms to WCAG 2.1 also conforms to WCAG 2.0</p>
<p style={{ maxWidth: "100%" }}><strong>WCAG 2.0 (A, AA): </strong> Referenced by US Section 508, but not the latest W3C recommendation</p>
</Modal>
</Modal>, document.body)}
</div>

{typeof document === 'undefined' ? null : ReactDOM.createPortal(<Modal
modalHeading="Stored scans"
primaryButtonText="Change Guidelines"
secondaryButtonText="Cancel"
open={this.state.modalGuidelinesWithScans}
onRequestClose={(() => {
this.setState({ modalGuidelinesWithScans: false });
this.setState({ selected_ruleset: this.getGuideline(this.state.lastSettings?.selected_archive!, this.state.lastSettings?.selected_ruleset.id!) });
}).bind(this)}
onRequestSubmit={(() => {
this.clearStoredScans();
this.setState({ modalGuidelinesWithScans: false });
}).bind(this)
}
>
<p>Changing the rule set deployment dates will delete any currently stored scans.</p>
</Modal>, document.body)}


<h2>Keyboard checker mode</h2>
<div>
Expand All @@ -448,7 +541,6 @@ export class OptionsApp extends React.Component<{}, OptionsAppState> {
checked={this.state.tabStopLines}
//@ts-ignore
onChange={(value: any, id: any) => {
// console.log("lines checkbox id.checked = ",id.checked);
this.setState({ tabStopLines: id.checked });
}}

Expand All @@ -459,7 +551,6 @@ export class OptionsApp extends React.Component<{}, OptionsAppState> {
checked={this.state.tabStopOutlines}
//@ts-ignore
onChange={(value: any, id: any) => {
// console.log("lines checkbox id.checked = ",id.checked);
this.setState({ tabStopOutlines: id.checked });
}}
/>
Expand Down

0 comments on commit 72ea29c

Please sign in to comment.