fix(extra-info): show extra info in the RCE thread page
The extra info feature worked with the old thread pages. This CL brings
support to the new RCE thread pages.
Bug: twpowertools:93
Change-Id: I47e4235afa4f7ec441f5a92edfcc28b1cb5f0419
diff --git a/src/contentScripts/communityConsole/extraInfo/services/message.js b/src/contentScripts/communityConsole/extraInfo/services/message.js
new file mode 100644
index 0000000..3b43403
--- /dev/null
+++ b/src/contentScripts/communityConsole/extraInfo/services/message.js
@@ -0,0 +1,56 @@
+import MessageModel from '../../../../models/Message.js';
+
+import StatesExtraInfoService from './states.js';
+
+export default class MessageExtraInfoService {
+ static getMessageIdFromNode(messageNode) {
+ const id =
+ messageNode.querySelector('.scTailwindThreadMessageMessagecardcontent')
+ ?.getAttribute?.('data-stats-id');
+ if (id === undefined)
+ throw new Error(`Couldn't retrieve message id from node.`);
+ return id;
+ }
+
+ static getMessageFromThreadModel(messageId, threadModel) {
+ for (const messageOrGap of threadModel.getMessageOrGapModels()) {
+ if (!(messageOrGap instanceof MessageModel)) continue;
+ if (messageOrGap.getId() == messageId) {
+ return messageOrGap;
+ } else {
+ for (const subMessageOrGap of messageOrGap.getCommentsAndGaps()) {
+ if (!(subMessageOrGap instanceof MessageModel)) continue;
+ if (subMessageOrGap.getId() == messageId) {
+ return subMessageOrGap;
+ }
+ }
+ }
+ }
+
+ throw new Error(`Couldn't find message ${messageId} in thread.`);
+ }
+
+ static getMessageChips(messageModel) {
+ const chips = [];
+ const tooltips = [];
+
+ const endPendingStateTimestampMicros =
+ messageModel.getEndPendingStateTimestampMicros();
+ const [pendingStateChip, pendingStateTooltip] =
+ StatesExtraInfoService.getPendingStateChip(
+ endPendingStateTimestampMicros);
+ if (pendingStateChip) chips.push(pendingStateChip);
+ if (pendingStateTooltip) tooltips.push(pendingStateTooltip);
+
+ const itemMetadata = messageModel.data?.[1]?.[5];
+ chips.push(...StatesExtraInfoService.getMetadataChips(itemMetadata));
+
+ const liveReviewStatus = messageModel.data?.[1]?.[36];
+ const [liveReviewChip, liveReviewTooltip] =
+ StatesExtraInfoService.getLiveReviewStatusChip(liveReviewStatus);
+ if (liveReviewChip) chips.push(liveReviewChip);
+ if (liveReviewTooltip) tooltips.push(liveReviewTooltip);
+
+ return [chips, tooltips];
+ }
+}
diff --git a/src/contentScripts/communityConsole/extraInfo/services/states.js b/src/contentScripts/communityConsole/extraInfo/services/states.js
new file mode 100644
index 0000000..6904e3e
--- /dev/null
+++ b/src/contentScripts/communityConsole/extraInfo/services/states.js
@@ -0,0 +1,106 @@
+import {createPlainTooltip} from '../../../../common/tooltip.js';
+import {kItemMetadataState, kItemMetadataStateI18n} from '../consts.js';
+
+export default class StatesExtraInfoService {
+ static getPendingStateChip(endPendingStateTimestampMicros) {
+ const endPendingStateTimestamp =
+ Math.floor(endPendingStateTimestampMicros / 1e3);
+ const now = Date.now();
+ if (!endPendingStateTimestampMicros || endPendingStateTimestamp < now)
+ return [null, null];
+
+ const span = document.createElement('span');
+ span.textContent =
+ chrome.i18n.getMessage('inject_extrainfo_message_pendingstate');
+
+ const date = new Date(endPendingStateTimestamp).toLocaleString();
+ const pendingTooltip = createPlainTooltip(
+ span,
+ chrome.i18n.getMessage(
+ 'inject_extrainfo_message_pendingstate_tooltip', [date]),
+ false);
+ return [span, pendingTooltip];
+ }
+
+ static getLiveReviewStatusChip(liveReviewStatus) {
+ const verdict = liveReviewStatus?.['1'];
+ if (!verdict) return [null, null];
+
+ const [label, labelClass] = this.getLiveReviewStatusLabel(verdict);
+ if (!label || !labelClass) return [null, null];
+
+ const reviewedBy = liveReviewStatus?.['2'];
+ const timestamp = liveReviewStatus?.['3'];
+ const date = (new Date(Math.floor(timestamp / 1e3))).toLocaleString();
+
+ let a = document.createElement('a');
+ a.href = 'https://support.google.com/s/community/user/' + reviewedBy;
+ a.classList.add(labelClass);
+ a.textContent = chrome.i18n.getMessage(
+ 'inject_extrainfo_message_livereviewverdict',
+ [chrome.i18n.getMessage(
+ 'inject_extrainfo_message_livereviewverdict_' + label)]);
+ let liveReviewTooltip = createPlainTooltip(a, date, false);
+ return [a, liveReviewTooltip];
+ }
+
+ static getLiveReviewStatusLabel(verdict) {
+ let label, labelClass;
+ switch (verdict) {
+ case 1: // LIVE_REVIEW_RELEVANT
+ label = 'relevant';
+ labelClass = 'TWPT-extrainfo-good';
+ break;
+
+ case 2: // LIVE_REVIEW_OFF_TOPIC
+ label = 'offtopic';
+ labelClass = 'TWPT-extrainfo-bad';
+ break;
+
+ case 3: // LIVE_REVIEW_ABUSE
+ label = 'abuse';
+ labelClass = 'TWPT-extrainfo-bad';
+ break;
+
+ default:
+ return [null, null];
+ }
+ return [label, labelClass];
+ }
+
+ static getMetadataChips(itemMetadata) {
+ return [
+ this.getStateChip(itemMetadata),
+ this.getShadowBlockChip(itemMetadata),
+ ].filter(chip => chip !== null);
+ }
+
+ static getStateChip(itemMetadata) {
+ const state = itemMetadata?.['1'];
+ if (!state || state == 1) return null;
+
+ const stateI18nKey =
+ 'inject_extrainfo_message_state_' + kItemMetadataStateI18n[state];
+ const stateLocalized = chrome.i18n.getMessage(stateI18nKey) ?? state;
+
+ const span = document.createElement('span');
+ span.textContent = chrome.i18n.getMessage(
+ 'inject_extrainfo_message_state', [stateLocalized]);
+ span.title = kItemMetadataState[state] ?? state;
+ return span;
+ }
+
+ static getShadowBlockChip(itemMetadata) {
+ const shadowBlockInfo = itemMetadata?.['10'];
+ const blockedTimestampMicros = shadowBlockInfo?.['2'];
+ if (!blockedTimestampMicros) return null;
+
+ const isBlocked = shadowBlockInfo?.['1'];
+ let span = document.createElement('span');
+ span.textContent = chrome.i18n.getMessage(
+ 'inject_extrainfo_message_shadowblock' +
+ (isBlocked ? 'active' : 'notactive'));
+ if (isBlocked) span.classList.add('TWPT-extrainfo-bad');
+ return span;
+ }
+}
diff --git a/src/contentScripts/communityConsole/extraInfo/services/thread.js b/src/contentScripts/communityConsole/extraInfo/services/thread.js
index 357ed3d..c36dfa5 100644
--- a/src/contentScripts/communityConsole/extraInfo/services/thread.js
+++ b/src/contentScripts/communityConsole/extraInfo/services/thread.js
@@ -1,5 +1,4 @@
-import {createPlainTooltip} from '../../../../common/tooltip.js';
-import {kItemMetadataState, kItemMetadataStateI18n} from '../consts.js';
+import StatesExtraInfoService from './states.js';
export default class ThreadExtraInfoService {
/**
@@ -11,42 +10,27 @@
let chips = [];
let tooltips = [];
- const [pendingStateInfo, pendingTooltip] = this.getPendingStateChip(thread);
+ const endPendingStateTimestampMicros = thread?.['2']?.['39'];
+ const [pendingStateInfo, pendingTooltip] =
+ StatesExtraInfoService.getPendingStateChip(
+ endPendingStateTimestampMicros);
if (pendingStateInfo) chips.push(pendingStateInfo);
if (pendingTooltip) tooltips.push(pendingTooltip);
chips.push(...this.getTrendingChips(thread));
- chips.push(...this.getMetadataChips(thread));
+ const itemMetadata = thread?.['2']?.['12'];
+ chips.push(...StatesExtraInfoService.getMetadataChips(itemMetadata));
+
+ const liveReviewStatus = thread?.['2']?.['38'];
const [liveReviewInfo, liveReviewTooltip] =
- this.getLiveReviewStatusChip(thread);
+ StatesExtraInfoService.getLiveReviewStatusChip(liveReviewStatus);
if (liveReviewInfo) chips.push(liveReviewInfo);
if (liveReviewTooltip) tooltips.push(liveReviewTooltip);
return [chips, tooltips];
}
- static getPendingStateChip(thread) {
- const endPendingStateTimestampMicros = thread?.['2']?.['39'];
- const endPendingStateTimestamp =
- Math.floor(endPendingStateTimestampMicros / 1e3);
- const now = Date.now();
- if (!endPendingStateTimestampMicros || endPendingStateTimestamp < now)
- return [null, null];
-
- const span = document.createElement('span');
- span.textContent =
- chrome.i18n.getMessage('inject_extrainfo_message_pendingstate');
-
- const date = new Date(endPendingStateTimestamp).toLocaleString();
- const pendingTooltip = createPlainTooltip(
- span,
- chrome.i18n.getMessage(
- 'inject_extrainfo_message_pendingstate_tooltip', [date]),
- false);
- return [span, pendingTooltip];
- }
-
static getTrendingChips(thread) {
const chips = [];
@@ -62,91 +46,6 @@
return chips;
}
- static getMetadataChips(thread) {
- const itemMetadata = thread?.['2']?.['12'];
-
- return [
- this.getStateChip(itemMetadata),
- this.getShadowBlockChip(itemMetadata),
- ].filter(chip => chip !== null);
- }
-
- static getLiveReviewStatusChip(thread) {
- const liveReviewStatus = thread?.['2']?.['38'];
- const verdict = liveReviewStatus?.['1'];
- if (!verdict) return [null, null];
-
- const [label, labelClass] = this.getLiveReviewStatusLabel(verdict);
- if (!label || !labelClass) return [null, null];
-
- const reviewedBy = liveReviewStatus?.['2'];
- const timestamp = liveReviewStatus?.['3'];
- const date = (new Date(Math.floor(timestamp / 1e3))).toLocaleString();
-
- let a = document.createElement('a');
- a.href = 'https://support.google.com/s/community/user/' + reviewedBy;
- a.classList.add(labelClass);
- a.textContent = chrome.i18n.getMessage(
- 'inject_extrainfo_message_livereviewverdict',
- [chrome.i18n.getMessage(
- 'inject_extrainfo_message_livereviewverdict_' + label)]);
- let liveReviewTooltip = createPlainTooltip(a, date, false);
- return [a, liveReviewTooltip];
- }
-
- static getStateChip(itemMetadata) {
- const state = itemMetadata?.['1'];
- if (!state || state == 1) return null;
-
- const stateI18nKey =
- 'inject_extrainfo_message_state_' + kItemMetadataStateI18n[state];
- const stateLocalized = chrome.i18n.getMessage(stateI18nKey) ?? state;
-
- const span = document.createElement('span');
- span.textContent = chrome.i18n.getMessage(
- 'inject_extrainfo_message_state', [stateLocalized]);
- span.title = kItemMetadataState[state] ?? state;
- return span;
- }
-
- static getLiveReviewStatusLabel(verdict) {
- let label, labelClass;
- switch (verdict) {
- case 1: // LIVE_REVIEW_RELEVANT
- label = 'relevant';
- labelClass = 'TWPT-extrainfo-good';
- break;
-
- case 2: // LIVE_REVIEW_OFF_TOPIC
- label = 'offtopic';
- labelClass = 'TWPT-extrainfo-bad';
- break;
-
- case 3: // LIVE_REVIEW_ABUSE
- label = 'abuse';
- labelClass = 'TWPT-extrainfo-bad';
- break;
-
- default:
- return [null, null];
- }
- return [label, labelClass];
- }
-
- static getShadowBlockChip(itemMetadata) {
- const shadowBlockInfo = itemMetadata?.['10'];
- const blockedTimestampMicros = shadowBlockInfo?.['2'];
- if (!blockedTimestampMicros) return null;
-
- const isBlocked = shadowBlockInfo?.['1'];
- let span = document.createElement('span');
- span.textContent = chrome.i18n.getMessage(
- 'inject_extrainfo_message_shadowblock' +
- (isBlocked ? 'active' : 'notactive'));
- if (isBlocked) span.classList.add('TWPT-extrainfo-bad');
- return span;
- }
-
static getThreadFromThreadList(threadList, currentThreadInfo) {
return threadList?.find?.(thread => {
const threadInfo = thread?.['2']?.['1'];