import 'chrome://resources/ash/common/cr_elements/cr_button/cr_button.js';
import 'chrome://resources/ash/common/cr_elements/icons.html.js';
import 'chrome://resources/ash/common/cr_elements/policy/cr_policy_indicator.js';
import 'chrome://resources/ash/common/cr_elements/cr_shared_style.css.js';
import 'chrome://resources/polymer/v3_0/iron-list/iron-list.js';
import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js';
import 'chrome://resources/polymer/v3_0/paper-tooltip/paper-tooltip.js';
import './print_job_clear_history_dialog.js';
import './print_job_entry.js';
import './print_management_fonts.css.js';
import './print_management_shared.css.js';
import './printer_setup_info.js';
import '/strings.m.js';
import type {IronIconElement} from '//resources/polymer/v3_0/iron-icon/iron-icon.js';
import {I18nMixin} from 'chrome://resources/ash/common/cr_elements/i18n_mixin.js';
import {loadTimeData} from 'chrome://resources/ash/common/load_time_data.m.js';
import {ColorChangeUpdater} from 'chrome://resources/cr_components/color_change_listener/colors_css_updater.js';
import {assert} from 'chrome://resources/js/assert.js';
import type {PolymerElementProperties} from 'chrome://resources/polymer/v3_0/polymer/interfaces.js';
import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {getMetadataProvider, getPrintManagementHandler} from './mojo_interface_provider.js';
import {getTemplate} from './print_management.html.js';
import type {PrintingMetadataProviderInterface, PrintJobInfo, PrintJobsObserverInterface, PrintManagementHandlerInterface} from './printing_manager.mojom-webui.js';
import {ActivePrintJobState, LaunchSource, PrintJobsObserverReceiver} from './printing_manager.mojom-webui.js';
const METADATA_STORED_INDEFINITELY = -1;
const METADATA_STORED_FOR_ONE_DAY = 1;
const METADATA_NOT_STORED = 0;
type RemovePrintJobEvent = CustomEvent<string>;
declare global {
interface HTMLElementEventMap {
'remove-print-job': RemovePrintJobEvent;
'all-history-cleared': CustomEvent<void>;
}
}
function comparePrintJobsReverseChronologically(
first: PrintJobInfo, second: PrintJobInfo): number {
return -comparePrintJobsChronologically(first, second);
}
function comparePrintJobsChronologically(
first: PrintJobInfo, second: PrintJobInfo): number {
return Number(first.creationTime.internalValue) -
Number(second.creationTime.internalValue);
}
* @fileoverview
* 'print-management' is used as the main app to display print jobs.
*/
const PrintManagementElementBase = I18nMixin(PolymerElement);
export interface PrintManagementElement {
$: {deleteIcon: IronIconElement};
}
export class PrintManagementElement extends PrintManagementElementBase
implements PrintJobsObserverInterface {
static get is(): string {
return 'print-management';
}
static get template(): HTMLTemplateElement {
return getTemplate();
}
static get properties(): PolymerElementProperties {
return {
printJobs: {
type: Array,
value: () => [],
},
printJobHistoryExpirationPeriod: {
type: String,
value: '',
},
activeHistoryInfoIcon: {
type: String,
value: '',
},
isPolicyControlled: {
type: Boolean,
value: false,
},
ongoingPrintJobs: {
type: Array,
value: () => [],
},
lastFocused: Object,
listBlurred: Boolean,
showClearAllButton: {
type: Boolean,
value: false,
reflectToAttribute: true,
},
showClearAllDialog: {
type: Boolean,
value: false,
},
deletePrintJobHistoryAllowedByPolicy: {
type: Boolean,
value: true,
},
shouldDisableClearAllButton: {
type: Boolean,
computed: 'computeShouldDisableClearAllButton(printJobs,' +
'deletePrintJobHistoryAllowedByPolicy)',
},
* Receiver responsible for observing print job updates notification
* events.
*/
printJobsObserverReceiver: {type: Object},
printJobsLoaded: Boolean,
};
}
static get observers(): string[] {
return ['onClearAllButtonUpdated(shouldDisableClearAllButton)'];
}
constructor() {
super();
this.mojoInterfaceProvider = getMetadataProvider();
this.pageHandler = getPrintManagementHandler();
window.CrPolicyStrings = {
controlledSettingPolicy:
loadTimeData.getString('clearAllPrintJobPolicyIndicatorToolTip'),
};
this.addEventListener('all-history-cleared', () => this.getPrintJobs());
this.addEventListener('remove-print-job', (e) => this.removePrintJob(e));
}
private mojoInterfaceProvider: PrintingMetadataProviderInterface;
private pageHandler: PrintManagementHandlerInterface;
private isPolicyControlled: boolean;
private printJobs: PrintJobInfo[];
private printJobHistoryExpirationPeriod: string;
private activeHistoryInfoIcon: string;
private ongoingPrintJobs: PrintJobInfo[];
private lastFocused: Element;
private listBlurred: boolean;
private showClearAllButton: boolean;
private showClearAllDialog: boolean;
private deletePrintJobHistoryAllowedByPolicy: boolean;
private shouldDisableClearAllButton: boolean;
private printJobsObserverReceiver: PrintJobsObserverReceiver;
private printJobsLoaded: boolean = false;
override connectedCallback(): void {
super.connectedCallback();
this.getPrintJobHistoryExpirationPeriod();
this.startObservingPrintJobs();
this.fetchDeletePrintJobHistoryPolicy();
ColorChangeUpdater.forDocument().start();
}
override disconnectedCallback(): void {
super.disconnectedCallback();
this.printJobsObserverReceiver.$.close();
}
private startObservingPrintJobs(): void {
this.printJobsObserverReceiver = new PrintJobsObserverReceiver((this));
this.mojoInterfaceProvider
.observePrintJobs(
this.printJobsObserverReceiver.$.bindNewPipeAndPassRemote())
.then(() => {
this.getPrintJobs();
});
}
private fetchDeletePrintJobHistoryPolicy(): void {
this.mojoInterfaceProvider.getDeletePrintJobHistoryAllowedByPolicy().then(
(param) => {
this.onGetDeletePrintHistoryPolicy(param);
});
}
private onGetDeletePrintHistoryPolicy(responseParam: {
isAllowedByPolicy: boolean,
}): void {
this.showClearAllButton = true;
this.deletePrintJobHistoryAllowedByPolicy = responseParam.isAllowedByPolicy;
}
onAllPrintJobsDeleted(): void {
this.getPrintJobs();
}
onPrintJobUpdate(job: PrintJobInfo): void {
assert(job.activePrintJobInfo);
const idx = this.getIndexOfOngoingPrintJob(job.id);
if (idx !== -1) {
this.splice('ongoingPrintJobs', idx, 1, job);
} else {
this.push('ongoingPrintJobs', job);
}
if (job.activePrintJobInfo?.activeState ===
ActivePrintJobState.kDocumentDone) {
this.getPrintJobs();
}
}
private onPrintJobsReceived(
jobs: {printJobs: PrintJobInfo[]}, requestStartTime: number): void {
if (!this.printJobsLoaded) {
this.printJobsLoaded = true;
}
const ongoingList = [];
const historyList = [];
for (const job of jobs.printJobs) {
if (job.activePrintJobInfo) {
ongoingList.push(job);
} else {
historyList.push(job);
}
}
this.ongoingPrintJobs = ongoingList.sort(comparePrintJobsChronologically);
this.printJobs = historyList.sort(comparePrintJobsReverseChronologically);
this.pageHandler.recordGetPrintJobsRequestDuration(
Date.now() - requestStartTime);
}
private getPrintJobs(): void {
const requestStartTime = Date.now();
this.mojoInterfaceProvider.getPrintJobs().then(
(jobs: {printJobs: PrintJobInfo[]}) =>
this.onPrintJobsReceived(jobs, requestStartTime));
}
private onPrintJobHistoryExpirationPeriodReceived(printJobPolicyInfo: {
expirationPeriodInDays: number,
isFromPolicy: boolean,
}): void {
const expirationPeriod = printJobPolicyInfo.expirationPeriodInDays;
if (expirationPeriod === METADATA_NOT_STORED) {
return;
}
this.isPolicyControlled = printJobPolicyInfo.isFromPolicy;
this.activeHistoryInfoIcon =
this.isPolicyControlled ? 'enterpriseIcon' : 'infoIcon';
switch (expirationPeriod) {
case METADATA_STORED_INDEFINITELY:
this.printJobHistoryExpirationPeriod =
loadTimeData.getString('printJobHistoryIndefinitePeriod');
break;
case METADATA_STORED_FOR_ONE_DAY:
this.printJobHistoryExpirationPeriod =
loadTimeData.getString('printJobHistorySingleDay');
break;
default:
this.printJobHistoryExpirationPeriod = loadTimeData.getStringF(
'printJobHistoryExpirationPeriod',
expirationPeriod,
);
}
}
private getPrintJobHistoryExpirationPeriod(): void {
this.mojoInterfaceProvider.getPrintJobHistoryExpirationPeriod().then(
this.onPrintJobHistoryExpirationPeriodReceived.bind(this));
}
private removePrintJob(e: RemovePrintJobEvent): void {
this.printJobsLoaded = false;
const idx = this.getIndexOfOngoingPrintJob(e.detail);
if (idx !== -1) {
this.splice('ongoingPrintJobs', idx, 1);
}
}
private onClearHistoryClicked(): void {
this.showClearAllDialog = true;
}
private onClearHistoryDialogClosed(): void {
this.showClearAllDialog = false;
}
private getIndexOfOngoingPrintJob(expectedId: string): number {
return this.ongoingPrintJobs.findIndex(
arrJob => arrJob.id === expectedId,
);
}
private computeShouldDisableClearAllButton(): boolean {
return !this.deletePrintJobHistoryAllowedByPolicy || !this.printJobs.length;
}
private onClearAllButtonUpdated(): void {
this.$.deleteIcon.classList.toggle(
'delete-enabled', !this.shouldDisableClearAllButton);
this.$.deleteIcon.classList.toggle(
'delete-disabled', this.shouldDisableClearAllButton);
}
private shouldShowSetupAssistance(): boolean {
return this.printJobsLoaded && this.ongoingPrintJobs.length === 0 &&
this.printJobs.length === 0;
}
private shouldShowOngoingEmptyState(): boolean {
return this.printJobs.length > 0 && this.ongoingPrintJobs.length === 0;
}
private shouldShowManagePrinterButton(): boolean {
return this.ongoingPrintJobs.length > 0 || this.printJobs.length > 0;
}
private onManagePrintersClicked(): void {
this.pageHandler.launchPrinterSettings(LaunchSource.kHeaderButton);
}
}
customElements.define(PrintManagementElement.is, PrintManagementElement);